services:
  isaac-sim:
    profiles:
      - isaac-sim
    image: &image_tag ${PROJECT_DOCKER_REGISTRY}/${PROJECT_NAME}:v${VERSION}_isaac-sim
    build:
      context: ../
      dockerfile: docker/Dockerfile.isaac-ros
      tags:
        - *image_tag
        # Floating tag republished by docker-build.yml on main/develop. The
        # versioned tag above never exists yet on a PR (check-version-increment
        # forces VERSION up), so it can only ever be a cache miss.
        - &cache_tag ${PROJECT_DOCKER_REGISTRY}/${PROJECT_NAME}:${CACHE_TAG:-cache}_isaac-sim
      cache_from:
        - *image_tag
        - *cache_tag
    container_name: isaac-sim
    entrypoint: ""
    command: >
      bash -c "
      tmux new -d -s isaac;
      if [ $$AUTOLAUNCH = 'true' ]; then
        if [ \"${ISAAC_SIM_USE_STANDALONE}\" = 'true' ]; then
          tmux send-keys -t isaac 'PYTHONPATH="$$ISAAC_SIM_PYTHONPATH" /isaac-sim/python.sh /isaac-sim/AirStack/simulation/isaac-sim/launch_scripts/${ISAAC_SIM_SCRIPT_NAME} --ext-folder ~/.local/share/ov/data/documents/Kit/shared/exts' ENTER
        else
          tmux send-keys -t isaac 'ros2 launch isaacsim run_isaacsim.launch.py install_path:=/isaac-sim gui:=\"${ISAAC_SIM_GUI}\" play_sim_on_start:=\"${PLAY_SIM_ON_START}\" ' ENTER
        fi
      fi;
      sleep infinity"
    # Interactive shell
    stdin_open: true # docker run -i
    tty: true # docker run -t
    ipc: host
    privileged: true
    networks:
      airstack_network:
        # INVARIANT: every sim service (isaac-sim, ms-airsim, simple-sim)
        # binds this same fixed address — robot containers reach the sim at
        # SIM_IP (default 172.31.0.200), so only one sim can run at a time.
        ipv4_address: 172.31.0.200
    env_file:
      - ./omni_pass.env
      # PX4 SITL parameter set, applied by rcS at boot.
      - ./px4-params/${PX4_PARAM_SET:-default}.env
    environment:
      - AUTOLAUNCH=${AUTOLAUNCH:-'false'}
      - DISPLAY=${DISPLAY}
      - QT_X11_NO_MITSHM=1
      # Isaac Sim stuff
      - PLAY_SIM_ON_START=${PLAY_SIM_ON_START}
      - NUM_ROBOTS=${NUM_ROBOTS:-1}
      - ENABLE_LIDAR=${ENABLE_LIDAR:-false}
      # Fleet spawner input: fleet_spawn.py maps the robot-container
      # path onto this container's /isaac-sim/AirStack checkout mount.
      - FLEET_CONFIG_FILE=${FLEET_CONFIG_FILE:-}
      - ISAAC_SIM_HEADLESS=${ISAAC_SIM_HEADLESS:-false}
      # Scene selection (`airstack up --scene <shortname>` → simulation/scenes.yaml):
      # a Pegasus SIMULATION_ENVIRONMENTS key or a USD URL, resolved by the
      # launch scripts (pegasus_app.resolve_scene_from_env). Empty = script default.
      - ISAAC_SIM_SCENE=${ISAAC_SIM_SCENE:-}
      - ISAAC_SIM_STAGE_SCALE=${ISAAC_SIM_STAGE_SCALE:-}
      # Viewport follow-camera (pegasus_app.py): domain id of the drone to
      # chase (default 1; off/none/0 disables) and its world-frame x,y,z
      # offset in meters.
      - ISAAC_SIM_FOLLOW_CAM=${ISAAC_SIM_FOLLOW_CAM:-}
      - ISAAC_SIM_FOLLOW_CAM_OFFSET=${ISAAC_SIM_FOLLOW_CAM_OFFSET:-}
      # Spawn-row center "x,y" in meters (default origin) — for scenes whose
      # origin is cluttered; see launch_scripts/pegasus_app.py.
      - ISAAC_SIM_SPAWN_XY=${ISAAC_SIM_SPAWN_XY:-}
      # Dome light override "intensity[,exposure]" for dim indoor scenes.
      - ISAAC_SIM_DOME_LIGHT=${ISAAC_SIM_DOME_LIGHT:-}
      # Multiply the scene's own lights (office/hospital ceiling lights are
      # authored dim); follow-cam headlight intensity for unlit interiors.
      - ISAAC_SIM_LIGHT_BOOST=${ISAAC_SIM_LIGHT_BOOST:-}
      - ISAAC_SIM_FOLLOW_CAM_LIGHT=${ISAAC_SIM_FOLLOW_CAM_LIGHT:-}
      # Pegasus physics tuning — read by pegasus/simulator/params.py
      - PX4_PHYSICS_HZ=${PX4_PHYSICS_HZ:-100}
      - ARDUPILOT_PHYSICS_HZ=${ARDUPILOT_PHYSICS_HZ:-800}
      - PX4_RENDERING_HZ=${PX4_RENDERING_HZ:-30}
      - ARDUPILOT_RENDERING_HZ=${ARDUPILOT_RENDERING_HZ:-120}
    deploy:
      # let it use the GPU
      resources:
        reservations:
          devices:
            - driver: nvidia # https://stackoverflow.com/a/70761193
              count: 1
              capabilities: [ gpu ]
    volumes:
       # display
      - $HOME/.Xauthority:/isaac-sim/.Xauthority
      - /tmp/.X11-unix:/tmp/.X11-unix
      # isaac sim stuff
      - $HOME/docker/isaac-sim/cache/main:/isaac-sim/.cache:rw \
      - $HOME/docker/isaac-sim/cache/computecache:/isaac-sim/.nv/ComputeCache:rw \
      - $HOME/docker/isaac-sim/logs:/isaac-sim/.nvidia-omniverse/logs:rw \
      - $HOME/docker/isaac-sim/config:/isaac-sim/.nvidia-omniverse/config:rw \
      - $HOME/docker/isaac-sim/data:/isaac-sim/.local/share/ov/data:rw \
      - $HOME/docker/isaac-sim/pkg:/isaac-sim/.local/share/ov/pkg:rw \
      # pegasus integration
      - ../extensions/PegasusSimulator/extensions/pegasus.simulator:/isaac-sim/.local/share/ov/data/documents/Kit/shared/exts/pegasus.simulator/:rw
      # omniverse
      - ./omniverse.toml:/isaac-sim/.nvidia-omniverse/config/omniverse.toml:rw
      - ./user.config.json:/isaac-sim/.local/share/ov/data/Kit/Isaac-Sim Full/5.1/user.config.json:rw # enables pegasus extension; IMPORTANT: set the version number without the trailing .0
      # developer stuff
      - .dev:/isaac-sim/.dev:rw # developer config
      - .bashrc:/isaac-sim/.bashrc:rw # bash config
      - ../../../common/inputrc:/etc/inputrc:rw # for using page up/down to search through command history
      - ../../../common/.tmux.conf:/isaac-sim/.tmux.conf:rw
      # airstack code
      - ../../..:/isaac-sim/AirStack:rw
      - ../../../.devcontainer/isaac-sim/launch.json:/isaac-sim/AirStack/.vscode/launch.json:rw
      - ../../../.devcontainer/isaac-sim/tasks.json:/isaac-sim/AirStack/.vscode/tasks.json:rw

  # ===================================================================================================================
  # Full Isaac Sim GUI editor for USD/scene editing on any asset (runapp.sh,
  # no Pegasus/ROS launch script). Deliberately NOT on airstack_network — no
  # DDS reaches the robots, so it is for scene authoring, not for flying.
  # Run with: airstack up --profile isaac-sim-gui isaac-sim-gui
  # See docs/simulation/isaac_sim/docker.md ("GUI-Only Mode").
  isaac-sim-gui:
    extends:
      service: isaac-sim
    container_name: isaac-sim-gui
    # don't spawn by default, only when you want to use the GUI
    profiles: !override
      - isaac-sim-gui
    command: >
      bash -c "tmux new -d -s isaac; 
        tmux send-keys -t isaac '/isaac-sim/runapp.sh' ENTER;  
      sleep infinity"
    networks: !reset null

  # ===================================================================================================================
  # WebRTC livestream variant for OSMO / remote dev. Headless: no X server,
  # no display, no GUI window. Kit's `omni.kit.livestream.webrtc` extension
  # serves WebSocket signaling on TCP 49100 and SRTP media on UDP 49099 (the
  # latter pinned by `app.livestream.fixedHostPort/minHostPort/maxHostPort=49099`
  # in the Pegasus launch script — see example_one_px4_pegasus_launch_script.py).
  # Those two ports are published into the host (the OSMO workspace pod's
  # network namespace) so `osmo workflow port-forward` can reach them. Kit
  # 107's default media-port range is wider and dynamic, so pinning to a
  # known value is the only way to keep the forward surface to two ports.
  #
  # Selected via COMPOSE_PROFILES (e.g. `desktop,isaac-sim-livestream`) in
  # osmo/workspace/entrypoint.sh, or by setting ISAAC_SIM_LIVESTREAM=true.
  isaac-sim-livestream:
    extends:
      service: isaac-sim
    container_name: isaac-sim-livestream
    profiles: !override
      - isaac-sim-livestream
    # Always run the Pegasus standalone path; the livestream branch in the
    # script is gated on ISAAC_SIM_LIVESTREAM=true (env-driven, additive
    # to the existing script behavior).
    command: >
      bash -c "
      tmux new -d -s isaac;
      tmux send-keys -t isaac 'PYTHONPATH=\"$$ISAAC_SIM_PYTHONPATH\" /isaac-sim/python.sh /isaac-sim/AirStack/simulation/isaac-sim/launch_scripts/${ISAAC_SIM_SCRIPT_NAME} --ext-folder ~/.local/share/ov/data/documents/Kit/shared/exts --/app/livestream/enabled=true' ENTER;
      sleep infinity"
    environment:
      # Inherit everything from isaac-sim and append:
      - ISAAC_SIM_LIVESTREAM=true
      - ISAAC_SIM_USE_STANDALONE=true
      - ISAAC_SIM_HEADLESS=true
    # Publish the WebRTC livestream ports to the pod NS. Bridge-mode +
    # publish (the conservative choice) keeps the rest of the stack on
    # airstack_network for DDS multicast.
    ports:
      - "49100:49100/tcp"      # WebSocket signaling (omni.kit.livestream.webrtc, app.livestream.port=49100)
      - "49099:49099/udp"      # SRTP media (pinned via app.livestream.fixedHostPort=49099 in the launch script)
    # Drop X11-specific volume mounts inherited from the isaac-sim service —
    # there is no X server in an OSMO pod.
    volumes: !override
      - $HOME/docker/isaac-sim/cache/main:/isaac-sim/.cache:rw
      - $HOME/docker/isaac-sim/cache/computecache:/isaac-sim/.nv/ComputeCache:rw
      - $HOME/docker/isaac-sim/logs:/isaac-sim/.nvidia-omniverse/logs:rw
      - $HOME/docker/isaac-sim/config:/isaac-sim/.nvidia-omniverse/config:rw
      - $HOME/docker/isaac-sim/data:/isaac-sim/.local/share/ov/data:rw
      - $HOME/docker/isaac-sim/pkg:/isaac-sim/.local/share/ov/pkg:rw
      - ../extensions/PegasusSimulator/extensions/pegasus.simulator:/isaac-sim/.local/share/ov/data/documents/Kit/shared/exts/pegasus.simulator/:rw
      - ./omniverse.toml:/isaac-sim/.nvidia-omniverse/config/omniverse.toml:rw
      - ./user.config.json:/isaac-sim/.local/share/ov/data/Kit/Isaac-Sim Full/5.1/user.config.json:rw
      - .dev:/isaac-sim/.dev:rw
      - .bashrc:/isaac-sim/.bashrc:rw
      - ../../../common/inputrc:/etc/inputrc:rw
      - ../../../common/.tmux.conf:/isaac-sim/.tmux.conf:rw
      - ../../..:/isaac-sim/AirStack:rw
      - ../../../.devcontainer/isaac-sim/launch.json:/isaac-sim/AirStack/.vscode/launch.json:rw
      - ../../../.devcontainer/isaac-sim/tasks.json:/isaac-sim/AirStack/.vscode/tasks.json:rw
