public void DumpSourcePartSets(LogMsg log, String msg) { if (log == null) { return; } log.AppendLine("DumpSourcePartSets ", msg); foreach (int type in sourcePartSets.Keys) { log.AppendLine("SourcePartSet for ", ResourceContainer.GetResourceName(type)); HashSet <PartSim> sourcePartSet = sourcePartSets[type]; if (sourcePartSet.Count > 0) { foreach (PartSim partSim in sourcePartSet) { log.AppendLine("Part ", partSim.name, ":", partSim.partId); } } else { log.AppendLine("No parts"); } } }
public static EngineSim New(PartSim theEngine, ModuleEngines engineMod, double atmosphere, float machNumber, bool vectoredThrust, bool fullThrust, LogMsg log) { float maxFuelFlow = engineMod.maxFuelFlow; float minFuelFlow = engineMod.minFuelFlow; float thrustPercentage = engineMod.thrustPercentage; List <Transform> thrustTransforms = engineMod.thrustTransforms; List <float> thrustTransformMultipliers = engineMod.thrustTransformMultipliers; Vector3 vecThrust = CalculateThrustVector(vectoredThrust ? thrustTransforms : null, vectoredThrust ? thrustTransformMultipliers : null, log); FloatCurve atmosphereCurve = engineMod.atmosphereCurve; bool atmChangeFlow = engineMod.atmChangeFlow; FloatCurve atmCurve = engineMod.useAtmCurve ? engineMod.atmCurve : null; FloatCurve velCurve = engineMod.useVelCurve ? engineMod.velCurve : null; float currentThrottle = engineMod.currentThrottle; float IspG = engineMod.g; bool throttleLocked = engineMod.throttleLocked || fullThrust; List <Propellant> propellants = engineMod.propellants; bool active = engineMod.isOperational; float resultingThrust = engineMod.resultingThrust; bool isFlamedOut = engineMod.flameout; EngineSim engineSim = pool.Borrow(); engineSim.isp = 0.0; engineSim.maxMach = 0.0f; engineSim.actualThrust = 0.0; engineSim.partSim = theEngine; engineSim.isActive = active; engineSim.thrustVec = vecThrust; engineSim.isFlamedOut = isFlamedOut; engineSim.resourceConsumptions.Reset(); engineSim.maxResourceConsumptions.Reset(); engineSim.resourceFlowModes.Reset(); engineSim.appliedForces.Clear(); double flowRate = 0.0; double maxFlowRate = 0.0; if (engineSim.partSim.hasVessel) { if (log != null) { log.AppendLine("hasVessel is true"); } float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, engineSim.partSim.part.atmDensity, velCurve, machNumber, ref engineSim.maxMach); engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere); engineSim.fullThrust = GetThrust(maxFuelFlow * flowModifier, engineSim.isp); engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp); engineSim.actualThrust = engineSim.isActive ? resultingThrust : 0.0; if (log != null) { log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier); log.buf.AppendFormat("isp = {0:g6}\n", engineSim.isp); log.buf.AppendFormat("thrust = {0:g6}\n", engineSim.thrust); log.buf.AppendFormat("actual = {0:g6}\n", engineSim.actualThrust); } if (throttleLocked) { if (log != null) { log.AppendLine("throttleLocked is true, using thrust for flowRate"); } flowRate = GetFlowRate(engineSim.thrust, engineSim.isp); } else { if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false) { // TODO: This bit doesn't work for RF engines if (log != null) { log.AppendLine("throttled up and not landed, using actualThrust for flowRate"); } flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp); } else { if (log != null) { log.AppendLine("throttled down or landed, using thrust for flowRate"); } flowRate = GetFlowRate(engineSim.thrust, engineSim.isp); } } maxFlowRate = GetFlowRate(engineSim.fullThrust, engineSim.isp); } else { if (log != null) { log.buf.AppendLine("hasVessel is false"); } float altitude = BasicDeltaV.Instance.AtmosphereDepth; float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, BasicDeltaV.Instance.CurrentCelestialBody.GetDensity(BasicDeltaV.Instance.CurrentCelestialBody.GetPressure(altitude), BasicDeltaV.Instance.CurrentCelestialBody.GetTemperature(altitude)), velCurve, machNumber, ref engineSim.maxMach); engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere); engineSim.fullThrust = GetThrust(maxFuelFlow * flowModifier, engineSim.isp); engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp); engineSim.actualThrust = 0d; if (log != null) { log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier); log.buf.AppendFormat("isp = {0:g6}\n", engineSim.isp); log.buf.AppendFormat("thrust = {0:g6}\n", engineSim.thrust); log.buf.AppendFormat("actual = {0:g6}\n", engineSim.actualThrust); log.AppendLine("no vessel, using thrust for flowRate"); } flowRate = GetFlowRate(engineSim.thrust, engineSim.isp); maxFlowRate = GetFlowRate(engineSim.fullThrust, engineSim.isp); } if (log != null) { log.buf.AppendFormat("flowRate = {0:g6}\n", flowRate); } float flowMass = 0f; for (int i = 0; i < propellants.Count; ++i) { Propellant propellant = propellants[i]; if (!propellant.ignoreForIsp) { flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id); } } if (log != null) { log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass); } for (int i = 0; i < propellants.Count; ++i) { Propellant propellant = propellants[i]; if (propellant.name == "ElectricCharge" || propellant.name == "IntakeAir") { continue; } double consumptionRate = propellant.ratio * flowRate / flowMass; if (log != null) { log.buf.AppendFormat( "Add consumption({0}, {1}:{2:d}) = {3:g6}\n", ResourceContainer.GetResourceName(propellant.id), theEngine.name, theEngine.partId, consumptionRate); } engineSim.resourceConsumptions.Add(propellant.id, consumptionRate); engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode()); double maxConsumptionRate = propellant.ratio * maxFlowRate / flowMass; engineSim.maxResourceConsumptions.Add(propellant.id, maxConsumptionRate); } for (int i = 0; i < thrustTransforms.Count; i++) { Transform thrustTransform = thrustTransforms[i]; Vector3d direction = thrustTransform.forward.normalized; Vector3d position = thrustTransform.position; AppliedForce appliedForce = AppliedForce.New(direction * engineSim.thrust * thrustTransformMultipliers[i], position); engineSim.appliedForces.Add(appliedForce); } return(engineSim); }
public bool SetPossibleResourceDrains(LogMsg log, List <PartSim> allParts, HashSet <PartSim> drainingParts) { //DumpSourcePartSets(log, "before clear"); foreach (HashSet <PartSim> sourcePartSet in fullSourcePartSets.Values) { sourcePartSet.Clear(); } //DumpSourcePartSets(log, "after clear"); for (int index = 0; index < this.resourceConsumptions.Types.Count; index++) { int type = this.resourceConsumptions.Types[index]; if (!fullSourcePartSets.TryGetValue(type, out HashSet <PartSim> sourcePartSet)) { sourcePartSet = new HashSet <PartSim>(); fullSourcePartSets.Add(type, sourcePartSet); } switch ((ResourceFlowMode)this.resourceFlowModes[type]) { case ResourceFlowMode.NO_FLOW: if (partSim.maxResources[type] > SimManager.RESOURCE_MIN) { 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.maxResources[type] > SimManager.RESOURCE_MIN) { sourcePartSet.Add(aPartSim); } } break; case ResourceFlowMode.STAGE_PRIORITY_FLOW: case ResourceFlowMode.STAGE_PRIORITY_FLOW_BALANCE: //All vessel ordered by stage 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.maxResources[type] > SimManager.RESOURCE_MIN) { int stage = aPartSim.inverseStage; if (stage > maxStage) { maxStage = stage; } if (!stagePartSets.TryGetValue(stage, out HashSet <PartSim> tempPartSet)) { tempPartSet = new HashSet <PartSim>(); stagePartSets.Add(stage, tempPartSet); } tempPartSet.Add(aPartSim); } } //Add resource containers in order by stage for (int j = maxStage; j >= -1; j--) { //if (log != null) log.AppendLine("Testing stage ", j); if (stagePartSets.TryGetValue(j, out HashSet <PartSim> 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(); //Resource containers limited to current stage if (log != null) { log.Append("Find ", ResourceContainer.GetResourceName(type), " sources for ", partSim.name) .AppendLine(":", partSim.partId); } partSim.GetSourceSet(type, true, allParts, visited, sourcePartSet, true, log, ""); break; default: if (log != null) { log.Append("SetResourceDrains(", partSim.name, ":", partSim.partId) .AppendLine(") Unexpected flow type for ", ResourceContainer.GetResourceName(type), ")"); } break; } } // 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]; if (!fullSourcePartSets.TryGetValue(type, out HashSet <PartSim> sourcePartSet) || sourcePartSet.Count == 0) { if (log != null) { log.AppendLine("No source of ", ResourceContainer.GetResourceName(type)); } 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++) { HashSet <PartSim> sourcePartSet = fullSourcePartSets[resourceConsumptions.Types[i]]; // Loop through the members of the set foreach (PartSim partSim in sourcePartSet) { drainingParts.Add(partSim); } } return(true); }
public void GetSourceSet_Internal(int type, bool includeSurfaceMountedParts, List <PartSim> allParts, HashSet <PartSim> visited, HashSet <PartSim> allSources, bool checkMax, ref int priMax, LogMsg log, String indent) { if (log != null) { log.Append(indent, "GetSourceSet_Internal(", ResourceContainer.GetResourceName(type), ") for ") .AppendLine(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.Append(indent, "Nothing added, already visited (", name, ":") .AppendLine(partId + ")"); } return; } if (log != null) { log.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.Append(indent, "Fuel target already visited, skipping (", partSim.name, ":") .AppendLine(partSim.partId, ")"); } } else { if (log != null) { log.Append(indent, "Adding fuel target as source (", partSim.name, ":") .AppendLine(partSim.partId, ")"); } partSim.GetSourceSet_Internal(type, includeSurfaceMountedParts, allParts, visited, allSources, checkMax, ref priMax, log, indent); } } } if (fuelCrossFeed) { if (includeSurfaceMountedParts) { // check surface mounted fuel targets for (int i = 0; i < surfaceMountFuelTargets.Count; i++) { PartSim partSim = this.surfaceMountFuelTargets[i]; if (partSim != null) { if (visited.Contains(partSim)) { if (log != null) { log.Append(indent, "Surface part already visited, skipping (", partSim.name, ":") .AppendLine(partSim.partId, ")"); } } else { if (log != null) { log.Append(indent, "Adding surface part as source (", partSim.name, ":") .AppendLine(partSim.partId, ")"); } partSim.GetSourceSet_Internal(type, includeSurfaceMountedParts, allParts, visited, allSources, checkMax, ref priMax, log, indent); } } } } 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.Append(indent, "Attached part already visited, skipping (", attachSim.attachedPartSim.name, ":") .AppendLine(attachSim.attachedPartSim.partId, ")"); } } else { bool flg = true; if (attachSim.attachedPartSim.isEnginePlate) //y u make me do dis. { foreach (AttachNodeSim att in attachSim.attachedPartSim.attachNodes) { if (att.attachedPartSim == this && att.id == "bottom") { flg = false; } } } if (flg) { if (log != null) { log.Append(indent, "Adding attached part as source (", attachSim.attachedPartSim.name, ":") .AppendLine(attachSim.attachedPartSim.partId, ")"); } attachSim.attachedPartSim.GetSourceSet_Internal(type, includeSurfaceMountedParts, allParts, visited, allSources, checkMax, ref priMax, log, indent); } } } } } } } // 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) and it contains fuel, it adds itself. if (checkMax ? (maxResources.HasType(type)) : (resources.HasType(type) && resourceFlowStates[type] > 0.0)) { if (checkMax ? (maxResources[type] > SimManager.RESOURCE_MIN) : (resources[type] > resRequestRemainingThreshold)) { // Get the priority of this tank int pri = GetResourcePriority(); if (pri > priMax) { // This tank is higher priority than the previously added ones so we clear the sources // and set the priMax to this priority allSources.Clear(); priMax = pri; } // If this is the correct priority then add this to the sources if (pri == priMax) { if (log != null) { log.Append(indent, "Adding enabled tank as source (", name, ":") .AppendLine(partId, ")"); } allSources.Add(this); } } } else { if (log != null) { log.Append(indent, "Not fuel tank or disabled. HasType = ", resources.HasType(type)) .AppendLine(" FlowState = " + resourceFlowStates[type]); } } }
public void DumpPartToLog(LogMsg log, String prefix, List <PartSim> allParts = null) { if (log == null) { return; } log.Append(prefix); log.Append(name); log.Append(":[id = ", partId, ", decouple = ", decoupledInStage); log.Append(", invstage = ", inverseStage); //log.Append(", vesselName = '", vesselName, "'"); //log.Append(", vesselType = ", SimManager.GetVesselTypeString(vesselType)); //log.Append(", initialVesselName = '", initialVesselName, "'"); log.Append(", isNoPhys = ", isNoPhysics); log.buf.AppendFormat(", baseMass = {0}", baseMass); log.buf.AppendFormat(", baseMassForCoM = {0}", baseMassForCoM); log.Append(", fuelCF = {0}", fuelCrossFeed); log.Append(", noCFNKey = '{0}'", noCrossFeedNodeKey); log.Append(", isSep = {0}", isSepratron); try { for (int i = 0; i < resources.Types.Count; i++) { int type = resources.Types[i]; log.buf.AppendFormat(", {0} = {1:g6}", ResourceContainer.GetResourceName(type), resources[type]); } } catch (Exception e) { log.Append("error dumping part resources " + e.ToString()); } try { if (attachNodes.Count > 0) { log.Append(", attached = <"); attachNodes[0].DumpToLog(log); for (int i = 1; i < attachNodes.Count; i++) { log.Append(", "); if (attachNodes[i] != null) { attachNodes[i].DumpToLog(log); //its u, isn't it? } } log.Append(">"); } } catch (Exception e) { log.Append("error dumping part nodes" + e.ToString()); } try { if (surfaceMountFuelTargets.Count > 0) { log.Append(", surface = <"); if (surfaceMountFuelTargets[0] != null) { log.Append(surfaceMountFuelTargets[0].name, ":", surfaceMountFuelTargets[0].partId); } for (int i = 1; i < surfaceMountFuelTargets.Count; i++) { if (surfaceMountFuelTargets[i] != null) { log.Append(", ", surfaceMountFuelTargets[i].name, ":", surfaceMountFuelTargets[i].partId); //no it was u. } } log.Append(">"); } } catch (Exception e) { log.Append("error dumping part surface fuels " + e.ToString()); } // Add more info here log.AppendLine("]"); if (allParts != null) { String newPrefix = prefix + " "; for (int i = 0; i < allParts.Count; i++) { PartSim partSim = allParts[i]; if (partSim.parent == this) { partSim.DumpPartToLog(log, newPrefix, allParts); } } } }