From 18519b5fa67c1c6aa76afde47c1723684a88c53c Mon Sep 17 00:00:00 2001 From: Ben Spiers Date: Sun, 28 Jul 2013 03:32:41 +0100 Subject: [PATCH] Fix the EnergyNetwork memory leak. --- common/mekanism/common/EnergyNetwork.java | 112 ++++++++++++++---- .../common/EnergyNetworkRegistry.java | 21 +++- common/mekanism/common/IUniversalCable.java | 22 ++++ .../common/TileEntityUniversalCable.java | 56 ++++++++- 4 files changed, 185 insertions(+), 26 deletions(-) diff --git a/common/mekanism/common/EnergyNetwork.java b/common/mekanism/common/EnergyNetwork.java index 1b8d0081c..0a77c4e91 100644 --- a/common/mekanism/common/EnergyNetwork.java +++ b/common/mekanism/common/EnergyNetwork.java @@ -23,13 +23,15 @@ import buildcraft.api.power.IPowerReceptor; public class EnergyNetwork { - public Set cables = new HashSet(); + public HashSet cables = new HashSet(); public Set possibleAcceptors = new HashSet(); public Map acceptorDirections = new HashMap(); private double joulesTransmitted = 0; private double joulesLastTick = 0; + private int ticksSinceCreate = 0; + private boolean fixed = false; public EnergyNetwork(IUniversalCable... varCables) { @@ -37,6 +39,20 @@ public class EnergyNetwork EnergyNetworkRegistry.getInstance().registerNetwork(this); } + public EnergyNetwork(Set networks) + { + for (EnergyNetwork net : networks) + { + if(net != null) + { + addAllCables(net.cables); + net.deregister(); + } + } + refresh(); + EnergyNetworkRegistry.getInstance().registerNetwork(this); + } + public double getEnergyNeeded(ArrayList ignored) { double totalNeeded = 0; @@ -155,7 +171,8 @@ public class EnergyNetwork public void refresh() { - Iterator it = cables.iterator(); + Set iterCables = (Set) cables.clone(); + Iterator it = iterCables.iterator(); possibleAcceptors.clear(); acceptorDirections.clear(); @@ -164,20 +181,17 @@ public class EnergyNetwork { IUniversalCable conductor = (IUniversalCable)it.next(); - if(conductor == null) - { - it.remove(); - } - else if(((TileEntity)conductor).isInvalid()) + if(conductor == null || ((TileEntity)conductor).isInvalid()) { it.remove(); + cables.remove(conductor); } else { conductor.setNetwork(this); } } - for(IUniversalCable cable : cables) + for(IUniversalCable cable : iterCables) { TileEntity[] acceptors = CableUtils.getConnectedEnergyAcceptors((TileEntity)cable); @@ -194,24 +208,26 @@ public class EnergyNetwork public void merge(EnergyNetwork network) { - EnergyNetworkRegistry registry = EnergyNetworkRegistry.getInstance(); - if(network != null && network != this) { - EnergyNetwork newNetwork = new EnergyNetwork(); - newNetwork.cables.addAll(cables); - registry.removeNetwork(this); - newNetwork.cables.addAll(network.cables); - registry.removeNetwork(network); + Set networks = new HashSet(); + networks.add(this); + networks.add(network); + EnergyNetwork newNetwork = new EnergyNetwork(networks); newNetwork.refresh(); } } + + public void addAllCables(Set newCables) + { + cables.addAll(newCables); + } public void split(IUniversalCable splitPoint) { if(splitPoint instanceof TileEntity) { - cables.remove(splitPoint); + removeCable(splitPoint); TileEntity[] connectedBlocks = new TileEntity[6]; boolean[] dealtWith = {false, false, false, false, false, false}; @@ -233,7 +249,7 @@ public class EnergyNetwork if(connectedBlockA instanceof IUniversalCable && !dealtWith[countOne]) { NetworkFinder finder = new NetworkFinder(((TileEntity)splitPoint).worldObj, Object3D.get(connectedBlockA), Object3D.get((TileEntity)splitPoint)); - List partNetwork = finder.findNetwork(); + List partNetwork = finder.exploreNetwork(); for(int countTwo = countOne + 1; countTwo < connectedBlocks.length; countTwo++) { @@ -267,10 +283,50 @@ public class EnergyNetwork } } - EnergyNetworkRegistry.getInstance().removeNetwork(this); + deregister(); } } + public void fixMessedUpNetwork(IUniversalCable cable) + { + System.out.println("Fixing Network"); + if(cable instanceof TileEntity) + { + NetworkFinder finder = new NetworkFinder(((TileEntity) cable).getWorldObj(), Object3D.get((TileEntity)cable), null); + List partNetwork = finder.exploreNetwork(); + Set newCables = new HashSet(); + for(Object3D node : partNetwork) + { + TileEntity nodeTile = node.getTileEntity(((TileEntity)cable).worldObj); + + if(nodeTile instanceof IUniversalCable) + { + ((IUniversalCable) nodeTile).removeFromNetwork(); + newCables.add((IUniversalCable)nodeTile); + } + } + EnergyNetwork newNetwork = new EnergyNetwork(newCables.toArray(new IUniversalCable[0])); + newNetwork.refresh(); + newNetwork.fixed = true; + deregister(); + } + } + + public void removeCable(IUniversalCable cable) + { + cables.remove(cable); + if(cables.size() == 0) + { + deregister(); + } + } + + public void deregister() + { + cables.clear(); + EnergyNetworkRegistry.getInstance().removeNetwork(this); + } + public static class NetworkFinder { public World worldObj; @@ -313,7 +369,7 @@ public class EnergyNetwork } } - public List findNetwork() + public List exploreNetwork() { loopAll(start); @@ -350,6 +406,22 @@ public class EnergyNetwork return "[EnergyNetwork] " + cables.size() + " cables, " + possibleAcceptors.size() + " acceptors."; } + + public void tick() + { + clearJoulesTransmitted(); + //Fix weird behaviour periodically. + if(!fixed) + { + ++ticksSinceCreate; + if(ticksSinceCreate > 1200) + { + ticksSinceCreate = 0; + fixMessedUpNetwork(cables.toArray(new IUniversalCable[0])[0]); + } + } + } + public void clearJoulesTransmitted() { joulesLastTick = joulesTransmitted; @@ -360,4 +432,4 @@ public class EnergyNetwork { return joulesLastTick * 20; } -} \ No newline at end of file +} diff --git a/common/mekanism/common/EnergyNetworkRegistry.java b/common/mekanism/common/EnergyNetworkRegistry.java index d6fcac04c..de562173c 100644 --- a/common/mekanism/common/EnergyNetworkRegistry.java +++ b/common/mekanism/common/EnergyNetworkRegistry.java @@ -13,7 +13,7 @@ public class EnergyNetworkRegistry implements ITickHandler { private static EnergyNetworkRegistry INSTANCE = new EnergyNetworkRegistry(); - private Set networks = new HashSet(); + private HashSet networks = new HashSet(); public EnergyNetworkRegistry() { @@ -38,6 +38,17 @@ public class EnergyNetworkRegistry implements ITickHandler } } + public void pruneEmptyNetworks() { + for(EnergyNetwork e : networks) + { + if(e.cables.size() == 0) + { + removeNetwork(e); + } + } + + } + @Override public void tickStart(EnumSet type, Object... tickData) { @@ -47,9 +58,13 @@ public class EnergyNetworkRegistry implements ITickHandler @Override public void tickEnd(EnumSet type, Object... tickData) { - for(EnergyNetwork net : networks) + Set iterNetworks = (Set) networks.clone(); + for(EnergyNetwork net : iterNetworks) { - net.clearJoulesTransmitted(); + if(networks.contains(net)) + { + net.tick(); + } } } diff --git a/common/mekanism/common/IUniversalCable.java b/common/mekanism/common/IUniversalCable.java index 42e1f7985..9315abcea 100644 --- a/common/mekanism/common/IUniversalCable.java +++ b/common/mekanism/common/IUniversalCable.java @@ -9,10 +9,20 @@ public interface IUniversalCable { /** * Gets the EnergyNetwork currently in use by this cable segment. + * Will try to connect to adjacent networks or create a new one * @return EnergyNetwork this cable is using */ public EnergyNetwork getNetwork(); + /** + * Gets the EnergyNetwork currently in use by this cable segment. + * @param createIfNull - If true, the cable will try and connect to an + * adjacent network, merging several if necessary, or creating a new one + * if none is available + * @return EnergyNetwork this cable is using + */ + public EnergyNetwork getNetwork(boolean createIfNull); + /** * Sets this cable segment's EnergyNetwork to a new value. * @param network - EnergyNetwork to set to @@ -23,4 +33,16 @@ public interface IUniversalCable * Refreshes the cable's EnergyNetwork. */ public void refreshNetwork(); + + /** + * Remove a cable from its network. + */ + public void removeFromNetwork(); + + /** + * Call this if you're worried a cable's network is messed up and you want + * it to try and fix itself. + */ + public void fixNetwork(); + } diff --git a/common/mekanism/common/TileEntityUniversalCable.java b/common/mekanism/common/TileEntityUniversalCable.java index 70c03cbe0..9acff79c8 100644 --- a/common/mekanism/common/TileEntityUniversalCable.java +++ b/common/mekanism/common/TileEntityUniversalCable.java @@ -1,6 +1,7 @@ package mekanism.common; import java.util.ArrayList; +import java.util.HashSet; import mekanism.api.Object3D; import net.minecraft.tileentity.TileEntity; @@ -35,14 +36,47 @@ public class TileEntityUniversalCable extends TileEntity implements IUniversalCa @Override public EnergyNetwork getNetwork() { - if(energyNetwork == null) + return getNetwork(true); + } + + @Override + public EnergyNetwork getNetwork(boolean createIfNull) + { + if(energyNetwork == null && createIfNull) { - energyNetwork = new EnergyNetwork(this); + TileEntity[] adjacentCables = CableUtils.getConnectedCables(this); + HashSet connectedNets = new HashSet(); + for(TileEntity cable : adjacentCables) + { + if(cable instanceof IUniversalCable && ((IUniversalCable)cable).getNetwork(false) != null) + { + connectedNets.add(((IUniversalCable)cable).getNetwork()); + } + } + if(connectedNets.size() == 0) + { + energyNetwork = new EnergyNetwork(this); + } + else if(connectedNets.size() == 1) + { + energyNetwork = (EnergyNetwork)connectedNets.toArray()[0]; + energyNetwork.cables.add(this); + } + else { + energyNetwork = new EnergyNetwork(connectedNets); + energyNetwork.cables.add(this); + } } return energyNetwork; } + @Override + public void fixNetwork() + { + getNetwork().fixMessedUpNetwork(this); + } + @Override public void invalidate() { @@ -57,7 +91,17 @@ public class TileEntityUniversalCable extends TileEntity implements IUniversalCa @Override public void setNetwork(EnergyNetwork network) { - energyNetwork = network; + if(network != energyNetwork) + { + removeFromNetwork(); + energyNetwork = network; + } + } + + @Override + public void removeFromNetwork() + { + energyNetwork.removeCable(this); } @Override @@ -105,6 +149,12 @@ public class TileEntityUniversalCable extends TileEntity implements IUniversalCa { return INFINITE_EXTENT_AABB; } + + @Override + public void onChunkUnload() { + invalidate(); + EnergyNetworkRegistry.getInstance().pruneEmptyNetworks(); + } } class CablePowerProvider extends PowerProvider