blob: ab3808f30ebfd3e52a825c3a6563787edc37a812 [file] [log] [blame] [raw]
package li.cil.oc.api.network
import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.relauncher.Side
import li.cil.oc.OpenComputers
import net.minecraft.nbt.NBTTagCompound
/**
* This trait may be used in nodes that should be visible to computers.
* <p/>
* Computer "visibility" may have to differ from real network visibility in
* some cases, such as network cards (which have to be able to communicate
* across the whole network, but a computer should only "see" the card
* installed in itself).
* <p/>
* Unlike the node's network visibility, this is a dynamic value and can be
* changed at any time. For example, this is used to hide multi-block screen
* parts that are not the origin from computers in the network.
* <p/>
* The method responsible for dispatching network messages from computers also
* checks this flag, so nodes won't receive messages from computer's that
* should not be able to see them.
*/
trait ComputerVisible extends Node {
private var visibility_ = Visibility.None
/**
* The visibility of this node when it comes to computers.
* <p/>
* This is used to decide for which components to generate `component_added`
* and `component_removed` signals in computers when they are added and
* removed from the network, respectively.
* <p/>
* For example, a network card should be visible to the entire network so
* that it can receive messages from network cards in other computers, but
* other computers that the one it is plugged into should not treat them as
* components added to them, since that would be silly, meaning this field
* will be set to neighbors only for them.
* <p/>
* Another example would power distributors, which should also be visible
* to the entire network, but always be invisible to computers, so their
* value for this field will be `Visibility.None`.
*/
def computerVisibility = visibility_
def computerVisibility_=(value: Visibility.Value) = {
val newVisibility = if (value > visibility) {
OpenComputers.log.warning("Trying to set computer visibility to '" + value + "' on a node with visibility '" +
visibility + "'. It will be limited to the node's visibility.")
visibility
}
else value
if (newVisibility != visibility_ && FMLCommonHandler.instance.getEffectiveSide == Side.SERVER) {
visibility_ match {
case Visibility.Neighbors => newVisibility match {
case Visibility.Network =>
network.foreach(network => {
val neighbors = network.neighbors(this).toSet
val visible = network.nodes(this)
val delta = visible.filterNot(neighbors.contains)
delta.foreach(node => network.sendToAddress(this, node.address.get, "computer.signal", "component_added"))
})
case Visibility.None => network.foreach(_.sendToNeighbors(this, "computer.signal", "component_removed"))
case _ => // Cannot happen, but avoids compiler warnings.
}
case Visibility.Network => newVisibility match {
case Visibility.Neighbors =>
network.foreach(network => {
val neighbors = network.neighbors(this).toSet
val visible = network.nodes(this)
val delta = visible.filterNot(neighbors.contains)
delta.foreach(node => network.sendToAddress(this, node.address.get, "computer.signal", "component_removed"))
})
case Visibility.None => network.foreach(_.sendToVisible(this, "computer.signal", "component_removed"))
case _ => // Cannot happen, but avoids compiler warnings.
}
case Visibility.None => newVisibility match {
case Visibility.Neighbors => network.foreach(_.sendToNeighbors(this, "computer.signal", "component_added"))
case Visibility.Network => network.foreach(_.sendToVisible(this, "computer.signal", "component_added"))
case _ => // Cannot happen, but avoids compiler warnings.
}
}
visibility_ = newVisibility
}
this
}
/**
* Tests whether this node can be seen by the specified node, representing a
* computer in the network.
*
* @param computer the computer node to check for.
* @return true if the computer can see this node; false otherwise.
*/
def canBeSeenBy(computer: Node) = computerVisibility match {
case Visibility.None => false
case Visibility.Network => true
case Visibility.Neighbors => network.exists(_.neighbors(computer).exists(_ == this))
}
// ----------------------------------------------------------------------- //
override def receive(message: Message) = super.receive(message) orElse {
message.name match {
case "computer.started" if canBeSeenBy(message.source) =>
network.get.sendToAddress(this, message.source.address.get, "computer.signal", "component_added")
case _ => None
}
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) {
super.load(nbt)
if (nbt.hasKey("computerVisibility"))
visibility_ = Visibility(nbt.getInteger("computerVisibility"))
}
override def save(nbt: NBTTagCompound) {
super.save(nbt)
nbt.setInteger("computerVisibility", visibility_.id)
}
}