Runtime Doors.
Not a Static Config File.
rde_doors is a production-grade, fully database-backed door system: 8-layer access control, lockpick mini-games, passcode unlock, sliding/garage/gate types, and zero-downtime auto-migration. Full ox_doorlock feature parity, plus everything ox_doorlock doesn't do.
Overview
Most door scripts are static config files — restart the server, lose runtime changes. rde_doors persists every door to MySQL, syncs state via StateBags, and validates every action server-side.
Door Types
| Type | Behavior |
|---|---|
| Single / Double | Standard swing doors — double doors sync perfectly as one unit |
| Sliding | Zero door-rate, instant open |
| Garage / Gate | Large automatic doors, auto=true by default |
Quick Start
ensure oxmysql
ensure ox_core
ensure ox_lib
ensure ox_target
ensure ox_inventory
ensure rde_nostr_log -- optional but recommended
ensure rde_doors
add_ace group.admin rde.doors.admin allow
Tables are created and migrated automatically on first start — no manual SQL import. Create your first door with /createdoor, aimed at a door entity in the world.
Access Control — 8 Layers, In Order
| # | Layer | Notes |
|---|---|---|
| 1 | Admin | ACE permission + ox_core groups + Steam ID fallback |
| 2 | Owner | The character who created or purchased the door |
| 3 | Access list | Per-character allowlist, granted by owner or admin |
| 4 | Legacy auth array | Group name only, grade 0 — backward compatible |
| 5 | groups_data (v4) | Group name + minimum grade requirement |
| 6 | items_data (v4) | Item name + optional metadata + consume-on-use flag |
| 7 | Legacy items array | Simple item check, no metadata |
| 8 | Passcode | Anyone with the correct code can toggle |
Lockpick & Passcode
Config.Lockpick = {
items = { 'lockpick', 'advancedlockpick' },
defaultDifficulty = { 'easy', 'easy', 'medium' },
breakChanceOnFail = 0.20, -- 20% break on failed pick
breakChanceOnSuccess = 0.05, -- 5% break on successful pick
cooldownMs = 1500,
}
has_passcode boolean is synced. The server-side skill check result is validated independently of whatever the client reports.
Configuration
Config.Defaults = {
locked = true,
autolock = 0, -- 0 = disabled, seconds otherwise
maxDistance = 2.5, -- ox_target interaction radius
doorRateSwing = 10.0,
doorRateAuto = 0.0, -- 0 = instant
}
Config.DoorTypes = {
['garage'] = { autoDefault = true },
['sliding'] = { autoDefault = true },
}
Exports & Developer API
| Export | Notes |
|---|---|
| getDoor(doorId) | Returns the full door object |
| getAllDoors() | Safe client representation, passcode excluded |
| setDoorState(doorId, locked, reason) | Bypasses access checks — programmatic control |
| editDoor(doorId, data) | Bypasses access checks, edits any field |
AddEventHandler('rde_doors:stateChanged', function(source, doorId, locked, reason)
-- reason: 'owner' | 'access_list' | 'group_grade' | 'item_meta:badge' | 'passcode' | 'lockpick:lockpick' | 'autolock' | 'export'
end)
Nostr Logging
Every significant event — lock/unlock, create/update/delete, purchase, lockpick attempt, autolock fire — is logged to rde_nostr_log if it's running. If not, logging is silently skipped — no errors, no crashes.
Common Pitfalls
attempt to index a number value (local 'player') on ox:playerLoaded
The correct ox_core v3+ signature is function(playerId, userId, charId) — an older pattern assumed the second argument was a player table, but it's actually the numeric userId.
Fix: already corrected in v4.0.0. If you're extending rde_doors, always destructure as (playerId, userId, charId).
No such export postLog in resource rde_nostr_log
The correct export name is postLog, not log.
Fix: exports['rde_nostr_log']:postLog('message', {{'event','type'}}).
Door created but invisible in-game
rde_doors stores the integer result of GetEntityModel() directly — many door entities have no registered string name, so GetHashKey isn't used as the primary source.
Fix: use /doorinfo while standing near the expected position to confirm the door saved with correct coordinates and model hash.
FAQ
Is this ox_doorlock-compatible?
Yes — client exports like getClosestDoor(), useClosestDoor(), and pickClosestDoor() mirror the ox_doorlock API surface.
Does upgrading from v3 to v4 need a migration?
No — auto-migration adds the new v4 columns automatically with zero data loss. Downgrading from v4 to v3 is also safe; v3 simply ignores the new columns.
Changelog
Sliding/garage/gate types, lockpick system, passcode unlock, group+grade access, item+metadata access, custom sounds, hold-open, hide-UI, auto-migration.
Double door support, door groups, Nostr logging, triple admin verification.