public HashSet<PartSim> GetSourceSet(int type, List<PartSim> allParts, HashSet<PartSim> visited, LogMsg log, String indent)
{
if (log != null)
{
log.buf.AppendLine(indent + "GetSourceSet(" + ResourceContainer.GetResourceName(type) + ") for " + name + ":" + partId);
indent += " ";
}
HashSet<PartSim> allSources = new HashSet<PartSim>();
HashSet<PartSim> partSources = null;
// Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns empty list.
if (visited.Contains(this))
{
if (log != null)
log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")");
return allSources;
}
//if (log != null)
// log.buf.AppendLine(indent + "Adding this to visited");
visited.Add(this);
// Rule 2: Part performs scan on start of every fuel pipe ending in it. This scan is done in order in which pipes were installed.
// Then it makes an union of fuel tank sets each pipe scan returned. If the resulting list is not empty, it is returned as result.
//MonoBehaviour.print("foreach fuel line");
foreach (PartSim partSim in fuelTargets)
{
if (visited.Contains(partSim))
{
//if (log != null)
// log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
partSources = partSim.GetSourceSet(type, allParts, visited, log, indent);
if (partSources.Count > 0)
{
allSources.UnionWith(partSources);
partSources.Clear();
}
}
}
if (allSources.Count > 0)
{
if (log != null)
log.buf.AppendLine(indent + "Returning " + allSources.Count + " fuel target sources (" + name + ":" + partId + ")");
return allSources;
}
// Rule 3: This rule has been removed and merged with rules 4 and 7 to fix issue with fuel tanks with disabled crossfeed
// Rule 4: Part performs scan on each of its axially mounted neighbors.
// Couplers (bicoupler, tricoupler, ...) are an exception, they only scan one attach point on the single attachment side,
// skip the points on the side where multiple points are. [Experiment]
// Again, the part creates union of scan lists from each of its neighbor and if it is not empty, returns this list.
// The order in which mount points of a part are scanned appears to be fixed and defined by the part specification file. [Experiment]
if (fuelCrossFeed)
{
//MonoBehaviour.print("foreach attach node");
foreach (AttachNodeSim attachSim in attachNodes)
{
if (attachSim.attachedPartSim != null)
{
if (attachSim.nodeType == AttachNode.NodeType.Stack)
{
if (!(noCrossFeedNodeKey != null && noCrossFeedNodeKey.Length > 0 && attachSim.id.Contains(noCrossFeedNodeKey)))
{
if (visited.Contains(attachSim.attachedPartSim))
{
//if (log != null)
// log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
partSources = attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, log, indent);
if (partSources.Count > 0)
{
allSources.UnionWith(partSources);
partSources.Clear();
}
}
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "AttachNode is noCrossFeedKey, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
}
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "AttachNode is not NodeType.Stack, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
}
}
}
if (allSources.Count > 0)
{
if (log != null)
log.buf.AppendLine(indent + "Returning " + allSources.Count + " attached sources (" + name + ":" + partId + ")");
return allSources;
}
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "Crossfeed disabled, skipping axial connected parts (" + name + ":" + partId + ")");
}
// Rule 5: If the part is fuel container for searched type of fuel (i.e. it has capability to contain that type of fuel and the fuel
// type was not disabled [Experiment]) and it contains fuel, it returns itself.
// Rule 6: If the part is fuel container for searched type of fuel (i.e. it has capability to contain that type of fuel and the fuel
// type was not disabled) but it does not contain the requested fuel, it returns empty list. [Experiment]
if (resources.HasType(type) && resourceFlowStates[type] != 0)
{
if (resources[type] > SimManager.RESOURCE_MIN)
{
allSources.Add(this);
if (log != null)
log.buf.AppendLine(indent + "Returning enabled tank as only source (" + name + ":" + partId + ")");
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "Returning empty set, enabled tank is empty (" + name + ":" + partId + ")");
}
return allSources;
}
// Rule 7: If the part is radially attached to another part and it is child of that part in the ship's tree structure, it scans its
// parent and returns whatever the parent scan returned. [Experiment] [Experiment]
if (parent != null && parentAttach == AttachModes.SRF_ATTACH)
{
if (fuelCrossFeed)
{
if (visited.Contains(parent))
{
//if (log != null)
// log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")");
}
else
{
allSources = parent.GetSourceSet(type, allParts, visited, log, indent);
if (allSources.Count > 0)
{
if (log != null)
log.buf.AppendLine(indent + "Returning " + allSources.Count + " parent sources (" + name + ":" + partId + ")");
return allSources;
}
}
}
else
{
//if (log != null)
// log.buf.AppendLine(indent + "Crossfeed disabled, skipping radial parent (" + name + ":" + partId + ")");
}
}
// Rule 8: If all preceding rules failed, part returns empty list.
//if (log != null)
// log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
return allSources;
}