Scripting limits

From Wiki G1R-MP G1 Remake Multiplayer
Revision as of 11:51, 12 September 2026 by QCherry (talk | contribs) (Document expanded scripting capacities and complete audited limits for 0.1.3 BUILD81)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
CURRENT IN UPDATE 0.1.3 — expanded-budget BUILD81 (2026-09-12). Earlier 0.1.3 binaries have smaller capacities. Update the server and the complete client/launcher package before relying on the expanded limits.

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.

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, os, 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.

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.

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 this update.

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.

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 say has its separate 512-byte message cap.
  • Animation API uses the 27-key validated animation catalog. startAnim blend argument range is 0..2 seconds. Catalog keys are not raw montage paths.
  • 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 .ogg resource 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.
  • 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 setInnerRML byte 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.

Source audit and practical use

Audit date: 2026-09-12; expanded-budget 0.1.3 BUILD81, protocol 34. Changes increase capacities, not packet layouts. Main sources:

  • shared/resource_limits.hpp, resource_event_protocol.hpp, client_ipc_protocol.hpp, scripting/LuaJson.hpp/.cpp, CameraProtocol.hpp, PlayerProgressionCatalog.hpp, PlayerAnimationCatalog.hpp, NameplateValidation.hpp.
  • server/src/config/ServerConfig.cpp/.hpp, server/src/scripting/ScriptRuntime.cpp, server/src/resources/ResourceManager.cpp, resource catalog/manifest, database, HTTP, voice and world implementations, server/enet_server.cpp.
  • client-runtime/src/scripting/ClientScriptRuntime.cpp/.hpp, app/ClientRuntimeMain.cpp, catalog, audio and UI implementations.

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.