private void UpdateSunObservationStatus() { // determine sun surface observation status for all suns in the system vesselsPerSun.Clear(); foreach (var entries in EquipmentStates.states) { foreach (var e in entries.Value) { if (e.id == Configuration.SunObservationEquipment && e.value == EquipmentState.nominal) { Vessel v = FlightGlobals.FindVessel(entries.Key); if (v != null) { var sun = Sim.GetParentStar(v.mainBody); if (!vesselsPerSun.ContainsKey(sun)) { vesselsPerSun[sun] = new List <Vessel>(); } vesselsPerSun[sun].Add(v); } } } } foreach (var e in vesselsPerSun) { var sun = e.Key; var vessels = e.Value; if (solarSurfaces == null) { solarSurfaces = BodySurfaceObservation.CreateVisibleSurfaces(); } var context = new EvaluationContext(GetUniverseEvaluator(), null, sun); context.SetTime(Planetarium.GetUniversalTime()); Vector3d sunPosition = context.BodyPosition(sun); var observedSurface = (float)BodySurfaceObservation.VisibleSurface(vessels, context, sunPosition, Configuration.MinSunObservationAngle, solarSurfaces); API.SetStormObservationQuality(sun, observedSurface); Utils.LogDebug($"Solar surface observation for {sun.displayName}: {(observedSurface * 100.0).ToString("F2")}%"); } }
protected override void OnUpdate() { base.OnUpdate(); if (ParameterCount == 0) { return; } if (state != ParameterState.Incomplete) { return; } if (!KerbalismContractsMain.KerbalismInitialized) { return; } if (lastUpdate == 0) { lastUpdate = Planetarium.GetUniversalTime(); return; } bool childParameterChanged = false; if (subRequirementParameters.Count == 0) { childParameterChanged = true; CreateSubParameters(); } var lastUpdateAge = Planetarium.GetUniversalTime() - lastUpdate; if (lastUpdateAge < 1.0) { return; } lastUpdate = Planetarium.GetUniversalTime(); vessels.Clear(); context = CreateContext(lastUpdateAge); foreach (var sp in subRequirementParameters) { sp.ResetContext(context); } foreach (Vessel vessel in FlightGlobals.Vessels) { if (!Utils.IsVessel(vessel)) { continue; } if (!CouldBeCandidate(vessel)) { continue; } vessels.Add(vessel); } if (!hideChildren) { foreach (var vsp in vesselStatusParameters) { vsp.obsolete = true; } } List <Vessel> vesselsMeetingCondition = new List <Vessel>(); int stepCount = context.steps.Count; for (int i = 0; i < stepCount; i++) { var now = context.steps[i]; context.SetTime(now); vesselsMeetingCondition.Clear(); bool doLabelUpdate = !hideChildren && i + 1 == stepCount; foreach (Vessel vessel in vessels) { // Note considering early termination for performance gains: // If we already know that we have enough vessels to satisfy // our requirement, and if we don't have to update labels, // then we don' tneed to test all vessels. However, this // doesn't work when we have complex requirements that need // to consider multiple vessels at once (like body surface // observation percentage). We could change the implementation // to continuously integrate one vessel at a time into the // multi-vessel test and abort as soon as that one is satisfied, // but if that also calculates a number visible to the user // (like percentage of surface observed), that number would // be wrong. So we need to test all vessels, all the time. // if (!doLabelUpdate && vesselsMeetingCondition.Count >= minVessels) // break; string statusLabel; bool conditionMet = VesselMeetsCondition(vessel, doLabelUpdate, out statusLabel); if (conditionMet) { vesselsMeetingCondition.Add(vessel); } if (doLabelUpdate) { childParameterChanged |= UpdateVesselStatus(vessel, statusLabel, conditionMet); } } bool allConditionsMet = vesselsMeetingCondition.Count >= minVessels; allConditionsMet &= VesselsMeetCondition(vesselsMeetingCondition); if (durationParameter == null) { SetState(allConditionsMet ? ParameterState.Complete : ParameterState.Incomplete); } else { durationParameter.Update(allConditionsMet, now); SetState(durationParameter.State); } if (state == ParameterState.Complete) { break; } } childParameterChanged |= RemoveObsoleteVesselStatusParameters(); if (childParameterChanged) { ContractConfigurator.ContractConfigurator.OnParameterChange.Fire(this.Root, this); } }