Docs

X3D Replay

BETA pricing. Records every player, every session. Watch it back in game: 4 cameras, kill/death timeline, pressed keys, script usage, macro flags.

Buy / Get freeConfig builder

Installation

1. Database

Run the bundled install.sql against the same database oxmysql uses.

mysql -u <user> -p <database> < install.sql

Or paste the whole file into HeidiSQL / phpMyAdmin / DBeaver and run it · safe to run again, existing data is kept.

2. Files

Put the x3d_replay folder in resources/ — do not rename it (other scripts reference this name in the inject line).

3. server.cfg

ensure after oxmysql and es_extended, and before any script that uses the inject files.

ensure oxmysql
ensure es_extended
ensure x3d_replay

set x3d_license_x3d-replay "X3D-XXXXX-XXXXX-XXXXX-XXXXX"

# optional: grant viewing by ACE instead of ESX groups
add_ace group.admin x3d_replay.admin allow

You can put the key in config/config.license.lua instead of the convar.

4. Check it works

Join as an admin and type /replay. The browser opens with your own name and the session being recorded (green dot = online).

5. Updating

Replay files live in x3d_replay/data/ — keep the data folder when you update or every old replay is lost.

Watching

Action How
Open the browser /replay → player → day → session → start time → watch
Open directly /replay <session id | online player id | name> [mm:ss]
Exit Esc or /replay stop
Toggle mouse / camera look Alt
Follow someone else click a name in the players panel or press 1–9

The viewer is moved to their own routing bucket (Config.Viewer.BucketBase + server id), invisible to the live city, and returned to where they were on exit. Every view is logged to TB_X3D_REPLAY_ACCESS (who watched which session, when).

Configuration — config/config.general.lua

Section What it controls
Config.Record Sample rate (Hz) · days to keep (RetentionDays) · events that keep a session forever (KeepKinds)
Config.Storage Storage folder (empty = data/ inside the script)
Config.Client On/off: shots · poses · clothes/face · pressed keys
Config.Actions ESX money/items/job · inject data · event argument summaries · ignored names · macro thresholds
Config.Detect Flag melee hits that land on the head · melee weapon list
Config.Viewer Command · groups allowed · radius and count of nearby players loaded · file send rate
Config.Consent 'card' accept card · 'notice' plain notice · 'off' none (put it in your rules) · wording in Text ({days} = retention days) · bump Version = everyone accepts again
Config.Voice Still in testing — leave Enabled = false

Script usage capture (inject)

Add as the first line of each block in the fxmanifest.lua of any script you want recorded. No code changes, no dependencies.

client_scripts { '@x3d_replay/inject/client.lua', 'client/main.lua' }
server_scripts { '@x3d_replay/inject/server.lua', 'server/main.lua' }
  • client — typed commands and hotkeys (shown as [F9]) · NUI buttons · events sent to the server · animations the script plays on the player (the stand-in plays them too)
  • server — every net event a player sends into that script
  • x3d_replay not running = no effect

After adding the inject lines, restart x3d_replay first, wait a moment, then restart that script.

Animations / emotes

GTA cannot report which animation a ped plays, so the emote script has to tell us. The dpemotes wiring is in addons/hooks/client.lua · from any other script:

exports.x3d_replay:Anim(dict, name, flag)
exports.x3d_replay:AnimStop()

Scripts with the client inject do this automatically.

Hooks — addons/hooks/

File Functions
server.lua Hooks.ShouldRecord(src) return false = do not record this player · Hooks.OnMark(src, kind, data) every written event (forward to logs / Discord) · Hooks.CanView(src) (optional) return true/false instead of the group check
client.lua Hooks.OnView(on) hide/show other scripts' HUD when a replay starts/ends

Other scripts can listen: AddEventHandler('x3d_replay:viewing', function(on) end) or LocalPlayer.state.x3dReplay.

Exports (server)

exports.x3d_replay:Mark(src, 'report', { by = reporterSrc, text = '...' })   -- 'anticheat' / 'report' / 'bookmark' = keep forever
exports.x3d_replay:IsRecording(src)          -- true / false
exports.x3d_replay:GetSession(src)           -- { id, t } or nil
exports.x3d_replay:Open(viewerSrc, target, 'mm:ss')   -- watch (target = session id / player id / name)
exports.x3d_replay:OpenBrowser(viewerSrc, target)     -- open the browser (target optional)

X3D Admin Panel (optional)

With X3D Admin Panel installed you get a Replays menu: players table → open that player's browser, closing returns to the panel. Permissions live in the panel › roles: mod.x3d_replay.players.view / mod.x3d_replay.players.action.browse.

Troubleshooting

  • LICENSE CHECK FAILED — LICENSE_INVALID key does not match the product · NETWORK license server unreachable · LICENSE_IP_MISMATCH IP changed, update it in your account page
  • No permission — the ESX group is not in Config.Viewer.Groups and there is no x3d_replay.admin ACE
  • Failed to load script @x3d_replay/inject/client.lua — ensure x3d_replay before the scripts that use the inject
  • Stand-in does not play a pose — that script has no client inject, or the emote script is not wired
  • No money/items on the timeline — Config.Actions.Framework must be on, ESX required
  • Old replays gone — the data/ folder was deleted on update, or past RetentionDays (kept sessions are never deleted)
View product page