diff --git a/assets/opencomputers/lang/de_DE.lang b/assets/opencomputers/lang/de_DE.lang
index fb472408f..4facf3947 100644
--- a/assets/opencomputers/lang/de_DE.lang
+++ b/assets/opencomputers/lang/de_DE.lang
@@ -23,6 +23,7 @@ oc:block.Screen1.name=Hochwertiger Bildschirm
oc:block.Screen2.name=Ausgezeichneter Bildschirm
# Items
+oc:item.AbstractBusCard.name=Abstrakter-Bus-Karte
oc:item.Acid.name=Grog
oc:item.ALU.name=Arithmetisch-logische Einheit (ALU)
oc:item.Analyzer.name=Messgerät
@@ -77,6 +78,7 @@ oc:container.Case=Computer
oc:container.DiskDrive=Diskettenlaufwerk
# Item / Block Tooltips
+oc:tooltip.AbstractBusCard=Erlaubt es LIP-Pakete des Abstrakten Busses von §fStargateTech 2§7 zu senden und zu empfangen.
oc:tooltip.Acid=Eine hochgiftige Möchtegernflüssigkeit, wird üblicherweise nur von gewissen Piraten konsumiert. Dank ihrer korrosiven Eigenschaften ideal zum Bedrucken von Leiterplatten geeignet.
oc:tooltip.Adapter=Erlaubt es Blöcke anzusteuern, die keine Komponentenblöcke sind, wie etwa reguläre Minecraft-Blöcke oder Blöcke anderer Mods.
oc:tooltip.ALU=Zählt Zahlen zum Zeitvertreib. Klingt komisch, is aber so.
diff --git a/assets/opencomputers/lang/en_US.lang b/assets/opencomputers/lang/en_US.lang
index 1e8933334..d9e40efee 100644
--- a/assets/opencomputers/lang/en_US.lang
+++ b/assets/opencomputers/lang/en_US.lang
@@ -23,6 +23,7 @@ oc:block.Screen1.name=Advanced Screen
oc:block.Screen2.name=Superior Screen
# Items
+oc:item.AbstractBusCard.name=Abstract Bus Card
oc:item.Acid.name=Grog
oc:item.ALU.name=Arithmetic Logic Unit (ALU)
oc:item.Analyzer.name=Analyzer
@@ -77,6 +78,7 @@ oc:container.Case=Computer
oc:container.DiskDrive=Disk Drive
# Item / Block Tooltips
+oc:tooltip.AbstractBusCard=Allows interacting with §fStargateTech 2§7's abstract bus by sending and receiving LIP packets.
oc:tooltip.Acid=A highly toxic pseudo-liquid, usually only consumed by certain pirates. Thanks to its corrosive nature it is perfectly suited for etching circuit boards.
oc:tooltip.Adapter=Used to control non-component blocks, such as vanilla blocks or blocks from other mods.
oc:tooltip.ALU=Adds number so you don't have to. It might be better this way.
diff --git a/assets/opencomputers/recipes/default.recipes b/assets/opencomputers/recipes/default.recipes
index 2027fadc4..844f59760 100644
--- a/assets/opencomputers/recipes/default.recipes
+++ b/assets/opencomputers/recipes/default.recipes
@@ -51,6 +51,10 @@ hdd3 {
["oc:circuitElite", "oc:craftingHDDAdvanced", "oc:circuitElite"]]
}
+abstractBusCard {
+ input: [[busCable, {item=naquadah, subID=8}, ""]
+ ["", "oc:craftingCard", ""]]
+}
graphicsCard1 {
input: [["oc:circuitBasic", "oc:craftingALU", "oc:craftingRAMBasic"]
["", "oc:craftingCard", ""]]
diff --git a/assets/opencomputers/textures/items/card_abstract_bus.png b/assets/opencomputers/textures/items/card_abstract_bus.png
new file mode 100644
index 000000000..6bbe35504
Binary files /dev/null and b/assets/opencomputers/textures/items/card_abstract_bus.png differ
diff --git a/li/cil/oc/Items.scala b/li/cil/oc/Items.scala
index 4a0c7efe6..4325f9290 100644
--- a/li/cil/oc/Items.scala
+++ b/li/cil/oc/Items.scala
@@ -7,57 +7,58 @@ import net.minecraft.item.{Item, ItemStack}
import net.minecraftforge.oredict.OreDictionary
object Items {
- var multi: item.Delegator = null
+ var multi: item.Delegator = _
// ----------------------------------------------------------------------- //
// Tools
- var analyzer: item.Analyzer = null
+ var analyzer: item.Analyzer = _
// ----------------------------------------------------------------------- //
// Memory
- var ram1, ram2, ram3, ram4, ram5: item.Memory = null
+ var ram1, ram2, ram3, ram4, ram5: item.Memory = _
// ----------------------------------------------------------------------- //
// Storage
- var floppyDisk: item.FloppyDisk = null
- var hdd1, hdd2, hdd3: item.HardDiskDrive = null
+ var floppyDisk: item.FloppyDisk = _
+ var hdd1, hdd2, hdd3: item.HardDiskDrive = _
// ----------------------------------------------------------------------- //
// Cards
- var gpu1, gpu2, gpu3: item.GraphicsCard = null
- var lan: item.NetworkCard = null
- var rs: item.RedstoneCard = null
- var wlan: item.WirelessNetworkCard = null
+ var abstractBus: item.AbstractBusCard = _
+ var gpu1, gpu2, gpu3: item.GraphicsCard = _
+ var lan: item.NetworkCard = _
+ var rs: item.RedstoneCard = _
+ var wlan: item.WirelessNetworkCard = _
// ----------------------------------------------------------------------- //
// Upgrades
- var upgradeCrafting: item.UpgradeCrafting = null
- var upgradeGenerator: item.UpgradeGenerator = null
- var upgradeNavigation: item.UpgradeNavigation = null
- var upgradeSign: item.UpgradeSign = null
- var upgradeSolarGenerator: item.UpgradeSolarGenerator = null
+ var upgradeCrafting: item.UpgradeCrafting = _
+ var upgradeGenerator: item.UpgradeGenerator = _
+ var upgradeNavigation: item.UpgradeNavigation = _
+ var upgradeSign: item.UpgradeSign = _
+ var upgradeSolarGenerator: item.UpgradeSolarGenerator = _
// ----------------------------------------------------------------------- //
// Crafting
- var ironNugget: item.IronNugget = null
- var cuttingWire: item.CuttingWire = null
- var acid: item.Acid = null
- var disk: item.Disk = null
+ var ironNugget: item.IronNugget = _
+ var cuttingWire: item.CuttingWire = _
+ var acid: item.Acid = _
+ var disk: item.Disk = _
- var buttonGroup: item.ButtonGroup = null
- var arrowKeys: item.ArrowKeys = null
- var numPad: item.NumPad = null
+ var buttonGroup: item.ButtonGroup = _
+ var arrowKeys: item.ArrowKeys = _
+ var numPad: item.NumPad = _
- var transistor: item.Transistor = null
- var chip1, chip2, chip3: item.Microchip = null
- var alu: item.ALU = null
- var cpu: item.CPU = null
- var cu: item.ControlUnit = null
+ var transistor: item.Transistor = _
+ var chip1, chip2, chip3: item.Microchip = _
+ var alu: item.ALU = _
+ var cpu: item.CPU = _
+ var cu: item.ControlUnit = _
- var rawCircuitBoard: item.RawCircuitBoard = null
- var circuitBoard: item.CircuitBoard = null
- var pcb: item.PrintedCircuitBoard = null
- var card: item.CardBase = null
+ var rawCircuitBoard: item.RawCircuitBoard = _
+ var circuitBoard: item.CircuitBoard = _
+ var pcb: item.PrintedCircuitBoard = _
+ var card: item.CardBase = _
def init() {
multi = new item.Delegator(Settings.get.itemId)
@@ -115,6 +116,8 @@ object Items {
ram4 = new item.Memory(multi, 3)
ram5 = new item.Memory(multi, 4)
+ abstractBus = new item.AbstractBusCard(multi)
+
// ----------------------------------------------------------------------- //
registerExclusive("craftingPiston", new ItemStack(Block.pistonBase), new ItemStack(Block.pistonStickyBase))
diff --git a/li/cil/oc/OpenComputersCore.scala b/li/cil/oc/OpenComputersCore.scala
new file mode 100644
index 000000000..0ade59b0a
--- /dev/null
+++ b/li/cil/oc/OpenComputersCore.scala
@@ -0,0 +1,8 @@
+package li.cil.oc
+
+import cpw.mods.fml.common.Mod
+
+// This empty mod is used to avoid cyclic dependencies with mods we depend on
+// for optional interfaces, for example, but that also depend on our API.
+@Mod(modid = "OpenComputers|Core", name = "OpenComputers (Core)", version = "1.0.0", modLanguage = "scala")
+object OpenComputersCore
diff --git a/li/cil/oc/Recipes.scala b/li/cil/oc/Recipes.scala
index 7cffe689f..bad78cceb 100644
--- a/li/cil/oc/Recipes.scala
+++ b/li/cil/oc/Recipes.scala
@@ -64,6 +64,7 @@ object Recipes {
addRecipe(Items.hdd2.createItemStack(), recipes, "hdd2")
addRecipe(Items.hdd3.createItemStack(), recipes, "hdd3")
+ addRecipe(Items.abstractBus.createItemStack(), recipes, "abstractBusCard")
addRecipe(Items.gpu1.createItemStack(), recipes, "graphicsCard1")
addRecipe(Items.gpu2.createItemStack(), recipes, "graphicsCard2")
addRecipe(Items.gpu3.createItemStack(), recipes, "graphicsCard3")
diff --git a/li/cil/oc/Settings.scala b/li/cil/oc/Settings.scala
index 53a487610..145df6699 100644
--- a/li/cil/oc/Settings.scala
+++ b/li/cil/oc/Settings.scala
@@ -122,6 +122,7 @@ class Settings(config: Config) {
val robotMoveCost = config.getDouble("power.cost.robotMove") max 0
val robotExhaustionCost = config.getDouble("power.cost.robotExhaustion") max 0
val wirelessCostPerRange = config.getDouble("power.cost.wirelessStrength") max 0
+ val abstractBusPacketCost = config.getDouble("power.cost.abstractBusPacket") max 0
// ----------------------------------------------------------------------- //
// filesystem
diff --git a/li/cil/oc/api/package-info.java b/li/cil/oc/api/package-info.java
index 80f4792b8..d3b693586 100644
--- a/li/cil/oc/api/package-info.java
+++ b/li/cil/oc/api/package-info.java
@@ -35,7 +35,7 @@
*
*/
@cpw.mods.fml.common.API(
- owner = "OpenComputers",
+ owner = "OpenComputers|Core",
provides = "OpenComputersAPI",
apiVersion = "1.2.0")
package li.cil.oc.api;
\ No newline at end of file
diff --git a/li/cil/oc/client/PacketHandler.scala b/li/cil/oc/client/PacketHandler.scala
index 4f2ce836c..9e6637a47 100644
--- a/li/cil/oc/client/PacketHandler.scala
+++ b/li/cil/oc/client/PacketHandler.scala
@@ -23,6 +23,7 @@ class PacketHandler extends CommonPacketHandler {
override def dispatch(p: PacketParser) =
p.packetType match {
+ case PacketType.AbstractBusState => onAbstractBusState(p)
case PacketType.Analyze => onAnalyze(p)
case PacketType.ChargerState => onChargerState(p)
case PacketType.ComputerState => onComputerState(p)
@@ -47,6 +48,12 @@ class PacketHandler extends CommonPacketHandler {
case _ => // Invalid packet.
}
+ def onAbstractBusState(p: PacketParser) =
+ p.readTileEntity[AbstractBusAware]() match {
+ case Some(t) => t.isAbstractBusAvailable = p.readBoolean()
+ case _ => // Invalid packet.
+ }
+
def onAnalyze(p: PacketParser) {
val player = p.player.asInstanceOf[EntityPlayer]
val stats = p.readNBT().asInstanceOf[NBTTagCompound]
diff --git a/li/cil/oc/common/PacketType.scala b/li/cil/oc/common/PacketType.scala
index c8a8a14c3..e121e80d2 100644
--- a/li/cil/oc/common/PacketType.scala
+++ b/li/cil/oc/common/PacketType.scala
@@ -3,6 +3,7 @@ package li.cil.oc.common
object PacketType extends Enumeration {
val
// Server -> Client
+ AbstractBusState,
Analyze,
ChargerState,
ComputerState,
diff --git a/li/cil/oc/common/Proxy.scala b/li/cil/oc/common/Proxy.scala
index f6a57a9e6..c24f4741e 100644
--- a/li/cil/oc/common/Proxy.scala
+++ b/li/cil/oc/common/Proxy.scala
@@ -28,16 +28,17 @@ class Proxy {
api.Driver.add(driver.block.CommandBlock)
api.Driver.add(driver.block.NoteBlock)
- api.Driver.add(driver.item.UpgradeCrafting)
+ api.Driver.add(driver.item.AbstractBusCard)
api.Driver.add(driver.item.FileSystem)
- api.Driver.add(driver.item.UpgradeGenerator)
- api.Driver.add(driver.item.SolarGenerator)
api.Driver.add(driver.item.GraphicsCard)
- api.Driver.add(driver.item.UpgradeNavigation)
api.Driver.add(driver.item.Memory)
api.Driver.add(driver.item.NetworkCard)
- api.Driver.add(driver.item.UpgradeSign)
api.Driver.add(driver.item.RedstoneCard)
+ api.Driver.add(driver.item.UpgradeCrafting)
+ api.Driver.add(driver.item.UpgradeGenerator)
+ api.Driver.add(driver.item.UpgradeNavigation)
+ api.Driver.add(driver.item.UpgradeSign)
+ api.Driver.add(driver.item.UpgradeSolarGenerator)
api.Driver.add(driver.item.WirelessNetworkCard)
Recipes.init()
diff --git a/li/cil/oc/common/item/AbstractBusCard.scala b/li/cil/oc/common/item/AbstractBusCard.scala
new file mode 100644
index 000000000..6d3aba644
--- /dev/null
+++ b/li/cil/oc/common/item/AbstractBusCard.scala
@@ -0,0 +1,26 @@
+package li.cil.oc.common.item
+
+import cpw.mods.fml.common.Loader
+import java.util
+import li.cil.oc.Settings
+import li.cil.oc.util.Tooltip
+import net.minecraft.client.renderer.texture.IconRegister
+import net.minecraft.entity.player.EntityPlayer
+import net.minecraft.item.ItemStack
+
+class AbstractBusCard(val parent: Delegator) extends Delegate {
+ val unlocalizedName = "AbstractBusCard"
+
+ override val showInItemList = Loader.isModLoaded("StargateTech2")
+
+ override def tooltipLines(stack: ItemStack, player: EntityPlayer, tooltip: util.List[String], advanced: Boolean) {
+ tooltip.addAll(Tooltip.get(unlocalizedName))
+ super.tooltipLines(stack, player, tooltip, advanced)
+ }
+
+ override def registerIcons(iconRegister: IconRegister) = {
+ super.registerIcons(iconRegister)
+
+ icon = iconRegister.registerIcon(Settings.resourceDomain + ":card_abstract_bus")
+ }
+}
diff --git a/li/cil/oc/common/tileentity/AbstractBusAware.scala b/li/cil/oc/common/tileentity/AbstractBusAware.scala
new file mode 100644
index 000000000..88b490d2a
--- /dev/null
+++ b/li/cil/oc/common/tileentity/AbstractBusAware.scala
@@ -0,0 +1,105 @@
+package li.cil.oc.common.tileentity
+
+import cpw.mods.fml.common.{Loader, Optional}
+import cpw.mods.fml.relauncher.{SideOnly, Side}
+import li.cil.oc.api.network.Node
+import li.cil.oc.server.{PacketSender => ServerPacketSender, component}
+import net.minecraft.item.ItemStack
+import net.minecraft.nbt.NBTTagCompound
+import net.minecraftforge.common.MinecraftForge
+import stargatetech2.api.StargateTechAPI
+import stargatetech2.api.bus.{BusEvent, IBusDevice}
+
+@Optional.Interface(iface = "stargatetech2.api.bus.IBusDevice", modid = "StargateTech2")
+trait AbstractBusAware extends TileEntity with ComponentInventory with IBusDevice {
+ def getInterfaces(side: Int) =
+ if (isAbstractBusAvailable) {
+ if (isServer) {
+ components collect {
+ case Some(abstractBus: component.AbstractBus) => abstractBus.busInterface
+ }
+ }
+ else fakeInterface
+ }
+ else null
+
+ protected var _isAbstractBusAvailable = false
+
+ private lazy val fakeInterface = Array(StargateTechAPI.api.getFactory.getIBusInterface(this, null))
+
+ def getWorld = world
+
+ def getXCoord = x
+
+ def getYCoord = y
+
+ def getZCoord = z
+
+ def isAbstractBusAvailable = _isAbstractBusAvailable
+
+ def isAbstractBusAvailable_=(value: Boolean) = {
+ if (value != isAbstractBusAvailable) {
+ _isAbstractBusAvailable = value
+ if (isAbstractBusAvailable) addAbstractBus()
+ else removeAbstractBus()
+ world.notifyBlocksOfNeighborChange(x, y, z, block.blockID)
+ if (isServer) ServerPacketSender.sendAbstractBusState(this)
+ else world.markBlockForRenderUpdate(x, y, z)
+ }
+ this
+ }
+
+ @SideOnly(Side.CLIENT)
+ override def readFromNBTForClient(nbt: NBTTagCompound) {
+ super.readFromNBTForClient(nbt)
+ isAbstractBusAvailable = nbt.getBoolean("isAbstractBusAvailable")
+ }
+
+ override def writeToNBTForClient(nbt: NBTTagCompound) {
+ super.writeToNBTForClient(nbt)
+ nbt.setBoolean("isAbstractBusAvailable", isAbstractBusAvailable)
+ }
+
+ override protected def onItemAdded(slot: Int, stack: ItemStack) {
+ super.onItemAdded(slot, stack)
+ if (isServer) {
+ isAbstractBusAvailable = hasAbstractBusCard
+ }
+ }
+
+ override protected def onItemRemoved(slot: Int, stack: ItemStack) {
+ super.onItemRemoved(slot, stack)
+ if (isServer) {
+ isAbstractBusAvailable = hasAbstractBusCard
+ }
+ }
+
+ abstract override def onConnect(node: Node) {
+ super.onConnect(node)
+ isAbstractBusAvailable = hasAbstractBusCard
+ }
+
+ abstract override def onDisconnect(node: Node) {
+ super.onDisconnect(node)
+ removeAbstractBus()
+ }
+
+ protected def addAbstractBus() {
+ // Mod loaded check to avoid class not found errors.
+ if (isServer && Loader.isModLoaded("StargateTech2")) {
+ MinecraftForge.EVENT_BUS.post(new BusEvent.AddToNetwork(world, x, y, z))
+ }
+ }
+
+ protected def removeAbstractBus() {
+ // Mod loaded check to avoid class not found errors.
+ if (isServer && Loader.isModLoaded("StargateTech2")) {
+ MinecraftForge.EVENT_BUS.post(new BusEvent.RemoveFromNetwork(world, x, y, z))
+ }
+ }
+
+ protected def hasAbstractBusCard = components exists {
+ case Some(_: component.AbstractBus) => true
+ case _ => false
+ }
+}
diff --git a/li/cil/oc/common/tileentity/Computer.scala b/li/cil/oc/common/tileentity/Computer.scala
index 927213997..de4a8c4d7 100644
--- a/li/cil/oc/common/tileentity/Computer.scala
+++ b/li/cil/oc/common/tileentity/Computer.scala
@@ -11,7 +11,7 @@ import net.minecraftforge.common.ForgeDirection
import scala.Some
import scala.collection.mutable
-abstract class Computer(isRemote: Boolean) extends Environment with ComponentInventory with Rotatable with BundledRedstoneAware with Analyzable with Context {
+abstract class Computer(isRemote: Boolean) extends Environment with ComponentInventory with Rotatable with BundledRedstoneAware with AbstractBusAware with Analyzable with Context {
protected val _computer = if (isRemote) null else new component.Computer(this)
def computer = _computer
diff --git a/li/cil/oc/common/tileentity/Environment.scala b/li/cil/oc/common/tileentity/Environment.scala
index bd8ea125d..a86ba722a 100644
--- a/li/cil/oc/common/tileentity/Environment.scala
+++ b/li/cil/oc/common/tileentity/Environment.scala
@@ -6,22 +6,10 @@ import li.cil.oc.api.{Network, network}
import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.util.Persistable
import net.minecraft.nbt.NBTTagCompound
-import net.minecraft.network.INetworkManager
-import net.minecraft.network.packet.Packet132TileEntityData
import net.minecraftforge.common.ForgeDirection
import scala.math.ScalaNumber
-abstract class Environment extends net.minecraft.tileentity.TileEntity with TileEntity with network.Environment with Persistable {
- def world = getWorldObj
-
- def x = xCoord
-
- def y = yCoord
-
- def z = zCoord
-
- def block = getBlockType
-
+abstract class Environment extends TileEntity with network.Environment with Persistable {
protected var addedToNetwork = false
// ----------------------------------------------------------------------- //
@@ -76,18 +64,6 @@ abstract class Environment extends net.minecraft.tileentity.TileEntity with Tile
// ----------------------------------------------------------------------- //
- override def getDescriptionPacket = {
- val nbt = new NBTTagCompound()
- writeToNBTForClient(nbt)
- if (nbt.hasNoTags) null else new Packet132TileEntityData(x, y, z, -1, nbt)
- }
-
- override def onDataPacket(manager: INetworkManager, packet: Packet132TileEntityData) {
- readFromNBTForClient(packet.data)
- }
-
- // ----------------------------------------------------------------------- //
-
def onMessage(message: network.Message) {}
def onConnect(node: network.Node) {}
diff --git a/li/cil/oc/common/tileentity/Router.scala b/li/cil/oc/common/tileentity/Router.scala
index 2ba7602d5..5f7b023b9 100644
--- a/li/cil/oc/common/tileentity/Router.scala
+++ b/li/cil/oc/common/tileentity/Router.scala
@@ -11,7 +11,7 @@ import net.minecraftforge.common.ForgeDirection
import scala.collection.mutable
@Optional.Interface(iface = "dan200.computer.api.IPeripheral", modid = "ComputerCraft")
-class Router extends net.minecraft.tileentity.TileEntity with api.network.SidedEnvironment with IPeripheral with PassiveNode {
+class Router extends TileEntity with api.network.SidedEnvironment with IPeripheral with PassiveNode {
private val plugs = ForgeDirection.VALID_DIRECTIONS.map(side => new Plug(side))
// ----------------------------------------------------------------------- //
diff --git a/li/cil/oc/common/tileentity/TileEntity.scala b/li/cil/oc/common/tileentity/TileEntity.scala
index d894267d1..ba2538e6a 100644
--- a/li/cil/oc/common/tileentity/TileEntity.scala
+++ b/li/cil/oc/common/tileentity/TileEntity.scala
@@ -1,25 +1,38 @@
package li.cil.oc.common.tileentity
import cpw.mods.fml.relauncher.{Side, SideOnly}
-import net.minecraft.block.Block
import net.minecraft.nbt.NBTTagCompound
-import net.minecraft.world.World
+import net.minecraft.network.INetworkManager
+import net.minecraft.network.packet.Packet132TileEntityData
+import net.minecraft.tileentity.{TileEntity => MCTileEntity}
-trait TileEntity {
- def world: World
+trait TileEntity extends MCTileEntity {
+ def world = getWorldObj
- def x: Int
+ def x = xCoord
- def y: Int
+ def y = yCoord
- def z: Int
+ def z = zCoord
- def block: Block
+ def block = getBlockType
lazy val isClient = world.isRemote
lazy val isServer = !isClient
+ // ----------------------------------------------------------------------- //
+
+ override def getDescriptionPacket = {
+ val nbt = new NBTTagCompound()
+ writeToNBTForClient(nbt)
+ if (nbt.hasNoTags) null else new Packet132TileEntityData(x, y, z, -1, nbt)
+ }
+
+ override def onDataPacket(manager: INetworkManager, packet: Packet132TileEntityData) {
+ readFromNBTForClient(packet.data)
+ }
+
@SideOnly(Side.CLIENT)
def readFromNBTForClient(nbt: NBTTagCompound) {}
diff --git a/li/cil/oc/server/PacketSender.scala b/li/cil/oc/server/PacketSender.scala
index 66be4fe86..6a70700f3 100644
--- a/li/cil/oc/server/PacketSender.scala
+++ b/li/cil/oc/server/PacketSender.scala
@@ -8,9 +8,17 @@ import li.cil.oc.util.PackedColor
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection
-import scala.Some
object PacketSender {
+ def sendAbstractBusState(t: AbstractBusAware) {
+ val pb = new PacketBuilder(PacketType.AbstractBusState)
+
+ pb.writeTileEntity(t)
+ pb.writeBoolean(t.isAbstractBusAvailable)
+
+ pb.sendToNearbyPlayers(t)
+ }
+
def sendAnalyze(stats: NBTTagCompound, address: String, player: Player) {
val pb = new PacketBuilder(PacketType.Analyze)
@@ -20,28 +28,22 @@ object PacketSender {
pb.sendToPlayer(player)
}
- def sendChargerState(t: Charger, player: Option[Player] = None) {
+ def sendChargerState(t: Charger) {
val pb = new PacketBuilder(PacketType.ChargerState)
pb.writeTileEntity(t)
pb.writeDouble(t.chargeSpeed)
- player match {
- case Some(p) => pb.sendToPlayer(p)
- case _ => pb.sendToNearbyPlayers(t)
- }
+ pb.sendToNearbyPlayers(t)
}
- def sendComputerState(t: Computer, player: Option[Player] = None) {
+ def sendComputerState(t: Computer) {
val pb = new PacketBuilder(PacketType.ComputerState)
pb.writeTileEntity(t)
pb.writeBoolean(t.isRunning)
- player match {
- case Some(p) => pb.sendToPlayer(p)
- case _ => pb.sendToNearbyPlayers(t)
- }
+ pb.sendToNearbyPlayers(t)
}
def sendComputerUserList(t: Computer, list: Array[String]) {
@@ -54,20 +56,17 @@ object PacketSender {
pb.sendToNearbyPlayers(t)
}
- def sendPowerState(t: PowerInformation, player: Option[Player] = None) {
+ def sendPowerState(t: PowerInformation) {
val pb = new PacketBuilder(PacketType.PowerState)
pb.writeTileEntity(t)
pb.writeDouble(t.globalBuffer)
pb.writeDouble(t.globalBufferSize)
- player match {
- case Some(p) => pb.sendToPlayer(p)
- case _ => pb.sendToNearbyPlayers(t)
- }
+ pb.sendToNearbyPlayers(t)
}
- def sendRedstoneState(t: RedstoneAware, player: Option[Player] = None) {
+ def sendRedstoneState(t: RedstoneAware) {
val pb = new PacketBuilder(PacketType.RedstoneState)
pb.writeTileEntity(t)
@@ -76,10 +75,7 @@ object PacketSender {
pb.writeByte(t.output(d))
}
- player match {
- case Some(p) => pb.sendToPlayer(p)
- case _ => pb.sendToNearbyPlayers(t)
- }
+ pb.sendToNearbyPlayers(t)
}
def sendRobotMove(t: Robot, ox: Int, oy: Int, oz: Int, direction: ForgeDirection) {
@@ -150,17 +146,14 @@ object PacketSender {
pb.sendToNearbyPlayers(t)
}
- def sendRotatableState(t: Rotatable, player: Option[Player] = None) {
+ def sendRotatableState(t: Rotatable) {
val pb = new PacketBuilder(PacketType.RotatableState)
pb.writeTileEntity(t)
pb.writeDirection(t.pitch)
pb.writeDirection(t.yaw)
- player match {
- case Some(p) => pb.sendToPlayer(p)
- case _ => pb.sendToNearbyPlayers(t)
- }
+ pb.sendToNearbyPlayers(t)
}
def sendScreenColorChange(t: Buffer, foreground: Int, background: Int) {
diff --git a/li/cil/oc/server/component/AbstractBus.scala b/li/cil/oc/server/component/AbstractBus.scala
new file mode 100644
index 000000000..d60874605
--- /dev/null
+++ b/li/cil/oc/server/component/AbstractBus.scala
@@ -0,0 +1,119 @@
+package li.cil.oc.server.component
+
+import li.cil.oc.api.network.{Arguments, Context, LuaCallback, Visibility}
+import li.cil.oc.common.tileentity
+import li.cil.oc.{Settings, api}
+import net.minecraft.nbt.NBTTagCompound
+import scala.collection.convert.WrapAsScala._
+import stargatetech2.api.StargateTechAPI
+import stargatetech2.api.bus.{BusPacketLIP, BusPacket, IBusDriver, IBusInterface}
+
+class AbstractBus(val owner: tileentity.Computer) extends ManagedComponent with IBusDriver {
+ val node = api.Network.newNode(this, Visibility.Neighbors).
+ withComponent("abstract_bus").
+ withConnector().
+ create()
+
+ val busInterface: IBusInterface = StargateTechAPI.api.getFactory.getIBusInterface(owner, this)
+
+ protected var isEnabled = true
+
+ protected var address = 0
+
+ protected var sendQueue: Option[QueuedPacket] = None
+
+ // ----------------------------------------------------------------------- //
+
+ def canHandlePacket(sender: Short, protocolID: Int, hasLIP: Boolean) = hasLIP
+
+ def handlePacket(packet: BusPacket) {
+ val lip = packet.getPlainText
+ val data = Map(lip.getEntryList.map(key => (key, lip.get(key))): _*)
+ val metadata = Map("mod" -> lip.getMetadata.modID, "device" -> lip.getMetadata.deviceName, "player" -> lip.getMetadata.playerName)
+ owner.signal("bus_message", Int.box(packet.getProtocolID), Int.box(packet.getSender), Int.box(packet.getTarget), data, metadata)
+ }
+
+ def getNextPacketToSend = if (sendQueue.isDefined) {
+ val info = sendQueue.get
+ sendQueue = None
+ val packet = new BusPacketLIP(info.sender, info.target)
+ for ((key, value) <- info.data) {
+ packet.set(key, value)
+ }
+ packet.setMetadata(new BusPacketLIP.LIPMetadata("OpenComputers", node.address, null))
+ packet.finish()
+ packet
+ }
+ else null
+
+ def isInterfaceEnabled = isEnabled
+
+ def getInterfaceAddress = address.toShort
+
+ // ----------------------------------------------------------------------- //
+
+ @LuaCallback("getEnabled")
+ def getEnabled(context: Context, args: Arguments): Array[AnyRef] = result(isEnabled)
+
+ @LuaCallback("setEnabled")
+ def setEnabled(context: Context, args: Arguments): Array[AnyRef] = {
+ isEnabled = args.checkBoolean(0)
+ result(isEnabled)
+ }
+
+ @LuaCallback("getAddress")
+ def getAddress(context: Context, args: Arguments): Array[AnyRef] = result(address)
+
+ @LuaCallback("setAddress")
+ def setAddress(context: Context, args: Arguments): Array[AnyRef] = {
+ address = args.checkInteger(0) & 0xFFFF
+ result(address)
+ }
+
+ @LuaCallback("send")
+ def send(context: Context, args: Arguments): Array[AnyRef] = {
+ val target = args.checkInteger(0) & 0xFFFF
+ val data = args.checkTable(1)
+ if (node.tryChangeBuffer(-Settings.get.abstractBusPacketCost)) {
+ sendQueue = Some(new QueuedPacket(address.toShort, target.toShort, Map(data.toSeq.map(entry => (entry._1.toString, entry._2.toString)): _*)))
+ busInterface.sendAllPackets()
+ result(true)
+ }
+ else result(false, "not enough energy")
+ }
+
+ @LuaCallback(value = "maxPacketSize", direct = true)
+ def maxPacketSize(context: Context, args: Arguments): Array[AnyRef] = result(Settings.get.maxNetworkPacketSize)
+
+ // ----------------------------------------------------------------------- //
+
+ override def load(nbt: NBTTagCompound) {
+ super.load(nbt)
+ busInterface.readFromNBT(nbt, "bus")
+ // Don't default to false.
+ if (nbt.hasKey("enabled")) {
+ isEnabled = nbt.getBoolean("enabled")
+ }
+ address = nbt.getInteger("address") & 0xFFFF
+ }
+
+ override def save(nbt: NBTTagCompound) {
+ super.save(nbt)
+ busInterface.writeToNBT(nbt, "bus")
+ nbt.setBoolean("enabled", isEnabled)
+ nbt.setInteger("address", address)
+ }
+
+ protected class QueuedPacket(val sender: Short, val target: Short, val data: Map[String, String]) {
+ // Extra braces because we don't want/have to keep size as a field.
+ {
+ val size = data.foldLeft(0)((acc, arg) => {
+ acc + arg._1.length + arg._2.length
+ })
+ if (size > Settings.get.maxNetworkPacketSize) {
+ throw new IllegalArgumentException("packet too big (max " + Settings.get.maxNetworkPacketSize + ")")
+ }
+ }
+ }
+
+}
diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala
index 9a9ee05b0..2651385c0 100644
--- a/li/cil/oc/server/component/Computer.scala
+++ b/li/cil/oc/server/component/Computer.scala
@@ -1018,8 +1018,8 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con
lua.pushBoolean(true)
lua.pushNil()
lua.pushString(e.getMessage)
- if (true) {
- lua.pushString(e.getStackTraceString)
+ if (Settings.get.logLuaCallbackErrors) {
+ lua.pushString(e.getStackTraceString.replace("\r\n", "\n"))
4
}
else 3
diff --git a/li/cil/oc/server/driver/item/AbstractBusCard.scala b/li/cil/oc/server/driver/item/AbstractBusCard.scala
new file mode 100644
index 000000000..bfc9cda42
--- /dev/null
+++ b/li/cil/oc/server/driver/item/AbstractBusCard.scala
@@ -0,0 +1,20 @@
+package li.cil.oc.server.driver.item
+
+import cpw.mods.fml.common.Loader
+import li.cil.oc.Items
+import li.cil.oc.api.driver.Slot
+import li.cil.oc.common.tileentity
+import li.cil.oc.server.component
+import net.minecraft.item.ItemStack
+import net.minecraft.tileentity.{TileEntity => MCTileEntity}
+
+object AbstractBusCard extends Item {
+ def worksWith(stack: ItemStack) = isOneOf(stack, Items.abstractBus)
+
+ override def createEnvironment(stack: ItemStack, container: MCTileEntity) = container match {
+ case computer: tileentity.Computer if Loader.isModLoaded("StargateTech2") => new component.AbstractBus(computer)
+ case _ => null
+ }
+
+ def slot(stack: ItemStack) = Slot.Card
+}
diff --git a/li/cil/oc/server/driver/item/SolarGenerator.scala b/li/cil/oc/server/driver/item/UpgradeSolarGenerator.scala
similarity index 91%
rename from li/cil/oc/server/driver/item/SolarGenerator.scala
rename to li/cil/oc/server/driver/item/UpgradeSolarGenerator.scala
index 0998fe1f7..b8e89b469 100644
--- a/li/cil/oc/server/driver/item/SolarGenerator.scala
+++ b/li/cil/oc/server/driver/item/UpgradeSolarGenerator.scala
@@ -6,7 +6,7 @@ import li.cil.oc.server.component
import net.minecraft.item.ItemStack
import net.minecraft.tileentity.{TileEntity => MCTileEntity}
-object SolarGenerator extends Item {
+object UpgradeSolarGenerator extends Item {
override def worksWith(stack: ItemStack) = isOneOf(stack, Items.upgradeSolarGenerator)
override def createEnvironment(stack: ItemStack, container: MCTileEntity) = new component.UpgradeSolarGenerator(container)
diff --git a/mcmod.info b/mcmod.info
index dc6b83b19..1dfa3f861 100644
--- a/mcmod.info
+++ b/mcmod.info
@@ -4,7 +4,7 @@
"modid": "OpenComputers",
"name": "OpenComputers",
"description": "This mod adds modular computers and robots that can be programmed in Lua.",
- "version": "1.1.1",
+ "version": "1.1.2",
"mcversion": "1.6.4",
"url": "https://github.com/MightyPirates/OpenComputers/wiki",
"authors": ["Florian 'Sangar' Nücke", "Johannes 'Lord Joda' Lohrer"],
@@ -18,6 +18,7 @@
"MineFactoryReloaded",
"ProjRed|Transmission",
"RedLogic",
+ "StargateTech2",
"ThermalExpansion"
],
"useDependencyInformation": "true"
diff --git a/reference.conf b/reference.conf
index 2398a10af..50c05ca5d 100644
--- a/reference.conf
+++ b/reference.conf
@@ -519,6 +519,9 @@ opencomputers {
# the higher the cost of wireless messages.
# See also: `maxWirelessRange`.
wirelessStrength: 0.05
+
+ # The cost of a single packet sent via StargateTech 2's abstract bus.
+ abstractBusPacket: 1
}
}
diff --git a/stargatetech2/api/IFactory.java b/stargatetech2/api/IFactory.java
new file mode 100644
index 000000000..0a9b43492
--- /dev/null
+++ b/stargatetech2/api/IFactory.java
@@ -0,0 +1,15 @@
+package stargatetech2.api;
+
+import stargatetech2.api.bus.IBusDevice;
+import stargatetech2.api.bus.IBusDriver;
+import stargatetech2.api.bus.IBusInterface;
+
+/**
+ * A factory for private classes that implement
+ * interfaces from the public API.
+ *
+ * @author LordFokas
+ */
+public interface IFactory {
+ public IBusInterface getIBusInterface(IBusDevice device, IBusDriver driver);
+}
diff --git a/stargatetech2/api/IStargateTechAPI.java b/stargatetech2/api/IStargateTechAPI.java
new file mode 100644
index 000000000..ab00336e3
--- /dev/null
+++ b/stargatetech2/api/IStargateTechAPI.java
@@ -0,0 +1,27 @@
+package stargatetech2.api;
+
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraftforge.fluids.Fluid;
+import stargatetech2.api.stargate.IStargateNetwork;
+
+public interface IStargateTechAPI {
+ /**
+ * @return The Fluid instance corresponding to Ionized Particles.
+ */
+ public Fluid getIonizedParticlesFluidInstance();
+
+ /**
+ * @return The creative inventory tab used by StargateTech 2.
+ */
+ public CreativeTabs getStargateTab();
+
+ /**
+ * @return The IStargateNetwork singleton instance.
+ */
+ public IStargateNetwork getStargateNetwork();
+
+ /**
+ * @return The current IFactory instance.
+ */
+ public IFactory getFactory();
+}
\ No newline at end of file
diff --git a/stargatetech2/api/ITabletAccess.java b/stargatetech2/api/ITabletAccess.java
new file mode 100644
index 000000000..d9ffb5edb
--- /dev/null
+++ b/stargatetech2/api/ITabletAccess.java
@@ -0,0 +1,27 @@
+package stargatetech2.api;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.world.World;
+
+/**
+ * Implemented by blocks that run special actions when clicked with a TabletPC in hand.
+ * The default action in StargateTech2 is opening a special GUI.
+ *
+ * @author LordFokas
+ */
+public interface ITabletAccess {
+
+ /**
+ * Make the block run a special action when activated with a TabletPC.
+ * This method is only called on the client side.
+ * Implementations requiring server side should use packets.
+ *
+ * @param player The player activating the block.
+ * @param world The world the block is in.
+ * @param x The block's X coordinate.
+ * @param y The block's Y coordinate.
+ * @param z The block's Z coordinate.
+ * @return True if a special action was executed, false otherwise.
+ */
+ public boolean onTabletAccess(EntityPlayer player, World world, int x, int y, int z);
+}
diff --git a/stargatetech2/api/StargateTechAPI.java b/stargatetech2/api/StargateTechAPI.java
new file mode 100644
index 000000000..c3096a6e5
--- /dev/null
+++ b/stargatetech2/api/StargateTechAPI.java
@@ -0,0 +1,16 @@
+package stargatetech2.api;
+
+public abstract class StargateTechAPI implements IStargateTechAPI {
+ protected static IStargateTechAPI apiInstance;
+
+ /**
+ * StargateTech's API is abstract, and it's implementation is not visible in the API package.
+ * All available methods in IStargateTechAPI are implemented elsewhere.
+ * This method allows you to retrieve an instance of that implementation.
+ *
+ * @return a concrete implementation of IStargateTechAPI
+ */
+ public static IStargateTechAPI api(){
+ return apiInstance;
+ }
+}
\ No newline at end of file
diff --git a/stargatetech2/api/bus/BusEvent.java b/stargatetech2/api/bus/BusEvent.java
new file mode 100644
index 000000000..80038e88c
--- /dev/null
+++ b/stargatetech2/api/bus/BusEvent.java
@@ -0,0 +1,40 @@
+package stargatetech2.api.bus;
+
+import net.minecraft.world.World;
+import net.minecraftforge.event.Event;
+
+public class BusEvent extends Event{
+ public final World world;
+ public final int x, y, z;
+
+ protected BusEvent(World world, int x, int y, int z){
+ this.world = world;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /**
+ * Fire this event on Forge's BUS_EVENT to add the IBusDevice
+ * in this location to a bus network, if any is available.
+ *
+ * @author LordFokas
+ */
+ public static final class AddToNetwork extends BusEvent{
+ public AddToNetwork(World world, int x, int y, int z) {
+ super(world, x, y, z);
+ }
+ }
+
+ /**
+ * Fire this event on Forge's BUS_EVENT to remove the IBusDevice
+ * in this location from any connected bus networks.
+ *
+ * @author LordFokas
+ */
+ public static final class RemoveFromNetwork extends BusEvent{
+ public RemoveFromNetwork(World world, int x, int y, int z) {
+ super(world, x, y, z);
+ }
+ }
+}
\ No newline at end of file
diff --git a/stargatetech2/api/bus/BusPacket.java b/stargatetech2/api/bus/BusPacket.java
new file mode 100644
index 000000000..10116cd4c
--- /dev/null
+++ b/stargatetech2/api/bus/BusPacket.java
@@ -0,0 +1,68 @@
+package stargatetech2.api.bus;
+
+public abstract class BusPacket {
+ private final short sender;
+ private final short target;
+ private final boolean hasLIP;
+
+ /**
+ * @param sender The address of the Device that is sending this packet.
+ * @param target The address of the Device(s) that should receive this packet.
+ * @param hasLIP Whether or not this packet supports being converted to a plain text (LIP) format.
+ */
+ protected BusPacket(short sender, short target, boolean hasLIP){
+ this.sender = sender;
+ this.target = target;
+ this.hasLIP = hasLIP;
+ }
+
+ /**
+ * @return The address of the device that sent this packet.
+ */
+ public final short getSender(){
+ return sender;
+ }
+
+ /**
+ * @return The address of the device(s) that should receive this packet.
+ */
+ public final short getTarget(){
+ return target;
+ }
+
+ /**
+ * @return The ID of the protocol this packet corresponds to.
+ */
+ public final int getProtocolID(){
+ return BusProtocols.getProtocolID(this.getClass());
+ }
+
+ /**
+ * @return A plain text (LIP) version of this packet, if it has one.
+ */
+ public final BusPacketLIP getPlainText(){
+ if(this instanceof BusPacketLIP){
+ return (BusPacketLIP) this;
+ }else if(hasLIP){
+ BusPacketLIP lip = new BusPacketLIP(sender, target);
+ fillPlainText(lip);
+ lip.finish();
+ return lip;
+ }
+ return null;
+ }
+
+ /**
+ * Used by subclasses to convert themselves to plain text format.
+ *
+ * @param lip The Lazy Intercom Protocol (LIP) packet we're filling with our data.
+ */
+ protected abstract void fillPlainText(BusPacketLIP lip);
+
+ /**
+ * @return Whether or not this packet supports conversion to the LIP format.
+ */
+ public final boolean hasPlainText(){
+ return hasLIP;
+ }
+}
diff --git a/stargatetech2/api/bus/BusPacketLIP.java b/stargatetech2/api/bus/BusPacketLIP.java
new file mode 100644
index 000000000..063d19b89
--- /dev/null
+++ b/stargatetech2/api/bus/BusPacketLIP.java
@@ -0,0 +1,113 @@
+package stargatetech2.api.bus;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+/**
+ * LIP - Lazy Intercom Protocol
+ *
+ * Baptized by sciguyryan (often found in #ThermalExpansion and #StargateTech on esper.net's IRC),
+ * this is the universal plain text format used in the Abstract Bus.
+ *
+ * Any packet can choose to be convertible to this format, allowing for any class anywhere to
+ * read data from a packet which has an unknown and / or private class by asking it to convert to
+ * a text format. This removes all the problems with type casting and such.
+ *
+ * @author LordFokas
+ */
+public final class BusPacketLIP extends BusPacket {
+ public static final int PROTOCOL_ID = BusProtocols.addProtocol(BusPacketLIP.class);
+ private boolean isEditable = true;
+ private LIPMetadata metadata = null;
+ private Hashtable data = new Hashtable();
+
+ /**
+ * Defines optional metadata that helps sorting this packet out / figuring out what to do with this.
+ * The fact this is a plain text protocol makes the possibilities so vague it'd be impossible to
+ * guess what kind of data this packet carries.
+ *
+ * @author LordFokas
+ */
+ public static final class LIPMetadata{
+ public final String modID;
+ public final String deviceName;
+ public final String playerName;
+
+ /**
+ * Example: new LIPMetadata("StargateTech2", "shieldEmitter", "LordFokas");
+ *
+ * @param modID The ID of the mod that generated this packet. PLEASE do fill this one.
+ * @param deviceName The name (or a unique identifier) of the type of machine that generated this.
+ * @param playerName The name of the player that made this packet be generated, if any.
+ */
+ public LIPMetadata(String modID, String deviceName, String playerName){
+ this.modID = modID;
+ this.deviceName = deviceName;
+ this.playerName = playerName;
+ }
+ }
+
+ public BusPacketLIP(short sender, short target) {
+ super(sender, target, true);
+ }
+
+ /**
+ * @param metadata The LIPMetadata object to set to this packet.
+ */
+ public void setMetadata(LIPMetadata metadata){
+ if(isEditable && this.metadata == null){
+ this.metadata = metadata;
+ }
+ }
+
+ /**
+ * @return The LIPMetadata object on this object. May be null.
+ */
+ public LIPMetadata getMetadata(){
+ return metadata;
+ }
+
+ @Override // We don't need this. At all.
+ protected void fillPlainText(BusPacketLIP lip){}
+
+ /**
+ * Finish creating this packet.
+ * As soon as you call this, it can no longer be modified.
+ */
+ public void finish(){
+ isEditable = false;
+ }
+
+ /**
+ * @return A list of all the keys for the data on this packet.
+ */
+ public ArrayList getEntryList(){
+ ArrayList entries = new ArrayList();
+ entries.addAll(data.keySet());
+ return entries;
+ }
+
+ /**
+ * Add a new entry to this packet.
+ * If the key already exists the entry is ignored.
+ *
+ * @param key The key under which to send the data.
+ * @param val The data to send.
+ */
+ public void set(String key, String val){
+ if(isEditable && !data.containsKey(key)){
+ data.put(key.toLowerCase(), val);
+ }
+ }
+
+ /**
+ * Get the value stored under that key, if any.
+ * Case Insensitive.
+ *
+ * @param key The key under which the data is stored.
+ * @return The data stored under that key, if any, null otherwise.
+ */
+ public String get(String key){
+ return data.get(key.toLowerCase());
+ }
+}
\ No newline at end of file
diff --git a/stargatetech2/api/bus/BusProtocols.java b/stargatetech2/api/bus/BusProtocols.java
new file mode 100644
index 000000000..8cfceb4e6
--- /dev/null
+++ b/stargatetech2/api/bus/BusProtocols.java
@@ -0,0 +1,32 @@
+package stargatetech2.api.bus;
+
+import java.util.ArrayList;
+
+public final class BusProtocols {
+ private static final ArrayList> protocols = new ArrayList();
+
+ /**
+ * Add a protocol to the list, if it doesn't exist yet.
+ *
+ * @param packetClass the class of the packet corresponding to the protocol we're adding.
+ * @return the id of the protocol we just added.
+ */
+ public static final int addProtocol(Class extends BusPacket> packetClass){
+ if(!protocols.contains(packetClass)){
+ protocols.add(packetClass);
+ }
+ return protocols.indexOf(packetClass);
+ }
+
+ /**
+ * Gives you the id of the protocol correspondig to a given packet class.
+ *
+ * @param packetClass the class of the packet for which we want to know the protocol ID.
+ * @return the ID of the protocol corresponding to the packet class.
+ */
+ public static final int getProtocolID(Class extends BusPacket> packetClass){
+ return protocols.indexOf(packetClass);
+ }
+
+ private BusProtocols(){}
+}
diff --git a/stargatetech2/api/bus/IBusDevice.java b/stargatetech2/api/bus/IBusDevice.java
new file mode 100644
index 000000000..becf8b4d7
--- /dev/null
+++ b/stargatetech2/api/bus/IBusDevice.java
@@ -0,0 +1,41 @@
+package stargatetech2.api.bus;
+
+import net.minecraft.world.World;
+
+/**
+ * To be implemented by Tile Entities that wish
+ * to access the Abstract Bus.
+ *
+ * @author LordFokas
+ */
+public interface IBusDevice {
+ /**
+ * Returns the IBusInterfaces that exist on that
+ * side of the Tile Entity. It may be multiple
+ * values or null.
+ *
+ * @param side The side of the block that is being queried.
+ * @return This side's IBusInterface, if any.
+ */
+ public IBusInterface[] getInterfaces(int side);
+
+ /**
+ * @return This device's worldObj.
+ */
+ public World getWorld();
+
+ /**
+ * @return This device's X Coordinate.
+ */
+ public int getXCoord();
+
+ /**
+ * @return This device's Y Coordinate.
+ */
+ public int getYCoord();
+
+ /**
+ * @return This device's Z Coordinate.
+ */
+ public int getZCoord();
+}
diff --git a/stargatetech2/api/bus/IBusDriver.java b/stargatetech2/api/bus/IBusDriver.java
new file mode 100644
index 000000000..d4c25d6ae
--- /dev/null
+++ b/stargatetech2/api/bus/IBusDriver.java
@@ -0,0 +1,53 @@
+package stargatetech2.api.bus;
+
+/**
+ * This provides a level of abstraction over the IBusInterface.
+ * Implement to your own liking.
+ *
+ * @author LordFokas
+ */
+public interface IBusDriver {
+ /**
+ * Used to check if this device should receive a specific
+ * packet type from this sender. If true is returned,
+ * handlePacket() is called afterwards.
+ *
+ * @param sender The Bus address of the packet's sender.
+ * @param protocolID The unique ID of this packet type.
+ * @param hasLIP whether the packet can be converted to the LIP format or not.
+ * @return Whether the device will accept this packet or not.
+ */
+ public boolean canHandlePacket(short sender, int protocolID, boolean hasLIP);
+
+ /**
+ * Called by the network to have this device handle a packet.
+ *
+ * @param packet The packet to be handled.
+ */
+ public void handlePacket(BusPacket packet);
+
+ /**
+ * Used to make the IBusDriver give all packets in its send
+ * queue, one by one, to the IBusInterface so that it can
+ * send them accross the network.
+ *
+ * @return The next BusPacket in the queue, if any, null otherise.
+ */
+ public BusPacket getNextPacketToSend();
+
+ /**
+ * Called by the hardware representation (IBusInterface)
+ * to check if it's active or not.
+ * Inactive interfaces cannot send or receive packets.
+ *
+ * @return Whether this interface is active or not.
+ */
+ public boolean isInterfaceEnabled();
+
+ /**
+ * Called by this Driver's Interface to check it's own address.
+ *
+ * @return The address of this IBusDriver's IBusInterface.
+ */
+ public short getInterfaceAddress();
+}
\ No newline at end of file
diff --git a/stargatetech2/api/bus/IBusInterface.java b/stargatetech2/api/bus/IBusInterface.java
new file mode 100644
index 000000000..39a1dfe87
--- /dev/null
+++ b/stargatetech2/api/bus/IBusInterface.java
@@ -0,0 +1,35 @@
+package stargatetech2.api.bus;
+
+import net.minecraft.nbt.NBTTagCompound;
+
+/**
+ * DO NOT IMPLEMENT THIS INTERFACE! To get an instance use
+ * StargateTechAPI.api().getFactory().getIBusInterface();
+ *
+ * @author LordFokas
+ */
+public interface IBusInterface {
+ /**
+ * Makes the IBusInterface call its IBusDriver's
+ * getNextPacketToSend() method repeatedly until it returns
+ * null. Every packet returned by that method will be sent
+ * across the network.
+ */
+ public void sendAllPackets();
+
+ /**
+ * Serialize this object.
+ *
+ * @param nbt The tag compound where this object's data is.
+ * @param tag The name of the tag under which this object's data is stored.
+ */
+ public void writeToNBT(NBTTagCompound nbt, String tag);
+
+ /**
+ * Unserialize this object.
+ *
+ * @param nbt The tag compound where this object's data is.
+ * @param tag The name of the tag under which this object's data is stored.
+ */
+ public void readFromNBT(NBTTagCompound nbt, String tag);
+}
\ No newline at end of file
diff --git a/stargatetech2/api/shields/IShieldable.java b/stargatetech2/api/shields/IShieldable.java
new file mode 100644
index 000000000..b185defe8
--- /dev/null
+++ b/stargatetech2/api/shields/IShieldable.java
@@ -0,0 +1,35 @@
+package stargatetech2.api.shields;
+
+import net.minecraft.world.World;
+
+/**
+ * Used by shield emitters to make shieldable blocks in their way raise and lower their shields.
+ *
+ * @author LordFokas
+ */
+public interface IShieldable {
+ /**
+ * Called by shield emitters to make blocks raise their shields.
+ * The block on {px, py, pz} contains an ITileShieldEmitter from which
+ * you can get the current ShieldPermissions object.
+ *
+ * @param world The world this IShieldable is on.
+ * @param x This IShieldable's X Coordinate.
+ * @param y This IShieldable's Y Coordinate.
+ * @param z This IShieldable's Z Coordinate.
+ * @param px The X Coordinate of the shield emitter raising a shield on this block.
+ * @param py The Y Coordinate of the shield emitter raising a shield on this block.
+ * @param pz The Z Coordinate of the shield emitter raising a shield on this block.
+ */
+ public void onShield(World world, int x, int y, int z, int px, int py, int pz);
+
+ /**
+ * Called by shield emitters to make blocks lower their shields.
+ *
+ * @param world The world this IShieldable is on.
+ * @param x This IShieldable's X Coordinate.
+ * @param y This IShieldable's Y Coordinate.
+ * @param z This IShieldable's Z Coordinate.
+ */
+ public void onUnshield(World world, int x, int y, int z);
+}
\ No newline at end of file
diff --git a/stargatetech2/api/shields/ITileShieldEmitter.java b/stargatetech2/api/shields/ITileShieldEmitter.java
new file mode 100644
index 000000000..96dd027b0
--- /dev/null
+++ b/stargatetech2/api/shields/ITileShieldEmitter.java
@@ -0,0 +1,65 @@
+package stargatetech2.api.shields;
+
+/**
+ * Implemented by the shield emitter TileEntities.
+ *
+ * @author LordFokas
+ */
+public interface ITileShieldEmitter {
+ /**
+ * Given the way shield emitters work together, you cannot
+ * directly access their ShieldPermissions object.
+ * This means you cannot use this method to change
+ * permissions on a shield.
+ *
+ * @return A deep clone of theShieldPermissions object that
+ * defines this emitter's shield behavior.
+ */
+ public ShieldPermissions getPermissions();
+
+ /**
+ * @return True if the shield is activated, false otherwise.
+ */
+ public boolean isShieldOn();
+
+ /**
+ * Update the permissions on this emitter.
+ * It will propagate to the whole shield.
+ *
+ * @param isAllow true if allowing this flag, false if disallowing.
+ * @param flag The flag we're (dis)allowing.
+ * @see stargatetech2.api.ShieldPermissions
+ */
+ public void updatePermissions(boolean isAllow, int flag);
+
+ /**
+ * Update the exceptions on this emitter.
+ * It will propagate to the whole shield.
+ *
+ * @param isAdding true if we're adding a player to the exceptions, false if removing.
+ * @param player The name of the player we're adding / removing.
+ * @see stargatetech2.api.ShieldPermissions
+ */
+ public void updateExceptions(boolean isAdding, String player);
+
+ /**
+ * Sets the owner of this Shield Emitter.
+ * An owner has previleges no other players have.
+ *
+ * @param owner The owner's player name.
+ */
+ public void setOwner(String owner);
+
+ /**
+ * @return The player name of this machine's owner.
+ */
+ public String getOwner();
+
+ /**
+ * Checks if a player can access this device.
+ *
+ * @param player The player's name.
+ * @return Whether or not this player can access this device.
+ */
+ public boolean canAccess(String player);
+}
\ No newline at end of file
diff --git a/stargatetech2/api/shields/ShieldPermissions.java b/stargatetech2/api/shields/ShieldPermissions.java
new file mode 100644
index 000000000..c0cf3920c
--- /dev/null
+++ b/stargatetech2/api/shields/ShieldPermissions.java
@@ -0,0 +1,163 @@
+package stargatetech2.api.shields;
+
+import java.util.ArrayList;
+
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.item.EntityMinecart;
+import net.minecraft.entity.monster.EntityMob;
+import net.minecraft.entity.passive.EntityAnimal;
+import net.minecraft.entity.passive.EntityVillager;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.nbt.NBTTagCompound;
+
+
+public class ShieldPermissions {
+ // Permission Flags
+ public static final int PERM_PLAYER = 0x01;
+ public static final int PERM_VILLAGER = 0x02;
+ public static final int PERM_ANIMAL = 0x04;
+ public static final int PERM_MONSTER = 0x08;
+ public static final int PERM_MINECART = 0x10;
+
+ private int permValue = 0;
+ private ArrayList playerExceptions = new ArrayList();
+
+ /**
+ * @return A default ShieldPermissions object.
+ */
+ public static ShieldPermissions getDefault(){
+ ShieldPermissions perm = new ShieldPermissions();
+ perm.allow(PERM_PLAYER);
+ return perm;
+ }
+
+ /**
+ * @param perm Make shields allow this PERM_* flag.
+ * Combinations (binary or) are allowed.
+ */
+ public void allow(int perm){
+ permValue |= perm;
+ }
+
+ /**
+ * @param perm Make shields disallow this PERM_* flag.
+ * Combinations (binary or) are allowed.
+ */
+ public void disallow(int perm){
+ permValue &= ~perm;
+ }
+
+ /**
+ * Add an exception to the current player permission setting.
+ * @param player The name of the player to add to the exceptions.
+ */
+ public void setPlayerException(String player){
+ if(!playerExceptions.contains(player))
+ playerExceptions.add(player);
+ }
+
+ /**
+ * Remove an exception from the current player permission setting.
+ * @param player The name of the player to remove from the exceptions.
+ */
+ public void removePlayerException(String player){
+ playerExceptions.remove(player);
+ }
+
+ /**
+ * @return A list of strings containing the names of all the players
+ * who currently are exceptions to the player permission setting.
+ */
+ public ArrayList getExceptionList(){
+ return playerExceptions;
+ }
+
+ /**
+ * Check if this entity is allowed to go through the shields.
+ *
+ * @param entity The entity to be checked.
+ * @param doDismount If set to true, when an allowed entity is being ridden
+ * by a disallowed one, it's rider will be dismounted so this entity can pass.
+ * @return Whether this entity can go through or not.
+ */
+ public boolean isEntityAllowed(Entity entity, boolean doDismount){
+ boolean allow = false;
+ if(entity instanceof EntityPlayer){
+ if(hasBit(PERM_PLAYER)){
+ allow = true;
+ }
+ if(playerExceptions.contains(entity.getEntityName())){
+ allow = !allow;
+ }
+ }else if(entity instanceof EntityVillager){
+ allow = hasBit(PERM_VILLAGER);
+ }else if(entity instanceof EntityAnimal){
+ allow = hasBit(PERM_ANIMAL);
+ }else if(entity instanceof EntityMob){
+ allow = hasBit(PERM_MONSTER);
+ }else if(entity instanceof EntityMinecart){
+ allow = hasBit(PERM_MINECART);
+ }
+ if(allow && entity.riddenByEntity != null && doDismount && entity.worldObj.isRemote == false){
+ if(!isEntityAllowed(entity.riddenByEntity, true)){
+ Entity rider = entity.riddenByEntity;
+ if(rider instanceof EntityPlayer){
+ rider.mountEntity(null);
+ }else{
+ rider.ridingEntity = null;
+ rider.prevPosY += 1;
+ rider.posY += 1;
+ entity.riddenByEntity = null;
+ }
+ }
+ }
+ return allow;
+ }
+
+ /**
+ * @param bit A binary flag to check against these permissions.
+ * While usually this is a PERM_* flag, any combination of bits is allowed.
+ * @return Whether this flag exists in these permissions or not.
+ */
+ public boolean hasBit(int bit){
+ return (permValue & bit) != 0;
+ }
+
+ /**
+ * @return A deep clone of this object.
+ */
+ public ShieldPermissions deepClone(){
+ ShieldPermissions clone = new ShieldPermissions();
+ clone.permValue = this.permValue;
+ for(String player : playerExceptions){
+ clone.playerExceptions.add(player);
+ }
+ return clone;
+ }
+
+ // This really doesn't need an explanation...
+ public static ShieldPermissions readFromNBT(NBTTagCompound nbt){
+ ShieldPermissions permissions = getDefault();
+ if(nbt != null){
+ int exceptions = nbt.getInteger("exceptions");
+ permissions.permValue = nbt.getInteger("permValue");
+ permissions.playerExceptions = new ArrayList(exceptions);
+ for(int i = 0; i < exceptions; i++){
+ permissions.setPlayerException(nbt.getString("pex" + i));
+ }
+ }
+ return permissions;
+ }
+
+ // ... does it?
+ public NBTTagCompound writeToNBT(){
+ NBTTagCompound nbt = new NBTTagCompound();
+ int exceptions = playerExceptions.size();
+ nbt.setInteger("permValue", permValue);
+ nbt.setInteger("exceptions", exceptions);
+ for(int i = 0; i < exceptions; i++){
+ nbt.setString("pex" + i, playerExceptions.get(i));
+ }
+ return nbt;
+ }
+}
\ No newline at end of file
diff --git a/stargatetech2/api/stargate/Address.java b/stargatetech2/api/stargate/Address.java
new file mode 100644
index 000000000..5f7caa404
--- /dev/null
+++ b/stargatetech2/api/stargate/Address.java
@@ -0,0 +1,82 @@
+package stargatetech2.api.stargate;
+
+public class Address {
+ private Symbol[] symbols;
+
+ public static Address create(Symbol[] symbols){
+ try{
+ boolean used[] = new boolean[40];
+ if(symbols.length < 7) throw new Exception("Address too short: " + symbols.length);
+ if(symbols.length > 9) throw new Exception("Address too long: " + symbols.length);
+ for(int i = 0; i < used.length; i++){
+ used[i] = (i == 0);
+ }
+ for(Symbol symbol : symbols){
+ if(symbol == null || symbol == Symbol.VOID){
+ throw new Exception("Invalid Symbol.");
+ }
+ if(used[symbol.ordinal()]){
+ throw new Exception("Repeated Symbol.");
+ }
+ used[symbol.ordinal()] = true;
+ }
+ return new Address(symbols);
+ }catch(Exception e){
+ return null;
+ }
+ }
+
+ private Address(Symbol[] symbols){
+ this.symbols = symbols;
+ }
+
+ public int length(){
+ return symbols.length;
+ }
+
+ public Symbol getSymbol(int symbol){
+ if(symbol >= 0 && symbol < length()){
+ return symbols[symbol];
+ }else{
+ return Symbol.VOID;
+ }
+ }
+
+ @Override
+ public String toString(){
+ StringBuilder sb = new StringBuilder();
+ sb.append(getSymbol(0).toString());
+ sb.append(getSymbol(1).toString().toLowerCase());
+ sb.append(getSymbol(2).toString().toLowerCase());
+ sb.append(" ");
+ sb.append(getSymbol(3).toString());
+ sb.append(getSymbol(4).toString().toLowerCase());
+ sb.append(getSymbol(5).toString().toLowerCase());
+ sb.append(" ");
+ sb.append(getSymbol(6).toString());
+ sb.append(getSymbol(7).toString().toLowerCase());
+ sb.append(getSymbol(8).toString().toLowerCase());
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o){
+ if(o instanceof Address){
+ Address a = (Address) o;
+ if(a.length() == length()){
+ for(int i = 0; i < length(); i++){
+ if(symbols[i] != a.symbols[i]){
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode(){
+ return length();
+ }
+}
\ No newline at end of file
diff --git a/stargatetech2/api/stargate/IStargateNetwork.java b/stargatetech2/api/stargate/IStargateNetwork.java
new file mode 100644
index 000000000..7bd3ce4c5
--- /dev/null
+++ b/stargatetech2/api/stargate/IStargateNetwork.java
@@ -0,0 +1,36 @@
+package stargatetech2.api.stargate;
+
+import net.minecraft.world.World;
+
+public interface IStargateNetwork {
+ /**
+ * @return Whether the Stargate Network is loaded (working) or not.
+ */
+ public boolean isLoaded();
+
+ /**
+ * @param address The string representation of an address. (e.g. "Proclarush Taonas At")
+ * @return an address object if the string is a valid address, null otherwise.
+ */
+ public Address parseAddress(String address);
+
+ /**
+ * Checks if a given address exists in the network or not.
+ * (i.e., if this address maps to a physical Stargate)
+ *
+ * @param address the address we want to check.
+ * @return whether the address exists or not.
+ */
+ public boolean addressExists(Address address);
+
+ /**
+ * Returns the address of the Stargate in a specific location if it exists or null otherwise.
+ *
+ * @param world The world the target Stargate is in.
+ * @param x The target Stargate's X coordinate.
+ * @param y The target Stargate's Y coordinate.
+ * @param z The target Stargate's Z coordinate.
+ * @return The Stargate's address, or null if the location doesn't contain a Stargate.
+ */
+ public Address getAddressOf(World world, int x, int y, int z);
+}
\ No newline at end of file
diff --git a/stargatetech2/api/stargate/ITileStargate.java b/stargatetech2/api/stargate/ITileStargate.java
new file mode 100644
index 000000000..b50d2d8ab
--- /dev/null
+++ b/stargatetech2/api/stargate/ITileStargate.java
@@ -0,0 +1,16 @@
+package stargatetech2.api.stargate;
+
+/**
+ * Represents a Stargate ring.
+ * Stargate "base" blocks contain the ring, so they implement this as well.
+ *
+ * All you can get from the Stargate ring is the address.
+ *
+ * @author LordFokas
+ */
+public interface ITileStargate {
+ /**
+ * @return This Stargate's address. null values are possible on the client side.
+ */
+ public Address getAddress();
+}
\ No newline at end of file
diff --git a/stargatetech2/api/stargate/ITileStargateBase.java b/stargatetech2/api/stargate/ITileStargateBase.java
new file mode 100644
index 000000000..43e8fdae6
--- /dev/null
+++ b/stargatetech2/api/stargate/ITileStargateBase.java
@@ -0,0 +1,25 @@
+package stargatetech2.api.stargate;
+
+/**
+ * Represents a Stargate base block (the block that supports the stargate).
+ *
+ * It contains all the important logic in the Stargate,
+ * like dialing, Iris control and power usage.
+ *
+ * Because the ring is inside the block that supports it, it is possible to
+ * call the same methods you can call on a ring.
+ *
+ * @see ITileStargate
+ *
+ * @author LordFokas
+ */
+public interface ITileStargateBase extends ITileStargate{
+
+ /**
+ * Used to try making the Stargate dial an address.
+ *
+ * @param address The address this Stargate should dial.
+ * @return whether the dialing sequence started (true) or failed (false).
+ */
+ public boolean dial(Address address);
+}
\ No newline at end of file
diff --git a/stargatetech2/api/stargate/Symbol.java b/stargatetech2/api/stargate/Symbol.java
new file mode 100644
index 000000000..dcad644a7
--- /dev/null
+++ b/stargatetech2/api/stargate/Symbol.java
@@ -0,0 +1,63 @@
+package stargatetech2.api.stargate;
+
+public enum Symbol {
+ VOID(""),
+ AT ("At"), // 1
+ AL ("Al"), // 2
+ CLA ("Cla"), // 3
+ UR ("Ur"), // 4
+ ON ("On"), // 5
+ DEH ("Deh"), // 6
+ EC ("Ec"), // 7
+ MIG ("Mig"), // 8
+ AM ("Am"), // 9
+ RUM ("Rum"), // 10
+ AR ("Ar"), // 11
+ VA ("Va"), // 12
+ COR ("Cor"), // 13
+ PRA ("Pra"), // 14
+ OM ("Om"), // 15
+ ET ("Et"), // 16
+ AS ("As"), // 17
+ US ("Us"), // 18
+ GON ("Gon"), // 19
+ ORM ("Orm"), // 20
+ EM ("Em"), // 21
+ AC ("Ac"), // 22
+ OTH ("Oth"), // 23
+ LOS ("Los"), // 24
+ LAN ("Lan"), // 25
+ EST ("Est"), // 26
+ CRO ("Cro"), // 27
+ SIL ("Sil"), // 28
+ TA ("Ta"), // 29
+ BREI("Brei"), // 30
+ RUSH("Rush"), // 31
+ ERP ("Erp"), // 32
+ SET ("Set"), // 33
+ ULF ("Ulf"), // 34
+ PRO ("Pro"), // 35
+ SAL ("Sal"), // 36
+ TIS ("Tis"), // 37
+ MAC ("Mac"), // 38
+ IRT ("Irt"); // 39
+
+ private String name;
+
+ private Symbol(String name){
+ this.name = name;
+ }
+
+ public static Symbol get(int s){
+ if(s >= 0 && s <= 39){
+ return values()[s];
+ }else{
+ return VOID;
+ }
+ }
+
+ @Override
+ public String toString(){
+ return name;
+ }
+}
\ No newline at end of file