# HappyBums / HappyBumsPlus — Full Architecture ## v4.3 (HappyBumsPlus) / v4.2 (HappyBums) --- ## Overview Two product variants share the same architecture: - **HappyBums** — wetting only (wetness states 0–4) - **HappyBumsPlus** — wetting + messing (wetness 0–4, mess states 0–3) Each variant consists of two separate wearable objects: 1. **Main Diaper HUD** — the primary object containing all logic, storage, and web connectivity. Contains three scripts and 21 prims (root + 20 children). 2. **HoverText Wearable** — an optional separate attachment (skull point) that displays floating text above the wearer. Contains one script and 2 prims (root + 1 child). Shared between both variants. --- ## Scripts ### Core v4.2 (HappyBums) / v4.3 (HappyBumsPlus) The main logic script. Handles: - All menus (touch, dialog, command channel) - Wetness state, change locking, removal locking - Mess state (HappyBumsPlus only) - Auto-wet and auto-mess timers - Access control (whitelist, blacklist, RLV owners) - Announce routing (Private IM / Local Chat / Everyone) - RLV lock/release calls - HTTP POST to the web panel (webPost) - Hover text channel updates to the HoverText wearable - Web heartbeat timer - Safeword handling (resets both wetness and mess in Plus) - Region maturity gating ### Persistence v4.2 (HappyBums) / v4.3 (HappyBumsPlus) Storage-only script. No user-facing logic. Handles: - All reads and writes to prim descriptions - Startup handshake (sends `PERSIST_MODE` to Core) - Routes `SAVE_CFG` to the correct settings prim - Assembles `LOADED`, `CFG`, `LIST` replies for Core ### WebRelay v1.1 (HappyBums) / v1.2 (HappyBumsPlus) HTTP relay script. Handles: - `llRequestURL()` to obtain a simulator URL - Broadcasts simulator URL to Core via `WEB_RELAY_URL` - Receives `WEB_RELAY_INIT` from Core to get the HUD UUID for request validation - Validates incoming POST requests from the PHP control panel - Translates valid commands into `WEB_CMD|...` linked messages to Core - Re-requests URL on region change or URL expiry ### HoverText v1.1 *(separate wearable — shared between both variants)* Floating text script. Handles: - Deriving a private listen channel from the owner UUID - Displaying coloured floating text on a child prim (link 2) - Responding to `STATE:`, `TOGGLE:`, and `HEIGHT:` commands from the main HUD - Saving its own on/height settings to its own root prim description - Backwards-compatible: shows wet-only display for HappyBums, combined wet+mess for HappyBumsPlus --- ## Main HUD — Linkset Layout (21 prims) | Link # | Prim Name | Purpose | |--------|--------------------|----------------------------------------------| | 1 | root | Runtime state | | 2 | Settings A1 | Timer / announce / access flags | | 3 | Settings A2 | Control / identity / limits | | 4 | Settings B | Safeword, owner title | | 5 | Settings C | Wet state names (raw CSV) | | 6 | Settings D | Mess state names (raw CSV) — Plus only; spare in HappyBums | | 7 | Whitelist Page 1 | Whitelist UUIDs 1–3 | | 8 | Whitelist Page 2 | Whitelist UUIDs 4–6 | | 9 | Whitelist Page 3 | Whitelist UUIDs 7–9 | | 10 | Whitelist Page 4 | Whitelist UUIDs 10–12 | | 11 | Blacklist Page 1 | Blacklist UUIDs 1–3 | | 12 | Blacklist Page 2 | Blacklist UUIDs 4–6 | | 13 | Blacklist Page 3 | Blacklist UUIDs 7–9 | | 14 | Blacklist Page 4 | Blacklist UUIDs 10–12 | | 15 | RLV Owners Page 1 | RLV owner UUIDs 1–3 | | 16 | RLV Owners Page 2 | RLV owner UUIDs 4–6 | | 17 | HUD UUID | Persistent HUD UUID (`hu=`) | | 18 | Website URL | Raw website URL string | | 19 | Spare | Reserved for future use | | 20 | Spare | Reserved for future use | | 21 | Spare | Reserved for future use | All three scripts (Core, Persistence, WebRelay) live in the root prim (link 1). --- ## HoverText Wearable — Linkset Layout (2 prims) | Link # | Prim Name | Purpose | |--------|-----------|-----------------------------------------------------------| | 1 | root | Script host; stores `on=` and `h=` in prim description | | 2 | child | Floating text display prim; repositioned via PRIM_POS_LOCAL | --- ## Prim Description Formats ### Link 1 — Runtime State HappyBums: ``` w=0,cl=0,rl=0,do=1,et=0,t=1 ``` HappyBumsPlus: ``` w=0,cl=0,rl=0,do=1,et=0,m=0,me=0,t=1 ``` | Field | Key | Meaning | Values | |-------|-----|---------------------------|---------------------------| | w | w | Wetness | 0–4 | | cl | cl | Change locked | 0=No / 1=Wearer / 2=Owner | | rl | rl | Removal locked | 0=No / 1=Owner | | do | do | Diaper on | 0/1 | | et | et | Elapsed wet timer (secs) | 0–n | | m | m | Mess state (Plus only) | 0–3 | | me | me | Elapsed mess timer (secs) | 0–n (Plus only) | | t | t | Touch enabled | 0/1 | > **Lockout recovery:** manually edit root prim description, change `t=0` to `t=1`, reset scripts. --- ### Link 2 — Settings A1 (timer / announce / access flags) HappyBums: ``` awi=1800,af=0,al=1,ac=0,ach=1,nw=1,cc=0,sc=0,mr=0,now=0 ``` HappyBumsPlus: ``` awi=900,af=0,al=1,ac=0,ach=1,nw=1,cc=0,sc=0,mr=0,now=0,ami=0,mm=0 ``` | Field | Key | Meaning | Default | |-------|----------------------|----------------------------------|---------| | awi | auto_wet_interval | Auto-wet interval (secs) | 1800 | | af | announce_full | Announce on full wet | 0 | | al | announce_leak | Announce on leak | 1 | | ac | access_mode | 0=Open/List 1=Owner Only | 0 | | ach | announce_change | Announce on change | 1 | | nw | notify_wearer | Notify wearer on wet | 1 | | cc | command_channel | Command channel offset | 0 | | sc | safeword_channel | Safeword channel offset | 0 | | mr | min_maturity | Min region maturity (0/1/2) | 0 | | now | notify_on_wear | Notify owner on wear/login | 0 | | ami | auto_mess_interval | Auto-mess interval (secs, Plus) | 0 | | mm | min_mess | Min mess state for change (Plus) | 0 | --- ### Link 3 — Settings A2 (control / identity / limits) ``` cp=,mcs=0,chl=-1,chc=-1,wi=180 ``` | Field | Key | Meaning | Default | |-------|------------------|-----------------------------------|---------| | cp | command_prefix | Command prefix (auto-generated) | "" | | mcs | min_change_state | Min wetness to allow change | 0 | | chl | change_limit | Change limit (-1=unlimited) | -1 | | chc | change_counter | Remaining changes (-1=unlimited) | -1 | | wi | web_interval | Web heartbeat interval (secs) | 180 | --- ### Link 4 — Settings B (safeword, owner title) ``` sw=SAFEWORD,ot=Caregiver ``` | Field | Key | Meaning | Default | |-------|-------------|-------------------|------------| | sw | safeword | Safeword string | SAFEWORD | | ot | owner_title | Owner title label | Caregiver | --- ### Link 5 — Settings C (wet state names) ``` Dry,Damp,Wet,Soaking,Leaking ``` Raw comma-separated CSV only. No `key=` prefix. 5 values. --- ### Link 6 — Settings D (mess state names — HappyBumsPlus only) ``` Clean,Soiled,Messy,Blowout ``` Raw comma-separated CSV only. No `key=` prefix. 4 values. Spare prim in HappyBums. --- ### Links 7–16 — Access Lists (pipe-separated UUIDs) ``` uuid1|uuid2|uuid3 ``` Maximum 3 UUIDs per prim (3 × 36 chars + 2 pipes = 110 chars, within 128-char limit). | Prims | List | Max UUIDs | |--------|------------|-----------| | 7–10 | whitelist | 12 | | 11–14 | blacklist | 12 | | 15–16 | rlv_owners | 6 | --- ### Link 17 — HUD UUID ``` hu= ``` Persistent unique identifier for this HUD instance. Used as the access key for web panel authentication. --- ### Link 18 — Website URL Raw URL string. No key= prefix. --- ### HoverText Wearable — Root Prim Description ``` on=1,h=0.5 ``` | Field | Meaning | |-------|-----------------------| | on | Display enabled (0/1) | | h | Vertical offset in metres | --- ## Linked Message Protocol (channel 1001) ### Core → Persistence | Message | Action | |-------------------------------|---------------------------------------------| | `SAVE_ALL\|k=v\|...` | Write runtime state fields to link 1 | | `SAVE_CFG\|key=value` | Update single setting in correct child prim | | `SAVE_LIST\|which\|uuid\|...` | Write list across correct list prims | | `SAVE_HUD_UUID\|uuid` | Write HUD UUID to link 17 | | `SAVE_WEBSITE_URL\|url` | Write website URL to link 18 | | `LOAD_SETTINGS` | Request touch_enabled from link 1 | | `LOAD_CFG` | Request all settings | | `LOAD_ALL` | Request runtime state | | `LOAD_LIST\|which` | Request whitelist / blacklist / rlv_owners | | `LOAD_HUD_UUID` | Request HUD UUID from link 17 | | `LOAD_WEBSITE_URL` | Request website URL from link 18 | ### Persistence → Core | Message | Meaning | |-------------------------------|---------------------------------------------| | `PERSIST_MODE\|primdesc` | Startup handshake | | `SETTINGS\|touch_enabled=n` | Reply to LOAD_SETTINGS | | `CFG\|key=val\|...` | Reply to LOAD_CFG (all settings) | | `LOADED\|k=v\|...` | Reply to LOAD_ALL (runtime state) | | `LIST\|which\|uuid\|...` | Reply to LOAD_LIST | | `HUD_UUID\|uuid` | Reply to LOAD_HUD_UUID | | `WEBSITE_URL\|url` | Reply to LOAD_WEBSITE_URL | ### Core → WebRelay | Message | Meaning | |-------------------------------|-----------------------------------------------| | `WEB_RELAY_INIT\|uuid` | Sends HUD UUID so WebRelay can validate POSTs | ### WebRelay → Core | Message | Meaning | |---------------------------------|------------------------------------------| | `WEB_RELAY_URL\|url` | Simulator URL for inclusion in heartbeat | | `WEB_CMD\|wet` | Wet the diaper by 1 step | | `WEB_CMD\|mess` | Mess the diaper by 1 step (Plus only) | | `WEB_CMD\|change` | Change the diaper | | `WEB_CMD\|change_lock\|n` | Set change lock (0/1/2) | | `WEB_CMD\|hud_lock\|n` | Set removal lock (0/1) | | `WEB_CMD\|autowet\|n` | Set auto-wet interval (seconds) | | `WEB_CMD\|automess\|n` | Set auto-mess interval (seconds, Plus) | | `WEB_CMD\|msg\|text` | Send IM to wearer | | `WEB_CMD\|announce_full\|n` | Set announce_full (0/1/2) | | `WEB_CMD\|announce_leak\|n` | Set announce_leak (0/1/2) | | `WEB_CMD\|announce_change\|n` | Set announce_change (0/1/2) | | `WEB_CMD\|notify_wearer\|n` | Set notify_wearer (0/1) | | `WEB_CMD\|owner_title\|text` | Set owner title string | | `WEB_CMD\|state_names\|csv` | Set all 5 wet state name labels | | `WEB_CMD\|mess_names\|csv` | Set all 4 mess state name labels (Plus) | ### Core → HoverText Wearable (llSay on private channel) Channel derived as: `channel = -1 - (integer)("0x" + first 7 chars of owner UUID)` HappyBums (3-part): ``` STATE:wetIdx|displayName|wetStateName ``` HappyBumsPlus (5-part): ``` STATE:wetIdx|displayName|wetStateName|MESS:messIdx|messStateName ``` | Message | Meaning | |----------------------------------|----------------------------------| | `STATE:...` (see above) | Update text and colour | | `TOGGLE:0` / `TOGGLE:1` | Disable / enable display | | `HEIGHT:+0.1` / `HEIGHT:-0.1` | Adjust vertical offset | | `HEIGHT:0` | Reset vertical offset to default | --- ## Initialisation Sequence ``` Persistence state_entry() └─ 0.5s timer → PERSIST_MODE|primdesc → Core Core receives PERSIST_MODE └─ LOAD_SETTINGS → Persistence └─ SETTINGS|touch_enabled=n → Core Core receives SETTINGS └─ LOAD_CFG → Persistence └─ CFG|key=val|... → Core Core receives CFG └─ LOAD_ALL → Persistence └─ LOADED|k=v|... → Core Core receives LOADED └─ LOAD_LIST|whitelist → Persistence → LIST|whitelist|... └─ LOAD_LIST|blacklist → Persistence → LIST|blacklist|... └─ LOAD_LIST|rlv_owners → Persistence → LIST|rlv_owners|... └─ LOAD_HUD_UUID → Persistence → HUD_UUID|uuid └─ LOAD_WEBSITE_URL → Persistence → WEBSITE_URL|url Core tracks g_lists_loaded bitmask (1+2+4+8+16 = 31) └─ When == 31 → finishInit() └─ WEB_RELAY_INIT|uuid → WebRelay └─ webPost() heartbeat to PHP └─ RLV relock if g_removal_locked == 1 └─ Notify owner if g_notify_on_wear == 1 WebRelay (parallel, independent) └─ state_entry() → llRequestURL() └─ URL_REQUEST_GRANTED → WEB_RELAY_URL|url → Core ``` --- ## Web Panel Integration ### Core → PHP (webPost) Core sends an HTTP POST to `g_website_url` on: - `finishInit()` — startup heartbeat - `applyWetting()` — state change - `applyMessing()` — state change (Plus only) - `changeDiaper()` — state change - Timer tick — when `g_web_elapsed >= g_web_interval` - `WEB_RELAY_URL` received — to push updated simulator URL POST body fields (JSON): | Field | Notes | |---------------------|---------------------------------------| | access_uuid | HUD UUID | | wearer_name | Display name | | region_name | Current region | | region_rating | 0=General / 1=Moderate / 2=Adult | | diaper_state | Wet state name string | | mess_state | Mess state name string (Plus: always present) | | mess_capable | "1" (Plus only — always sent) | | removal_locked | 0/1 | | change_lock | 0/1/2 | | auto_wet_interval | Seconds | | auto_mess_interval | Seconds (Plus only) | | simulator_url | WebRelay URL | | last_seen | Unix timestamp | | owner_list | Comma-separated RLV owner UUIDs | | announce_full | 0/1/2 | | announce_leak | 0/1/2 | | announce_change | 0/1/2 | | notify_wearer | 0/1 | | owner_title | String | | state_names | 5-item CSV | | mess_names | 4-item CSV (Plus only) | ### PHP → In-World (via WebRelay) PHP sends a POST to the simulator URL with JSON: ```json { "cmd": "wet", "access_uuid": "" } ``` WebRelay validates `access_uuid` then sends the appropriate `WEB_CMD` linked message. Available commands: `wet`, `mess` (Plus), `change`, `change_lock`, `hud_lock`, `autowet`, `automess` (Plus), `msg`, `announce_full`, `announce_leak`, `announce_change`, `notify_wearer`, `owner_title`, `state_names`, `mess_names` (Plus). --- ## PHP Scripts ### happybums.php (V8) Main web endpoint. Single-file PHP application. Shared between HappyBums and HappyBumsPlus — the `mess_capable` flag in the heartbeat payload controls whether mess UI is rendered. Handles: - Receiving heartbeat POSTs from Core; storing/updating wearer state in SQLite - Processing `add_owner` and `reset_password` actions from Core - Owner login, cookie session management (30-day remember-me) - Dashboard showing all linked wearers with state summary - Control panel: wet/mess buttons, change, lock controls, auto-wet/mess intervals - Settings modals: Announce, Identity (state names, mess names), web commands Database tables: `wearers`, `owners`, `owner_wearers`, `nicknames`. New wearers columns added in V8: `mess_state`, `mess_capable`, `auto_mess_interval`, `mess_names`. ### happybums_cleanup.php Maintenance script. Removes stale wearer records (default: not seen for >365 days) and cascades to orphaned rows in all related tables. Run via cron or web. Supports `--dry-run` flag. --- ## Key Runtime Variables (Core) ### State | Variable | Meaning | Plus only | |-------------------|---------------------------------------|-----------| | g_wetness | Current wetness 0–4 | | | g_mess | Current mess 0–3 | ✓ | | g_change_locked | 0=No / 1=Wearer / 2=Owner | | | g_removal_locked | 0=No / 1=Owner locked | | | g_diaper_on | 1=wearing | | | g_elapsed_timer | Seconds since last auto-wet | | | g_mess_elapsed | Seconds since last auto-mess | ✓ | ### Settings | Variable | Meaning | Plus only | |----------------------|------------------------------------------|-----------| | g_auto_wet_interval | Seconds between auto-wets (0=off) | | | g_auto_mess_interval | Seconds between auto-mess events (0=off) | ✓ | | g_min_change_state | Min wetness before change allowed | | | g_min_mess | Min mess before change allowed | ✓ | | g_announce_full | 0=PrivateIM / 1=Local / 2=Everyone | | | g_announce_leak | Same scale | | | g_announce_change | Same scale | | | g_notify_wearer | Notify wearer on state change | | | g_touch_enabled | Whether touch opens menus | | | g_access_mode | 0=Open/List / 1=Owner Only | | | g_command_channel | Channel offset for text commands | | | g_safeword_channel | Channel offset for safeword | | | g_safeword | Safeword string | | | g_command_prefix | Text command prefix | | | g_owner_title | Label for owner (e.g. "Caregiver") | | | g_change_limit | Max changes allowed (-1=unlimited) | | | g_change_counter | Remaining changes (-1=unlimited) | | | g_web_interval | Heartbeat interval in seconds (0=off) | | | g_notify_on_wear | IM owners when HUD is worn/logged in | | | g_min_maturity | Minimum region maturity to allow use | | ### Lists | Variable | Contents | Max | |--------------|-------------------------------|-----| | g_whitelist | Allowed third-party UUIDs | 12 | | g_blacklist | Blocked third-party UUIDs | 12 | | g_rlv_owners | UUIDs allowed to use RLV lock | 6 | | g_state_names | Wet state name labels (5) | | | g_mess_names | Mess state name labels (4) | ✓ | --- ## Mess State Values (HappyBumsPlus) | Index | Default Name | |-------|--------------| | 0 | Clean | | 1 | Soiled | | 2 | Messy | | 3 | Blowout | Blowout triggers a special announce mirroring the Leaking announce for wetness. Safeword resets both wetness AND mess to 0. Change lock: either the wet threshold OR the mess threshold being met allows a change. --- ## Access Control Logic 1. Owner always has full access. 2. If `g_access_mode == 1` (Owner Only), no one else can interact. 3. If UUID is on blacklist → denied. 4. If whitelist is non-empty and UUID is not on it → denied. 5. If whitelist is empty → any third party may interact (Open mode). RLV lock/unlock is restricted to UUIDs in `g_rlv_owners`. --- ## Hypergrid Behaviour - Prim descriptions are part of the asset and survive hypergrid travel. - Scripts do not run on foreign grids (expected and acceptable). - On return home, scripts resume with full state intact. - `llLinksetData` is not used anywhere in the system. --- ## Lockout Recovery If touch is disabled and the wearer is locked out of menus: 1. Open the root prim's description in the editor. 2. Change `t=0` to `t=1`. 3. Save and reset scripts. The `t=` field is always written last in the root prim description to make it easy to find and edit manually.