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; } if (arguments.requireElectricity && !API.IsPowered(vessel)) { if (!hideChildren) { childParameterChanged |= UpdateVesselStatus(vessel, Lib.Color("#KerCon_NoEC", Lib.Kolor.Red), false); // No EC } continue; } if (arguments.requireCommunication && !API.VesselConnectionLinked(vessel)) { if (!hideChildren) { childParameterChanged |= UpdateVesselStatus(vessel, Lib.Color("#KerCon_NoComms", Lib.Kolor.Red), false); // No Comms } 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't need 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 >= arguments.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); } }