# Packet Types This document describes the currently implemented local prototype packet types for Commonwealth Online. The current protocol is newline-separated JSON over a local TCP connection to `127.0.0.1:7777`. Implemented packet types: - `welcome` - `transform` - `disconnect` The current system is still a local networking prototype. It is not playable multiplayer yet. ## Implemented ### Welcome Packet Sent from the server to a newly connected client after the server assigns a `playerId`. Example: ```json { "type": "welcome", "playerId": 1, "serverTime": 1780212098.457079 } ``` Fields: ```text type Packet type. Always "welcome". playerId Server-assigned player ID for this connection. serverTime Server timestamp when the welcome packet was created. ``` The Fallout 4 plugin and `server/fake_client.py` receive this packet. The plugin stores the assigned `playerId` for filtering its own future transform echoes. ### Transform Packet Sent by the Fallout 4 plugin to the local server when the local player's transform changes. The server adds `playerId` and `serverTime`, then broadcasts the processed packet to other connected clients. Example after server processing: ```json { "type": "transform", "playerId": 2, "x": -81781.26, "y": 87962.61, "z": 7696.05, "angleZ": 3.20, "movementType": "normal", "cellId": "0000DD60", "worldspaceId": "0000003C", "clientTime": 1780212128.301, "isMoving": true, "isSprinting": false, "isSneaking": false, "isJumping": false, "weaponDrawn": false, "movementSpeed": 186.4, "equippedItems": [ { "slot": "body", "formId": "0001F66A" }, { "slot": "headband", "formId": "" }, { "slot": "rightHand", "formId": "0001F4A6" } ], "appearance": { "version": 3, "raceFormId": "00013746", "height": 1.0, "morphWeight": { "thin": 0.0, "muscular": 0.0, "large": 0.0 }, "bodyTintColor": { "r": 255, "g": 220, "b": 190, "a": 255 }, "hairColorFormId": "", "facialHairColorFormId": "", "complexionFormId": "", "headParts": [], "morphs": [], "morphRegions": [], "facialBoneMorphs": [], "tints": [] }, "serverTime": 1780212128.3011043 } ``` Fields: ```text type Packet type. Always "transform". playerId Server-assigned player ID for the sender. x Local player X position. y Local player Y position. z Local player Z position. angleZ Local player Z rotation angle. movementType Movement classification for this transform update. cellId Current cell form ID as a string. worldspaceId Current worldspace form ID as a string. clientTime Timestamp generated by the sending plugin. isMoving Optional movement-state flag; defaults to false when missing. isSprinting Optional movement-state flag; defaults to false when missing. isSneaking Optional movement-state flag; defaults to false when missing. isJumping Optional movement-state flag; defaults to false when missing. weaponDrawn Optional weapon drawn state; defaults to false when missing. movementSpeed Optional derived movement speed in game units per second; defaults to 0.0 when missing. equippedItems Optional full snapshot of tracked visible apparel slots. Each entry has a string `slot` and hex-string `formId`; an empty `formId` means the slot is intentionally unequipped. appearance Optional versioned player appearance snapshot for runtime proxy visuals. serverTime Timestamp added by the server before broadcast. ``` Possible `movementType` values: ```text normal cell_change worldspace_change teleport ``` `cell_change` and `worldspace_change` are currently represented through `movementType` inside transform packets. They are not separate packet types yet. Movement state fields are data-only for now. Receivers must treat them as optional and must not reject older transform packets when they are absent. Equipment fields are optional and additive. When `equippedItems` is missing, receivers keep their existing/default proxy appearance. When present, it is a complete snapshot for the tracked visible apparel slots: ```text hairTop hairLong body underTorso underLeftArm underRightArm underLeftLeg underRightLeg aboveTorso aboveLeftArm aboveRightArm aboveLeftLeg aboveRightLeg headband eyes scalp ``` Tracked slots include 16 visible apparel BIPED slots (listed above) plus: ```text rightHand Right-hand weapon slot (WEAP form ID); optional ``` The equipment-sync milestones send resolved `ARMO` and `WEAP` form IDs and empty strings for unequipped tracked slots. Off-hand weapons, power armor, weapon condition, legendary instance data, tint/material overrides, and forms missing from the receiver load order are outside this packet extension. When `rightHand` is missing, receivers keep their existing proxy weapon. When present with an empty `formId`, the proxy is unequipped. When a `WEAP` form ID is not found locally, receivers log a throttled warning and skip equipping that weapon; the proxy continues with its current state and other sync intact. Appearance fields are optional and additive. When `appearance` is missing, receivers keep the proxy's existing/default body and face. When present, it is a best-effort snapshot for male-proxy-compatible runtime visuals: ```text version Appearance payload version. Current value is 3. raceFormId Hex-string race form ID captured for diagnostics/future use; receivers do not switch proxy race yet. height NPC height scalar. morphWeight Body triangle weights: thin, muscular, and large. bodyTintColor Body tint channels r, g, b, a as 0-255 integers. hairColorFormId Hex-string `CLFM` form ID for hair color, or empty when unavailable. facialHairColorFormId Hex-string `CLFM` form ID for facial hair color, or empty when unavailable. complexionFormId Hex-string `TXST` form ID for skin complexion (hands, arms, body tone), or empty when unavailable. headParts Hex-string `HDPT` form IDs for the sender's current head parts. morphs Morph slider values as `{ "id": hex-string, "value": number }` entries. morphRegions Region morph slider values as a flat array of numbers (added in version 2). facialBoneMorphs Bone-based facial morphs as `{ "id": hex-string, "position": [x,y,z], "rotation": [x,y,z], "scale": [x,y,z] }` entries (added in version 2). tints Character tint layers (skin tone, complexion, makeup, beard shade) as `{ "id": number, "type": number, "value": number, "color": hex-string, "swatch": number }` entries (added in version 3). `id` is the race tint-template uniqueID, `type` is the tint entry type (0 mask, 1 palette, 2 texture), and `value` is the 0-255 intensity. `color` (ARGB hex) and `swatch` are present only for palette entries. ``` `morphRegions` and `facialBoneMorphs` are optional and additive. Version 1 senders omit them; receivers must treat their absence as "no change" and keep existing proxy morph data. `tints` is optional and additive (added in version 3). Earlier senders omit it; receivers must treat its absence as "no change". Receivers apply a tint by matching `id` against an existing proxy tint entry (updating intensity/color in place) and only reconstruct a missing entry when the proxy race exposes a matching tint template, skipping unresolved tints rather than failing. Receivers must treat missing or malformed appearance subfields as non-fatal and apply only the parts they can resolve locally. Gender is intentionally not part of this payload yet; female proxy support can add it later. ### Disconnect Packet Sent by the server to remaining connected clients when a client disconnects. Example: ```json { "type": "disconnect", "playerId": 2, "serverTime": 1780212134.0 } ``` Fields: ```text type Packet type. Always "disconnect". playerId Server-assigned player ID that disconnected. serverTime Server timestamp when the disconnect packet was created. ``` The Fallout 4 plugin and `server/fake_client.py` use this packet to remove remote players from their in-memory state tables. ## Receiver Behavior The Fallout 4 plugin and fake client both receive: ```text welcome transform disconnect ``` The plugin receive loop runs on a background networking thread. It stores plain remote-player state only and does not spawn actors or touch Fallout 4 game objects. ## Planned Later - Remote actor spawning. - Gameplay synchronization.