Skip to content

Vessel Overhaul #50

@Katniss218

Description

@Katniss218

Vessel Rework and Simulation Roadmap

1. Executive Summary & Goals

The current vessel simulation architecture, where all vessels are always loaded as single, monolithic rigid bodies, presents significant limitations in performance, physical fidelity, and gameplay possibilities. This document outlines a comprehensive rework of the vessel system to address these limitations.

The primary goals of this rework are:

  • Performance & Scalability: Move from an "all-vessels-loaded" model to an on-demand "bubble" where only nearby vessels are physically simulated. This is critical for supporting complex career saves with many vessels.
  • Physical Fidelity: Evolve vessels from single rigid bodies into multi-body systems connected by joints. This will enable more realistic structural mechanics, flexing, and failures.
  • Gameplay Flexibility: The new architecture will support more complex vessel designs, docking, and construction mechanics.
  • Maintainability: Decouple the part connectivity graph from the Unity GameObject hierarchy to create a more robust and easier-to-manage system.

2. Core Architectural Changes

2.1. Vessel Structure: From Monolith to Multi-Body "Islands"

The fundamental concept of a Vessel will be redefined. The hierarchy will shift from a tree of parts to a collection of physics clusters.

  • Vessel: A logical container that owns a list of VesselIslands. It is responsible for high-level state, metadata, and trajectory simulation.
  • Vessel Island: A group of parts that are rigidly connected and share a single Rigidbody. All parts within an island are considered a single, perfectly rigid body. Structural flexing and articulation only occur between islands via joints.
  • Part (Logic): A pure data class holding state, resources, and references to specific VesselComponents.
  • Part View (GameObject): The visual and collider representation (MonoBehaviour) that exists only when the vessel is fully loaded.
  • No "Root Part": The concept of a specific "Root Part" that dictates the hierarchy of transforms is removed. The vessel is a graph of connected islands.

2.2. Part Connectivity Graph

The logical connection between parts will be separated from the visual GameObject hierarchy.

  • Attachment Graph: A directed graph will represent all part-to-part connections. An edge will exist from a parent part's FAttachNode to a child part's FAttachNode.
  • Graph Traversal: Algorithms (BFS/DFS) will traverse this graph to detect "Rigid Clusters". A VesselIsland is effectively the runtime result of such a cluster.
  • Dynamic Splitting: When a joint breaks or a decoupler fires, the cluster detection re-runs. If the graph splits into discontinuous sub-graphs, new Vessels and VesselIslands are created automatically.

2.3. GameObject Hierarchy Rework

To support the island model and improve performance, the GameObject hierarchy will be standardized and flattened.

  • New Structure:
    Vessel (root GameObject with Vessel component)
    ├── Island 0 (GameObject with Rigidbody and IPhysicsTransform)
    │   ├── PartView A (Mesh, Colliders)
    │   ├── PartView B (...)
    │   └── PartView C (...)
    └── Island 1 (GameObject with Rigidbody and IPhysicsTransform)
        ├── PartView D (...)
        └── PartView E (...)
    
  • All parts within an island are siblings in the hierarchy, parented to the island's GameObject. The islands are, in turn, siblings parented to the main Vessel object.

3. Physics & Simulation Rework

3.1. Composite Reference Frame Transform

The HybridReferenceFrameTransform will be replaced by a CompositeReferenceFrameTransform capable of handling a cloud of rigidbodies.

  • Absolute Mode (On-Rails):

    • Aggregate State: The trajectory system simulates the Center of Mass (CoM) of the entire vessel cluster.
    • Calculation: When switching to Absolute Mode, the system iterates all Islands to compute the Mass-Weighted Average Position and Velocity.
    • Relative Storage: A "Main" island (e.g., largest mass) is selected. The relative positions and rotations of all other islands are stored relative to this Main island. Only the Main island is virtually tracked; others are assumed rigidly attached.
  • Scene Mode (Physics):

    • Restoration: The system instantiates the GameObjects. It applies the Absolute Velocity to the "Main" Rigidbody.
    • Offset Restoration: Secondary islands are restored based on their stored relative offsets to the Main island.
    • Velocity Dampening (Crucial): Upon loading physics, relative velocities between islands must be zeroed out (treated as a rigid whole) to prevent immediate physics explosions caused by slight drift or floating point errors. This zeroing must occur in the non-inertial frame to preserve angular momentum.

3.2. On-Demand Vessel Loading ("Vessel Bubbles")

