RDE_DOORS DOCS
RED DRAGON ELITE // PROPERTY & WORLD

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.

01 / Start Here

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.

Core Principle Access is checked through 8 ordered layers — admin, owner, access list, legacy auth, group+grade, item+metadata, legacy items, passcode. The first layer to pass wins.

Door Types

TypeBehavior
Single / DoubleStandard swing doors — double doors sync perfectly as one unit
SlidingZero door-rate, instant open
Garage / GateLarge automatic doors, auto=true by default
02 / Start Here

Quick Start

server.cfg
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.

03 / Reference

Access Control — 8 Layers, In Order

#LayerNotes
1AdminACE permission + ox_core groups + Steam ID fallback
2OwnerThe character who created or purchased the door
3Access listPer-character allowlist, granted by owner or admin
4Legacy auth arrayGroup name only, grade 0 — backward compatible
5groups_data (v4)Group name + minimum grade requirement
6items_data (v4)Item name + optional metadata + consume-on-use flag
7Legacy items arraySimple item check, no metadata
8PasscodeAnyone with the correct code can toggle
04 / Reference

Lockpick & Passcode

config.lua — Lockpick
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,
}
Passcode security The passcode is never sent to the client — only a has_passcode boolean is synced. The server-side skill check result is validated independently of whatever the client reports.
05 / Reference

Configuration

shared/config.lua
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 },
}
06 / Reference

Exports & Developer API

ExportNotes
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
Listen for lock state changes
AddEventHandler('rde_doors:stateChanged', function(source, doorId, locked, reason)
    -- reason: 'owner' | 'access_list' | 'group_grade' | 'item_meta:badge' | 'passcode' | 'lockpick:lockpick' | 'autolock' | 'export'
end)
07 / Reference

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.

08 / More

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.

09 / More

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.

10 / More

Changelog

v4.0.0

Sliding/garage/gate types, lockpick system, passcode unlock, group+grade access, item+metadata access, custom sounds, hold-open, hide-UI, auto-migration.

v3.0.0

Double door support, door groups, Nostr logging, triple admin verification.