GetSourceSet() public method

public GetSourceSet ( int type, List allParts, HashSet visited, LogMsg log, String indent ) : HashSet
type int
allParts List
visited HashSet
log LogMsg
indent String
return HashSet
Example #1
0
        // All functions below this point must not rely on the part member (it may be null)
        //

        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.Surface &&*/
                            !(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 + ")");
                        }
                    }
                }

                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)
            {
                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);
        }
Example #2
0
        public bool SetResourceDrains(List <PartSim> allParts, List <PartSim> allFuelLines, HashSet <PartSim> drainingParts)
        {
            LogMsg log = null;

            // A dictionary to hold a set of parts for each resource
            Dictionary <int, HashSet <PartSim> > sourcePartSets = new Dictionary <int, HashSet <PartSim> >();

            foreach (int type in resourceConsumptions.Types)
            {
                HashSet <PartSim> sourcePartSet = null;
                switch (ResourceContainer.GetResourceFlowMode(type))
                {
                case ResourceFlowMode.NO_FLOW:
                    if (partSim.resources[type] > SimManager.RESOURCE_MIN)
                    {
                        sourcePartSet = new HashSet <PartSim>();
                        //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this");
                        sourcePartSet.Add(partSim);
                    }
                    break;

                case ResourceFlowMode.ALL_VESSEL:
                    foreach (PartSim aPartSim in allParts)
                    {
                        if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
                        {
                            if (sourcePartSet == null)
                            {
                                sourcePartSet = new HashSet <PartSim>();
                            }

                            sourcePartSet.Add(aPartSim);
                        }
                    }
                    break;

                case ResourceFlowMode.STAGE_PRIORITY_FLOW:
                {
                    Dictionary <int, HashSet <PartSim> > stagePartSets = new Dictionary <int, HashSet <PartSim> >();
                    int maxStage = -1;
                    foreach (PartSim aPartSim in allParts)
                    {
                        if (aPartSim.resources[type] > SimManager.RESOURCE_MIN)
                        {
                            //int stage = aPartSim.decoupledInStage;            // Use the number of the stage the tank is decoupled in
                            int stage = aPartSim.DecouplerCount();                      // Use the count of decouplers between tank and root
                            if (stage > maxStage)
                            {
                                maxStage = stage;
                            }
                            if (stagePartSets.ContainsKey(stage))
                            {
                                sourcePartSet = stagePartSets[stage];
                            }
                            else
                            {
                                sourcePartSet = new HashSet <PartSim>();
                                stagePartSets.Add(stage, sourcePartSet);
                            }

                            sourcePartSet.Add(aPartSim);
                        }
                    }

                    while (maxStage >= 0)
                    {
                        if (stagePartSets.ContainsKey(maxStage))
                        {
                            if (stagePartSets[maxStage].Count() > 0)
                            {
                                sourcePartSet = stagePartSets[maxStage];
                                break;
                            }
                        }
                        maxStage--;
                    }
                }
                break;

                case ResourceFlowMode.STACK_PRIORITY_SEARCH:
                    HashSet <PartSim> visited = new HashSet <PartSim>();

                    if (SimManager.logOutput)
                    {
                        log = new LogMsg();
                        log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + partSim.name + ":" + partSim.partId);
                    }
                    sourcePartSet = partSim.GetSourceSet(type, allParts, visited, log, "");
                    if (SimManager.logOutput)
                    {
                        MonoBehaviour.print(log.buf);
                    }
                    break;

                default:
                    MonoBehaviour.print("SetResourceDrains(" + partSim.name + ":" + partSim.partId + ") Unexpected flow type for " + ResourceContainer.GetResourceName(type) + ")");
                    break;
                }

                if (sourcePartSet != null && sourcePartSet.Count > 0)
                {
                    sourcePartSets[type] = sourcePartSet;
                    if (SimManager.logOutput)
                    {
                        log = new LogMsg();
                        log.buf.AppendLine("Source parts for " + ResourceContainer.GetResourceName(type) + ":");
                        foreach (PartSim partSim in sourcePartSet)
                        {
                            log.buf.AppendLine(partSim.name + ":" + partSim.partId);
                        }
                        MonoBehaviour.print(log.buf);
                    }
                }
            }

            // If we don't have sources for all the needed resources then return false without setting up any drains
            foreach (int type in resourceConsumptions.Types)
            {
                if (!sourcePartSets.ContainsKey(type))
                {
                    if (SimManager.logOutput)
                    {
                        MonoBehaviour.print("No source of " + ResourceContainer.GetResourceName(type));
                    }

                    isActive = false;
                    return(false);
                }
            }

            // Now we set the drains on the members of the sets and update the draining parts set
            foreach (int type in resourceConsumptions.Types)
            {
                HashSet <PartSim> sourcePartSet = sourcePartSets[type];
                // Loop through the members of the set
                double amount = resourceConsumptions[type] / sourcePartSet.Count;
                foreach (PartSim partSim in sourcePartSet)
                {
                    if (SimManager.logOutput)
                    {
                        MonoBehaviour.print("Adding drain of " + amount + " " + ResourceContainer.GetResourceName(type) + " to " + partSim.name + ":" + partSim.partId);
                    }

                    partSim.resourceDrains.Add(type, amount);
                    drainingParts.Add(partSim);
                }
            }

            return(true);
        }