blob: b61f576394dc3bd979775dfc1f9a1b6532debd06 [file] [log] [blame] [raw]
package li.cil.oc.server.driver
import li.cil.oc.api
import li.cil.oc.api.driver
import li.cil.oc.api.network._
import li.cil.oc.util.ExtendedNBT._
import net.minecraft.block.Block
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.world.World
class MultiBlockDriver(val blocks: driver.Block*) extends driver.Block {
override def createEnvironment(world: World, x: Int, y: Int, z: Int) = blocks.map {
driver => Option(driver.createEnvironment(world, x, y, z)) match {
case Some(environment) => (driver, environment)
case _ => null
}
} filter (_ != null) match {
case Seq() => null
case list =>
val blockId = world.getBlockId(x, y, z)
val isValidBlock = blockId >= 0 && blockId < Block.blocksList.length && Block.blocksList(blockId) != null
val name =
if (isValidBlock) {
val metadata = world.getBlockMetadata(x, y, z)
cleanName(new ItemStack(blockId, 1, metadata).getUnlocalizedName)
}
else "multi"
new MultiBlockEnvironment(name, list: _*)
}
override def worksWith(world: World, stack: ItemStack) = blocks.forall(_.worksWith(world, stack))
override def worksWith(world: World, x: Int, y: Int, z: Int) = blocks.forall(_.worksWith(world, x, y, z))
override def equals(obj: Any) = obj match {
case multi: MultiBlockDriver if multi.blocks.length == blocks.length =>
(multi.blocks, blocks).zipped.forall((a, b) => a.getClass.getName == b.getClass.getName)
true
case _ => false
}
private def cleanName(name: String) = {
val withoutNameSpace = if (name.contains(":")) name.substring(name.indexOf(":") + 1) else name
val withoutPrefixes = if (withoutNameSpace.contains(".")) withoutNameSpace.substring(withoutNameSpace.lastIndexOf(".") + 1) else withoutNameSpace
withoutPrefixes
}
}
class MultiBlockEnvironment(val name: String, val environments: (driver.Block, ManagedEnvironment)*) extends ManagedEnvironment {
// 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 node = api.Network.newNode(this, (environments.filter(_._2.node != null).map(_._2.node.reachability) ++ Seq(Visibility.None)).max).
withComponent(name).
create()
// 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.node match {
case component: Component => component.setVisibility(Visibility.Neighbors)
case _ =>
}
override def canUpdate = environments.exists(_._2.canUpdate)
override def update() {
for ((_, environment) <- environments if environment.canUpdate) {
environment.update()
}
}
override def onMessage(message: Message) {}
override def onConnect(node: Node) {
if (node == this.node) {
for ((_, environment) <- environments if environment.node != null) {
node.connect(environment.node)
}
}
}
override def onDisconnect(node: Node) {
if (node == this.node) {
for ((_, environment) <- environments if environment.node != null) {
environment.node.remove()
}
}
}
override def load(nbt: NBTTagCompound) {
node.load(nbt)
for ((driver, environment) <- environments) {
val name = driver.getClass.getName
if (nbt.hasKey(name)) {
environment.load(nbt.getCompoundTag(name))
}
}
}
override def save(nbt: NBTTagCompound) {
node.save(nbt)
for ((driver, environment) <- environments) {
val name = driver.getClass.getName
nbt.setNewCompoundTag(name, environment.save)
}
}
}