void FixedUpdate() { // remove control locks in any case Misc.ClearLocks(); // do nothing if paused if (Lib.IsPaused()) { return; } // maintain elapsed_s, converting to double only once // and detect warp blending double fixedDeltaTime = TimeWarp.fixedDeltaTime; if (Math.Abs(fixedDeltaTime - elapsed_s) > double.Epsilon) { warp_blending = 0; } else { ++warp_blending; } elapsed_s = fixedDeltaTime; // evict oldest entry from vessel cache Cache.Update(); // store info for oldest unloaded vessel double last_time = 0.0; Vessel last_v = null; Vessel_info last_vi = null; VesselData last_vd = null; Vessel_resources last_resources = null; // for each vessel foreach (Vessel v in FlightGlobals.Vessels) { // get vessel info from the cache Vessel_info vi = Cache.VesselInfo(v); // set locks for active vessel if (v.isActiveVessel) { Misc.SetLocks(v, vi); } // maintain eva dead animation and helmet state if (v.loaded && v.isEVA) { EVA.Update(v); } // keep track of rescue mission kerbals, and gift resources to their vessels on discovery if (v.loaded && vi.is_vessel) { // manage rescue mission mechanics Misc.ManageRescueMission(v); } // do nothing else for invalid vessels if (!vi.is_valid) { continue; } // get vessel data from db VesselData vd = DB.Vessel(v); // get resource cache Vessel_resources resources = ResourceCache.Get(v); // if loaded if (v.loaded) { // get most used resource Resource_info ec = resources.Info(v, "ElectricCharge"); // show belt warnings Radiation.BeltWarnings(v, vi, vd); // update storm data Storm.Update(v, vi, vd, elapsed_s); Communications.Update(v, vi, vd, ec, elapsed_s); // Habitat equalization ResourceBalance.Equalizer(v); // transmit science data Science.Update(v, vi, vd, resources, elapsed_s); // apply rules Profile.Execute(v, vi, vd, resources, elapsed_s); // apply deferred requests resources.Sync(v, elapsed_s); // call automation scripts vd.computer.Automate(v, vi, resources); // remove from unloaded data container unloaded.Remove(vi.id); } // if unloaded else { // get unloaded data, or create an empty one Unloaded_data ud; if (!unloaded.TryGetValue(vi.id, out ud)) { ud = new Unloaded_data(); unloaded.Add(vi.id, ud); } // accumulate time ud.time += elapsed_s; // maintain oldest entry if (ud.time > last_time) { last_time = ud.time; last_v = v; last_vi = vi; last_vd = vd; last_resources = resources; } } } // at most one vessel gets background processing per physics tick // if there is a vessel that is not the currently loaded vessel, then // we will update the vessel whose most recent background update is the oldest if (last_v != null) { // get most used resource Resource_info last_ec = last_resources.Info(last_v, "ElectricCharge"); // show belt warnings Radiation.BeltWarnings(last_v, last_vi, last_vd); // update storm data Storm.Update(last_v, last_vi, last_vd, last_time); Communications.Update(last_v, last_vi, last_vd, last_ec, last_time); // transmit science data Science.Update(last_v, last_vi, last_vd, last_resources, last_time); // apply rules Profile.Execute(last_v, last_vi, last_vd, last_resources, last_time); // simulate modules in background Background.Update(last_v, last_vi, last_vd, last_resources, last_time); // apply deferred requests last_resources.Sync(last_v, last_time); // call automation scripts last_vd.computer.Automate(last_v, last_vi, last_resources); // remove from unloaded data container unloaded.Remove(last_vi.id); } // update storm data for one body per-step if (storm_bodies.Count > 0) { storm_bodies.ForEach(k => k.time += elapsed_s); Storm_data sd = storm_bodies[storm_index]; Storm.Update(sd.body, sd.time); sd.time = 0.0; storm_index = (storm_index + 1) % storm_bodies.Count; } }
void FixedUpdate() { // remove control locks in any case Misc.ClearLocks(); // do nothing if paused if (Lib.IsPaused()) { return; } // maintain elapsed_s, converting to double only once // and detect warp blending double fixedDeltaTime = TimeWarp.fixedDeltaTime; if (Math.Abs(fixedDeltaTime - elapsed_s) > double.Epsilon) { warp_blending = 0; } else { ++warp_blending; } elapsed_s = fixedDeltaTime; // evict oldest entry from vessel cache Cache.Update(); // vvvv------- This code tests for a theroy that could cause #313 // If KSP itself has the same vessel more than once in the // FlightGlobals.Vessels list, it would cause processes to run too many times. // The other possible cause was a Vessel ID collision in Lib.VesselID(), which // only used 4 bytes of a 16 byte GUID to create an ID from. // // If the BUG TRIGGERED message is never observed in the wild, // it is safe to remove this chunk of code. Dictionary <UInt64, Vessel> vessels = new Dictionary <UInt64, Vessel>(); foreach (Vessel v in FlightGlobals.Vessels) { if (vessels.ContainsKey(Lib.VesselID(v))) { Lib.Log("THIS SHOULD NOT BE HAPPENING: Vessel " + v.name + " already seen in FlightGlobals.Vessels"); Message.Post(Lib.BuildString(Lib.Color("red", "BUG TRIGGERED", true), "\n", v.name + " duplicated in FlightGlobals.Vessels. Please report this on GitHub.")); } else { vessels.Add(Lib.VesselID(v), v); } } // ^^^^-------- end theory test code // store info for oldest unloaded vessel double last_time = 0.0; Vessel last_v = null; Vessel_info last_vi = null; VesselData last_vd = null; Vessel_resources last_resources = null; // for each vessel //foreach (Vessel v in FlightGlobals.Vessels) foreach (Vessel v in vessels.Values) { // get vessel info from the cache Vessel_info vi = Cache.VesselInfo(v); // set locks for active vessel if (v.isActiveVessel) { Misc.SetLocks(v, vi); } // maintain eva dead animation and helmet state if (v.loaded && v.isEVA) { EVA.Update(v); } // keep track of rescue mission kerbals, and gift resources to their vessels on discovery if (v.loaded && vi.is_vessel) { // manage rescue mission mechanics Misc.ManageRescueMission(v); } // do nothing else for invalid vessels if (!vi.is_valid) { continue; } // get vessel data from db VesselData vd = DB.Vessel(v); // get resource cache Vessel_resources resources = ResourceCache.Get(v); // if loaded if (v.loaded) { // get most used resource Resource_info ec = resources.Info(v, "ElectricCharge"); // show belt warnings Radiation.BeltWarnings(v, vi, vd); // update storm data Storm.Update(v, vi, vd, elapsed_s); Communications.Update(v, vi, vd, ec, elapsed_s); // Habitat equalization ResourceBalance.Equalizer(v); // transmit science data Science.Update(v, vi, vd, resources, elapsed_s); // apply rules Profile.Execute(v, vi, vd, resources, elapsed_s); // apply deferred requests resources.Sync(v, elapsed_s); // call automation scripts vd.computer.Automate(v, vi, resources); // remove from unloaded data container unloaded.Remove(vi.id); } // if unloaded else { // get unloaded data, or create an empty one Unloaded_data ud; if (!unloaded.TryGetValue(vi.id, out ud)) { ud = new Unloaded_data(); unloaded.Add(vi.id, ud); } // accumulate time ud.time += elapsed_s; // maintain oldest entry if (ud.time > last_time) { last_time = ud.time; last_v = v; last_vi = vi; last_vd = vd; last_resources = resources; } } } // at most one vessel gets background processing per physics tick // if there is a vessel that is not the currently loaded vessel, then // we will update the vessel whose most recent background update is the oldest if (last_v != null) { // get most used resource Resource_info last_ec = last_resources.Info(last_v, "ElectricCharge"); // show belt warnings Radiation.BeltWarnings(last_v, last_vi, last_vd); // update storm data Storm.Update(last_v, last_vi, last_vd, last_time); Communications.Update(last_v, last_vi, last_vd, last_ec, last_time); // transmit science data Science.Update(last_v, last_vi, last_vd, last_resources, last_time); // apply rules Profile.Execute(last_v, last_vi, last_vd, last_resources, last_time); // simulate modules in background Background.Update(last_v, last_vi, last_vd, last_resources, last_time); // apply deferred requests last_resources.Sync(last_v, last_time); // call automation scripts last_vd.computer.Automate(last_v, last_vi, last_resources); // remove from unloaded data container unloaded.Remove(last_vi.id); } // update storm data for one body per-step if (storm_bodies.Count > 0) { storm_bodies.ForEach(k => k.time += elapsed_s); Storm_data sd = storm_bodies[storm_index]; Storm.Update(sd.body, sd.time); sd.time = 0.0; storm_index = (storm_index + 1) % storm_bodies.Count; } }
void FixedUpdate() { // remove control locks in any case Misc.ClearLocks(); // do nothing if paused if (Lib.IsPaused()) { return; } // convert elapsed time to double only once double fixedDeltaTime = TimeWarp.fixedDeltaTime; // and detect warp blending if (Math.Abs(fixedDeltaTime - elapsed_s) < 0.001) { warp_blending = 0; } else { ++warp_blending; } // update elapsed time elapsed_s = fixedDeltaTime; // store info for oldest unloaded vessel double last_time = 0.0; Guid last_id = Guid.Empty; Vessel last_v = null; VesselData last_vd = null; VesselResources last_resources = null; foreach (VesselData vd in DB.VesselDatas) { vd.EarlyUpdate(); } // for each vessel foreach (Vessel v in FlightGlobals.Vessels) { // get vessel data VesselData vd = v.KerbalismData(); // update the vessel data validity vd.Update(v); // set locks for active vessel if (v.isActiveVessel) { Misc.SetLocks(v); } // maintain eva dead animation and helmet state if (v.loaded && v.isEVA) { EVA.Update(v); } // keep track of rescue mission kerbals, and gift resources to their vessels on discovery if (v.loaded && vd.is_vessel) { // manage rescue mission mechanics Misc.ManageRescueMission(v); } // do nothing else for invalid vessels if (!vd.IsSimulated) { continue; } // get resource cache VesselResources resources = ResourceCache.Get(v); // if loaded if (v.loaded) { //UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.VesselDataEval"); // update the vessel info vd.Evaluate(false, elapsed_s); //UnityEngine.Profiling.Profiler.EndSample(); // get most used resource ResourceInfo ec = resources.GetResource(v, "ElectricCharge"); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Radiation"); // show belt warnings Radiation.BeltWarnings(v, vd); // update storm data Storm.Update(v, vd, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Comms"); Communications.Update(v, vd, ec, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); // Habitat equalization ResourceBalance.Equalizer(v); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Science"); // transmit science data Science.Update(v, vd, ec, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Profile"); // apply rules Profile.Execute(v, vd, resources, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Profile"); // part module resource updates vd.ResourceUpdate(resources, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Loaded.Resource"); // apply deferred requests resources.Sync(v, vd, elapsed_s); UnityEngine.Profiling.Profiler.EndSample(); // call automation scripts vd.computer.Automate(v, vd, resources); // remove from unloaded data container unloaded.Remove(vd.VesselId); } // if unloaded else { // get unloaded data, or create an empty one Unloaded_data ud; if (!unloaded.TryGetValue(vd.VesselId, out ud)) { ud = new Unloaded_data(); unloaded.Add(vd.VesselId, ud); } // accumulate time ud.time += elapsed_s; // maintain oldest entry if (ud.time > last_time) { last_time = ud.time; last_v = v; last_vd = vd; last_resources = resources; } } } // at most one vessel gets background processing per physics tick : // if there is a vessel that is not the currently loaded vessel, then // we will update the vessel whose most recent background update is the oldest if (last_v != null) { //UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.VesselDataEval"); // update the vessel info (high timewarp speeds reevaluation) last_vd.Evaluate(false, last_time); //UnityEngine.Profiling.Profiler.EndSample(); // get most used resource ResourceInfo last_ec = last_resources.GetResource(last_v, "ElectricCharge"); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Radiation"); // show belt warnings Radiation.BeltWarnings(last_v, last_vd); // update storm data Storm.Update(last_v, last_vd, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Comms"); Communications.Update(last_v, last_vd, last_ec, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Profile"); // apply rules Profile.Execute(last_v, last_vd, last_resources, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Background"); // simulate modules in background Background.Update(last_v, last_vd, last_resources, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Science"); // transmit science data Science.Update(last_v, last_vd, last_ec, last_time); UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.FixedUpdate.Unloaded.Resource"); // apply deferred requests last_resources.Sync(last_v, last_vd, last_time); UnityEngine.Profiling.Profiler.EndSample(); // call automation scripts last_vd.computer.Automate(last_v, last_vd, last_resources); // remove from unloaded data container unloaded.Remove(last_vd.VesselId); } // update storm data for one body per-step if (storm_bodies.Count > 0) { storm_bodies.ForEach(k => k.time += elapsed_s); Storm_data sd = storm_bodies[storm_index]; Storm.Update(sd.body, sd.time); sd.time = 0.0; storm_index = (storm_index + 1) % storm_bodies.Count; } }
public vessel_info(Vessel v, uint vessel_id, UInt64 inc) { // NOTE: anything used here can't in turn use cache, unless you know what you are doing // NOTE: you can't cache vessel position // at any point in time all vessel/body positions are relative to a different frame of reference // so comparing the current position of a vessel, with the cached one of another make no sense // associate with an unique incremental id this.inc = inc; // determine if this is a valid vessel is_vessel = Lib.IsVessel(v); if (!is_vessel) return; // determine if this is a rescue mission vessel is_rescue = Misc.IsRescueMission(v); if (is_rescue) return; // dead EVA are not valid vessels if (EVA.IsDead(v)) return; // shortcut for common tests is_valid = true; // generate id once id = vessel_id; // calculate crew info for the vessel crew_count = Lib.CrewCount(v); crew_capacity = Lib.CrewCapacity(v); // get vessel position Vector3d position = Lib.VesselPosition(v); // this should never happen again if (Vector3d.Distance(position, v.mainBody.position) < 1.0) { throw new Exception("Shit hit the fan for vessel " + v.vesselName); } // determine if in sunlight, calculate sun direction and distance sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0; // at the two highest timewarp speed, the number of sun visibility samples drop to the point that // the quantization error first became noticeable, and then exceed 100% // to solve this, we switch to an analytical estimation of the portion of orbit that was in sunlight // - we check against timewarp rate, instead of index, to avoid issues during timewarp blending if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f) { sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v); } // environment stuff atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir); gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude); underwater = Sim.Underwater(v); breathable = Sim.Breathable(v, underwater); landed = Lib.Landed(v); // temperature at vessel position temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux); temp_diff = Sim.TempDiff(temperature, v.mainBody, landed); // radiation radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar); // extended atmosphere thermosphere = Sim.InsideThermosphere(v); exosphere = Sim.InsideExosphere(v); // malfunction stuff malfunction = Reliability.HasMalfunction(v); critical = Reliability.HasCriticalFailure(v); // signal info avoid_inf_recursion.Add(v.id); connection = Communications.connection(v); transmitting = Science.transmitting(v, connection.linked); relaying = ""; avoid_inf_recursion.Remove(v.id); // habitat data volume = Habitat.tot_volume(v); surface = Habitat.tot_surface(v); pressure = Habitat.pressure(v); poisoning = Habitat.poisoning(v); shielding = Habitat.shielding(v); living_space = Habitat.living_space(v); comforts = new Comforts(v, landed, crew_count > 1, connection.linked); // data about greenhouses greenhouses = Greenhouse.Greenhouses(v); // other stuff gravioli = Sim.Graviolis(v); }