OpenComputers/src/main/scala/li/cil/oc/server/driver/CompoundBlockNodeContainer.scala
2017-03-25 12:55:57 +01:00

94 lines
3.1 KiB
Scala

package li.cil.oc.server.driver
import java.nio.charset.Charset
import com.google.common.hash.Hashing
import li.cil.oc.OpenComputers
import li.cil.oc.api
import li.cil.oc.api.network._
import net.minecraft.nbt.NBTTagCompound
class CompoundBlockNodeContainer(val name: String, val environments: (String, NodeContainerItem)*) extends NodeContainerItem {
// Block drivers with visibility < network usually won't make much sense,
// but let's play it safe and use the least possible visibility based on
// the drivers we encapsulate.
val getNode: ComponentNode = api.Network.newNode(this, (environments.filter(_._2.getNode != null).map(_._2.getNode.getReachability) ++ Seq(Visibility.NONE)).max).
withComponent(name).
create()
val updatingEnvironments = environments.map(_._2).filter(_.canUpdate)
// Force all wrapped components to be neighbor visible, since we as their
// only neighbor will take care of all component-related interaction.
for ((_, environment) <- environments) environment.getNode match {
case component: ComponentNode => component.setVisibility(Visibility.NEIGHBORS)
case _ =>
}
override def canUpdate: Boolean = environments.exists(_._2.canUpdate)
override def update() {
for (environment <- updatingEnvironments) {
environment.update()
}
}
override def onMessage(message: Message) {}
override def onConnect(node: Node) {
if (node == this.getNode) {
for ((_, environment) <- environments if environment.getNode != null) {
node.connect(environment.getNode)
}
}
}
override def onDisconnect(node: Node) {
if (node == this.getNode) {
for ((_, environment) <- environments if environment.getNode != null) {
environment.getNode.remove()
}
}
}
private final val TypeHashTag = "typeHash"
override def serializeNBT(): NBTTagCompound = {
val nbt = new NBTTagCompound()
nbt.setLong(TypeHashTag, typeHash)
getNode.save(nbt)
for ((driver, environment) <- environments) {
try {
nbt.setTag(driver, environment.serializeNBT())
} catch {
case e: Throwable => OpenComputers.log.warn(s"A block component of type '${environment.getClass.getName}' (provided by driver '$driver') threw an error while saving.", e)
}
}
nbt
}
override def deserializeNBT(nbt: NBTTagCompound): Unit = {
// Ignore existing data if the underlying type is different.
if (nbt.hasKey(TypeHashTag) && nbt.getLong(TypeHashTag) != typeHash) return
getNode.load(nbt)
for ((driver, environment) <- environments) {
if (nbt.hasKey(driver)) {
try {
environment.deserializeNBT(nbt.getCompoundTag(driver))
} catch {
case e: Throwable => OpenComputers.log.warn(s"A block component of type '${environment.getClass.getName}' (provided by driver '$driver') threw an error while loading.", e)
}
}
}
}
override def save(nbt: NBTTagCompound) {
}
private def typeHash = {
val hash = Hashing.sha256().newHasher()
environments.map(_._2.getClass.getName).sorted.foreach(hash.putString(_, Charset.defaultCharset()))
hash.hash().asLong()
}
}