public GetSourceSet ( int type, bool includeSurfaceMountedParts, List |
||
type | int | |
includeSurfaceMountedParts | bool | |
allParts | List |
|
visited | HashSet |
|
allSources | HashSet |
|
log | LogMsg | |
indent | String | |
Résultat | void |
public bool SetResourceDrains(List <PartSim> allParts, List <PartSim> allFuelLines, HashSet <PartSim> drainingParts) { LogMsg log = null; foreach (HashSet <PartSim> sourcePartSet in sourcePartSets.Values) { sourcePartSet.Clear(); } for (int index = 0; index < this.resourceConsumptions.Types.Count; index++) { int type = this.resourceConsumptions.Types[index]; HashSet <PartSim> sourcePartSet; if (!sourcePartSets.TryGetValue(type, out sourcePartSet)) { sourcePartSet = new HashSet <PartSim>(); sourcePartSets.Add(type, sourcePartSet); } switch ((ResourceFlowMode)this.resourceFlowModes[type]) { case ResourceFlowMode.NO_FLOW: if (partSim.resources[type] > SimManager.RESOURCE_MIN && partSim.resourceFlowStates[type] != 0) { //sourcePartSet = new HashSet<PartSim>(); //MonoBehaviour.print("SetResourceDrains(" + name + ":" + partId + ") setting sources to just this"); sourcePartSet.Add(partSim); } break; case ResourceFlowMode.ALL_VESSEL: for (int i = 0; i < allParts.Count; i++) { PartSim aPartSim = allParts[i]; if (aPartSim.resources[type] > SimManager.RESOURCE_MIN && aPartSim.resourceFlowStates[type] != 0) { sourcePartSet.Add(aPartSim); } } break; case ResourceFlowMode.STAGE_PRIORITY_FLOW: foreach (HashSet <PartSim> stagePartSet in stagePartSets.Values) { stagePartSet.Clear(); } var maxStage = -1; //Logger.Log(type); for (int i = 0; i < allParts.Count; i++) { var aPartSim = allParts[i]; if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0) { continue; } int stage = aPartSim.DecouplerCount(); if (stage > maxStage) { maxStage = stage; } if (!stagePartSets.TryGetValue(stage, out sourcePartSet)) { sourcePartSet = new HashSet <PartSim>(); stagePartSets.Add(stage, sourcePartSet); } sourcePartSet.Add(aPartSim); } for (int j = 0; j <= maxStage; j++) { HashSet <PartSim> stagePartSet; if (stagePartSets.TryGetValue(j, out stagePartSet) && stagePartSet.Count > 0) { sourcePartSet = stagePartSet; } } break; case ResourceFlowMode.STACK_PRIORITY_SEARCH: visited.Clear(); if (SimManager.logOutput) { log = new LogMsg(); log.buf.AppendLine("Find " + ResourceContainer.GetResourceName(type) + " sources for " + partSim.name + ":" + partSim.partId); } partSim.GetSourceSet(type, allParts, visited, sourcePartSet, 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.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 for (int i = 0; i < this.resourceConsumptions.Types.Count; i++) { int type = this.resourceConsumptions.Types[i]; HashSet <PartSim> sourcePartSet; if (!sourcePartSets.TryGetValue(type, out sourcePartSet) || sourcePartSet.Count == 0) { 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 for (int i = 0; i < this.resourceConsumptions.Types.Count; i++) { int type = this.resourceConsumptions.Types[i]; 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); }
public bool SetResourceDrains(LogMsg log, List <PartSim> allParts, List <PartSim> allFuelLines, HashSet <PartSim> drainingParts) { //DumpSourcePartSets(log, "before clear"); foreach (HashSet <PartSim> sourcePartSet in sourcePartSets.Values) { sourcePartSet.Clear(); } //DumpSourcePartSets(log, "after clear"); for (int index = 0; index < this.resourceConsumptionsForMass.Types.Count; index++) { int type = this.resourceConsumptionsForMass.Types[index]; HashSet <PartSim> sourcePartSet; if (!sourcePartSets.TryGetValue(type, out sourcePartSet)) { sourcePartSet = new HashSet <PartSim>(); sourcePartSets.Add(type, sourcePartSet); } switch ((ResourceFlowMode)this.resourceFlowModes[type]) { case ResourceFlowMode.NO_FLOW: if (partSim.resources[type] > SimManager.RESOURCE_MIN && partSim.resourceFlowStates[type] != 0) { sourcePartSet.Add(partSim); } break; case ResourceFlowMode.ALL_VESSEL: case ResourceFlowMode.ALL_VESSEL_BALANCE: for (int i = 0; i < allParts.Count; i++) { PartSim aPartSim = allParts[i]; if (aPartSim.resources[type] > SimManager.RESOURCE_MIN && aPartSim.resourceFlowStates[type] != 0) { sourcePartSet.Add(aPartSim); } } break; case ResourceFlowMode.STAGE_PRIORITY_FLOW: case ResourceFlowMode.STAGE_PRIORITY_FLOW_BALANCE: if (log != null) { log.Append("Find ", ResourceContainer.GetResourceName(type), " sources for ", partSim.name) .AppendLine(":", partSim.partId); } foreach (HashSet <PartSim> stagePartSet in stagePartSets.Values) { stagePartSet.Clear(); } var maxStage = -1; for (int i = 0; i < allParts.Count; i++) { var aPartSim = allParts[i]; //if (log != null) log.Append(aPartSim.name, ":" + aPartSim.partId, " contains ", aPartSim.resources[type]) // .AppendLine((aPartSim.resourceFlowStates[type] == 0) ? " (disabled)" : ""); if (aPartSim.resources[type] <= SimManager.RESOURCE_MIN || aPartSim.resourceFlowStates[type] == 0) { continue; } int stage = aPartSim.inverseStage; if (stage > maxStage) { maxStage = stage; } HashSet <PartSim> tempPartSet; if (!stagePartSets.TryGetValue(stage, out tempPartSet)) { tempPartSet = new HashSet <PartSim>(); stagePartSets.Add(stage, tempPartSet); } tempPartSet.Add(aPartSim); } for (int j = maxStage; j >= -1; j--) { //if (log != null) log.AppendLine("Testing stage ", j); HashSet <PartSim> stagePartSet; if (stagePartSets.TryGetValue(j, out stagePartSet) && stagePartSet.Count > 0) { //if (log != null) log.AppendLine("Not empty"); // We have to copy the contents of the set here rather than copying the set reference or // bad things (tm) happen foreach (PartSim aPartSim in stagePartSet) { sourcePartSet.Add(aPartSim); } break; } } break; case ResourceFlowMode.STACK_PRIORITY_SEARCH: case ResourceFlowMode.STAGE_STACK_FLOW: case ResourceFlowMode.STAGE_STACK_FLOW_BALANCE: visited.Clear(); if (log != null) { log.Append("Find ", ResourceContainer.GetResourceName(type), " sources for ", partSim.name) .AppendLine(":", partSim.partId); } partSim.GetSourceSet(type, allParts, visited, sourcePartSet, log, ""); break; default: if (log != null) { log.Append("SetResourceDrains(", partSim.name, ":", partSim.partId) .AppendLine(") Unexpected flow type for ", ResourceContainer.GetResourceName(type), ")"); } break; } if (log != null && sourcePartSet.Count > 0) { log.AppendLine("Source parts for ", ResourceContainer.GetResourceName(type), ":"); foreach (PartSim partSim in sourcePartSet) { log.AppendLine(partSim.name, ":", partSim.partId); } } //DumpSourcePartSets(log, "after " + ResourceContainer.GetResourceName(type)); } // If we don't have sources for all the needed resources then return false without setting up any drains for (int i = 0; i < this.resourceConsumptionsForMass.Types.Count; i++) { int type = this.resourceConsumptionsForMass.Types[i]; HashSet <PartSim> sourcePartSet; if (!sourcePartSets.TryGetValue(type, out sourcePartSet) || sourcePartSet.Count == 0) { if (log != null) { log.AppendLine("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 for (int i = 0; i < this.resourceConsumptionsForMass.Types.Count; i++) { int type = this.resourceConsumptionsForMass.Types[i]; HashSet <PartSim> sourcePartSet = sourcePartSets[type]; ResourceFlowMode mode = (ResourceFlowMode)resourceFlowModes[type]; double consumption = resourceConsumptionsForMass[type]; double amount = 0d; double total = 0d; if (mode == ResourceFlowMode.ALL_VESSEL_BALANCE || mode == ResourceFlowMode.STAGE_PRIORITY_FLOW_BALANCE || mode == ResourceFlowMode.STAGE_STACK_FLOW_BALANCE || mode == ResourceFlowMode.STACK_PRIORITY_SEARCH) { foreach (PartSim partSim in sourcePartSet) { total += partSim.resources[type]; } } else { amount = consumption / sourcePartSet.Count; } // Loop through the members of the set foreach (PartSim partSim in sourcePartSet) { if (total != 0d) { amount = consumption * partSim.resources[type] / total; } if (log != null) { log.Append("Adding drain of ", amount, " ", ResourceContainer.GetResourceName(type)) .AppendLine(" to ", partSim.name, ":", partSim.partId); } partSim.resourceDrains.Add(type, amount); drainingParts.Add(partSim); } } return(true); }
// All functions below this point must not rely on the part member (it may be null) // public void GetSourceSet(int type, bool includeSurfaceMountedParts, List <PartSim> allParts, HashSet <PartSim> visited, HashSet <PartSim> allSources, LogMsg log, String indent) { if (log != null) { log.buf.AppendLine(indent + "GetSourceSet(" + ResourceContainer.GetResourceName(type) + ") for " + name + ":" + partId); indent += " "; } // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns as is. if (visited.Contains(this)) { if (log != null) { log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")"); } return; } 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("for each fuel line"); int lastCount = allSources.Count; for (int i = 0; i < this.fuelTargets.Count; i++) { PartSim partSim = this.fuelTargets[i]; if (partSim != null) { 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 + ")"); } partSim.GetSourceSet(type, includeSurfaceMountedParts, allParts, visited, allSources, log, indent); } } } // check surface mounted fuel targets if (includeSurfaceMountedParts) { for (int i = 0; i < surfaceMountFuelTargets.Count; i++) { PartSim partSim = this.surfaceMountFuelTargets[i]; if (partSim != null) { 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 + ")"); } partSim.GetSourceSet(type, true, allParts, visited, allSources, log, indent); } } } } if (allSources.Count > lastCount) { if (log != null) { log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " fuel target sources (" + this.name + ":" + this.partId + ")"); } return; } // 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) { lastCount = allSources.Count; //MonoBehaviour.print("for each attach node"); for (int i = 0; i < this.attachNodes.Count; i++) { AttachNodeSim attachSim = this.attachNodes[i]; if (attachSim.attachedPartSim != null) { if (attachSim.nodeType == AttachNode.NodeType.Stack) { if ((string.IsNullOrEmpty(noCrossFeedNodeKey) == false && attachSim.id.Contains(noCrossFeedNodeKey)) == false) { 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 + ")"); } attachSim.attachedPartSim.GetSourceSet(type, includeSurfaceMountedParts, allParts, visited, allSources, log, indent); } } } } } if (allSources.Count > lastCount) { if (log != null) { log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")"); } return; } } // 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.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 + ")"); } } return; } else { if (log != null) { log.buf.AppendLine(indent + "Not fuel tank or disabled. HasType = " + resources.HasType(type) + " FlowState = " + resourceFlowStates[type]); } } // 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 { lastCount = allSources.Count; this.parent.GetSourceSet(type, includeSurfaceMountedParts, allParts, visited, allSources, log, indent); if (allSources.Count > lastCount) { if (log != null) { log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")"); } return; } } } } // 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; }