diff --git a/src/main/java/li/cil/oc/Settings.scala b/src/main/java/li/cil/oc/Settings.scala index 91e49dcd7..65f946d73 100644 --- a/src/main/java/li/cil/oc/Settings.scala +++ b/src/main/java/li/cil/oc/Settings.scala @@ -176,7 +176,7 @@ class Settings(config: Config) { Array(2, 4, 8) } val updateCheck = config.getBoolean("misc.updateCheck") - + val alwaysTryNative = config.getBoolean("misc.alwaysTryNative") } object Settings { diff --git a/src/main/java/li/cil/oc/common/asm/ClassTransformer.scala b/src/main/java/li/cil/oc/common/asm/ClassTransformer.scala index 1bc68d095..81384c9ca 100644 --- a/src/main/java/li/cil/oc/common/asm/ClassTransformer.scala +++ b/src/main/java/li/cil/oc/common/asm/ClassTransformer.scala @@ -6,10 +6,10 @@ import cpw.mods.fml.relauncher.IFMLLoadingPlugin.TransformerExclusions import java.util.logging.{Level, Logger} import li.cil.oc.util.mods.StargateTech2 import net.minecraft.launchwrapper.{LaunchClassLoader, IClassTransformer} +import net.minecraft.tileentity.TileEntity import org.objectweb.asm.tree._ import org.objectweb.asm.{ClassWriter, ClassReader} import scala.collection.convert.WrapAsScala._ -import net.minecraft.tileentity.TileEntity @TransformerExclusions(Array("li.cil.oc.common.asm")) class ClassTransformer extends IClassTransformer { @@ -17,15 +17,15 @@ class ClassTransformer extends IClassTransformer { val log = Logger.getLogger("OpenComputers") - override def transform(name: String, transformedName: String, basicClass: Array[Byte]): Array[Byte] = { + override def transform(name: String, transformedName: String, basicClass: Array[Byte]): Array[Byte] = try { if (name == "li.cil.oc.common.tileentity.Computer" || name == "li.cil.oc.common.tileentity.Rack") { return ensureStargateTechCompatibility(basicClass) } else if (basicClass != null - && !name.startsWith( """net.minecraft.""") - && !name.startsWith( """net.minecraftforge.""") - && !name.startsWith( """li.cil.oc.common.asm.""") - && !name.startsWith( """li.cil.oc.api.""")) { + && !name.startsWith("""net.minecraft.""") + && !name.startsWith("""net.minecraftforge.""") + && !name.startsWith("""li.cil.oc.common.asm.""") + && !name.startsWith("""li.cil.oc.api.""")) { val classNode = newClassNode(basicClass) if (classNode.interfaces.contains("li/cil/oc/api/network/SimpleComponent")) { try { @@ -40,6 +40,11 @@ class ClassTransformer extends IClassTransformer { } basicClass } + catch { + case t: Throwable => + log.log(Level.WARNING, "Something went wrong!", t) + basicClass + } def ensureStargateTechCompatibility(basicClass: Array[Byte]): Array[Byte] = { if (!Loader.isModLoaded("StargateTech2")) { @@ -104,9 +109,9 @@ class ClassTransformer extends IClassTransformer { case _ => log.fine(s"No original implementation of $methodName, will inject override.") template.methods.find(_.name == methodName + "0") match { - case Some(method) => classNode.methods.add(method) - case _ => throw new AssertionError(s"Couldn't find ${methodName}0 in template implementation.") - } + case Some(method) => classNode.methods.add(method) + case _ => throw new AssertionError(s"Couldn't find ${methodName}0 in template implementation.") + } } template.methods.find(filter) match { case Some(method) => classNode.methods.add(method) @@ -125,7 +130,11 @@ class ClassTransformer extends IClassTransformer { writeClass(classNode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) } - val tileEntityName = classOf[TileEntity].getName.replace('.', '/') + val tileEntityName = { + (try classOf[TileEntity] catch { + case _: Throwable => loader.findClass("net.minecraft.tileentity.TileEntity") // Dev env? + }).getName.replace('.', '/') + } def isTileEntity(classNode: ClassNode): Boolean = { classNode.name != "java/lang/Object" && (classNode.name == tileEntityName || isTileEntity(classNodeFor(classNode.superName))) diff --git a/src/main/java/li/cil/oc/common/block/Delegate.scala b/src/main/java/li/cil/oc/common/block/Delegate.scala index 626dc008f..d1eb0969d 100644 --- a/src/main/java/li/cil/oc/common/block/Delegate.scala +++ b/src/main/java/li/cil/oc/common/block/Delegate.scala @@ -35,6 +35,8 @@ trait Delegate { def drops(world: World, x: Int, y: Int, z: Int, fortune: Int): Option[java.util.ArrayList[ItemStack]] = None + def explosionResistance(entity: Entity, world: World, x: Int, y: Int, z: Int, explosionX: Double, explosionY: Double, explosionZ: Double): Float = parent.getExplosionResistance(entity) + def isNormalCube(world: World, x: Int, y: Int, z: Int) = true def validRotations(world: World, x: Int, y: Int, z: Int) = validRotations_ diff --git a/src/main/java/li/cil/oc/common/block/Delegator.scala b/src/main/java/li/cil/oc/common/block/Delegator.scala index 8cb97b590..511ae7a38 100644 --- a/src/main/java/li/cil/oc/common/block/Delegator.scala +++ b/src/main/java/li/cil/oc/common/block/Delegator.scala @@ -46,7 +46,7 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { subBlock(block.getMetadata(stack.getItemDamage)) case _ => None } - else None + else None def subBlock(world: IBlockAccess, x: Int, y: Int, z: Int): Option[Child] = if (world.getBlockId(x, y, z) == blockID) subBlock(world.getBlockMetadata(x, y, z)) @@ -134,6 +134,12 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { dropBlockAsItem_do(world, x, y, z, stack) } + override def getExplosionResistance(entity: Entity, world: World, x: Int, y: Int, z: Int, explosionX: Double, explosionY: Double, explosionZ: Double) = + subBlock(world, x, y, z) match { + case Some(subBlock) => subBlock.explosionResistance(entity, world, x, y, z, explosionX, explosionY, explosionZ) + case _ => super.getExplosionResistance(entity, world, x, y, z, explosionX, explosionY, explosionZ) + } + override def isBlockNormalCube(world: World, x: Int, y: Int, z: Int) = subBlock(world.getBlockMetadata(x, y, z)) match { case Some(subBlock) => subBlock.isNormalCube(world, x, y, z) diff --git a/src/main/java/li/cil/oc/common/block/RobotProxy.scala b/src/main/java/li/cil/oc/common/block/RobotProxy.scala index 6a7f8ce60..e901aa99d 100644 --- a/src/main/java/li/cil/oc/common/block/RobotProxy.scala +++ b/src/main/java/li/cil/oc/common/block/RobotProxy.scala @@ -8,7 +8,7 @@ import li.cil.oc.server.component.robot import li.cil.oc.util.Tooltip import li.cil.oc.{Blocks, Settings, OpenComputers} import net.minecraft.client.renderer.texture.IconRegister -import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.{Entity, EntityLivingBase} import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.{EnumRarity, ItemStack} import net.minecraft.util.{Icon, MovingObjectPosition, AxisAlignedBB, Vec3} @@ -71,6 +71,8 @@ class RobotProxy(val parent: SpecialDelegator) extends RedstoneAware with Specia // ----------------------------------------------------------------------- // + override def explosionResistance(entity: Entity, world: World, x: Int, y: Int, z: Int, explosionX: Double, explosionY: Double, explosionZ: Double) = 10f + override def isNormalCube(world: World, x: Int, y: Int, z: Int) = false override def isSolid(world: IBlockAccess, x: Int, y: Int, z: Int, side: ForgeDirection) = false diff --git a/src/main/java/li/cil/oc/common/component/Buffer.scala b/src/main/java/li/cil/oc/common/component/Buffer.scala index 97fc4daa0..9e028c53a 100644 --- a/src/main/java/li/cil/oc/common/component/Buffer.scala +++ b/src/main/java/li/cil/oc/common/component/Buffer.scala @@ -118,7 +118,8 @@ class Buffer(val owner: Buffer.Owner) extends api.network.Environment { buffer.load(nbt.getCompoundTag("buffer")) } - def save(nbt: NBTTagCompound) = { + // Null check for Waila (and other mods that may call this client side). + def save(nbt: NBTTagCompound) = if (node != null) { // Happy thread synchronization hack! Here's the problem: GPUs allow direct // calls for modifying screens to give a more responsive experience. This // causes the following problem: when saving, if the screen is saved first, diff --git a/src/main/java/li/cil/oc/common/tileentity/Case.scala b/src/main/java/li/cil/oc/common/tileentity/Case.scala index 973598b0f..da462b0bd 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Case.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Case.scala @@ -1,5 +1,6 @@ package li.cil.oc.common.tileentity +import cpw.mods.fml.relauncher.{SideOnly, Side} import li.cil.oc.Settings import li.cil.oc.api.driver import li.cil.oc.api.driver.Slot @@ -7,10 +8,16 @@ import li.cil.oc.server.driver.Registry import net.minecraft.entity.player.EntityPlayer import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.ForgeDirection class Case(var tier: Int, isRemote: Boolean) extends Computer(isRemote) { def this() = this(0, false) + @SideOnly(Side.CLIENT) + override protected def hasConnector(side: ForgeDirection) = side != facing + + override protected def connector(side: ForgeDirection) = Option(if (side != facing && computer != null) computer.node else null) + var maxComponents = 0 def recomputeMaxComponents() { diff --git a/src/main/java/li/cil/oc/common/tileentity/Environment.scala b/src/main/java/li/cil/oc/common/tileentity/Environment.scala index bb82a84a6..7a97508af 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Environment.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Environment.scala @@ -1,14 +1,71 @@ package li.cil.oc.common.tileentity +import cpw.mods.fml.common.Optional import li.cil.oc.Settings -import li.cil.oc.api.network.SidedEnvironment +import li.cil.oc.api.network.{Connector, SidedEnvironment} import li.cil.oc.api.{Network, network} import li.cil.oc.util.ExtendedNBT._ import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.ForgeDirection import scala.math.ScalaNumber +import universalelectricity.api.UniversalClass +import universalelectricity.api.energy.{IEnergyContainer, IEnergyInterface} +import cpw.mods.fml.relauncher.{Side, SideOnly} -abstract class Environment extends TileEntity with network.Environment { +// Because @UniversalClass injects custom invalidate and validate methods for +// IC2 setup/teardown we have to use a base class and implement our own logic +// in a child class. This also means we can't use the Environment base class, +// since mixins are linked up at compile time, whereas UniversalClass injects +// its methods at runtime. +@UniversalClass +@Optional.InterfaceList(Array( + new Optional.Interface(iface = "universalelectricity.api.energy.IEnergyInterface", modid = "UniversalElectricity"), + new Optional.Interface(iface = "universalelectricity.api.energy.IEnergyContainer", modid = "UniversalElectricity") +)) +abstract class PowerAcceptor extends TileEntity with network.Environment with IEnergyInterface with IEnergyContainer { + override def canConnect(direction: ForgeDirection, source: AnyRef) = + (if (isClient) hasConnector(direction) else connector(direction).isDefined) && + direction != null && direction != ForgeDirection.UNKNOWN + + override def onReceiveEnergy(from: ForgeDirection, receive: Long, doReceive: Boolean) = connector(from) match { + case Some(node) if !Settings.get.ignorePower => + val energy = fromUE(receive) + if (doReceive) { + val surplus = node.changeBuffer(energy) + receive - toUE(surplus) + } + else { + val space = node.globalBufferSize - node.globalBuffer + math.min(receive, toUE(space)) + } + case _ => 0 + } + + override def onExtractEnergy(from: ForgeDirection, extract: Long, doExtract: Boolean) = 0 + + override def setEnergy(from: ForgeDirection, energy: Long) {} + + override def getEnergy(from: ForgeDirection) = connector(from) match { + case Some(node) => toUE(node.globalBuffer) + case _ => 0 + } + + override def getEnergyCapacity(from: ForgeDirection) = connector(from) match { + case Some(node) => toUE(node.globalBufferSize) + case _ => 0 + } + + protected def toUE(energy: Double) = (energy * Settings.ratioBC).toLong + + protected def fromUE(energy: Long) = energy / Settings.ratioBC + + @SideOnly(Side.CLIENT) + protected def hasConnector(side: ForgeDirection) = false + + protected def connector(side: ForgeDirection): Option[Connector] = None +} + +abstract class Environment extends PowerAcceptor { protected var addedToNetwork = false // ----------------------------------------------------------------------- // diff --git a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala index e7770e6ca..b57429bca 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Hologram.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Hologram.scala @@ -60,6 +60,7 @@ class Hologram extends Environment with SidedEnvironment { // ----------------------------------------------------------------------- // + @SideOnly(Side.CLIENT) override def canConnect(side: ForgeDirection) = side != ForgeDirection.UP override def sidedNode(side: ForgeDirection) = node diff --git a/src/main/java/li/cil/oc/common/tileentity/Hub.scala b/src/main/java/li/cil/oc/common/tileentity/Hub.scala index 69ede28ce..050950416 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Hub.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Hub.scala @@ -17,7 +17,7 @@ trait Hub extends Environment with SidedEnvironment { @SideOnly(Side.CLIENT) override def canConnect(side: ForgeDirection) = true - override def sidedNode(side: ForgeDirection) = plugs(side.ordinal()).node + override def sidedNode(side: ForgeDirection) = if (side != ForgeDirection.UNKNOWN) plugs(side.ordinal()).node else null // ----------------------------------------------------------------------- // @@ -30,11 +30,14 @@ trait Hub extends Environment with SidedEnvironment { override def writeToNBT(nbt: NBTTagCompound) { super.writeToNBT(nbt) - nbt.setNewTagList(Settings.namespace + "plugs", plugs.map(plug => { - val plugNbt = new NBTTagCompound() - plug.node.save(plugNbt) - plugNbt - })) + // Side check for Waila (and other mods that may call this client side). + if (isServer) { + nbt.setNewTagList(Settings.namespace + "plugs", plugs.map(plug => { + val plugNbt = new NBTTagCompound() + plug.node.save(plugNbt) + plugNbt + })) + } } // ----------------------------------------------------------------------- // diff --git a/src/main/java/li/cil/oc/common/tileentity/PowerConverter.scala b/src/main/java/li/cil/oc/common/tileentity/PowerConverter.scala index 7eea67c4b..e5764274a 100644 --- a/src/main/java/li/cil/oc/common/tileentity/PowerConverter.scala +++ b/src/main/java/li/cil/oc/common/tileentity/PowerConverter.scala @@ -1,113 +1,20 @@ package li.cil.oc.common.tileentity -import cpw.mods.fml.common.Optional +import cpw.mods.fml.relauncher.{SideOnly, Side} import li.cil.oc.api.network._ -import li.cil.oc.api.{Network, network} -import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.{Settings, api} import net.minecraft.entity.player.EntityPlayer -import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.ForgeDirection -import universalelectricity.api.UniversalClass -import universalelectricity.api.energy.{IEnergyContainer, IEnergyInterface} -// Because @UniversalClass injects custom invalidate and validate methods for -// IC2 setup/teardown we have to use a base class and implement our own logic -// in a child class. This also means we can't use the Environment base class, -// since mixins are linked up at compile time, whereas UniversalClass injects -// its methods at runtime. -@UniversalClass -@Optional.InterfaceList(Array( - new Optional.Interface(iface = "universalelectricity.api.energy.IEnergyInterface", modid = "UniversalElectricity"), - new Optional.Interface(iface = "universalelectricity.api.energy.IEnergyContainer", modid = "UniversalElectricity") -)) -abstract class PowerConverterBase extends TileEntity with network.Environment with IEnergyInterface with IEnergyContainer { - override def node: Connector - - def canConnect(direction: ForgeDirection) = direction != null && direction != ForgeDirection.UNKNOWN - - override def canConnect(direction: ForgeDirection, source: AnyRef) = canConnect(direction) - - override def onReceiveEnergy(from: ForgeDirection, receive: Long, doReceive: Boolean) = { - if (!Settings.get.ignorePower && node != null) { - val energy = fromUE(receive) - if (doReceive) { - val surplus = node.changeBuffer(energy) - receive - toUE(surplus) - } - else { - val space = node.globalBufferSize - node.globalBuffer - math.min(receive, toUE(space)) - } - } - else 0 - } - - override def onExtractEnergy(from: ForgeDirection, extract: Long, doExtract: Boolean) = 0 - - override def setEnergy(from: ForgeDirection, energy: Long) {} - - override def getEnergy(from: ForgeDirection) = if (node != null) toUE(node.globalBuffer) else 0 - - override def getEnergyCapacity(from: ForgeDirection) = if (node != null) toUE(node.globalBufferSize) else Long.MaxValue - - protected def toUE(energy: Double) = (energy * Settings.ratioBC).toLong - - protected def fromUE(energy: Long) = energy / Settings.ratioBC -} - -class PowerConverter extends PowerConverterBase with Analyzable { +class PowerConverter extends Environment with Analyzable { val node = api.Network.newNode(this, Visibility.Network). withConnector(Settings.get.bufferConverter). create() - protected var addedToNetwork = false + @SideOnly(Side.CLIENT) + override protected def hasConnector(side: ForgeDirection) = true - // ----------------------------------------------------------------------- // + override protected def connector(side: ForgeDirection) = Option(node) override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = null - - // ----------------------------------------------------------------------- // - - override def updateEntity() { - super.updateEntity() - if (!addedToNetwork) { - addedToNetwork = true - Network.joinOrCreateNetwork(this) - } - } - - override def onChunkUnload() { - super.onChunkUnload() - Option(node).foreach(_.remove) - } - - override def invalidate() { - super.invalidate() - Option(node).foreach(_.remove) - } - - // ----------------------------------------------------------------------- // - - override def readFromNBT(nbt: NBTTagCompound) { - super.readFromNBT(nbt) - if (node != null) { - node.load(nbt.getCompoundTag(Settings.namespace + "node")) - } - } - - override def writeToNBT(nbt: NBTTagCompound) { - super.writeToNBT(nbt) - if (node != null) { - nbt.setNewCompoundTag(Settings.namespace + "node", node.save) - } - } - - // ----------------------------------------------------------------------- // - - override def onMessage(message: network.Message) {} - - override def onConnect(node: network.Node) {} - - override def onDisconnect(node: network.Node) {} } diff --git a/src/main/java/li/cil/oc/common/tileentity/PowerDistributor.scala b/src/main/java/li/cil/oc/common/tileentity/PowerDistributor.scala index eda2ae94f..16daea9db 100644 --- a/src/main/java/li/cil/oc/common/tileentity/PowerDistributor.scala +++ b/src/main/java/li/cil/oc/common/tileentity/PowerDistributor.scala @@ -36,10 +36,13 @@ class PowerDistributor extends Environment with PowerBalancer with Analyzable { override def writeToNBT(nbt: NBTTagCompound) { super.writeToNBT(nbt) - nbt.setNewTagList(Settings.namespace + "connector", nodes.map(connector => { - val connectorNbt = new NBTTagCompound() - connector.save(connectorNbt) - connectorNbt - })) + // Side check for Waila (and other mods that may call this client side). + if (isServer) { + nbt.setNewTagList(Settings.namespace + "connector", nodes.map(connector => { + val connectorNbt = new NBTTagCompound() + connector.save(connectorNbt) + connectorNbt + })) + } } } diff --git a/src/main/java/li/cil/oc/common/tileentity/Rack.scala b/src/main/java/li/cil/oc/common/tileentity/Rack.scala index f98146a59..0f29aa9b8 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Rack.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Rack.scala @@ -36,6 +36,11 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun // For client side rendering. var isPresent = Array.fill[Option[String]](getSizeInventory)(None) + @SideOnly(Side.CLIENT) + override protected def hasConnector(side: ForgeDirection) = side != facing + + override protected def connector(side: ForgeDirection) = Option(if (side != facing) sidedNode(side).asInstanceOf[Connector] else null) + // ----------------------------------------------------------------------- // override def canConnect(side: ForgeDirection) = side != facing @@ -220,7 +225,8 @@ class Rack extends Hub with PowerBalancer with Inventory with Rotatable with Bun range = nbt.getInteger(Settings.namespace + "range") } - override def writeToNBT(nbt: NBTTagCompound) { + // Side check for Waila (and other mods that may call this client side). + override def writeToNBT(nbt: NBTTagCompound) = if (isServer) { if (!new Exception().getStackTrace.exists(_.getClassName.startsWith("mcp.mobius.waila"))) { nbt.setNewTagList(Settings.namespace + "servers", servers map { case Some(server) => diff --git a/src/main/java/li/cil/oc/common/tileentity/Robot.scala b/src/main/java/li/cil/oc/common/tileentity/Robot.scala index 054811d5b..8ebdcda6c 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Robot.scala @@ -338,7 +338,8 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w } } - override def writeToNBT(nbt: NBTTagCompound) = this.synchronized { + // Side check for Waila (and other mods that may call this client side). + override def writeToNBT(nbt: NBTTagCompound) = if (isServer) this.synchronized { // Note: computer is saved when proxy is saved (in proxy's super writeToNBT) // which is a bit ugly, and may be refactored some day, but it works. nbt.setNewCompoundTag(Settings.namespace + "buffer", buffer.save) diff --git a/src/main/java/li/cil/oc/server/component/Server.scala b/src/main/java/li/cil/oc/server/component/Server.scala index 24062b99c..5a4aed594 100644 --- a/src/main/java/li/cil/oc/server/component/Server.scala +++ b/src/main/java/li/cil/oc/server/component/Server.scala @@ -26,9 +26,9 @@ class Server(val rack: tileentity.Rack, val number: Int) extends Machine.Owner { // ----------------------------------------------------------------------- // - override def address() = machine.node.address + override def address = machine.node.address - override def node() = machine.node + override def node = machine.node override def start() = machine.start() diff --git a/src/main/java/li/cil/oc/server/fs/Capacity.scala b/src/main/java/li/cil/oc/server/fs/Capacity.scala index f0a9d2fdd..3e39e005b 100644 --- a/src/main/java/li/cil/oc/server/fs/Capacity.scala +++ b/src/main/java/li/cil/oc/server/fs/Capacity.scala @@ -78,6 +78,9 @@ trait Capacity extends OutputStreamFileSystem { case None => None case Some(stream) => used += delta + if (mode == Mode.Append) { + stream.seek(stream.length()) + } Some(new CountingOutputHandle(this, stream)) } } diff --git a/src/main/java/li/cil/oc/server/fs/FileOutputStreamFileSystem.scala b/src/main/java/li/cil/oc/server/fs/FileOutputStreamFileSystem.scala index 0e43ddc0f..de1eaa9a6 100644 --- a/src/main/java/li/cil/oc/server/fs/FileOutputStreamFileSystem.scala +++ b/src/main/java/li/cil/oc/server/fs/FileOutputStreamFileSystem.scala @@ -23,8 +23,7 @@ trait FileOutputStreamFileSystem extends FileInputStreamFileSystem with OutputSt override protected def openOutputHandle(id: Int, path: String, mode: Mode): Option[OutputHandle] = Some(new FileHandle(new RandomAccessFile(new io.File(root, path), mode match { - case Mode.Append => "a" - case Mode.Write => "w" + case Mode.Append | Mode.Write => "rw" case _ => throw new IllegalArgumentException() }), this, id, path)) diff --git a/src/main/java/li/cil/oc/util/LuaStateFactory.scala b/src/main/java/li/cil/oc/util/LuaStateFactory.scala index 19722d9cf..6c3066800 100644 --- a/src/main/java/li/cil/oc/util/LuaStateFactory.scala +++ b/src/main/java/li/cil/oc/util/LuaStateFactory.scala @@ -86,14 +86,16 @@ 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'm afraid you'll have to use a newer Windows. I very much recommend upgrading your Windows, anyway, since Microsoft will stop supporting Windows XP in April 2014.") - break() - } + if (isWindows && !Settings.get.alwaysTryNative) { + if (SystemUtils.IS_OS_WINDOWS_XP) { + OpenComputers.log.warning("Sorry, but Windows XP isn't supported. I'm afraid you'll have to use a newer Windows. I very much recommend upgrading your Windows, anyway, since Microsoft will stop supporting Windows XP in April 2014.") + break() + } - if (isWindows && SystemUtils.IS_OS_WINDOWS_2003) { - OpenComputers.log.warning("Sorry, but Windows Server 2003 isn't supported. I'm afraid you'll have to use a newer Windows.") - break() + if (SystemUtils.IS_OS_WINDOWS_2003) { + OpenComputers.log.warning("Sorry, but Windows Server 2003 isn't supported. I'm afraid you'll have to use a newer Windows.") + break() + } } val tmpPath = { diff --git a/src/main/resources/reference.conf b/src/main/resources/reference.conf index a7402249c..06994c155 100644 --- a/src/main/resources/reference.conf +++ b/src/main/resources/reference.conf @@ -689,5 +689,13 @@ opencomputers { # if a new version is available (contacts Github once the first player # joins a server / the first map in single player is opened). updateCheck: true + + # On some platforms the native library can crash the game, so there are + # a few checks in place to avoid trying to load it in those cases. This + # is Windows XP and Windows Server 2003, right. If you think it might + # work nonetheless (never builds of Server2k3 e.g.) you might want to + # try setting this to `true`. Use this at your own risk. If the game + # crashes as a result of setting this to `true` DO NOT REPORT IT. + alwaysTryNative: false } } \ No newline at end of file