To dramatically improve performance, vessels will be loaded and unloaded dynamically based on their proximity to an observer (e.g., the active vessel).

  • Packing (Unload): Runtime state is serialized to VesselData. GameObjects are destroyed. The Vessel logical object remains alive in memory to handle resource consumption or background logic.
  • Unpacking (Load): VesselData is deserialized. PartView prefabs are instantiated. Joints are reconstructed.
  • Loading Logic:
    • A configurable load/unload distance will determine the "physics bubble".
    • Loading/Unloading is asynchronous to prevent frame drops.
  • Hysteresis: A buffer zone (e.g., load at 2.5km, unload at 3.0km) will be used to prevent rapid loading/unloading cycles.

3.3. Vessel Simulation States

A vessel will exist in one of several simulation states to manage performance and stability.

  • Physical: The vessel is fully loaded in the physics bubble, with active Rigidbodys and components. This is the only state where a vessel can be actively controlled or interact with other objects.
  • Physicsless (On-Rails): The vessel's GameObject is loaded and visible, but all Rigidbodys are kinematic. Its position is updated directly by the trajectory system. This is for visible but non-interactive vessels outside the immediate physics bubble.
  • Background (Unloaded): The vessel exists only as data. Its trajectory is still simulated, but no GameObject is present in the scene. VesselComponents may still receive ticks (e.g., for resource processing).

3.4. Far Vessel Pinning

Landed, stationary, or distant vessels can be "pinned" to the surface of a celestial body to save performance.

  • Pinning Condition: A vessel is eligible for pinning if it is outside a certain range of the active vessel. Contrary to initial thoughts about only pinning stationary vessels, it's safer to pin any distant vessel to prevent physics instability when its GameObject is unloaded (e.g., falling through terrain).
  • Mechanism: When pinned, its state (velocity, angular velocity, etc.) is saved to a serializable variable. The ReferenceFrameTransform is replaced with a PinnedReferenceFrameTransform.
  • Unpinning: A vessel is unpinned and reloaded into a Physical state when it enters the physics bubble. Its saved velocity and other parameters are restored, ensuring continuity of motion.

3.5. Asynchronous Simulation Pipeline

To manage the increased computational load of multi-body physics, on-demand loading, and other complex systems, the simulation loop will be re-architected to run asynchronously. This will move heavy calculations off the main thread, preventing physics stutter and ensuring a responsive user experience. The full details of this architecture are outlined in the Asynchronous Simulation Architecture document. This system is built around two key concepts:

  1. A Dual-Loop Model: The AsyncSimulationManager orchestrates two parallel loops:

    • Fixed Update Loop (IAsyncFixedSimSystem): For physics-critical tasks (e.g., short-term trajectories, resource flow) that must be synchronized with the FixedUpdate physics step.
    • Update Loop (IAsyncUpdateSimSystem): For non-critical, long-running tasks (e.g., map view trajectory prediction, career mode processing) that should not block the main thread.
  2. The "Prepare-Perform-Apply" Pattern: Each simulation step is broken into three phases, managed by callbacks in a PlayerLoop hook:

    • Prepare (Main Thread, Pre-Physics): Gather data from live GameObjects into thread-safe snapshots.
    • Perform (Background Thread): Run all heavy computations using only the snapshot data.
    • Apply (Main Thread, Post-Physics): Apply the simulation results back to the live GameObjects, correcting their state after the physics step.

4. Serialization Overhaul

The vessel save format must be updated to support the new architecture.

  • Proposed File Structure: For a single vessel, the data will be split into multiple files within its save directory:
    • _vessel.json: Contains the top-level Vessel metadata, simulation state flags, and a list of its islands.
    • islands.json: An array of island definitions, including each island's Rigidbody state.
    • parts.json: A flat list of all serialized part data.
    • graph.json: Defines the attachment graph, storing connections between FAttachNodes by referencing part and node IDs.

5. Component & API Changes

  • VesselComponent System (Logic vs View):

    • Current: Components like FRocketEngine inherit from MonoBehaviour and mix logic with Unity transforms.
    • Target: Introduce a pure C# VesselComponent base class. This contains the logic (e.g., consuming fuel, calculating thrust). It has a lifecycle (OnLoad, OnFixedUpdate, OnUnload) managed by a VesselComponentSystem.
    • View: The visual aspect (particle effects, sound sources, transform positions) remains on a MonoBehaviour (the PartView).
    • Interaction: When Loaded, the VesselComponent acquires a reference to its PartView. When Unloaded, it releases the reference but maintains its data state.
  • Refactor Vessel.cs:

    • Remove RequireComponent(typeof(Rigidbody)).
    • Remove IPhysicsTransform implementation from the Vessel itself; delegate it to VesselIslands.

