package li.cil.oc.api.prefab; import li.cil.oc.api.Network; 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 net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ITickable; /** * TileEntities can implement the {@link li.cil.oc.api.network.Environment} * interface to allow them to interact with the component network, by providing * a {@link li.cil.oc.api.network.Node} and connecting it to said network. * <p/> * Nodes in such a network can communicate with each other, or just use the * network as an index structure to find other nodes connected to them. */ @SuppressWarnings("UnusedDeclaration") public abstract class TileEntityEnvironment extends TileEntity implements Environment, ITickable { /** * This must be set in subclasses to the node that is used to represent * this tile entity. * <p/> * You must only create new nodes using the factory method in the network * API, {@link li.cil.oc.api.Network#newNode(Environment, Visibility)}. * <p/> * For example: * <pre> * // The first parameters to newNode is the host() of the node, which will * // usually be this tile entity. The second one is it's reachability, * // which determines how other nodes in the same network can query this * // node. See {@link li.cil.oc.api.network.Network#nodes(li.cil.oc.api.network.Node)}. * node = Network.newNode(this, Visibility.Network) * // This call allows the node to consume energy from the * // component network it is in and act as a consumer, or to * // inject energy into that network and act as a producer. * // If you do not need energy remove this call. * .withConnector() * // This call marks the tile entity as a component. This means you * // can mark methods in it using the {@link li.cil.oc.api.machine.Callback} * // annotation, making them callable from user code. The first * // parameter is the name by which the component will be known in * // the computer, in this case it could be accessed as * // <tt>component.example</tt>. The second parameter is the * // component's visibility. This is like the node's reachability, * // but only applies to computers. For example, network cards can * // only be <em>seen</em> by the computer they're installed in, but * // can be <em>reached</em> by all other network cards in the same * // network. If you do not need callbacks remove this call. * .withComponent("example", Visibility.Neighbors) * // Finalizes the construction of the node and returns it. * .create(); * </pre> */ protected Node node; // See updateEntity(). protected boolean addedToNetwork = false; // ----------------------------------------------------------------------- // @Override public Node node() { return node; } @Override public void onConnect(final Node node) { // This is called when the call to Network.joinOrCreateNetwork(this) in // updateEntity was successful, in which case `node == this`. // This is also called for any other node that gets connected to the // network our node is in, in which case `node` is the added node. // If our node is added to an existing network, this is called for each // node already in said network. } @Override public void onDisconnect(final Node node) { // This is called when this node is removed from its network when the // tile entity is removed from the world (see onChunkUnload() and // invalidate()), in which case `node == this`. // This is also called for each other node that gets removed from the // network our node is in, in which case `node` is the removed node. // If a net-split occurs this is called for each node that is no longer // connected to our node. } @Override public void onMessage(final Message message) { // This is used to deliver messages sent via node.sendToXYZ. Handle // messages at your own discretion. If you do not wish to handle a // message you should *not* throw an exception, though. } // ----------------------------------------------------------------------- // @Override public void update() { // On the first update, try to add our node to nearby networks. We do // this in the update logic, not in validate() because we need to access // neighboring tile entities, which isn't possible in validate(). // We could alternatively check node != null && node.network() == null, // but this has somewhat better performance, and makes it clearer. if (!addedToNetwork) { addedToNetwork = true; Network.joinOrCreateNetwork(this); } } @Override public void onChunkUnload() { super.onChunkUnload(); // Make sure to remove the node from its network when its environment, // meaning this tile entity, gets unloaded. if (node != null) node.remove(); } @Override public void invalidate() { super.invalidate(); // Make sure to remove the node from its network when its environment, // meaning this tile entity, gets unloaded. if (node != null) node.remove(); } // ----------------------------------------------------------------------- // @Override public void readFromNBT(final NBTTagCompound nbt) { super.readFromNBT(nbt); // The host check may be superfluous for you. It's just there to allow // some special cases, where getNode() returns some node managed by // some other instance (for example when you have multiple internal // nodes in this tile entity). if (node != null && node.host() == this) { // This restores the node's address, which is required for networks // to continue working without interruption across loads. If the // node is a power connector this is also required to restore the // internal energy buffer of the node. node.load(nbt.getCompoundTag("oc:node")); } } @Override public NBTTagCompound writeToNBT(final NBTTagCompound nbt) { super.writeToNBT(nbt); // See readFromNBT() regarding host check. if (node != null && node.host() == this) { final NBTTagCompound nodeNbt = new NBTTagCompound(); node.save(nodeNbt); nbt.setTag("oc:node", nodeNbt); } return nbt; } }