2026-05-13 07:24:36 +02:00

236 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Architecture — HS_DollyCam
## System Overview
HS_DollyCam is a multi-script Second Life HUD system. The Controller resides in the ROOT prim of a single-prim HUD; all other scripts are linked children. Communication is exclusively via `llMessageLinked` with integer channel codes.
## Component Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ HS_CamController.lsl (ROOT) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Chat parser (/88) │ Preset manager │ State mgmt │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │ │ │ │ │
│ ┌────┘ │ │ │ └────┐ │
│ ▼ ▼ ▼ ▼ ▼ │
│ ┌─────┐ ┌──────────┐ ┌────────┐ ┌────────┐ ┌──────┐ │
│ │ Menu │ │Playlist │ │Engine │ │Markers │ │ FOV │ │
│ │ │ │ │ │Tour │ │ │ │ │ │
│ └──┬───┘ └────┬─────┘ └───┬────┘ └───┬────┘ └──┬───┘ │
│ │ │ │ │ │ │
│ └ └ └ └ ┘ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ HS_CamEngineCore.lsl │ │
│ │ Camera permissions, │ │
│ │ llSetCameraParams, │ │
│ │ Follow/Lock math │ │
│ └──────────────┬──────────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ SL Viewer │ │
│ │ (Camera) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Component Details
### 1. HS_CamController.lsl (ROOT — Main Orchestrator)
**Responsibility:** Central command router and state coordinator.
**Key responsibilities:**
- Chat command parsing on channel 88 (`/88 help`, `/88 save`, `/88 load`, `/88 moveto`, `/88 tour`, etc.)
- Preset management via Linkset Data (`P1`, `P2`, … keys)
- State persistence: Follow/Lock state, Marker visibility, Camera state
- Routing all high-level commands to specialized helper scripts
- Demo mode enforcement (`DEMO_MAX_SLOTS`)
**Key constants:**
- `CH = 88` — Chat channel
- `CE_CMD_*` — Engine command channels (10001060)
- `CE_EVT_*` — Engine event channels (20002060)
- `PH_CMD_*` — Playlist command channels (61006104)
- `MC_CMD = 5100` — Marker command channel
- `MN_CMD = 5200` — Menu command channel
**Notable patterns:**
- `loadPreset(idx)` — reads Linkset Data, extracts position/focus/FOV into temp globals
- `packPreset(pos, foc, rot, fovRad)` — serializes camera state to pipe-delimited string
- `engineMove(pos, foc, durMs)` — sends `CE_CMD_MOVE` to Engine, hides HUD during animated moves
- `phStop(reason)` — forwards `PH_CMD_STOP` to all helpers
### 2. HS_CamPlaylist.lsl (Notecard-Driven Playlist Engine)
**Responsibility:** Asynchronous notecard reading and playlist execution.
**Key responsibilities:**
- Reads playlist notecards line-by-line
- Supports `moveto`, `goto`, `load`, `wait`, `tour...endtour`, `dollyzoom`, `fov`, `lock`, `follow` commands
- Builds `CE_CMD_TOUR` payloads for tour blocks
- Uses `llGetNotecardLineSync` with `NAK` fallback
- Compact notecard tours avoid slow multi-line notecard reads
**Memory optimization:**
- `loadPreset()` uses targeted field parsing (not full `llParseString2List`)
- Tour blocks store indices first, load position/focus at `endtour`
- Token helpers instead of full `llParseString2List(line, [" "], [])`
### 3. HS_CamTourCommands.lsl (Secondary Tour Command Helper)
**Responsibility:** Chat/menu one-shot tour builders.
**Key responsibilities:**
- Handles `/88 tour ...`, `/88 dollyzoom ...`, menu `TOURRUN` payloads
- Builds `CE_CMD_TOUR` payloads without adding memory pressure to Playlist
- Targeted preset parsing for position/focus/FOV fields
**Design principle:** Keep heavy tour parsing out of Playlist; this script absorbs the memory cost.
### 4. HS_CamEngineTour.lsl (Continuous Tour Runtime)
**Responsibility:** High-frequency multi-waypoint camera tour playback.
**Key responsibilities:**
- Receives `CE_CMD_TOUR` from Playlist and TourCommands
- Requests current camera state from Core via `CE_CMD_GET_STATE`
- Builds runtime lists: positions, focuses, holds, weights, segment lengths, cumulative lengths, point times
- Drives camera via `CE_INT_SET_CAM` to EngineCore
- Implements Catmull-Rom spline interpolation and trapezoidal motion profiles
- Throttled camera-frame sending via `tourSendCam()` at ~30Hz
**Memory-critical decisions:**
- Active tour lists stay in script memory (never Linkset Data)
- Segment caching reduces repeated `llList2Vector` access
- `CE_CMD_TOUR` payload parsed with targeted pipe-field helpers
### 5. HS_CamEngineCore.lsl (Camera Engine Core)
**Responsibility:** Low-level camera interface to Second Life viewer.
**Key responsibilities:**
- Camera permissions (`PERMISSION_CONTROL_CAMERA`, `PERMISSION_TRACK_CAMERA`)
- Executes `llSetCameraParams` for all camera movement
- Follow mode math (World/Local/Yaw coordinate frames)
- Lock mode math (tracks target position)
- Configuration dump consumed by Playlist and TourEngine
**Hot path:** `CE_INT_SET_CAM` parsing uses direct separator lookup (no `llParseString2List`).
**Tour-related config keys:**
- `tour_max_points=20` — Max waypoints per segment
- `tour_cam_min_interval=0.033` — ~30Hz camera update cap
- `tour_pos_epsilon=0.005` — Position change threshold
- `tour_focus_epsilon=0.005` — Focus change threshold
### 6. HS_CamMenu.lsl (Dialog Menu / UI)
**Responsibility:** Touch-based dialog menus and UI command dispatch.
**Key responsibilities:**
- Dialog menus with page state
- Menu-driven tour building
- Nearby target lists (avatars/objects)
- UI command dispatch via `MN_CMD` to Controller
**Design note:** Menu paths are secondary to notecard playlist workflows.
### 7. HS_CamMarkers.lsl (Visual Marker Helper)
**Responsibility:** Rez marker pyramids at preset positions.
**Key responsibilities:**
- Rezzes `HS_CamMarker` objects at preset positions
- Uses `MARKER_CH = -880088` region channel
- Uses `llRegionSayTo` for marker communication when keys are known
- Mixed marker list (known to be less memory-efficient, but marker use is rare)
### 8. HS_CamFov.lsl (FOV Controller)
**Responsibility:** Field of View adjustments and FOV state synchronization.
**Key responsibilities:**
- FOV clamping (`RLV_FOV_MIN_DEG=10`, `RLV_FOV_MAX_DEG=179`)
- FOV state sync across scripts
- RLVa integration
## Data Flow
### Preset Save Flow
```
User: /88 save 3
→ Controller: requests camera state from Core (CE_CMD_GET_STATE)
← Core: returns current pos/focus/rot (CE_EVT_STATE)
→ Controller: packs preset, writes to Linkset Data (P3)
← Controller: confirms save to user
```
### Smooth Move Flow
```
User: /88 moveto 5 2500
→ Controller: phStop() (stops any active playlist/tour)
→ Controller: engineMove(<pos5>, <foc5>, 2500)
← EngineCore: camera permission (if needed)
→ EngineCore: llSetCameraParams (smooth interpolation)
← EngineCore: CE_EVT_MOVE_DONE when complete
→ Controller: hudShow()
```
### Continuous Tour Flow
```
User: /88 tour 10000 spline 1 3 5 7
→ Controller: phChatTour(msg)
→ TourCommands: builds CE_CMD_TOUR payload
← TourCommands: sends CE_CMD_TOUR to TourEngine
→ TourEngine: requests current state from Core
← TourEngine: builds runtime lists (positions, focuses, holds, segments)
→ TourEngine: CE_INT_SET_CAM frames @ ~30Hz
← EngineCore: llSetCameraParams (continuous drive)
← TourEngine: CE_INT_TOUR_BEGIN / CE_INT_TOUR_END
```
### Notecard Playlist Flow
```
User: /88 play MyTour
→ Controller: phPlay("MyTour", 0)
→ Playlist: reads notecard line-by-line
← Playlist: executes moveto/goto/load/wait commands
← Playlist: builds tour blocks, sends CE_CMD_TOUR to TourEngine
← TourEngine: drives continuous tour
← Playlist: chains next command on MOVE_DONE
```
## Linkset Data Keys
| Key | Format | Purpose |
|-----|--------|---------|
| `P1``P999` | `px|py|pz|fx|fy|fz|rx|ry|rz|rs|fovRad` | Preset storage |
| `HS_CAMS` | `shown|N` | Marker visibility state |
| `HS_FOLLOW` | `on|uuid` | Follow target state |
| `HS_LOCK` | `on|arg` | Lock target state |
## Communication Channel Map
| Prefix | Range | Direction | Purpose |
|--------|-------|-----------|---------|
| `CE_CMD_` | 10001060 | Ctrl→Core, Playlist, TourEngine | Engine commands |
| `CE_EVT_` | 20002060 | Core→Ctrl, Playlist | Engine events |
| `CE_INT_` | 30003003 | TourEngine→Core | Internal engine ops |
| `PH_CMD_` | 61006104 | Ctrl→Playlist, TourCommands | Playlist commands |
| `MC_CMD` | 5100 | Ctrl→Markers | Marker commands |
| `MC_EVT_*` | 5101 | Markers→Ctrl | Marker events |
| `MN_CMD` | 5200 | Menu→Ctrl | Menu commands |
| `CH` | 88 | User→Ctrl | Chat commands |
| `MARKER_CH` | -880088 | Markers→Region | Marker region say |
## Memory Architecture Principles
1. **Hot paths are timer-driven or high-frequency link_message**`CE_INT_SET_CAM` in EngineCore, tour playback in TourEngine
2. **No `llParseString2List` in hot paths** — Use `llSubStringIndex` for separator lookup, `llGetSubString` for field extraction
3. **Runtime data in script memory, not Linkset Data** — Tour lists are read every timer tick; Linkset Data reads add latency
4. **Short-lived data patterns** — Tour blocks store indices, load position/focus at `endtour`, build final payload directly
5. **Mixed-type lists are expensive** — Avoid in all scripts; use parallel single-type lists instead