This commit is contained in:
Florian Nücke 2014-03-02 18:30:55 +01:00
commit 61f744dcb9
19 changed files with 155 additions and 138 deletions

View File

@ -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 {

View File

@ -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)))

View File

@ -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_

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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() {

View File

@ -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
// ----------------------------------------------------------------------- //

View File

@ -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

View File

@ -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
}))
}
}
// ----------------------------------------------------------------------- //

View File

@ -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) {}
}

View File

@ -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
}))
}
}
}

View File

@ -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) =>

View File

@ -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)

View File

@ -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()

View File

@ -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))
}
}

View File

@ -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))

View File

@ -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 = {

View File

@ -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
}
}