# HS_DollyCam Project Information This repository contains LSL (Linden Scripting Language) scripts for **HS_DollyCam**, a professional camera control system for Second Life. The project is highly memory-sensitive. LSL script memory is limited, and large lists, mixed-type lists, and repeated string splitting can create avoidable memory pressure. Prefer targeted parsing and short-lived data where practical. ## Core Components The system is split across specialized scripts that communicate mostly via `llMessageLinked`. ### 1. `HS_CamController.lsl` (Main Controller) The central command and state coordinator. - Handles chat commands and menu commands. - Coordinates playlist, menu, marker, FOV, and engine scripts. - Saves presets into Linkset Data. - Handles marker click events and forwards camera movement requests. - Maintains FOLLOW and LOCK state in Linkset Data. Important note: movement math and continuous tour playback are not owned entirely by the Controller anymore. Controller dispatches movement/tour commands to helper scripts and engine scripts. ### 2. `HS_CamPlaylist.lsl` (Playlist Manager) Primary script for notecard-driven workflows. - Reads playlist notecards line by line. - Uses `llGetNotecardLineSync` when the simulator has the notecard cached, with fallback to `llGetNotecardLine` on `NAK`. - Handles `moveto`, `goto`, `load`, `wait`, `tour ... endtour`, `dollyzoom`, `fov`, `lock`, `follow`, and marker show/hide commands. - Builds tour payloads and sends them to `HS_CamEngineTour.lsl` via `CE_CMD_TOUR`. - For notecard tour blocks, the builder stores preset indices, holds, and weights, then loads position/focus only at `endtour`. - Also supports compact notecard tours (`tour [mode] `) to avoid slow multi-line notecard reads when no holds/weights are needed. - Compact notecard tours add an internal `startfirst` mode flag so `HS_CamEngineTour.lsl` starts from the first preset without a current-camera-state roundtrip. - `loadPreset()` intentionally uses targeted field parsing instead of splitting the full preset string into a list. - Standard notecard command parsing uses token helpers rather than full `llParseString2List(line, [" "], [])`. The user's primary workflow is Notecard Tours, so optimize this file carefully and prioritize notecard-tour memory use over chat/menu one-liner convenience. ### 3. `HS_CamTourCommands.lsl` (Secondary Tour Command Helper) Dedicated helper for chat/menu one-shot tour builders. - Handles `/88 tour ...`, `/88 dollyzoom ...`, and menu-built `TOURRUN` payloads. - Builds `CE_CMD_TOUR` payloads for secondary workflows without adding memory pressure to `HS_CamPlaylist.lsl`. - Uses targeted preset parsing for position/focus/FOV fields. - Keep notecard playlist logic in `HS_CamPlaylist.lsl`; keep chat/menu convenience parsing here. ### 4. `HS_CamEngineTour.lsl` (Continuous Tour Runtime) Dedicated runtime for continuous multi-waypoint camera tours. - Receives `CE_CMD_TOUR` payloads from Playlist and TourCommands paths. - Requests current camera state from Core via `CE_CMD_GET_STATE`. - Builds runtime lists for active tour playback: position, focus, holds, segment lengths, cumulative lengths, point times, and optional weights. - Drives the camera by sending `CE_INT_SET_CAM` to `HS_CamEngineCore.lsl`. - Supports spline/linear movement, easing profiles, FOV ramps, and keep-frame mode. - Uses throttled camera-frame sending via `tourSendCam()` to reduce repeated `CE_INT_SET_CAM` messages. - Uses segment caching during timer playback to reduce repeated `llList2Vector` access. - Parses large `CE_CMD_TOUR` payloads using targeted pipe-field helpers rather than splitting the whole payload list. Do not move active tour runtime lists into Linkset Data. They are read every timer tick; Linkset Data would reduce script memory but likely hurt runtime performance due to repeated string reads and conversions. ### 5. `HS_CamEngineCore.lsl` (Camera Engine Core) Low-level camera engine. - Handles camera permissions, base camera params, MoveTo, Follow, Lock, config, and state queries. - Receives internal tour camera frames with `CE_INT_SET_CAM`. - `CE_INT_SET_CAM` is parsed without `llParseString2List` because it is part of the active tour hot path. - Applies `llSetCameraParams` for active camera movement. - Holds engine configuration and emits config dumps consumed by Playlist and TourEngine. Tour-related config keys include: - `tour_max_points` - `tour_cam_min_interval` - `tour_pos_epsilon` - `tour_focus_epsilon` ### 6. `HS_CamMenu.lsl` (Menu/UI) Handles dialog menus, page state, menu-driven tour building, nearby target lists, and UI command dispatch. - Sends menu commands with `MN_CMD`. - Keeps short UI lists such as nearby avatars/objects and selected tour indices. - Menu paths are secondary compared with notecard tours. ### 7. `HS_CamMarkers.lsl` (Marker Helper) Marker support is a comparatively rare workflow. - Rezzes `HS_CamMarker` objects at preset positions. - Uses `MARKER_CH = -880088`. - Uses `llRegionSayTo` for marker setup/cleanup when marker keys are known. - Keeps a mixed marker list internally. This is known to be less memory-efficient, but marker usage is rare and should not be prioritized unless marker workflows become important. ### 8. `HS_CamFov.lsl` Handles Field of View adjustments and FOV-related state synchronization. ## Communication Protocol Primary communication uses `llMessageLinked`. Important constants: - `MC_CMD = 5100`: Marker helper command channel, e.g. `SHOW|N`, `HIDE`. - `MC_EVT_CLICK = 5101`: Marker click event from Markers to Controller. - `MN_CMD = 7000`: Menu command channel. - `PH_CMD_PLAY = 6100`: Controller/Menu to Playlist play command. - `PH_CMD_STOP = 6101`: Stop playlist command. - `PH_CMD_CHAT_TOUR = 6102`: Chat one-liner tour forwarded to TourCommands. - `PH_CMD_TOURRUN = 6103`: Menu-built tour forwarded to TourCommands. - `PH_CMD_CHAT_DZ = 6104`: Chat DollyZoom forwarded to TourCommands. - `CE_CMD_MOVE = 1010`: Engine move command. - `CE_CMD_TOUR = 1011`: Continuous tour command handled by TourEngine. - `CE_CMD_STOP = 1012`: Stop engine movement. - `CE_CMD_LOCK = 1020`: Lock command. - `CE_CMD_FOLLOW = 1030`: Follow command. - `CE_CMD_FOV = 1040`: FOV command. - `CE_CMD_GET_STATE = 1060`: Request current camera state. - `CE_INT_SET_CAM = 3000`: TourEngine to Core camera frame, payload `|`. - `CE_INT_TOUR_BEGIN = 3001`: TourEngine begins external drive. - `CE_INT_TOUR_END = 3002`: TourEngine ends external drive. - `CE_INT_TOUR_STOP = 3003`: Stop external tour drive. - `MARKER_CH = -880088`: Region channel for marker communication. ## Preset Storage Presets are stored in Linkset Data using keys like `P1`, `P2`, etc. Preset format: ```text px|py|pz|fx|fy|fz|rx|ry|rz|rs|fovRad ``` Many consumers only need the first six fields: - position: fields `0..2` - focus: fields `3..5` - optional FOV: field `10` When reading presets in memory-sensitive code, avoid full `llParseString2List(data, ["|"], [])` if only these fields are needed. ## Performance And Memory Guidelines ### Prefer targeted parsing in hot paths Avoid full `llParseString2List` when: - parsing `CE_INT_SET_CAM` - parsing preset data - parsing large `CE_CMD_TOUR` payloads - parsing normal notecard playlist lines Use targeted helpers such as: - `lineToken()` in `HS_CamPlaylist.lsl` - pipe-field helpers in `HS_CamEngineTour.lsl` - direct separator lookup for two-field payloads in `HS_CamEngineCore.lsl` ### Keep active runtime data in script memory Active tour playback reads position/focus/segment lists every timer tick. Keep those lists in `HS_CamEngineTour.lsl`; do not replace them with Linkset Data reads. Linkset Data is appropriate for persistent presets and shared state, not per-frame runtime data. ### Minimize mixed-type and large temporary lists Avoid mixed-type list builders for large payloads where a direct string build is clear and safe. For notecard tour blocks: - Store preset indices while parsing. - Load preset position/focus at `endtour`. - Build the final `CE_CMD_TOUR` payload directly. ### Be careful with timer hot paths Timer-driven code should avoid: - full string splitting - repeated Linkset Data reads - repeated object detail calls unless needed - unnecessary `llMessageLinked` calls Tour playback currently reduces load with: - `tour_cam_min_interval` - `tour_pos_epsilon` - `tour_focus_epsilon` - segment caching in TourEngine ### Use `llRegionSayTo` when target keys are known For marker communication, prefer `llRegionSayTo` over `llRegionSay` when the marker key is known. This reduces unnecessary listener wakeups in the region. ## Configuration Engine configuration lives in `HS_CamEngine.properties`. Useful current keys: ```text move_step=0.025 follow_step=0.05 default_move_ms=3000 default_focus_dist=10.0 move_pos_lag=0.5 move_focus_lag=0.5 follow_pos_lag=0.5 follow_focus_lag=0.5 pos_threshold=0.02 focus_threshold=0.02 tour_cam_min_interval=0.033 tour_pos_epsilon=0.005 tour_focus_epsilon=0.005 follow_predict=0.10 tour_max_points=20 ``` `tour_cam_min_interval=0.033` caps internal tour camera updates around 30 Hz while still allowing path computation at `move_step`. ## Validation Notes There is no official local Second Life LSL compiler in this repository. The authoritative compile check is still in-world via the Second Life Viewer or Firestorm. Local checks that are useful before in-world compile: - brace-balance checks - conflict marker search - targeted `rg` scans for unwanted `llParseString2List` reintroductions in hot paths - optional `lslint` if installed, with the understanding that it is not the official Linden compiler ## Current Optimization Priorities Highest priority: - Notecard tour memory behavior. - TourEngine timer hot path. - Core `CE_INT_SET_CAM` hot path. - Large `CE_CMD_TOUR` startup parsing. Lower priority: - Marker memory layout, because marker use is rare. - Chat one-liner tour convenience paths. - Menu-only tour building paths, unless they become a primary workflow.