Scripting limits: Difference between revisions
Complete upcoming 0.1.9 documentation: weather, crafting UI, world removal, doors and ladders; preserve release status |
Document upcoming 0.1.9 Discord Rich Presence: server Lua functions, callback, opt-in and owner setup; not a release |
||
| Line 461: | Line 461: | ||
* Editor live application replaces its whole saved removal/door set, not a merge or arbitrary client request. Map formats 1/2/3 require the matching supplied loaders. In-game verification is still needed for each deployed scene. | * Editor live application replaces its whole saved removal/door set, not a merge or arbitrary client request. Map formats 1/2/3 require the matching supplied loaders. In-game verification is still needed for each deployed scene. | ||
<!-- complete019:end --> | <!-- complete019:end --> | ||
<!-- discord019:start --> | |||
== Discord Rich Presence (from 0.1.9) == | |||
'''Available from 0.1.9 (upcoming; not yet publicly released). Not included in public 0.1.8. Use matching updated clients and server.''' | |||
One owning resource/profile per player; 15-second latest-value coalescing and reconnect spacing, 45-second client lease fallback. Text/asset keys at most 128 bytes; button labels 32 bytes, HTTPS URLs 512 bytes, at most two links. Unix timestamp seconds 0..4102444800; displayed counts 0..1000000 with size <= max and paired party fields. Application ID is a 17..20-digit unsigned-64 decimal string, never a Lua number. [[Discord Rich Presence#Profile fields|Complete fields, validation and lifecycle]]. Local opt-in cannot be overridden; reports cannot authorize gameplay. | |||
<!-- discord019:end --> | |||
Revision as of 09:36, 20 October 2026
0.1.4 additions are explicitly marked below: os.time and resource-file/GUI security in BUILD126; static WebP images in BUILD125; map-editor capacities in BUILD124. The current public release is 0.1.8 / Protocol 40. Historical baseline values and version-specific additions are distinguished below.
This reference lists the current developer-facing Lua, resource, API, queue and configuration limits audited in source. It distinguishes fixed capacities, compiled defaults and operator-configurable bounds. It does not treat every internal rendering/physics constant as a scripting limit or guarantee that the maximum workload will run smoothly on every machine.
- All 84 numeric server settings: default, minimum, maximum and units
- All 59 player statistic ranges
- Allowed appearance, equipment, monster and other catalog keys
Units: KiB = 1024 bytes; MiB = 1024 KiB; GiB = 1024 MiB. String limits count bytes unless a separate Unicode-codepoint limit is stated. Most position-based Lua functions use metres; server sync-distance configuration and voice range use centimetres. Times are milliseconds unless stated otherwise. Coordinates must be finite; numeric validity is not a promise that playable terrain exists at that position.
Lua VM and execution
| Limit | Client | Server | Scope / behaviour |
|---|---|---|---|
| Lua VM allocation budget | 1024 MiB | 1024 MiB default; configurable 4..4096 MiB | Per resource/VM. Allocated on demand, not reserved on resource startup. This is not a cap on total process/native allocations, textures, audio or database buffers. |
| Instruction budget | 10000000 | 10000000 default; configurable 10000..1000000000 | Reset on each protected script chunk/callback invocation. Exceeding it raises a Lua error. |
| Execution timeout | 5000 ms | 5000 ms default; configurable 10..60000 ms | Cooperative Lua-hook check, not an OS watchdog and not preemption of a blocking native API call. |
| Hook interval | 10000 instructions | 10000 default; configurable 100..1000000 | Budgets are checked in samples; execution can pass a nominal boundary before the next check. |
Server settings are lua.memoryLimitMB, lua.instructionLimit, lua.timeoutMs, lua.hookInstructionInterval. They do not propagate to the client. An existing configuration retaining older values overrides the new server defaults. The production and bundled GothicRP-test configuration templates now use the expanded Lua/DB defaults.
Lua is the sandboxed LuaJIT/Lua 5.1 environment with JIT disabled. Base, table, string and math libraries are exposed; general filesystem/OS/module-loading access is not. dofile, load, loadfile, loadstring, getfenv, setfenv, collectgarbage, newproxy, coroutine, io, package, debug, jit, ffi and string.dump are unavailable. Lua bytecode is rejected. Increasing capacity does not weaken sandbox, hash, ownership, path or network validation.
Safe wall-clock time (since 0.1.4 BUILD126)
The os table remains unavailable in 0.1.3. Since 0.1.4 BUILD126, client and server resources receive a restricted table containing only os.time(). It returns Unix seconds from the local host clock and accepts no arguments (not even a date table or explicit nil). The full OS library is never opened: os.execute, os.exit, filesystem operations, environment access and all other OS-library members remain unavailable.
-- Seed once at resource startup, not before every draw.
math.randomseed(os.time())
local roll = math.random(1, 100)
This is ordinary, non-cryptographic randomness. Use getTickCount for elapsed time; wall-clock time can change and client clocks are not authoritative. See os.time for the complete contract.
Timers, handlers and commands
| Capacity | Client, per resource | Server |
|---|---|---|
| Timers | 8192 (previously 256) | No additional fixed timer-count cap in the server Lua API; still subject to memory and execution cost. |
| Timer callbacks selected per tick | 256 (previously 32), oldest deadline first | No matching fixed per-tick callback-count cap. Due timers are processed by the server runtime. |
| Event handlers, total | 8192 (previously 256) | No additional fixed count cap in the registration API. |
| Handlers for one event | 512 (previously 32) | No matching fixed per-event count cap. |
| Declared remote event names | 4096 (previously 256) | No additional fixed registration-count cap. |
| Key bindings | 1024 (previously 128) | Client-only feature. |
Both timer APIs require an interval of at least 10 ms; interval and repeat-count parameters are unsigned 32-bit values. Repeat count 0 means repeat indefinitely. This is not a precision guarantee: timer dispatch follows runtime ticks, and missed intervals are not replayed in an unlimited catch-up loop. Client timers and key bindings accept at most 32 callback arguments. Cancelled client timers leave their storage slots when the tick removes cancelled entries. Client setTimer returns 0 on rejection; handler/key-binding registration returns false. Check return values.
Client selection is deadline-ordered and snapshots timer IDs before callbacks. Large batches of fast repeating timers therefore do not permanently starve later timers; callbacks may still be delayed by load. Do not use thousands of 10-ms timers as a substitute for batching work.
Server local event dispatch has a recursion-depth limit of 32; nested command execution has a depth limit of 16. Command names are nonempty and at most 64 bytes. executeCommandHandler accepts at most 32 arguments with at most 2048 bytes of converted argument text in total. These recursion guards are not capacities for how many independent events/commands a gamemode can declare.
Network events and IPC
| Field | Fixed limit |
|---|---|
| Resource name in an event envelope | 96 bytes |
| Event name | 128 bytes |
| Arguments per serialized resource event | 32 |
| One event string | 32 KiB |
| Complete serialized resource event | 64 KiB, including headers, names and all arguments |
| Client IPC payload | 64 KiB |
| IPC buffered bytes / queued frames | 256 KiB / 256 frames; separate guards |
Values transported directly are nil, boolean, integer/number and string, not Lua tables, functions or userdata. Client local event argument conversion also uses the 32-argument/32-KiB-string guards. Server-local callbacks should not be confused with serialized network messages. Lua numbers do not represent every 64-bit integer exactly: keep large opaque identifiers as strings where the API specifies strings.
A 1-MiB JSON document cannot be sent as one event string. The expanded JSON limit is for local serialization/storage; the event envelope is unchanged. For bulk application data, use bounded application-level chunks or appropriate resource/HTTP/database facilities. Validate sender permissions, payloads and request rates. Packet/IP budgets in Server configuration limits still apply to the connection as a whole.
Resource files and downloads
| Capacity | BUILD81 value | Previous value |
|---|---|---|
| One Lua source file | 128 MiB | 64 MiB |
| One resource file | 256 MiB | 64 MiB |
| All files in the client download catalog | 32 GiB | 8 GiB |
| Catalog file count | 262144 | 65536 |
| Serialized catalog document | 128 MiB | 64 MiB |
The download totals cover client/shared scripts and declared files, not server-only scripts. Server-only Lua files still have their individual Lua source-file cap. Server, launcher and client share these constants. A resource exceeding the old client limits will not work with old launchers simply because the server was updated.
Client catalog relative paths are at most 512 bytes, with at most 128 bytes per segment; file URLs are at most 2048 bytes. Resource names used across the whole scripting/network stack should fit the stricter 96-byte event-name envelope field even though filesystem-side validators allow longer names. Paths must stay inside the resource, use the accepted relative-path syntax and refer to declared files; absolute paths and traversal are not enabled by larger file budgets.
Download and GUI security (since 0.1.4 BUILD126)
These 0.1.4 changes enforce a shared file policy in the server manifest/catalog and client catalog/download path. They do not increase the size budgets above.
- Allowed extensions (case-insensitive):
.lua .json .xml .txt .csv .rml .html .rcss .css .png .webp .tga .jpg .jpeg .bmp .svg .ttf .otf .woff .woff2 .ogg .wav .mp3 .flac. - This is a transport allowlist, not a decoder capability list. It does not enable JavaScript, arbitrary HTML-browser features, additional audio codecs or every listed image format. Existing Lua audio remains declared join-time Ogg; supported GUI image behaviour is documented in RmlUi images.
- Executables and native modules such as
.exe .dll .asi .com .scr, installers, shell scripts and shortcuts are not allowed. Recognized native executable headers (MZ/PE, ELF and Mach-O) are rejected even when renamed to an allowed suffix; cached files are checked too. This is defence in depth, not an antivirus or a guarantee that arbitrary content is harmless. Historical cache files are not automatically erased. - Relative path segments use ASCII letters/digits, spaces,
_,-and.; empty/dot/traversal segments, absolute paths, backslashes, alternate data streams, Windows reserved device names and trailing dots/spaces are rejected. Case-insensitive catalog collisions are rejected. The 512-byte path and 128-byte segment limits remain. - The catalog's canonical SHA-256 must match the revision obtained from the official HTTPS server listing. Launcher/supervisor and client runtime enforce this pin before accepting resource payloads. An absent or stale listing is rejected, not replaced with an untrusted HTTP fallback. After changing resources, allow the official listing to refresh before rejoining. HTTP asset transfer remains unencrypted: integrity verification is not confidentiality.
- RmlUi reads verified, declared GUI assets owned by the requesting resource. Arbitrary local files, other resources, scripts and undeclared files are not available through GUI references. Resource file size/hash and final resolved paths are checked, including rejection of reparse/junction redirection. The host's explicitly approved system-font fallback is separate from resource access.
See Update 0.1.4; use the updated server and complete client/launcher package for these protections. The complete public 0.1.4 release uses Protocol 36; update both client and server.
JSON
toJSON/fromJSON now allow 1 MiB, nesting depth 64 and 65536 cumulative entries across the document (previously 32 KiB / 16 / 2048). Object keys remain at most 256 bytes. Arrays must use contiguous positive indices; mixed array/object key tables, cyclic references and non-finite numbers are rejected. Failure returns false plus an error description. The byte cap applies to the serialized document, not to the full native/Lua memory consumed while processing it.
Database and password work
| Compiled default | BUILD81 value | Configuration / scope |
|---|---|---|
| DB workers | 8 | Global worker pool |
| DB connections | 16 | Per resource |
| Pending DB queries | 1024 | Per resource |
| SQL statement | 4 MiB | Per query |
| DB result | 50000 rows and 64 MiB | Per result, both guards apply |
| DB timeouts | connect 5000 / read 15000 / write 15000 ms | Connection options may reduce, but not exceed, configured timeouts; minimum 100 ms |
| Blocking dbPoll | 100 ms maximum | Configurable; negative timeout becomes non-blocking and excessive timeout is clamped |
| Password workers / queue / pending per resource | 4 / 1024 / 256 | Password hashing/verifying service |
All configurable ranges are listed in Server configuration limits. Result overflow is reported as a database error (client result-limit error 90001), not a successful partial result. Free/poll results and avoid unbounded result retention; use SQL pagination. MariaDB/MySQL can impose additional server-side limits, including its packet and connection settings, which this application does not automatically change.
Passwords for hash/verify are at most 256 bytes; encoded hashes at most 512 bytes. Default Argon2id parameters remain 65536 KiB memory, 3 iterations, parallelism 1; larger queue capacity does not weaken hash security. DB multi-statements, multi-queries, local infile and automatic reconnect are not enabled as a side effect of the 0.1.3 capacity update. Separately, 0.1.4 adds explicit opt-in recovery; see MySQL connection recovery.
requestRemote
| Limit | Value |
|---|---|
| Workers / queued work / pending per resource | 8 / 256 / 32 (compiled defaults) |
| URL | 2048 bytes |
| Request body / response body | 4 MiB / 8 MiB |
| Request headers / response headers | 128 / 256 |
| Aggregate header bytes | 64 KiB |
| Header name / username / password | 128 / 512 / 512 bytes |
| Connection attempts | 1..3; default 1 |
| Connect timeout | 500..10000 ms; default 5000 |
| Total timeout | 1000..30000 ms; default 15000 |
| Redirect count | 0..3; default 2 |
Allowed methods are GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS. Only the supported HTTP/HTTPS destinations are accepted. Loopback/private-address restrictions, DNS and redirect validation stay enabled in production. Capacity or validation rejection returns an error; asynchronous transfers also report completion errors. Keep callbacks short. The larger download-catalog file limit is not the requestRemote response limit.
World entities and text
| Feature | Fixed capacity / range |
|---|---|
| Active world items | 16384 globally (previously 4096); quantity 1..1000 per spawn |
| Active NPCs | 8192 globally (previously 2048) |
| Active monsters | 4096 globally (previously 1024) |
| NPC route | 1..1024 points (previously 256); each wait 0..3600000 ms; speed 0.1..12 m/s |
| NPC scripted movement arrival radius | 0.01..5 m |
| Monster scripted movement | speedScale >0 and <=1; Lua arrivalRadius 0.01..5 m |
| Monster max health / attack damage | max health >0 and <=1000000; damage 0..100000 |
| NPC name | 3..16 bytes, without control characters |
| Monster/nameplate display text | At most 96 UTF-8 bytes and 48 codepoints |
| 3D text objects | 1024 per resource / 8192 globally (previously 256 / 2048) |
| 3D text content | Nonempty, at most 256 bytes AND 128 Unicode codepoints; no control characters/newlines |
| 3D text draw distance / scale | 1..1000 m / 0.25..5 |
| Scripted world positions | Finite coordinates within +/-1000000 m per axis where the Lua position validator is used |
Global capacities are shared across resources. Creation above a capacity is rejected; it does not expand the cap or authorize mutation of another resource's entities. More accepted entities do not mean that placing all of them in one visible area is performant. Navigation, authoritative sync distance, client streaming and actual hardware still matter.
Navigation
The compiled custom-collision capacities are 16384 blockers globally / 4096 per owner (previously 4096 / 1024). The internal settings validator permits global capacity up to 65536, with owner capacity positive and no greater than global capacity. These are not extra numeric serverconf.cfg options.
- Lua custom blocker coordinates: +/-100000 m; size/height dimensions 0.01..10000 m; polygons 3..16 vertices and must pass geometry validation.
- Navigation artifact: at most 256 MiB and 200000 baked blockers (previously 64 MiB / 50000); polygon cap 16 vertices.
- Compiled search defaults remain grid cell 50 cm, detour margin 1200 cm, maximum slope 45 degrees, maximum path distance 30000 cm (300 m), maximum search nodes 120000.
- Internal settings bounds: grid cell 5..1000 cm; detour margin 0..50000 cm; slope >=0 and <89 degrees; path distance >=grid cell and <=1000000 cm; search nodes 64..1000000.
- Navigation failure/search exhaustion is not permission to cross blockers. See NPC and monster navigation collision.
Player state, appearance and nameplates
- Player names: 3..16 bytes, accepted player-name character set. Appearance, armor, weapons, spells, skills and tattoo selection use validated catalogs, not arbitrary game asset paths; see Lua API catalogs.
- Skin RGB and display RGBA components: integers 0..255. Tattoo catalog: 12 presets. These are valid value ranges, not gamemode capacity budgets, and were not expanded.
- Inventory give/remove amount: 1..1000 per call. Server-controlled cumulative count: ammunition at most 65535, other supported items at most 100000. Ownership and item-specific rules still apply.
- Consumable grant count: 1..100; persistent consumable commit keys at most 96 bytes. This does not authorize trusting client-submitted permanent stats.
- All 59 stat ranges: Player statistic limits. Common HP/STR/DEX values cap at 100000; max-health minimum is 1. Level caps at 1000, magician level at 6; other stats have their own bounds.
- Scripted player damage amount: positive, at most 100000. Unconscious duration: 0 or 250..3600000 ms; configured health arguments must fit the relevant player-health range. Life-state checks still apply.
- Player/nameplate text: at most 96 UTF-8 bytes and 48 codepoints. Nameplate height offset is within +/-100 m.
- Observer-specific nameplates: defaults 250000 pairs globally and per resource; per-resource mutation budget 4096/s with burst 8192. Configurable ranges: Server configuration limits. These are directed observer/target overrides, not persistent database rows. Throttle bulk restore operations and handle rejected mutations.
- Nearby-player radius: 0..100000 m. Focus-query maximum distance: 0.1..1000 m; field of view: 1..180 degrees.
- Lua chat output: nonempty and at most 2048 bytes; chat RGB values are clamped to 0..255. Administrative
sayhas its separate 512-byte message cap. - Animation API catalog: 27 original aliases, 118 from 0.1.4, and 962 from upcoming 0.1.9 (844 additions). See Player animation catalog and Activity animation catalog. The blend argument range remains 0..2 seconds, default 0.15. Catalog keys are not raw asset paths; catalog size is not a simultaneous-animation capacity guarantee.
- Account binding key: 3..24 bytes with its validated identifier syntax; serial: 32 hexadecimal characters. Kick/ban reason: nonempty, at most 160 bytes, valid text without controls. Ban duration: 0 (permanent) or at most 5256000 minutes.
Camera
Camera safety/representation ranges were not changed by this capacity update. There is no 100-metre distance-from-player restriction. Keep engine streaming and server relevance in mind; coordinate acceptance alone cannot guarantee valid/rendered terrain everywhere. See Scripted camera.
| Parameter | Limit |
|---|---|
| Camera command document | 24 KiB |
| Position/focus/path/orbit envelope | Finite coordinates within +/-1000000 m per axis |
| Path points | 1..32 |
| FOV | 15..150 degrees |
| Rotation / orbit starting angle | Absolute value <=360000 degrees |
| Orbit sweep | Absolute value <=3600 degrees |
| Orbit radius / height offset | 0.1..50 m / absolute value <=50 m |
| Command duration | At most 600000 ms |
| Each path point | Duration 1..600000 ms; hold 0..600000 ms; sum of all durations and holds <=600000 ms per cycle |
| Orbit duration | 100..600000 ms |
| Reset blend | 0..10000 ms |
| Camera state document | At most 4096 bytes |
Looped paths/orbits can repeat; the per-cycle duration bound is not a total lifetime cap. Invalid commands are rejected, not silently replaced by a different camera path. Resource ownership and cleanup still apply.
Client audio and UI
- Audio: 128 sound handles per resource / 512 globally (previously 32 / 128). Declared join-time
.oggresource files only. Stop unused handles; an accepted handle is not a promise that hundreds of simultaneously mixed sounds are cheap. - Sound volume 0..1; finite 3D coordinates +/-1000000 m; minimum distance >=0.01 m, maximum distance greater than minimum and <=10000 m. Audio paths must also satisfy the catalog's stricter relative-path bounds.
- UI texture files: at most 256 MiB encoded (previously 64 MiB); decoded width and height remain at most 8192 pixels each. This is not a VRAM allocation guarantee.
- Since 0.1.4 BUILD125: static lossy/lossless WebP with alpha works in RML images and RCSS image decorators; PNG support is retained. Animated WebP is rejected. No new Lua image function is required. See RmlUi images for manifest/RML examples and format restrictions. BUILD126 also hardens uncompressed 24/32-bit TGA validation and resource GUI reads.
- UI attribute name: 1..64 bytes with safe-name validation; attribute value at most 16384 bytes (previously 4096). Event-handler attribute injection remains prohibited.
- GUI append-text retains at most 1000 child lines per target element (previously 200), removing older children. This is not a cap on all elements in an RML document.
- No separate fixed document-count or general
setInnerRMLbyte cap was found in the exposed UI API. Resource ownership, file limits, Lua/native memory and rendering cost still apply; this does not mean unlimited capacity.
Voice
Voice remains a separate real-time stream: 48000 Hz, 960 samples/20-ms frame, two channels; encoded frame at most 512 bytes and voice datagram at most 768 bytes. Default sender budgets are 55 frames/s and 65536 bytes/s; see Server configuration limits for ranges.
Voice range values use centimetres, including setPlayerVoiceRange/getPlayerVoiceRange. A positive finite custom range is normalized to 50 cm..configured voice.maxRange; defaults are whisper 500 cm (5 m), normal 1800 cm (18 m), shout 3500 cm (35 m), maximum 10000 cm (100 m). Voice volume is 0..2; channel ID 0..4294967295. Increasing Lua capacity does not alter voice gain, codec timing or anti-abuse limits.
Validation and practical use
Focused follow-up: 2026-09-20, development 0.1.4 BUILD125/126, protocol 35: WebP, restricted os.time, resource file policy and GUI loading. This is not a new audit of every historical numeric limit below. Earlier audit baseline follows.
Audit date: 2026-09-12; expanded-budget 0.1.3 BUILD81, protocol 34. Changes increase capacities, not packet layouts.
The test suite executes the real Lua runtimes with 8192 client timers / 8193 server timers, expanded handler/remote-event/key-binding capacities, JSON boundary and overflow cases, client timer fairness and restart/cleanup. Capacity boundaries are not a full in-game performance benchmark. Use staged loading, staggered timers, asynchronous DB/HTTP, pagination and explicit cleanup even on fast computers. Always check API results and the runtime logs.
Map editor and world objects (since 0.1.4)
- BUILD124 and updated scripts remove the fixed editor/legacy/map_scene object-count caps. Remaining document bounds: 1000000-byte transfers, shared JSON codec 1 MiB and 65536 entries (including nested fields); 200 undo commands; map names up to 48 ASCII letters/digits/_/-.
- WorldObjects since BUILD124: no fixed instance-count, pending-request-count or requests/second cap (former 512/32/80 removed). Still 16 owning resources, command JSON up to 4096 bytes and a 10-second result timeout. Shared IPC queues remain bounded at 256 frames each: check rejection and pace submissions. Memory/CPU/GPU limits still apply; the scene loader remains sequential.
- Coordinates +/-100000 metres; rotations +/-36000 degrees; scale 0.01-100 per axis; ray length up to 1000 m; object IDs up to 64 characters and asset paths up to 512.
- Resource storage: 1 MiB/file and 64-character keys. Pre-write admission rejects an existing directory over 64 MiB or over 512 regular files (including backups); these are not post-write hard quotas.
See Map editor, World objects, Resource data storage. Other limits documented on this page remain unchanged unless explicitly marked otherwise.
NPC control API since 0.1.5
See NPC scripting for the new functions. Health/damage/mana: 0..100000 (maxHP at least 1); ammo: integer 0..65535; perception: distance >0..1000 metres, FOV >0..360 degrees; projectile range 1..40 m; aim 150..30000 ms; cooldown 360..60000 ms; skillTier 0..2; animation blend-out 0..2 s. Combat walk 0.1..2.5 m/s, run 2.6..8 m/s; chase is independently configurable. These validations do not replace earlier server resource/capacity limits. Defaults and lifecycle caveats are documented on the linked function pages.
NPC appearance validation since 0.1.5
RGB: integer sRGB channels 0..255. Identity/tattoo keys: at most 48 bytes, ASCII case-insensitive closed catalogs; no arbitrary asset paths. IDs must identify a live server NPC record and mutation requires its owning resource. See NPC scripting#NPC appearance since 0.1.5.
Area notifications (since 0.1.6)
Server-side ShowAreaNotification / HideAreaNotification and lower-camel aliases. Available since 0.1.6.
- Connected numeric player ID: finite integer 1..4294967295.
- Heading: 0..256 UTF-8 bytes; title: 1..512 UTF-8 bytes. Literal text only; malformed UTF-8, NUL, controls and line breaks are rejected.
- Duration: finite integer 1000..30000 ms, default 5000 ms; includes fades. Omit the optional argument rather than passing nil.
- One custom banner per player; latest show replaces the previous owner/timer. At most 8192 distinct tracked player IDs per resource; explicit hide/resource cleanup releases tracking.
- Native pending queue: 32 commands; excess commands may be discarded. Three bounded creation attempts, 500 ms apart. Server acceptance is not a visual acknowledgement.
See Area notifications for cleanup, per-resource ownership, Unicode and the separate automatic discovery-banner suppression. Other limits are unchanged by this addition.
Mounts (since 0.1.6)
Server-side createPlayerMount and destroyPlayerMount; available since 0.1.6. See Mounts for ownership, native eligibility and verification status.
- One active mount per player. No separate global mount-count cap in this subsystem; ordinary player/resource limits still apply.
- No fixed ride lifetime or two-minute age-based despawn. Disconnect, resource stop, ineligibility and explicit removal still clean up the session.
- Initial server observation readiness: 15 seconds; an established session is revoked after more than 20 seconds without accepted observations. These are health timeouts, not maximum riding duration.
- Native spawn requests have a 10-second cooldown and bounded readiness checks. Avoid repeated creation/removal loops; return values acknowledge requests, not native completion.
- Initial boarding/incomplete native transitions use a 6000 ms recovery grace. A lost previously confirmed seat outside a native transition uses a 500 ms debounce. A transition grace is latched for its continuous unhealthy episode; repeated phase reports do not renew it. Healthy riding has no recovery timer running.
- Snapshot observation is approximately 10 Hz. Server ownership/sequence/finite-value, movement and collision-registry validation remain enforced. This is not full native-world collision replication.
- Petting observations are bounded to 4 metres, idle gait and at most 8 seconds of montage position; native eligibility still applies. Petting availability needs final in-game confirmation.
- Ownership is tied to the creating resource and current connection player ID; no database persistence or ownership-transfer API.
The server/client safety bounds above are separate from the existing nameplate range and do not increase it.
Game audio (since 0.1.7)
Available since update 0.1.7. These limits apply to Game audio, not existing resource-file audio or voice chat.
| Item | Limit / behavior |
|---|---|
| Sound key | Exact entry in the built-in catalog. No arbitrary files, URLs or native audio paths. |
| Volume | Finite number 0..1; default 1. |
| Coordinates | Each axis -200000..200000 metres; finite numbers only. |
| Attenuation | minDistance >= 0; maxDistance >= 0.01; minDistance < maxDistance <= 200000 metres. Defaults 1 and 30. |
| Options | Only volume, minDistance and maxDistance. Unknown keys are rejected. |
| Catalog search | Query at most 160 bytes; categories empty, sfx, music or dialogue. |
| Catalog pagination | Zero-based nonnegative integer offset; integer limit 1..200, default 50. |
| Active sounds | 128 per client, shared across resources, including pending/starting playbacks. |
| Audio resource owners | 16 per client. Resource/lifecycle cleanup releases ownership; stopping the last sound alone does not release the owner or its cache. |
| Prepared native cache | 64 entries per owner. Dialogue 2D and 3D variants use separate entries. Cache is released by resource/lifecycle cleanup, not by stopping one sound. |
| Pending requests / native work queue | 256 each per client. Rejected work must not be retried in a tight loop. |
| Retained sound records | Up to 512 across resources; older terminal records are evicted as new handles are created. |
| Loading timeout | 12 seconds for queued native preparation; 15 seconds for runtime request completion. A timed-out play request is cancelled. |
| Owner heartbeat | Once per second, with a 5-second native lease. Expiry cleans up owned audio. |
| Playback-state observation | Approximately every 50 ms while the game is ticking; not a real-time timing guarantee. |
Handles/request IDs are positive runtime-assigned numbers, not engine pointers or persistent IDs. Playback and controls are asynchronous. onClientGameSoundResult supplies results; getGameSoundState supplies the latest accumulated state, not a guaranteed full property snapshot.
Voice preload is reported as requested, with voicePreloadConfirmed=false; loaded event samples and a resolved recording do not independently confirm voice PCM loading. There is no automatic broadcast, late-join replay or precise cross-client audio clock. Cold loading is paced but is not guaranteed hitch-free.
Server TTS (since 0.1.7)
Available since 0.1.7. See Server TTS, TTS configuration and TTS voices. TTS is default-off and starts no Python/models when disabled.
- Text: 4000 Unicode characters and 12000 UTF-8 bytes. Output: at most 180 seconds and 8 MiB per clip.
- Private reference audio: WAV/OGG/FLAC, 1–30 seconds, 1–2 channels, 8–96 kHz, at most 8 MiB; relative ASCII path and lowercase SHA-256 required. Ukrainian requires a reference. No client uploads, URLs or arbitrary checkpoints.
- Default pending queue: 128 globally, 16 per resource (configurable); at most 2048 retained job handles. Release completed handles; this does not delete recordings.
- Per resource: up to 256 voices and 256 presets. Profile/named-recording identifiers: 1–64 ASCII letters/digits/underscores/hyphens.
- Active playback/preload handles: 128 server-side; 32 client-side. Recipient list at most 5000 entries, connected IDs only. Empty recipients reject the request.
- Playback volume 0..1. Spatial distances: 0.1 <= min <= max <= 1000 metres, defaults 1 and 30. Position is {x,y,z} metres with finite absolute components <= 1000000.
- Readiness deadline: 500..30000 ms, default 10000. A ready listener is required; slow clients do not block everyone indefinitely. Common start is normally scheduled 500 ms ahead.
- Default compressed server memory cache 256 MiB; persistent disk budget 2048 MiB; client decoded cache 256 MiB. These are not inference-model RAM limits.
- Persistent client download cache: 512 MiB / 8192 files, LRU. Deletion, eviction, corruption or unwritable storage can require another download; fresh session signatures remain mandatory.
- A stable saveAs name cannot silently overwrite different audio. Server disk exhaustion/corruption is an explicit error; stored recordings are not automatically erased to satisfy a new request.
- Generation is asynchronous but still consumes host CPU/RAM when used. Pre-render frequent dialogue and enforce permissions/quotas on player-driven requests.
Native HUD and menus (since 0.1.7)
- Client-side, resource-owned policy; 6 original HUD groups and 4 native menus. From 0.1.9, crafting becomes a seventh HUD group; the menu count stays four. Exact keys and bit masks: Native HUD and menus / getNativeUiState.
- Up to 256 owner records per client session, including released records retained for safe ordering. Excess new owners can be rejected; reset is not a way to allocate unlimited new owner identities.
- Mutators return a positive request ID or false. Consecutive requests can coalesce into the latest complete policy; intermediate IDs are not guaranteed individual acknowledgements.
- Acknowledged native state is fresh for less than 6000 ms while connected. Unrenewed policies expire after 6000 ms; ordinary heartbeats renew them every 1000 ms.
- Native result JSON is bounded to 8192 bytes. Read the returned table or decode the result string; do not infer success merely from pending=false.
- false adds a restriction; true/reset releases only the caller's restriction. Stopping a resource releases ownership. Native quicksave/quickload and pause save/load restrictions cannot be re-enabled by Lua.
See onClientNativeUiResult and Native HUD and menus for the public contract.
Character dimensions (since 0.1.8)
- Server-controlled integer dimension numbers: 0..2147483647. Default 0. Invalid/fractional/non-finite/string values fail.
- No independent dimension-creation pool: entity/player capacity and existing streaming distances still apply.
- NPC/monster setters require the owning resource. Player dimensions are gamemode-managed and are not automatically restored when the resource stops.
- One player transition at a time. Pending transitions/position changes, active interactions/climbing and owned mount leases can reject a change. An unchanged dimension is a no-op success.
- spawnNpc / spawnMonster accept
options.dimension. Omission preserves dimension 0; normal spawn validation still applies. - This isolates characters, combat and proximity voice, not world items, doors/gates, static/custom blockers, global events or arbitrary script audio. See Character dimensions for exact scope and examples.
- Requires matching 0.1.8 / Protocol 40 peers.
Item profiles and interactive editor objects (upcoming 0.1.9)
Not yet publicly released; public 0.1.8 does not include these additions.
- Item type stats affects every copy of one known item type across this server, not per-instance/per-dimension variants. Item types are resource-owned while overridden. No arbitrary engine field writes or new item definitions.
- getItemStatDefinitions supplies exact finite-number ranges, integer rules and per-item support. See Item stat properties. Invalid/unsupported inputs and ownership conflicts reject the transaction. Resource stop resets owned overrides; persistence is explicit.
- Joining clients need support for active profiles. A setter/report is not proof of completed native gameplay. Revisions are strings; missing defaults are not zero.
- Interactive map objects provides 94 editor prefabs: 18 seats, 48 lights, seven doors and 21 ladder sizes. Test native remains local; shared placed-door deployment is separate. One native test at a time; position/yaw only, original scale/collision. Seat cleanup waits for release/exit and 1-metre clearance.
- The updated map_scene loader accepts formats 1/2/3 for supported static objects, server-owned doors and original-world removals. Shared seats/lights/placed ladders are still unsupported; these categories are rejected, not silently made static. Original NPC obstacle data is unchanged.
Armor-upgrade API (from 0.1.9)
Upcoming; not yet publicly released. See Armor upgrades and the complete Armor catalog / Armor upgrade catalog.
- Server-side, known keys only: 26 bases, 84 parts, three slots top/mid/bottom. The part setter replaces all three slots; omitted slots clear. Empty strings or none clear a slot; {} clears all parts.
- Exact lowercase base keys and preset names. Part values are recognized catalog strings (maximum 64 bytes); non-string values/unknown fields reject the request. Character IDs must be finite integer numbers 1..4294967295. Player/NPC getters take one argument; setters take exactly two.
- Players need owned base/parts and must meet server requirements. NPC mutation requires the owning resource. Setters never grant items, equip a different base, raise attributes or heal/refill.
- Six tier presets choose only existing compatible parts; none clears. A known base without upgrades returns empty catalog/preset tables, not fabricated pieces.
- Selection is per character; numeric type profiles are server-wide. Persistence in custom gamemodes is explicit. Existing dimension/visibility rules remain.
Female identity presentation (from 0.1.9)
Improved from 0.1.9 (upcoming; not yet publicly released). This improvement is not included in public 0.1.8.
- Supported keys for the correction:
syra,velaya,seraphia,chani,natalia; existing catalog and permission checks remain. - Full authored female outfit requires matching identity body/head selections and no equipped armor. Separate head selection does not replace a separately selected body.
- Armor retains its native shape and protection; no automatically generated female armor variants.
- Neutral facial expression only; this does not introduce facial animation or lip synchronization. Skin/tattoo display remains limited to supported exposed material regions.
- Existing server-side setters and authoritative state are reused. Success means acceptance, not completed rendering. All viewing clients need the update. See Female identities.
Activity animation scope (from 0.1.9)
Available from 0.1.9 (upcoming; not yet publicly released). Not included in public 0.1.8. Both the server and observing clients need the matching update.
- Existing player/NPC start/stop APIs and validation remain. Aliases must be in the running server's catalog; arbitrary asset paths are not accepted.
- Looping remains explicit: omitted looped means false. Use the mode returned by getPlayerAnimationInfo when appropriate.
- Cosmetic rods/tools do not grant items or rewards; furniture/workstation placement and gameplay checks remain the gamemode's responsibility.
- First-use loading can occur. Server acceptance is not client-render confirmation, and catalog qualification is not a live acknowledgement. See Activity animations for visual-test status and boundaries.
Available from 0.1.9 (upcoming; not yet publicly released). Not included in public 0.1.8. Use matching updated server and clients.
Custom keys and placed doors
See complete limits. Keys: 64 distinct types/resource, 256/process including inactive registrations; immutable recipes, approved donor only. Doors: 1024/resource, 4096 total, six placement fields and original native scale. Deferred notifications: 4096 queued, 64/tick; one key-denial notification/player/second. Resource stop drops its queued events. No automatic database persistence or arbitrary custom weapon/armor definitions.
Weather, crafting and original-world editing from 0.1.9
Available from 0.1.9 (upcoming; not yet publicly released). Not included in public 0.1.8. Use matching updated clients and server.
- Weather exposes a closed 43-name catalog, not arbitrary particle/asset paths. Transition range remains 0..300000 ms, default 3000. Weather is global server state, not per-player/dimension. Render/ACK limitations remain explicit.
- Native crafting UI is a seventh HUD component, not a fifth management menu, recipe executor or server authorization system. Existing resource ownership/expiry and async result contracts apply.
- Interactive map objects exposes 94 editor prefabs with original scale/collision and yaw rotation. Only the seven doors have shared placed-interaction authority; seats/lights/ladders remain local tests.
- World model removal retains command-size, owner, catalog, exact-identity and protected-object guards. It does not alter terrain, baked HLOD or NPC navigation data. Group changes and first loading can hitch; bounded work is not a zero-cost promise.
- Editor live application replaces its whole saved removal/door set, not a merge or arbitrary client request. Map formats 1/2/3 require the matching supplied loaders. In-game verification is still needed for each deployed scene.
Discord Rich Presence (from 0.1.9)
Available from 0.1.9 (upcoming; not yet publicly released). Not included in public 0.1.8. Use matching updated clients and server.
One owning resource/profile per player; 15-second latest-value coalescing and reconnect spacing, 45-second client lease fallback. Text/asset keys at most 128 bytes; button labels 32 bytes, HTTPS URLs 512 bytes, at most two links. Unix timestamp seconds 0..4102444800; displayed counts 0..1000000 with size <= max and paired party fields. Application ID is a 17..20-digit unsigned-64 decimal string, never a Lua number. Complete fields, validation and lifecycle. Local opt-in cannot be overridden; reports cannot authorize gameplay.