Added IC2 classic power support.

Switched things around a bit, power traits don't implement their interfaces by default now, instead they get injected by the class transformer if the power mod is present to avoid class not found errors in conjunction with interface stripping seemingly getting confused by Scala's synthetic classes.
This commit is contained in:
Florian Nücke 2014-08-02 19:32:45 +02:00
parent 1538fb2586
commit d5012a6873
17 changed files with 176 additions and 70 deletions

Binary file not shown.

BIN
libs/factorization-api.zip Normal file

Binary file not shown.

BIN
libs/ic2classic-api.zip Normal file

Binary file not shown.

View File

@ -121,13 +121,7 @@ class Settings(config: Config) {
// power
val pureIgnorePower = config.getBoolean("power.ignorePower")
val ignorePower = pureIgnorePower ||
(!Mods.BuildCraftPower.isAvailable &&
!Mods.Factorization.isAvailable &&
!Mods.IndustrialCraft2.isAvailable &&
!Mods.Mekanism.isAvailable &&
!Mods.ThermalExpansion.isAvailable &&
!Mods.UniversalElectricity.isAvailable)
val ignorePower = pureIgnorePower || !Mods.isPowerProvidingModPresent
val tickFrequency = config.getDouble("power.tickFrequency") max 1
val chargeRate = config.getDouble("power.chargerChargeRate")
val generatorEfficiency = config.getDouble("power.generatorEfficiency")

View File

@ -5,7 +5,6 @@ import java.util.logging.Level
import cpw.mods.fml.common._
import cpw.mods.fml.common.network.{IConnectionHandler, Player}
import ic2.api.energy.event.{EnergyTileLoadEvent, EnergyTileUnloadEvent}
import li.cil.oc._
import li.cil.oc.api.Network
import li.cil.oc.client.renderer.PetRenderer
@ -43,21 +42,41 @@ object EventHandler extends ITickHandler with IConnectionHandler with ICraftingH
}
@Optional.Method(modid = Mods.IDs.IndustrialCraft2)
def scheduleIC2Add(tileEntity: power.IndustrialCraft2) {
def scheduleIC2Add(tileEntity: power.IndustrialCraft2Experimental) {
if (SideTracker.isServer) pending.synchronized {
pending += (() => if (!tileEntity.addedToPowerGrid && !tileEntity.isInvalid) {
MinecraftForge.EVENT_BUS.post(new EnergyTileLoadEvent(tileEntity))
tileEntity.addedToPowerGrid = true
pending += (() => if (!tileEntity.addedToIC2PowerGrid && !tileEntity.isInvalid) {
MinecraftForge.EVENT_BUS.post(new ic2.api.energy.event.EnergyTileLoadEvent(tileEntity.asInstanceOf[ic2.api.energy.tile.IEnergyTile]))
tileEntity.addedToIC2PowerGrid = true
})
}
}
@Optional.Method(modid = Mods.IDs.IndustrialCraft2)
def scheduleIC2Remove(tileEntity: power.IndustrialCraft2) {
def scheduleIC2Remove(tileEntity: power.IndustrialCraft2Experimental) {
if (SideTracker.isServer) pending.synchronized {
pending += (() => if (tileEntity.addedToPowerGrid) {
MinecraftForge.EVENT_BUS.post(new EnergyTileUnloadEvent(tileEntity))
tileEntity.addedToPowerGrid = false
pending += (() => if (tileEntity.addedToIC2PowerGrid) {
MinecraftForge.EVENT_BUS.post(new ic2.api.energy.event.EnergyTileUnloadEvent(tileEntity.asInstanceOf[ic2.api.energy.tile.IEnergyTile]))
tileEntity.addedToIC2PowerGrid = false
})
}
}
@Optional.Method(modid = Mods.IDs.IndustrialCraft2Classic)
def scheduleIC2Add(tileEntity: power.IndustrialCraft2Classic) {
if (SideTracker.isServer) pending.synchronized {
pending += (() => if (!tileEntity.addedToIC2PowerGrid && !tileEntity.isInvalid) {
MinecraftForge.EVENT_BUS.post(new ic2classic.api.energy.event.EnergyTileLoadEvent(tileEntity.asInstanceOf[ic2classic.api.energy.tile.IEnergyTile]))
tileEntity.addedToIC2PowerGrid = true
})
}
}
@Optional.Method(modid = Mods.IDs.IndustrialCraft2Classic)
def scheduleIC2Remove(tileEntity: power.IndustrialCraft2Classic) {
if (SideTracker.isServer) pending.synchronized {
pending += (() => if (tileEntity.addedToIC2PowerGrid) {
MinecraftForge.EVENT_BUS.post(new ic2classic.api.energy.event.EnergyTileUnloadEvent(tileEntity.asInstanceOf[ic2classic.api.energy.tile.IEnergyTile]))
tileEntity.addedToIC2PowerGrid = false
})
}
}

View File

@ -5,6 +5,7 @@ import java.util.logging.{Level, Logger}
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper
import li.cil.oc.common.asm.template.SimpleComponentImpl
import li.cil.oc.util.mods.Mods
import li.cil.oc.util.mods.Mods.Mod
import net.minecraft.launchwrapper.{IClassTransformer, LaunchClassLoader}
import org.objectweb.asm.tree._
import org.objectweb.asm.{ClassReader, ClassWriter, Opcodes}
@ -13,9 +14,19 @@ import scala.collection.convert.WrapAsJava._
import scala.collection.convert.WrapAsScala._
class ClassTransformer extends IClassTransformer {
val loader = classOf[ClassTransformer].getClassLoader.asInstanceOf[LaunchClassLoader]
private val loader = classOf[ClassTransformer].getClassLoader.asInstanceOf[LaunchClassLoader]
val log = Logger.getLogger("OpenComputers")
private val log = Logger.getLogger("OpenComputers")
private lazy val powerTypes = Map[Mod, Array[String]](
Mods.BuildCraftPower -> Array("buildcraft/api/power/IPowerReceptor"),
Mods.Factorization -> Array("factorization/api/IChargeConductor"),
Mods.IndustrialCraft2 -> Array("ic2/api/energy/tile/IEnergySink"),
Mods.IndustrialCraft2Classic -> Array("ic2classic/api/energy/tile/IEnergySink"),
Mods.Mekanism -> Array("mekanism/api/energy/IStrictEnergyAcceptor"),
Mods.ThermalExpansion -> Array("cofh/api/energy/IEnergyHandler"),
Mods.UniversalElectricity -> Array("universalelectricity/api/energy/IEnergyInterface", "universalelectricity/api/energy/IEnergyContainer")
)
override def transform(name: String, transformedName: String, basicClass: Array[Byte]): Array[Byte] = {
var transformedClass = basicClass
@ -50,6 +61,14 @@ class ClassTransformer extends IClassTransformer {
log.fine(s"Stripping method ${method.name} from class $name because the following types in its signature are missing: $missing")
}
classNode.methods.removeAll(incompleteMethods)
// Inject available power interfaces into power acceptors.
if (classNode.interfaces.contains("li/cil/oc/common/tileentity/traits/PowerAcceptor")) {
for ((mod, interfaces) <- powerTypes if mod.isAvailable) {
interfaces.foreach(classNode.interfaces.add)
}
}
transformedClass = writeClass(classNode)
}
{

View File

@ -46,7 +46,7 @@ class PowerConverter(val parent: SimpleDelegator) extends SimpleDelegate {
if (Mods.Factorization.isAvailable) {
addRatio("Factorization", Settings.ratioFactorization)
}
if (Mods.IndustrialCraft2.isAvailable) {
if (Mods.IndustrialCraft2.isAvailable || Mods.IndustrialCraft2Classic.isAvailable) {
addRatio("IndustrialCraft2", Settings.ratioIndustrialCraft2)
}
if (Mods.Mekanism.isAvailable) {

View File

@ -4,7 +4,8 @@ trait PowerAcceptor
extends power.Common
with power.BuildCraft
with power.Factorization
with power.IndustrialCraft2
with power.IndustrialCraft2Experimental
with power.IndustrialCraft2Classic
with power.Mekanism
with power.ThermalExpansion
with power.UniversalElectricity

View File

@ -6,8 +6,7 @@ import li.cil.oc.Settings
import li.cil.oc.util.mods.Mods
import net.minecraftforge.common.ForgeDirection
@Optional.Interface(iface = "buildcraft.api.power.IPowerReceptor", modid = Mods.IDs.BuildCraftPower)
trait BuildCraft extends Common with IPowerReceptor {
trait BuildCraft extends Common {
private var powerHandler: Option[AnyRef] = None
private lazy val useBuildCraftPower = isServer && !Settings.get.ignorePower && Mods.BuildCraftPower.isAvailable
@ -32,7 +31,7 @@ trait BuildCraft extends Common with IPowerReceptor {
@Optional.Method(modid = Mods.IDs.BuildCraftPower)
def getPowerProvider = {
if (powerHandler.isEmpty) {
val handler = new PowerHandler(this, PowerHandler.Type.MACHINE)
val handler = new PowerHandler(this.asInstanceOf[IPowerReceptor], PowerHandler.Type.MACHINE)
if (handler != null) {
handler.configure(1, 320, Float.MaxValue, 640)
handler.configurePowerPerdition(0, 0)

View File

@ -6,9 +6,9 @@ import li.cil.oc.Settings
import li.cil.oc.util.mods.Mods
import net.minecraftforge.common.ForgeDirection
@Optional.Interface(iface = "factorization.api.IChargeConductor", modid = Mods.IDs.Factorization)
trait Factorization extends Common with IChargeConductor {
private lazy val charge: AnyRef = new Charge(this)
trait Factorization extends Common {
@Optional.Method(modid = Mods.IDs.Factorization)
private lazy val charge: AnyRef = new Charge(this.asInstanceOf[IChargeConductor])
private lazy val useFactorizationPower = isServer && !Settings.get.ignorePower && Mods.Factorization.isAvailable
@ -45,11 +45,11 @@ trait Factorization extends Common with IChargeConductor {
// ----------------------------------------------------------------------- //
@Optional.Method(modid = Mods.IDs.Factorization)
override def getCharge = charge.asInstanceOf[Charge]
def getCharge = charge.asInstanceOf[Charge]
@Optional.Method(modid = Mods.IDs.Factorization)
override def getInfo = ""
def getInfo = ""
@Optional.Method(modid = Mods.IDs.Factorization)
override def getCoord = new Coord(this)
def getCoord = new Coord(this)
}

View File

@ -0,0 +1,71 @@
package li.cil.oc.common.tileentity.traits.power
import cpw.mods.fml.common.Optional
import ic2classic.api.Direction
import li.cil.oc.Settings
import li.cil.oc.common.EventHandler
import li.cil.oc.util.mods.Mods
import net.minecraft.tileentity.TileEntity
import net.minecraftforge.common.ForgeDirection
trait IndustrialCraft2Classic extends Common with IndustrialCraft2Common {
private var lastInjectedAmount = 0.0
private lazy val useIndustrialCraft2ClassicPower = isServer && !Settings.get.ignorePower && Mods.IndustrialCraft2Classic.isAvailable
// ----------------------------------------------------------------------- //
override def validate() {
super.validate()
if (useIndustrialCraft2ClassicPower && !addedToIC2PowerGrid) EventHandler.scheduleIC2Add(this)
}
override def invalidate() {
super.invalidate()
if (useIndustrialCraft2ClassicPower && addedToIC2PowerGrid) EventHandler.scheduleIC2Remove(this)
}
override def onChunkUnload() {
super.onChunkUnload()
if (useIndustrialCraft2ClassicPower && addedToIC2PowerGrid) EventHandler.scheduleIC2Remove(this)
}
// ----------------------------------------------------------------------- //
@Optional.Method(modid = Mods.IDs.IndustrialCraft2Classic)
def isAddedToEnergyNet = addedToIC2PowerGrid
@Optional.Method(modid = Mods.IDs.IndustrialCraft2Classic)
def acceptsEnergyFrom(emitter: TileEntity, direction: Direction) = canConnectPower(direction.toForgeDirection)
@Optional.Method(modid = Mods.IDs.IndustrialCraft2Classic)
def injectEnergy(directionFrom: Direction, amount: Int) = {
lastInjectedAmount = amount
var energy = amount * Settings.ratioIndustrialCraft2
// Work around IC2 being uncooperative and always just passing 'unknown' along here.
if (directionFrom.toForgeDirection == ForgeDirection.UNKNOWN) {
for (side <- ForgeDirection.VALID_DIRECTIONS if energy > 0) {
energy -= tryChangeBuffer(side, energy)
}
(energy / Settings.ratioIndustrialCraft2).toInt
}
else (amount - tryChangeBuffer(directionFrom.toForgeDirection, energy) / Settings.ratioIndustrialCraft2).toInt
}
@Optional.Method(modid = Mods.IDs.IndustrialCraft2Classic)
def demandsEnergy = {
if (Settings.get.ignorePower || isClient) 0
else {
var force = false
val demand = ForgeDirection.VALID_DIRECTIONS.map(side => {
val size = globalBufferSize(side)
val value = globalBuffer(side)
val space = size - value
force = force || (space > size / 2)
space
}).max / Settings.ratioIndustrialCraft2
if (force || lastInjectedAmount <= 0 || demand >= lastInjectedAmount) demand.toInt
else 0
}
}
}

View File

@ -0,0 +1,7 @@
package li.cil.oc.common.tileentity.traits.power
trait IndustrialCraft2Common {
var addedToIC2PowerGrid = false
def getMaxSafeInput = Integer.MAX_VALUE
}

View File

@ -1,16 +1,12 @@
package li.cil.oc.common.tileentity.traits.power
import cpw.mods.fml.common.Optional
import ic2.api.energy.tile.IEnergySink
import li.cil.oc.Settings
import li.cil.oc.common.EventHandler
import li.cil.oc.util.mods.Mods
import net.minecraftforge.common.ForgeDirection
@Optional.Interface(iface = "ic2.api.energy.tile.IEnergySink", modid = Mods.IDs.IndustrialCraft2)
trait IndustrialCraft2 extends Common with IEnergySink {
var addedToPowerGrid = false
trait IndustrialCraft2Experimental extends Common with IndustrialCraft2Common {
private var lastInjectedAmount = 0.0
private lazy val useIndustrialCraft2Power = isServer && !Settings.get.ignorePower && Mods.IndustrialCraft2.isAvailable
@ -19,17 +15,17 @@ trait IndustrialCraft2 extends Common with IEnergySink {
override def validate() {
super.validate()
if (useIndustrialCraft2Power && !addedToPowerGrid) EventHandler.scheduleIC2Add(this)
if (useIndustrialCraft2Power && !addedToIC2PowerGrid) EventHandler.scheduleIC2Add(this)
}
override def invalidate() {
super.invalidate()
if (useIndustrialCraft2Power && addedToPowerGrid) EventHandler.scheduleIC2Remove(this)
if (useIndustrialCraft2Power && addedToIC2PowerGrid) EventHandler.scheduleIC2Remove(this)
}
override def onChunkUnload() {
super.onChunkUnload()
if (useIndustrialCraft2Power && addedToPowerGrid) EventHandler.scheduleIC2Remove(this)
if (useIndustrialCraft2Power && addedToIC2PowerGrid) EventHandler.scheduleIC2Remove(this)
}
// ----------------------------------------------------------------------- //
@ -51,9 +47,6 @@ trait IndustrialCraft2 extends Common with IEnergySink {
else amount - tryChangeBuffer(directionFrom, energy) / Settings.ratioIndustrialCraft2
}
@Optional.Method(modid = Mods.IDs.IndustrialCraft2)
def getMaxSafeInput = Integer.MAX_VALUE
@Optional.Method(modid = Mods.IDs.IndustrialCraft2)
def demandedEnergyUnits = {
if (Settings.get.ignorePower || isClient) 0

View File

@ -3,23 +3,21 @@ package li.cil.oc.common.tileentity.traits.power
import cpw.mods.fml.common.Optional
import li.cil.oc.Settings
import li.cil.oc.util.mods.Mods
import mekanism.api.energy.IStrictEnergyAcceptor
import net.minecraftforge.common.ForgeDirection
@Optional.Interface(iface = "mekanism.api.energy.IStrictEnergyAcceptor", modid = Mods.IDs.Mekanism)
trait Mekanism extends Common with IStrictEnergyAcceptor {
trait Mekanism extends Common {
@Optional.Method(modid = Mods.IDs.Mekanism)
override def canReceiveEnergy(side: ForgeDirection) = canConnectPower(side)
def canReceiveEnergy(side: ForgeDirection) = canConnectPower(side)
@Optional.Method(modid = Mods.IDs.Mekanism)
override def transferEnergyToAcceptor(side: ForgeDirection, amount: Double) = tryChangeBuffer(side, amount * Settings.ratioMekanism) / Settings.ratioMekanism
def transferEnergyToAcceptor(side: ForgeDirection, amount: Double) = tryChangeBuffer(side, amount * Settings.ratioMekanism) / Settings.ratioMekanism
@Optional.Method(modid = Mods.IDs.Mekanism)
override def getMaxEnergy = ForgeDirection.VALID_DIRECTIONS.map(globalBufferSize).max / Settings.ratioMekanism
def getMaxEnergy = ForgeDirection.VALID_DIRECTIONS.map(globalBufferSize).max / Settings.ratioMekanism
@Optional.Method(modid = Mods.IDs.Mekanism)
override def getEnergy = ForgeDirection.VALID_DIRECTIONS.map(globalBuffer).max / Settings.ratioMekanism
def getEnergy = ForgeDirection.VALID_DIRECTIONS.map(globalBuffer).max / Settings.ratioMekanism
@Optional.Method(modid = Mods.IDs.Mekanism)
override def setEnergy(energy: Double) {}
def setEnergy(energy: Double) {}
}

View File

@ -1,13 +1,11 @@
package li.cil.oc.common.tileentity.traits.power
import cofh.api.energy.IEnergyHandler
import cpw.mods.fml.common.Optional
import li.cil.oc.Settings
import li.cil.oc.util.mods.Mods
import net.minecraftforge.common.ForgeDirection
@Optional.Interface(iface = "cofh.api.energy.IEnergyHandler", modid = Mods.IDs.ThermalExpansion)
trait ThermalExpansion extends Common with IEnergyHandler {
trait ThermalExpansion extends Common {
@Optional.Method(modid = Mods.IDs.ThermalExpansion)
def canInterface(from: ForgeDirection) = canConnectPower(from)

View File

@ -4,29 +4,24 @@ import cpw.mods.fml.common.Optional
import li.cil.oc.Settings
import li.cil.oc.util.mods.Mods
import net.minecraftforge.common.ForgeDirection
import universalelectricity.api.energy.{IEnergyContainer, IEnergyInterface}
@Optional.InterfaceList(Array(
new Optional.Interface(iface = "universalelectricity.api.energy.IEnergyInterface", modid = Mods.IDs.UniversalElectricity),
new Optional.Interface(iface = "universalelectricity.api.energy.IEnergyContainer", modid = Mods.IDs.UniversalElectricity)
))
trait UniversalElectricity extends Common with IEnergyInterface with IEnergyContainer {
trait UniversalElectricity extends Common {
@Optional.Method(modid = Mods.IDs.UniversalElectricity)
override def canConnect(direction: ForgeDirection, source: AnyRef) = canConnectPower(direction)
def canConnect(direction: ForgeDirection, source: AnyRef) = canConnectPower(direction)
@Optional.Method(modid = Mods.IDs.UniversalElectricity)
override def onReceiveEnergy(from: ForgeDirection, receive: Long, doReceive: Boolean) =
def onReceiveEnergy(from: ForgeDirection, receive: Long, doReceive: Boolean) =
(tryChangeBuffer(from, receive * Settings.ratioUniversalElectricity, doReceive) / Settings.ratioUniversalElectricity).toLong
@Optional.Method(modid = Mods.IDs.UniversalElectricity)
override def getEnergy(from: ForgeDirection) = (globalBuffer(from) / Settings.ratioUniversalElectricity).toLong
def getEnergy(from: ForgeDirection) = (globalBuffer(from) / Settings.ratioUniversalElectricity).toLong
@Optional.Method(modid = Mods.IDs.UniversalElectricity)
override def getEnergyCapacity(from: ForgeDirection) = (globalBufferSize(from) / Settings.ratioUniversalElectricity).toLong
def getEnergyCapacity(from: ForgeDirection) = (globalBufferSize(from) / Settings.ratioUniversalElectricity).toLong
@Optional.Method(modid = Mods.IDs.UniversalElectricity)
override def onExtractEnergy(from: ForgeDirection, extract: Long, doExtract: Boolean) = 0
def onExtractEnergy(from: ForgeDirection, extract: Long, doExtract: Boolean) = 0
@Optional.Method(modid = Mods.IDs.UniversalElectricity)
override def setEnergy(from: ForgeDirection, energy: Long) {}
def setEnergy(from: ForgeDirection, energy: Long) {}
}

View File

@ -3,6 +3,8 @@ package li.cil.oc.util.mods
import cpw.mods.fml.common.versioning.VersionParser
import cpw.mods.fml.common.{Loader, ModAPIManager}
import scala.collection.mutable
object Mods {
object IDs {
@ -13,6 +15,7 @@ object Mods {
final val ForgeMultipart = "ForgeMultipart"
final val GregTech = "gregtech_addon"
final val IndustrialCraft2 = "IC2"
final val IndustrialCraft2Classic = "IC2-Classic"
final val Mekanism = "Mekanism"
final val MineFactoryReloaded = "MineFactoryReloaded"
final val NotEnoughItems = "NotEnoughItems"
@ -28,8 +31,12 @@ object Mods {
final val WirelessRedstoneSV = "WirelessRedstoneCore"
}
private val knownMods = mutable.ArrayBuffer.empty[Mod]
lazy val isPowerProvidingModPresent = knownMods.exists(_.providesPower)
val BattleGear2 = new SimpleMod(IDs.BattleGear2)
val BuildCraftPower = new SimpleMod(IDs.BuildCraftPower)
val BuildCraftPower = new SimpleMod(IDs.BuildCraftPower, providesPower = true)
val ComputerCraft15 = new SimpleMod(IDs.ComputerCraft) {
override val isAvailable = isModLoaded && (try Class.forName("dan200.computer.api.ComputerCraftAPI") != null catch {
case _: Throwable => false
@ -43,11 +50,12 @@ object Mods {
val ComputerCraft = new Mod {
override def isAvailable = ComputerCraft15.isAvailable || ComputerCraft16.isAvailable
}
val Factorization = new SimpleMod(IDs.Factorization)
val Factorization = new SimpleMod(IDs.Factorization, providesPower = true)
val ForgeMultipart = new SimpleMod(IDs.ForgeMultipart)
val GregTech = new SimpleMod(IDs.GregTech)
val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2)
val Mekanism = new SimpleMod(IDs.Mekanism)
val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2, providesPower = true)
val IndustrialCraft2Classic = new SimpleMod(IDs.IndustrialCraft2Classic, providesPower = true)
val Mekanism = new SimpleMod(IDs.Mekanism, providesPower = true)
val MineFactoryReloaded = new SimpleMod(IDs.MineFactoryReloaded)
val NotEnoughItems = new SimpleMod(IDs.NotEnoughItems)
val PortalGun = new SimpleMod(IDs.PortalGun)
@ -59,18 +67,22 @@ object Mods {
mod.getVersion.startsWith("0.7.")
}
}
val ThermalExpansion = new SimpleMod(IDs.ThermalExpansion)
val ThermalExpansion = new SimpleMod(IDs.ThermalExpansion, providesPower = true)
val TinkersConstruct = new SimpleMod(IDs.TinkersConstruct)
val UniversalElectricity = new SimpleMod(IDs.UniversalElectricity + "@[3.1,)")
val UniversalElectricity = new SimpleMod(IDs.UniversalElectricity + "@[3.1,)", providesPower = true)
val Waila = new SimpleMod(IDs.Waila)
val WirelessRedstoneCBE = new SimpleMod(IDs.WirelessRedstoneCBE)
val WirelessRedstoneSV = new SimpleMod(IDs.WirelessRedstoneSV)
trait Mod {
knownMods += this
def isAvailable: Boolean
def providesPower: Boolean = false
}
class SimpleMod(val id: String) extends Mod {
class SimpleMod(val id: String, override val providesPower: Boolean = false) extends Mod {
protected val isModLoaded = {
val version = VersionParser.parseVersionReference(id)
if (Loader.isModLoaded(version.getLabel))