blob: 590a56cea9593c80554eba8ab1e9b611d179aba6 [file] [log] [blame] [raw]
package li.cil.oc.common.tileentity
import java.util.UUID
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.Driver
import li.cil.oc.api.fs.Label
import li.cil.oc.api.network.Analyzable
import li.cil.oc.api.network.Visibility
import li.cil.oc.common.Slot
import li.cil.oc.server.component.FileSystem
import li.cil.oc.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
class Raid extends traits.Environment with traits.Inventory with traits.Rotatable with Analyzable {
val node = api.Network.newNode(this, Visibility.None).create()
var filesystem: Option[FileSystem] = None
val label = new RaidLabel()
// Used on client side to check whether to render disk activity indicators.
var lastAccess = 0L
// For client side rendering.
val presence = Array.fill(getSizeInventory)(false)
// ----------------------------------------------------------------------- //
override def onAnalyze(player: EntityPlayer, side: Int, hitX: Float, hitY: Float, hitZ: Float) = Array(filesystem.map(_.node).orNull)
override def canUpdate = false
// ----------------------------------------------------------------------- //
override def getSizeInventory = 3
override def getInventoryStackLimit = 1
override def isItemValidForSlot(slot: Int, stack: ItemStack) = Option(Driver.driverFor(stack, getClass)) match {
case Some(driver) => driver.slot(stack) == Slot.HDD
case _ => false
}
override protected def onItemAdded(slot: Int, stack: ItemStack) {
super.onItemAdded(slot, stack)
if (isServer) this.synchronized {
ServerPacketSender.sendRaidChange(this)
tryCreateRaid(UUID.randomUUID().toString)
}
}
override def markDirty() {
super.markDirty()
// Makes the implementation of the comparator output easier.
items.map(_.isDefined).copyToArray(presence)
}
override protected def onItemRemoved(slot: Int, stack: ItemStack) {
super.onItemRemoved(slot, stack)
if (isServer) this.synchronized {
ServerPacketSender.sendRaidChange(this)
filesystem.foreach(fs => {
fs.fileSystem.close()
fs.fileSystem.list("/").foreach(fs.fileSystem.delete)
fs.save(new NBTTagCompound()) // Flush buffered fs.
fs.node.remove()
filesystem = None
})
}
}
def tryCreateRaid(id: String) {
if (items.count(_.isDefined) == items.length && filesystem.fold(true)(fs => fs.node == null || fs.node.address != id)) {
filesystem.foreach(fs => if (fs.node != null) fs.node.remove())
val fs = api.FileSystem.asManagedEnvironment(
api.FileSystem.fromSaveDirectory(id, wipeDisksAndComputeSpace, Settings.get.bufferChanges),
label, this, Settings.resourceDomain + ":hdd_access", 6).
asInstanceOf[FileSystem]
val nbtToSetAddress = new NBTTagCompound()
nbtToSetAddress.setString("address", id)
fs.node.load(nbtToSetAddress)
fs.node.setVisibility(Visibility.Network)
// Ensure we're in a network before connecting the raid fs.
api.Network.joinNewNetwork(node)
node.connect(fs.node)
filesystem = Option(fs)
}
}
private def wipeDisksAndComputeSpace = items.foldLeft(0L) {
case (acc, Some(hdd)) => acc + (Option(api.Driver.driverFor(hdd)) match {
case Some(driver) => driver.createEnvironment(hdd, this) match {
case fs: FileSystem =>
val nbt = driver.dataTag(hdd)
fs.load(nbt)
fs.fileSystem.close()
fs.fileSystem.list("/").foreach(fs.fileSystem.delete)
fs.save(nbt)
fs.fileSystem.spaceTotal.toInt
case _ => 0L // Ignore.
}
case _ => 0L
})
case (acc, None) => acc
}
// ----------------------------------------------------------------------- //
override def readFromNBTForServer(nbt: NBTTagCompound) {
super.readFromNBTForServer(nbt)
if (nbt.hasKey(Settings.namespace + "fs")) {
val tag = nbt.getCompoundTag(Settings.namespace + "fs")
tryCreateRaid(tag.getCompoundTag("node").getString("address"))
filesystem.foreach(fs => fs.load(tag))
}
label.load(nbt)
}
override def writeToNBTForServer(nbt: NBTTagCompound) {
super.writeToNBTForServer(nbt)
filesystem.foreach(fs => nbt.setNewCompoundTag(Settings.namespace + "fs", fs.save))
label.save(nbt)
}
@SideOnly(Side.CLIENT) override
def readFromNBTForClient(nbt: NBTTagCompound) {
super.readFromNBTForClient(nbt)
nbt.getByteArray("presence").
map(_ != 0).
copyToArray(presence)
label.setLabel(nbt.getString("label"))
}
override def writeToNBTForClient(nbt: NBTTagCompound) {
super.writeToNBTForClient(nbt)
nbt.setTag("presence", items.map(_.isDefined))
if (label.getLabel != null)
nbt.setString("label", label.getLabel)
}
// ----------------------------------------------------------------------- //
class RaidLabel extends Label {
var label = "raid"
override def getLabel = label
override def setLabel(value: String) = label = Option(value).map(_.take(16)).orNull
override def load(nbt: NBTTagCompound) {
if (nbt.hasKey(Settings.namespace + "label")) {
label = nbt.getString(Settings.namespace + "label")
}
}
override def save(nbt: NBTTagCompound) {
nbt.setString(Settings.namespace + "label", label)
}
}
}