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 builderInstallation
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_replaynot 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_INVALIDkey does not match the product ·NETWORKlicense server unreachable ·LICENSE_IP_MISMATCHIP changed, update it in your account page- No permission — the ESX group is not in
Config.Viewer.Groupsand there is nox3d_replay.adminACE Failed to load script @x3d_replay/inject/client.lua—ensure x3d_replaybefore 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.Frameworkmust be on, ESX required - Old replays gone — the
data/folder was deleted on update, or pastRetentionDays(kept sessions are never deleted)