11 KiB
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 channelCE_CMD_*— Engine command channels (1000–1060)CE_EVT_*— Engine event channels (2000–2060)PH_CMD_*— Playlist command channels (6100–6104)MC_CMD = 5100— Marker command channelMN_CMD = 5200— Menu command channel
Notable patterns:
loadPreset(idx)— reads Linkset Data, extracts position/focus/FOV into temp globalspackPreset(pos, foc, rot, fovRad)— serializes camera state to pipe-delimited stringengineMove(pos, foc, durMs)— sendsCE_CMD_MOVEto Engine, hides HUD during animated movesphStop(reason)— forwardsPH_CMD_STOPto 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,followcommands - Builds
CE_CMD_TOURpayloads for tour blocks - Uses
llGetNotecardLineSyncwithNAKfallback - Compact notecard tours avoid slow multi-line notecard reads
Memory optimization:
loadPreset()uses targeted field parsing (not fullllParseString2List)- 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 ..., menuTOURRUNpayloads - Builds
CE_CMD_TOURpayloads 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_TOURfrom 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_CAMto 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
llList2Vectoraccess CE_CMD_TOURpayload 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
llSetCameraParamsfor 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 segmenttour_cam_min_interval=0.033— ~30Hz camera update captour_pos_epsilon=0.005— Position change thresholdtour_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_CMDto 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_CamMarkerobjects at preset positions - Uses
MARKER_CH = -880088region channel - Uses
llRegionSayTofor 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 |
HS_CAMS |
`shown | N` |
HS_FOLLOW |
`on | uuid` |
HS_LOCK |
`on | arg` |
Communication Channel Map
| Prefix | Range | Direction | Purpose |
|---|---|---|---|
CE_CMD_ |
1000–1060 | Ctrl→Core, Playlist, TourEngine | Engine commands |
CE_EVT_ |
2000–2060 | Core→Ctrl, Playlist | Engine events |
CE_INT_ |
3000–3003 | TourEngine→Core | Internal engine ops |
PH_CMD_ |
6100–6104 | 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
- Hot paths are timer-driven or high-frequency link_message —
CE_INT_SET_CAMin EngineCore, tour playback in TourEngine - No
llParseString2Listin hot paths — UsellSubStringIndexfor separator lookup,llGetSubStringfor field extraction - Runtime data in script memory, not Linkset Data — Tour lists are read every timer tick; Linkset Data reads add latency
- Short-lived data patterns — Tour blocks store indices, load position/focus at
endtour, build final payload directly - Mixed-type lists are expensive — Avoid in all scripts; use parallel single-type lists instead