# OPEN//77 — complete documentation > OPEN//77 is an open, community-run multiplayer platform for Cyberpunk 2077. It is not a single server: it is the client, dedicated server and scripting layer that lets communities host and script their own persistent Night City worlds. This site documents the platform and its Lua API, and hosts the server browser. The project is pre-alpha and unaffiliated with CD PROJEKT RED. Source: https://open2077.net/docs Documentation synced from the platform wiki on 2026-08-21. Status: pre-alpha. There is no public build and no release date. The server listings on the website are labelled demo data, not live servers. Everything below describes software under construction and can change. OPEN//77 is an unofficial, independent community project. It is not affiliated with, endorsed by, or sponsored by CD PROJEKT S.A. “Cyberpunk”, “Cyberpunk 2077” and related marks are trademarks of CD PROJEKT S.A. Game imagery is used for illustration of a fan project. Playing on OPEN//77 will always require your own legal copy of Cyberpunk 2077 — the platform does not accept piracy, and pirated or cracked copies are neither supported nor welcome. --- Source: https://open2077.net/docs # CyberM resource documentation CyberM turns Cyberpunk 2077 into a server-driven multiplayer platform. Gameplay and UI features are packaged as **resources**: self-contained directories with a manifest, Lua scripts, declared permissions, dependencies, and optional web interfaces. Developers familiar with FiveM will recognize the client/server split, events, exports, commands, and manifest-driven lifecycle. CyberM APIs remain independent and reflect REDengine constraints. ## Session model The server selects the resource set for a session. A connecting client downloads that set, verifies its signature and content hashes, and activates it before entering the world. Only CyberM's trusted bootstrap resources load outside the server-provided generation. The server is authoritative. Clients render approved state and submit bounded observations or requests; they do not choose canonical loot, life, vehicle, time, weather, or routing state. ## Create a resource A resource lives below the server's configured resource root and contains a `cyberm.lua` manifest: ```lua resource "hello" version "1.0.0" auto_start true client_script "client/main.lua" server_script "server/main.lua" ``` Client entry point: ```lua AddEventHandler("onClientResourceStart", function(name) if name ~= GetCurrentResourceName() then return end local state = CyberM.character.state() print(("spawned at %.1f, %.1f"):format(state.position.x, state.position.y)) end) ``` Server entry point: ```lua RegisterCommand("hello", function(source, args) print(("player %d said hello"):format(source)) end, false) ``` Start the server, connect a client, and invoke `hello` from the CyberM developer console or chat. ## Guides | Guide | Subject | |---|---| | [Server resources](server-resources.md) | Manifests, runtime separation, signing, download, and reload. | | [Complete server Lua API](server-api.md) | Every server global, `CyberM.*` method, permission, constant, and low-level alias. | | [Official resource exports](resource-exports.md) | Every client export exposed by the official Lua packages and how to call it safely. | | [Game data reference](data-reference.md) | NPC templates, vehicle records, seats, flags, weapons, appearances, VFX, SFX, animations, and sprite catalogues. | | [Identity and ACL](server-acl.md) | Authentication, restricted commands, and access control. | | [Player identity](identity.md) | Durable identifiers, display names, and rename flow. | | [Loot](loot.md) | Authoritative ground drops and pickup integration. | | [Weather](weather.md) | Session time, weather presets, synchronization, and events. | | [Vehicles](vehicles.md) | Identity, streaming, authority leases, seats, and Lua APIs. | | [NPCs](npcs.md) | Implemented server-owned NPCs, templates, streaming, task queues, authority leases, life, events, and Lua APIs. | | [Contextual interactions](interactions.md) | Custom world/NPC prompts, action keys, projection, ownership, and server-safe integration. | | [Notifications](notifications.md) | Reusable WebUI toasts, client/server exports, queues, positions, progress, and ownership. | | [Elevators](elevators.md) | Implemented server-authoritative native lifts, bucket/chunk streaming, late join, ACL commands, and Lua APIs. | | [Blips](blips.md) | Vanilla map markers, entity attachment, and sprites. | | [Visual and audio effects](effects.md) | Resource-owned world/entity VFX and spatialised SFX. | | [Privileged debug runtime](debug-runtime.md) | ACL-targeted client Lua execution, native lab commands, and REDscript bridge probes. | | [Chat](chat.md) | Messages, slash commands, completion, and resource integration. | | [Clipboard](clipboard.md) | Write-only client clipboard API and the `/pos` and `/rot` transform commands. | | [Client persistent KVP](client-kvp.md) | Endpoint- and resource-isolated local key/value persistence, search, atomic operations, and quotas. | ## API reference coverage CyberM has three deliberately separate Lua surfaces. The wiki covers all three without implying that a server method exists in a client VM or that a package export is a native: | Surface | Reference | Coverage | |---|---|---| | Client native runtime | The **CLIENT** API reference cards in `index.html` | 215 registered functions across 37 namespaces; every signature is reviewed and every card has a detailed description. | | Dedicated server runtime | The **SERVER · CyberM.vehicles** cards and [Complete server Lua API](server-api.md) | All 43 authoritative vehicle methods are individually searchable cards; the complete guide covers every server global, `CyberM.*` namespace, constant, permission, and result shape. | | Official client packages | [Official resource exports](resource-exports.md) | Every literal export currently published by the official resource tree: 59 exports across 13 packages. | Generated cards are separated by runtime, so identical names such as `CyberM.vehicles.get` cannot confuse a client projection with server authority. They state whether a call is shared, needs a live game instance, or uses the network backend, and document permissions, ownership, generation lifetime, and failure values. Run both documentation checks after changing a binding or export: ```powershell python wiki/tools/extract-api.py --json python wiki/tools/audit-api.py ``` The generator fails when a registered client function has no verifiable handler body or detailed description. It also compares the 43 server vehicle cards with the real embedded Lua bootstrap, so adding or removing a method cannot silently leave the searchable reference incomplete. ## API conventions ### Engine IDs are opaque REDengine identifiers are 64-bit values and may not be exactly representable as Lua numbers. Store, compare, and return them unchanged. Do not pass them through `tonumber`. ### Failures are values Most APIs return `value` on success or `nil, reason` on failure. Callers can distinguish an invalid request from a temporarily unavailable subsystem without wrapping every call in `pcall`. ### Permissions are explicit Guarded APIs require manifest permissions: ```lua permissions { "network.events", "world.loot" } ``` Request only the capabilities the resource needs. ### Client and server runtimes are separate `server_script` files never reach a player's machine. `client_script` files are distributed in the signed resource set, and `shared_script` files execute in both runtimes. Secrets and authoritative decisions belong exclusively in server code. ## License CyberM-owned documentation and code follow the repository [license](../LICENSE). Third-party names, game data, and dependencies remain subject to their respective terms. --- Source: https://open2077.net/docs/platform # How OPEN//77 works The platform, the architecture, and the creator toolkit — documented in the open as the pre-alpha evolves. Design intent, not shipped software. ## Overview OPEN//77 is an open platform that brings community-run multiplayer servers to Cyberpunk 2077 — the way FiveM opened GTA V. Not one server: an ecosystem of them, each with its own game mode, rules and community. ### OPEN//77 is not - One official multiplayer server run by us - A fixed game mode you have to play - A peer-to-peer co-op session mod - A product of CD PROJEKT RED ### OPEN//77 is - The infrastructure that lets anyone run a Cyberpunk 2077 server - A client that discovers and connects you to community servers - A creator toolkit for building custom game modes and systems - Common ground for players, server owners and developers ## How it works (for players) 1. **Own the game** — OPEN//77 requires your own legal copy of Cyberpunk 2077, at build 2.31, with Phantom Liberty DLC. The platform never distributes game content — it builds on the game you bought. Pirated or cracked copies are not supported and not welcome. 2. **Install the client** — The OPEN//77 client runs alongside your installation. Your single-player game, saves and mods stay untouched. 3. **Browse the servers** — Open the server browser, filter by game mode or language, read a server's page, and pick the world you want to live in tonight. 4. **Connect & play** — The client fetches that server's resource set, verifies its signature and content hashes, and drops you into Night City alongside everyone else on that server. ## Requirements Two of these are stricter than the usual "you need the game" line, so they are worth stating plainly: the client is built against game build 2.31 specifically rather than that version or newer, and Phantom Liberty DLC is required rather than recommended. One more thing is not negotiable: OPEN//77 does not accept piracy. You buy Cyberpunk 2077, or you do not play on it. ### To play - **Your own legal copy of Cyberpunk 2077** — OPEN//77 never distributes the game or any of its assets. It builds on the installation you already own — bought, not pirated. Cracked copies are not supported and not welcome. - **Game build 2.31** — This exact build, not a minimum. The client hooks the game engine at addresses established for it and refuses to load when they do not match. - **Phantom Liberty DLC** — The expansion ships as EP1, and the client needs it: the world it loads when you connect to a server is an EP1 save. - **Windows 10 or 11, 64-bit** — The client is a native Windows plugin that loads inside the game process. ### To host a server Hosting is a different list. A dedicated server is a normal server process and has no relationship with the game at all. - **The game is not needed** — A dedicated server runs independently of Cyberpunk 2077, REDengine and the client plugin. It never loads game content and never needs a copy installed. - **Windows x64 and .NET 10** — The server is a standalone .NET process with a native networking layer. It is the machine you keep online, not the machine you play on. - **Your players still need all of the above** — Everyone who connects needs Cyberpunk 2077 2.31 + Phantom Liberty DLC on their own machine. Hosting changes nothing about that. ## Dedicated servers OPEN//77 is built around real dedicated servers, not peer-to-peer sessions. A server is a persistent process that a community operates — it holds the authoritative state of its world, and players connect to it. - **Persistent worlds** — The world keeps running when you log off. Economies, factions and stories continue — the server remembers. - **Authoritative state** — Positions, inventories, vehicles, loot, time and weather: the server decides what is true, and clients render approved state. That is what makes real economies and fair PvP possible. - **Operated by communities** — Anyone will be able to run the server software — on their own hardware or a rented machine — and set their world's rules, resources and moderation. ## Resources and scripting A server is only as interesting as what runs on it. Gameplay is packaged as resources: self-contained directories with a manifest, Lua scripts, declared permissions, dependencies and optional web interfaces. The server picks the resource set for a session; connecting clients download it, verify its signature and content hashes, and activate it before entering the world. Documented systems: - **Vehicles** (/docs/vehicles) — network identity, streaming, authority leases, seats, doors and damage - **NPCs** (/docs/npcs) — server-owned templates, streaming, task queues and life state - **Loot** (/docs/loot) — authoritative ground drops and validated pickups - **Time and weather** (/docs/weather) — synchronised session time and weather presets - **Elevators** (/docs/elevators) — server-authoritative native lifts with late-join catch-up - **Interactions** (/docs/interactions) — contextual world and NPC prompts with action keys - **Custom UI** (/docs/notifications) — WebUI pages, toasts, blips and map pins - **Identity and ACL** (/docs/server-acl) — durable player ids, whitelists and restricted commands Resource manifest (`resources/hello/cyberm.lua`): ```lua resource "hello" version "1.0.0" auto_start true client_script "client/main.lua" server_script "server/main.lua" permissions { "network.events", "world.loot" } ``` Server entry point (`resources/hello/server/main.lua`): ```lua RegisterCommand("hello", function(source, args) print(("player %d said hello"):format(source)) end, false) ``` That is the real API, not a sketch — every registered function is listed in the Lua API reference at /docs/api, separated by runtime so a client projection is never mistaken for server authority. The surface will still change while the project is in pre-alpha. ## Roadmap OPEN//77 is in pre-alpha. There is no public build, no live server list, and no release date — and we will not invent any. Here is the honest shape of the road. ### NOW (PRE-ALPHA) — Core multiplayer foundations Client/server architecture, session handling, and synchronizing players inside the same world — the unglamorous groundwork everything else depends on. ### NEXT — Dedicated server & resource system The self-hostable server build, the resource format, and automatic resource delivery to connecting clients. ### THEN — Server browser & creator SDK Public server discovery, server pages, and a documented scripting API so the first community worlds can open their doors. ### BEYOND — The ecosystem Featured communities, server reputation, resource sharing between servers — the parts that only matter once real worlds exist. The community will shape these. ## FAQ ### Is OPEN//77 official? Is CD PROJEKT RED involved? No. OPEN//77 is an independent community project. It is not affiliated with, endorsed by, or supported by CD PROJEKT RED. Cyberpunk 2077 is the property of CD PROJEKT S.A. — we build alongside the game, not on their behalf. ### Do I need to own Cyberpunk 2077? Yes, always. OPEN//77 never distributes the game or its assets. You need your own legal copy of Cyberpunk 2077 on 64-bit Windows, at game build 2.31, with Phantom Liberty DLC installed. The platform adds multiplayer infrastructure on top of it. ### Does OPEN//77 work with pirated or cracked copies? No — and it never will, as a matter of principle, not just engineering. This project exists because we love Cyberpunk 2077; buying the game and its expansion is how the studio that made it gets paid, and it is the baseline for being part of this community. Pirated and cracked installations are unsupported, receive no help in any community channel, and server operators are expected to turn them away. If you cannot buy the game yet, wait for a sale — do not pirate it. ### Is Phantom Liberty DLC required, or only recommended? Required. The expansion ships as the EP1 content set, and the world the client loads when you connect to a server is an EP1 save — without the expansion installed there is nothing for it to load. The base game on its own is not enough. ### Do I need Cyberpunk 2077 to host a server? No. A dedicated server runs independently of Cyberpunk 2077, REDengine and the client plugin — it is a standalone .NET process on 64-bit Windows and never loads game content. Everyone who connects to it still needs their own Cyberpunk 2077 2.31 installation with Phantom Liberty DLC. ### So is this one big multiplayer server? No — and this is the core idea. OPEN//77 is the platform underneath many servers. Communities run their own independent worlds with their own game modes and rules; the client lets you browse and join them. If FiveM's model for GTA V is familiar, that is the shape. ### Can I play it right now? Not yet. The project is in pre-alpha and there is no public build. We publish development progress openly rather than promising dates — when a build is ready for testing, it will be announced through the project's channels. ### Will I be able to host my own server? That is the whole design. The dedicated server software will be self-hostable, so you can run your world on your own hardware or a rented machine, moderate it your way, and list it in the public browser. ### What can server creators actually customize? Servers run resources: packages of server-side and client-side Lua with a manifest, declared permissions and optional web interfaces. The documented systems today include vehicles, NPCs, loot, time and weather, elevators, contextual interactions, chat, notifications, blips and visual effects. A pure racing server and a hardcore roleplay city can both be OPEN//77 servers. ### Will it break my single-player game or saves? The client is designed to run alongside your installation without touching your single-player saves or mod setup. Multiplayer state lives on the server you join. ### How much will it cost? OPEN//77 is a community project, not a storefront. The platform itself is intended to be free to play on. Beyond that, honest answer: sustainability decisions come after a working platform, and they will be discussed in the open. --- Source: https://open2077.net/docs/server-resources # Lua resources loaded by the server The server picks the session's resources, builds their client image, and the game downloads them before entering Night City — the same model FiveM uses. The local `red4ext/plugins/CyberM/bootstrap` folder holds only the trusted bootstrap: `cyberm_shell` / `cyberm_pause`, which draw the server browser, the connection flow, and the loading screen. Gameplay resources on the player's disk are never auto-discovered. Use this guide to write a resource, understand what reaches the player, and publish a change to a running session. ## Connection flow 1. The GNS handshake announces a generation, a SHA-256 digest, an Ed25519 key, and an HTTPS URL. 2. The shell shows a full-screen loading WebUI. 3. The client verifies the signed set, the CBOR manifests, each chunk, then each file. 4. The complete generation is committed under `red4ext/plugins/CyberM/cache/server-resources/sets//resources`. 5. Only then does CyberM load the pristine save. 6. The local Lua runtime is replaced by the server's client image. The screen reports `manifest`, `downloading`, `verifying`, `ready`, or `failed`, along with the resource, the byte count, and the number of files. A signature, hash, or path error blocks entry and disconnects the client. ## Writing a resource The resource lives in the folder configured by the server's `resources.root`: ```lua resource "garage" version "1.0.0" auto_start true shared_script "shared/config.lua" server_script "server/main.lua" client_script "client/main.lua" web_ui_page "web/index.html" web_files { "web/**" } files { "assets/blips/*.png", "assets/audio/*.wav" } permissions { "network.events" } ``` The server runs `server_script` and `shared_script`. The downloaded package contains `cyberm.lua`, the `client` and `shared` files, and the declared assets — never the `server/` files. The client and server Lua APIs are documented in the wiki's main reference. The authoritative subsystem for ground items is covered in [loot.md](loot.md). The reference time/weather package and its protocol are covered in [weather.md](weather.md). `files` / `file` declare generic client assets. Globs are expanded by the server, included in the signed resource set, downloaded before Lua starts, and recorded in the client allowlist. Use `web_files` only for files served to that resource's WebUI. For example, `CyberM.assets.texture("assets/blips/job-center.png")` only succeeds when the exact file matched a `files` entry. Empty globs, traversal paths, oversized files, and undeclared texture reads fail the resource instead of falling back to arbitrary disk access. A server script can register a command reachable from the CyberM developer terminal or from the dedicated console: ```lua RegisterCommand("garage.list", function(source, args, rawCommand) -- source = authenticated playerId from the CyberM terminal, 0 from the dedicated console. print("garages: " .. tostring(#args)) end, false) -- true puts the command behind the `command.garage.list` ACL ``` In the in-game terminal, CyberM runs local native commands first. If no local handler matches, the tokenised line is sent reliably to the server under the session's identity. The server never trusts a `source` supplied by the client. Commands are removed automatically along with their VM when a resource stops or reloads. Commands declared with `restricted=true` require the ACL permission `command.`. The `*` permission and namespace wildcards such as `command.garage.*` are accepted. See [server-acl.md](server-acl.md). ## Publishing and reloading With `autoStart=true`, the server notices any valid change. It prepares a new server VM, publishes a new signed set, then sends `ResourceSetChanged` to the players. The client downloads only the missing chunks and switches generation once verification completes. An invalid Lua candidate keeps the previous generation. Useful server commands: ```text resources refresh ensure start stop restart reload ``` Client diagnostic commands: ```text resource.root resource.distribution resource.list resource.status ``` `resource.root` shows `source=bootstrap` before the session and `source=server` once active. `resource.distribution` exposes phase, generation, progress, digest, and current resource. ## Security and operations - HTTPS is mandatory for a public URL; HTTP is limited to loopback. - HTTP redirects and absolute or traversal paths are refused. - The server must keep its signing key file across a migration. - The private key and the `.cyberm` cache must never be committed. - A server resource is code chosen by the operator: only grant sensitive permissions to resources you audit. Minimum configuration: ```json "resources": { "enabled": true, "root": "../resources", "autoStart": true, "download": { "enabled": true, "listenUrl": "http://0.0.0.0:11779", "publicBaseUrl": "https://cdn.example.net/", "cacheDirectory": ".cyberm/resource-cache", "signingKeyFile": ".cyberm/resource-signing-key.json", "chunkSizeBytes": 1048576 } } ``` --- Source: https://open2077.net/docs/identity # Player identity and username CyberM gives every installation a durable cryptographic identity. The username shown in chat, nameplates, presence events, and server scripts belongs to that identity and is verified by the Master. ## Stable id and display name Two identifiers have different jobs: | Value | Lifetime | Use | |---|---|---| | `userId` | Durable | Characters, inventories, bans, ACLs, progression | | `playerId` / `source` | One connection | Addressing the player during the current session | | `displayName` | Editable profile field | Chat and presentation only | Always persist `userId`. A player can rename their profile and receives a new `playerId` after reconnecting. ## Changing the username The server browser shows the current username in its **Identity** field. Pressing **Save** sends a freshly signed enrollment request to the Master. The Master accepts the update only when the private key already attached to the `userId` signed it. Names contain 1 through 32 UTF-8 bytes and cannot contain control characters. A username cannot be changed during an active game session. The private key never leaves the Windows identity store. The request, response, and saved profile contain no reusable password. ## What a game server verifies The Master issues an Ed25519 certificate covering all three public profile values: ```text userId || P-256 public key || displayName ``` During connection, the game server verifies that certificate and a fresh P-256 session proof bound to its challenge. Changing only the name in a modified client invalidates the Master certificate, so the forged name is rejected before the session becomes active. ## Server Lua Server resources receive the verified values through the normal player API: ```lua AddEventHandler("playerJoining", function() local player = source print(GetPlayerIdentifier(player)) -- durable userId print(GetPlayerName(player)) -- Master-verified displayName end) ``` The username-editing Lua bridge is reserved for the trusted local server-browser package. Downloaded server resources cannot rewrite a player's identity. --- Source: https://open2077.net/docs/server-acl # Public identity, server commands, and ACL Server-side Lua commands are typed straight into the CyberM developer terminal in game (`²`). A command the client knows stays local; anything else is forwarded to the server over the authenticated network session, then looked up among the `RegisterCommand` registrations of the Lua resources. Use this guide to whitelist a player, restrict a command to specific people, and understand what identity the server actually trusts. ## Exporting your public identity In the CyberM terminal: ```text identity.dump ``` The reply gives the absolute path and the SHA-256 fingerprint: ```text OK identity_public_dumped path=".../red4ext/plugins/CyberM/exports/identity-.json" fingerprint=sha256:... ``` The file holds the `userId`, the P-256 public key, its fingerprint, and a ready-to-copy `aclPrincipal` object. It never holds the private key, the DPAPI blob, the session proof, or the `%LOCALAPPDATA%/CyberM/identity-v1.dat` file. Do not copy that last one to the server. ## Whitelisting a player The server loads the relative file configured in `server.jsonc`: ```json "accessControl": { "file": "acl.jsonc" } ``` Copy the exported `aclPrincipal` value into `principals`: ```json { "version": 1, "principals": [ { "name": "owner", "userId": "00000000-0000-0000-0000-000000000000", "publicKey": "base64...", "permissions": [ "command.loot.*" ] } ] } ``` Restart the server, or type `acl.reload` in its administration console. `acl.list` reports the path actually loaded; `acl.check ` is there for diagnosis. The comparison is made on the 64 bytes of public key certified during the handshake. If the entry also carries a `userId`, that must match too. The displayed nickname and the temporary `playerId` never take part in authorisation. ## Declaring a restricted command ```lua RegisterCommand("garage.delete", function(source, args, rawCommand) -- source is the playerId of the authenticated session, or 0 for the server console. end, true) ``` From a client, this command requires `command.garage.delete`. An exact permission, `*`, or a trailing wildcard such as `command.garage.*` will grant it. The dedicated console uses `source=0` and stays authorised for local administration. The transport caps a line at 32 tokens and each token at 256 UTF-8 bytes, validates the command name, and reuses the network limit of 32 events per second. Refusals and results come back to the CyberM terminal through `cyberm:command:result`. --- Source: https://open2077.net/docs/server-api # Complete server Lua API This page inventories the Lua surface installed by the dedicated server runtime. These functions exist only in `server_script` and server-side `shared_script` files. The generated client reference documents a different runtime; a function appearing on this page must not be assumed to exist on a client. Prefer the `CyberM.*` names below. FiveM-style globals remain available where listed for familiar resource code and as the low-level implementation surface. ## Runtime, scheduler, events, commands, and JSON | Function | Signature | Result / purpose | |---|---|---| | `CreateThread` | `(function)` | Schedule a coroutine in this resource. | | `GetGameTimer` | `()` | Process-monotonic milliseconds used by the server scheduler. | | `Wait` | `(milliseconds)` | Yield the current managed coroutine; accepted range is 0–86,400,000 ms. | | `SetTimeout` | `(milliseconds, function)` | Schedule a one-shot callback and return its timer ID. | | `ClearTimeout` | `(timerId)` | Cancel a scheduled timeout. | | `AddEventHandler` | `(event, handler)` | Register a local handler and return its ID. | | `RemoveEventHandler` | `(handlerId)` | Remove a local or network handler. | | `TriggerEvent` | `(event, ...)` | Queue a local event in every matching handler of this VM. | | `RegisterNetEvent` | `(event, handler?)` | Register an authenticated client event; requires `network.events`. | | `TriggerClientEvent` | `(event, playerId|-1, ...)` | Send to one session or broadcast; requires `network.events`. | | `RegisterCommand` | `(name, handler, restricted?)` | Register a server/chat command. Restricted commands require ACL `command.`. | | `GetCurrentResourceName` | `()` | Return this manifest's resource name. | | `GetResourceState` | `(resourceName)` | Return the current server resource state. | | `print` | `(...)` | Write a resource-prefixed server log entry. | | `json.encode` | `(value)` | Serialize a bounded Lua value to JSON. | | `json.decode` | `(text)` | Decode JSON into safe Lua values. | Limits are 1,024 scheduled tasks and 2,048 handlers per resource. Network events accept at most 32 arguments in a 48 KiB JSON envelope. During a network handler, global `source` is set from the authenticated connection, never from client payload data. The namespaced equivalents are: | Function | Signature | |---|---| | `CyberM.runtime.luaVersion` | `()` | | `CyberM.time.monotonic` | `()` — monotonic seconds | | `CyberM.resource.name` | `()` | | `CyberM.resource.state` | `(resourceName)` | | `CyberM.events.on` / `off` / `emit` | Same as `AddEventHandler`, `RemoveEventHandler`, `TriggerEvent` | | `CyberM.net.on` / `emitClient` | Same as `RegisterNetEvent`, `TriggerClientEvent` | ## Notifications These methods route to the official `cyberm_notifications` client package. IDs and mutation rights are isolated per calling server resource. | Function | Signature | Result | |---|---|---| | `CyberM.notifications.send` | `(playerId, definition)` | Owner-local notification ID, or `nil, reason`. | | `CyberM.notifications.broadcast` | `(definition)` | Owner-local broadcast ID, or `nil, reason`. | | `CyberM.notifications.update` | `(id, patch)` | `boolean, reason?` | | `CyberM.notifications.dismiss` | `(id)` | `boolean, reason?` | | `CyberM.notifications.clear` | `(playerId?)` | Clear this owner's notifications for one player or everyone. | See [notifications](notifications.md) for every definition field and queue limit. ## Players and authoritative life | Function | Permission | Signature | Result / purpose | |---|---|---|---| | `CyberM.players.name` | None | `(playerId)` | Display name or `nil`. | | `CyberM.players.identifier` | None | `(playerId)` | Durable authenticated identifier or `nil`. | | `CyberM.players.position` | None | `(playerId)` | `{ x, y, z, bucket }` or `nil`. | | `CyberM.players.getLifeState` | `players.life.read` | `(playerId)` | Canonical life snapshot or `nil`. | | `CyberM.players.isDead` | `players.life.read` | `(playerId)` | Whether phase is dead/revive-pending/respawn-pending. | | `CyberM.players.kill` | `players.life.kill` | `(playerId, options?)` | `boolean, reason?` | | `CyberM.players.revive` | `players.life.revive` | `(playerId, options?)` | `boolean, reason?` | | `CyberM.players.respawn` | `players.life.respawn` | `(playerId, options)` | `boolean, reason?` | | `CyberM.players.requestLifeResync` | `players.life.resync` | `(playerId)` | `boolean, reason?` | | `CyberM.players.getHealth` | `players.damage.read` | `(playerId)` | Health/armor/god-mode snapshot or `nil`. | | `CyberM.players.damage` | `players.damage.apply` | `(playerId, amount, options?)` | Apply authoritative damage. | | `CyberM.players.heal` | `players.damage.apply` | `(playerId, amount)` | Apply authoritative healing. | | `CyberM.players.setHealth` | `players.damage.apply` | `(playerId, health)` | Set health; zero passes through life authority. | | `CyberM.players.setMaxHealth` | `players.damage.apply` | `(playerId, maxHealth)` | Update the canonical maximum. | | `CyberM.players.setArmor` | `players.damage.apply` | `(playerId, armor)` | Update canonical armor. | | `CyberM.players.setGodMode` | `players.damage.apply` | `(playerId, enabled)` | Toggle canonical damage immunity. | | `CyberM.players.setRegen` | `players.damage.apply` | `(playerId, pointsPerSecond)` | Set authoritative regeneration. | Life option fields are: - `kill`: `killer`, `cause`, `weapon`, `impulse = { x, y, z }`; - `revive`: `health`, `graceMs`; - `respawn`: required `position = { x, y, z }`, plus `heading`, `bucket`, `health`, `graceMs`; - `damage`: `attacker`, `cause`/`kind`, `weapon`. Low-level aliases are `GetPlayerName`, `GetPlayerIdentifier`, `GetPlayerPosition`, `GetPlayerLifeState`, `IsPlayerDead`, `KillPlayer`, `RevivePlayer`, `RespawnPlayer`, `RequestPlayerLifeResync`, `GetPlayerHealth`, `DamagePlayer`, `HealPlayer`, `SetPlayerHealth`, `SetPlayerMaxHealth`, `SetPlayerArmor`, `SetPlayerGodMode`, and `SetPlayerRegen`. Prefer the namespaced wrappers because they accept structured option tables. ## Combat policy All combat policy functions require `combat.config`. | Function | Signature | Purpose | |---|---|---| | `CyberM.combat.onDamage` | `(handler)` | Add a synchronous damage arbiter and return it. `false` cancels; a number rewrites damage. | | `CyberM.combat.offDamage` | `(handler)` | Remove a previously installed arbiter. | | `CyberM.combat.setFriendlyFire` | `(enabled)` | Enable or disable damage between teammates. | | `CyberM.combat.setTeam` | `(playerId, teamId)` | Assign a non-negative team. | | `CyberM.combat.setDamageMultiplier` | `(multiplier)` | Set global multiplier, range 0–100. | | `CyberM.combat.setHeadshotMultiplier` | `(multiplier)` | Set headshot multiplier, range 0–100. | | `CyberM.combat.setWeaponDamageMultiplier` | `(weaponTdbId, multiplier)` | Override one weapon, range 0–100. | | `CyberM.combat.setKindDamageMultiplier` | `(ranged|melee|explosion, multiplier)` | Override one attack kind. | Low-level aliases are `SetCombatFriendlyFire`, `SetCombatTeam`, `SetCombatDamageMultiplier`, `SetCombatHeadshotMultiplier`, `SetCombatWeaponMultiplier`, and `SetCombatKindMultiplier`. ## Routing buckets | Function | Signature | Result / purpose | |---|---|---| | `CyberM.routingBuckets.getPlayer` | `(playerId)` | Player bucket, default `0`. | | `CyberM.routingBuckets.setPlayer` | `(playerId, bucket)` | `boolean`; moves authoritative visibility scope. | | `CyberM.routingBuckets.getEntity` | `(entityId)` | Entity bucket, default `0`. | | `CyberM.routingBuckets.setEntity` | `(entityId, bucket)` | `boolean`. | | `CyberM.routingBuckets.setLockdownMode` | `(bucket, mode)` | Mode: `inactive`, `relaxed`, `strict`, or `full`. | | `CyberM.routingBuckets.setPopulationEnabled` | `(bucket, enabled)` | Toggle ambient population policy for the bucket. | The corresponding globals are `GetPlayerRoutingBucket`, `SetPlayerRoutingBucket`, `GetEntityRoutingBucket`, `SetEntityRoutingBucket`, `SetRoutingBucketEntityLockdownMode`, and `SetRoutingBucketPopulationEnabled`. ## Ground loot Every method requires `world.loot`. Drops are authoritative and owned by their creating resource. | Function | Signature | Result | |---|---|---| | `CyberM.loot.create` | `(definition)` | CyberM loot ID, or `nil, reason`. | | `CyberM.loot.update` | `(id, patch)` | `boolean` | | `CyberM.loot.remove` | `(id)` | `boolean` | | `CyberM.loot.get` | `(id)` | Drop snapshot or `nil`. | | `CyberM.loot.all` | `(bucket?)` | Array of drop snapshots. | Definitions accept `item`, `quantity`, `position`, `bucket`, `radius`, `label`, `visualItem`/`model`, and `ttlMs`. Low-level aliases are `CreateLootDrop`, `UpdateLootDrop`, `RemoveLootDrop`, `GetLootDrop`, and `GetLootDrops`. See [loot](loot.md) for pickup validation and client projection. ## Vehicles Every method in this section requires `world.vehicles`. IDs are server-assigned CyberM IDs; do not substitute REDengine entity pointers or local spawn handles. The [vehicle guide](vehicles.md#complete-lua-api-inventory) lists all 43 server methods individually, the six client methods, the two package exports, exact snapshot fields, bit indexes, and examples. ### Lifecycle and state | Function | Signature | Purpose | |---|---|---| | `CyberM.vehicles.create` | `(definition)` | Create and return an authoritative vehicle ID. | | `CyberM.vehicles.update` | `(id, patch)` | Patch health, flags, colours, doors, windows, tires, body, glass, and lights. | | `CyberM.vehicles.get` | `(id)` | Full canonical vehicle snapshot or `nil`. | | `CyberM.vehicles.all` | `(bucket?)` | All canonical vehicles, optionally filtered by bucket. | | `CyberM.vehicles.setTransform` | `(id, transform)` | Set authoritative position and yaw. | | `CyberM.vehicles.remove` | `(id)` | Remove the authoritative vehicle. | | `CyberM.vehicles.getDamage` | `(id)` | `{ body, glass, lights, tires }` or `nil`. | | `CyberM.vehicles.setDamage` | `(id, damage)` | Replace combined damage fields. | | `CyberM.vehicles.repair` | `(id, scope?)` | Scope: `glass`, `body`, `lights`, `tires`, `visual`, `mechanical`, or `full`. | `create` accepts `record`, `position`, `yaw`, `bucket`, `appearance`, `health`, `flags`, `primaryColor`, `secondaryColor`, and the same initial damage/opening fields accepted by `update`. ### Body, glass, lights, and tires | Function | Signature | Purpose | |---|---|---| | `setBodyDamage` | `(id, values[30])` | Replace all normalized body cells. | | `setBodyCell` / `damageBodyCell` / `repairBodyCell` | `(id, cell, value?)` | Set, add to, or clear cell 1–30. | | `setBodyZone` / `damageBodyZone` / `repairBodyZone` | `(id, zone, value?)` | Mutate a named/profile zone or explicit cell array. | | `setGlassMask` | `(id, mask)` | Replace the 32-bit broken-glass mask. | | `setGlassBroken` | `(id, glass, broken)` | Mutate one numeric or profile-named pane. | | `breakGlass` / `repairGlass` | `(id, glass)` | Convenience pane mutation. | | `breakAllGlass` / `repairAllGlass` | `(id, count?)` / `(id)` | Break the first 0–32 panes or clear the mask. | | `setLightMask` | `(id, mask)` | Replace broken-light mask. | | `setLightBroken` | `(id, index, broken)` | Mutate one light bit. | | `breakLight` / `repairLight` / `repairAllLights` | `(id, index?)` | Light convenience methods. | | `setTireMask` | `(id, mask)` | Replace four-wheel broken-tire mask. | | `setTireBroken` | `(id, index, broken)` | Mutate tire index 0–3. | | `breakTire` / `repairTire` / `repairAllTires` | `(id, index?)` | Tire convenience methods. | | `registerDamageProfile` | `(record, profile)` | Register record-specific glass names and body zones in this VM. | | `getDamageProfile` | `(record)` | Return this resource's registered profile or `nil`. | Default `CyberM.vehicles.bodyZones` are `backLeft`, `back`, `backRight`, `left`, `center`, `right`, `frontLeft`, `front`, `frontRight`, `lower`, `roof`, and `all`. ### Doors and windows | Function | Signature | Purpose | |---|---|---| | `setDoorMask` | `(id, mask)` | Replace the six-bit opening mask. | | `setDoorOpen` | `(id, door, opened)` | Set one opening. | | `openDoor` / `closeDoor` | `(id, door)` | Convenience mutation. | | `isDoorOpen` | `(id, door)` | Boolean or `nil` for unknown vehicle. | | `setWindowOpen` | `(id, window, opened)` | Set one window opening. | | `openWindow` / `closeWindow` | `(id, window)` | Convenience mutation. | | `isWindowOpen` | `(id, window)` | Boolean or `nil` for unknown vehicle. | Door names are `frontLeft`, `frontRight`, `backLeft`, `backRight`, `trunk`, and `hood`; windows use the four side names. Constants live in `CyberM.vehicles.doors` and `.windows`. State flags live in `.flags`: `engineOn`, `locked`, `destroyed`, `exploded`, `invulnerable`, `immortal`, `lightsOn`, `highBeams`, and `sirenOn`. Low-level aliases are `CreateVehicle`, `UpdateVehicleState`, `SetVehicleTransform`, `RemoveVehicle`, `GetVehicle`, and `GetVehicles`. The namespaced API supplies validation and damage helpers and is the recommended surface. See [vehicles](vehicles.md) for snapshots, streaming, authority and seats. ## NPCs and tasks All methods require `world.npcs`. ### NPC lifecycle and state | Function | Signature | Purpose | |---|---|---| | `CyberM.npcs.create` | `(definition)` | Create an authoritative NPC and return its ID. | | `CyberM.npcs.update` | `(id, patch)` | Patch appearance, loadout, AI mode, damage policy, health, or ragdoll. | | `CyberM.npcs.setTransform` | `(id, transform)` | Set canonical position and yaw. | | `CyberM.npcs.setBucket` | `(id, bucket)` | Move NPC visibility scope. | | `CyberM.npcs.setAppearance` | `(id, appearance)` | Appearance convenience patch. | | `CyberM.npcs.setLoadout` | `(id, loadout)` | Loadout convenience patch. | | `CyberM.npcs.setHealth` | `(id, health, maxHealth?)` | Health convenience patch. | | `CyberM.npcs.setDamagePolicy` | `(id, policy)` | Set mortal/immortal/invulnerable policy. | | `CyberM.npcs.setAiMode` | `(id, mode)` | Set tasks/frozen/native mode. | | `CyberM.npcs.setRagdoll` | `(id, enabled)` | Set canonical ragdoll state. | | `CyberM.npcs.kill` / `revive` / `applyDamage` | `(id, ...)` | Authoritative life mutations. | | `CyberM.npcs.remove` | `(id)` | Remove the NPC. | | `CyberM.npcs.get` / `all` | `(id)` / `(bucket?)` | One snapshot or an array. | | `CyberM.npcs.templates` | `()` | Complete curated template catalogue. | Definition fields include `template`, `position`, `yaw`, `bucket`, `appearance`, `loadout`, `aiMode`, `damagePolicy`, `health`, `maxHealth`, `streamingRadius`, `streamingHysteresis`, `despawnWhenUnobserved`, and `persistent`. Constants are `CyberM.npcs.flags`, `.ai`, `.damage`, and `.channels`. ### Task queue | Function | Signature | Purpose | |---|---|---| | `CyberM.npcs.tasks.enqueue` | `(id, type, parameters?, options?)` | Enqueue any supported task. | | `cancel` | `(id, taskId)` | Cancel one task. | | `clear` | `(id, channel?)` | Clear queued/current tasks. | | `get` | `(id, taskId)` | Read one task. | | `all` | `(id)` | List tasks for an NPC. | | `moveTo` | `(id, position, options?)` | Move with speed, acceptance radius, priority, and timeout. | | `follow` | `(id, target, options?)` | Follow a player, NPC, or position. | | `patrol` | `(id, points, options?)` | Patrol with loop/back-and-forth options. | | `wander` | `(id, options?)` | Wander using the supplied movement parameters. | | `face` | `(id, position, options?)` | Rotate toward a world point. | | `lookAt` | `(id, target, options?)` | Drive the look channel toward player/NPC/position. | | `wait` | `(id, durationMs, options?)` | Timed action-channel wait. | | `hold` | `(id, options?)` | Hold movement indefinitely or until timeout/cancel. | | `playAnimation` | `(id, animation, options?)` | Run a full-body animation task. | Low-level aliases are `CreateNpc`, `UpdateNpc`, `SetNpcTransform`, `SetNpcBucket`, `RemoveNpc`, `GetNpc`, `GetNpcs`, `EnqueueNpcTask`, `CancelNpcTask`, `ClearNpcTasks`, `GetNpcTask`, `GetNpcTasks`, `KillNpc`, `ReviveNpc`, `DamageNpc`, and `GetNpcTemplates`. See [NPCs](npcs.md) for the task state machine, ownership, streaming, templates, and events. ## Elevators All methods require `world.elevators`. | Function | Signature | Purpose | |---|---|---| | `CyberM.elevators.adopt` | `(definition)` | Adopt a native lift and return a CyberM elevator ID. | | `goTo` / `call` | `(id, floor, options?)` | Start authoritative travel; options include `travelMs` and `force`. | | `teleport` | `(id, floor)` | Administrative recovery without travel. | | `pause` / `resume` | `(id)` | Pause or continue authoritative movement. | | `setFlags` | `(id, flags)` | Update power, lock, interaction, and door policy. | | `remove` | `(id)` | Release the managed elevator. | | `get` / `all` | `(id)` / `(bucket?)` | Read canonical snapshots. | `adopt` accepts `engineEntity`, `position`, `bucket`, `initialFloor`, `flags`, and required `floorCount`. Constants are in `CyberM.elevators.flags`. Low-level aliases are `AdoptElevator`, `GoToElevator`, `TeleportElevator`, `PauseElevator`, `ResumeElevator`, `SetElevatorFlags`, `RemoveElevator`, `GetElevator`, and `GetElevators`. See [elevators](elevators.md). ## Database Database access requires `database.access`. `CyberM.database` and `MySQL` refer to the same oxmysql-compatible table. | Method | Callback form | Await form | |---|---|---| | `query` / `prepare` | `(sql, params?, callback?)` | `.await(sql, params?)` returns rows. | | `single` | `(sql, params?, callback?)` | `.await` returns one row or `nil`. | | `scalar` | `(sql, params?, callback?)` | `.await` returns one scalar. | | `insert` | `(sql, params?, callback?)` | `.await` returns inserted ID/result. | | `update` / `rawExecute` | `(sql, params?, callback?)` | `.await` returns affected-row result. | | `transaction` | `(statements, callback?)` | `.await(statements)` returns `true` or `false, reason`. | Callbacks and `.await` continuations resume on the owning resource's scheduler, never on the database worker. See the database guide in `docs/database.md` for parameter forms, limits, transactions, configuration, and migrations. ## Logging `CyberM.log.debug`, `.info`, `.warn`, and `.error` currently forward their arguments to the resource-prefixed server logger. Their common signature is `(...)`; no return value is produced. ## Permission summary | Capability | Server namespaces | |---|---| | `network.events` | `CyberM.net`, `RegisterNetEvent`, `TriggerClientEvent` | | `world.loot` | `CyberM.loot` | | `world.vehicles` | `CyberM.vehicles` | | `world.npcs` | `CyberM.npcs` | | `world.elevators` | `CyberM.elevators` | | `players.life.read` | Player life reads | | `players.life.kill` | `CyberM.players.kill` | | `players.life.revive` | `CyberM.players.revive` | | `players.life.respawn` | `CyberM.players.respawn` | | `players.life.resync` | `CyberM.players.requestLifeResync` | | `players.damage.read` | `CyberM.players.getHealth` | | `players.damage.apply` | Player health/damage mutations | | `combat.config` | `CyberM.combat` and damage arbiters | | `database.access` | `CyberM.database` / `MySQL` | Request only the capabilities a resource actually uses. A manifest permission grants access to a binding; it does not replace validation of player identity, distance, ownership, revision, bucket, or gameplay state. ## Audit status This page covers every public global installed by `LuaResourceRuntime.Sandbox`, including all 69 low-level bindings, and every namespaced helper and constant installed by the server bootstrap. `wiki/tools/audit-api.py` compares public globals with this page and fails when a new binding is not documented. The higher-level tables are kept beside their validation and permission rules above so their authoritative semantics remain explicit instead of being confused with the client runtime. --- Source: https://open2077.net/docs/resource-exports # Official resource exports CyberM's native Lua API and resource exports are two separate surfaces. Native methods such as `CyberM.vehicles.get` are registered by the client or server runtime. The exports below are owned by official Lua resources and add lifecycle isolation, WebUI ownership, or higher-level behavior. All exports on this page are **client exports**. Server-authoritative mutation remains in server scripts through the [server Lua API](server-api.md), net events, or a package's documented server interface. ## Calling an export The portable cross-resource form is asynchronous: ```lua local promise, reason = CyberM.exports.call("cyberm_notifications", "show", { type = "success", title = "Garage", message = "Vehicle stored." }) if not promise then error(reason) end local result = promise:await() if not result.ok then print(result.error) end ``` The FiveM-style proxy is also available in a client resource: ```lua exports.cyberm_chat:addMessage({ author = "SYSTEM", message = "Ready" }) ``` Handles returned by UI packages are resource-owned. Another resource cannot update or dismiss them, and they are cleaned automatically when the owning generation stops or reloads. ## Export catalogue ### `cyberm_appearance` | Export | Signature | Result | |---|---|---| | `open` | `open(mode?)` | Requests the server-authorized appearance workflow. | | `capture` | `capture()` | Current native appearance snapshot. | | `isOpen` | `isOpen()` | Whether the appearance UI is active. | | `revision` | `revision()` | Last canonical appearance revision. | | `characterKey` | `characterKey()` | Durable character key associated with the synchronized appearance. | See the package README at `resources/cyberm_appearance/README.md` for the transaction lifecycle. ### `cyberm_chat` | Export | Signature | Result | |---|---|---| | `addMessage` | `addMessage(message)` | Adds one structured message to the local chat UI. | | `clear` | `clear()` | Clears visible messages. | | `addSuggestion` | `addSuggestion(command, help, parameters?)` | Adds or replaces slash-command completion metadata. | | `removeSuggestion` | `removeSuggestion(command)` | Removes one completion entry. | | `setEnabled` | `setEnabled(enabled)` | Enables/disables chat for the calling resource context. | | `isEnabled` | `isEnabled()` | Returns the current enable state. | Message and suggestion schemas are documented in [Chat](chat.md). ### `cyberm_death` | Export | Signature | Result | |---|---|---| | `isDead` | `isDead(playerId?)` | Canonical death state for the local or selected player. | | `getState` | `getState(playerId?)` | Canonical life-state snapshot. | | `getLocalDeathContext` | `getLocalDeathContext()` | Local death context, with the last package snapshot as fallback. | | `all` | `all()` | All currently known player life states. | ### `cyberm_effects` | Export | Signature | Result | |---|---|---| | `playVfx` | `playVfx(effect, options?)` | Starts a world VFX owned by the caller. | | `playEntityVfx` | `playEntityVfx(effect, options?)` | Starts an entity-attached VFX. | | `playSfx` | `playSfx(event, options?)` | Starts an SFX event, optionally spatialized or attached. | | `stop` | `stop(handle)` | Stops a caller-owned effect handle. | | `catalog` | `catalog()` | Returns the runtime effect catalogue. | See [Visual and audio effects](effects.md) and [Game data reference](data-reference.md). ### `cyberm_elevators` | Export | Signature | Result | |---|---|---| | `get` | `get(id)` | One streamed authoritative elevator snapshot. | | `all` | `all()` | All streamed elevator snapshots. | | `requestFloor` | `requestFloor(id, floor)` | Requests a `goto` action. | | `requestCall` | `requestCall(id, floor)` | Requests a `call` action. | See [Elevators](elevators.md). Elevator IDs are opaque even though this compatibility package currently normalizes them before calling the native API. ### `cyberm_interactions` | Export | Signature | Result | |---|---|---| | `create` | `create(definition)` | Creates a caller-owned contextual interaction and returns its handle. | | `update` | `update(handle, patch)` | Applies a partial update. | | `remove` | `remove(handle)` | Removes one caller-owned interaction. | | `setVisible` | `setVisible(handle, visible)` | Convenience visibility update. | | `get` | `get(handle)` | Snapshot of one caller-owned interaction. | | `all` | `all()` | Snapshots of every interaction owned by the caller. | | `clear` | `clear()` | Removes all caller-owned interactions. | | `setEnabled` | `setEnabled(enabled)` | Enables/disables rendering and input for the caller. | | `isEnabled` | `isEnabled()` | Returns the caller enable state. | Definitions, marker types, choices, distances, entity attachment, and responses are documented in [Contextual interactions](interactions.md). ### `cyberm_loot` | Export | Signature | Result | |---|---|---| | `get` | `get(id)` | One streamed canonical loot drop. | | `all` | `all()` | Copy of all streamed drops. | | `requestPickup` | `requestPickup(id)` | Submits a bounded pickup request to the server. | See [Loot](loot.md). Clients cannot create or award authoritative loot. ### `cyberm_markers` | Export | Signature | Result | |---|---|---| | `create` | `create(definition)` | Creates a native marker and returns its ID. | | `update` | `update(id, patch)` | Updates mutable marker fields. | | `remove` | `remove(id)` | Removes one marker. | | `clear` | `clear()` | Removes resource-owned markers. | | `list` | `list()` | Lists current resource-owned markers. | The lower-level method schema is in the generated `CyberM.markers.*` reference. ### `cyberm_nameplates` | Export | Signature | Result | |---|---|---| | `setEnabled` | `setEnabled(enabled)` | Enables/disables caller-owned overrides. | | `isEnabled` | `isEnabled()` | Current enable state. | | `set` | `set(playerId, options)` | Sets a nameplate override for one player. | | `remove` | `remove(playerId)` | Removes one override. | | `clear` | `clear()` | Removes every caller-owned override. | ### `cyberm_notifications` | Export | Signature | Result | |---|---|---| | `show` | `show(definition)` | Displays a caller-owned notification and returns its handle. | | `update` | `update(handle, patch)` | Updates a visible or queued notification. | | `dismiss` | `dismiss(handle)` | Dismisses one caller-owned notification. | | `clear` | `clear()` | Dismisses every caller-owned notification. | | `list` | `list()` | Snapshots of caller-owned notifications. | | `setEnabled` | `setEnabled(enabled)` | Enables/disables notifications for the caller. Disabling also clears them. | | `isEnabled` | `isEnabled()` | Returns the caller enable state. | See [Notifications](notifications.md) for types, positions, duration, progress, actions, replacement, and the server-to-client envelope. ### `cyberm_vehicles` | Export | Signature | Result | |---|---|---| | `get` | `get(id)` | One streamed canonical vehicle snapshot. | | `all` | `all()` | All streamed canonical vehicle snapshots. | See [Vehicles](vehicles.md) for server mutation and native presentation methods. ### `cyberm_weather` | Export | Signature | Result | |---|---|---| | `isReady` | `isReady()` | Whether the first authoritative environment snapshot arrived. | | `requestSync` | `requestSync()` | Requests an immediate resynchronization. | | `getState` | `getState()` | Projected server time and canonical weather state. | See [Weather](weather.md). This package intentionally exposes no client mutation command. ### `cyberm_example` | Export | Signature | Result | |---|---|---| | `hello` | `hello(name?)` | Minimal export example used by the starter package. | This export is instructional and should not be used as a production dependency. ## Audit status This catalogue is generated from every literal `exports("name", ...)` declaration under the official `resources/` tree. It currently covers **59 exports across 13 packages**. Dynamic exports are intentionally discouraged because they cannot be audited or completed reliably by tooling. --- Source: https://open2077.net/docs/vehicles # Network vehicles CyberM vehicles are server entities. A server resource creates a vehicle, owns its durable state, and removes it. Clients only stream a REDengine projection around their player. ## Manifest ```lua permissions { "world.vehicles", "vehicles.read", "vehicles.presentation" } ``` `world.vehicles` is a server permission. `vehicles.read` exposes the read-only client projection. `vehicles.presentation` is optional and permits a client resource to select the visual entry path for an occupant whose exact player, vehicle, and seat were already validated by the server. ## Complete Lua API inventory The vehicle surface is intentionally asymmetric: | Runtime | Surface | Count | Mutation | |---|---|---:|---| | Server | `CyberM.vehicles.*` | 43 methods | Authoritative lifecycle, state, damage, openings, paint, and transform. | | Client | `CyberM.vehicles.*` | 6 methods | Read-only state plus guarded remote-occupant presentation. | | Client package | `cyberm_vehicles` exports | 2 exports | Read-only compatibility wrappers. | | Server low level | FiveM-style globals | 6 functions | Raw implementation surface; prefer `CyberM.vehicles.*`. | There is deliberately no client API for breaking or repairing glass, tyres, lights, or bodywork. A client observes native damage and sends a bounded witness report; the server merges destructive state monotonically. Scripted mutation uses the server methods below. ### All server lifecycle and state methods Every method in this table requires `world.vehicles`. | Method | Signature | Return / behavior | |---|---|---| | `CyberM.vehicles.create` | `(definition)` | Vehicle ID, or `nil, reason`. | | `CyberM.vehicles.update` | `(id, patch)` | `boolean`; replaces supplied canonical fields. | | `CyberM.vehicles.get` | `(id)` | Server snapshot or `nil`. | | `CyberM.vehicles.all` | `(bucket?)` | Array of server snapshots, ordered by ID. | | `CyberM.vehicles.remove` | `(id)` | `boolean`; only the creating resource can remove it. | | `CyberM.vehicles.setTransform` | `(id, transform)` | `boolean`; position plus yaw, revoking any active physics lease. | | `CyberM.vehicles.getDamage` | `(id)` | `{ body, glass, lights, tires }`, or `nil`. | | `CyberM.vehicles.setDamage` | `(id, damage)` | `boolean`; combined damage update. | | `CyberM.vehicles.repair` | `(id, scope?)` | `boolean`; scope is `glass`, `body`, `lights`, `tires`, `visual`, `mechanical`, or `full`. | | `CyberM.vehicles.registerDamageProfile` | `(record, profile)` | `true`; registers names inside the calling resource VM. | | `CyberM.vehicles.getDamageProfile` | `(record)` | This resource's profile or `nil`. | ### All server body-damage methods Body cells use Lua indexes **1..30** and normalized finite values **0..1**. | Method | Signature | Return / behavior | |---|---|---| | `CyberM.vehicles.setBodyDamage` | `(id, values)` | Replaces the exact 30-value grid. | | `CyberM.vehicles.setBodyCell` | `(id, cell, value)` | Sets one normalized cell. | | `CyberM.vehicles.damageBodyCell` | `(id, cell, amount)` | Adds damage and clamps the result to 0..1. | | `CyberM.vehicles.repairBodyCell` | `(id, cell)` | Sets one cell to zero. | | `CyberM.vehicles.setBodyZone` | `(id, zone, value)` | Sets every cell in a named zone or explicit index array. | | `CyberM.vehicles.damageBodyZone` | `(id, zone, amount)` | Adds and clamps damage across a zone. | | `CyberM.vehicles.repairBodyZone` | `(id, zone)` | Clears a zone. | `CyberM.vehicles.bodyZones` contains `backLeft`, `back`, `backRight`, `left`, `center`, `right`, `frontLeft`, `front`, `frontRight`, `lower`, `roof`, and `all`. A damage profile can override or extend the zone map for one vehicle record. ### All server glass, light, and tyre methods Glass and light indexes are **0..31**. Tyre indexes are **0..3**. Glass ordering comes from the specific vehicle record's `Destruction.Glass` list; it is not equivalent to the four openable side-window indexes. | Method | Signature | Return / behavior | |---|---|---| | `CyberM.vehicles.setGlassMask` | `(id, mask)` | Replaces the 32-bit broken-glass mask. | | `CyberM.vehicles.setGlassBroken` | `(id, glass, broken)` | Sets one numeric or profile-named glass bit. | | `CyberM.vehicles.breakGlass` | `(id, glass)` | Sets one glass bit. | | `CyberM.vehicles.repairGlass` | `(id, glass)` | Clears one glass bit. | | `CyberM.vehicles.breakAllGlass` | `(id, count?)` | Breaks the first `count` bits; default is all 32. | | `CyberM.vehicles.repairAllGlass` | `(id)` | Clears the entire glass mask. | | `CyberM.vehicles.setLightMask` | `(id, mask)` | Replaces the 32-bit broken-light mask. | | `CyberM.vehicles.setLightBroken` | `(id, index, broken)` | Sets or clears one light bit. | | `CyberM.vehicles.breakLight` | `(id, index)` | Sets one light bit. | | `CyberM.vehicles.repairLight` | `(id, index)` | Clears one light bit. | | `CyberM.vehicles.repairAllLights` | `(id)` | Clears the complete light mask. | | `CyberM.vehicles.setTireMask` | `(id, mask)` | Replaces the four-bit broken-tyre mask. | | `CyberM.vehicles.setTireBroken` | `(id, index, broken)` | Sets or clears one tyre bit. | | `CyberM.vehicles.breakTire` | `(id, index)` | Sets one tyre bit. | | `CyberM.vehicles.repairTire` | `(id, index)` | Clears one tyre bit. | | `CyberM.vehicles.repairAllTires` | `(id)` | Clears the complete tyre mask. | ### All server door and openable-window methods Doors are a six-bit reversible state. Openable windows are a separate four-bit reversible state; neither mask represents broken glass. | Method | Signature | Return / behavior | |---|---|---| | `CyberM.vehicles.setDoorMask` | `(id, mask)` | Replaces the door/trunk/hood mask; range 0..63. | | `CyberM.vehicles.setDoorOpen` | `(id, door, opened)` | Sets one opening bit. | | `CyberM.vehicles.openDoor` | `(id, door)` | Opens one door, trunk, or hood. | | `CyberM.vehicles.closeDoor` | `(id, door)` | Closes one door, trunk, or hood. | | `CyberM.vehicles.isDoorOpen` | `(id, door)` | `boolean`, or `nil` for an unknown vehicle. | | `CyberM.vehicles.setWindowOpen` | `(id, window, opened)` | Sets one side-window opening bit. | | `CyberM.vehicles.openWindow` | `(id, window)` | Opens one side window. | | `CyberM.vehicles.closeWindow` | `(id, window)` | Closes one side window. | | `CyberM.vehicles.isWindowOpen` | `(id, window)` | `boolean`, or `nil` for an unknown vehicle. | The remaining `CyberM.vehicles.update` fields are `health`, `flags`, `primaryColor`, `secondaryColor`, `doors`, `windows`, `tires`, `bodyDamage`, `brokenGlass`, and `brokenLights`. ### Exact client methods | Method | Permission | Signature | Return / behavior | |---|---|---|---| | `CyberM.vehicles.get` | `vehicles.read` | `(id)` | One streamed client snapshot or `nil`. | | `CyberM.vehicles.all` | `vehicles.read` | `()` | All currently streamed snapshots; empty when unavailable or denied. | | `CyberM.vehicles.isDoorOpen` | `vehicles.read` | `(id, door)` | Reads the canonical six-bit door state. | | `CyberM.vehicles.isWindowOpen` | `vehicles.read` | `(id, window)` | Reads the canonical four-bit opening state, not broken glass. | | `CyberM.vehicles.warpPlayerIntoVehicle` | `vehicles.presentation` | `(playerId, vehicleId, seat)` | Instantly presents an already-authorized remote occupant. | | `CyberM.vehicles.taskPlayerEnterVehicle` | `vehicles.presentation` | `(playerId, vehicleId, seat)` | Reserved animated path; currently fails closed with `animated_entry_unsupported`. | Client constants are `CyberM.vehicles.doors`, `CyberM.vehicles.windows`, and `CyberM.vehicles.seats`. They are tables, not callable methods. ### Official package exports The `cyberm_vehicles` client package exposes only: | Export | Signature | Result | |---|---|---| | `get` | `get(id)` | Compatibility wrapper over `CyberM.vehicles.get`. | | `all` | `all()` | Compatibility wrapper over `CyberM.vehicles.all`. | Call them with `CyberM.exports.call("cyberm_vehicles", "get", id)` or the FiveM-style export proxy. The package intentionally exposes no mutation export. ### Low-level server globals These six globals are public for framework compatibility, but the namespaced API above supplies structured tables, defaults, and helper validation. | Global | Signature | |---|---| | `CreateVehicle` | `(record, x, y, z, yaw, bucket, appearance, health, flags, primaryR, primaryG, primaryB, secondaryR, secondaryG, secondaryB)` | | `UpdateVehicleState` | `(id, health, flags, primaryR, primaryG, primaryB, secondaryR, secondaryG, secondaryB, doors, windows, tires, bodyDamage30, brokenGlass, brokenLights)` | | `SetVehicleTransform` | `(id, x, y, z, yaw)` | | `RemoveVehicle` | `(id)` | | `GetVehicle` | `(id)` | | `GetVehicles` | `(bucket?)` | ## Server API ```lua local id, reason = CyberM.vehicles.create({ record = "Vehicle.v_standard2_archer_hella_player", appearance = "default", position = { x = -1607.4, y = 1268.2, z = 18.1 }, yaw = 90.0, bucket = 0, health = 1.0, flags = CyberM.vehicles.flags.locked, primaryColor = { r = 22, g = 105, b = 180 }, secondaryColor = { r = 8, g = 15, b = 24 }, }) ``` ### `CyberM.vehicles.create(definition)` Creates a generation-checked 64-bit vehicle id. Required fields are `record` and `position`. Optional fields are `appearance`, `yaw`, `bucket`, `health`, `flags`, `primaryColor`, and `secondaryColor`. Returns `id`, or `nil, reason`. ### `CyberM.vehicles.update(id, patch)` Updates durable state. Supported fields are `health`, `flags`, `primaryColor`, `secondaryColor`, `doors`, `windows`, `tires`, `bodyDamage`, `brokenGlass`, `brokenLights`, and the nested `damage = { body, glass, lights, tires }` form. `windows` means opened windows; it is deliberately separate from `brokenGlass`. Door bits are front-left, front-right, back-left, back-right, trunk, and hood. Window/tire bits use the first four positions. ```lua local flags = CyberM.vehicles.flags.engineOn | CyberM.vehicles.flags.lightsOn CyberM.vehicles.update(id, { flags = flags, health = 0.85 }) ``` Available flags: | Constant | Value | Constant | Value | |---|---:|---|---:| | `CyberM.vehicles.flags.engineOn` | `1` | `CyberM.vehicles.flags.locked` | `2` | | `CyberM.vehicles.flags.destroyed` | `4` | `CyberM.vehicles.flags.exploded` | `8` | | `CyberM.vehicles.flags.invulnerable` | `16` | `CyberM.vehicles.flags.immortal` | `32` | | `CyberM.vehicles.flags.lightsOn` | `64` | `CyberM.vehicles.flags.highBeams` | `128` | | `CyberM.vehicles.flags.sirenOn` | `256` | | | Combine flags with Lua 5.4 bitwise operators (`|`, `&`, `~`). Never replace the complete mask when you only intend to toggle one bit without first reading the current canonical value. ### Doors, trunk, hood, and windows Openings have named, persistent server APIs. They are replicated to current viewers and included in stream-in/late-join state. Live changes use the vehicle's native animation; the initial streamed state is applied immediately so an already-open trunk does not visibly replay from closed. ```lua CyberM.vehicles.openDoor(id, "trunk") CyberM.vehicles.closeDoor(id, "hood") CyberM.vehicles.setDoorOpen(id, CyberM.vehicles.doors.frontRight, true) if CyberM.vehicles.isDoorOpen(id, "trunk") then -- Server-side inventory logic can now expose the trunk contents. end CyberM.vehicles.openWindow(id, "frontLeft") CyberM.vehicles.closeWindow(id, CyberM.vehicles.windows.frontLeft) ``` Door names are `frontLeft`, `frontRight`, `backLeft`, `backRight`, `trunk`, and `hood`. Snake-case cabin aliases are also accepted. Window names are the first four door names. Low-level `setDoorMask(id, mask)` and `update(id, { doors = mask, windows = mask })` remain available for frameworks that already store bitfields. | Index / bit | Door | Openable window | |---:|---|---| | `0` | `frontLeft` / `front_left` | `frontLeft` | | `1` | `frontRight` / `front_right` | `frontRight` | | `2` | `backLeft` / `back_left` | `backLeft` | | `3` | `backRight` / `back_right` | `backRight` | | `4` | `trunk` | — | | `5` | `hood` | — | Natural player interactions are observed too: opening or closing a trunk/hood in the world updates the canonical server state. A reversible opening report is accepted only from the current driver or a streamed player within 15 metres; a distant client cannot toggle another vehicle. ### Damage and repair API Damage is canonical server state and is replayed to current viewers, stream-in clients, and late joiners. The client observation channel can only add damage. Only the server resource owning the vehicle can repair it. ```lua -- Glass indices are zero-based indices into this model's Destruction.Glass list. CyberM.vehicles.breakGlass(id, 0) CyberM.vehicles.repairGlass(id, 0) CyberM.vehicles.breakAllGlass(id) -- all 32 mask bits CyberM.vehicles.breakAllGlass(id, 6) -- first six glass records CyberM.vehicles.repairAllGlass(id) CyberM.vehicles.setTireBroken(id, 0, true) CyberM.vehicles.repairTire(id, 0) CyberM.vehicles.setLightBroken(id, 2, true) CyberM.vehicles.repairLight(id, 2) CyberM.vehicles.damageBodyCell(id, 13, 0.25) -- cells are Lua indices 1..30 CyberM.vehicles.damageBodyZone(id, "front", 0.40) CyberM.vehicles.repairBodyZone(id, "front") CyberM.vehicles.repair(id, "visual") CyberM.vehicles.repair(id, "full") ``` Available body zones are `backLeft`, `back`, `backRight`, `left`, `center`, `right`, `frontLeft`, `front`, `frontRight`, `lower`, `roof`, and `all`. The low-level API remains exposed for custom damage systems: ```lua local damage = CyberM.vehicles.getDamage(id) damage.body[14] = 0.9 damage.glass = damage.glass | (1 << 3) CyberM.vehicles.setDamage(id, damage) CyberM.vehicles.setBodyDamage(id, thirtyNormalizedValues) CyberM.vehicles.setGlassMask(id, 0x15) CyberM.vehicles.setLightMask(id, 0x02) CyberM.vehicles.setTireMask(id, 0x05) ``` Glass ordering is record-specific. A resource can register readable names instead of spreading numeric indices throughout gameplay code: ```lua CyberM.vehicles.registerDamageProfile("Vehicle.v_standard2_archer_hella_player", { glass = { windshield = 0, rearWindow = 1, frontLeft = 2, frontRight = 3 }, bodyZones = { engineBay = { 13, 14, 15 } }, }) CyberM.vehicles.breakGlass(id, "windshield") CyberM.vehicles.damageBodyZone(id, "engineBay", 0.5) ``` CyberM intentionally does not ship guessed glass names: the `Destruction.Glass` order differs by vehicle record. Numeric glass/light indices are `0..31`, tyre indices are `0..3`, and all body values are finite normalized values in `0..1`. ### Other server calls ```lua CyberM.vehicles.setTransform(id, { x = 10, y = 20, z = 30, yaw = 180 }) CyberM.vehicles.get(id) CyberM.vehicles.all() CyberM.vehicles.all(bucket) CyberM.vehicles.remove(id) ``` `setTransform` is server-authoritative: it revokes an active physics lease, advances the authority epoch, and publishes the complete canonical transform to every current viewer. `get` and `all` also return the canonical seat ledger: ```lua local vehicle = CyberM.vehicles.get(id) for _, occupant in ipairs(vehicle.occupants) do print(occupant.playerId, occupant.seat) end ``` Seat names are `seat_front_left`, `seat_front_right`, `seat_back_left`, and `seat_back_right`. `seat_front_left` is the only driver seat. Scripts cannot write this ledger directly: it is produced by native mount detection and validated by the server. ### Server snapshot fields `CyberM.vehicles.get` and each entry returned by `all` contain: | Group | Fields | |---|---| | Identity | `id`, `resource`, `record`, `appearance`, `revision` | | World | `bucket`, `x`, `y`, `z` | | Authority | `physicsOwner`, `authorityEpoch` | | Durable state | `health`, `flags`, `doors`, `windows`, `tires`, `brokenGlass`, `brokenLights` | | Paint | `primaryR`, `primaryG`, `primaryB`, `secondaryR`, `secondaryG`, `secondaryB` | | Body | `bodyDamage[1..30]` | | Damage view | `damage = { body, glass, lights, tires }` | | Seats | `occupants[] = { playerId, seat }` | The current server Lua snapshot does not expose orientation. Pass an explicit `yaw` to `setTransform`; omitting it uses `0` rather than preserving an unreadable heading. Validation constraints are `health = 0..1`, RGB channels `0..255`, finite world coordinates with an absolute maximum of 1,000,000, a record length up to 256 characters, an appearance length up to 128, flags limited to the documented nine bits, exactly 30 normalized body values, doors `0..63`, and windows/tyres `0..15`. ### Server events ```lua AddEventHandler("onVehicleCreated", function(id, resource, record) end) AddEventHandler("onVehicleUpdated", function(id, revision) end) AddEventHandler("onVehicleRemoved", function(id, reason) end) AddEventHandler("onVehicleAuthorityChanged", function(id, owner, epoch, reason) end) AddEventHandler("onVehicleOccupancyChanged", function(id, revision) local canonical = CyberM.vehicles.get(tonumber(id)) end) AddEventHandler("onVehicleDamageChanged", function(id, revision) local damage = CyberM.vehicles.getDamage(tonumber(id)) end) ``` Server runtime event arguments arrive as strings. Preserve the ID as an opaque value unless the called binding explicitly requires an integer. `onVehicleUpdated` fires for every canonical state update; `onVehicleDamageChanged` is the narrower damage-specific signal. Resources can mutate or remove only their own vehicles. Stopping or reloading a resource removes every vehicle it owns. ## Client API The client state surface is intentionally read-only: ```lua local vehicle = CyberM.vehicles.get(id) local streamed = CyberM.vehicles.all() local trunkOpen = CyberM.vehicles.isDoorOpen(id, "trunk") local hoodOpen = CyberM.vehicles.isDoorOpen(id, CyberM.vehicles.doors.hood) ``` Trusted presentation resources can request an entry presentation or use an explicit instant warp: ```lua -- FiveM-compatible seat numbers: driver=-1, front passenger=0, -- rear-left=1, rear-right=2. local ok, reason = CyberM.vehicles.taskPlayerEnterVehicle( playerId, vehicleId, CyberM.vehicles.seats.frontPassenger) -- Recovery, stream reconstruction, teleport-oriented game modes, or tests. ok, reason = CyberM.vehicles.warpPlayerIntoVehicle( playerId, vehicleId, CyberM.vehicles.seats.driver) ``` Named seats (`driver`, `frontPassenger`, `rearLeft`, `rearRight`, `frontLeft`, `frontRight`, `backLeft`, `backRight`, and canonical `seat_*` names) are accepted too. These functions operate only on remote player proxies. They return `false, "occupancy_mismatch"` unless the replicated server ledger already contains that exact tuple. They cannot grant a seat, move the local player, steal a vehicle, or change physics authority. `taskPlayerEnterVehicle` is currently fail-closed and returns `false, "animated_entry_unsupported"`. The first implementation forwarded the vanilla NPC `MountAIEvent` to CyberM's player proxy; a two-client runtime test showed that REDengine can dereference a missing AI/workspot object and crash the observing client. Normal replication and `warpPlayerIntoVehicle` therefore use the stable mounting facility until the staged door/workspot implementation has passed two-client validation. This keeps the API name stable without exposing the unsafe engine path. ### Client snapshot fields The client snapshot deliberately differs from the server snapshot: | Group | Fields | |---|---| | Identity | `id`, `record`, `revision` | | Local projection | `entity`, `engineEntity`, `streamed`, `locallyOwned` | | Authority | `physicsOwner`, `authorityEpoch` | | Durable state | `health`, `flags`, `doors`, `windows`, `tires`, `brokenGlass`, `brokenLights` | | Body and damage | `bodyDamage[1..30]`, `damage = { body, glass, lights, tires }` | | Drivetrain | `speed`, `rpm`, `rpmMax`, `throttle`, `brake`, `gear`, `burnout` | | Wheels/suspension | `steering`, `wheelRotation`, `suspensionLongitudinal`, `suspensionTransversal`, `onGround`, `reversing` | | Seats | `occupants[] = { playerId, seat }` | `entity` is an ephemeral, generation-checked CyberM handle for the local projection. `engineEntity` is diagnostic engine identity. Neither is the durable server vehicle ID, and neither should be cached after stream-out. Client snapshots do not include server ownership metadata such as `resource`, `bucket`, paint channels, or world coordinates. Client events: ```lua AddEventHandler("cyberm:vehicleCreated", function(id) end) AddEventHandler("cyberm:vehicleRemoved", function(id, reason) end) AddEventHandler("cyberm:vehicleAuthorityChanged", function(id, ownerPlayerId) end) AddEventHandler("cyberm:vehicleOccupancyChanged", function(id, revision) end) AddEventHandler("cyberm:vehicleDamageChanged", function(id, revision) end) ``` The reference resource also emits `cyberm:vehicleOwnerChanged(id, ownerPlayerId)` and `cyberm:vehicleSeatsChanged(vehicleSnapshot, revision)`. The latter resolves the fresh snapshot before dispatch, unlike the lower-level occupancy event. ## Seat and proxy replication 1. REDengine reports the local player's real mount and slot. 2. The client requests that seat; it never assigns itself locally in the network ledger. 3. The server checks vehicle id, routing bucket, 15-metre proximity, lock/destruction state, one-seat-per-player, and one-player-per-seat. 4. A reliable ordered occupancy snapshot is sent to every vehicle viewer. 5. Each observing client mounts the corresponding remote player proxy into the streamed vehicle and exact seat. A live addition runs the native NPC approach/door/workspot behavior; an initial stream snapshot uses the instant warp so it does not replay an old entrance. When the snapshot removes the player, CyberM discards that disposable native proxy and recreates it from the next authoritative player snapshot. This avoids reusing a REDengine puppet whose vehicle workspot left its locomotion representation inactive. 6. Root player movement is suspended only after the native mount is confirmed, avoiding a transform fight between pedestrian interpolation and the vehicle mounting system. A fresh pedestrian controller is installed on the replacement proxy after exit. If a local engine mount disagrees with the server for two seconds (for example a locked seat was rejected), CyberM unmounts the player. Disconnect, vehicle removal, seat change, and exit all clear the server ledger. Leaving the driver seat also revokes physics authority. ## Damage, electrical state, and horn Protocol 1.13 extends the reliable observation channel for state changed by REDengine. The current physics owner captures normalized health, the native 30-cell body-destruction grid, broken glass/light bitfields, flat tyres, engine state, headlight mode, six door states, and four window states while driving. Streamed clients also watch monotonic destructive changes on nearby vehicles, so gunfire, collisions, fire, and explosions are reported even when the target vehicle is parked and has no physics owner. Nearby clients also report reversible opening changes. The server accepts damage witness reports only from the vehicle's current interest set and merges damage monotonically; a client can add damage but cannot repair a vehicle or change its electrical state. Opening changes additionally require a position within 15 metres. Repairs and arbitrary opening mutations remain explicit server-resource operations. The canonical state is sent to current viewers and embedded in `VehicleCreate` for stream-in and late join. A player connecting after a collision or explosion receives the same health, dents, broken glass/lights, tyres, destroyed state, and native explosion event instead of a pristine local projection. When the driver exits, disconnects, dies, loses the lease, or is revoked, the server clears `engineOn`, `lightsOn`, `highBeams`, and `sirenOn` before publishing the new authority epoch. This prevents parked vehicles from retaining engine audio or headlights on one client. Horn state is intentionally transient rather than durable. The native `VehicleComponent` horn latch is sampled in the realtime motion stream and observers call `ToggleHorn` only on edges. Receivers force it off after 350 ms without a fresh owner packet and on every authority change, so packet loss can never leave a remote horn stuck on. There is no `setHorn`, `setRpm`, `setSteering`, `setWheelRotation`, or seat-assignment Lua method. Those values describe native driver input, physics, or the validated occupancy ledger and cannot be authored as durable script state. Engine, lights, high beams, siren, locks, destruction, immortality, and invulnerability are the scriptable `flags` bits. ## Authority and streaming - Stream-in radius: 350 metres. - Stream-out radius: 425 metres, providing hysteresis. - Only the canonical front-left occupant requests a two-second physics lease automatically. - Valid owner motion renews the lease. - Exit, timeout, disconnect, stale epoch, or an implausible jump revokes it. - Create/remove/state/authority use reliable ordered delivery. - Motion uses unreliable sequenced delivery and is coalesced client-side. - Observers interpolate and briefly extrapolate the latest accepted transform. - The owner also retains every outgoing motion sample locally. Because the server does not echo unreliable motion to its sender, this retained sample is the handoff pose when authority is released; exiting a vehicle therefore cannot fall back to its original spawn transform. - An observer projection uses REDengine's whole-vehicle movement path: simple movement, physics masking, and `ForceMoveTo` with the interpolated pose. CyberM deliberately does not make streamed vehicles kinematic: runtime tests showed REDengine did not reconstruct a driveable backend when local ownership was later acquired. On local ownership, CyberM clears the observer physics mask explicitly, disables simple movement, restores player control, enables transform updates, and wakes native physics. - Direct manipulation of a mesh `PhysicalBodyInterface` remains deliberately disabled: that prototype crashed the second client during stream-in. Private vehicle entry points are accepted only when their 2.31 relocation resolves to the exact audited executable RVA. ### Drivetrain, wheels, and engine audio The live vehicle blackboard and input state are appended to every owner motion sample. RPM, maximum RPM, gear, speed, and longitudinal/transversal suspension forces are read from the 2.31 `VehicleDef` blackboard. Throttle, brake, burnout, reverse, and on-ground state come from the native `vehicleBaseObject`. Observers smooth these values, write them into their streamed vehicle's blackboard, and update entity-scoped mechanical audio parameters at 30 Hz. Engine pitch, load, braking, gear, and lateral load therefore follow the network owner instead of being inferred independently by each client. Remote engine audio starts when the canonical engine state turns on and stops when it turns off, streams out, or authority becomes local. Two switchable strategies exist (debug bridge `vehicle.audiomode_<0-3>`; default mechanical): *mechanical* engages the vanilla driver-mix state machine (`vehicleAudioEvent OnPlayerDriving`) and feeds the measured 2.31 RTPC names (`paramEngineRPM`, `paramVehicleSpeed`, `paramWheelAngularSpeed`, `veh_speed`, `veh_accel`, `veh_engine_throttle_input`) from the replicated motion at 30 Hz, so pitch and load follow the network owner; *traffic* plays the model's discrete `_traffic_engine_loop` Wwise pair resolved from the live TweakDB record. Replicated gear transitions additionally play the model's `_gear_up`/`_gear_down` one-shots. See `docs/research/vehicle-audio-and-wheel-fx-replication.md` for the evidence and validation plan. Body damage is replayed only after the streamed vehicle's authored components have attached. Broken-glass bits are resolved against that exact vehicle record's destruction-glass list and then applied through native glass events, so custom/model-specific window component names are preserved for current viewers and late joiners. `steering` is normalized to `-1..1` and `wheelRotation` is a wrapped radian phase. REDengine 2.31 does not expose its live steering input through RTTI, but CyberM's audited 2.31 adapter reads the native lateral vehicle input at `vehicleBaseObject+0x278`. The owner therefore transmits real keyboard/controller steering even while stationary. The authoritative wrapped wheel phase initializes the observer and replicated velocity advances it every rendered frame without packet-phase feedback. These values remain available in read-only client snapshots. CyberM does not currently write the observer's hard-transform wheel bindings: their parent animation graph can be incomplete immediately after streamed attachment, and querying that graph caused a reproducible null dereference inside REDengine on both clients. The locally driven vehicle keeps its native wheel animation and real physics; a lifecycle-safe observer chassis adapter remains required for guaranteed visual wheel pose. The server validates bucket, claim proximity, owner-to-vehicle proximity, generation/epoch, monotonic tick, finite values, velocity/RPM/input/suspension bounds, and travelled distance. Client scripts cannot claim authority directly. ## Multiplayer spawn policy There is no client-side vehicle creation API. The entire native `vehicle.*` developer-command module is absent from the client build; the documented commands below are Lua server commands and therefore use command ACLs. During a multiplayer connection, every vehicle spawn notification is checked against the live network registry. A REDengine vehicle without a server-issued 64-bit CyberM vehicle id is removed immediately; merely having a local dynamic-entity handle does not count. Entering an unknown vehicle is independently detected and forcibly unmounted. This policy complements the multiplayer REDscript suppression of traffic, summons, and ambient vehicle producers. It is an identity boundary, not just a traffic-density setting. ## Reference resource and commands `resources/cyberm_vehicles` is the runnable example. It registers: ```text vehicle.list [bucket] vehicle.create [yaw] [model] [bucket] vehicle.create.player [model] vehicle.remove vehicle.engine vehicle.lock vehicle.health <0..1> vehicle.damage.dump vehicle.glass.break vehicle.glass.repair vehicle.repair [glass|body|lights|tires|visual|mechanical|full] vehicle.paint [r2 g2 b2] ``` `vehicle.list` and `vehicle.damage.dump` are read-only. Mutation commands are restricted. Grant the corresponding exact `command.vehicle.*` ACL permissions before using them from chat. Vehicle record names are listed in the project vehicle catalog. Prefer player variants such as `Vehicle.v_standard2_archer_hella_player`; quest and traffic variants are valid records but are not guaranteed to be pilotable. --- Source: https://open2077.net/docs/npcs # Server-owned NPCs CyberM NPCs are canonical server entities projected into REDengine only for nearby players. A Lua resource creates and owns the canonical NPC; the server controls identity, routing bucket, health, tasks and simulation authority. Clients cannot create or mutate canonical NPCs. The reference implementation is [`resources/cyberm_npcs`](../resources/cyberm_npcs/README.md). ## Manifest permissions Server mutation requires `world.npcs`. Client inspection requires `npcs.read`. ```lua permissions { "world.npcs", "npcs.read" } ``` ## Architecture - NPC IDs are opaque, generation-aware 64-bit server IDs. - The server streams NPCs only to players in the same routing bucket and inside the configured radius. Hysteresis prevents rapid stream-in/stream-out near the boundary. - One ready client receives a short simulation lease and executes native REDengine commands. The lease carries an epoch; reports from an old owner or epoch are rejected. - Other clients interpolate authoritative motion and never run a competing task. - Late joiners receive the complete NPC state and active tasks. - Movement, look, action and full-body channels execute independently. Starting a look-at does not cancel movement, and starting movement does not stop an active full-body animation. - A resource may inspect and mutate only NPCs it owns. - Stopping a resource removes its non-persistent NPCs. Persistent NPCs must be removed explicitly or restored/managed by server code after a resource restart. ## Templates Raw `Character.*` records are deliberately not accepted. Use a reviewed alias from `CyberM.npcs.templates()`: ```lua for _, template in ipairs(CyberM.npcs.templates()) do print(template.name, template.record) end ``` | Alias | Intended use | |---|---| | `civilian_female_relaxed_01` | Relaxed civilian projection and scripted locomotion. | | `hostile_female_ranged_lab` | Ranged laboratory template; native combat remains experimental. | An alias contains its server-approved record, observer record and capability list. An advertised capability describes the underlying rig/template; it does not make an unstable task public. ### Complete 2.31 research catalogue The reviewed runtime allowlist above is intentionally small, but the vanilla research catalogue is now exhaustive for Cyberpunk 2077 2.31 + Phantom Liberty: - [6,668 `Character.*` records](../docs/generated/npc-records-2.31.csv), including template, gameplay metadata, crowd appearances and structural risk classification; - [1,524 unique `.ent` templates](../docs/generated/npc-templates-2.31.md), all verified present and readable in the installed base-game/EP1 archives; - [all `.ent` appearance bindings](../docs/generated/npc-entity-appearances-2.31.csv); - [all definitions from the referenced `.app` resources](../docs/generated/npc-appearance-resources-2.31.csv); - [detailed machine-readable `.ent`/`.app` graph](../docs/generated/npc-entity-appearances-2.31.json). The `category` and `risk` columns are research filters, not permission to spawn a raw record. In particular, `candidate` means only that no obvious quest/player/vendor/special-rig blocker was found in the extracted fields. A record becomes available to Lua only after it has been tested and added to the server-owned alias registry. See the [methodology, source hashes, limitations and validation backlog](../docs/research/npc-templates-and-appearances-catalog.md). ## Create and inspect ```lua local npcId, reason = CyberM.npcs.create({ template = "civilian_female_relaxed_01", position = { x = -1378.0, y = 1262.0, z = 123.0 }, yaw = 90.0, bucket = 0, appearance = nil, loadout = {}, aiMode = CyberM.npcs.ai.tasks, damagePolicy = CyberM.npcs.damage.immortal, health = 100, maxHealth = 100, streamingRadius = 180, streamingHysteresis = 40, despawnWhenUnobserved = false, persistent = false, }) if not npcId then error(reason) end local npc = CyberM.npcs.get(npcId) local owned = CyberM.npcs.all() -- this resource only local inBucket = CyberM.npcs.all(12) -- optional bucket filter ``` `get` returns the template, appearance, loadout JSON, position, bucket, streaming values, health, flags, AI/damage modes, revisions, active task and current authority lease. Limits are enforced server-side: 4096 NPCs globally, 512 per resource and 64 tasks per NPC. ### Server API reference All functions in this table require `world.npcs`. IDs are opaque 64-bit Lua integers. Mutation functions return `true` only when the NPC exists and belongs to the calling resource. Invalid definitions, task parameters, IDs or enum values raise a Lua error; callers should treat these as resource bugs rather than normal gameplay failures. | Function | Parameters | Return | |---|---|---| | `CyberM.npcs.create` | `definition` | `npcId`, or `nil, reason` when the subsystem/permission is unavailable | | `CyberM.npcs.get` | `npcId` | owned NPC snapshot or `nil` | | `CyberM.npcs.all` | optional `bucket` | array of owned NPC snapshots | | `CyberM.npcs.templates` | none | array of approved template snapshots | | `CyberM.npcs.update` | `npcId, fields` | boolean | | `CyberM.npcs.setTransform` | `npcId, transform` | boolean | | `CyberM.npcs.setBucket` | `npcId, bucket` | boolean | | `CyberM.npcs.setAppearance` | `npcId, appearance` | boolean | | `CyberM.npcs.setLoadout` | `npcId, loadout` | boolean | | `CyberM.npcs.setHealth` | `npcId, health, optional maxHealth` | boolean | | `CyberM.npcs.setDamagePolicy` | `npcId, policy` | boolean | | `CyberM.npcs.setAiMode` | `npcId, mode` | boolean | | `CyberM.npcs.setRagdoll` | `npcId, enabled` | boolean | | `CyberM.npcs.applyDamage` | `npcId, amount, optional source, optional cause` | boolean | | `CyberM.npcs.kill` | `npcId, optional reason` | boolean | | `CyberM.npcs.revive` | `npcId, optional health` | boolean | | `CyberM.npcs.remove` | `npcId` | boolean | An NPC snapshot contains: | Field | Type | Meaning | |---|---|---| | `id`, `revision`, `taskRevision` | integer | Canonical identity and monotonic revisions. | | `resource` | string | Owning resource. | | `template`, `record`, `observerRecord` | string | Approved alias and resolved REDengine records. | | `appearance`, `loadout` | string | Appearance name and canonical loadout JSON. | | `x`, `y`, `z`, `yaw` | number | Canonical transform. | | `bucket` | integer | Routing bucket. | | `streamingRadius`, `streamingHysteresis` | number | Interest thresholds in metres. | | `health`, `maxHealth` | number | Canonical health. | | `flags`, `aiMode`, `damagePolicy` | integer | Values from the constant tables below. | | `currentTaskId` | integer | Preferred active task for compact replication, or `0`. | | `authorityPlayerId`, `authorityEpoch` | integer | Current simulation lease owner and epoch, or `0`. | A template snapshot contains `name`, `record`, `observerRecord`, `defaultAppearance` and a `capabilities` array. ## State mutation ```lua CyberM.npcs.setTransform(npcId, { position = { x = 1, y = 2, z = 3 }, yaw = 180 }) CyberM.npcs.setBucket(npcId, 7) CyberM.npcs.setAppearance(npcId, "appearance_name") CyberM.npcs.setLoadout(npcId, { weapon = "Items.Preset_Lexington_Default" }) CyberM.npcs.setHealth(npcId, 80, 100) CyberM.npcs.setDamagePolicy(npcId, CyberM.npcs.damage.mortal) CyberM.npcs.setAiMode(npcId, CyberM.npcs.ai.tasks) CyberM.npcs.setRagdoll(npcId, true) CyberM.npcs.remove(npcId) ``` `CyberM.npcs.update(id, fields)` can atomically change appearance, loadout, AI mode, damage policy, health, maximum health and ragdoll. The named setters above are convenience wrappers. Moving an NPC between buckets or teleporting it revokes the current simulation lease before the new state is broadcast. ### Constants ```lua CyberM.npcs.flags.alive CyberM.npcs.flags.ragdoll CyberM.npcs.flags.despawnWhenUnobserved CyberM.npcs.flags.persistent CyberM.npcs.ai.tasks CyberM.npcs.ai.frozen CyberM.npcs.ai.native CyberM.npcs.damage.mortal CyberM.npcs.damage.immortal CyberM.npcs.damage.invulnerable ``` `tasks` is the stable default. `frozen` immediately revokes the simulation lease and suspends every task channel; returning to `tasks` resumes them with fresh timeout/duration accounting. A dead NPC cannot receive a lease, motion report or new task until it is revived. `native` is reserved for templates whose autonomous REDengine behaviour has been explicitly validated. ## Tasks Tasks are server queues partitioned into movement, look, action and full-body channels. Priority is evaluated within a channel. One task may execute in each channel at the same time. A timeout of `0` means no timeout. Task/channel combinations are validated server-side; for example `moveTo` is movement-only, `lookAt` is look-only and `playAnimation` is full-body-only. `wait` may be assigned to any channel and blocks only that channel. | Helper | Channel | Behaviour | |---|---:|---| | `moveTo` | movement | Native navigation to one position. | | `follow` | movement | Re-paths toward a player, NPC or fixed position. | | `patrol` | movement | Sequences arbitrary positions, waits and optional loops. | | `wander` | movement | Deterministic roaming around a centre. | | `face` | look | Rotates the body toward a point. | | `lookAt` | look | Continuously aims the look-at target at a player, NPC or point. | | `wait` | action by default | Server-timed delay. | | `hold` | movement | Holds the current position. | | `playAnimation` | full body | Plays a reviewed named workspot animation. | ### Move, follow and patrol ```lua local move = CyberM.npcs.tasks.moveTo(npcId, { x = 10, y = 20, z = 30 }, { speed = "walk", acceptanceRadius = 1.0, timeoutMs = 30000, }) local follow = CyberM.npcs.tasks.follow(npcId, { type = "player", id = playerId }, { speed = "run", distance = 2.0, onTargetLost = "wait", }) local followNpc = CyberM.npcs.tasks.follow(npcId, { type = "npc", id = otherNpcId }) local patrol = CyberM.npcs.tasks.patrol(npcId, { { x = 10, y = 20, z = 30, waitMs = 500 }, { x = 16, y = 20, z = 30, waitMs = 1000 }, }, { speed = "walk", loop = true, backAndForth = false }) local wander = CyberM.npcs.tasks.wander(npcId, { x = 10, y = 20, z = 30, radius = 15, speed = "walk", seed = 42, }) ``` `walk`, `run` and `sprint` are supported movement speeds. Patrol accepts 1 to 64 points. The current `onTargetLost` policy waits for the target to become available again. ### Look, hold and animation ```lua CyberM.npcs.tasks.face(npcId, { x = 1, y = 2, z = 3 }, { tolerance = 3, speed = 180, timeoutMs = 5000, }) CyberM.npcs.tasks.lookAt(npcId, { type = "player", id = playerId }) CyberM.npcs.tasks.wait(npcId, 1500) CyberM.npcs.tasks.hold(npcId, { durationMs = 5000 }) CyberM.npcs.tasks.playAnimation(npcId, "emote_smoke", { loop = false }) ``` Named full-body animations remain active until they are cancelled, preempted, timed out or the NPC streams out. REDengine does not expose a reliable completion signal for every workspot clip, so use `timeoutMs` or explicit cancellation when the animation must end deterministically. ### Generic queue and cancellation ```lua local taskId = CyberM.npcs.tasks.enqueue(npcId, "moveTo", { x = 1, y = 2, z = 3, speed = "walk", }, { channel = CyberM.npcs.channels.movement, priority = 10, timeoutMs = 30000 }) local task = CyberM.npcs.tasks.get(npcId, taskId) local tasks = CyberM.npcs.tasks.all(npcId) CyberM.npcs.tasks.cancel(npcId, taskId, "script_cancel") CyberM.npcs.tasks.clear(npcId, CyberM.npcs.channels.movement, "new_route") ``` Only the task names listed above are accepted. Unsupported types and malformed targets, paths, durations or animation names are rejected before replication. ### Task API reference | Function | Parameters | Return | |---|---|---| | `CyberM.npcs.tasks.enqueue` | `npcId, type, parameters, optional options` | task ID | | `CyberM.npcs.tasks.moveTo` | `npcId, position, optional options` | task ID | | `CyberM.npcs.tasks.follow` | `npcId, target, optional options` | task ID | | `CyberM.npcs.tasks.patrol` | `npcId, points, optional options` | task ID | | `CyberM.npcs.tasks.wander` | `npcId, optional options` | task ID | | `CyberM.npcs.tasks.face` | `npcId, target, optional options` | task ID | | `CyberM.npcs.tasks.lookAt` | `npcId, target, optional options` | task ID | | `CyberM.npcs.tasks.wait` | `npcId, durationMs, optional options` | task ID | | `CyberM.npcs.tasks.hold` | `npcId, optional options` | task ID | | `CyberM.npcs.tasks.playAnimation` | `npcId, animation, optional options` | task ID | | `CyberM.npcs.tasks.get` | `npcId, taskId` | task snapshot or `nil` | | `CyberM.npcs.tasks.all` | `npcId` | array of task snapshots | | `CyberM.npcs.tasks.cancel` | `npcId, taskId, optional reason` | boolean | | `CyberM.npcs.tasks.clear` | `npcId, optional channel, optional reason` | number cancelled | Common options are `priority` (signed integer) and `timeoutMs` (`0` disables the timeout). Generic `enqueue` also accepts `channel`. A task snapshot contains `npcId`, `id`, `resource`, `type`, the JSON string `parameters`, `channel`, `priority`, `timeoutMs`, `status`, `revision` and `reason`. Statuses are `queued`, `suspended`, `executing`, `success`, `failure`, `cancelled` and `interrupted`. ## Health, damage and death ```lua CyberM.npcs.applyDamage(npcId, 25, "resource:arena", "firearm") CyberM.npcs.kill(npcId, "admin") CyberM.npcs.revive(npcId, 100) ``` - `mortal` allows health to reach zero. - `immortal` applies damage but clamps health to 1. - `invulnerable` rejects damage. Health and death are canonical server state. Client hit detection should request a bounded server action; it must not directly mutate a projection. ## Events Server resource events: ```lua AddEventHandler("onNpcCreated", function(npcId, resource, template) end) AddEventHandler("onNpcUpdated", function(npcId, revision) end) AddEventHandler("onNpcRemoved", function(npcId, reason, resource) end) AddEventHandler("onNpcTaskState", function(npcId, taskId, status, reason) end) AddEventHandler("onNpcAuthorityChanged", function(npcId, playerId, epoch, reason) end) AddEventHandler("onNpcDamaged", function(npcId, source, amount, health, cause) end) AddEventHandler("onNpcDied", function(npcId, source, cause) end) ``` Client resource events: ```lua AddEventHandler("onNpcStreamIn", function(npcId, revision) end) AddEventHandler("onNpcReady", function(npcId, entity) end) AddEventHandler("onNpcChanged", function(npcId, revision) end) AddEventHandler("onNpcTaskChanged", function(npcId, taskId) end) AddEventHandler("onNpcAuthorityChanged", function(npcId, playerId) end) AddEventHandler("onNpcStreamOut", function(npcId, reason) end) ``` ## Client read-only API ```lua local npc = CyberM.npcs.get(npcId) local visible = CyberM.npcs.all() local ready = CyberM.npcs.isStreamedIn(npcId) local entity = CyberM.npcs.entity(npcId) -- local CyberM entity handle or nil local taskId = CyberM.npcs.currentTask(npcId) -- canonical current task ID or nil ``` Snapshots expose `streamed` and `locallyAuthoritative`. The local entity handle is ephemeral: do not cache it across stream-out, reconnect or resource reload. Client snapshots contain `id`, `revision`, `entity`, `template`, `appearance`, `flags`, `bucket`, `aiMode`, `damagePolicy`, `health`, `maxHealth`, `currentTaskId`, `taskRevision`, `authorityPlayerId`, `authorityEpoch`, `streamed` and `locallyAuthoritative`. Without `npcs.read`, `all()` returns an empty array, `get()`/`entity()`/`currentTask()` return `nil`, and `isStreamedIn()` returns `false`. ## Current limitations - Server persistence storage is resource-defined; `persistent=true` only changes cleanup policy. - Arbitrary records, raw REDengine handles and client-side canonical mutation are intentionally unsupported. - Native attack/shoot/melee/combat tasks are not in the stable API yet. Use server-authoritative scripted damage until animation, targeting and hit validation are proven safe for each rig. - Native authored patrol paths (`NodeRef`) are not exposed; CyberM patrols sequence `moveTo` tasks. - A client authority lease is required for native navigation. With no ready client, tasks suspend and resume when authority becomes available. --- Source: https://open2077.net/docs/elevators # Network elevators CyberM keeps Cyberpunk 2077's native moving-platform motion, sounds, collision and floor markers, but makes the dedicated server authoritative over every registered elevator. > **Status:** protocol 1.7, server authority, bucket/chunk streaming, late-join catch-up, Lua APIs > and the `cyberm_elevators` reference package are implemented. Two-client runtime acceptance is > still required for quest-specific elevators and landing-door variants. ## Architecture ```text button / Lua request | v server validation + deadline + revision + bucket | v reliable ElevatorState client WorldQuery -> streamed LiftDevice -> native MoveTo / Pause / Unpause / TeleportTo ``` The server advances an elevator even when no client streams it. A client entering its interest area receives the current authoritative phase and remaining time. Old revisions are ignored. Elevators are static world entities and are **adopted**, not spawned. Identity includes the routing bucket, so one native `LiftDevice` can be idle at floor 0 in bucket 0 and moving to floor 4 in bucket 42 without leaking state between instances. Spatial interest uses 128 m chunks, streams in at 225 m and streams out at 275 m. The hysteresis prevents repeated create/remove traffic near a chunk boundary. ## Manifest permissions ```lua permissions { "world.elevators", -- server adoption and mutation "elevators.read", -- client streamed snapshots "elevators.request" -- client button/call intentions } ``` `world.elevators` is server-only. Client resources cannot call native movement, choose markers, set deadlines or report an arrival as canonical. ## Server API ### Adopt a native elevator Use the inspector in game to obtain the `LiftDevice` entity hash and its position: ```lua local id, reason = CyberM.elevators.adopt({ engineEntity = "0x0123456789ABCDEF", position = { x = -1200.0, y = 450.0, z = 20.0 }, bucket = 0, initialFloor = 0, floorCount = 3, flags = CyberM.elevators.flags.powered | CyberM.elevators.flags.interactionAllowed, }) assert(id, reason) ``` REDengine hashes are opaque unsigned 64-bit values. Keep them as hexadecimal strings; never pass them through `tonumber`. The dedicated server does not load REDengine, so type validation happens when a streamed client resolves the hash. A non-lift hash remains abstract and is never projected. The adopting resource owns the elevator until `remove`, resource stop or server shutdown. The same `engineEntity` may be adopted once per bucket. Re-adopting the same structural definition from the same resource is idempotent: it returns the existing ID and preserves its phase and deadline, which makes transactional resource reloads safe. A different owner, position or floor count is rejected. ### Read snapshots ```lua local lift = CyberM.elevators.get(id) for _, other in ipairs(CyberM.elevators.all(0)) do print(other.id, other.engineEntity, other.phase, other.activeFloor) end ``` Server snapshots contain: - `id`, `resource`, `engineEntity`, `bucket`, `chunkX`, `chunkY`, `floorCount`; - `x`, `y`, `z`, `phase`, `activeFloor`, `originFloor`, `targetFloor`; - `travelMs`, `pausedRemainingMs`, `flags`, `revision`. Phases are `idle`, `moving` and `paused`. ### Move, pause and recover ```lua CyberM.elevators.goTo(id, 2, { travelMs = 12000 }) CyberM.elevators.call(id, 1, { travelMs = 8000 }) CyberM.elevators.pause(id) CyberM.elevators.resume(id) CyberM.elevators.teleport(id, 0) -- administration/recovery ``` `goTo` and `call` schedule the same authoritative native trip. `travelMs` is bounded from 100 ms to one hour. `teleport` cancels the schedule and aligns all projections to one exact floor marker. ### Flags ```lua local lift = CyberM.elevators.get(id) lift.flags = lift.flags | CyberM.elevators.flags.locked CyberM.elevators.setFlags(id, lift.flags) ``` | Flag | Meaning | |---|---| | `powered` | Player requests are accepted when set. | | `locked` | Player requests are denied when set. | | `interactionAllowed` | Enables bounded button/call requests. | | `doorsClosed` | Closes cabin doors; set automatically during normal movement. | Authoritative arrival clears `doorsClosed`. More detailed roleplay access policy belongs in the owning server resource and its ACL-restricted commands. ### Server events ```lua AddEventHandler("onElevatorStateChanged", function( id, revision, bucket, phase, activeFloor, targetFloor ) end) AddEventHandler("onElevatorRemoved", function(id, revision, reason) end) ``` ## Client API The client surface is read-only except for bounded requests: ```lua local lift = CyberM.elevators.get(id) local streamedStates = CyberM.elevators.all() local submitted, reason = CyberM.elevators.request(id, 1, "call") local submitted, reason = CyberM.elevators.request(id, 2, "goto") ``` Client requests accept only `call` and `goto`; `pause` and `resume` are server-Lua-only mutations. The submission result only means that the packet was queued; the later `ElevatorState` is the authority decision. The server validates session, life state, bucket, distance (18 m), flags, floor range and current phase. Client snapshots add `position`, `remainingMs`, `streamed` and `applied`. While a lift is moving, `remainingMs` is extrapolated from the most recent authoritative heartbeat, so it decreases between packets; it is still corrected by every server resynchronization. The reference resource publishes convenience events: ```lua AddEventHandler("cyberm:elevator:streamedIn", function(id, snapshot) end) AddEventHandler("cyberm:elevator:updated", function(id, snapshot) end) AddEventHandler("cyberm:elevator:streamedOut", function(id) end) ``` ## Reference resource and commands `resources/cyberm_elevators` is auto-started and is both a working package and an example for other developers. Server resources use the native `CyberM.elevators` namespace directly; client-side convenience exports are also provided. Its restricted commands use the normal CyberM ACL: ```text elevator.list [bucket] elevator.adopt [bucket] [initialFloor] elevator.adopt.player [initialFloor] elevator.goto [travelMs] elevator.teleport elevator.pause elevator.resume elevator.power elevator.lock elevator.remove ``` The chat receives descriptions and parameter completion after `chat:ready`. The client developer console can inspect current projections with: ```text resource.emit cyberm:elevators:probe resource.emit cyberm:elevators:nearby 100 ``` `nearby` lists streamed native `LiftDevice` hashes and exact positions, including unmanaged lifts, which makes the output directly usable with `elevator.adopt`. ## Native behavior and late join A trip uses the vanilla `MovingPlatformMovementDynamic` in time mode and the floor's native `NodeRef`. This retains physical cabin motion, engine sounds and transport of actors standing in the cabin. It is not a sequence of transform teleports. For a late join, CyberM starts the full canonical curve, then uses the native `Pause/Unpause` time cursor on the next script frame to seek to elapsed progress. A paused server state remains paused. At authoritative arrival, every client receives `idle` and performs a one-shot exact marker alignment to remove residual drift. If REDengine unloads and later recreates the `LiftDevice` while the CyberM state remains in range, the new native instance is detected, its topology is re-read, and the current state is projected again even when the server revision did not change. Time spent waiting for native topology is deducted before the movement cursor is positioned. Managed `LiftControllerPS.OnGoToFloor` and `OnCallElevator` actions are intercepted before their vanilla local mutation and converted to `ElevatorRequest`. Unmanaged single-player lifts keep their normal behavior outside the CyberM interest set. CyberM maps both the streamed `LiftDevice` entity and its persistent `LiftControllerPS` identity, because some vanilla variants use different IDs for movement and button actions. At departure, CyberM closes the configured cabin doors and sends `LiftDepartedEvent` to every floor terminal so all landing doors lock. At authoritative arrival, the native floor event opens only the active landing and only the front/left/right cabin sides declared by that floor's `ElevatorFloorSetup`. Local save authorization cannot make two clients disagree on a managed landing door; access has already been decided by the server request path. ## Security and limits - A client cannot provide an engine entity hash, marker, duration, curve, door state or revision. - Invalid packet enums, floors, positions, times and flags are rejected by both codecs. - Elevator requests are soft-limited to 8 packets per authenticated session per second. - A well-formed request that races a stream-out, resource reload or bucket transition is denied without disconnecting the player; only malformed protocol payloads are connection violations. - Server mutation is resource-owned and protected by `world.elevators` plus command ACLs. - At most 2048 elevators can be adopted per server. - Floor indexes are vanilla per-lift indexes in `0..floorCount-1`; they are not universal floor IDs. - Quest lifts may have extra workspots, layers or scripted doors and need explicit runtime testing. Implementation evidence, Ghidra handlers, known risks and the acceptance matrix are recorded in [the elevator research note](../docs/research/elevators-and-moving-platform-replication.md). --- Source: https://open2077.net/docs/loot # Server loot and ground drops In a CyberM session, ground loot is server-authoritative. Vanilla bodies, bags, containers, collectibles, and physical drops never hand an item to the player directly. An item visible on the ground is a local projection, presented through Cyberpunk's own interface — contents, rarity, detail card, `Take` and `Take All`. Selecting an item there sends a request to the server, which checks the drop, the dimension, and the distance before allowing the pickup. The local `TransactionSystem` removes nothing until the reply arrives. The official `cyberm_loot` resource must stay started. Its manifest asks for `network.events` and `world.loot`, and its client is distributed with the server's resource set. Use this guide to place items in the world from a server resource, and to credit them to a player's inventory when they are picked up. ## Server API Server resources that declare `world.loot` get `CyberM.loot`: ```lua permissions { "network.events", "world.loot" } ``` ```lua local dropId, reason = CyberM.loot.create({ item = "Items.money", -- TweakDB record quantity = 250, position = { x = -1450.2, y = 117.8, z = 12.4 }, bucket = 0, -- routing bucket radius = 2.0, -- 0.5 to 10 metres label = "Eurodollars", visualItem = "Items.MoneyShard", -- record used only for the 3D entity ttlMs = 300000 -- optional, seven days maximum }) assert(dropId, reason) CyberM.loot.update(dropId, { quantity = 300, position = { x = -1450.0, y = 118.1, z = 12.4 }, radius = 2.5 }) local drop = CyberM.loot.get(dropId) local bucketDrops = CyberM.loot.all(0) CyberM.loot.remove(dropId) ``` A player's authoritative position is available server-side too: ```lua local position = CyberM.players.position(playerId) -- { x, y, z, bucket }, or nil when the player or snapshot is unavailable. ``` A drop belongs to the resource that created it. Another resource can neither change nor delete it, and stopping the owning resource cleans up its drops. The registry is capped at 4,096 entries, quantities at 1,000,000, and positions at the world bounds the protocol accepts. `item` and `visualItem` play distinct roles. `item` is the authoritative content actually granted once the pickup is validated. `visualItem` is a TweakDB record that owns a `dropObject` and serves only to create the physical `gameItemDropObject`. For a weapon, leaving `visualItem` empty uses the weapon's own record directly. Since `Items.money` is abstract currency, CyberM automatically picks `Items.MoneyShard` (`smallItemDrop`, entity `money`) when no override is supplied. After an accepted pickup, every server VM receives: ```lua AddEventHandler("onLootPickup", function(playerId, dropId, item, quantity, ownerResource) if ownerResource ~= GetCurrentResourceName() then return end -- Write the authoritative persistent inventory here (database, weight, -- transaction log, and so on). The client never decides the outcome. print(playerId, dropId, item, quantity) end) ``` The pickup is atomic within the registry: two players cannot consume the same id. Validation uses a `PlayerSnapshot` received less than two seconds ago, requires the same routing bucket, and accepts at most `radius + 0.75 m` to absorb network latency. ## Testing from the CyberM terminal These commands are genuinely declared in `cyberm_loot/server/main.lua` with `RegisterCommand`, just as in a FiveM resource: ```text loot.create.player 1 Items.money 250 1.0 2.0 Items.MoneyShard loot.create Items.money 250 -1450.2 117.8 12.4 0 2.0 loot.create.player 1 Items.Preset_Lexington_Default 1 loot.list 0 loot.remove 1 ``` Type these lines into the developer terminal opened with `²` in Cyberpunk. `loot.list` is public. The mutations `loot.create`, `loot.create.player`, and `loot.remove` are registered with `restricted=true` and require the ACL permissions `command.loot.create`, `command.loot.create.player`, and `command.loot.remove` respectively (or a suitable wildcard). `loot.create` expects ` [bucket] [radius] [visualItem]`. Decimal numbers use a dot. The drop is replicated to the bucket's players immediately; its prompt should disappear on every client as soon as a pickup is accepted. `loot.create.player` uses the player's latest fresh snapshot and adds one metre in Z by default, so the item falls in front of them. Its full form is `loot.create.player [offsetZ] [radius] [visualItem]`. The representation is a real native entity produced by `LootManager.SpawnItemDrop`: the record's mesh, a `gameItemDropObject` wrapper, placement, physics, highlight, and REDengine UI. CyberM binds the native `EntityID` to the server id when the child object appears, then fills the native inventory with `item` and `quantity`. There is no separate CyberM anchor or prompt any more. ## Client API Gameplay clients read the projection through `cyberm_loot`'s exports: ```lua CreateThread(function() local promise, err = CyberM.exports.call("cyberm_loot", "all") if not promise then return print(err) end local drops = assert(promise:await()) for _, drop in ipairs(drops) do print(drop.id, drop.item, drop.quantity) end end) -- The native prompt already performs this. Useful for a custom UI. CreateThread(function() local promise = CyberM.exports.call("cyberm_loot", "requestPickup", 42) if promise then print(promise:await()) end end) ``` Available exports: - `get(id)` — returns the local drop, or `nil`; - `all()` — snapshot sorted by id; - `requestPickup(id)` — sends the request to the server. This local event lets you show feedback without touching authority: ```lua AddEventHandler("cyberm:loot:result", function(id, accepted, reason, item, quantity) if not accepted then print("Pickup refused: " .. tostring(reason)) end end) ``` Do not call `CyberM.loot.upsert`, `acceptPickup`, or `setAuthorityEnabled` directly from a gameplay resource. Those are the internal primitives of the distributed projection, guarded by `world.loot`. ## The boundary between native UI and server authority - `Inventory` choices stay visible only for entities bound to a server drop; - `Inventory.OnInteractionUsed` is intercepted before its local `RemoveItem` and becomes a `cyberm:loot:pickup` request; - the native pickup condition is re-enabled only for bound `gameItemDropObject`s; - legacy placed pickups (`HealthConsumable`, `VirtualItem_TEMP`) and the `Loot` choices of inspectable objects; - the container role of bodies, bags, ground items, and static containers; - the vanilla backpack's "drop" action; - the normal held-weapon drop path when an NPC dies; - drops already present when authority activates, purged before the server projection. The global purge runs only when authority activates. After that, a pickup, a removal, or an update empties only the inventory of the entity concerned. Cyberpunk then receives its normal `OnInventoryEmptyEvent` and cleanly removes the HUD, the interaction, and the visual without recreating the other ground items. CyberM items therefore use the same presentation as vanilla: the physical mesh resolved by the TweakDB record falls with the game's physics, and the `Inventory` component builds the list and the item card. That entity holds no authority though: removal and granting only happen after the server answers positively. ## Scope **A drop holds one stack** — one `item` and one `quantity`. Containers holding several stacks, and corpses carrying an authoritative inventory, belong to the container API and are not part of this one. **Persistent inventory is yours to write.** This subsystem decides *who may take what*, and stops there. `onLootPickup` is where you credit an account, apply weight, or write a transaction log. **Quest collectibles that bypass `Inventory`** are not intercepted. A handful of highly specialised pickups take neither the `Inventory` path nor the standard loot conditions; those still grant locally. If you meet one, its class can be identified with the CyberM inspector. --- Source: https://open2077.net/docs/weather # Synchronised time and weather `cyberm_weather` is the single authority for a session's time and weather. Every player sees the same clock and the same sky, and neither drifts: the server holds the canonical state and clients project it locally. At server boot the canonical state is `12:00:00`, the weather is `sunny`, and the clock advances at `timeScale`. A player joining later receives the current time, never the boot time, and joins a weather transition already in progress at its current point rather than restarting it. Use this guide if you are writing a resource that needs to read the time, react to weather, or — from a trusted server resource — change either. ## Network model ```text server monotonic clock + canonical state | | versioned snapshot / reliable broadcast v client request ---- RTT/2 ----> local REDengine projection ^ | periodic resynchronisation ``` The snapshot carries `authorityEpoch`, `revision`, `secondsOfDay`, `rate`, `frozen`, the weather name and preset, the transition, the priority, and the deadline of the next random event. The client measures the round trip of its own request, adds at most two seconds of half-RTT, then re-anchors its monotonic reference. A mutation broadcast applies immediately; a reply carrying an older revision of the same epoch is rejected. A new epoch lets a server hot-reload restart at revision 1 without leaving clients stuck on the previous incarnation. CyberM projects the server clock twice a second. It deliberately does not hold REDengine's `SetPausedState`: two-client runtime testing proved that this flag can also slow gameplay and vehicle physics. Periodic absolute correction prevents long-term clock drift without changing the simulation rate. At midnight, circular arithmetic turns the roll over to `00:00` into normal forward motion. A small step back caused by a late packet is ignored, so REDengine's "next occurrence" semantics are not triggered — which would jump a whole day. ## Configuration Edit `resources/cyberm_weather/shared/config.lua`: - `startupTime` — `12:00:00` by default; - `timeScale` — game seconds per real second (`4.0`); - `syncIntervalMs` — full resynchronisation (`15000`); - `applyIntervalMs` — projection frequency (`500`); - `heartbeatIntervalMs` — authoritative server broadcast (`5000`); - `environmentEnforceIntervalMs` — local lock and preset check (`5000`); - `randomWeather` and `initialWeatherDurationSeconds`; - `presets` — weight, real min/max duration, and transition for each weather. The file is shared and therefore public. It must hold no secret, key, or ACL. Presets supplied: `sunny`, `lightclouds`, `cloudy`, `rain`, `heavyclouds`, `fog`, `pollution`, and `sandstorm`. The REDengine `24h_weather_*` values are still accepted server-side. ## Server commands and ACL From the in-game CyberM terminal or the dedicated console: ```text weather.status weather.time.set 06:45 weather.time.freeze weather.time.resume weather.rate 12 weather.set fog 25 weather.random off weather.next ``` `weather`, `weather.status`, and `weather.time` are read-only. Every other command uses `RegisterCommand(..., true)` and is authorised against the player's authenticated public identity. For example: ```json { "permissions": ["command.weather.*"] } ``` The client DLL exposes no local `time.*` or `weather.*` command, so every interactive change goes through the server and its ACL. The network events the resource accepts serve only to request a snapshot: no client mutation event exists. ## API for a server resource These events are local to the server runtime: ```lua TriggerEvent("cyberm:weather:setTime", 20, 15, 0) TriggerEvent("cyberm:weather:setRate", 4) TriggerEvent("cyberm:weather:setFrozen", false) TriggerEvent("cyberm:weather:setWeather", "rain", 30) TriggerEvent("cyberm:weather:setRandomEnabled", true) ``` To observe the state: ```lua AddEventHandler("cyberm:weather:state", function(state) print(("weather=%s revision=%d"):format(state.weather, state.revision)) end) TriggerEvent("cyberm:weather:requestState") ``` `cyberm:weather:timeChanged` and `cyberm:weather:weatherChanged` report the precise cause. These APIs are meant for trusted server resources; server scripts are not distributed to players. ## API for a client resource Listening, with no dependency: ```lua AddEventHandler("cyberm:weather:updated", function(state) print(state.weather, state.rate, state.frozen) end) ``` A one-off read through an export: ```lua CreateThread(function() local promise, reason = CyberM.exports.call("cyberm_weather", "getState") assert(promise, reason) local state = promise:await() print(string.format("%02d:%02d:%02d", state.hour, state.minute, state.second)) end) ``` Available exports: - `isReady()` — has the first snapshot arrived? - `getState()` — time predicted at the moment of the call, and the weather state; - `requestSync()` — forces a reliable resynchronisation request. The native `CyberM.environment` table (`getTime`, `setTime`, `setTimeFrozen`, `setWeather`, `setWeatherFrozen`, `isWeatherFrozen`) is guarded by the `world.environment` permission. It exists to implement the authority, not for ordinary gameplay scripts. ## Random weather events The server makes a weighted draw that excludes the current weather, applies the new preset's transition, then schedules its real min/max duration. The seed comes from the process's monotonic clock at the first tick, so two boots do not systematically replay the same sequence. `weather.random off` suspends the draws without changing the current weather; `weather.random on` cleanly reschedules the deadline. ## Deployment The resource sits under the configured `resources.root`. The server watcher prepares its VM, rebuilds the signed set, and distributes only the manifest, the client and shared scripts, and this README. The new client DLL is required for the `CyberM.environment` primitive; if it is not loaded yet, the resource stays inert and explicitly asks for Cyberpunk to be restarted. --- Source: https://open2077.net/docs/blips # Vanilla blips and mappins `CyberM.blips` creates real Cyberpunk 2077 mappins. Depending on the vanilla profile attached to the sprite, the same blip can appear in the HUD, the minimap, and the world map. The API requires this permission: ```lua permissions { "ui.vanilla.map" } ``` The ids returned are 64-bit decimal strings. Keep them as they are: never convert them with `tonumber`. Use this guide to mark a position or an entity on the player's map, minimap, and HUD. ## A first blip ```lua local blip, reason = CyberM.blips.create({ position = { x = -1442.2, y = 127.4, z = 18.0 }, sprite = "objective", title = "Vehicle Dealership", description = "Purchase and collect street-legal vehicles.", active = true, visibleThroughWalls = false }) assert(blip, reason) assert(CyberM.blips.setPosition(blip, { x = -1440.0, y = 130.0, z = 18.0 })) assert(CyberM.blips.setSprite(blip, "VehicleVariant")) assert(CyberM.blips.remove(blip)) ``` ## Custom PNG icons Declare every client asset in `cyberm.lua`. Undeclared files cannot be used as textures: ```lua files { "assets/blips/*.png" } permissions { "ui.vanilla.map" } ``` Then validate the texture and associate it with the blip. The native `sprite` provides the actual rendering, selection, filtering, GPS routing, and fullscreen-map tooltip on Cyberpunk 2077 2.31. ```lua local jobIcon, reason = CyberM.assets.texture("assets/blips/job-center.png") assert(jobIcon, reason) local jobCenter = assert(CyberM.blips.create({ position = { x = -1442.2, y = 127.4, z = 18.0 }, sprite = "tech", title = "Job Center", description = "Browse available civilian jobs and city contracts.", icon = { asset = jobIcon.asset, size = 56 } })) assert(CyberM.blips.setIcon(jobCenter, "assets/blips/job-center.png")) assert(CyberM.blips.setIcon(jobCenter, false)) -- restore the native sprite ``` `icon` accepts a declared asset path, the descriptor returned by `CyberM.assets.texture`, or a table `{ asset = path, size = pixels }`. Display size is limited to `16..128` pixels. Textures are currently PNG only, at most 512 KiB and 512×512. The test asset is 128×128 with transparency. The downloaded PNG compositor is disabled on Cyberpunk 2077 2.31. REDengine applies mappin projection after the normal Ink transform pass: script-visible widget coordinates remain local, and reading or forcing fullscreen-map layout while its native tree is being constructed causes an engine null dereference. CyberM therefore keeps and validates the `icon` metadata but deliberately renders the native `sprite`. This is a compatibility fallback, not a promise that the PNG appears. `CyberM.assets.list()` returns the current resource's declared `files`; `texture(path)` returns `{ type, asset, mime, width, height, bytes }` without exposing the file contents. A blip can follow a CyberM entity instead of a position: ```lua local playerBlip = assert(CyberM.blips.create({ entity = remotePlayerEntityId, sprite = "remote_player", slot = "poi_mappin", offset = { x = 0.0, y = 0.0, z = 2.0 } })) CyberM.blips.attachToEntity(playerBlip, anotherEntityId, "poi_mappin", { x = 0.0, y = 0.0, z = 2.0 }) ``` `position` and `entity` are mutually exclusive at creation. `setPosition` turns an attached blip into a positional one. In `update`, `entity = false` only detaches when a new `position` is supplied. ## Full API | Function | Result | Role | |---|---|---| | `create(options)` | `id`, or `nil, reason` | Creates a positional or attached blip. | | `update(id, patch)` | `boolean, reason?` | Changes several properties in one operation. | | `setPosition(id, position)` | `boolean, reason?` | Moves the blip and makes it positional. | | `attachToEntity(id, entity, slot?, offset?)` | `boolean, reason?` | Attaches the blip to a CyberM entity. | | `setSprite(id, sprite)` | `boolean, reason?` | Accepts a name, an alias, or an integer `0..146`. | | `setTitle(id, title)` | `boolean, reason?` | Changes the fullscreen-map title, 128 bytes maximum. | | `setDescription(id, description)` | `boolean, reason?` | Changes the fullscreen-map description, 1024 bytes maximum. An empty string hides it. | | `setLabel(id, label)` | `boolean, reason?` | Backward-compatible alias of `setTitle`. | | `setIcon(id, iconOrFalse)` | `boolean, reason?` | Stores a declared PNG icon or clears it; 2.31 renders the native sprite. | | `setActive(id, active)` | `boolean, reason?` | Enables or disables the vanilla mappin. | | `setVisibleThroughWalls(id, visible)` | `boolean, reason?` | Changes visibility through walls. | | `setTrackingAlternative(id, targetIdOrNil)` | `boolean, reason?` | Sets or clears the alternative routing blip. | | `untrack(id)` | `true, wasTracked`, or `false, reason` | Removes tracking only if this blip is the tracked one. | | `get(id)` | `snapshot`, or `nil, reason` | Reads a blip owned by the current resource. | | `list()` | `snapshots`, or `nil, reason` | Lists only the current resource's blips. | | `sprites()` | `{ {name, value}, ... }` | Returns the current build's 147 variants. | | `remove(id)` | `boolean, reason?` | Deletes a blip. | | `clear()` | `true` | Deletes every blip owned by the resource. | `create` options: `position` or `entity`, `sprite`, `title`, `description`, `icon`, `active`, `visibleThroughWalls`, plus `slot` and `offset` for an entity. `label` remains an alias for `title`; do not provide both. `update` accepts the same fields, and the dedicated setters can change text at runtime. The quotas are 128 blips per resource and 512 per client. Stopping, reloading, and leaving the world clean up blips automatically. A resource can neither read, change, nor delete another resource's blip. The TweakDB type is fixed to `Mappins.DefaultStaticMappin`; downloaded packages cannot inject an arbitrary UI profile. `title` and `description` are resource-owned text. When the player highlights the blip on the fullscreen map, CyberM replaces the variant-specific tooltip with those exact values. Variant-specific fixer progress, threat, journal, price and travel panels are hidden for CyberM blips. HUD-only variants can still be absent from the fullscreen map; use a map-capable sprite such as `objective`, `quest`, `fast_travel`, `vehicle`, or a service-point variant when map selection is required. ## Stable aliases | Alias | Variant | |---|---| | `default` | `DefaultVariant` | | `objective` | `DefaultQuestVariant` | | `quest` | `QuestGiverVariant` | | `important` | `ExclamationMarkVariant` | | `question` | `QuestionMarkVariant` | | `fast_travel` | `FastTravelVariant` | | `vehicle` | `VehicleVariant` | | `loot` | `LootVariant` | | `danger` | `HazardWarningVariant` | | `vendor` | `OpenVendorVariant` | | `apartment`, `stash`, `wardrobe` | matching variants | | `bar`, `clothes`, `cyberware`, `drop_point`, `food`, `guns`, `junk`, `meds`, `ripperdoc`, `tech` | matching `ServicePoint*` variants | | `race`, `ncart`, `fixer`, `tarot` | matching variants | | `ping_door`, `ping_go_here`, `ping_loot`, `remote_player` | matching `CPO_*` variants | Exact names are insensitive to case, spaces, hyphens, and underscores. Aliases are preferable for generic gameplay; full names are useful when a server wants one specific vanilla asset. ## Complete sprite list (Cyberpunk 2077 2.31) `Count=147` and `Invalid=148` are sentinels and are not accepted. The usable values are: | ID | Nom | ID | Nom | ID | Nom | |---:|---|---:|---|---:|---| | 0 | `ActionDealDamageVariant` | 49 | `ExclamationMarkVariant` | 98 | `ServicePointDropPointVariant` | | 1 | `ActionFastSoloVariant` | 50 | `FailedCrossingVariant` | 99 | `ServicePointFoodVariant` | | 2 | `ActionGenericInteractionVariant` | 51 | `FastTravelVariant` | 100 | `ServicePointGunsVariant` | | 3 | `ActionNetrunnerAccessPointVariant` | 52 | `FixerVariant` | 101 | `ServicePointJunkVariant` | | 4 | `ActionNetrunnerVariant` | 53 | `FocusClueVariant` | 102 | `ServicePointMedsVariant` | | 5 | `ActionScanVariant` | 54 | `GPSForcedPathVariant` | 103 | `ServicePointMeleeTrainerVariant` | | 6 | `ActionSoloVariant` | 55 | `GPSPortalVariant` | 104 | `ServicePointNetTrainerVariant` | | 7 | `ActionTechieVariant` | 56 | `GangWatchVariant` | 105 | `ServicePointProstituteVariant` | | 8 | `AimVariant` | 57 | `GenericRoleVariant` | 106 | `ServicePointRipperdocVariant` | | 9 | `AllowVariant` | 58 | `GetInVariant` | 107 | `ServicePointTechVariant` | | 10 | `ApartmentVariant` | 59 | `GetUpVariant` | 108 | `SitVariant` | | 11 | `ArrowVariant` | 60 | `GrenadeVariant` | 109 | `SmugglersDenVariant` | | 12 | `BackOutVariant` | 61 | `GunSuicideVariant` | 110 | `SoloTechieVariant` | | 13 | `BountyHuntVariant` | 62 | `HandVariant` | 111 | `SoloVariant` | | 14 | `CallVariant` | 63 | `HazardWarningVariant` | 112 | `SpeechVariant` | | 15 | `ChangeToFriendlyVariant` | 64 | `HiddenStashVariant` | 113 | `TakeControlVariant` | | 16 | `ClientInDistressVariant` | 65 | `HitVariant` | 114 | `TakeDownVariant` | | 17 | `ConversationVariant` | 66 | `HuntForPsychoVariant` | 115 | `TarotVariant` | | 18 | `ConvoyVariant` | 67 | `ImportantInteractionVariant` | 116 | `TechieVariant` | | 19 | `CoolVariant` | 68 | `InvalidVariant` | 117 | `ThieveryVariant` | | 20 | `CourierVariant` | 69 | `JackInVariant` | 118 | `UseVariant` | | 21 | `CustomPositionVariant` | 70 | `JamWeaponVariant` | 119 | `VehicleVariant` | | 22 | `CyberspaceNPC` | 71 | `LifepathCorpoVariant` | 120 | `WanderingMerchantVariant` | | 23 | `CyberspaceObject` | 72 | `LifepathNomadVariant` | 121 | `Zzz01_CarForPurchaseVariant` | | 24 | `DefaultInteractionVariant` | 73 | `LifepathStreetKidVariant` | 122 | `Zzz02_MotorcycleForPurchaseVariant` | | 25 | `DefaultQuestVariant` | 74 | `LootVariant` | 123 | `Zzz03_MotorcycleVariant` | | 26 | `DefaultVariant` | 75 | `MinorActivityVariant` | 124 | `Zzz04_PreventionVehicleVariant` | | 27 | `DistractVariant` | 76 | `NPCVariant` | 125 | `Zzz05_ApartmentToPurchaseVariant` | | 28 | `DropboxVariant` | 77 | `NetrunnerAccessPointVariant` | 126 | `Zzz06_NCPDGigVariant` | | 29 | `DynamicEventVariant` | 78 | `NetrunnerSoloTechieVariant` | 127 | `Zzz07_PlayerStashVariant` | | 30 | `EffectAlarmVariant` | 79 | `NetrunnerSoloVariant` | 128 | `Zzz08_WardrobeVariant` | | 31 | `EffectControlNetworkVariant` | 80 | `NetrunnerTechieVariant` | 129 | `Zzz09_CourierSandboxActivityVariant` | | 32 | `EffectControlOtherDeviceVariant` | 81 | `NetrunnerVariant` | 130 | `Zzz10_RemoteControlDrivingVariant` | | 33 | `EffectControlSelfVariant` | 82 | `NonLethalTakedownVariant` | 131 | `Zzz11_RoadBlockadeVariant` | | 34 | `EffectCutPowerVariant` | 83 | `OffVariant` | 132 | `Zzz12_QuickHackQueueVariant` | | 35 | `EffectDistractVariant` | 84 | `OpenVendorVariant` | 133 | `Zzz12_WorldEncounterVariant` | | 36 | `EffectDropPointVariant` | 85 | `OutpostVariant` | 134 | `Zzz13_DogtownGateVariant` | | 37 | `EffectExplodeLethalVariant` | 86 | `PhoneCallVariant` | 135 | `Zzz14_ServicePointBlackMarketVariant` | | 38 | `EffectExplodeNonLethalVariant` | 87 | `QuestGiverVariant` | 136 | `Zzz15_QuickHackDurationVariant` | | 39 | `EffectFallVariant` | 88 | `QuestionMarkVariant` | 137 | `Zzz16_RelicDeviceBasicVariant` | | 40 | `EffectGrantInformationVariant` | 89 | `QuickHackVariant` | 138 | `Zzz16_RelicDeviceSpecialVariant` | | 41 | `EffectHideBodyVariant` | 90 | `ReflexesVariant` | 139 | `Zzz17_NCARTVariant` | | 42 | `EffectLootVariant` | 91 | `ResourceVariant` | 140 | `Zzz18_RacingVariant` | | 43 | `EffectOpenPathVariant` | 92 | `RetrievingVariant` | 141 | `Zzz19_DelamainTaxiVariant` | | 44 | `EffectPushVariant` | 93 | `SOSsignalVariant` | 142 | `Zzz20_DelamainTaxiDestinationVariant` | | 45 | `EffectServicePointVariant` | 94 | `SabotageVariant` | 143 | `CPO_PingDoorVariant` | | 46 | `EffectShootVariant` | 95 | `ServicePointBarVariant` | 144 | `CPO_PingGoHereVariant` | | 47 | `EffectSpreadGasVariant` | 96 | `ServicePointClothesVariant` | 145 | `CPO_PingLootVariant` | | 48 | `EffectStoreItemsVariant` | 97 | `ServicePointCyberwareVariant` | 146 | `CPO_RemotePlayerVariant` | A variant existing in the enum does not guarantee its profile renders on every surface. The `CPO_*` variants, for instance, come from a dormant multiplayer HUD and must be checked visually in the server's context. ## Colour, size, text, and tracking `gamemappinsMappinData` carries neither colour nor scale. Those properties belong to the UI/TweakDB profile the game picks. The API therefore offers no fake `color` or `scale` that would do nothing. `title` and `description` are kept in CyberM's private mappin data. The fullscreen-map tooltip reads those values after vanilla setup, so a highlighted blip can display guaranteed free-form text such as `Job Center` and a multiline description. Limits are 128 and 1024 UTF-8 bytes respectively. The HUD does not permanently draw that text next to the icon. Custom PNG icons are not converted into `gamedataMappinVariant` values. CyberM keeps the native mappin and its declared icon metadata, but 2.31 renders only the native sprite for stability. WebP and runtime REDengine archive mounting are not supported. The native system can clear the current tracking and set an alternative, but offers no safe `TrackMappin(id)`. The world map tracks a UI controller, not a raw id. `untrack(id)` therefore checks that the requested mappin really is the tracked one before doing anything; it cannot remove a vanilla objective. --- Source: https://open2077.net/docs/interactions # Contextual world interactions `cyberm_interactions` is the shared client service for contextual actions attached to a world position or a streamed CyberM entity. It projects the target through REDengine's active camera and draws a transparent WebUI marker at the corresponding screen position. At `markerDistance` the player sees only the world point and its distance; once they enter `distance` and look at the point, the marker expands into the custom action card. The service then reads an allowlisted action key and emits a local event owned by the calling resource. This is not Cyberpunk's native interaction prompt. The point, distance label, action card, colours, copy and hold progress are rendered by the package WebUI while the target remains anchored to its 3D world position. The prompt is fully data-driven. `Utiliser` is only an example: labels such as `Parler à Jackie`, `Consulter les offres`, `Ouvrir le coffre`, or `Réparer le véhicule` are accepted, together with a custom description, key, short icon, colour, press/hold behavior, and up to four choices. ## Add the dependency ```lua resource "jobs" version "1.0.0" dependency "cyberm_interactions >=0.1.0" client_script "client/main.lua" ``` Add `permission "network.events"` only when the client handler itself calls `TriggerServerEvent`. The interaction service cannot send a server event on another resource's behalf. Exports are asynchronous because every resource has an isolated Lua VM. Call them from a `CreateThread` and await the returned promise: ```lua local interaction CreateThread(function() local promise, callError = CyberM.exports.call("cyberm_interactions", "create", { id = "job_center", position = { x = -1464.7, y = -124.3, z = 6.2 }, distance = 2.2, markerDistance = 12.0, marker = "arrow", markerScale = 1.0, markerNearScale = 2.0, markerAnimated = true, label = "Consulter les offres", description = "Pôle emplois de Night City", key = "E", icon = "JOB", color = "#FFD84A", event = "jobs:open", data = { office = "city_center" }, }) assert(promise, callError) local result, awaitError = promise:await() assert(result and result.ok, awaitError or (result and result.error)) interaction = result.handle end) AddEventHandler("jobs:open", function(context) print(context.interactionId, context.choiceId, context.distance) end) ``` The service obtains the calling resource and its generation from the runtime. A resource cannot forge an owner name, update another resource's handles, or retain stale handles after a restart. Stopped owners are swept automatically. ## Attach to a player or NPC `entity` accepts the same opaque CyberM entity handle as `CyberM.character.state`. Keep a 64-bit handle as returned; do not pass it through `tonumber`. ```lua local npcEntity = CyberM.npcs.entity(npcId) if npcEntity then CreateThread(function() local promise = assert(CyberM.exports.call("cyberm_interactions", "create", { id = "talk_to_receptionist", entity = npcEntity, offset = { x = 0.0, y = 0.0, z = 1.85 }, distance = 2.5, label = "Parler à la réceptionniste", description = "Demander un rendez-vous", key = "F", icon = "DIALOG", event = "clinic:reception", })) local result = promise:await() assert(result and result.ok, result and result.error) end) end ``` An entity interaction disappears while its entity is not streamed and follows its rendered world position when it returns. Create it after `CyberM.npcs.isStreamedIn(npcId)` becomes true, or update it with the new local entity handle after a stream-out/stream-in cycle. ## Multiple custom actions and hold ```lua local promise = CyberM.exports.call("cyberm_interactions", "create", { id = "apartment_door", position = { x = -1448.2, y = 96.1, z = 17.5 }, distance = 2.0, priority = 20, choices = { { id = "knock", label = "Frapper à la porte", description = "Prévenir les occupants", key = "E", icon = "DOOR", color = "#00E5FF", event = "apartment:knock", }, { id = "force", label = "Forcer la serrure", description = "Maintenir pendant 1,5 seconde", key = "G", icon = "LOCK", color = "#FFD84A", holdSeconds = 1.5, event = "apartment:forceLock", data = { difficulty = 4 }, }, }, }) ``` Keys must be unique inside one interaction. Supported keys are `A`–`Z`, `0`–`9`, `SPACE`, `ENTER`/`RETURN`, and the four arrow keys. Input is suppressed whenever another WebUI owns keyboard focus, so typing in chat cannot trigger a world action. ## Updating and removing ```lua local function call(name, ...) local promise, reason = CyberM.exports.call("cyberm_interactions", name, ...) assert(promise, reason) return promise:await() end CreateThread(function() assert(call("setVisible", interaction, false).ok) assert(call("update", interaction, { label = "Le guichet est fermé", description = "Revenez à 08:00", color = "#FF4D5A", }).ok) assert(call("setVisible", interaction, true).ok) local current = call("get", interaction) local owned = call("all") assert(call("remove", interaction).ok) -- call("clear") removes every interaction owned by this resource. end) ``` `setEnabled(false)` suspends every interaction owned by the caller without affecting other resources. `isEnabled()` returns that caller-specific state. ## Definition reference | Field | Meaning | |---|---| | `id` | Stable owner-local ID, maximum 96 characters. Generated when omitted. | | `position` | Static `{ x, y, z }` target. Exactly one of `position` or `entity` is required. | | `entity` | Streamed CyberM entity handle followed through `CyberM.character.state`. | | `offset` | World offset from the position/entity origin; defaults to zero. | | `distance` | Activation radius, 0.25–25 m; defaults to 2.5 m. | | `markerDistance` | Maximum marker display distance, from `distance` to 250 m; defaults to at least 12 m. Only the winning interaction is rendered. | | `showDistance` | Backward-compatible alias of `markerDistance`. | | `marker` | WebUI motif: `dot` (default), `ring`, `diamond`, `arrow`, `chevron`, `exclamation`, `info`, `vehicle` (`car` alias), `person`, `door`, or `shop`. `arrow` points down toward the projected world position. | | `markerScale` | Marker scale from 0.6 to 2.0; defaults to 1.0. | | `markerNearScale` | Proximity multiplier from 1.0 to 4.0; defaults to 2.0. The marker progressively grows from `markerScale` at `markerDistance` to this multiplier at interaction range. | | `markerAnimated` | Enables the marker's subtle vertical animation; defaults to `true`. | | `requireLookAt` | Requires the projection to be close to the screen centre; defaults to `true`. | | `focusRadius` | Normalized screen-centre radius, 0.02–1.0; defaults to 0.18. | | `priority` | Tie-breaker from -1000 to 1000; higher wins. | | `visible` | Presentation flag; defaults to `true`. | | `cooldown` | Client presentation debounce in seconds, 0–60. Never use it as server security. | | `label`, `description`, `key`, `icon`, `color`, `event`, `data`, `holdSeconds` | Single-choice shorthand. | | `choices` | Array of 1–4 complete choice records; replaces the shorthand. | Choice labels are arbitrary UTF-8 text up to 96 bytes, descriptions up to 160 bytes, and icons are short textual marks up to 12 bytes. Colours use `#RRGGBB`. Events and IDs use letters, numbers, underscore, colon, dash, and dot. The arbiter renders one target at a time. An active target wins over a merely visible one, then `priority`, then distance. This prevents overlapping cards from fighting each other every frame. ## Event payload and server authority Every selected choice emits its custom `event` and the common `cyberm:interaction` event with: ```lua { interactionId = "job_center", handle = 1, owner = "jobs", choiceId = "primary", key = "E", position = { x = 0, y = 0, z = 0 }, distance = 1.4, data = {}, interactionData = {}, } ``` This payload is client presentation evidence, not authority. If an action changes shared state, the owner may submit only the minimum intent: ```lua -- client/main.lua; manifest requires network.events AddEventHandler("jobs:open", function(context) TriggerServerEvent("jobs:requestOpen", context.interactionId) end) -- server/main.lua RegisterNetEvent("jobs:requestOpen", function(interactionId) local playerId = source -- authenticated by CyberM; never accept it from the payload if interactionId ~= "job_center" then return end local position = CyberM.players.position(playerId) if not position then return end -- Recheck routing bucket, distance, role/ACL, cooldown, and authoritative -- job-centre state here before opening or mutating anything. TriggerClientEvent("jobs:openMenu", playerId, { office = "city_center" }) end) ``` The WebUI never receives input focus and builds all copy with DOM `textContent`; labels cannot inject HTML. The service intentionally does not claim line-of-sight or server-side proximity. --- Source: https://open2077.net/docs/notifications # WebUI notifications `cyberm_notifications` is the shared toast service for CyberM resources. It provides a FiveM-style notification API without coupling gameplay packages to their own browser surface. Notifications can originate locally or from an authoritative server resource and are always owned by their caller. The WebUI is transparent and never captures input. Copy is inserted with DOM `textContent`, queues are bounded, and notifications disappear automatically when their owner stops or reloads. ## Add the dependency ```lua resource "jobs" version "1.0.0" dependency "cyberm_notifications >=1.0.0" client_script "client/main.lua" server_script "server/main.lua" ``` Exports cross isolated Lua VMs and therefore return a promise. Call them from a scheduler coroutine. ## Local client notification ```lua CreateThread(function() local promise, callError = CyberM.exports.call("cyberm_notifications", "show", { id = "job_started", type = "success", title = "Mission acceptee", message = "Rendez-vous au garage de Kabuki.", icon = "JOB", position = "middle_left", durationMs = 5000, progress = true, color = "#54E38E", data = { mission = "garage_intro" }, }) assert(promise, callError) local result, awaitError = promise:await() assert(result and result.ok, awaitError or (result and result.error)) print("notification handle", result.handle) end) ``` Supported types are `info`, `success`, `warning`, and `error`. Each type supplies a default colour; `color` overrides it with a `#RRGGBB` value. ## Update, dismiss, and clear ```lua local function notifications(name, ...) local promise, reason = CyberM.exports.call("cyberm_notifications", name, ...) assert(promise, reason) return promise:await() end CreateThread(function() local shown = notifications("show", { id = "download", type = "info", title = "Synchronisation", message = "Telechargement des donnees...", durationMs = 0, -- persistent until update/dismiss/clear progress = false, }) Wait(3000) notifications("update", shown.handle, { type = "success", message = "Synchronisation terminee.", durationMs = 3500, progress = true, }) -- notifications("dismiss", shown.handle) -- notifications("clear") removes every toast owned by this resource. end) ``` `setEnabled(false)` clears and suppresses the caller's notifications. `list()` returns that caller's active entries; resources cannot inspect, update, or dismiss another owner's handles. ## Server-targeted notification Server resources use the owner-aware API built into the server Lua runtime. The resource name is attached by the runtime; scripts cannot impersonate another owner: ```lua RegisterNetEvent("jobs:completed", function(jobId) local playerId = source -- Validate the authoritative job state before notifying the player. local id, reason = CyberM.notifications.send(playerId, { type = "success", title = "Mission terminee", message = "Votre paiement a ete transfere.", icon = "E$", durationMs = 6000, position = "middle_left", }) assert(id, reason) end) ``` Server methods are: | Method | Purpose | |---|---| | `CyberM.notifications.send(playerId, definition)` | Send to one authenticated session ID and return its owner-local ID. | | `CyberM.notifications.broadcast(definition)` | Send to every connected player. | | `CyberM.notifications.update(id, patch)` | Update a notification previously returned by this server resource. | | `CyberM.notifications.dismiss(id)` | Remove one notification owned by this server resource. | | `CyberM.notifications.clear([playerId])` | Clear this owner's notifications for one player or everyone. | Server IDs are owner-scoped. Client resources never receive an API that can forge a server-owned toast. Server records expire with timed notifications and are cleared when their owner stops. ## Definition reference | Field | Meaning | |---|---| | `id` | Optional stable owner-local ID, maximum 96 characters. | | `replace` | Replace an existing notification with the same `id` when `true`. | | `type` / `kind` | `info`, `success`, `warning`, or `error`; defaults to `info`. | | `title` | Optional heading, maximum 96 UTF-8 bytes. | | `message` / `text` | Required body, maximum 384 UTF-8 bytes. | | `icon` | Optional short textual badge, maximum 16 UTF-8 bytes. | | `position` | `middle_left` (default), `top_left`, `top_center`, `top_right`, `bottom_left`, `bottom_center`, or `bottom_right`. | | `durationMs` / `duration` | Lifetime in milliseconds. `0` is persistent; timed values are 750-120000. | | `progress` | Shows the lifetime bar when timed; defaults to `true`. | | `color` | Optional `#RRGGBB` accent override. | | `data` | Caller-owned serializable context returned by the removal event. | The client holds at most 32 notifications and at most eight per position. Adding a ninth toast to a position evicts its oldest toast. Only the notification owner can mutate its entries. ## Events and test command `cyberm:notificationRemoved` is emitted locally with `handle`, `id`, `owner`, `reason`, and `data`. Removal reasons include `expired`, `dismissed`, `queue_limit`, `owner_stopped`, and server cleanup. Authenticated administrators can validate the complete server-to-client route with: ```text /notification.test success /notification.test warning /notification.test error ``` --- Source: https://open2077.net/docs/effects # Visual and audio effects Client Lua resources can trigger REDengine world VFX, entity-authored VFX, and spatialised audio with the `world.effects` permission. Every returned handle is owned by the calling resource. CyberM stops and releases it on `stop`, resource reload, world exit, or plugin unload. ```lua permissions { "world.effects" } ``` ## World VFX ```lua local smoke, reason = CyberM.vfx.play("smoke.steam", { position = { x = -1440.0, y = 130.0, z = 18.0 }, orientation = { x = 0.0, y = 0.0, z = 0.0, w = 1.0 }, ignoreTimeDilation = false, duration = 15.0, }) assert(smoke, reason) assert(CyberM.vfx.stop(smoke)) ``` The first argument accepts a curated alias returned by `CyberM.vfx.catalog()` or a cooked `base\\...\\name.effect`/`dlc\\...\\name.effect` path. A raw path is advanced and build-dependent: the file being present does not guarantee that the effect is safe, visible, looped, or meaningful outside its original quest/entity context. Curated aliases currently include `explosion.frag`, `fire.small`, `smoke.steam`, `smoke.ambient`, `electric.destruction`, `impact.default`, and `impact.concrete`. `duration` is optional: `0` keeps the handle until explicit/resource cleanup; the accepted range is 0–600 seconds. A resource owns at most 64 effects and the client holds at most 256. ## Entity-authored VFX Some effects are names authored by an entity template rather than depot paths—weapon muzzle flashes are a common example: ```lua local flash = CyberM.vfx.playEntity("muzzle_flash", { entity = remotePuppetId, -- decimal-string CyberM entity id; omitted = local player instance = "shot_42", persistOnDetach = false, breakAllLoops = true, breakAllOnDestroy = true, duration = 0.15, }) ``` The effect name must exist on that entity's template. CyberM queues `entSpawnEffectEvent`; stopping queues `entKillEffectEvent`. An unknown authored name normally produces no visual result rather than a Lua error. ## Spatialised SFX ```lua local sound, reason = CyberM.sfx.play("event_name_from_catalog", { entity = remotePuppetId, -- emitter entity; omitted = local player emitter = "", -- optional authored emitter name tag = "my_resource", seekTime = 0.0, unique = true, duration = 8.0, }) assert(sound, reason) assert(CyberM.sfx.stop(sound)) ``` Audio is attached to an existing entity and therefore follows it in 3D. `stop` queues `SoundStopEvent` for the same event name. Because REDengine stopping is name-based, two simultaneous identical events on the same entity may be stopped together; use `unique = true` where the Wwise event supports it. ## Inspection and cleanup ```lua for _, effect in ipairs(CyberM.vfx.list()) do print(effect.id, effect.kind, effect.name, effect.entity, effect.remaining) end CyberM.vfx.clear() -- only this resource's VFX CyberM.sfx.clear() -- only this resource's SFX ``` Handles are decimal strings so their full 64-bit identity survives Lua number conversion. A resource cannot stop another resource's handle. ## Exhaustive references - [`docs/generated/vfx-assets-2.31.csv`](../docs/generated/vfx-assets-2.31.csv) lists all 1,070 `.effect` paths found in the local 2.31 cooked-archive inventory. - [`docs/generated/sfx-events-wolvenkit-seed.csv`](../docs/generated/sfx-events-wolvenkit-seed.csv) lists 17,586 distinct Wwise event names from 17,684 WolvenKit database rows. Its source declares game version 1.6; entries therefore require runtime validation on 2.31. These catalogues reference identifiers only. CyberM does not redistribute game assets or audio banks. --- Source: https://open2077.net/docs/chat # Chat, slash commands, and completion The official `cyberm_chat` package is documented in [`docs/chat.md`](../docs/chat.md). It provides English-only UI text, authenticated slash-command dispatch, automatic suggestion discovery, history, and keyboard completion. Quick usage: ```text T open chat Enter send or execute Escape close Arrow Up/Down select a suggestion while typing / Tab complete the selected command ``` Slash commands use the same server-side `RegisterCommand` and ACL path as the CyberM terminal; they are not chat messages and are never broadcast to other players. Built-in utility commands include: ```text /id show the temporary session player ID /pos copy the current world position as Lua /rot copy the current quaternion and yaw as Lua ``` `/pos` and `/rot` write only on the requesting client and display their result in chat and through the shared notification UI. See the [clipboard guide](clipboard.md) for the API, permission, output formats, limits, and failure reasons. --- Source: https://open2077.net/docs/clipboard # Clipboard API and transform commands CyberM exposes a write-only client API for copying generated text to the operating-system clipboard. It is intended for explicit user actions such as copying coordinates, identifiers, or configuration snippets. Lua resources cannot read or inspect the existing clipboard. ## Manifest permission Declare `clipboard.write` in the client resource that performs the write: ```lua resource "my_tools" version "1.0.0" client_script "client/main.lua" permission "clipboard.write" ``` The permission belongs to the resource whose client VM calls the API. A server resource cannot write directly to a player's clipboard. ## Write text ```lua local copied, reason = CyberM.clipboard.setText( "position = { x = 1660.068359, y = -723.649170, z = 50.512436 }" ) if not copied then print("Clipboard write failed: " .. tostring(reason)) end ``` `CyberM.clipboard.setText(text)` returns `true` on success. On refusal it returns `false, reason`. The text must be valid UTF-8, cannot contain an embedded NUL, and is limited to 256 KiB. Possible failure reasons include: - `permission_denied:clipboard.write` - `clipboard_text_too_large` - `clipboard_text_contains_nul` - `clipboard_invalid_utf8` - `clipboard_busy` - `clipboard_clear_failed` - `clipboard_allocation_failed` - `clipboard_lock_failed` - `clipboard_write_failed` - `clipboard_unavailable_on_this_host` The API is synchronous and should be called in response to a deliberate player action. If another desktop application temporarily owns the clipboard, report `clipboard_busy` and let the player retry instead of looping every frame. ## Built-in `/pos` and `/rot` commands The official chat resource provides two authenticated commands: ```text /pos /rot ``` `/pos` copies the local player's current world position: ```lua position = { x = 1660.068359, y = -723.649170, z = 50.512436 } ``` `/rot` copies the complete quaternion and the horizontal yaw: ```lua orientation = { x = 0.000000, y = 0.000000, z = 0.707107, w = 0.707107 }, yaw = 90.000000 ``` The command is registered on the server, then targets only the authenticated requesting client. The downloaded `cyberm_chat` client reads `CyberM.character.state()`, performs the clipboard write, and returns a bounded result. The server never receives the previous clipboard contents. Success or failure is shown both in chat and through a middle-left WebUI notification. This split is important for server packages: server network events are delivered to the active downloaded resource generation. A handler placed only in a protected bootstrap resource will not receive a normal server-resource event. ## Copy a character transform from your own resource The command implementation is only a convenience. A client resource can produce another format directly: ```lua local state, stateError = CyberM.character.state() if not state or not state.attached then print(stateError or "player_transform_unavailable") return end local p = state.position local q = state.orientation local text = string.format( "vec4(%.3f, %.3f, %.3f, %.3f) at vec3(%.3f, %.3f, %.3f)", q.x, q.y, q.z, q.w, p.x, p.y, p.z ) local copied, reason = CyberM.clipboard.setText(text) assert(copied, reason) ``` `state.position`, `state.orientation`, and `state.yaw` come from the same character snapshot, so the copied position and rotation describe one coherent sample. --- Source: https://open2077.net/docs/client-kvp # Client persistent KVP `CyberM.kvp` stores small client-local values persistently. Its namespace is always: ```text connection address -> resource name -> key ``` Connecting to `188.40.140.88:11777` and `localhost:11777` therefore creates two independent stores, even if both addresses reach the same machine. Resources cannot name or inspect another resource's namespace. ```lua local ok, reason = CyberM.kvp.set("character:lastSlot", 2) assert(ok, reason) local slot = CyberM.kvp.get("character:lastSlot", 1) local present = CyberM.kvp.has("character:lastSlot") local newCount = CyberM.kvp.increment("stats:connections", 1) ``` ## API | Method | Result | Description | |---|---|---| | `set(key, value)` | `true` or `false, reason` | Store a string, integer, finite number, or boolean. | | `get(key[, default])` | value/default, or `nil, reason` | Read the original Lua type. Missing keys are not errors. | | `has(key)` | boolean, optionally `reason` | Check whether the key exists. | | `delete(key)` | boolean, optionally `reason` | Delete a key and report whether it existed. | | `keys([prefix[, limit]])` | string array or `nil, reason` | Sorted prefix search; default limit is 256. | | `find([prefix[, limit]])` | entry array or `nil, reason` | Return `{ key, value, type }` records. | | `clear([prefix])` | removed count or `nil, reason` | Delete this resource's matching keys only. | | `increment(key[, delta])` | number or `nil, reason` | Atomically create/increment a numeric value. | | `setIfAbsent(key, value)` | boolean, optionally `reason` | Redis-style `SETNX`. | | `compareAndSet(key, expected, replacement)` | boolean, optionally `reason` | Atomic CAS. `nil` means missing for expected and deletion for replacement. | | `stats()` | table or `nil, reason` | Entry/byte usage, quotas, address, and resource namespace. | FiveM-familiar aliases are also available: `SetResourceKvp`, `GetResourceKvp`, and `DeleteResourceKvp`. New code should prefer `CyberM.kvp` because it exposes typed results and the atomic/search operations. ## Limits and persistence guarantees - Keys: 1-256 bytes, with no control characters. - String values: at most 64 KiB each. - Resource store: at most 4,096 entries and 1 MiB of key/value payload. - Files are committed through a same-directory temporary file and an atomic replace. - A versioned binary header and CRC32 reject truncated or corrupted files instead of silently replacing them. - Validation/preflight Lua states cannot write KVP data. Data is stored below `red4ext/plugins/CyberM/storage/kvp`. The connection address is reversibly hex-encoded before becoming a directory name, preventing path traversal without changing its namespace semantics. This is local persistence, not secret storage. The player owns the machine and can inspect or remove the files. Never store passwords, server tokens, private keys, or authoritative economy state in client KVP. Use the server database for anything that must resist client modification. --- Source: https://open2077.net/docs/data-reference # Game data reference This page is the entry point for identifiers passed to CyberM APIs: NPC templates, vehicle records, seat and damage indexes, weapons, appearances, effects, sounds, animations, and map sprites. The catalogues were extracted from Cyberpunk 2077 **2.31** unless another version is stated. ## Support levels Do not treat every identifier found in the game database as a supported multiplayer asset. | Level | Meaning | |---|---| | **CyberM-supported** | Exposed by a CyberM runtime catalogue or used by an official resource. Intended for normal resources. | | **Runtime-validated** | Resolved against the live 2.31 TweakDB or archives, but still requires an in-game spawn and cleanup test. | | **Extracted candidate** | Found in cooked data. Quest logic, missing dependencies, special rigs, or build drift can make it unsafe. | Record names and CyberM entity IDs are opaque values. Preserve their spelling and never pass a 64-bit entity ID through `tonumber`. ## NPC templates `CyberM.npcs.create` currently accepts the following server-approved aliases. Query the active runtime instead of hard-coding the list when building admin tools: ```lua for _, template in ipairs(CyberM.npcs.templates()) do print(template.name, template.record, template.observerRecord, template.defaultAppearance) end ``` | Supported alias | Authoritative record | Observer record | Intended use | |---|---|---|---| | `civilian_female_relaxed_01` | `Character.Panam` | `Character.Panam` | Non-hostile human with locomotion, look-at, workspot, and equipment capabilities. | | `hostile_female_ranged_lab` | `Character.cpz_maelstrom_grunt1_ranged1_lexington_wa` | same as authoritative record | Ranged hostile test puppet with the combat capability enabled. | The aliases are deliberately conservative. A raw `.ent` path or arbitrary `Character.*` record from the extracted database is **not** accepted by the authoritative NPC service until it has been promoted to the supported catalogue. ### Complete extracted NPC database | Dataset | Entries | Contents | |---|---:|---| | [NPC catalogue overview](../docs/generated/npc-templates-2.31.md) | 6,668 records / 1,524 templates | Categories, risk classes, and the complete template table. | | [Character records CSV](../docs/generated/npc-records-2.31.csv) | 6,668 | `Character.*`, TweakDBID, template, appearances, affiliation, equipment, vendor and quest metadata. | | [Templates CSV](../docs/generated/npc-templates-2.31.csv) | 1,524 | Records grouped by `.ent`, appearances, categories, gender, and risk. | | [Templates JSON](../docs/generated/npc-templates-2.31.json) | 1,524 | Machine-readable version for tooling. | | [Entity appearances CSV](../docs/generated/npc-entity-appearances-2.31.csv) | 1,524 | Direct/effective appearances, archive ownership, includes, and `.app` resources. | | [Appearance resources CSV](../docs/generated/npc-appearance-resources-2.31.csv) | 9,242 | Appearance resource, archive, appearance name, and parent. | Risk values in the NPC catalogue are actionable: prefer `candidate`, audit `special_rig` and `special_vendor`, and do not promote `unsafe_quest_or_scene`, `restricted_child`, `deny_player`, or `missing_template` without dedicated engine and gameplay validation. ## Vehicle models Vehicle creation takes a TweakDB record, not an entity template hash: ```lua local id = CyberM.vehicles.create( { record = "Vehicle.v_standard2_archer_hella_player", position = { x = 100.0, y = 200.0, z = 30.0 }, yaw = 90.0 } ) ``` Prefer `*_player` records. The [complete vehicle model catalogue](../docs/vehicle-models.md) contains 1,372 records with a non-zero `entityTemplatePath`, including **89 player/garage variants**. It also documents records that resolve structurally but should not be spawned. The official freeroam resource provides these convenient command aliases. The record in the right column is the portable value to store in another resource or database. | Alias | Vehicle record | Alias | Vehicle record | |---|---|---|---| | `hella` | `Vehicle.v_standard2_archer_hella_player` | `bandit` | `Vehicle.v_standard2_archer_bandit_player` | | `quartz` | `Vehicle.v_standard2_archer_quartz_player` | `caliburn` | `Vehicle.v_sport1_rayfield_caliburn_player` | | `mordred` | `Vehicle.v_sport1_rayfield_caliburn_mordred_player` | `aerondight` | `Vehicle.v_sport1_rayfield_aerondight_player` | | `outlaw` | `Vehicle.v_sport1_herrera_outlaw_player` | `turbo` | `Vehicle.v_sport1_quadra_turbo_player` | | `type66` | `Vehicle.v_sport2_quadra_type66_player` | `shion` | `Vehicle.v_sport2_mizutani_shion_player` | | `porsche` | `Vehicle.v_sport2_porsche_911turbo_player` | `alvarado` | `Vehicle.v_sport2_villefort_alvarado_player` | | `deleon` | `Vehicle.v_sport2_villefort_deleon_player` | `cortes` | `Vehicle.v_standard2_villefort_cortes_player` | | `colby` | `Vehicle.v_standard2_thorton_colby_player` | `galena` | `Vehicle.v_standard2_thorton_galena_player` | | `supron` | `Vehicle.v_standard25_mahir_supron_player` | `maimai` | `Vehicle.v_standard2_makigai_maimai_player` | | `hozuki` | `Vehicle.v_standard2_mizutani_hozuki_player` | `thrax` | `Vehicle.v_standard2_chevalier_thrax_player` | | `kusanagi` | `Vehicle.v_sportbike1_yaiba_kusanagi_player` | `arch` | `Vehicle.v_sportbike2_arch_player` | | `jackie` | `Vehicle.v_sportbike2_arch_jackie_player` | `apollo` | `Vehicle.v_sportbike3_brennan_apollo_player` | ### Vehicle seats, doors, windows, and state bits | Seat | Canonical name | FiveM-style index | |---|---|---:| | Driver | `seat_front_left` / `driver` | `-1` | | Front passenger | `seat_front_right` / `frontPassenger` | `0` | | Rear left | `seat_back_left` / `rearLeft` | `1` | | Rear right | `seat_back_right` / `rearRight` | `2` | | Index | Door name | Window name | |---:|---|---| | `0` | `frontLeft` or `front_left` | `frontLeft` | | `1` | `frontRight` or `front_right` | `frontRight` | | `2` | `backLeft` or `back_left` | `backLeft` | | `3` | `backRight` or `back_right` | `backRight` | | `4` | `trunk` | — | | `5` | `hood` | — | Doors use a 6-bit mask; windows and broken tires use 4-bit masks. Bit `n` corresponds to index `n`. The authoritative vehicle flags are: | Flag | Value | Flag | Value | |---|---:|---|---:| | `engineOn` | `1` | `locked` | `2` | | `destroyed` | `4` | `exploded` | `8` | | `invulnerable` | `16` | `immortal` | `32` | | `lightsOn` | `64` | `highBeams` | `128` | | `sirenOn` | `256` | | | Motion dynamics add `onGround = 1`, `reversing = 2`, and `hornActive = 4`. See [Vehicles](vehicles.md) for the authoritative API, damage arrays, glass/light masks, authority, and streaming semantics. ## NPC and elevator constants | NPC group | Values | |---|---| | AI mode | `tasks = 0`, `frozen = 1`, `native = 2`; `observer = 3` is protocol-only and rejected for creation/update. | | Damage policy | `mortal = 0`, `immortal = 1`, `invulnerable = 2` | | State flags | `alive = 1`, `ragdoll = 2`, `despawnWhenUnobserved = 4`, `persistent = 8` | | Task channel | `movement = 0`, `look = 1`, `action = 2`, `fullBody = 3` | | Task status | `queued = 0`, `suspended = 1`, `executing = 2`, `success = 3`, `failure = 4`, `cancelled = 5`, `interrupted = 6` | Elevator phases are `idle = 0`, `moving = 1`, and `paused = 2`. Elevator state flags are `powered = 1`, `locked = 2`, `interactionAllowed = 4`, and `doorsClosed = 8`. ## Items, weapons, effects, sounds, and animations | Dataset | Entries | Runtime confidence | |---|---:|---| | [Weapons and weapon items](../docs/generated/weapons-2.31.csv) | 1,925 | Extracted from 2.31 TweakDB; use the `canonical`, `deprecated`, `can_drop`, and `usage` columns to filter. | | [Canonical weapon notes](../docs/generated/weapons-2.31-canonical.md) | curated | Recommended records grouped for normal gameplay use. | | [VFX assets](../docs/generated/vfx-assets-2.31.csv) | 1,070 | Archive-discovered paths; individual runtime validation is still required. | | [SFX event seed](../docs/generated/sfx-events-wolvenkit-seed.csv) | 17,586 | WolvenKit 1.6 seed data; explicitly requires 2.31 runtime validation. | | [Animation names](../docs/data/emote-animations.txt) | 23,044 | Extracted animation name candidates. | | [Animation sets](../docs/data/emote-animsets.txt) | 4,690 | Animation-set resource paths. | | [Blip sprites](blips.md#complete-sprite-list) | complete CyberM list | Validated native sprite names exposed by the blip API. | For effects, prefer the runtime catalogue when available: ```lua local catalog, reason = CyberM.vfx.catalog() if catalog then for alias, path in pairs(catalog) do print(alias, path) end end ``` An extracted row becoming visible in a CSV does not grant a resource permission or make it safe. The calling resource still needs the relevant manifest permission, and server-owned gameplay state must always be created through the authoritative server API. ## Promotion checklist Before adding an extracted candidate to a production resource: 1. Resolve it on the exact supported game build. 2. Spawn it through CyberM with one client, then remove it cleanly. 3. Repeat with two clients and a late joiner in the same routing bucket. 4. Verify streaming out/in, resource stop, player disconnect, and server restart behavior. 5. Check animations, collision, audio, damage, and authority transfer where applicable. 6. Promote it to a small resource-owned allowlist instead of accepting arbitrary client strings. --- Source: https://open2077.net/docs/debug-runtime # Privileged in-game Lua laboratory CyberM includes an ACL-controlled development path for testing client Lua, native laboratory commands, and the existing REDscript polling bridge without rebuilding the plugin after every experiment. This is intentionally not a public gameplay API. It is available only inside the bundled local `cyberm_debug` resource. A downloaded server resource cannot enable it by adding a permission to its manifest. ## Admin command Run this from the in-game CyberM terminal or chat: ```text client.exec ``` The command is registered as restricted. The server checks the authenticated caller against ACL permission `command.client.exec`, sends the source to the one requested session ID, and correlates the reply with the original admin. The bundled owner ACL using `"permissions": ["*"]` already has access. Examples: ```text client.exec 1 return 6 * 7 client.exec 1 return CyberM.character.state() client.exec 1 return CyberM.debug.command('vehicle.list') client.exec 1 return CyberM.debug.command('vehicle.status 4294967297') client.exec 1 return CyberM.debug.command('vehicle.glass 4294967297 windows_front_left') client.exec 1 return CyberM.debug.redscript('debug.trace:hello') ``` Use single quotes inside the Lua expression because the server command tokenizer reconstructs the source from the remaining whitespace-separated arguments. ## Position and rotation clipboard commands Any authenticated player can copy their own live transform from chat: ```text /pos /rot ``` `/pos` writes a reusable Lua field such as `position = { x = -1442.200000, y = 127.400000, z = 18.000000 }`. `/rot` writes the complete quaternion plus horizontal yaw. The server command targets the authenticated caller, while the downloaded `cyberm_chat` client reads the transform and writes the clipboard. The server receives a bounded success result but never sees prior clipboard contents. The result appears in chat and in a middle-left WebUI notification. Ordinary client resources can use the same write-only API after declaring the permission: ```lua permission "clipboard.write" local ok, reason = CyberM.clipboard.setText("text copied by my resource") ``` See the [clipboard guide](clipboard.md) for limits, failure reasons, complete output formats, and the client/server routing model. ## Client debug namespace Only `cyberm_debug`, on the trusted local host, can successfully call these functions: ```lua local ok, result = CyberM.debug.eval("return CyberM.camera.view()", "camera-probe") local ok, result = CyberM.debug.command("vehicle.list") local ok, result = CyberM.debug.redscript("debug.trace:glass-probe") ``` - `eval(source, label?)` compiles a text-only Lua chunk in the existing `cyberm_debug` VM. Returned primitives and serializable tables are converted to bounded text. - `command(commandLine)` calls the registered native laboratory table directly on the game thread. It does not forward unknown commands to the server. The vehicle laboratory is registered here, including `vehicle.glass`, `vehicle.tire`, `vehicle.body`, `vehicle.part`, and repair operations. - `redscript(command)` queues an opaque command through `CyberMScriptBridge.reds`. REDscript polls and executes it from a genuine script frame. `debug.trace:` is the initial observable probe; further `debug.*` handlers can be added on the REDscript side without changing the C++ bridge. ## Safety and limits - ACL authorization happens before Lua source is dispatched. - Execution is targeted, never broadcast. - Source is limited to 32 KiB, result text to 8 KiB, and replies time out after 10 seconds. - Lua runs with the resource host's 32 MiB memory quota, 500,000-instruction resume quota, and 2 ms frame budget. Infinite loops fail with `CyberM script execution budget exceeded`. - The normal sandbox remains intact: no `io`, `os`, `debug`, `package`, `load`, bytecode, filesystem escape, raw REDengine pointer, or foreign resource global is exposed. - The server-distributed copy of `cyberm_debug` is excluded from the downloaded client host. Its server script still registers `client.exec`; only the trusted bundled client copy evaluates it. Keep `debug.runtime` out of ordinary resource manifests. If a deployment should not expose this laboratory at all, remove `cyberm_debug` from the server resource set or remove `command.client.exec` from every ACL principal. --- Source: https://open2077.net/docs/api # Lua API reference 258 registered functions across 38 namespaces, generated from the platform bindings. A name present in both runtimes is not the same function: the server entry is authoritative, the client entry is a local projection. --- Source: https://open2077.net/docs/api/server/cyberm-vehicles # CyberM.vehicles — server runtime Runs on the dedicated server and is authoritative: state written here is the truth every client is told about. 43 functions. ## all ```lua CyberM.vehicles.all([bucket]) ``` `NETWORK` — Uses the network backend. Lists authoritative server vehicles. Returns snapshots ordered by CyberM ID. An optional routing bucket filters the result; omitting it returns every vehicle visible to the resource. | Parameter | Type | Required | Default | |---|---|---|---| | `bucket` | `integer` | optional | — | Returns: `array of vehicle tables` Registered in `LuaResourceRuntime.cs` (line 2769) as `LuaResourceRuntime.Bootstrap`. ## breakAllGlass ```lua CyberM.vehicles.breakAllGlass(id, [count]) ``` `NETWORK` — Uses the network backend. Breaks a range of vehicle glass elements. Requires `world.vehicles`. Breaks the first `count` destructible-glass bits. The optional count defaults to all 32 and must be in 0..32. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `count` | `integer` | optional | `32` | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2712) as `LuaResourceRuntime.Bootstrap`. ## breakGlass ```lua CyberM.vehicles.breakGlass(id, glass) ``` `NETWORK` — Uses the network backend. Breaks one vehicle glass element. Requires `world.vehicles`. Convenience wrapper over `setGlassBroken(id, glass, true)`; the canonical bit is replicated and retained for late joiners. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `glass` | `integer|string` | required | — | Returns: `boolean success` ```lua CyberM.vehicles.breakGlass(vehicleId, 0) ``` Registered in `LuaResourceRuntime.cs` (line 2710) as `LuaResourceRuntime.Bootstrap`. ## breakLight ```lua CyberM.vehicles.breakLight(id, index) ``` `NETWORK` — Uses the network backend. Breaks one vehicle light. Requires `world.vehicles`. Convenience wrapper over `setLightBroken(id, index, true)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `index` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2719) as `LuaResourceRuntime.Bootstrap`. ## breakTire ```lua CyberM.vehicles.breakTire(id, index) ``` `NETWORK` — Uses the network backend. Breaks one vehicle tire. Requires `world.vehicles`. Convenience wrapper over `setTireBroken(id, index, true)`. Tire indexes are 0..3. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `index` | `integer` | required | — | Returns: `boolean success` ```lua CyberM.vehicles.breakTire(vehicleId, 0) ``` Registered in `LuaResourceRuntime.cs` (line 2724) as `LuaResourceRuntime.Bootstrap`. ## closeDoor ```lua CyberM.vehicles.closeDoor(id, door) ``` `NETWORK` — Uses the network backend. Closes a door, trunk, or hood. Requires `world.vehicles`. Convenience wrapper over `setDoorOpen(id, door, false)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `door` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2737) as `LuaResourceRuntime.Bootstrap`. ## closeWindow ```lua CyberM.vehicles.closeWindow(id, window) ``` `NETWORK` — Uses the network backend. Closes one side window. Requires `world.vehicles`. Convenience wrapper over `setWindowOpen(id, window, false)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `window` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2747) as `LuaResourceRuntime.Bootstrap`. ## create ```lua CyberM.vehicles.create(definition) ``` `NETWORK` — Uses the network backend. Creates a server-owned network vehicle. Requires `world.vehicles`. The definition selects the record, transform, routing bucket, appearance, colors, flags, health, and optional initial damage. The server allocates the CyberM ID and replicates the canonical vehicle to interested clients. | Parameter | Type | Required | Default | |---|---|---|---| | `definition` | `table` | required | — | Returns: `vehicle ID, or `nil, reason`` ```lua local id, reason = CyberM.vehicles.create({ record = "Vehicle.v_standard2_thorton_galena_player", position = { x = -1671.2, y = -710.3, z = 49.9 }, yaw = 90.0, }) ``` Registered in `LuaResourceRuntime.cs` (line 2677) as `LuaResourceRuntime.Bootstrap`. ## damageBodyCell ```lua CyberM.vehicles.damageBodyCell(id, cell, amount) ``` `NETWORK` — Uses the network backend. Adds damage to one body cell. Requires `world.vehicles`. Adds the amount to the current normalized cell and clamps the result to 0..1. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `cell` | `integer` | required | — | | `amount` | `number` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2697) as `LuaResourceRuntime.Bootstrap`. ## damageBodyZone ```lua CyberM.vehicles.damageBodyZone(id, zone, amount) ``` `NETWORK` — Uses the network backend. Adds damage across a body zone. Requires `world.vehicles`. Adds the amount to each selected body cell and clamps every result to 0..1. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `zone` | `string|table` | required | — | | `amount` | `number` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2703) as `LuaResourceRuntime.Bootstrap`. ## get ```lua CyberM.vehicles.get(id) ``` `NETWORK` — Uses the network backend. Returns one authoritative server vehicle snapshot. Reads canonical identity, transform, flags, colors, damage, openings, occupants, and authority state. Returns `nil` for an unknown ID. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `vehicle table, or `nil`` Registered in `LuaResourceRuntime.cs` (line 2768) as `LuaResourceRuntime.Bootstrap`. ## getDamage ```lua CyberM.vehicles.getDamage(id) ``` `NETWORK` — Uses the network backend. Returns the canonical damage snapshot. Reads the server-owned body grid and broken glass, light, and tire masks. It returns `nil` when the vehicle ID is unknown. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `damage table, or `nil`` Registered in `LuaResourceRuntime.cs` (line 2693) as `LuaResourceRuntime.Bootstrap`. ## getDamageProfile ```lua CyberM.vehicles.getDamageProfile(record) ``` `NETWORK` — Uses the network backend. Returns a resource-local vehicle damage profile. Reads the profile registered by the current server resource for the specified vehicle record. Profiles are not shared implicitly between resources. | Parameter | Type | Required | Default | |---|---|---|---| | `record` | `string` | required | — | Returns: `profile table, or `nil`` Registered in `LuaResourceRuntime.cs` (line 2758) as `LuaResourceRuntime.Bootstrap`. ## isDoorOpen ```lua CyberM.vehicles.isDoorOpen(id, door) ``` `NETWORK` — Uses the network backend. Reads one canonical door opening state. Server-side authoritative query covering four doors, trunk, and hood. Returns `nil` for an unknown vehicle ID. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `door` | `integer` | required | — | Returns: `boolean, or `nil`` Registered in `LuaResourceRuntime.cs` (line 2738) as `LuaResourceRuntime.Bootstrap`. ## isWindowOpen ```lua CyberM.vehicles.isWindowOpen(id, window) ``` `NETWORK` — Uses the network backend. Reads one canonical side-window opening state. Server-side authoritative query for indexes 0..3. It does not report broken glass and returns `nil` for an unknown vehicle. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `window` | `integer` | required | — | Returns: `boolean, or `nil`` Registered in `LuaResourceRuntime.cs` (line 2748) as `LuaResourceRuntime.Bootstrap`. ## openDoor ```lua CyberM.vehicles.openDoor(id, door) ``` `NETWORK` — Uses the network backend. Opens a door, trunk, or hood. Requires `world.vehicles`. Convenience wrapper over `setDoorOpen(id, door, true)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `door` | `integer` | required | — | Returns: `boolean success` ```lua CyberM.vehicles.openDoor(vehicleId, CyberM.vehicles.doors.trunk) ``` Registered in `LuaResourceRuntime.cs` (line 2736) as `LuaResourceRuntime.Bootstrap`. ## openWindow ```lua CyberM.vehicles.openWindow(id, window) ``` `NETWORK` — Uses the network backend. Opens one side window. Requires `world.vehicles`. Convenience wrapper over `setWindowOpen(id, window, true)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `window` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2746) as `LuaResourceRuntime.Bootstrap`. ## registerDamageProfile ```lua CyberM.vehicles.registerDamageProfile(record, profile) ``` `NETWORK` — Uses the network backend. Registers resource-local named damage zones and glass parts. Requires `world.vehicles`. Profiles are scoped to the calling server resource VM and can extend or override the default body-zone mapping for one vehicle record. | Parameter | Type | Required | Default | |---|---|---|---| | `record` | `string` | required | — | | `profile` | `table` | required | — | Returns: ``true`` Registered in `LuaResourceRuntime.cs` (line 2753) as `LuaResourceRuntime.Bootstrap`. ## remove ```lua CyberM.vehicles.remove(id) ``` `NETWORK` — Uses the network backend. Removes a server-owned network vehicle. Requires `world.vehicles`. Only the resource that created the vehicle may remove it. Removal clears occupancy and authority before notifying streamed clients. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2767) as `LuaResourceRuntime.Bootstrap`. ## repair ```lua CyberM.vehicles.repair(id, [scope]) ``` `NETWORK` — Uses the network backend. Repairs a selected vehicle damage scope. Requires `world.vehicles`. Supported scopes are `glass`, `body`, `lights`, `tires`, `visual`, `mechanical`, and `full`. The default is `full`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `scope` | `string` | optional | `full` | Returns: `boolean success` ```lua CyberM.vehicles.repair(vehicleId, "visual") ``` Registered in `LuaResourceRuntime.cs` (line 2752) as `LuaResourceRuntime.Bootstrap`. ## repairAllGlass ```lua CyberM.vehicles.repairAllGlass(id) ``` `NETWORK` — Uses the network backend. Repairs all vehicle glass. Requires `world.vehicles`. Clears the complete canonical broken-glass mask. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2716) as `LuaResourceRuntime.Bootstrap`. ## repairAllLights ```lua CyberM.vehicles.repairAllLights(id) ``` `NETWORK` — Uses the network backend. Repairs every vehicle light. Requires `world.vehicles`. Clears the complete canonical broken-light mask. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2721) as `LuaResourceRuntime.Bootstrap`. ## repairAllTires ```lua CyberM.vehicles.repairAllTires(id) ``` `NETWORK` — Uses the network backend. Repairs all four vehicle tires. Requires `world.vehicles`. Clears the complete canonical broken-tire mask. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2726) as `LuaResourceRuntime.Bootstrap`. ## repairBodyCell ```lua CyberM.vehicles.repairBodyCell(id, cell) ``` `NETWORK` — Uses the network backend. Repairs one body cell. Requires `world.vehicles`. Sets the selected 1-based body cell to zero damage and replicates the repaired state. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `cell` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2701) as `LuaResourceRuntime.Bootstrap`. ## repairBodyZone ```lua CyberM.vehicles.repairBodyZone(id, zone) ``` `NETWORK` — Uses the network backend. Repairs every body cell in a zone. Requires `world.vehicles`. Clears all cells selected by a registered zone name or explicit index array. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `zone` | `string|table` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2704) as `LuaResourceRuntime.Bootstrap`. ## repairGlass ```lua CyberM.vehicles.repairGlass(id, glass) ``` `NETWORK` — Uses the network backend. Repairs one vehicle glass element. Requires `world.vehicles`. Convenience wrapper over `setGlassBroken(id, glass, false)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `glass` | `integer|string` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2711) as `LuaResourceRuntime.Bootstrap`. ## repairLight ```lua CyberM.vehicles.repairLight(id, index) ``` `NETWORK` — Uses the network backend. Repairs one vehicle light. Requires `world.vehicles`. Convenience wrapper over `setLightBroken(id, index, false)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `index` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2720) as `LuaResourceRuntime.Bootstrap`. ## repairTire ```lua CyberM.vehicles.repairTire(id, index) ``` `NETWORK` — Uses the network backend. Repairs one vehicle tire. Requires `world.vehicles`. Convenience wrapper over `setTireBroken(id, index, false)`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `index` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2725) as `LuaResourceRuntime.Bootstrap`. ## setBodyCell ```lua CyberM.vehicles.setBodyCell(id, cell, value) ``` `NETWORK` — Uses the network backend. Sets one body-damage cell. Requires `world.vehicles`. Lua body-cell indexes are 1..30 and the value is clamped or validated in the normalized 0..1 range. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `cell` | `integer` | required | — | | `value` | `number` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2696) as `LuaResourceRuntime.Bootstrap`. ## setBodyDamage ```lua CyberM.vehicles.setBodyDamage(id, values) ``` `NETWORK` — Uses the network backend. Replaces the complete body-damage grid. Requires `world.vehicles`. The table must contain exactly 30 normalized finite values in the range 0..1. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `values` | `table` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2695) as `LuaResourceRuntime.Bootstrap`. ## setBodyZone ```lua CyberM.vehicles.setBodyZone(id, zone, value) ``` `NETWORK` — Uses the network backend. Sets all body cells in a zone. Requires `world.vehicles`. The zone may be a registered zone name or an explicit array of cell indexes. Every selected cell receives the normalized value. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `zone` | `string|table` | required | — | | `value` | `number` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2702) as `LuaResourceRuntime.Bootstrap`. ## setDamage ```lua CyberM.vehicles.setDamage(id, damage) ``` `NETWORK` — Uses the network backend. Replaces multiple canonical damage components at once. Requires `world.vehicles`. Accepts a combined damage table and validates body cells and bit masks before publishing one authoritative update. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `damage` | `table` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2694) as `LuaResourceRuntime.Bootstrap`. ## setDoorMask ```lua CyberM.vehicles.setDoorMask(id, mask) ``` `NETWORK` — Uses the network backend. Replaces the vehicle opening mask. Requires `world.vehicles`. The six-bit mask covers four doors, trunk, and hood. Valid values are 0..63. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `mask` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2727) as `LuaResourceRuntime.Bootstrap`. ## setDoorOpen ```lua CyberM.vehicles.setDoorOpen(id, door, opened) ``` `NETWORK` — Uses the network backend. Sets one door, trunk, or hood opening state. Requires `world.vehicles`. `door` is an index 0..5 or one of the constants in `CyberM.vehicles.doors`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `door` | `integer` | required | — | | `opened` | `boolean` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2732) as `LuaResourceRuntime.Bootstrap`. ## setGlassBroken ```lua CyberM.vehicles.setGlassBroken(id, glass, broken) ``` `NETWORK` — Uses the network backend. Sets or clears one broken-glass bit. Requires `world.vehicles`. `glass` may be a numeric 0..31 index or a name supplied by the resource's registered damage profile. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `glass` | `integer|string` | required | — | | `broken` | `boolean` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2706) as `LuaResourceRuntime.Bootstrap`. ## setGlassMask ```lua CyberM.vehicles.setGlassMask(id, mask) ``` `NETWORK` — Uses the network backend. Replaces the broken-glass bit mask. Requires `world.vehicles`. The 32-bit mask describes destructible glass records, not the four reversible side-window opening states. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `mask` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2705) as `LuaResourceRuntime.Bootstrap`. ## setLightBroken ```lua CyberM.vehicles.setLightBroken(id, index, broken) ``` `NETWORK` — Uses the network backend. Sets or clears one broken-light bit. Requires `world.vehicles`. The light index must be in 0..31. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `index` | `integer` | required | — | | `broken` | `boolean` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2718) as `LuaResourceRuntime.Bootstrap`. ## setLightMask ```lua CyberM.vehicles.setLightMask(id, mask) ``` `NETWORK` — Uses the network backend. Replaces the broken-light bit mask. Requires `world.vehicles`. Replaces the complete 32-bit canonical broken-light mask. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `mask` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2717) as `LuaResourceRuntime.Bootstrap`. ## setTireBroken ```lua CyberM.vehicles.setTireBroken(id, index, broken) ``` `NETWORK` — Uses the network backend. Sets or clears one broken tire. Requires `world.vehicles`. Mutates one tire index in 0..3 and replicates the canonical state to streamed observers. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `index` | `integer` | required | — | | `broken` | `boolean` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2723) as `LuaResourceRuntime.Bootstrap`. ## setTireMask ```lua CyberM.vehicles.setTireMask(id, mask) ``` `NETWORK` — Uses the network backend. Replaces the broken-tire bit mask. Requires `world.vehicles`. Only the lower four bits are valid and correspond to tire indexes 0..3. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `mask` | `integer` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2722) as `LuaResourceRuntime.Bootstrap`. ## setTransform ```lua CyberM.vehicles.setTransform(id, transform) ``` `NETWORK` — Uses the network backend. Moves a vehicle authoritatively. Requires `world.vehicles`. Updates position and yaw, revokes any active physics lease, and publishes the new canonical transform to current viewers. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `transform` | `table` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2760) as `LuaResourceRuntime.Bootstrap`. ## setWindowOpen ```lua CyberM.vehicles.setWindowOpen(id, window, opened) ``` `NETWORK` — Uses the network backend. Sets one reversible side-window opening state. Requires `world.vehicles`. This controls the four openable side windows and is separate from destructible broken-glass state. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `window` | `integer` | required | — | | `opened` | `boolean` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2742) as `LuaResourceRuntime.Bootstrap`. ## update ```lua CyberM.vehicles.update(id, patch) ``` `NETWORK` — Uses the network backend. Updates canonical durable vehicle fields. Requires `world.vehicles`. Applies only supplied fields, such as health, flags, colors, door/window/tire masks, body damage, broken glass, or broken lights. The authoritative result is persisted and replicated to current viewers and late joiners. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `patch` | `table` | required | — | Returns: `boolean success` Registered in `LuaResourceRuntime.cs` (line 2692) as `LuaResourceRuntime.Bootstrap`. --- Source: https://open2077.net/docs/api/client/globals # Globals — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 19 functions. ## AddEventHandler ```lua AddEventHandler(event, handler) ``` `SHARED` — Available without a live game instance. Listens for a local event. Registers a callback on the current resource's local event bus. The handler is owned by the current resource generation and is discarded automatically when that generation stops or reloads; it never receives network traffic unless the event was separately registered as a network event. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `handler id` Registered in `ResourceHost.cpp` (line 6490) as `LuaAddEventHandler`. ## ClearTimeout ```lua ClearTimeout(id) ``` `SHARED` — Available without a live game instance. Cancels a timer created by `SetTimeout`. Cancels a pending timeout owned by the current resource generation. It returns `false` when the id is unknown or the callback has already begun; cancelling cannot interrupt a callback that is currently running. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6489) as `LuaClearTimeout`. ## CreateThread ```lua CreateThread(body) ``` `SHARED` — Available without a live game instance. Starts a coroutine managed by the host. Its body may call `Wait`, which an ordinary function cannot. | Parameter | Type | Required | Default | |---|---|---|---| | `body` | `function` | required | — | ```lua CreateThread(function() while true do print(CyberM.character.speed()) Wait(1000) end end) ``` Registered in `ResourceHost.cpp` (line 6486) as `LuaCreateThread`. ## DeleteResourceKvp ```lua DeleteResourceKvp(key) ``` `SHARED` — Available without a live game instance. FiveM-style alias for `CyberM.kvp.delete`. FiveM-familiar alias for `CyberM.kvp.delete`. It atomically removes only the named key owned by the calling resource and reports whether that key existed. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6502) as `LuaKvpDelete`. ## exports ```lua exports(name, body) ``` `SHARED` — Available without a live game instance. Declares a function callable by other resources. Publishes a named function from the current resource so another resource can call it through `CyberM.exports.call`. The registration is tied to the current generation, so stale functions cannot survive a stop or hot reload. | Parameter | Type | Required | Default | |---|---|---|---| | `name` | `string` | required | — | | `body` | `function` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6495) as `LuaRegisterExport`. ## GetCurrentResourceName ```lua GetCurrentResourceName() ``` `SHARED` — Available without a live game instance. Name of the current resource. Returns the immutable manifest name of the resource whose Lua VM is executing. Use it for diagnostics and namespacing, not as a mutable display label. Returns: `string` Registered in `ResourceHost.cpp` (line 6496) as `LuaResourceName`. ## GetInvokingResource ```lua GetInvokingResource() ``` `SHARED` — Available without a live game instance. Real caller of the currently executing export. Returns nil outside an export callback. Use this value for service ownership instead of accepting a forgeable owner argument. Returns: `resource name, or nil` Registered in `ResourceHost.cpp` (line 6497) as `LuaInvokingResource`. ## GetInvokingResourceGeneration ```lua GetInvokingResourceGeneration() ``` `SHARED` — Available without a live game instance. Generation of the resource invoking the current export. Returns nil outside an export callback. A changed generation lets a service retire handles left by an older VM. Returns: `integer, or nil` Registered in `ResourceHost.cpp` (line 6498) as `LuaInvokingResourceGeneration`. ## GetResourceKvp ```lua GetResourceKvp(key, [default]) ``` `SHARED` — Available without a live game instance. FiveM-style alias for `CyberM.kvp.get`. FiveM-familiar alias for `CyberM.kvp.get`. It returns the original stored Lua type or nil when absent and stays inside the active connection-address and calling-resource namespace. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `default` | `any` | optional | — | Returns: `value or nil`, `reason` Registered in `ResourceHost.cpp` (line 6501) as `LuaKvpGet`. ## GetResourceState ```lua GetResourceState(resource) ``` `SHARED` — Available without a live game instance. State of a resource. Reads the lifecycle state currently known by the client resource host. This is a snapshot only: it does not start, stop, or wait for the target resource. | Parameter | Type | Required | Default | |---|---|---|---| | `resource` | `string` | required | — | Returns: `string` Registered in `ResourceHost.cpp` (line 6499) as `LuaGetResourceState`. ## print ```lua print(…) ``` `SHARED` — Available without a live game instance. Writes to the CyberM log, prefixed with the resource name. Writes a resource-prefixed line to the CyberM log. Values are converted with bounded formatting; this does not send a chat message or write into a WebUI page. | Parameter | Type | Required | Default | |---|---|---|---| | `…` | `any` | required | — | Registered in `ResourceHost.cpp` (line 6484) as `LuaPrint`. ## RegisterNetEvent ```lua RegisterNetEvent(event, [handler]) ``` `NETWORK` — Uses the network backend. Allows an event to arrive from the server. Allows an authenticated server event with this name to enter the current resource, and optionally attaches a handler in the same call. Registration is generation-scoped, requires `network.events`, and does not turn arbitrary client events into server events. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | optional | — | Returns: `handler id` Registered in `ResourceHost.cpp` (line 6493) as `LuaRegisterNetEvent`. ## RemoveEventHandler ```lua RemoveEventHandler(event, handler) ``` `SHARED` — Available without a live game instance. Removes a handler. Removes the exact callback previously registered for the named local event. It returns `false` when that event/callback pair is not owned by the current resource generation. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6491) as `LuaRemoveEventHandler`. ## require ```lua require(module) ``` `SHARED` — Available without a live game instance. Loads a module from the resource. Loads a Lua module declared inside the current resource and caches its result for that resource generation. Resolution stays inside the sandbox: it does not expose the host filesystem, native `package` loaders, or modules from another resource. | Parameter | Type | Required | Default | |---|---|---|---| | `module` | `string` | required | — | Returns: `whatever the module returns` Registered in `ResourceHost.cpp` (line 6485) as `LuaRequire`. ## SetResourceKvp ```lua SetResourceKvp(key, value) ``` `SHARED` — Available without a live game instance. FiveM-style alias for `CyberM.kvp.set`. FiveM-familiar alias for `CyberM.kvp.set`. It stores one typed value in the calling resource's persistent namespace for the active connection address; it cannot select another server or resource. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `value` | `any` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6500) as `LuaKvpSet`. ## SetTimeout ```lua SetTimeout(milliseconds, body) ``` `SHARED` — Available without a live game instance. Runs a function once, later. Schedules a Lua callback after at least the requested number of milliseconds without blocking the game thread. The timer belongs to the current resource generation and is cancelled automatically on stop or hot reload. | Parameter | Type | Required | Default | |---|---|---|---| | `milliseconds` | `integer` | required | — | | `body` | `function` | required | — | Returns: `timer id` Registered in `ResourceHost.cpp` (line 6488) as `LuaSetTimeout`. ## TriggerEvent ```lua TriggerEvent(event, [payload]) ``` `SHARED` — Available without a live game instance. Fires a local event. Dispatches an event only inside the client resource runtime. Arguments must fit the runtime's bounded script-value representation; use `TriggerServerEvent` for traffic that must cross the network. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `payload` | `table` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6492) as `LuaTriggerEvent`. ## TriggerServerEvent ```lua TriggerServerEvent(event, [payload]) ``` `NETWORK` — Uses the network backend. Sends an event to the server. Serializes and sends an event to the connected server with the caller's authenticated player identity. It requires `network.events`; tables must be serializable and payload limits are enforced before anything is queued. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `payload` | `table` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6494) as `LuaTriggerServerEvent`. ## Wait ```lua Wait(milliseconds) ``` `SHARED` — Available without a live game instance. Suspends the current coroutine. Only usable inside a `CreateThread`. | Parameter | Type | Required | Default | |---|---|---|---| | `milliseconds` | `integer` | required | — | Registered in `ResourceHost.cpp` (line 6487) as `LuaWait`. --- Source: https://open2077.net/docs/api/client/cyberm-animations # CyberM.animations — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 5 functions. ## current ```lua CyberM.animations.current(entity) ``` `GAME` — Requires a live game instance. The clip a body is currently playing. Returns false when it is playing nothing — which is a state, not an error. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | required | — | Returns: `clip name, or false`, `reason, when applicable` Registered in `ResourceHost.cpp` (line 6591) as `LuaAnimationCurrent`. ## play ```lua CyberM.animations.play(entity, animation) ``` `GAME` — Requires a live game instance. Plays a named animation on a body. Does not work on the local player: their body cannot hold a workspot. Use `CyberM.animations.playSelf` for that, which stands a double in for them. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | required | — | | `animation` | `string` | required | — | Returns: `true on success, otherwise false`, `reason for the refusal` ```lua local ok, reason = CyberM.animations.play(entityId, "emote_smoke") if not ok then print("refused: " .. reason) end ``` Registered in `ResourceHost.cpp` (line 6587) as `LuaAnimationPlay`. ## playSelf ```lua CyberM.animations.playSelf(animation, [thirdPerson]) ``` `GAME` — Requires a live game instance. Plays an emote on the local player, through a stand-in body. The player's own body cannot hold a workspot, so an invisible double takes their place for the length of the clip. This is a separate call rather than `play` with the player's id because the mechanism is genuinely different. | Parameter | Type | Required | Default | |---|---|---|---| | `animation` | `string` | required | — | | `thirdPerson` | `boolean` | optional | — | Returns: `true on success, otherwise false`, `reason for the refusal` Registered in `ResourceHost.cpp` (line 6588) as `LuaSelfEmotePlay`. ## stop ```lua CyberM.animations.stop(entity) ``` `GAME` — Requires a live game instance. Stops whatever a body is playing and releases what was set up for it. Stops the workspot animation currently managed by CyberM for the selected body and releases its native animation state. It does not claim or stop arbitrary game animations that CyberM does not own. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | required | — | Returns: `true on success, otherwise false`, `reason for the refusal` Registered in `ResourceHost.cpp` (line 6590) as `LuaAnimationStop`. ## stopSelf ```lua CyberM.animations.stopSelf() ``` `GAME` — Requires a live game instance. Stops the local player's emote and removes the stand-in. Ends the local-player emote created by `playSelf` and removes its stand-in body. Cleanup is idempotent and is also performed when the owning resource generation stops. Returns: `true on success, otherwise false`, `reason for the refusal` Registered in `ResourceHost.cpp` (line 6589) as `LuaSelfEmoteStop`. --- Source: https://open2077.net/docs/api/client/cyberm-appearance # CyberM.appearance — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 5 functions. ## apply ```lua CyberM.appearance.apply(snapshot) ``` `GAME` — Requires a live game instance. Applies a previously captured appearance snapshot to the local player. Requires `player.appearance.edit`. The runtime validates the schema, build, catalog digest, gender, option identities, choice bounds, and duplicates before touching the game. | Parameter | Type | Required | Default | |---|---|---|---| | `snapshot` | `table` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6635) as `LuaAppearanceApply`. ## capture ```lua CyberM.appearance.capture() ``` `GAME` — Requires a live game instance. Captures the local player's complete validated appearance snapshot. Requires `player.appearance.read`. The snapshot is bound to schema version 1, game build 2.31, a catalog digest, gender hash, and at most 256 head/body/arms options. Returns: `table { schemaVersion, gameBuild, catalogDigest, gender, options }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6634) as `LuaAppearanceCapture`. ## finishCommit ```lua CyberM.appearance.finishCommit() ``` `GAME` — Requires a live game instance. Finishes the current appearance commit transaction. Requires `player.appearance.edit`. Call after a successful apply/persistence flow so the native editor can release its commit state. Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6636) as `LuaAppearanceFinish`. ## isOpen ```lua CyberM.appearance.isOpen() ``` `GAME` — Requires a live game instance. Whether the local appearance editor is open. Requires `player.appearance.read`; returns false when the permission or backend is unavailable. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6633) as `LuaAppearanceIsOpen`. ## open ```lua CyberM.appearance.open([options]) ``` `GAME` — Requires a live game instance. Opens the local Cyberpunk appearance editor. Requires `player.appearance.edit`. The optional value may be a mode string or `{ mode = string }`; `ripperdoc` is used by default. | Parameter | Type | Required | Default | |---|---|---|---| | `options` | `string|table` | optional | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6632) as `LuaAppearanceOpen`. --- Source: https://open2077.net/docs/api/client/cyberm-assets # CyberM.assets — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## list ```lua CyberM.assets.list() ``` `SHARED` — Available without a live game instance. Lists generic files declared by the current resource. Returns the resource files declared by the current manifest. It is an allow-list view, not a directory listing, and does not grant access to undeclared files or arbitrary paths. Returns: `array of relative paths` Registered in `ResourceHost.cpp` (line 6541) as `LuaAssetList`. ## texture ```lua CyberM.assets.texture(path) ``` `SHARED` — Available without a live game instance. Validates a declared PNG texture for resource APIs. The path must match the manifest's `files` allowlist. PNG textures are limited to 512 KiB and 512 by 512 pixels. | Parameter | Type | Required | Default | |---|---|---|---| | `path` | `string` | required | — | Returns: `descriptor { type, asset, mime, width, height, bytes }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6540) as `LuaAssetTexture`. --- Source: https://open2077.net/docs/api/client/cyberm-blips # CyberM.blips — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 18 functions. ## attachToEntity ```lua CyberM.blips.attachToEntity(id, entity, [slot], [offset]) ``` `GAME` — Requires a live game instance. Makes a blip follow a CyberM entity. Changes an owned blip from a fixed world position to tracking a streamed CyberM entity. The entity id is ephemeral and the call requires `ui.vanilla.map`; remove or reattach the blip when its gameplay target changes. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `entity` | `entity` | required | — | | `slot` | `string` | optional | `poi_mappin` | | `offset` | `table { x, y, z }` | optional | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6779) as `LuaBlipAttachToEntity`. ## clear ```lua CyberM.blips.clear() ``` `GAME` — Requires a live game instance. Removes every blip owned by the current resource. Removes every vanilla-map blip owned by the calling resource generation. Other resources' blips are left untouched, and generation teardown performs the same cleanup automatically. Returns: `true` Registered in `ResourceHost.cpp` (line 6790) as `LuaBlipClear`. ## create ```lua CyberM.blips.create(options) ``` `GAME` — Requires a live game instance. Creates a resource-owned vanilla map pin. Requires `ui.vanilla.map`. Provide exactly one of `position` or `entity`. The returned 64-bit generation handle is a decimal string and is cleaned up automatically when the resource stops. | Parameter | Type | Required | Default | |---|---|---|---| | `options` | `table { position|entity, sprite?, label?, icon?, active?, visibleThroughWalls?, slot?, offset? }` | required | — | Returns: `decimal-string blip id, or nil`, `reason` ```lua local id = assert(CyberM.blips.create({ position = { x = 10, y = 20, z = 30 }, sprite = "objective", label = "Street race" })) ``` Registered in `ResourceHost.cpp` (line 6776) as `LuaBlipCreate`. ## get ```lua CyberM.blips.get(id) ``` `GAME` — Requires a live game instance. Reads one blip owned by the current resource. Returns a read-only snapshot of one blip owned by the calling resource. The handle must still belong to the current generation; a stale or foreign id is rejected. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | Returns: `snapshot table, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6791) as `LuaBlipGet`. ## list ```lua CyberM.blips.list() ``` `GAME` — Requires a live game instance. Lists blips owned by the current resource. Lists snapshots of all vanilla-map blips owned by the calling resource generation. The returned tables are copies and changing them does not mutate the map. Returns: `array of snapshot tables` Registered in `ResourceHost.cpp` (line 6792) as `LuaBlipList`. ## remove ```lua CyberM.blips.remove(id) ``` `GAME` — Requires a live game instance. Removes one owned blip. Deletes one blip owned by the calling resource and invalidates its handle. Removal is resource-scoped, so one package cannot erase another package's map state. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6789) as `LuaBlipRemove`. ## setActive ```lua CyberM.blips.setActive(id, active) ``` `GAME` — Requires a live game instance. Activates or deactivates a vanilla mappin. Updates the active/highlighted state of an owned vanilla-map blip. This changes presentation only and does not create a route or change server state. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `active` | `boolean` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6785) as `LuaBlipSetActive`. ## setDescription ```lua CyberM.blips.setDescription(id, description) ``` `GAME` — Requires a live game instance. Sets the custom fullscreen-map description of an owned blip. Requires `ui.vanilla.map`. The description is displayed by CyberM's fullscreen-map tooltip for the selected native mappin. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `string` | required | — | | `description` | `string` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6783) as `LuaBlipSetDescription`. ## setIcon ```lua CyberM.blips.setIcon(id, icon) ``` `GAME` — Requires a live game instance. Sets a declared PNG icon or restores the native sprite. Accepts a path, a texture descriptor, `{ asset, size }`, or false. The native mappin remains underneath for map selection, routing, tooltips, and fallback. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `icon` | `string|table|false` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6784) as `LuaBlipSetIcon`. ## setLabel ```lua CyberM.blips.setLabel(id, label) ``` `GAME` — Requires a live game instance. Changes the fullscreen-map tooltip title. CyberM keeps the label in private script data, independent from the vanilla variant's generic title. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `label` | `string` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6782) as `LuaBlipSetLabel`. ## setPosition ```lua CyberM.blips.setPosition(id, position) ``` `GAME` — Requires a live game instance. Moves a blip to a world position. Also detaches an entity-following blip. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `position` | `table { x, y, z }` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6778) as `LuaBlipSetPosition`. ## setSprite ```lua CyberM.blips.setSprite(id, sprite) ``` `GAME` — Requires a live game instance. Changes the vanilla mappin variant. Accepts an exact 2.31 variant name, a stable alias, or an integer from 0 through 146. See `wiki/blips.md` for the complete list. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `sprite` | `string|integer` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6780) as `LuaBlipSetSprite`. ## setTitle ```lua CyberM.blips.setTitle(id, title) ``` `GAME` — Requires a live game instance. Sets the custom fullscreen-map title of an owned blip. Requires `ui.vanilla.map`. This is the semantic title alias of `setLabel`; the HUD does not permanently render it beside the icon. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `string` | required | — | | `title` | `string` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6781) as `LuaBlipSetTitle`. ## setTrackingAlternative ```lua CyberM.blips.setTrackingAlternative(id, target) ``` `GAME` — Requires a live game instance. Sets another owned blip as the routing alternative. Passing nil clears it. This does not force the world-map controller to start tracking. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `target` | `decimal string|nil` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6787) as `LuaBlipSetTrackingAlternative`. ## setVisibleThroughWalls ```lua CyberM.blips.setVisibleThroughWalls(id, visible) ``` `GAME` — Requires a live game instance. Changes vanilla through-wall visibility. Controls whether an owned world marker remains visible when geometry occludes it. The setting affects presentation on this client only and requires `ui.vanilla.map`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `visible` | `boolean` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6786) as `LuaBlipSetVisibleThroughWalls`. ## sprites ```lua CyberM.blips.sprites() ``` `GAME` — Requires a live game instance. Lists every usable mappin variant in the current build. Returns 147 entries for Cyberpunk 2077 2.31. This metadata query does not require map mutation permission. Returns: `array of { name, value }` Registered in `ResourceHost.cpp` (line 6793) as `LuaBlipSprites`. ## untrack ```lua CyberM.blips.untrack(id) ``` `GAME` — Requires a live game instance. Safely clears manual tracking for this blip. The native action is invoked only if this owned blip is currently tracked, so a resource cannot untrack a quest or another system's pin. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | Returns: `true`, `whether it was tracked` Registered in `ResourceHost.cpp` (line 6788) as `LuaBlipUntrack`. ## update ```lua CyberM.blips.update(id, patch) ``` `GAME` — Requires a live game instance. Updates several properties of an owned blip. A replacement mappin is registered before the previous one is removed. `position` switches to positional mode; `entity` switches to attached mode. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `decimal string` | required | — | | `patch` | `table` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6777) as `LuaBlipUpdate`. --- Source: https://open2077.net/docs/api/client/cyberm-camera # CyberM.camera — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## attach ```lua CyberM.camera.attach() ``` `GAME` — Requires a live game instance. Reattaches the camera to the body. Attaches the CyberM camera to a game entity using the supplied local offset and rotation. Camera ownership is local to the resource generation; attaching replaces the resource's previous detached/attached camera state. Returns: `true on success, otherwise false`, `reason for the refusal` Registered in `ResourceHost.cpp` (line 6750) as `LuaCameraAttach`. ## detach ```lua CyberM.camera.detach(x, y, z) ``` `GAME` — Requires a live game instance. Detaches the camera from the body, with an offset in the body's own space. Detaches the CyberM camera from its target while retaining a controllable camera view. It does not synchronize a camera to other players and is automatically restored during resource cleanup. | Parameter | Type | Required | Default | |---|---|---|---| | `x` | `number` | required | — | | `y` | `number` | required | — | | `z` | `number` | required | — | Returns: `true on success, otherwise false`, `reason for the refusal` Registered in `ResourceHost.cpp` (line 6749) as `LuaCameraDetach`. ## project ```lua CyberM.camera.project(position) ``` `GAME` — Requires a live game instance. Projects a world point into normalized WebUI viewport coordinates. Uses REDengine's active camera projection. `(0,0)` is the top-left and `(1,1)` the bottom-right. `onScreen` is false for points behind the view or beyond the viewport. | Parameter | Type | Required | Default | |---|---|---|---| | `position` | `table { x, y, z }` | required | — | Returns: `table { x, y, depth, distance, onScreen }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6753) as `LuaCameraProject`. ## setFov ```lua CyberM.camera.setFov(degrees) ``` `GAME` — Requires a live game instance. Sets the field of view, in degrees. Changes the field of view of the camera currently controlled by CyberM. The value is validated by the native backend and applies only to this client's presentation. | Parameter | Type | Required | Default | |---|---|---|---| | `degrees` | `number` | required | — | Returns: `true on success, otherwise false`, `reason for the refusal` ```lua CyberM.camera.setFov(90) ``` Registered in `ResourceHost.cpp` (line 6751) as `LuaCameraFieldOfView`. ## thirdPerson ```lua CyberM.camera.thirdPerson(enabled, [distance], [height]) ``` `GAME` — Requires a live game instance. Switches the view to third person. Turning it off restores the view the game had before the call, rather than some default. | Parameter | Type | Required | Default | |---|---|---|---| | `enabled` | `boolean` | required | — | | `distance` | `number` | optional | — | | `height` | `number` | optional | — | Returns: `true on success, otherwise false`, `reason for the refusal` ```lua CyberM.camera.thirdPerson(true, 2.5, 1.7) ``` Registered in `ResourceHost.cpp` (line 6748) as `LuaCameraThirdPerson`. ## view ```lua CyberM.camera.view() ``` `GAME` — Requires a live game instance. Where the view is: position, forward vector, field of view. Returns the latest game-thread camera snapshot used by projection and presentation APIs. It is a same-client read and may return `nil, reason` while the game camera is unavailable. Returns: `position (x, y, z)`, `forward (x, y, z)`, `field of view` Registered in `ResourceHost.cpp` (line 6752) as `LuaCameraView`. --- Source: https://open2077.net/docs/api/client/cyberm-character # CyberM.character — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 18 functions. ## animation ```lua CyberM.character.animation([entity]) ``` `GAME` — Requires a live game instance. The animation currently playing on this character. Reads the current animation snapshot for an entity, or for the local player when omitted. The result is observational and can change on the next frame; it does not grant animation ownership. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `clip name, or nil` Registered in `ResourceHost.cpp` (line 6615) as `LuaCharacterAnimation`. ## groundSpeed ```lua CyberM.character.groundSpeed([entity]) ``` `GAME` — Requires a live game instance. Speed projected on the ground, without the vertical component. Returns horizontal movement speed for the selected character, excluding vertical velocity. Entity ids refer to the current client stream and must not be persisted as server identity. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `number` Registered in `ResourceHost.cpp` (line 6617) as `LuaCharacterNumber<&SelectGroundSpeed>`. ## health ```lua CyberM.character.health([entity]) ``` `GAME` — Requires a live game instance. Current health. Reads the engine-side health visible for the selected character on this client. For replicated player gameplay rules use the server-authoritative player health APIs; this helper is a presentation snapshot, not authority. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `number` Registered in `ResourceHost.cpp` (line 6618) as `LuaCharacterNumber<&SelectHealth>`. ## isAlive ```lua CyberM.character.isAlive([entity]) ``` `GAME` — Requires a live game instance. Whether the character is alive. Reports the current engine alive/dead flag for the selected character. It is useful for presentation and diagnostics but may lag the authoritative server health transition by a replication frame. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6620) as `LuaCharacterFlag<&SelectAlive>`. ## isArmed ```lua CyberM.character.isArmed([entity]) ``` `GAME` — Requires a live game instance. Whether a weapon is drawn. Reports whether the selected character is currently considered armed by the game presentation state. It does not enumerate inventory or prove that a weapon action is server-authorized. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6625) as `LuaCharacterFlag<&SelectArmed>`. ## isCrouched ```lua CyberM.character.isCrouched([entity]) ``` `GAME` — Requires a live game instance. Whether the character is crouching. Reads the character's current crouch presentation flag. Omit the entity to inspect the local player; remote values exist only while that proxy is streamed. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6622) as `LuaCharacterFlag<&SelectCrouched>`. ## isDriver ```lua CyberM.character.isDriver([entity]) ``` `GAME` — Requires a live game instance. Whether they occupy the driver's seat. Returns whether the selected character occupies the canonical driver seat of a vehicle. Use `seat()` when the exact seat and vehicle entity are also needed. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6627) as `LuaCharacterFlag<&SelectDriverSeat>`. ## isEmoting ```lua CyberM.character.isEmoting([entity]) ``` `GAME` — Requires a live game instance. Whether they hold a workspot (an emote is running). Reports whether CyberM currently presents the character in an emote/workspot state. This is a transient local snapshot and is cleared with the owning presentation lifecycle. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6628) as `LuaCharacterFlag<&SelectInWorkspot>`. ## isGrounded ```lua CyberM.character.isGrounded([entity]) ``` `GAME` — Requires a live game instance. Whether the character is touching the ground. Reads the engine grounded flag for the selected character. The value is sampled from the current client frame and should not be used alone for authoritative movement validation. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6621) as `LuaCharacterFlag<&SelectGrounded>`. ## isInVehicle ```lua CyberM.character.isInVehicle([entity]) ``` `GAME` — Requires a live game instance. Whether the character is mounted in a vehicle. Reports whether the character is mounted in a vehicle according to the current client presentation. Call `seat()` to retrieve the mounted slot and vehicle entity id. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6626) as `LuaCharacterFlag<&SelectInVehicle>`. ## isSliding ```lua CyberM.character.isSliding([entity]) ``` `GAME` — Requires a live game instance. Whether the character is sliding. Reads the current sliding locomotion flag for the selected character. It is an observational state and does not start or stop a slide. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6623) as `LuaCharacterFlag<&SelectSliding>`. ## isVaulting ```lua CyberM.character.isVaulting([entity]) ``` `GAME` — Requires a live game instance. Whether the character is vaulting. Reads the current vaulting locomotion flag for the selected character. Remote values are available only while the corresponding proxy is streamed. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6624) as `LuaCharacterFlag<&SelectVaulting>`. ## position ```lua CyberM.character.position([entity]) ``` `GAME` — Requires a live game instance. The character's position. Returns the character's current world-space coordinates from the game-thread snapshot. Omit the entity for the local player; do not persist a client entity id as a network identity. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `x, y, z` Registered in `ResourceHost.cpp` (line 6612) as `LuaCharacterPosition`. ## seat ```lua CyberM.character.seat([entity]) ``` `GAME` — Requires a live game instance. The seat occupied in a vehicle, if any. Returns the canonical seat name and the mounted vehicle's client entity id when the character is in a vehicle. A character that is not mounted returns `nil`; both values are snapshots and the entity id is valid only in the current client stream. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `seat name and vehicle entity id, or nil`, `reason when the character could not be read` Registered in `ResourceHost.cpp` (line 6613) as `LuaCharacterSeat`. ## speed ```lua CyberM.character.speed([entity]) ``` `GAME` — Requires a live game instance. Instantaneous speed, all components. Returns total character movement speed, including vertical motion, from the latest local snapshot. Use `groundSpeed()` when only horizontal locomotion is relevant. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `number` Registered in `ResourceHost.cpp` (line 6616) as `LuaCharacterNumber<&SelectSpeed>`. ## state ```lua CyberM.character.state([entity]) ``` `GAME` — Requires a live game instance. One complete snapshot of a character. A single engine pass fills the whole record even when the caller only wanted the speed. That is deliberate: every field then describes the **same instant**, so a caller cannot see a body grounded and airborne in the same breath. With no argument, answers about the local player. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `table { isPlayer, attached, id, engineId, position, orientation, forward, velocity, speed, groundSpeed, yaw, alive, health, grounded, crouched, sliding, vaulting, air, fall, landing, weapon…, inVehicle, seat, driver }`, `reason, when the first is nil` ```lua local s = CyberM.character.state() if s.inVehicle and s.driver then print("driving at " .. math.floor(s.speed) .. " u/s") end ``` Registered in `ResourceHost.cpp` (line 6611) as `LuaCharacterState`. ## weapon ```lua CyberM.character.weapon([entity]) ``` `GAME` — Requires a live game instance. The equipped weapon and its state. Returns the drawn weapon's recognized item id and category for the selected character. It returns `nil` when no recognized weapon is currently presented and does not expose or mutate inventory. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `table { itemId, category }, or nil`, `reason when the character could not be read` Registered in `ResourceHost.cpp` (line 6614) as `LuaCharacterWeapon`. ## yaw ```lua CyberM.character.yaw([entity]) ``` `GAME` — Requires a live game instance. Horizontal orientation, in degrees. Returns the selected character's current world yaw in degrees. The value is a presentation snapshot and should be normalized by the caller when computing angular deltas. | Parameter | Type | Required | Default | |---|---|---|---| | `entity` | `entity` | optional | — | Returns: `number` Registered in `ResourceHost.cpp` (line 6619) as `LuaCharacterNumber<&SelectYaw>`. --- Source: https://open2077.net/docs/api/client/cyberm-clipboard # CyberM.clipboard — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 1 function. ## setText ```lua CyberM.clipboard.setText(text) ``` `GAME` — Requires a live game instance. Writes UTF-8 text to the operating-system clipboard. Client-only and requires `clipboard.write` on the resource whose VM performs the call. Text is limited to 256 KiB, must be valid UTF-8 and cannot contain an embedded NUL. The operation is write-only: resources cannot inspect the user's existing clipboard. A temporarily owned clipboard returns `false, clipboard_busy`; callers should let the player retry instead of polling every frame. | Parameter | Type | Required | Default | |---|---|---|---| | `text` | `string` | required | — | Returns: `true on success, otherwise false`, `reason for the refusal` ```lua local ok, reason = CyberM.clipboard.setText("position = { x = 1, y = 2, z = 3 }") ``` Registered in `ResourceHost.cpp` (line 6607) as `LuaClipboardSetText`. --- Source: https://open2077.net/docs/api/client/cyberm-debug # CyberM.debug — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 3 functions. ## command ```lua CyberM.debug.command(commandLine) ``` `GAME` — Requires a live game instance. Runs one registered native laboratory command directly. Requires `debug.runtime` and the trusted `cyberm_debug` owner. Input is limited to 4096 bytes and unknown commands are not forwarded to the server. | Parameter | Type | Required | Default | |---|---|---|---| | `commandLine` | `string` | required | — | Returns: `true and command result on success`, `false and reason` Registered in `ResourceHost.cpp` (line 6551) as `LuaDebugCommand`. ## eval ```lua CyberM.debug.eval(source, [label]) ``` `GAME` — Requires a live game instance. Compiles and executes a bounded text-only Lua chunk in the privileged debug VM. Requires `debug.runtime` and the trusted `cyberm_debug` owner. Source is limited to 32 KiB, the optional chunk label to 64 bytes, returned values to 16 and result text to 8 KiB. The ordinary memory, instruction and frame-time quotas remain active. | Parameter | Type | Required | Default | |---|---|---|---| | `source` | `string` | required | — | | `label` | `string` | optional | `exec` | Returns: `true and bounded result text on success`, `false and compile/runtime reason` Registered in `ResourceHost.cpp` (line 6550) as `LuaDebugEval`. ## redscript ```lua CyberM.debug.redscript(command) ``` `GAME` — Requires a live game instance. Queues one bounded command through the REDscript debug bridge. Requires `debug.runtime` and the trusted `cyberm_debug` owner. The opaque command is limited to 4096 bytes and executes from a genuine REDscript frame. | Parameter | Type | Required | Default | |---|---|---|---| | `command` | `string` | required | — | Returns: `true and bridge result on success`, `false and reason` Registered in `ResourceHost.cpp` (line 6552) as `LuaDebugRedscript`. --- Source: https://open2077.net/docs/api/client/cyberm-doors # CyberM.doors — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 23 functions. ## aimed ```lua CyberM.doors.aimed() ``` `GAME` — Requires a live game instance. The streamed door currently under the crosshair. Requires `world.doors`. The returned `id` is an opaque 64-bit REDengine identity encoded as a string; never convert it to a Lua number. A successful discovery also makes that door addressable by `state` and the command functions while it remains streamed. Returns: `door snapshot, or nil`, `reason when the first is nil` ```lua local door, reason = CyberM.doors.aimed() if door then print(door.id, door.open, door.locked, door.distance) end ``` Registered in `ResourceHost.cpp` (line 6647) as `LuaDoorAimed`. ## available ```lua CyberM.doors.available() ``` `GAME` — Requires a live game instance. Whether the client door backend is available. This capability check does not discover or stream a door. Door operations require the `world.doors` permission. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6646) as `LuaDoorsAvailable`. ## clearInteractionPolicy ```lua CyberM.doors.clearInteractionPolicy(door) ``` `GAME` — Requires a live game instance. Removes this resource's interaction policy for a door. Requires `world.doors`. Other resources' policies are unaffected. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | Returns: `true on success, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6676) as `LuaDoorPolicy`. ## close ```lua CyberM.doors.close(door, [force]) ``` `GAME` — Requires a live game instance. Closes a door. Alias of `setOpen(door, false, force)`. Requires `world.doors`; application is asynchronous. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6662) as `LuaDoorCommand`. ## closest ```lua CyberM.doors.closest([radius]) ``` `GAME` — Requires a live game instance. The closest streamed door around the local player. Requires `world.doors`. Uses the same 0.5 to 100 metre player-centered query as `near`. | Parameter | Type | Required | Default | |---|---|---|---| | `radius` | `number` | optional | `20` | Returns: `door snapshot, or nil`, `reason when the first is nil` Registered in `ResourceHost.cpp` (line 6649) as `LuaDoorClosest`. ## grantKey ```lua CyberM.doors.grantKey(door, holder) ``` `GAME` — Requires a live game instance. Grants an entity an opening token for a door. Requires `world.doors`. Uses the door controller's native token mechanism rather than a parallel CyberM key list. This grants authorization but does not lock or deny an otherwise usable door; access enforcement belongs to `setInteractionAllowed`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `holder` | `opaque entity id` | required | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6671) as `LuaDoorCommand`. ## hasKey ```lua CyberM.doors.hasKey(door, holder) ``` `GAME` — Requires a live game instance. Whether an entity holds an opening token for a door. Requires `world.doors`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `holder` | `opaque entity id` | required | — | Returns: `boolean, or nil`, `reason when the first is nil` Registered in `ResourceHost.cpp` (line 6652) as `LuaDoorHasKey`. ## holders ```lua CyberM.doors.holders(door) ``` `GAME` — Requires a live game instance. The entities holding an opening token for a door. Requires `world.doors`. Holder IDs are opaque strings for the same precision reason as door IDs. Tokens are vanilla authorization data, not a global lock rule: an unlocked interactive door remains usable with no token. Combine `hasKey` with `setInteractionAllowed` when implementing an ox_doorlock-style policy. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | Returns: `array of opaque entity ids, or nil`, `reason when the first is nil` Registered in `ResourceHost.cpp` (line 6651) as `LuaDoorHolders`. ## lock ```lua CyberM.doors.lock(door, [force]) ``` `GAME` — Requires a live game instance. Locks a door. Alias of `setLocked(door, true, force)`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6664) as `LuaDoorCommand`. ## near ```lua CyberM.doors.near([radius]) ``` `GAME` — Requires a live game instance. All streamed doors around the local player. Requires `world.doors`. The radius is centered on the player and must be between 0.5 and 100 metres. Results are sorted nearest first and register each door for later ID-based operations. | Parameter | Type | Required | Default | |---|---|---|---| | `radius` | `number` | optional | `20` | Returns: `array of door snapshots, or nil`, `reason when the first is nil` Registered in `ResourceHost.cpp` (line 6648) as `LuaDoorNear`. ## open ```lua CyberM.doors.open(door, [force]) ``` `GAME` — Requires a live game instance. Opens a door. Alias of `setOpen(door, true, force)`. Requires `world.doors`; application is asynchronous. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6661) as `LuaDoorCommand`. ## reset ```lua CyberM.doors.reset(door) ``` `GAME` — Requires a live game instance. Resets a door to its configured default state. Requires `world.doors`; queues the vanilla `ResetDoorState` event. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6670) as `LuaDoorCommand`. ## revokeKey ```lua CyberM.doors.revokeKey(door, holder) ``` `GAME` — Requires a live game instance. Revokes an entity's opening token for a door. Requires `world.doors`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `holder` | `opaque entity id` | required | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6672) as `LuaDoorCommand`. ## seal ```lua CyberM.doors.seal(door, [force]) ``` `GAME` — Requires a live game instance. Seals a door. Alias of `setSealed(door, true, force)`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6667) as `LuaDoorCommand`. ## setAutomaticClose ```lua CyberM.doors.setAutomaticClose(door, enabled) ``` `GAME` — Requires a live game instance. Enables or disables a door's automatic closing behavior. Requires `world.doors`; queues the vanilla `SetCloseItself` event. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `enabled` | `boolean` | required | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6669) as `LuaDoorCommand`. ## setInteractionAllowed ```lua CyberM.doors.setInteractionAllowed(door, allowed) ``` `GAME` — Requires a live game instance. Pre-declares whether vanilla interaction may open a door. Requires `world.doors`. The decision is synchronous when the game interacts with the door. Policies are owned by the resource, all active policies must allow, and they are removed automatically on stop/reload. `cyberm:doorInteract` is an observational event with `(doorId, activatorId, "true"|"false")`; it is too late to change that interaction. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `allowed` | `boolean` | required | — | Returns: `true on success, otherwise false`, `reason for refusal` ```lua CyberM.doors.setInteractionAllowed(doorId, playerHasAccess) AddEventHandler("cyberm:doorInteract", function(door, activator, allowed) print(door, activator, allowed) end) ``` Registered in `ResourceHost.cpp` (line 6674) as `LuaDoorPolicy`. ## setLocked ```lua CyberM.doors.setLocked(door, locked, [force]) ``` `GAME` — Requires a live game instance. Sets whether a door is locked. Requires `world.doors`. `force` uses the vanilla quest-authority action; application is asynchronous. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `locked` | `boolean` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6663) as `LuaDoorCommand`. ## setOpen ```lua CyberM.doors.setOpen(door, open, [force]) ``` `GAME` — Requires a live game instance. Sets whether a door is open. Requires `world.doors`. Success means the REDscript action was accepted; application is asynchronous and may take up to 200 ms. `force` uses the vanilla quest-authority action. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `open` | `boolean` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6660) as `LuaDoorCommand`. ## setSealed ```lua CyberM.doors.setSealed(door, sealed, [force]) ``` `GAME` — Requires a live game instance. Sets whether a door is sealed. Requires `world.doors`. Sealing is distinct from locking. `force` uses the vanilla quest-authority action. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `sealed` | `boolean` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6666) as `LuaDoorCommand`. ## setState ```lua CyberM.doors.setState(door, state, [force]) ``` `GAME` — Requires a live game instance. Sets a door state by name. Accepted states: `open`, `closed`, `locked`, `unlocked`, `sealed`, `unsealed`. Requires `world.doors`; `force` selects the quest-authority action. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `state` | `string` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6673) as `LuaDoorSetState`. ## state ```lua CyberM.doors.state(door) ``` `GAME` — Requires a live game instance. A live snapshot of a streamed door. Requires `world.doors`. Reads the live `DoorControllerPS`, never a fabricated default from the save record. Returns `door_not_streamed` after the entity unloads. Snapshot fields include `id`, `class`, `name`, `position`, `distance`, `open`, `closed`, `locked`, `sealed`, `busy`, `playerAuthorised`, `automaticClose`, toggle capabilities, shutter/lift flags, type/sides and opening speed/time. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | Returns: `door snapshot, or nil`, `reason when the first is nil` Registered in `ResourceHost.cpp` (line 6650) as `LuaDoorState`. ## unlock ```lua CyberM.doors.unlock(door, [force]) ``` `GAME` — Requires a live game instance. Unlocks a door. Alias of `setLocked(door, false, force)`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6665) as `LuaDoorCommand`. ## unseal ```lua CyberM.doors.unseal(door, [force]) ``` `GAME` — Requires a live game instance. Unseals a door. Alias of `setSealed(door, false, force)`. | Parameter | Type | Required | Default | |---|---|---|---| | `door` | `opaque door id` | required | — | | `force` | `boolean` | optional | — | Returns: `true when accepted, otherwise false`, `reason for refusal` Registered in `ResourceHost.cpp` (line 6668) as `LuaDoorCommand`. --- Source: https://open2077.net/docs/api/client/cyberm-elevators # CyberM.elevators — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 4 functions. ## all ```lua CyberM.elevators.all() ``` `GAME` — Requires a live game instance. Lists every replicated elevator state visible to the client. Requires `elevators.read`; returns an empty array when the capability or backend is unavailable. Returns: `array of elevator snapshots` Registered in `ResourceHost.cpp` (line 6724) as `LuaElevatorsAll`. ## get ```lua CyberM.elevators.get(id) ``` `GAME` — Requires a live game instance. Reads one replicated elevator by CyberM ID. Requires `elevators.read`. Elevator IDs are server-assigned and should be kept unchanged. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `table { id, revision, bucket, engineEntity, activeFloor, originFloor, targetFloor, floorCount, travelMs, remainingMs, flags, phase, position, streamed, applied }, or nil` Registered in `ResourceHost.cpp` (line 6723) as `LuaElevatorGet`. ## nearby ```lua CyberM.elevators.nearby([radius]) ``` `GAME` — Requires a live game instance. Discovers streamed native elevators around the local player. Requires `elevators.read`. Radius must be between 1 and 300 metres. Results distinguish unmanaged engine lifts from elevators already adopted by CyberM. | Parameter | Type | Required | Default | |---|---|---|---| | `radius` | `number` | optional | `100` | Returns: `array of { engineEntity, controllerEntity, position, distance, managed, floorCount, activeFloor, id }` Registered in `ResourceHost.cpp` (line 6725) as `LuaElevatorsNearby`. ## request ```lua CyberM.elevators.request(id, floor, action) ``` `GAME` — Requires a live game instance. Submits a floor request to the authoritative server. Requires `elevators.request`. `action` is normally `call` or `goto`; the server validates the ID, floor, player bucket, range, state and policy. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `floor` | `integer` | required | — | | `action` | `string` | required | — | Returns: `true when submitted, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6726) as `LuaElevatorRequest`. --- Source: https://open2077.net/docs/api/client/cyberm-environment # CyberM.environment — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## getTime ```lua CyberM.environment.getTime() ``` `GAME` — Requires a live game instance. Lit l'horloge REDengine locale. Primitive interne protégée par `world.environment`. Retourne un snapshot atomique de l'heure appliquée et de l'état de pause. Dans une session normale, utilisez l'export `cyberm_weather.getState` plutôt que cette valeur de projection. Returns: `table { day, hour, minute, second, totalSeconds, frozen }, ou nil`, `raison si indisponible` Registered in `ResourceHost.cpp` (line 6739) as `LuaEnvironmentTime`. ## isWeatherFrozen ```lua CyberM.environment.isWeatherFrozen() ``` `GAME` — Requires a live game instance. Indique si la météo automatique vanilla est neutralisée. Demande `world.environment`. Returns: `boolean, ou nil`, `raison si indisponible` Registered in `ResourceHost.cpp` (line 6744) as `LuaEnvironmentWeatherFrozen`. ## setTime ```lua CyberM.environment.setTime(hour, minute, [second]) ``` `GAME` — Requires a live game instance. Projette une heure serveur dans REDengine. Demande `world.environment`. `cyberm_weather` est normalement le seul propriétaire de cette permission. REDengine choisit la prochaine occurrence de l'heure demandée ; le package officiel filtre donc les petits reculs réseau pour éviter un saut d'un jour. | Parameter | Type | Required | Default | |---|---|---|---| | `hour` | `integer 0..23` | required | — | | `minute` | `integer 0..59` | required | — | | `second` | `integer 0..59` | optional | `0` | Returns: `true en cas de succès, sinon false`, `raison du refus` Registered in `ResourceHost.cpp` (line 6740) as `LuaEnvironmentSetTime`. ## setTimeFrozen ```lua CyberM.environment.setTimeFrozen(frozen) ``` `GAME` — Requires a live game instance. Fige ou libère uniquement l'horloge du jeu. Ne fige pas la simulation. Demande `world.environment`; utilisé par la projection serveur pour neutraliser la vitesse vanilla. | Parameter | Type | Required | Default | |---|---|---|---| | `frozen` | `boolean` | required | — | Returns: `true en cas de succès, sinon false`, `raison du refus` Registered in `ResourceHost.cpp` (line 6741) as `LuaEnvironmentFreezeTime`. ## setWeather ```lua CyberM.environment.setWeather(preset, [transitionSeconds], [priority]) ``` `GAME` — Requires a live game instance. Applique un preset météo REDengine. Primitive interne demandant `world.environment`. Le second retour `applied=false` est aussi possible en cas de succès si le preset était déjà actif. | Parameter | Type | Required | Default | |---|---|---|---| | `preset` | `string` | required | — | | `transitionSeconds` | `number` | optional | `0` | | `priority` | `integer` | optional | `5` | Returns: `true en cas de succès, sinon false`, `applied si succès, sinon raison du refus` Registered in `ResourceHost.cpp` (line 6742) as `LuaEnvironmentSetWeather`. ## setWeatherFrozen ```lua CyberM.environment.setWeatherFrozen(frozen) ``` `GAME` — Requires a live game instance. Désactive ou réactive le contrôleur météo automatique vanilla. Demande `world.environment`. Figer conserve le preset courant et laisse le serveur décider du prochain événement. | Parameter | Type | Required | Default | |---|---|---|---| | `frozen` | `boolean` | required | — | Returns: `true en cas de succès, sinon false`, `raison du refus` Registered in `ResourceHost.cpp` (line 6743) as `LuaEnvironmentFreezeWeather`. --- Source: https://open2077.net/docs/api/client/cyberm-events # CyberM.events — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 3 functions. ## emit ```lua CyberM.events.emit(event, [payload]) ``` `SHARED` — Available without a live game instance. Fires a local event. Emits an event on the resource-local client bus and invokes matching local handlers. It never sends a packet; use the network event API for server communication. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `payload` | `table` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6558) as `LuaTriggerEvent`. ## off ```lua CyberM.events.off(event, handler) ``` `SHARED` — Available without a live game instance. Removes a handler registered with `on`. Unregisters a local event handler id previously returned by `on`/`AddEventHandler`. Handler ids are owned by a resource generation and cannot remove another resource's callback. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6557) as `LuaRemoveEventHandler`. ## on ```lua CyberM.events.on(event, handler) ``` `SHARED` — Available without a live game instance. Listens for a local event. Same as the `AddEventHandler` global. Events emitted by the plugin — `cyberm:pauseKey`, `cyberm:inspector:on` — arrive here. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `handler id` Registered in `ResourceHost.cpp` (line 6556) as `LuaAddEventHandler`. --- Source: https://open2077.net/docs/api/client/cyberm-exports # CyberM.exports — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 1 function. ## call ```lua CyberM.exports.call(resource, export, […]) ``` `SHARED` — Available without a live game instance. Calls a function exported by another resource. Schedules another running client resource's exported function and returns a generation-bound Promise. Arguments and results must be serializable; unavailable resources, missing exports, stale generations and scheduler saturation are returned immediately as `nil, reason`. | Parameter | Type | Required | Default | |---|---|---|---| | `resource` | `string` | required | — | | `export` | `string` | required | — | | `…` | `any` | optional | — | Returns: `whatever the export returns` Registered in `ResourceHost.cpp` (line 6577) as `LuaCallExport`. --- Source: https://open2077.net/docs/api/client/cyberm-input # CyberM.input — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## isCaptured ```lua CyberM.input.isCaptured() ``` `GAME` — Requires a live game instance. Whether another WebUI currently owns keyboard input. Contextual actions should become inert while this is true so chat and menu typing cannot activate gameplay. Returns: `boolean`, `reason when permission is refused` Registered in `ResourceHost.cpp` (line 6758) as `LuaInputCaptured`. ## isDown ```lua CyberM.input.isDown(key) ``` `GAME` — Requires a live game instance. Whether an allowlisted contextual action key is currently held. Requires `input.actions`. Supported keys are A-Z, 0-9, SPACE, ENTER/RETURN, and arrows. Prefer a press edge or hold timer over firing every frame. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | Returns: `boolean`, `reason when the key or permission is refused` Registered in `ResourceHost.cpp` (line 6757) as `LuaInputKeyDown`. --- Source: https://open2077.net/docs/api/client/cyberm-inspector # CyberM.inspector — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 3 functions. ## enable ```lua CyberM.inspector.enable([enabled]) ``` `GAME` — Requires a live game instance. Turns the permanent aim ray on or off. Turning it off also clears the outline: the outline belongs to the session that asked for it and must not outlive it. | Parameter | Type | Required | Default | |---|---|---|---| | `enabled` | `boolean` | optional | `true` | Returns: `true`, `reason, when the first is nil` Registered in `ResourceHost.cpp` (line 6641) as `LuaInspectorEnable`. ## outline ```lua CyberM.inspector.outline([enabled]) ``` `GAME` — Requires a live game instance. Outlines the aimed object, independently of the ray. Lets a caller read the target without painting the world. The outline uses `entRenderHighlightEvent`, the same event focus mode and scanning already use. | Parameter | Type | Required | Default | |---|---|---|---| | `enabled` | `boolean` | optional | `true` | Returns: `true`, `reason, when the first is nil` Registered in `ResourceHost.cpp` (line 6642) as `LuaInspectorOutline`. ## target ```lua CyberM.inspector.target() ``` `GAME` — Requires a live game instance. What the aim ray is currently pointing at. Reads a snapshot, never a probe. The ray has to be cast on the game thread, and the plugin refreshes it at 10 Hz, so calling this costs nothing and cannot land a raycast on the wrong thread. Always returns a table when a game is present. `valid` separates "nothing in view" from "no game" — the latter returns `nil, reason`. Returns: `table { valid, engineId, class, name, kind, position, distance }`, `reason, when the first is nil` ```lua local t = CyberM.inspector.target() if t and t.valid then print(t.kind, t.name, t.distance) --> door Door 1.38 end ``` Registered in `ResourceHost.cpp` (line 6640) as `LuaInspectorTarget`. --- Source: https://open2077.net/docs/api/client/cyberm-json # CyberM.json — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## decode ```lua CyberM.json.decode(text) ``` `SHARED` — Available without a live game instance. Parses a JSON string. Parses JSON into CyberM's bounded Lua value model. Invalid JSON returns `nil, "invalid_json"`; decoded objects and arrays contain only supported scalar/table values. | Parameter | Type | Required | Default | |---|---|---|---| | `text` | `string` | required | — | Returns: `value, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6830) as `LuaJsonDecode`. ## encode ```lua CyberM.json.encode(value) ``` `SHARED` — Available without a live game instance. Serialises a Lua value to JSON. Serializes a supported Lua value to JSON using the same bounded representation used by events, exports and WebUI. Functions, userdata, cycles and unsupported table shapes return `nil, reason`. | Parameter | Type | Required | Default | |---|---|---|---| | `value` | `any` | required | — | Returns: `string, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6829) as `LuaJsonEncode`. --- Source: https://open2077.net/docs/api/client/cyberm-kvp # CyberM.kvp — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 11 functions. ## clear ```lua CyberM.kvp.clear([prefix]) ``` `CLIENT` — Client-only surface. Clears this resource's keys matching a prefix. Atomically removes every key matching an optional prefix from the calling resource's current-server store and returns the removal count. An empty prefix clears only that resource namespace. | Parameter | Type | Required | Default | |---|---|---|---| | `prefix` | `string` | optional | — | Returns: `removed count, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6532) as `LuaKvpClear`. ## compareAndSet ```lua CyberM.kvp.compareAndSet(key, expected, replacement) ``` `CLIENT` — Client-only surface. Atomically changes a key when its typed value matches. Atomically replaces a key only when its typed value exactly matches the expected value. Nil expected means the key must be absent; nil replacement deletes after a successful comparison. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `expected` | `any` | required | — | | `replacement` | `any` | required | — | Returns: `boolean`, `reason on storage failure` Registered in `ResourceHost.cpp` (line 6535) as `LuaKvpCas`. ## delete ```lua CyberM.kvp.delete(key) ``` `CLIENT` — Client-only surface. Deletes one persistent key. Atomically deletes one key from the current resource store and returns whether it existed. Deleting a missing key succeeds with false. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | Returns: `true when removed, false when absent`, `reason on storage failure` Registered in `ResourceHost.cpp` (line 6529) as `LuaKvpDelete`. ## find ```lua CyberM.kvp.find([prefix], [limit]) ``` `CLIENT` — Client-only surface. Finds typed entries by sorted key prefix. Performs a sorted prefix search in the current resource store and returns bounded `{key, value, type}` records. The default result limit is 256 and the hard limit is 4096. | Parameter | Type | Required | Default | |---|---|---|---| | `prefix` | `string` | optional | — | | `limit` | `integer` | optional | `256` | Returns: `array of { key, value, type }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6530) as `LuaKvpFind`. ## get ```lua CyberM.kvp.get(key, [default]) ``` `CLIENT` — Client-only surface. Reads one typed persistent value. Reads a typed value from the current connection-address and resource namespace. Missing keys return the optional default (or nil) and are distinct from storage errors, which return `nil, reason`. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `default` | `any` | optional | — | Returns: `stored value, default or nil`, `reason on storage failure` Registered in `ResourceHost.cpp` (line 6527) as `LuaKvpGet`. ## has ```lua CyberM.kvp.has(key) ``` `CLIENT` — Client-only surface. Checks whether a persistent key exists. Checks whether a key exists in the calling resource's current-server store without exposing its value or any other resource namespace. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | Returns: `boolean`, `reason on storage failure` Registered in `ResourceHost.cpp` (line 6528) as `LuaKvpHas`. ## increment ```lua CyberM.kvp.increment(key, [delta]) ``` `CLIENT` — Client-only surface. Atomically increments a numeric key. Atomically creates or increments a numeric key. Integer arithmetic remains 64-bit and rejects overflow; mixed/floating arithmetic rejects non-finite results. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `delta` | `integer|number` | optional | `1` | Returns: `new numeric value, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6533) as `LuaKvpIncrement`. ## keys ```lua CyberM.kvp.keys([prefix], [limit]) ``` `CLIENT` — Client-only surface. Lists sorted keys matching a prefix. Returns only the sorted keys matching an optional prefix in the current resource store. It is a bounded index query and cannot enumerate another package or connection address. | Parameter | Type | Required | Default | |---|---|---|---| | `prefix` | `string` | optional | — | | `limit` | `integer` | optional | `256` | Returns: `string array, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6531) as `LuaKvpFind`. ## set ```lua CyberM.kvp.set(key, value) ``` `CLIENT` — Client-only surface. Persists one typed value for this server address and resource. Atomically persists a string, signed integer, finite number or boolean under the current connection address and resource. Keys/values and the 1 MiB resource quota are validated before the old file is replaced. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `value` | `string|integer|number|boolean` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6526) as `LuaKvpSet`. ## setIfAbsent ```lua CyberM.kvp.setIfAbsent(key, value) ``` `CLIENT` — Client-only surface. Stores a value only when its key is missing. Redis-style SETNX for the current resource namespace: atomically stores the typed value only when the key is missing and reports whether insertion occurred. | Parameter | Type | Required | Default | |---|---|---|---| | `key` | `string` | required | — | | `value` | `string|integer|number|boolean` | required | — | Returns: `boolean`, `reason on storage failure` Registered in `ResourceHost.cpp` (line 6534) as `LuaKvpSetNx`. ## stats ```lua CyberM.kvp.stats() ``` `CLIENT` — Client-only surface. Returns this resource store's usage and quotas. Returns this resource's entry/byte usage and enforced quotas together with the active address/resource scope. It exposes no keys or usage belonging to other resources. Returns: `table, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6536) as `LuaKvpStats`. --- Source: https://open2077.net/docs/api/client/cyberm-loot # CyberM.loot — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## acceptPickup ```lua CyberM.loot.acceptPickup(id, item, quantity) ``` `GAME` — Requires a live game instance. Applique localement un pickup déjà accepté par le serveur. API interne appelée uniquement après `cyberm:loot:pickupResult`. Elle projette l'objet dans l'inventaire REDengine local; l'inventaire persistant reste une responsabilité serveur. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `item` | `string` | required | — | | `quantity` | `integer` | required | — | Returns: `true en cas de succès`, `raison du refus` Registered in `ResourceHost.cpp` (line 6686) as `LuaLootAccept`. ## clear ```lua CyberM.loot.clear() ``` `GAME` — Requires a live game instance. Supprime toutes les projections locales et leurs prompts. Clears the client-side native loot projection when the caller has `world.loot`. This is intended for the authoritative loot replication package during snapshot replacement; ordinary gameplay resources should request server-owned changes instead. Registered in `ResourceHost.cpp` (line 6684) as `LuaLootClear`. ## remove ```lua CyberM.loot.remove(id) ``` `GAME` — Requires a live game instance. Retire une projection locale de loot. Removes one replicated native loot entity from this client's projection and requires `world.loot`. It does not by itself delete the server record, so gameplay code should normally use the authoritative loot package API. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `true en cas de succès`, `raison du refus` Registered in `ResourceHost.cpp` (line 6683) as `LuaLootRemove`. ## requestPickup ```lua CyberM.loot.requestPickup(id) ``` `NETWORK` — Uses the network backend. Demande au serveur de ramasser un drop. Le serveur contrôle l'existence, le routing bucket et la distance calculée depuis son dernier snapshot du joueur. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `true si la requête réseau est partie`, `raison du refus local` Registered in `ResourceHost.cpp` (line 6685) as `LuaLootRequest`. ## setAuthorityEnabled ```lua CyberM.loot.setAuthorityEnabled(enabled) ``` `GAME` — Requires a live game instance. Active ou désactive la projection de loot autoritaire. Réservé à `cyberm_loot`. Quand il est actif, les choix, conteneurs et drops vanilla sont neutralisés et les objets physiques deviennent de simples représentations du registre serveur. | Parameter | Type | Required | Default | |---|---|---|---| | `enabled` | `boolean` | required | — | Returns: `true en cas de succès`, `raison du refus` Registered in `ResourceHost.cpp` (line 6681) as `LuaLootAuthority`. ## upsert ```lua CyberM.loot.upsert(drop) ``` `GAME` — Requires a live game instance. Crée ou met à jour la projection locale d'un drop serveur. API interne de réplication. Demande la permission `world.loot`; un script gameplay ne doit pas inventer un drop côté client. | Parameter | Type | Required | Default | |---|---|---|---| | `drop` | `table { id, item, quantity, position, radius, label, model, revision }` | required | — | Returns: `true en cas de succès`, `raison du refus` Registered in `ResourceHost.cpp` (line 6682) as `LuaLootUpsert`. --- Source: https://open2077.net/docs/api/client/cyberm-markers # CyberM.markers — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 5 functions. ## clear ```lua CyberM.markers.clear() ``` `GAME` — Requires a live game instance. Removes every 3D marker owned by the calling resource. Requires `world.markers`; other resources are unaffected. Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6800) as `LuaMarkerClear`. ## create ```lua CyberM.markers.create(options) ``` `GAME` — Requires a live game instance. Creates a resource-owned 3D world marker. Requires `world.markers`. Options require `position` and accept `shape`, `style`, `radius`, `maxDistance`, `minDistance`, and `visible`. The returned decimal-string handle preserves its full 64-bit identity. | Parameter | Type | Required | Default | |---|---|---|---| | `options` | `table` | required | — | Returns: `marker handle string, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6797) as `LuaMarkerCreate`. ## list ```lua CyberM.markers.list() ``` `GAME` — Requires a live game instance. Lists the calling resource's 3D markers. Requires `world.markers`. Each snapshot includes its requested definition and whether the native renderer currently presents it. Returns: `array of { id, shape, style, radius, maxDistance, minDistance, visible, rendered, position }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6801) as `LuaMarkerList`. ## remove ```lua CyberM.markers.remove(id) ``` `GAME` — Requires a live game instance. Removes one resource-owned 3D marker. Requires `world.markers`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `string` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6799) as `LuaMarkerRemove`. ## update ```lua CyberM.markers.update(id, patch) ``` `GAME` — Requires a live game instance. Patches a resource-owned 3D marker. Requires `world.markers`. Only supplied fields are changed, and ownership prevents mutation of another resource's marker. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `string` | required | — | | `patch` | `table` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6798) as `LuaMarkerUpdate`. --- Source: https://open2077.net/docs/api/client/cyberm-nameplates # CyberM.nameplates — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 4 functions. ## clear ```lua CyberM.nameplates.clear() ``` `GAME` — Requires a live game instance. Removes every nameplate override owned by the calling resource. Requires `ui.nameplates`; other owners are unaffected. Returns: `true on success` Registered in `ResourceHost.cpp` (line 6771) as `LuaNameplateClear`. ## remove ```lua CyberM.nameplates.remove(playerId) ``` `GAME` — Requires a live game instance. Removes the calling resource's nameplate override for one player. Requires `ui.nameplates`. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer|string` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6770) as `LuaNameplateRemove`. ## set ```lua CyberM.nameplates.set(playerId, options) ``` `GAME` — Requires a live game instance. Creates or updates the calling resource's nameplate override for a remote player. Requires `ui.nameplates`. Options accept `label`, `color`, `maxDistance`, and `visible`. Overrides are owner-scoped and cleaned up with the resource. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer|string` | required | — | | `options` | `table` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6769) as `LuaNameplateSet`. ## snapshot ```lua CyberM.nameplates.snapshot() ``` `GAME` — Requires a live game instance. Returns the currently rendered remote-player nameplates. Requires `ui.nameplates`. Screen coordinates and distance describe the most recent presentation snapshot. Returns: `array of { id, label, color, x, y, distance }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6772) as `LuaNameplateSnapshot`. --- Source: https://open2077.net/docs/api/client/cyberm-net # CyberM.net — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## emitServer ```lua CyberM.net.emitServer(event, [payload]) ``` `NETWORK` — Uses the network backend. Sends an event to the server. Alias of `TriggerServerEvent`: sends a bounded, serializable event payload to the authenticated server session. The current resource must declare `network.events`. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `payload` | `table` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6563) as `LuaTriggerServerEvent`. ## on ```lua CyberM.net.on(event, handler) ``` `NETWORK` — Uses the network backend. Listens for an event coming from the server. Registers an authenticated incoming server event and its callback for the current resource generation. It is the namespaced equivalent of `RegisterNetEvent` and requires `network.events`. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `handler id` Registered in `ResourceHost.cpp` (line 6562) as `LuaRegisterNetEvent`. --- Source: https://open2077.net/docs/api/client/cyberm-network # CyberM.network — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 7 functions. ## catalog ```lua CyberM.network.catalog() ``` `NETWORK` — Uses the network backend. The catalog as of the last refresh. Reads a snapshot: refreshing is asynchronous, so call `refresh`, then `catalog` a beat later. Returns: `table { phase, generation, servers… }` Registered in `ResourceHost.cpp` (line 6568) as `LuaNetworkCatalog`. ## connect ```lua CyberM.network.connect(endpoint, [name]) ``` `NETWORK` — Uses the network backend. Joins a CyberM server. Starts a connection to the supplied CyberM server endpoint using the current identity and resource pipeline. It requires `network.client`; success means the request was accepted, while connection progress and errors are observed through `status()`. | Parameter | Type | Required | Default | |---|---|---|---| | `endpoint` | `string` | required | — | | `name` | `string` | optional | — | Returns: `true when the request is accepted`, `reason for the refusal` ```lua local ok, reason = CyberM.network.connect("127.0.0.1:11778", "Player") ``` Registered in `ResourceHost.cpp` (line 6569) as `LuaNetworkConnect`. ## disconnect ```lua CyberM.network.disconnect() ``` `NETWORK` — Uses the network backend. Leaves the current server. Requests an orderly disconnect with an optional diagnostic reason. It returns after queuing teardown; the session phase in `status()` is the authoritative view of when cleanup has completed. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6570) as `LuaNetworkDisconnect`. ## identity ```lua CyberM.network.identity() ``` `NETWORK` — Uses the network backend. Reads the local Master-backed identity profile state. Returns the durable user id, current display name, registration state, and asynchronous update phase. The private key is never exposed. This bridge exists for the trusted local server browser; server-downloaded resources should use the verified player APIs instead. Returns: `table { phase, generation, userId, displayName, error, registered }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6573) as `LuaNetworkIdentity`. ## identityUpdate ```lua CyberM.network.identityUpdate(catalogUrl, displayName) ``` `NETWORK` — Uses the network backend. Requests a signed username update from the Master. Queues the HTTP enrollment on the networking worker and returns immediately. Poll `identity()` until the matching generation becomes `ready` or `failed`. The backend is deliberately available only to the trusted system server-browser resource and refuses updates during a live session. | Parameter | Type | Required | Default | |---|---|---|---| | `catalogUrl` | `string` | required | — | | `displayName` | `string` | required | — | Returns: `true when queued, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6572) as `LuaNetworkIdentityUpdate`. ## refresh ```lua CyberM.network.refresh([url]) ``` `NETWORK` — Uses the network backend. Asks the directory for the server catalog again. Starts a master-server catalog refresh for the supplied URL and requires `network.client`. The call only accepts the request; use `catalog()` to inspect generation, phase, HTTP status, body and error. | Parameter | Type | Required | Default | |---|---|---|---| | `url` | `string` | optional | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6567) as `LuaNetworkRefresh`. ## status ```lua CyberM.network.status() ``` `NETWORK` — Uses the network backend. State of the network session. Returns the current client session snapshot: phase, endpoint, authenticated player identity, routing bucket, rates, server time, ping and downloaded resource-set metadata. Reading it does not initiate a connection or wait for a phase change. Returns: `table { phase, endpoint, playerId, routingBucket, ping, error }` Registered in `ResourceHost.cpp` (line 6571) as `LuaNetworkStatus`. --- Source: https://open2077.net/docs/api/client/cyberm-npcs # CyberM.npcs — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 5 functions. ## all ```lua CyberM.npcs.all() ``` `GAME` — Requires a live game instance. Lists server-owned NPCs currently known by this client. Canonical creation, tasks, health and removal are server-only; see wiki/npcs.md. Returns: `array of NPC snapshots` Registered in `ResourceHost.cpp` (line 6716) as `LuaNpcsAll`. ## currentTask ```lua CyberM.npcs.currentTask(id) ``` `GAME` — Requires a live game instance. Returns the canonical active task ID for an NPC. Returns the last CyberM NPC task snapshot currently presented for a network NPC. It requires `npcs.read`; task state is ephemeral and can disappear when the NPC leaves the streaming set. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `task id, or nil` Registered in `ResourceHost.cpp` (line 6719) as `LuaNpcCurrentTask`. ## entity ```lua CyberM.npcs.entity(id) ``` `GAME` — Requires a live game instance. Returns the ephemeral local CyberM entity handle for an NPC projection. Returns nil before readiness and after stream-out. Never cache this handle across lifecycle changes. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `entity, or nil` Registered in `ResourceHost.cpp` (line 6718) as `LuaNpcEntity`. ## get ```lua CyberM.npcs.get(id) ``` `GAME` — Requires a live game instance. Reads one server-owned NPC currently known by this client. Read-only and guarded by npcs.read. The local entity handle is generation-checked and becomes invalid after stream-out. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `NPC snapshot, or nil` Registered in `ResourceHost.cpp` (line 6715) as `LuaNpcGet`. ## isStreamedIn ```lua CyberM.npcs.isStreamedIn(id) ``` `GAME` — Requires a live game instance. Whether an NPC projection is attached and ready locally. Reports whether a network NPC currently has a live client proxy in this player's streaming scope. It does not request streaming or prove that the server NPC record no longer exists. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6717) as `LuaNpcIsStreamedIn`. --- Source: https://open2077.net/docs/api/client/cyberm-players # CyberM.players — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## allHealthStates ```lua CyberM.players.allHealthStates() ``` `GAME` — Requires a live game instance. Lists all replicated player health snapshots known to the client. Requires `players.life.read`; returns an empty array when unavailable. Returns: `array of health snapshots` Registered in `ResourceHost.cpp` (line 6735) as `LuaPlayerHealthAll`. ## allLifeStates ```lua CyberM.players.allLifeStates() ``` `GAME` — Requires a live game instance. Lists all replicated canonical player life states known to the client. Requires `players.life.read`; returns an empty array when unavailable. Returns: `array of life snapshots` Registered in `ResourceHost.cpp` (line 6733) as `LuaPlayerLifeAll`. ## getHealthState ```lua CyberM.players.getHealthState([playerId]) ``` `GAME` — Requires a live game instance. Reads one replicated player health snapshot. Requires `players.life.read`. Omit `playerId` for the local player. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer` | optional | — | Returns: `table { playerId, revision, health, maxHealth, armor, godMode, lastAttacker, lastDamage, lastAttackKind, lastBodyPart, lastHitDirection }, or nil` Registered in `ResourceHost.cpp` (line 6734) as `LuaPlayerHealthState`. ## getLifeState ```lua CyberM.players.getLifeState([playerId]) ``` `GAME` — Requires a live game instance. Reads the canonical replicated life state of one player. Requires `players.life.read`. Omit `playerId` for the local session player. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer` | optional | — | Returns: `life snapshot, or nil` Registered in `ResourceHost.cpp` (line 6730) as `LuaPlayerLifeState`. ## getLocalDeathContext ```lua CyberM.players.getLocalDeathContext() ``` `GAME` — Requires a live game instance. Reads the local player's replicated death context. Requires `players.life.read`. The snapshot includes phase, cause, killer, weapon, position, yaw, impulse, revision and grace duration. Returns: `life snapshot, or nil` Registered in `ResourceHost.cpp` (line 6731) as `LuaLocalDeathContext`. ## isDead ```lua CyberM.players.isDead([playerId]) ``` `GAME` — Requires a live game instance. Whether a player is canonically dead or awaiting revive/respawn. Requires `players.life.read`. Omit `playerId` for the local player. Unknown or unavailable states return false. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6732) as `LuaPlayerIsDead`. --- Source: https://open2077.net/docs/api/client/cyberm-promise # CyberM.Promise — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## await ```lua CyberM.Promise.await() ``` `SHARED` — Available without a live game instance. Waits for a promise to settle. Only usable inside a `CreateThread`. Returns: `resolved value, or nil`, `rejection reason` Registered in `ResourceHost.cpp` (line 6461) as `LuaPromiseAwait`. ## status ```lua CyberM.Promise.status() ``` `SHARED` — Available without a live game instance. State of the promise, without waiting. Returns the promise state without yielding the current coroutine. Use it for polling or diagnostics; `await()` remains the normal way to receive a completed export result. Returns: `"pending", "resolved" or "rejected"` Registered in `ResourceHost.cpp` (line 6462) as `LuaPromiseStatus`. --- Source: https://open2077.net/docs/api/client/cyberm-resource # CyberM.resource — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## generation ```lua CyberM.resource.generation([resource]) ``` `SHARED` — Available without a live game instance. Generation number, incremented on every reload. With no argument, returns the current resource generation. Pass a resource name to inspect that resource, or receive nil when it is missing. | Parameter | Type | Required | Default | |---|---|---|---| | `resource` | `string` | optional | — | Returns: `integer, or nil` Registered in `ResourceHost.cpp` (line 6518) as `LuaResourceGeneration`. ## hasPermission ```lua CyberM.resource.hasPermission(permission) ``` `SHARED` — Available without a live game instance. Whether the resource holds this permission. Checks whether the current resource manifest grants an exact CyberM capability. It is a read-only convenience check; native APIs still enforce their own permission and must handle refusal results. | Parameter | Type | Required | Default | |---|---|---|---| | `permission` | `string` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6522) as `LuaHasPermission`. ## name ```lua CyberM.resource.name() ``` `SHARED` — Available without a live game instance. Name of the current resource. Returns the current resource's immutable manifest name. This is equivalent to `GetCurrentResourceName()` and remains stable for the lifetime of the resource definition. Returns: `string` Registered in `ResourceHost.cpp` (line 6517) as `LuaResourceName`. ## readFile ```lua CyberM.resource.readFile(path) ``` `SHARED` — Available without a live game instance. Reads a file from the resource, within its declared allowlist. Reads a file declared by the current resource manifest through a safe relative path. Undeclared files, traversal, oversized content and host filesystem paths are rejected. | Parameter | Type | Required | Default | |---|---|---|---| | `path` | `string` | required | — | Returns: `contents, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6521) as `LuaReadFile`. ## state ```lua CyberM.resource.state([resource]) ``` `SHARED` — Available without a live game instance. State of a resource. Returns the lifecycle state known for a resource name, or for the current resource when omitted. It is an immediate snapshot and does not wait for dependencies or mutate lifecycle state. | Parameter | Type | Required | Default | |---|---|---|---| | `resource` | `string` | optional | — | Returns: `string` Registered in `ResourceHost.cpp` (line 6520) as `LuaGetResourceState`. ## version ```lua CyberM.resource.version() ``` `SHARED` — Available without a live game instance. Version declared in `cyberm.lua`. Returns the version string declared by the current resource manifest. It is package metadata and is unrelated to the CyberM runtime or Lua interpreter version. Returns: `string` Registered in `ResourceHost.cpp` (line 6519) as `LuaResourceVersion`. --- Source: https://open2077.net/docs/api/client/cyberm-runtime # CyberM.runtime — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## luaVersion ```lua CyberM.runtime.luaVersion() ``` `SHARED` — Available without a live game instance. Embedded Lua version. Returns the embedded Lua interpreter version used by this resource VM. Use it for diagnostics or compatibility checks, not to infer the CyberM build version. Returns: `string` Registered in `ResourceHost.cpp` (line 6546) as `LuaLanguageVersion`. ## version ```lua CyberM.runtime.version() ``` `SHARED` — Available without a live game instance. CyberM version. Returns the CyberM scripting runtime version exposed to resources. This describes the host API and is distinct from both the resource manifest version and game build. Returns: `string` Registered in `ResourceHost.cpp` (line 6545) as `LuaRuntimeVersion`. --- Source: https://open2077.net/docs/api/client/cyberm-session # CyberM.session — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 3 functions. ## loadPristine ```lua CyberM.session.loadPristine() ``` `GAME` — Requires a live game instance. Loads the local development world from CyberM's bundled pristine save. No network session is armed by this operation. Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6596) as `LuaSessionLoadPristine`. ## openSettings ```lua CyberM.session.openSettings() ``` `GAME` — Requires a live game instance. Opens the game's own settings screen without exposing the pause menu. Requests the client-side CyberM settings interface. It only changes local presentation and does not modify server configuration or another player's settings. Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6595) as `LuaSessionOpenSettings`. ## setMenuReady ```lua CyberM.session.setMenuReady(ready) ``` `GAME` — Requires a live game instance. Declares that this resource is able to serve the pause menu. The escape key is only intercepted while this is true. A resource that fails to start therefore leaves the game's own menu reachable, rather than stranding the player with none. | Parameter | Type | Required | Default | |---|---|---|---| | `ready` | `boolean` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6597) as `LuaSessionMenuReady`. --- Source: https://open2077.net/docs/api/client/cyberm-settings # CyberM.settings — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 3 functions. ## request ```lua CyberM.settings.request(group) ``` `GAME` — Requires a live game instance. Asks the script bridge to list the variables of a group. Asynchronous: request, then read with `values` a beat later. | Parameter | Type | Required | Default | |---|---|---|---| | `group` | `string` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6601) as `LuaSettingsRequest`. ## set ```lua CyberM.settings.set(group, name, value) ``` `GAME` — Requires a live game instance. Writes a settings variable. Submits one local CyberM setting change through the settings backend. The key, value type and published bounds are validated; use `values()` to read the resulting projection. | Parameter | Type | Required | Default | |---|---|---|---| | `group` | `string` | required | — | | `name` | `string` | required | — | | `value` | `integer` | required | — | Returns: `boolean`, `reason` Registered in `ResourceHost.cpp` (line 6603) as `LuaSettingsSet`. ## values ```lua CyberM.settings.values() ``` `GAME` — Requires a live game instance. The variables as the script last reported them. Returns a snapshot of the settings currently published by the client backend. The returned table is a copy and modifying it does not apply changes. Returns: `table of { name, value, minimum, maximum, step }` Registered in `ResourceHost.cpp` (line 6602) as `LuaSettingsValues`. --- Source: https://open2077.net/docs/api/client/cyberm-sfx # CyberM.sfx — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 4 functions. ## clear ```lua CyberM.sfx.clear() ``` `GAME` — Requires a live game instance. Stops every SFX owned by the calling resource. Requires `world.effects`; VFX and other resource owners are unaffected. Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6821) as `LuaEffectClear`. ## list ```lua CyberM.sfx.list() ``` `GAME` — Requires a live game instance. Lists active SFX owned by the calling resource. Requires `world.effects`. Returns: `array of { id, kind, name, entity, remaining }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6824) as `LuaEffectList`. ## play ```lua CyberM.sfx.play(event, [options]) ``` `GAME` — Requires a live game instance. Starts resource-owned spatial audio on an entity. Requires `world.effects`. Options accept `entity`, `emitter`, `tag`, `seekTime`, `duration`, and `unique`; omitting `entity` uses the local player. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `options` | `table` | optional | — | Returns: `effect handle string, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6818) as `LuaSfxPlay`. ## stop ```lua CyberM.sfx.stop(id) ``` `GAME` — Requires a live game instance. Stops one SFX handle owned by the calling resource. Requires `world.effects`. REDengine stops audio by event name, so identical simultaneous events on one entity may share stop behavior. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `string` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6819) as `LuaEffectStop`. --- Source: https://open2077.net/docs/api/client/cyberm-time # CyberM.time — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 1 function. ## monotonic ```lua CyberM.time.monotonic() ``` `SHARED` — Available without a live game instance. Monotonic clock, in milliseconds. Never goes backwards, unlike wall-clock time: this is the one to measure a duration with. Returns: `number` Registered in `ResourceHost.cpp` (line 6513) as `LuaMonotonic`. --- Source: https://open2077.net/docs/api/client/cyberm-travel # CyberM.travel — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 4 functions. ## isNoclip ```lua CyberM.travel.isNoclip() ``` `GAME` — Requires a live game instance. Whether local-player noclip is currently active. Returns false without `player.travel` or when the backend is unavailable. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6763) as `LuaTravelIsNoclip`. ## setNoclip ```lua CyberM.travel.setNoclip(enabled) ``` `GAME` — Requires a live game instance. Enables or disables native noclip for the local player. Requires `player.travel`. Multiplayer deployments should expose this only behind an ACL-checked server command. | Parameter | Type | Required | Default | |---|---|---|---| | `enabled` | `boolean` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6762) as `LuaTravelSetNoclip`. ## setNoclipSpeed ```lua CyberM.travel.setNoclipSpeed(speed) ``` `GAME` — Requires a live game instance. Sets the local noclip movement speed. Requires `player.travel`; the value must be finite and is validated by the native backend. | Parameter | Type | Required | Default | |---|---|---|---| | `speed` | `number` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6764) as `LuaTravelSetNoclipSpeed`. ## teleport ```lua CyberM.travel.teleport(x, y, z, [heading]) ``` `GAME` — Requires a live game instance. Teleports the local player directly to a world transform. Requires `player.travel`. Prefer the authoritative server respawn transaction for long-distance multiplayer moves because it handles streaming and life state. | Parameter | Type | Required | Default | |---|---|---|---| | `x` | `number` | required | — | | `y` | `number` | required | — | | `z` | `number` | required | — | | `heading` | `number` | optional | `0` | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6765) as `LuaTravelTeleport`. --- Source: https://open2077.net/docs/api/client/cyberm-vehicles # CyberM.vehicles — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## all ```lua CyberM.vehicles.all() ``` `GAME` — Requires a live game instance. Lists every vehicle currently streamed to this client. Requires `vehicles.read`. Returns an empty array when permission or the projection backend is unavailable. Every entry has the exact shape returned by `CyberM.vehicles.get`; server vehicles outside the client's streaming interest set are intentionally absent. Returns: `array of vehicle snapshots` Registered in `ResourceHost.cpp` (line 6691) as `LuaVehiclesAll`. ## get ```lua CyberM.vehicles.get(id) ``` `GAME` — Requires a live game instance. Reads one streamed server-owned vehicle. Client read-only API requiring `vehicles.read`. The snapshot contains durable state (`health`, flags, six door bits, four open-window bits, tyre/glass/light masks and the 30-cell body grid), authority and occupants, an ephemeral generation-checked local entity handle, plus the latest drivetrain and wheel telemetry. Open windows and broken glass are separate states. Creation, repair and arbitrary mutation are server-only; the complete 43-method server surface is documented in `wiki/vehicles.md`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | Returns: `table { id, record, entity, engineEntity, revision, physicsOwner, authorityEpoch, flags, health, doors, windows, tires, bodyDamage, brokenGlass, brokenLights, damage, speed, rpm, rpmMax, throttle, brake, steering, wheelRotation, suspensionLongitudinal, suspensionTransversal, burnout, gear, onGround, reversing, streamed, locallyOwned, occupants }, or nil` Registered in `ResourceHost.cpp` (line 6690) as `LuaVehicleGet`. ## isDoorOpen ```lua CyberM.vehicles.isDoorOpen(id, door) ``` `GAME` — Requires a live game instance. Reads a canonical vehicle door, trunk, or hood state. Client read-only API requiring `vehicles.read`. Accepts index 0..5, a standard camelCase/snake_case name, or a `CyberM.vehicles.doors` constant. This reads the replicated reversible opening mask. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `door` | `integer|string` | required | — | Returns: `boolean, or nil when denied, unavailable, or unknown` Registered in `ResourceHost.cpp` (line 6692) as `LuaVehicleIsDoorOpen`. ## isWindowOpen ```lua CyberM.vehicles.isWindowOpen(id, window) ``` `GAME` — Requires a live game instance. Reads a canonical openable side-window state. Client read-only API requiring `vehicles.read`. Windows use indexes 0..3 and names `frontLeft`, `frontRight`, `backLeft`, and `backRight`. This does not report shattered glass; inspect `brokenGlass` or `damage.glass` in the vehicle snapshot for that. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `integer` | required | — | | `window` | `integer|string` | required | — | Returns: `boolean, or nil when denied, unavailable, or unknown` Registered in `ResourceHost.cpp` (line 6693) as `LuaVehicleIsWindowOpen`. ## taskPlayerEnterVehicle ```lua CyberM.vehicles.taskPlayerEnterVehicle(playerId, vehicleId, seat) ``` `GAME` — Requires a live game instance. Reserved animated presentation path for a replicated occupant. Requires `vehicles.presentation` and an already-authorized occupancy tuple. The first native NPC `MountAIEvent` implementation could dereference an absent workspot object on remote player proxies, so this method currently fails closed with `animated_entry_unsupported`. Use `warpPlayerIntoVehicle` until the staged door/workspot implementation is validated on two clients. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer|string` | required | — | | `vehicleId` | `integer|string` | required | — | | `seat` | `string|integer` | required | — | Returns: `false`, `animated_entry_unsupported or another validation reason` Registered in `ResourceHost.cpp` (line 6695) as `LuaVehicleTaskPlayerEnter`. ## warpPlayerIntoVehicle ```lua CyberM.vehicles.warpPlayerIntoVehicle(playerId, vehicleId, seat) ``` `GAME` — Requires a live game instance. Presents a replicated player instantly in an authoritative vehicle seat. Requires `vehicles.presentation`. This is a visual client operation for an existing server-owned vehicle and occupancy assignment; it does not claim the seat or physics authority. The exact `(player, vehicle, seat)` tuple must already exist in the replicated ledger or the call fails with `occupancy_mismatch`. Seats accept canonical names, common aliases, or FiveM-compatible -1..2 indices. | Parameter | Type | Required | Default | |---|---|---|---| | `playerId` | `integer|string` | required | — | | `vehicleId` | `integer|string` | required | — | | `seat` | `string|integer` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6694) as `LuaVehicleWarpPlayer`. --- Source: https://open2077.net/docs/api/client/cyberm-vfx # CyberM.vfx — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 6 functions. ## catalog ```lua CyberM.vfx.catalog() ``` `GAME` — Requires a live game instance. Returns the curated stable world-VFX aliases and cooked paths. Catalog access does not start an effect. Raw cooked paths remain build-dependent even when present. Returns: `table mapping alias to effect path, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6814) as `LuaVfxCatalog`. ## clear ```lua CyberM.vfx.clear() ``` `GAME` — Requires a live game instance. Stops every VFX owned by the calling resource. Requires `world.effects`; SFX and other resource owners are unaffected. Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6809) as `LuaEffectClear`. ## list ```lua CyberM.vfx.list() ``` `GAME` — Requires a live game instance. Lists active VFX owned by the calling resource. Requires `world.effects`. Returns: `array of { id, kind, name, entity, remaining }, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6812) as `LuaEffectList`. ## play ```lua CyberM.vfx.play(effect, options) ``` `GAME` — Requires a live game instance. Starts a resource-owned world VFX at a fixed transform. Requires `world.effects`. `options` requires `position` and accepts `orientation`, `duration`, and `ignoreTimeDilation`. The effect is released automatically with its owner. | Parameter | Type | Required | Default | |---|---|---|---| | `effect` | `string` | required | — | | `options` | `table` | required | — | Returns: `effect handle string, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6805) as `LuaVfxPlay`. ## playEntity ```lua CyberM.vfx.playEntity(effect, [options]) ``` `GAME` — Requires a live game instance. Starts a resource-owned authored VFX on an entity. Requires `world.effects`. Options accept `entity`, `instance`, `persistOnDetach`, `breakAllLoops`, `breakAllOnDestroy`, and `duration`; omitting `entity` targets the local player. | Parameter | Type | Required | Default | |---|---|---|---| | `effect` | `string` | required | — | | `options` | `table` | optional | — | Returns: `effect handle string, or nil`, `reason` Registered in `ResourceHost.cpp` (line 6806) as `LuaVfxPlayEntity`. ## stop ```lua CyberM.vfx.stop(id) ``` `GAME` — Requires a live game instance. Stops one VFX handle owned by the calling resource. Requires `world.effects`. | Parameter | Type | Required | Default | |---|---|---|---| | `id` | `string` | required | — | Returns: `true on success, otherwise false`, `reason` Registered in `ResourceHost.cpp` (line 6807) as `LuaEffectStop`. --- Source: https://open2077.net/docs/api/client/cyberm-webui # CyberM.webui — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 2 functions. ## create ```lua CyberM.webui.create(options) ``` `SHARED` — Available without a live game instance. Creates a web surface. **Creation is asynchronous.** A `show()` issued right after `create` loses the race against the `visible` flag the request carried, and the surface then never paints at all. So a surface meant to stay up is created with `visible = true`, and the page shows or hides its own content. Valid layers: `hud`, `menu`, `modal`, `system` (needs the `webui.system` permission), `debug`. | Parameter | Type | Required | Default | |---|---|---|---| | `options` | `table` | required | — | Returns: `surface, or nil`, `reason` ```lua local overlay = WebUI.create({ entry = "web/index.html", layer = "hud", transparent = true, visible = true -- never false for a permanent overlay }) ``` Registered in `ResourceHost.cpp` (line 6581) as `LuaWebUiCreate`. ## default ```lua CyberM.webui.default() ``` `SHARED` — Available without a live game instance. The surface declared by `web_ui_page` in the manifest. Returns the auto-created WebUI page declared by `web_ui_page` in the current manifest. It returns `nil, reason` when the resource has no live default page; the handle is generation-owned and becomes stale after destroy or reload. Returns: `surface, or nil` Registered in `ResourceHost.cpp` (line 6582) as `LuaWebUiDefault`. --- Source: https://open2077.net/docs/api/client/webui-page # WebUI.Page — client runtime Runs inside the game process. Reads and presentation are local; anything that changes shared state has to go through the server. 9 functions. ## destroy ```lua WebUI.Page.destroy() ``` `SHARED` — Available without a live game instance. Destroys the surface. Destroys this resource-owned browser surface, removes all of its Lua event handlers and invalidates the page handle. Resource teardown performs the same cleanup automatically. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6472) as `LuaWebPageDestroy`. ## hide ```lua WebUI.Page.hide() ``` `SHARED` — Available without a live game instance. Hides the surface. Makes the owned browser surface invisible without destroying its document or handlers. Visibility is client-local and can be restored with `show()`. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6474) as `LuaWebPageVisibility`. ## id ```lua WebUI.Page.id() ``` `SHARED` — Available without a live game instance. Numeric id of the surface. Returns the opaque client-local surface id for diagnostics and host integration. It is not a network id and must not be persisted across page destruction or resource reload. Returns: `integer` Registered in `ResourceHost.cpp` (line 6471) as `LuaWebPageId`. ## off ```lua WebUI.Page.off(event, handler) ``` `SHARED` — Available without a live game instance. Removes a handler registered with `on`. Removes one WebUI callback id previously returned by `page:on`. The id must belong to this page and the current resource generation. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6478) as `LuaWebPageOff`. ## on ```lua WebUI.Page.on(event, handler) ``` `SHARED` — Available without a live game instance. Listens for an event the page raised with `CyberM.emit`. Registers a Lua callback for an event emitted by this page's JavaScript bridge. Event names and handler counts are bounded, and the registration is automatically removed with the page or resource generation. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `handler` | `function` | required | — | Returns: `handler id` Registered in `ResourceHost.cpp` (line 6477) as `LuaWebPageOn`. ## reply ```lua WebUI.Page.reply(request, ok, [payload]) ``` `SHARED` — Available without a live game instance. Answers an `invoke` call made by the page. Completes a pending JavaScript request identified by its request id with a JSON-serializable Lua value. Request ids are page-local and invalid or unsupported payloads are rejected. | Parameter | Type | Required | Default | |---|---|---|---| | `request` | `integer` | required | — | | `ok` | `boolean` | required | — | | `payload` | `table` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6479) as `LuaWebPageReply`. ## send ```lua WebUI.Page.send(event, [payload]) ``` `SHARED` — Available without a live game instance. Sends an event to the page. Sends a named event and JSON-serializable payload from Lua to this page's JavaScript runtime. This is local UI IPC, not a network event, and both event names and payloads are bounded. | Parameter | Type | Required | Default | |---|---|---|---| | `event` | `string` | required | — | | `payload` | `table` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6476) as `LuaWebPageSend`. ## setFocus ```lua WebUI.Page.setFocus(focused, [cursor], [keyboard]) ``` `SHARED` — Available without a live game instance. Gives the surface focus, cursor and keyboard separately. Keyboard capture is asked for separately so a page can take the mouse without depriving the game of the movement keys. | Parameter | Type | Required | Default | |---|---|---|---| | `focused` | `boolean` | required | — | | `cursor` | `boolean` | optional | — | | `keyboard` | `boolean` | optional | — | Returns: `boolean` Registered in `ResourceHost.cpp` (line 6475) as `LuaWebPageFocus`. ## show ```lua WebUI.Page.show() ``` `SHARED` — Available without a live game instance. Shows the surface. Avoid calling this right after `create` — see the race described in `CyberM.webui.create`. Returns: `boolean` Registered in `ResourceHost.cpp` (line 6473) as `LuaWebPageVisibility`.