6. Analysis of Current Implementation & Gaps

The proposed rework introduces several fundamental changes that are inconsistent with the current implementation. These areas will require significant refactoring.

  • Vessel & IPhysicsTransform Coupling: Currently, the Vessel component assumes it coexists on the same GameObject with a single IPhysicsTransform that manages a single Rigidbody.

    • Conflict: In the new model, the Vessel component will be a manager for multiple "islands." The IPhysicsTransform and Rigidbody components will move to the island GameObjects.
    • Resolution: The Vessel class must be refactored to manage a collection of islands and their respective physics bodies. Vessel.PhysicsTransform will likely be deprecated or changed to refer to the "root" island's transform.
  • VesselHierarchyUtils & Separation Logic: The current VesselHierarchyUtils.SetParent method is entirely based on Transform parenting and single-body physics.

    • Conflict: This logic is incompatible with the attachment graph and multi-body island model. A simple reparenting can no longer split a vessel.
    • Resolution: Vessel separation must be completely re-implemented. The new process will be:
      1. Graph Operation: A separation event (e.g., decoupler firing) severs an edge in the attachment graph.
      2. Island Discovery: A graph traversal algorithm (like Breadth-First Search) determines the new sets of connected parts.
      3. Island Creation: If the separation results in a new, disconnected set of parts, a new Island GameObject is created.
      4. Physics Realignment: The separated parts are moved in the GameObject hierarchy to their new island. New mass, CoM, and inertia tensors are calculated for all affected islands (the original and the new one).
      5. Vessel Creation: If the new island is not connected to any other island in the original vessel via a joint, a new Vessel object is created to manage it.
      6. Conservation of Momentum: On separation, the linear and angular momentum of the system must be conserved. The new velocities and angular velocities of the resulting bodies must be calculated based on the pre-separation state and the masses/inertia tensors of the new bodies.
  • Mass & Inertia Calculation: The current Vessel.RecalculateMass aggregates mass from all IHasMass components in the hierarchy and applies it to a single Rigidbody.

    • Conflict: This is no longer valid. Physics properties must be calculated per-island.
    • Resolution: The mass calculation logic must be adapted to run for each island, iterating only over the parts belonging to that island. The Vessel class will delegate these calculations to its islands.

7. Implementation Roadmap

This rework will be implemented in phases to ensure stability at each step.

  • Phase 1: Foundational Refactor (Single Island First)

    1. Implement the attachment graph system, decoupling part logic from the Transform hierarchy. This graph must provide a clear, public API for a part to query its logical parent.
    2. Update the Vessel class and construction system to use the attachment graph, while still assuming a single island and Rigidbody.
    3. Implement the new multi-file serialization format for single-island vessels. This must support saving and loading both standard parts from GameData (by reference) and any procedural parts like resource pipes (by value) created in the VAB. For temporary/unbaked procedural parts in the editor, a dynamic asset ID scheme (e.g., "proc::@<json_params>") should be investigated.
    4. Implement high-fidelity inertia tensor calculation from part meshes to ensure accurate rotational physics for complex shapes.
  • Phase 2: Component System Refactor

    1. Create VesselComponent abstract base class and VesselComponentSystem manager.
    2. Refactor IHasMass, IResourceContainer, etc., to work on VesselComponent.
    3. Convert major components (FRocketEngine) to inherit from VesselComponent, separating Logic (Data) from View (GameObject).
  • Phase 3: Multi-Body Physics

    1. Introduce the "Island" concept. Modify the Vessel class to manage multiple islands.
    2. Implement PhysX joint creation and management between islands based on attachment node types.
    3. Create the CompositeReferenceFrameTransform to handle on-rails and physics simulation for multi-body vessels using mass-weighted averages.
    4. Update separation logic (VesselHierarchyUtils replacement) to correctly split islands and create new vessels, ensuring conservation of momentum.
  • Phase 4: On-Demand Loading

    1. Implement the "vessel stub" system and the VesselManager logic for tracking all vessels in a timeline.
    2. Create the "physics bubble" logic for loading/unloading vessel GameObjects asynchronously.
    3. Define and implement the Physical, Physicsless, and Background simulation states.
    4. Implement the "Pack" (Serialize/Destroy) and "Unpack" (Deserialize/Instantiate) logic using the VesselComponent data state.
  • Phase 5: Optimizations & Future Work

    1. Implement the Far Vessel Pinning system.
    2. (Post-release) Investigate a lightweight background processing system for unloaded vessels to handle things like resource consumption without loading their GameObjects.
    3. Implement a VAB "Part Swapping" tool, enabled by the attachment graph, to allow one-click replacement of parts that share the same attachment node topology.

