blob: 3a6c3dc991ebf144fbdf660fbb16878a68f5e5ff [file] [log] [blame] [raw]
package li.cil.oc.server.component
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.Driver
import li.cil.oc.api.Machine
import li.cil.oc.api.driver.item.Memory
import li.cil.oc.api.driver.item.Processor
import li.cil.oc.api.internal
import li.cil.oc.api.machine.Architecture
import li.cil.oc.api.machine.MachineHost
import li.cil.oc.api.network.Environment
import li.cil.oc.api.network.Message
import li.cil.oc.api.network.Node
import li.cil.oc.api.network.Visibility
import li.cil.oc.common.Slot
import li.cil.oc.common.init.Items
import li.cil.oc.common.inventory.ComponentInventory
import li.cil.oc.common.inventory.ServerInventory
import li.cil.oc.common.item
import li.cil.oc.common.tileentity
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.util.ForgeDirection
class Server(val rack: tileentity.ServerRack, val slot: Int) extends Environment with MachineHost with internal.Server {
val machine = Machine.create(this)
val inventory = new NetworkedInventory()
// Used to grab messages when not connected to any side in the server rack.
val node = api.Network.newNode(this, Visibility.Network).create()
machine.onHostChanged()
def tier = Items.multi.subItem(rack.getStackInSlot(slot)) match {
case Some(server: item.Server) => server.tier
case _ => 0
}
// ----------------------------------------------------------------------- //
override def cpuArchitecture: Class[_ <: Architecture] = {
for (i <- 0 until inventory.getSizeInventory if inventory.isComponentSlot(i)) Option(inventory.getStackInSlot(i)) match {
case Some(s) => Option(Driver.driverFor(s, rack.getClass)) match {
case Some(driver: Processor) if driver.slot(s) == Slot.CPU => return driver.architecture(s)
case _ =>
}
case _ =>
}
null
}
override def callBudget = inventory.items.foldLeft(0.0)((sum, item) => sum + (item match {
case Some(stack) => Option(Driver.driverFor(stack, getClass)) match {
case Some(driver: Processor) if driver.slot(stack) == Slot.CPU => Settings.get.callBudgets(driver.tier(stack))
case _ => 0
}
case _ => 0
}))
override def installedMemory = inventory.items.foldLeft(0)((sum, item) => sum + (item match {
case Some(stack) => Option(Driver.driverFor(stack, rack.getClass)) match {
case Some(driver: Memory) => driver.amount(stack)
case _ => 0
}
case _ => 0
}))
lazy val maxComponents = if (!hasCPU) 0
else inventory.items.foldLeft(0)((sum, stack) => sum + (stack match {
case Some(item) => Option(Driver.driverFor(item, rack.getClass)) match {
case Some(driver: Processor) => driver.supportedComponents(item)
case _ => 0
}
case _ => 0
}))
override def componentSlot(address: String) = inventory.components.indexWhere(_.exists(env => env.node != null && env.node.address == address))
def hasCPU = inventory.items.exists {
case Some(stack) => Option(Driver.driverFor(stack, rack.getClass)) match {
case Some(driver) => driver.slot(stack) == Slot.CPU
case _ => false
}
case _ => false
}
override def xPosition = rack.x + 0.5
override def yPosition = rack.y + 0.5
override def zPosition = rack.z + 0.5
override def world = rack.world
override def markForSaving() = rack.markForSaving()
override def markChanged() = rack.markChanged()
// ----------------------------------------------------------------------- //
override def onConnect(node: Node) {}
override def onDisconnect(node: Node) {}
override def onMessage(message: Message) {
// If we're internal mode and this server is not connected to any side, we
// must manually propagate network messages to other servers in the rack.
// Ensure the message originated in our local network, to avoid infinite
// recursion if two unconnected servers are in one server rack.
if (rack.internalSwitch && message.name == "network.message" &&
rack.sides(this.slot) == None && // Only if we're in internal mode.
message.source != machine.node && // In this case it was relayed from another internal machine.
node.network.node(message.source.address) != null) {
for (slot <- 0 until rack.servers.length) {
rack.servers(slot) match {
case Some(server) if server != this => server.machine.node.sendToNeighbors(message.name, message.data: _*)
case _ =>
}
}
}
}
override def onMachineConnect(node: Node) {
if (node == machine.node) {
node.connect(this.node)
}
inventory.onConnect(node)
}
override def onMachineDisconnect(node: Node) = inventory.onDisconnect(node)
def load(nbt: NBTTagCompound) {
machine.load(nbt.getCompoundTag("machine"))
}
def save(nbt: NBTTagCompound) {
nbt.setNewCompoundTag("machine", machine.save)
inventory.saveComponents()
inventory.markDirty()
}
// Required due to abstract overrides in component inventory.
class NetworkedInventory extends ServerInventory with ComponentInventory {
override def onConnect(node: Node) {
if (node == this.node) {
connectComponents()
}
}
override def onDisconnect(node: Node) {
if (node == this.node) {
disconnectComponents()
}
}
override def tier = Server.this.tier
var containerOverride: ItemStack = _
override def container = if (containerOverride != null) containerOverride else rack.getStackInSlot(slot)
override def node() = machine.node
override def onMessage(message: Message) {}
override def host = rack
// Resolves conflict between ComponentInventory and ServerInventory.
override def getInventoryStackLimit = 1
}
}