/**
* Copyright (c) Lambda Innovation, 2013-2016
* This file is part of the AcademyCraft mod.
* https://github.com/LambdaInnovation/AcademyCraft
* Licensed under GPLv3, see project root for more information.
*/
package cn.academy.energy.internal;
import cn.academy.core.AcademyCraft;
import cn.academy.energy.api.block.IWirelessGenerator;
import cn.academy.energy.api.block.IWirelessNode;
import cn.academy.energy.api.block.IWirelessReceiver;
import cn.academy.energy.internal.VBlocks.VBlock;
import cn.academy.energy.internal.VBlocks.VNGenerator;
import cn.academy.energy.internal.VBlocks.VNNode;
import cn.academy.energy.internal.VBlocks.VNReceiver;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import java.util.*;
/**
* @author WeAthFolD
*
*/
public class NodeConn {
private static final int UPDATE_INTERVAL = 40;
private final WiWorldData data;
private final VNNode node;
private boolean disposed = false;
private List<VNReceiver> receivers = new LinkedList<>();
private List<VNGenerator> generators = new LinkedList<>();
private List<VNReceiver> toRemoveReceivers = new ArrayList<>();
private List<VNGenerator> toRemoveGenerators = new ArrayList<>();
public NodeConn(WiWorldData _data, VNNode _node) {
data = _data;
node = _node;
}
public NodeConn(WiWorldData _data, NBTTagCompound tag) {
data = _data;
node = new VNNode(tag.getCompoundTag("node"));
NBTTagList list = (NBTTagList) tag.getTag("receivers");
for(int i = 0; i < list.tagCount(); ++i) {
addReceiver(new VNReceiver(list.getCompoundTagAt(i)));
}
NBTTagList list2 = (NBTTagList) tag.getTag("generators");
for(int i = 0; i < list2.tagCount(); ++i) {
addGenerator(new VNGenerator(list2.getCompoundTagAt(i)));
}
}
NBTTagCompound toNBT() {
World world = getWorld();
NBTTagCompound ret = new NBTTagCompound();
NBTTagList list;
list = new NBTTagList();
for(VNReceiver r : receivers) {
if(!r.isLoaded(world) || r.get(world) != null) {
list.appendTag(r.toNBT());
}
}
ret.setTag("receivers", list);
list = new NBTTagList();
for(VNGenerator g : generators) {
if(!g.isLoaded(world) || g.get(world) != null) {
list.appendTag(g.toNBT());
}
}
ret.setTag("generators", list);
ret.setTag("node", node.toNBT());
return ret;
}
public void dispose() {
disposed = true;
}
public boolean isDisposed() {
return disposed;
}
boolean addReceiver(VNReceiver receiver) {
if(getLoad() >= getCapacity() || !checkRange(receiver))
return false;
World world = getWorld();
if(world != null) {
NodeConn old = data.getNodeConnection(receiver.get(world));
if(old != null) {
old.removeReceiver(receiver);
}
}
receivers.add(receiver);
data.nodeLookup.put(receiver, this);
return true;
}
void removeReceiver(VNReceiver receiver) {
toRemoveReceivers.add(receiver);
}
boolean addGenerator(VNGenerator gen) {
if(getLoad() >= getCapacity() || !checkRange(gen))
return false;
World world = getWorld();
NodeConn old = data.getNodeConnection(gen.get(world));
if(old != null) {
old.removeGenerator(gen);
}
generators.add(gen);
data.nodeLookup.put(gen, this);
return true;
}
void removeGenerator(VNGenerator gen) {
toRemoveGenerators.add(gen);
}
void onAdded(WiWorldData data) {
data.nodeLookup.put(node, this);
}
void onCleanup(WiWorldData data) {
data.nodeLookup.remove(node);
for(VNGenerator gen : generators)
data.nodeLookup.remove(gen);
for(VNReceiver rec : receivers)
data.nodeLookup.remove(rec);
}
boolean validate() {
World world = getWorld();
if (!disposed && node.isLoaded(world)) {
if (node.get(world) == null || (generators.size() == 0 && receivers.size() == 0)) {
disposed = true;
}
}
return !disposed;
}
private boolean checkRange(VBlock<?> block) {
IWirelessNode inode = node.get(getWorld());
double range = inode == null ? 1000 : inode.getRange();
return block.distSq(node) <= range * range;
}
public void tick() {
validate();
World world = getWorld();
if (node.isLoaded(world)) {
IWirelessNode iNode = node.get(world);
if(iNode == null) {
return;
}
double transferLeft = iNode.getBandwidth();
{
Collections.shuffle(generators);
Iterator<VNGenerator> iter = generators.iterator();
while(transferLeft != 0 && iter.hasNext()) {
VNGenerator gen = iter.next();
if(gen.isLoaded(world)) {
IWirelessGenerator igen = gen.get(world);
if(igen == null) {
removeGenerator(gen);
} else {
double cur = iNode.getEnergy();
double required = Math.min(transferLeft,
Math.min(igen.getBandwidth(), iNode.getMaxEnergy() - cur));
double amt = igen.getProvidedEnergy(required);
if(amt > required) {
AcademyCraft.log.warn("Energy input overflow for generator " + igen);
amt = required;
}
cur += amt;
iNode.setEnergy(cur);
transferLeft -= amt;
}
}
}
}
transferLeft = iNode.getBandwidth();
{
Collections.shuffle(receivers);
Iterator<VNReceiver> iter = receivers.iterator();
while(transferLeft != 0 && iter.hasNext()) {
VNReceiver rec = iter.next();
if(rec.isLoaded(world)) {
IWirelessReceiver irec = rec.get(world);
if(irec == null) {
removeReceiver(rec);
} else {
double cur = iNode.getEnergy();
double give = Math.min(cur, Math.min(transferLeft, irec.getBandwidth()));
give = Math.min(irec.getRequiredEnergy(), give);
give = give - irec.injectEnergy(give);
cur -= give;
transferLeft -= give;
iNode.setEnergy(cur);
}
}
}
}
// Remove toRemove receivers/generators
data.nodeLookup.keySet().removeAll(toRemoveGenerators);
generators.removeAll(toRemoveGenerators);
data.nodeLookup.keySet().removeAll(toRemoveReceivers);
receivers.removeAll(toRemoveReceivers);
toRemoveGenerators.clear();
toRemoveReceivers.clear();
}
}
public IWirelessNode getNode() {
return node.get(getWorld());
}
private World getWorld() {
return data.world;
}
public int getLoad() {
return receivers.size() + generators.size();
}
public int getCapacity() {
World world = getWorld();
IWirelessNode inode = world == null ? null : node.get(getWorld());
return inode == null ? Integer.MAX_VALUE : inode.getCapacity();
}
private void log(String str) {
if(AcademyCraft.DEBUG_MODE)
AcademyCraft.log.info("[NodeConn] " + str);
}
}