8. Recommended Ancillary Refactors & Fixes

While overhauling the vessel system, it is opportune to address several related areas of the codebase. These changes, while not strictly part of the core rework, will improve maintainability, performance, and alignment with the new architecture.

  • Deprecate and Remove Obsolete Code:

    • What: The FBulkConnection and commented-out FBulkContainer_Sphere components are marked as obsolete.
    • Why: They have been superseded by the IBuildsFlowNetwork system (FResourceConnection_FlowPipe, FResourceContainer_FlowTank). Leaving them in the codebase creates confusion.
    • Action: Physically remove the obsolete files from the project.
  • Adapt Control Systems for Multi-Body Physics:

    • What: The core avionics component (FAttitudeAvionics) produces a high-level attitude command (e.g., "pitch up"). Downstream components like FGimbalActuatorController and FReactionControlController are responsible for translating this command into specific physical actions (gimbal deflection, RCS thrust) relative to a designated FControlFrame.
    • Why: In a multi-body vessel, applying forces and torques to achieve a desired rotation is no longer trivial. A simple PID loop that assumes a single rigid body can induce or worsen oscillations between islands. The controllers that actuate physical devices must become aware that they are part of a multi-body system.
    • Action: Refactor actuator controllers (FGimbalActuatorController, etc.) to correctly distribute control authority across multiple, potentially moving, physics islands. The logic must intelligently calculate the required forces and torques on each island to achieve the vessel-wide attitude command without causing instability. This may involve more advanced control algorithms or simply a more robust definition of how the FControlFrame is used in a multi-body context.
  • Generalize Force Application:

    • What: Components like FRocketEngine apply forces directly to vessel.PhysicsTransform.
    • Why: In the new model, forces must be applied to the specific Rigidbody of the island that the part belongs to.
    • Action: Refactor all force-producing components. Add a mechanism for each part to cache a reference to its parent island's IPhysicsTransform and Rigidbody, and direct all force/torque applications there.
  • Define Resource Flow Across Joints:

    • What: The IBuildsFlowNetwork system connects resource containers via explicit components like FResourceConnection_FlowPipe.
    • Why: With vessels splitting into multiple islands or even new vessels, the behavior of these connections must be explicitly defined.
    • Action: The established rule is that if a pipe connects two parts, resources will flow regardless of whether they are on the same or different (but joint-connected) islands. To handle vessel separation, new event listeners must be created. These listeners will subscribe to island split events (ON_AFTER_VESSEL_ISLAND_SPLIT) and automatically sever any FResourceConnection components that now span two disconnected vessels. A future enhancement could also sever connections if a joint flexes beyond a certain structural limit, simulating a pipe breaking.
  • Modernize Manager Interactions with Unloaded Vessels:

    • What: Systems like ActiveVesselManager and AllLoadedVesselsPOIGetter currently operate on the assumption that all vessels are fully loaded GameObjects (VesselManager.LoadedVessels).
    • Why: With the new on-demand loading system, these managers will need to work with "vessel stubs."
    • Action:
      • Refactor VesselManager to manage both stubs and fully loaded Vessel instances.
      • Update ActiveVesselManager to handle cases where the active "vessel" might just be a stub, and ensure it is always loaded.
      • Modify AllLoadedVesselsPOIGetter to source its points of interest from the trajectory data of all vessel stubs, not just loaded GameObjects, to ensure terrain LOD is generated correctly for approaching vessels.
  • Review Physics Synchronization via PlayerLoop:

    • What: Several ReferenceFrameTransform implementations inject logic directly into Unity's PlayerLoop for precise synchronization with the physics step.
    • Why: This is a powerful but complex and potentially fragile technique. The major refactor of physics components is a good time to review this.
    • Action: Re-evaluate if this is the most robust and maintainable solution. Investigate if newer Unity APIs or a different combination of MonoBehaviour execution order and events could achieve the same result with less complexity.
  • General Code Cleanup:

    • What: The codebase contains several #warning pragmas and // TODO comments.
    • Why: A major rework is the perfect opportunity for housekeeping.
    • Action: Audit all warnings and to-do items within the files being modified for the vessel rework. Address them, remove them if obsolete, or create new roadmap items if they represent larger tasks. For example, the IResourceContainer interface has a warning suggesting it should be moved.

Metadata

Metadata

Assignees

No one assigned

    Labels

    apiRequesting a change or addition to the API - might affect mods or other parts of the codeimprovementMake an existing feature betteroptimizationMake something run faster (describe how)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions