Repository: vegastrike/Vega-Strike-Engine-Source
Pull request #1090: Fix "Nav 8" issue (crashing into invisible planets) -- 0.10.x
Author: login: stephengtuggy
Labels: name: bug
Created: 2025-04-11T17:17:14Z | Merged: 2025-04-20T05:37:36Z

Code Changes:
- [X] (Largely) Have the PR Validation Tests been run? See https://github.com/vegastrike/Vega-Strike-Engine-Source/wiki/Pull-Request-Validation

Issues Fixed:
- Fixes #516 

Known Issues Remaining:
- Can still dock with Nav Points. Need to fix this in a follow-up PR.

Purpose:
- What is this pull request trying to do? Fix the Nav 8 case for the 0.10.x and following releases. Specifically, make it so that nav points cannot be collided with.
- What release is this for? 0.10.x
- Is there a project or milestone we should apply this to? 0.10.x


Linked issue #516: PWCU: Unexpectedly, Nav 8 in Troy is an object that can be collided with
Linked issue comments: user: login: ermo
created_at: 2021-08-16T19:40:24Z
body: To add to this, I had a Mission Computer "visit n nav points" patrol mission active and used auto-pilot to jump to each nav-point.

Upon reaching Nav 8 (and without manually changing course), I flew straight until I collided with Nav 8 which blew up my ship.

I expected to be able to just fly through Nav 8 like in OG Privateer.
author_association: CONTRIBUTOR
user: login: BenjamenMeyer
created_at: 2025-04-06T03:31:36Z
body: @stephengtuggy can we confirm this is fully closed in 0.9.x? I see it got marked as Done by a merge for 0.8.x; would be good if we could just close this out entirely.
author_association: MEMBER
user: login: stephengtuggy
created_at: 2025-04-07T19:08:50Z
body: @BenjamenMeyer It is not fixed in 0.9.x. As I recall, I did a quick patch job on 0.8.x, but you wanted to fix it a different way in 0.9.x. The latter was never completed.
author_association: CONTRIBUTOR
user: login: BenjamenMeyer
created_at: 2025-04-08T05:11:22Z
body: Okay found the discussion - https://github.com/vegastrike/Vega-Strike-Engine-Source/pull/540#issuecomment-915624381

I'm going to vote that we change that discussion into its own issue and then apply the 0.8.x changes to 0.9.x and 0.10.x so we can close this. Thoughts?
author_association: MEMBER
user: login: stephengtuggy
created_at: 2025-04-08T19:25:19Z
body: > Okay found the discussion - [#540 (comment)](https://github.com/vegastrike/Vega-Strike-Engine-Source/pull/540#issuecomment-915624381)
> 
> I'm going to vote that we change that discussion into its own issue and then apply the 0.8.x changes to 0.9.x and 0.10.x so we can close this. Thoughts?

Sure, sounds good.
author_association: CONTRIBUTOR
user: login: stephengtuggy
created_at: 2025-04-08T19:27:39Z
body: See https://github.com/orgs/vegastrike/discussions/1084
author_association: CONTRIBUTOR

Diff:
diff --git a/CMakePresets.json b/CMakePresets.json
index 36064e66fc..352a213cdb 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -23,7 +23,8 @@
       "displayName": "Debug",
       "inherits": "default",
       "cacheVariables": {
-        "CMAKE_BUILD_TYPE": "Debug"
+        "CMAKE_BUILD_TYPE": "Debug",
+        "LOG_TIME_TAKEN_DETAILS": true
       }
     },
     {
diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt
index 822dcf9334..111b1439b0 100644
--- a/engine/CMakeLists.txt
+++ b/engine/CMakeLists.txt
@@ -692,6 +692,11 @@ IF (NOT DISABLE_CLIENT)
         TARGET_COMPILE_DEFINITIONS(vegastrike-engine PUBLIC "$<$<CONFIG:Debug>:Py_DEBUG>")
     ENDIF()
 
+    OPTION (LOG_TIME_TAKEN_DETAILS "Whether to log timing details in the main loop" OFF)
+    IF (LOG_TIME_TAKEN_DETAILS)
+        TARGET_COMPILE_DEFINITIONS(vegastrike-engine PUBLIC LOG_TIME_TAKEN_DETAILS)
+    ENDIF ()
+
     TARGET_INCLUDE_DIRECTORIES(vegastrike-engine SYSTEM PRIVATE ${VSE_TST_INCLUDES})
     TARGET_INCLUDE_DIRECTORIES(vegastrike-engine PRIVATE
             # VS engine headers
@@ -1264,5 +1269,5 @@ IF (USE_GTEST)
     )
 
     INCLUDE(GoogleTest)
-    gtest_discover_tests(${TEST_NAME})
+    gtest_discover_tests(${TEST_NAME} PROPERTIES DISCOVERY_TIMEOUT 30)
 ENDIF (USE_GTEST)
diff --git a/engine/src/cmd/ai/fire.cpp b/engine/src/cmd/ai/fire.cpp
index 237c2601a5..71a7717355 100644
--- a/engine/src/cmd/ai/fire.cpp
+++ b/engine/src/cmd/ai/fire.cpp
@@ -809,28 +809,21 @@ void FireAt::Execute() {
     done = tmp;
     Unit *targ;
     if (parent->isUnit() == Vega_UnitType::unit) {
-        static float
-                cont_update_time = XMLSupport::parse_float(vs_config->getVariable("AI", "ContrabandUpdateTime", "1"));
+        const float cont_update_time = configuration()->ai.contraband_update_time;
         //Will rand() be in the expected range here? -- stephengtuggy 2020-07-25
         if (rand() < RAND_MAX * SIMULATION_ATOM / cont_update_time) {
             UpdateContrabandSearch();
         }
-        static float
-                cont_initiate_time = XMLSupport::parse_float(vs_config->getVariable("AI", "CommInitiateTime", "300"));
+        const float cont_initiate_time = configuration()->ai.comm_initiate_time;
         //Or here?
-        if ((float) rand() < ((float) RAND_MAX * (SIMULATION_ATOM / cont_initiate_time))) {
-            static float contraband_initiate_time =
-                    XMLSupport::parse_float(vs_config->getVariable("AI", "ContrabandInitiateTime", "3000"));
-            static float comm_to_player =
-                    XMLSupport::parse_float(vs_config->getVariable("AI", "CommToPlayerPercent", ".05"));
-            static float comm_to_target =
-                    XMLSupport::parse_float(vs_config->getVariable("AI", "CommToTargetPercent", ".25"));
-            static float contraband_to_player =
-                    XMLSupport::parse_float(vs_config->getVariable("AI", "ContrabandToPlayerPercent", ".98"));
-            static float contraband_to_target =
-                    XMLSupport::parse_float(vs_config->getVariable("AI", "ContrabandToTargetPercent", "0.001"));
-
-            unsigned int modulo = ((unsigned int) (contraband_initiate_time / cont_initiate_time));
+        if (static_cast<float>(rand()) < (static_cast<float>(RAND_MAX) * (SIMULATION_ATOM / cont_initiate_time))) {
+            const float contraband_initiate_time = configuration()->ai.contraband_initiate_time;
+            const float comm_to_player = configuration()->ai.comm_to_player_percent;
+            const float comm_to_target = configuration()->ai.comm_to_target_percent;
+            const float contraband_to_player = configuration()->ai.contraband_to_player_percent;
+            const float contraband_to_target = configuration()->ai.contraband_to_target_percent;
+
+            unsigned int modulo = static_cast<unsigned int>(contraband_initiate_time / cont_initiate_time);
             if (modulo < 1) {
                 modulo = 1;
             }
diff --git a/engine/src/cmd/planet.cpp b/engine/src/cmd/planet.cpp
index 3fbd650773..88a68f0624 100644
--- a/engine/src/cmd/planet.cpp
+++ b/engine/src/cmd/planet.cpp
@@ -2,9 +2,8 @@
  * planet.cpp
  *
  * Copyright (C) 2001-2019 Daniel Horn and other Vega Strike contributors
- * Copyright (C) 2020-2021 pyramid3d, Roy Falk, Stephen G. Tuggy,
+ * Copyright (C) 2020-2025 pyramid3d, Roy Falk, Stephen G. Tuggy,
  * and other Vega Strike contributors
- * Copyright (C) 2022 Stephen G. Tuggy
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
  *
@@ -44,6 +43,7 @@
 #include "gfx/planetary_transform.h"
 #endif
 
+#include "vega_cast_utils.h"
 #include "collide2/CSopcodecollider.h"
 #include "cmd/images.h"
 #include "gfx/halo.h"
@@ -221,7 +221,8 @@ Planet::Planet(QVector x,
         const std::vector<GFXLightLocal> &ligh,
         int faction,
         string fgid,
-        bool inside_out) :
+        bool inside_out,
+        float days) :
         Unit(0) {
     atmosphere = nullptr;
     atmospheric = false;
@@ -359,7 +360,8 @@ Planet::Planet(QVector x,
             orbitcent, parent,
             faction, fgid,
             inside_out,
-            nlights);
+            nlights,
+            days);
 }
 
 Planet::~Planet() {
@@ -387,22 +389,23 @@ Planet::~Planet() {
 }
 
 void Planet::InitPlanet(QVector x,
-        QVector y,
-        float vely,
-        const Vector &rotvel,
-        float pos,
-        float gravity,
-        float radius,
-        const string &filename,
-        const string &technique,
-        const string &unitname,
-        const vector<string> &dest,
-        const QVector &orbitcent,
-        Unit *parent,
-        int faction,
-        string fullname,
-        bool inside_out,
-        unsigned int lights_num) {
+                        QVector y,
+                        float vely,
+                        const Vector &rotvel,
+                        float pos,
+                        float gravity,
+                        float radius,
+                        const string &filename,
+                        const string &technique,
+                        const string &unitname,
+                        const vector<string> &dest,
+                        const QVector &orbitcent,
+                        Unit *parent,
+                        int faction,
+                        string fullname,
+                        bool inside_out,
+                        unsigned int lights_num,
+                        const float days) {
     const float bodyradius = configuration()->graphics.star_body_radius;
 
     if (lights_num) {
@@ -415,8 +418,8 @@ void Planet::InitPlanet(QVector x,
     //this->faction = neutralfaction;
     killed = false;
     bool notJumppoint = dest.empty();
-    for (unsigned int i = 0; i < dest.size(); ++i) {
-        AddDestination(dest[i]);
+    for (const auto & each_destination : dest) {
+        AddDestination(each_destination);
     }
     //name = "Planet - ";
     //name += textname;
@@ -424,6 +427,7 @@ void Planet::InitPlanet(QVector x,
     this->fullname = name;
     this->radius = radius;
     this->gravity = gravity;
+    this->days = days;
     const float densityOfRock = configuration()->physics.density_of_rock;
     const float densityOfJumpPoint = configuration()->physics.density_of_jump_point;
     //static  float massofplanet = XMLSupport::parse_float(vs_config->getVariable("physics","mass_of_planet","10000000"));
@@ -449,7 +453,7 @@ void Planet::InitPlanet(QVector x,
     setFullname(tempname);
 
     int tmpfac = faction;
-    if (UniverseUtil::LookupUnitStat(tempname, FactionUtil::GetFactionName(faction), "Cargo_Import").length() == 0) {
+    if (UniverseUtil::LookupUnitStat(tempname, FactionUtil::GetFactionName(faction), "Cargo_Import").empty()) {
         tmpfac = FactionUtil::GetPlanetFaction();
     }
     Unit *un = new Unit(tempname.c_str(), true, tmpfac);
@@ -765,41 +769,42 @@ void Planet::DrawTerrain() {
 ///////////////////////////////////////////////////////////////////////
 
 Unit *Planet::beginElement(QVector x,
-        QVector y,
-        float vely,
-        const Vector &rotvel,
-        float pos,
-        float gravity,
-        float radius,
-        const string &filename,
-        const string &technique,
-        const string &unitname,
-        BLENDFUNC blendSrc,
-        BLENDFUNC blendDst,
-        const vector<string> &dest,
-        int level,
-        const GFXMaterial &ourmat,
-        const vector<GFXLightLocal> &ligh,
-        bool isunit,
-        int faction,
-        string fullname,
-        bool inside_out) {
+                           QVector y,
+                           float vely,
+                           const Vector &rotvel,
+                           float pos,
+                           float gravity,
+                           float radius,
+                           const string &filename,
+                           const string &technique,
+                           const string &unitname,
+                           BLENDFUNC blendSrc,
+                           BLENDFUNC blendDst,
+                           const vector<string> &dest,
+                           int level,
+                           const GFXMaterial &ourmat,
+                           const vector<GFXLightLocal> &ligh,
+                           bool isunit,
+                           int faction,
+                           string fullname,
+                           bool inside_out,
+                           const float days) {
     //this function is OBSOLETE
     Unit *un = nullptr;
     if (level > 2) {
         un_iter satiterator = satellites.createIterator();
         assert(*satiterator);
         if ((*satiterator)->isUnit() == Vega_UnitType::planet) {
-            un = ((Planet *) (*satiterator))->beginElement(x, y, vely, rotvel, pos,
-                    gravity, radius,
-                    filename, technique, unitname,
-                    blendSrc, blendDst,
-                    dest,
-                    level - 1,
-                    ourmat, ligh,
-                    isunit,
-                    faction, fullname,
-                    inside_out);
+            un = vega_dynamic_cast_ptr<Planet>(*satiterator)->beginElement(x, y, vely, rotvel, pos,
+                                                                  gravity, radius,
+                                                                  filename, technique, unitname,
+                                                                  blendSrc, blendDst,
+                                                                  dest,
+                                                                  level - 1,
+                                                                  ourmat, ligh,
+                                                                  isunit,
+                                                                  faction, fullname,
+                                                                  inside_out, days);
         } else {
             VS_LOG(error, "Planets are unable to orbit around units");
         }
@@ -834,7 +839,7 @@ Unit *Planet::beginElement(QVector x,
             satellites.prepend(p = new Planet(x, y, vely, rotvel, pos, gravity, radius,
                     filename, technique, unitname,
                     blendSrc, blendDst, dest,
-                    QVector(0, 0, 0), this, ourmat, ligh, faction, fullname, inside_out));
+                    QVector(0, 0, 0), this, ourmat, ligh, faction, fullname, inside_out, days));
             un = p;
             p->SetOwner(this);
             VS_LOG(trace,
diff --git a/engine/src/cmd/planet.h b/engine/src/cmd/planet.h
index 73bf040aaa..dd539878f7 100644
--- a/engine/src/cmd/planet.h
+++ b/engine/src/cmd/planet.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2023 Daniel Horn, Roy Falk, pyramid3d,
+ * Copyright (C) 2001-2025 Daniel Horn, Roy Falk, pyramid3d,
  * Stephen G. Tuggy, Benjamen R. Meyer, and other Vega Strike contributors.
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -57,7 +57,8 @@ class Planet : public Unit {
     bool inside = false;
     bool atmospheric = false; //then users can go inside!
     float radius = 0.0f;
-    float gravity;
+    float gravity{};
+    float days{};
     UnitCollection insiders;
     std::vector<int> lights;
 public:
@@ -85,25 +86,27 @@ class Planet : public Unit {
             const std::vector<GFXLightLocal> &,
             int faction,
             string fullname,
-            bool inside_out = false);
+            bool inside_out = false,
+            float days = 0.0F);
 
     void InitPlanet(QVector x,
-            QVector y,
-            float vely,
-            const Vector &rotvel,
-            float pos,
-            float gravity,
-            float radius,
-            const string &filename,
-            const string &technique,
-            const string &unitname,
-            const vector<string> &dest,
-            const QVector &orbitcent,
-            Unit *parent,
-            int faction,
-            string fullname,
-            bool inside_out,
-            unsigned int lights_num);
+                    QVector y,
+                    float vely,
+                    const Vector &rotvel,
+                    float pos,
+                    float gravity,
+                    float radius,
+                    const string &filename,
+                    const string &technique,
+                    const string &unitname,
+                    const vector<string> &dest,
+                    const QVector &orbitcent,
+                    Unit *parent,
+                    int faction,
+                    string fullname,
+                    bool inside_out,
+                    unsigned int lights_num,
+                    float days = 0.0F);
 
     virtual ~Planet();
 
@@ -143,25 +146,25 @@ class Planet : public Unit {
     Vector AddSpaceElevator(const std::string &name, const std::string &faction, char direction);
 
     Unit *beginElement(QVector x,
-            QVector y,
-            float vely,
-            const Vector &rotvel,
-            float pos,
-            float gravity,
-            float radius,
-            const string &filename,
-            const string &technique,
-            const string &unitname,
-            BLENDFUNC blendsrc,
-            BLENDFUNC blenddst,
-            const vector<string> &dest,
-            int level,
-            const GFXMaterial &ourmat,
-            const std::vector<GFXLightLocal> &ligh,
-            bool isunit,
-            int faction,
-            string fullname,
-            bool inside_out);
+                       QVector y,
+                       float vely,
+                       const Vector &rotvel,
+                       float pos,
+                       float gravity,
+                       float radius,
+                       const string &filename,
+                       const string &technique,
+                       const string &unitname,
+                       BLENDFUNC blendsrc,
+                       BLENDFUNC blenddst,
+                       const vector<string> &dest,
+                       int level,
+                       const GFXMaterial &ourmat,
+                       const std::vector<GFXLightLocal> &ligh,
+                       bool isunit,
+                       int faction,
+                       string fullname,
+                       bool inside_out, float days);
 
     void DisableLights();
     virtual void Draw(const Transformation &quat = identity_transformation, const Matrix &m = identity_matrix);
@@ -197,6 +200,10 @@ class Planet : public Unit {
     void setAtmosphere(Atmosphere *);
     PlanetaryTransform *setTerrain(ContinuousTerrain *, float ratiox, int numwraps, float scaleatmos);
 
+    bool is_nav_point() const {
+        return gravity == 0.0F && days == 240.0F;
+    }
+
     class PlanetIterator {
     public:
         PlanetIterator(Planet *p) {
diff --git a/engine/src/cmd/script/script_call_unit_generic.cpp b/engine/src/cmd/script/script_call_unit_generic.cpp
index 587016ce84..6e748cfe73 100644
--- a/engine/src/cmd/script/script_call_unit_generic.cpp
+++ b/engine/src/cmd/script/script_call_unit_generic.cpp
@@ -1,7 +1,7 @@
 /*
  * script_call_unit_generic.cpp
  *
- * Copyright (C) 2001-2022 Daniel Horn, Alexander Rawass, pyramid3d,
+ * Copyright (C) 2001-2025 Daniel Horn, Alexander Rawass, pyramid3d,
  * Stephen G. Tuggy, and other Vega Strike contributors
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -990,7 +990,7 @@ Unit *Mission::call_unit_launch(CreateFlightgroup *fg, int type, const string &d
             my_unit = new Planet(QVector(0, 0, 0), QVector(0, 0, 0), 0, Vector(0, 0, 0),
                     0, 0, radius, tex, "", "", s,
                     d, ParseDestinations(destinations),
-                    QVector(0, 0, 0), NULL, mat,
+                    QVector(0, 0, 0), nullptr, mat,
                     vector<GFXLightLocal>(), faction_nr, nam);
             free(bsrc);
             free(bdst);
diff --git a/engine/src/gfx/vdu.cpp b/engine/src/gfx/vdu.cpp
index abe9abe3b6..6316404cce 100644
--- a/engine/src/gfx/vdu.cpp
+++ b/engine/src/gfx/vdu.cpp
@@ -1,7 +1,7 @@
 /*
  * vdu.cpp
  *
- * Copyright (C) 2001-2022 Daniel Horn, pyramid3d, Stephen G. Tuggy,
+ * Copyright (C) 2001-2025 Daniel Horn, pyramid3d, Stephen G. Tuggy,
  * and other Vega Strike contributors
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -28,6 +28,8 @@
 /// target info, and objectives
 
 #include "gfx/vdu.h"
+
+#include "vega_cast_utils.h"
 #include "cmd/unit_util.h"
 #include "gfx/hud.h"
 #include "root_generic/vs_globals.h"
@@ -606,32 +608,44 @@ void VDU::DrawTarget(GameCockpit *cp, Unit *parent, Unit *target) {
         armor_up = armor_down = armor_left = armor_right = target->hull.Percent();
     }
 
+    VSSprite* vs_sprite;
+    VSSprite* hud_image = target->getHudImage();
+    Vega_UnitType unit_type = target->isUnit();
+    if (hud_image) {
+        vs_sprite = hud_image;
+    } else if (!target->GetDestinations().empty()) {
+        vs_sprite = getJumpImage();
+    } else if (unit_type == Vega_UnitType::planet) {
+        const Planet * target_as_planet = vega_dynamic_const_cast_ptr<const Planet>(target);
+        if (target_as_planet->hasLights()) {
+            vs_sprite = getSunImage();
+        } else if (target_as_planet->is_nav_point()) {
+            vs_sprite = getNavImage();
+        } else {
+            vs_sprite = getPlanetImage();
+        }
+    } else {
+        vs_sprite = getPlanetImage();
+    }
     DrawHUDSprite(this,
-            ((target->isUnit() != Vega_UnitType::planet || target->getHudImage() != NULL) ? target->getHudImage()
-                    : (
-                            target->GetDestinations().size() != 0 ? getJumpImage()
-                                    : (((Planet *) target)->hasLights() ? getSunImage()
-                                    : (
-                                            target->getFullname().find(
-                                                    "invisible") != string::npos
-                                                    ? getNavImage() : getPlanetImage())))),
-            .6,
-            x,
-            y,
-            w,
-            h,
-            armor_up,
-            armor_right,
-            armor_left,
-            armor_down,
-            target->hull.Percent(),
-            true,
-            invert_target_sprite);
+                  vs_sprite,
+                  .6,
+                  x,
+                  y,
+                  w,
+                  h,
+                  armor_up,
+                  armor_right,
+                  armor_left,
+                  armor_down,
+                  target->hull.Percent(),
+                  true,
+                  invert_target_sprite);
 
     GFXDisable(TEXTURE0);
     //sprintf (t,"\n%4.1f %4.1f",target->FShieldData()*100,target->RShieldData()*100);
     double mm = 0;
-    string unitandfg = getUnitNameAndFgNoBase(target).c_str();
+    string unitandfg = getUnitNameAndFgNoBase(target);
     const bool out_of_cone_information = configuration()->graphics.hud.out_of_cone_distance;
     bool inrange = parent->InRange(target, mm, out_of_cone_information == false && !UnitUtil::isSignificant(
             target), false, false);
@@ -658,8 +672,7 @@ void VDU::DrawTarget(GameCockpit *cp, Unit *parent, Unit *target) {
             false,
             automatte);
     tp->bgcol = tpbg;
-    static float auto_message_lim =
-            XMLSupport::parse_float(vs_config->getVariable("graphics", "auto_message_time_lim", "5"));
+    const float auto_message_lim = configuration()->graphics.auto_message_time_lim;
     float delautotime = UniverseUtil::GetGameTime() - cp->autoMessageTime;
     bool draw_auto_message = (delautotime < auto_message_lim && cp->autoMessage.length() != 0);
     if (inrange) {
diff --git a/engine/src/star_system.cpp b/engine/src/star_system.cpp
index 6b8f363273..f8a999290c 100644
--- a/engine/src/star_system.cpp
+++ b/engine/src/star_system.cpp
@@ -336,8 +336,8 @@ void StarSystem::Draw(bool DrawCockpit) {
         //Array containing the two interesting units, so as not to have to copy-paste code
         Unit *camunits[2] = {saveparent, targ};
         float backup = simulation_atom_var;
-        //VS_LOG(trace, (boost::format("StarSystem::Draw(): simulation_atom_var as backed up  = %1%") % simulation_atom_var));
         unsigned int cur_sim_frame = _Universe->activeStarSystem()->getCurrentSimFrame();
+        //VS_LOG(trace, (boost::format("StarSystem::Draw(): simulation_atom_var as backed up  = %1%") % simulation_atom_var));
         for (int i = 0; i < 2; ++i) {
             Unit *unit = camunits[i];
             //Make sure unit is not null;
@@ -1108,7 +1108,9 @@ void StarSystem::Update(float priority, bool executeDirector) {
     ///just be sure to restore this at the end
     time += GetElapsedTime();
     _Universe->pushActiveStarSystem(this);
-//    double bolttime = 0;
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    double bolttime = 0.0;
+#endif
     if (time > simulation_atom_var) {
         if (time > simulation_atom_var * 2) {
             VS_LOG(trace,
@@ -1117,20 +1119,24 @@ void StarSystem::Update(float priority, bool executeDirector) {
                             % __FILE__ % __LINE__ % time % simulation_atom_var));
         }
 
-//        double missionSimulationTimeSubtotal = 0.0;
-//        double processUnitTimeSubtotal = 0.0;
-//
-//        double updateUnitsPhysicsTimeSubtotal = 0.0;
-//        double updateMissilesTimeSubtotal = 0.0;
-//        double collideTableUpdateTimeSubtotal = 0.0;
-//        double updateCameraSoundsTimeSubtotal = 0.0;
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        double missionSimulationTimeSubtotal = 0.0;
+        double processUnitTimeSubtotal = 0.0;
+
+        double updateUnitsPhysicsTimeSubtotal = 0.0;
+        double updateMissilesTimeSubtotal = 0.0;
+        double collideTableUpdateTimeSubtotal = 0.0;
+        double updateCameraSoundsTimeSubtotal = 0.0;
+#endif
 
         //Chew up all sim_atoms that have elapsed since last update
         // ** stephengtuggy 2020-07-23: We definitely need this block of code! **
         while (time > simulation_atom_var) {
-            //VS_LOG(trace, "void StarSystem::Update( float priority, bool executeDirector ): Chewing up a sim atom");
+            VS_LOG(trace, "void StarSystem::Update( float priority, bool executeDirector ): Chewing up a sim atom");
             if (current_stage == MISSION_SIMULATION) {
-//                double missionSimulationStageStartTime = realTime();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                double missionSimulationStageStartTime = realTime();
+#endif
                 TerrainCollide();
                 UpdateAnimatedTexture();
                 Unit::ProcessDeleteQueue();
@@ -1150,45 +1156,60 @@ void StarSystem::Update(float priority, bool executeDirector) {
                     //waste of frakkin time
                     active_missions[i]->BriefingUpdate();
                 }
-//                double missionSimulationStageEndTime = realTime();
-//                missionSimulationTimeSubtotal += (missionSimulationStageEndTime - missionSimulationStageStartTime);
-//                VS_LOG(trace, (boost::format("void StarSystem::Update( float priority, bool executeDirector ): Time taken by MISSION_SIMULATION stage: %1%") % (missionSimulationStageEndTime - missionSimulationStageStartTime)));
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                double missionSimulationStageEndTime = realTime();
+                missionSimulationTimeSubtotal += (missionSimulationStageEndTime - missionSimulationStageStartTime);
+                VS_LOG(trace, (boost::format("void StarSystem::Update( float priority, bool executeDirector ): Time taken by MISSION_SIMULATION stage: %1%") % (missionSimulationStageEndTime - missionSimulationStageStartTime)));
+#endif
                 current_stage = PROCESS_UNIT;
             } else if (current_stage == PROCESS_UNIT) {
-//                double processUnitStageStartTime = realTime();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                double processUnitStageStartTime = realTime();
+#endif
                 UpdateUnitsPhysics(firstframe);
-//                double updateUnitsPhysicsDoneTime = realTime();
-//                updateUnitsPhysicsTimeSubtotal += (updateUnitsPhysicsDoneTime - processUnitStageStartTime);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                double updateUnitsPhysicsDoneTime = realTime();
+                updateUnitsPhysicsTimeSubtotal += (updateUnitsPhysicsDoneTime - processUnitStageStartTime);
+#endif
                 UpdateMissiles(); //do explosions
-//                double updateMissilesDoneTime = realTime();
-//                updateMissilesTimeSubtotal += (updateMissilesDoneTime - updateUnitsPhysicsDoneTime);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                double updateMissilesDoneTime = realTime();
+                updateMissilesTimeSubtotal += (updateMissilesDoneTime - updateUnitsPhysicsDoneTime);
+#endif
                 collide_table->Update();
-//                double collideTableUpdateDoneTime = realTime();
-//                collideTableUpdateTimeSubtotal += (collideTableUpdateDoneTime - updateMissilesDoneTime);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                double collideTableUpdateDoneTime = realTime();
+                collideTableUpdateTimeSubtotal += (collideTableUpdateDoneTime - updateMissilesDoneTime);
+#endif
                 if (this == _Universe->getActiveStarSystem(0)) {
                     UpdateCameraSnds();
                 }
-//                bolttime = realTime();
-//                bolttime = realTime() - bolttime;
-//                double processUnitStageEndTime = realTime();
-//                processUnitTimeSubtotal += (processUnitStageEndTime - processUnitStageStartTime);
-//                updateCameraSoundsTimeSubtotal += (processUnitStageEndTime - collideTableUpdateDoneTime);
-//                VS_LOG(trace, (boost::format("void StarSystem::Update( float priority, bool executeDirector ): Time taken by PROCESS_UNIT stage: %1%") % (processUnitStageEndTime - processUnitStageStartTime)));
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                bolttime = realTime();
+                bolttime = realTime() - bolttime;
+                double processUnitStageEndTime = realTime();
+                processUnitTimeSubtotal += (processUnitStageEndTime - processUnitStageStartTime);
+                updateCameraSoundsTimeSubtotal += (processUnitStageEndTime - collideTableUpdateDoneTime);
+                VS_LOG(trace, (boost::format("void StarSystem::Update( float priority, bool executeDirector ): Time taken by PROCESS_UNIT stage: %1%") % (processUnitStageEndTime - processUnitStageStartTime)));
+#endif
                 current_stage = MISSION_SIMULATION;
                 firstframe = false;
             }
             time -= simulation_atom_var;
         }
 
-//        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by MISSION_SIMULATION: %3%") % __FILE__ % __LINE__ % missionSimulationTimeSubtotal));
-//        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by PROCESS_UNIT: %3%") % __FILE__ % __LINE__ % processUnitTimeSubtotal));
-//
-//        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating units' physics: %3%") % __FILE__ % __LINE__ % updateUnitsPhysicsTimeSubtotal));
-//        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating missiles: %3%") % __FILE__ % __LINE__ % updateMissilesTimeSubtotal));
-//        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating collide tables: %3%") % __FILE__ % __LINE__ % collideTableUpdateTimeSubtotal));
-//        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating camera sounds: %3%") % __FILE__ % __LINE__ % updateCameraSoundsTimeSubtotal));
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by MISSION_SIMULATION: %3%") % __FILE__ % __LINE__ % missionSimulationTimeSubtotal));
+        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by PROCESS_UNIT: %3%") % __FILE__ % __LINE__ % processUnitTimeSubtotal));
+
+        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating units' physics: %3%") % __FILE__ % __LINE__ % updateUnitsPhysicsTimeSubtotal));
+        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating missiles: %3%") % __FILE__ % __LINE__ % updateMissilesTimeSubtotal));
+        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating collide tables: %3%") % __FILE__ % __LINE__ % collideTableUpdateTimeSubtotal));
+        VS_LOG(trace, (boost::format("%1% %2%: Subtotal of time taken by updating camera sounds: %3%") % __FILE__ % __LINE__ % updateCameraSoundsTimeSubtotal));
+
+        double cycleThroughPlayersStartTime = realTime();
+#endif
 
-//        double cycleThroughPlayersStartTime = realTime();
         unsigned int i = _Universe->CurrentCockpit();
         for (unsigned int j = 0; j < _Universe->numPlayers(); ++j) {
             if (_Universe->AccessCockpit(j)->activeStarSystem == this) {
@@ -1204,8 +1225,10 @@ void StarSystem::Update(float priority, bool executeDirector) {
             }
         }
         _Universe->SetActiveCockpit(i);
-//        double cycleThroughPlayersEndTime = realTime();
-//        VS_LOG(trace, (boost::format("%1% %2%: Time taken by cycling through active players / cockpits: %3%") % __FILE__ % __LINE__ % (cycleThroughPlayersEndTime - cycleThroughPlayersStartTime)));
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        double cycleThroughPlayersEndTime = realTime();
+        VS_LOG(trace, (boost::format("%1% %2%: Time taken by cycling through active players / cockpits: %3%") % __FILE__ % __LINE__ % (cycleThroughPlayersEndTime - cycleThroughPlayersStartTime)));
+#endif
     }
     if (sigIter.isDone()) {
         sigIter = draw_list.createIterator();
diff --git a/engine/src/universe.cpp b/engine/src/universe.cpp
index 21600e306b..4ff90d1137 100644
--- a/engine/src/universe.cpp
+++ b/engine/src/universe.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2022 Daniel Horn, pyramid3d, Stephen G. Tuggy,
+ * Copyright (C) 2001-2025 Daniel Horn, pyramid3d, Stephen G. Tuggy,
  * and other Vega Strike contributors.
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -61,6 +61,7 @@
 #include <string>
 #include <vector>
 
+#include "resource/random_utils.h"
 #include "root_generic/options.h"
 
 // Using
@@ -376,52 +377,136 @@ void Universe::WriteSaveGame(bool auto_save) {
 void Universe::StartDraw() {
 #ifndef WIN32
     RESETTIME();
+#endif
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double gfx_begin_scene_start_time = realTime();
 #endif
     GFXBeginScene();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double gfx_begin_scene_end_time = realTime();
+    VS_LOG(trace, (boost::format("%1%: Time taken by GFXBeginScene(): %2%") % __FUNCTION__ % (gfx_begin_scene_end_time - gfx_begin_scene_start_time)));
+#endif
     size_t i;
-    StarSystem *lastStarSystem = NULL;
+    StarSystem *lastStarSystem = nullptr;
     for (i = 0; i < _cockpits.size(); ++i) {
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double set_active_cockpit_start_time = realTime();
+#endif
         SetActiveCockpit(i);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double set_active_cockpit_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by SetActiveCockpit(i): %2%") % __FUNCTION__ % (set_active_cockpit_end_time - set_active_cockpit_start_time)));
+#endif
         float x{};
         float y{};
         float w{};
         float h{};
         CalculateCoords(i, _cockpits.size(), x, y, w, h);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double calculate_coords_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by CalculateCoords(...): %2%") % __FUNCTION__ % (calculate_coords_end_time - set_active_cockpit_end_time)));
+#endif
         AccessCamera()->SetSubwindow(x, y, w, h);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double set_subwindow_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by AccessCamera()->SetSubwindow(...): %2%") % __FUNCTION__ % (set_subwindow_end_time - calculate_coords_end_time)));
+#endif
         if (_cockpits.size() > 1 && AccessCockpit(i)->activeStarSystem != lastStarSystem) {
             _active_star_systems[0]->SwapOut();
             lastStarSystem = AccessCockpit()->activeStarSystem;
             _active_star_systems[0] = lastStarSystem;
             lastStarSystem->SwapIn();
         }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double select_proper_camera_start_time = realTime();
+#endif
         AccessCockpit()->SelectProperCamera();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double select_proper_camera_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by AccessCockpit()->SelectProperCamera(): %2%") % __FUNCTION__ % (select_proper_camera_end_time - select_proper_camera_start_time)));
+#endif
         if (!_cockpits.empty()) {
             AccessCamera()->UpdateGFX();
         }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double update_gfx_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by AccessCamera()->UpdateGFX(): %2%") % __FUNCTION__ % (update_gfx_end_time - select_proper_camera_end_time)));
+#endif
         if (!RefreshGUI() && !UniverseUtil::isSplashScreenShowing()) {
             activeStarSystem()->Draw();
         }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double draw_active_star_system_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by activeStarSystem()->Draw(): %2%") % __FUNCTION__ % (draw_active_star_system_end_time - update_gfx_end_time)));
+#endif
         AccessCamera()->SetSubwindow(0, 0, 1, 1);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double access_camera_set_subwindow_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by AccessCamera()->SetSubwindow(...): %2%") % __FUNCTION__ % (access_camera_set_subwindow_end_time - draw_active_star_system_end_time)));
+#endif
     }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double update_time_start_time = realTime();
+#endif
     UpdateTime();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double update_time_end_time = realTime();
+    VS_LOG(trace, (boost::format("%1%: Time taken by UpdateTime(): %2%") % __FUNCTION__ % (update_time_end_time - update_time_start_time)));
+#endif
     UpdateTimeCompressionSounds();
-    _Universe->SetActiveCockpit(((int) (rand01() * _cockpits.size())) % _cockpits.size());
-    for (i = 0; i < star_system.size() && i < game_options()->NumRunningSystems; ++i) {
-        star_system[i]->Update((i == 0) ? 1 : game_options()->InactiveSystemTime / i, true);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double update_time_compression_sounds_end_time = realTime();
+    VS_LOG(trace, (boost::format("%1%: Time taken by UpdateTimeCompressionSounds(): %2%") % __FUNCTION__ % (update_time_compression_sounds_end_time - update_time_end_time)));
+#endif
+    _Universe->SetActiveCockpit(randomInt(_cockpits.size() - 1, 0));
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double universe_set_active_cockpit_end_time = realTime();
+    VS_LOG(trace, (boost::format("%1%: Time taken by _Universe->SetActiveCockpit(...): %2%") % __FUNCTION__ % (universe_set_active_cockpit_end_time - update_time_compression_sounds_end_time)));
+#endif
+    for (i = 0; i < star_system.size() && i < configuration()->physics.num_running_systems; ++i) {
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double update_star_system_start_time = realTime();
+#endif
+        star_system[i]->Update((i == 0) ? 1 : configuration()->physics.inactive_system_time / i, true);
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double update_star_system_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by star_system[i]->Update(...): %2%") % __FUNCTION__ % (update_star_system_end_time - update_star_system_start_time)));
+#endif
     }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double star_system_process_pending_jumps_start_time = realTime();
+#endif
     StarSystem::ProcessPendingJumps();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double star_system_process_pending_jumps_end_time = realTime();
+    VS_LOG(trace, (boost::format("%1%: Time taken by StarSystem::ProcessPendingJumps(): %2%") % __FUNCTION__ % (star_system_process_pending_jumps_end_time - star_system_process_pending_jumps_start_time)));
+#endif
     for (i = 0; i < _cockpits.size(); ++i) {
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double process_input_start_time = realTime();
+#endif
         SetActiveCockpit(i);
         pushActiveStarSystem(AccessCockpit(i)->activeStarSystem);
         ProcessInput(i);                       //input neesd to be taken care of;
         popActiveStarSystem();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+        const double process_input_end_time = realTime();
+        VS_LOG(trace, (boost::format("%1%: Time taken by ProcessInput(i) and surrounding for loop iteration: %2%") % __FUNCTION__ % (process_input_end_time - process_input_start_time)));
+#endif
     }
     if (screenshotkey) {
         KBData b;
         Screenshot(b, PRESS);
         screenshotkey = false;
     }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double gfx_end_scene_start_time = realTime();
+#endif
     GFXEndScene();
+#if defined(LOG_TIME_TAKEN_DETAILS)
+    const double gfx_end_scene_end_time = realTime();
+    VS_LOG(trace, (boost::format("%1%: Time taken by GFXEndScene(): %2%") % __FUNCTION__ % (gfx_end_scene_end_time - gfx_end_scene_start_time)));
+#endif
     //so we don't starve the audio thread
     micro_sleep(getmicrosleep());
 
diff --git a/libraries/cmd/CMakeLists.txt b/libraries/cmd/CMakeLists.txt
index b5128a706b..a5619b1d38 100644
--- a/libraries/cmd/CMakeLists.txt
+++ b/libraries/cmd/CMakeLists.txt
@@ -117,6 +117,11 @@ IF (WIN32)
     TARGET_COMPILE_DEFINITIONS(vegastrike_cmd PUBLIC "$<$<CONFIG:Debug>:Py_DEBUG>")
 ENDIF()
 
+OPTION (LOG_TIME_TAKEN_DETAILS "Whether to log timing details in the main loop" OFF)
+IF (LOG_TIME_TAKEN_DETAILS)
+    TARGET_COMPILE_DEFINITIONS(vegastrike_cmd PUBLIC LOG_TIME_TAKEN_DETAILS)
+ENDIF ()
+
 TARGET_INCLUDE_DIRECTORIES(vegastrike_cmd SYSTEM PRIVATE ${TST_INCLUDES})
 TARGET_INCLUDE_DIRECTORIES(vegastrike_cmd PRIVATE
         # VS engine headers
diff --git a/libraries/cmd/collision.cpp b/libraries/cmd/collision.cpp
index 6c1a9cdeaf..185820417c 100644
--- a/libraries/cmd/collision.cpp
+++ b/libraries/cmd/collision.cpp
@@ -1,7 +1,7 @@
 /*
  * collision.cpp
  *
- * Copyright (C) 2020-2022 Daniel Horn, Roy Falk, Stephen G. Tuggy and
+ * Copyright (C) 2020-2025 Daniel Horn, Roy Falk, Stephen G. Tuggy and
  * other Vega Strike contributors
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -35,6 +35,8 @@
 
 #include <typeinfo>
 // #include <boost/log/trivial.hpp>
+#include "vega_cast_utils.h"
+#include "cmd/planet.h"
 #include "src/vs_logging.h"
 
 // TODO: convert all float to double and all Vector to QVector.
@@ -60,13 +62,15 @@ Vega_UnitType::asteroid,
 Vega_UnitType::enhancement,
 Vega_UnitType::missile*/
 void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
+    Vega_UnitType other_units_type = other_unit->isUnit();
+
     // Collision with a nebula does nothing
-    if (other_unit->isUnit() == Vega_UnitType::nebula) {
+    if (other_units_type == Vega_UnitType::nebula) {
         return;
     }
 
     // Collision with a enhancement improves your shield apparently
-    if (other_unit->isUnit() == Vega_UnitType::enhancement) {
+    if (other_units_type == Vega_UnitType::enhancement) {
         apply_force = true;
         return;
     }
@@ -105,7 +109,26 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
             return;
 
             // Units (ships) should calculate actual damage
-        case Vega_UnitType::unit:
+    case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if (other_units_type == Vega_UnitType::planet) {
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                const double nav_8_start_time = realTime();
+#endif
+                const auto* as_planet = vega_dynamic_const_cast_ptr<const Planet>(other_unit);
+                if (as_planet->is_nav_point()) {
+                    VS_LOG(debug, "Can't collide with a Nav Point");
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                    const double nav_8_end_time = realTime();
+                    VS_LOG(trace, (boost::format("%1%: Time taken by handling Nav 8 case: %2%") % __FUNCTION__ % (nav_8_end_time - nav_8_start_time)));
+#endif
+                    return;
+                }
+#if defined(LOG_TIME_TAKEN_DETAILS)
+                const double nav_8_end_time = realTime();
+                VS_LOG(trace, (boost::format("%1%: Time taken by handling Nav 8 case: %2%") % __FUNCTION__ % (nav_8_end_time - nav_8_start_time)));
+#endif
+            }
             apply_force = true;
             deal_damage = true;
             return;
@@ -114,8 +137,8 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
             // TODO: refactor this.
         case Vega_UnitType::enhancement:
             // We can't enhance rocks
-            if (other_unit->isUnit() == Vega_UnitType::asteroid ||
-                    other_unit->isUnit() == Vega_UnitType::planet) {
+            if (other_units_type == Vega_UnitType::asteroid ||
+                    other_units_type == Vega_UnitType::planet) {
                 apply_force = true;
                 return;
             }
diff --git a/libraries/root_generic/options.cpp b/libraries/root_generic/options.cpp
index 5debc4987e..212c6e8b49 100644
--- a/libraries/root_generic/options.cpp
+++ b/libraries/root_generic/options.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2022 Daniel Horn, pyramid3d, Stephen G. Tuggy,
+ * Copyright (C) 2001-2025 Daniel Horn, pyramid3d, Stephen G. Tuggy,
  * and other Vega Strike contributors.
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -32,8 +32,6 @@ void vs_options::init() {
     command_interpretor = XMLSupport::parse_bool(vs_config->getVariable("general", "command_interpretor", "false"));
     load_last_savegame = XMLSupport::parse_bool(vs_config->getVariable("general", "load_last_savegame", "false"));
     debug_fs = XMLSupport::parse_int(vs_config->getVariable("general", "debug_fs", "0"));
-    simulation_atom = XMLSupport::parse_floatf(vs_config->getVariable("general", "simulation_atom", "0.1"));
-    audio_atom = XMLSupport::parse_floatf(vs_config->getVariable("general", "audio_atom", "0.05555555556"));
 
 
     /* Audio Options */
diff --git a/libraries/root_generic/options.h b/libraries/root_generic/options.h
index 853e9b87d7..5f3cff66be 100644
--- a/libraries/root_generic/options.h
+++ b/libraries/root_generic/options.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2023 Daniel Horn, pyramid3d, Stephen G. Tuggy, Benjamen R. Meyer,
+ * Copyright (C) 2001-2025 Daniel Horn, pyramid3d, Stephen G. Tuggy, Benjamen R. Meyer,
  * and other Vega Strike contributors.
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -44,8 +44,6 @@ class vs_options {
     bool command_interpretor{};
     bool load_last_savegame{};
     bool debug_fs{};
-    float simulation_atom{};
-    float audio_atom{};
 
 /* Audio Options */
     int threadtime{};
diff --git a/libraries/root_generic/system_factory.cpp b/libraries/root_generic/system_factory.cpp
index 0a2f53830e..095cee3fb9 100644
--- a/libraries/root_generic/system_factory.cpp
+++ b/libraries/root_generic/system_factory.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001-2022 Daniel Horn, pyramid3d, Stephen G. Tuggy,
+ * Copyright (C) 2001-2025 Daniel Horn, pyramid3d, Stephen G. Tuggy,
  * and other Vega Strike contributors.
  *
  * https://github.com/vegastrike/Vega-Strike-Engine-Source
@@ -266,6 +266,7 @@ Planet *SystemFactory::processPlanet(Star_XML *xml, Object &object, Planet *owne
     float radius = getFloatAttribute(object, "radius", 0.0f);
     float position = getFloatAttribute(object, "position", 0.0f);
     float rotational_velocity = getFloatAttribute(object, "day", 0.0f);
+    float days = rotational_velocity;
     int faction = 0;
     bool isDestination = false;
     bool insideout = getBoolAttribute(object, "InsideOut", false);
@@ -399,7 +400,7 @@ Planet *SystemFactory::processPlanet(Star_XML *xml, Object &object, Planet *owne
             filename, technique, unitname,
             blend_source, blend_destination, destination,
             orbit_center, owner, ourmat, curlights, faction,
-            fullname, insideout);
+            fullname, insideout, days);
 
     if (owner == nullptr) {
         // The sun or another body orbiting the center of the system
diff --git a/libraries/root_generic/vsfilesystem.cpp b/libraries/root_generic/vsfilesystem.cpp
index ef21afd30b..b14b49a68a 100644
--- a/libraries/root_generic/vsfilesystem.cpp
+++ b/libraries/root_generic/vsfilesystem.cpp
@@ -935,9 +935,9 @@ void InitPaths(string conf, string subdir) {
     Directories[PythonFile] = "bases";
     Directories[AccountFile] = "accounts";
 
-    SIMULATION_ATOM = game_options()->simulation_atom;
+    SIMULATION_ATOM = configuration()->general.simulation_atom;
     simulation_atom_var = SIMULATION_ATOM;
-    AUDIO_ATOM = game_options()->audio_atom;
+    AUDIO_ATOM = configuration()->general.audio_atom;
     audio_atom_var = AUDIO_ATOM;
     VS_LOG(info, (boost::format("SIMULATION_ATOM: %1%") % SIMULATION_ATOM));
 


Reviews:
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T08:01:36Z
user: login: vincele
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T09:46:32Z
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T11:09:26Z
user: login: vincele
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T17:43:37Z
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T01:40:06Z
user: login: royfalk
body: Conditional approval:
1. Test in VS with a nav point.
2. Figure out whether you really need to search for invisib in the name. That could easily bite someone later.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T07:45:20Z
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T08:30:46Z
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T04:27:39Z
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-19T02:21:13Z
user: login: stephengtuggy
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-19T02:25:53Z

Review comments:
diff_hunk: @@ -1264,5 +1264,5 @@ IF (USE_GTEST)
     )
 
     INCLUDE(GoogleTest)
-    gtest_discover_tests(${TEST_NAME})
+    gtest_discover_tests(${TEST_NAME} PROPERTIES DISCOVERY_TIMEOUT 30)
path: engine/CMakeLists.txt
user: login: stephengtuggy
body: Builds have started failing more and more often on my local machine with a timeout error discovering tests. Turns out that the default timeout is only 5 seconds. This increases it to 30. No more timeouts, at least not that I've seen.
created_at: 2025-04-13T08:00:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: vincele
body: Shouldn't these conditions test be abstracted away in something like `other_unit->is_invisible()` ?

If I read this properly, does it mean I should rename all my units with "invisible" somewhere in their names ?
created_at: 2025-04-13T09:46:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: stephengtuggy
body: Perhaps abstracting these conditions away would be a good idea. There's only two conditions though, IIRC, so I wasn't sure if it was worth it to create a whole new method. Especially since this would be the only place where it gets used.
created_at: 2025-04-13T11:09:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: vincele
body: That's not the number of conditions that made me think it should be abstracted away (from my sight) ;-)

It's more related to my second question. It's the search for the "invisible" string in the unit name that I think is questionable.

So my question is in fact: why is that other_unit not having the invisible status and is using name tricks to cater for it ?

What about a different flag from invisible, used for "collisionnable" status of objects (for "virtual objects"... we're coming straight into programming language abstractions territory here)?
That would be orthogonal to the fact that the object is visible or not...
created_at: 2025-04-13T17:43:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: stephengtuggy
body: So the search for the `"invisible"` text may not actually be required. That's the way I handled this issue previously, before I knew about the `invisible` property. For all I know, the `invisible` property by itself may be enough.

This needs to be tested. With PWCU. Unfortunately, PWCU's game assets are woefully out of date with respect to the latest Vega Strike Game Engine versions. So that will take some doing.
created_at: 2025-04-14T01:40:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: royfalk
body: > This needs to be tested. With PWCU. Unfortunately, PWCU's game assets are woefully out of date with respect to the latest Vega Strike Game Engine versions. So that will take some doing.

I think it would be easier to port the nav point to VS and add it to Cephid.
created_at: 2025-04-14T07:39:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: royfalk
body: I don't like any of this. It was bad code in the graphics. It's even worse here.
Better to check for something like `mass == 0` IMO.
But that might trigger some obscure bug somewhere.
created_at: 2025-04-14T07:43:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: stephengtuggy
body: > > This needs to be tested. With PWCU. Unfortunately, PWCU's game assets are woefully out of date with respect to the latest Vega Strike Game Engine versions. So that will take some doing.
> 
> I think it would be easier to port the nav point to VS and add it to Cephid.

That makes sense. I'll try that.
created_at: 2025-04-14T08:30:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: stephengtuggy
body: OK. So I took a look at the Nav_8 object and similar objects in PWCU, and imported Nav_8 into Cephid 17, as @royfalk suggested. I noticed that all the Nav_* objects had gravity == 0 and day == 240. The only other objects that had those same property values were jump points. It should not be possible to collide with any of the above, so I think those are the criteria I can use to determine whether an object can be collided with or not. No more string comparisons, which should be a lot better for performance.
created_at: 2025-04-18T04:27:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: stephengtuggy
body: OK, guys, I think I have a solution. I implemented it as listed in the last comment above. It's efficient; it's encapsulated; and it seems to work reliably. Let me know what you guys think.
created_at: 2025-04-19T02:21:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,6 +106,12 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
 
             // Units (ships) should calculate actual damage
         case Vega_UnitType::unit:
+            // Handle the "Nav 8" case
+            if ((other_unit->invisible & Unit::INVISUNIT)
path: libraries/cmd/collision.cpp
user: login: stephengtuggy
body: To test it, I added the following to sectors/Crucible/Cephid_17.system, under "planet" Cephid 17 A:

```xml
	<planet name="Nav_8" file="invisible.png" alpha="ONE ONE" radius="256" gravity="0" x="4000" y="4000" day="240"/>
```

This was copied verbatim from the PWCU repo.
created_at: 2025-04-19T02:25:53Z
author_association: CONTRIBUTOR

PR comments:
user: login: vincele
created_at: 2025-04-14T14:08:45Z
body: @royfalk why should mass have to do with the (in-)visibility tests ? Photons don't have mass, but I can still see (some) of those... And dark matter is invisible but has mass...
author_association: CONTRIBUTOR
user: login: royfalk
created_at: 2025-04-15T06:44:23Z
body: > @royfalk why should mass have to do with the (in-)visibility tests ? Photons don't have mass, but I can still see (some) of those... And dark matter is invisible but has mass...

We are talking about nav points here. These are not actual objects but artificial places on the map so you could navigate there and the quest side of things could fulfill conditions. These are non-collidable objects. We could add extra notation to the unit like `"object type": "nav_point"` but `mass=0` seemed simpler.

AFAIK, no other game object should have `mass=0`. 

As for unintended consequences, I'm reasonably fine right now with not drawing or handling collisions of objects with no mass.
author_association: CONTRIBUTOR
user: login: vincele
created_at: 2025-04-15T14:43:33Z
body: OK, if that's about being the simpler fix, I can understand.
author_association: CONTRIBUTOR