Doorlock
🔐 aty_doorlock
A powerful, fully-featured door lock system for FiveM (ESX & QBCore)
Built by atiysu — part of the[aty]resource suite
🔍 Overview
aty_doorlock is a comprehensive, database-driven door management system for FiveM servers. It supports both ESX and QBCore frameworks and provides server administrators with a fully interactive NUI panel to create, configure, and manage door locks entirely in-game — no file editing required after initial setup.
The system is designed around multi-layered security:
- Gate Authorization — Job, Citizen ID, or item-based access control
- Secondary Verification — PIN code, biometric scanner (fingerprint / face ID), or keycard
- Illegal Bypass — Lockpicking or terminal hacking minigames for criminals
Doors sync to all connected players in real time and their state is managed server-side.
✨ Features
| Feature | Description |
|---|---|
| 🖥️ NUI Admin Panel | Full in-game UI to create, edit, delete, and manage doors |
| 🚪 Single & Double Doors | Supports individual doors and synchronized double-door pairs |
| 🔑 Layered Access Control | Job, CitizenID, item-based, or public access |
| 🔢 PIN Code Locks | Number pad prompt for authorized users |
| 👆 Fingerprint Scanner | Physical prop spawned at door; blocks gloved players |
| 👤 Face ID Scanner | Physical prop spawned at door; blocks masked players |
| 💳 Keycard Reader | Uses keycard animation to unlock |
| 🛠️ Lockpick Bypass | Minigame bypass for lockpick-enabled doors |
| 💻 Terminal Hacking | ox_lib skill check for hackable doors |
| 🧬 Biometric Hacking | Word-search minigame to bypass scanners |
| 📡 Remote Controller | Item-based remote toggling within a configurable range |
| ⏱️ Auto-Lock | Doors can be configured to re-lock after a set interval |
| 🔊 Custom Sounds | Custom lock/unlock audio via NUI or GTA native sounds |
| 📂 Category System | Organize doors into categories (Police, Hospital, etc.) |
| 🌐 Real-time Sync | All door states sync across players instantly |
| 📥 ox_doorlock Import | One-command migration from ox_doorlock |
| 🎯 Scanner Prop Streaming | Physical scanner props spawn/despawn based on proximity |
| 🗺️ Teleport to Door | Admin can teleport to any door from the management UI |
📦 Dependencies
The following resources must be installed and started before aty_doorlock:
| Dependency | Required | Notes |
|---|---|---|
aty_lib |
✅ Yes | Core utility library (framework bridge) |
oxmysql |
✅ Yes | MySQL/MariaDB interface |
ox_lib |
✅ Yes | Used for skillCheck minigames |
es_extended or qb-core |
✅ One of them | Supported frameworks |
Note:
ox_inventoryis optional but recommended for item-metadata features (remote controller).
🚀 Installation
Step 1 — Copy the Resource
Place the aty_doorlock folder into your server's resources directory:
resources/
[aty]/
aty_doorlock/ ← here
Step 2 — Import the Database
Run the SQL file against your database using phpMyAdmin, HeidiSQL, or the MySQL CLI:
-- Run this file:
aty_doorlock/doorlocks.sql
The server will also attempt to auto-create the table on startup via
oxmysql, so this step is a safety net.
Step 3 — Add to server.cfg
Add the resource to your server.cfg and make sure it starts after its dependencies:
ensure oxmysql
ensure aty_lib
ensure ox_lib
ensure aty_doorlock
Step 4 — Configure
Open shared/config.lua and adjust the settings to match your server's setup. See the Configuration Reference section for full details.
Step 5 — Restart Server
Start or restart your FiveM server. You should see this in the console on a successful load:
[ATY-DOORLOCK] X doors loaded successfully.
🗄️ Database
The resource uses a single table: aty_doorlocks
| Column | Type | Description |
|---|---|---|
id |
INT | Auto-increment primary key |
doorId |
VARCHAR(50) | Unique string identifier for the door |
doorLabel |
VARCHAR(100) | Human-readable name of the door |
doorType |
VARCHAR(20) | single or double |
category |
VARCHAR(50) | Category label (e.g. police, hospital) |
dist |
FLOAT | Interaction radius in meters |
lockInterval |
INT | Auto-lock timer in seconds (0 = disabled) |
doorHash |
VARCHAR(255) | GTA model hash of the door entity |
coords |
LONGTEXT | JSON coordinates of the door(s) |
users |
LONGTEXT | JSON array of authorized CitizenIDs |
jobs |
LONGTEXT | JSON array of authorized job names |
items |
LONGTEXT | JSON array of authorized item names |
pinCode |
VARCHAR(20) | PIN code for secondary verification |
canLockpick |
TINYINT | 1 = lockpicking allowed |
lpItem |
VARCHAR(50) | Item name required to lockpick |
lpDiff |
VARCHAR(20) | Lockpick difficulty (easy, medium, hard) |
canHack |
TINYINT | 1 = terminal hacking allowed |
hackItem |
VARCHAR(50) | Item name required to hack |
hackDiff |
VARCHAR(20) | Hack difficulty (easy, medium, hard) |
hasFingerprint |
TINYINT | 1 = fingerprint scanner enabled |
hasFaceId |
TINYINT | 1 = face ID scanner enabled |
hasKeycard |
TINYINT | 1 = keycard reader enabled |
pinCodeCoords |
LONGTEXT | JSON coordinates of PIN pad prop |
fingerprintCoords |
LONGTEXT | JSON coordinates of fingerprint prop |
faceIdCoords |
LONGTEXT | JSON coordinates of face ID panel prop |
keycardCoords |
LONGTEXT | JSON coordinates of keycard reader prop |
isLockedByDefault |
TINYINT | 1 = locked on server start |
createRemoteController |
TINYINT | 1 = give creator a remote controller item |
⚙️ Configuration Reference
All configuration is located in shared/config.lua.
Core Settings
Config = {
Debug = true, -- Enable debug prints in server console
OldESX = false, -- Set true only if using ESX legacy (< 1.2)
LicenseType = "steam", -- Player identifier: steam, license, license2, discord, xbox
LocalTimeout = 500, -- ms cooldown per-player between toggles
GlobalTimeout = 1000, -- ms cooldown for a door to be toggled by anyone
}
Admin Command
DoorlockCommand = {
Name = 'doorlock', -- Chat command to open the admin panel
Suggestion = 'Door Lock', -- Description shown in command suggestions
Permissions = {
'admin', -- ESX group / QBCore permission required
-- 'god' -- Uncomment if using QBCore 'god' permission
}
}
Minigame Settings
Minigames = {
Lockpick = {
BreakChance = 30, -- % chance item breaks on minigame failure (if RemoveOnFail = false)
RemoveOnSuccess = true, -- Remove the lockpick item on success
RemoveOnFail = true, -- Remove the lockpick item on failure
Anim = { dict = "...", anim = "...", duration = -1 } -- Animation during lockpicking
},
Hack = {
BreakChance = 10, -- % chance terminal breaks on failure
RemoveOnSuccess = false,
RemoveOnFail = true,
},
Biometric = {
faceid = {
item = "hacking_kit", -- Item required to attempt face ID bypass
difficulty = "hard", -- Minigame difficulty
time = 15, -- Seconds to complete
lives = 3, -- Allowed mistakes
gridSize = 10, -- Grid size (10x10)
targetCount = 5 -- Letters to find
},
fingerprint = {
item = "lockpick",
difficulty = "medium",
time = 25,
lives = 5,
gridSize = 10,
targetCount = 4
}
}
}
Access Control
AdminBypass = false, -- Admins bypass all door locks entirely
MasterJobs = { "police", "sheriff" }, -- These jobs bypass all access checks
Scanner Props
These are the GTA prop models that are physically placed at scanner locations:
ScannerProps = {
faceid = "hei_prop_hei_securitypanel",
fingerprint = "ch_prop_fingerprint_scanner_01d",
keycard = "prop_cs_swipe_card",
pincode = "prop_ld_keypad_01",
}
Scanner Animations
Animations played when interacting with a scanner:
ScannerAnimations = {
faceid = { dict = "mp_common_miss", anim = "put_away_sub", duration = 2000 },
fingerprint = { dict = "mp_fbi_heist", anim = "loop", duration = 2000 },
keycard = { dict = "anim@heists@keycard@", anim = "exit", duration = 2000 },
pincode = { dict = "anim@mp_player_intmenu@key_fob@", anim = "fob_click", duration = 1500 },
}
Door Categories
Used for organizing doors in the admin UI:
Categories = {
{ label = "Police Department", value = "police" },
{ label = "Hospital", value = "hospital" },
{ label = "Cafes", value = "cafes" },
{ label = "General", value = "general" },
}
To add a new category: Simply add a new
{ label = "...", value = "..." }entry.
Sounds
Sounds = {
enabled = true,
lock = { file = "lock.mp3", volume = 0.3 },
unlock = { file = "unlock.mp3", volume = 0.3 }
}
Sound files must be placed in the
web/dist/folder or referenced as GTA native audio sets.
Remote Controller
RemoteDistance = 15.0, -- Maximum range (meters) to use the remote
RemoteItem = "remote_controller", -- Inventory item name for the remote
RemoteAnimation = { dict = "anim@mp_player_intmenu@key_fob@", anim = "fob_click", duration = 1000 }
🎮 In-Game Usage Guide
Admin Panel (Door Manager)
The door manager is an admin-only NUI interface for creating and managing all doors.
Opening the panel:
/doorlock
Requires the
adminpermission (or as configured inConfig.DoorlockCommand.Permissions).
The panel displays all registered doors in a table/list, filterable by category. From here you can:
- ➕ Create a new door
- ✏️ Edit an existing door's settings
- 🗑️ Delete a door
- 🔓 Toggle a door's state directly from the UI
- 📍 Teleport to a door's location (with 5-second stealth mode)
Creating a Single Door
- Open the panel with
/doorlock - Click "Add Door" / "Create"
- Fill in the required fields:
- Door ID — unique identifier (e.g.
pd_front_door) - Door Label — display name (e.g.
Police Department Front Door) - Door Type — select
Single - Category — select from the dropdown
- Interaction Distance — how close a player must be to interact (default:
5.0meters)
- Door ID — unique identifier (e.g.
- Click "Select Door" — the UI will hide and you'll enter door selection mode
- In the world, look at the door entity you want to register:
- A green outline will highlight the door you're aiming at
- Left Click to select it
- The door's hash and coordinates are automatically captured
- Configure access settings (jobs, users, items, scanners, PIN, etc.)
- Click Save to register the door
Creating a Double Door
For double doors (e.g. saloon-style swinging doors):
- Follow steps 1–3 above, but set Door Type to
Double - Click "Select Door"
- You must select 2 door entities one at a time:
- Select the first door panel (green outline appears → Left Click)
- The system awaits the second selection
- Select the second door panel
- Both entities are captured with their individual hashes and coordinates
- Continue with access configuration and save
Placing Scanner Props
If you enable a scanner (fingerprint, face ID, keycard, or PIN pad), a physical prop must be placed in the world.
- In the door creation/edit form, enable a scanner type (e.g. toggle Fingerprint Scanner)
- Click "Place Scanner" next to the scanner type
- The UI hides and a ghost prop appears, following your cursor:
- Point your camera at a wall or surface within 5 meters
- Use Scroll Wheel / Q / E / Arrow Keys to rotate the prop
- Left Click to place it at that position
- Right Click to cancel
- The prop's world position is saved to the door configuration
The prop will automatically appear/disappear based on the player's proximity (within 50 meters).
Editing & Deleting Doors
In the door manager panel:
- Edit: Click the edit/pencil icon on a door row. The form re-populates with current settings. Change any field and save.
- Delete: Click the delete/trash icon. The door is immediately removed from the database and all clients are synced.
Toggling Doors as a Player
Players can interact with nearby doors using the E key:
- Walk within the configured interaction distance (default:
5.0meters) of a door - A HUD indicator appears on-screen showing the door label and its current status (🔒 Locked / 🔓 Unlocked)
- Press
Eto attempt to toggle the door
What happens next depends on the door's configuration:
| Door State | Player Has Access | Secondary Verification | Result |
|---|---|---|---|
| Locked | ✅ Yes | None | Unlocks immediately |
| Locked | ✅ Yes | PIN Code | PIN pad UI appears |
| Locked | ✅ Yes | Fingerprint | Fingerprint scanner UI appears |
| Locked | ✅ Yes | Face ID | Face ID scanner UI appears |
| Locked | ✅ Yes | Keycard | Keycard animation plays, unlocks |
| Locked | ❌ No | Any | Error notification |
| Unlocked | ✅ Yes | N/A | Locks immediately |
🔐 Access Control System
Access is evaluated in this priority order on both client and server:
1. Admin Bypass (Optional)
If Config.AdminBypass = true, admins skip all checks.
2. Master Jobs
Jobs listed in Config.MasterJobs (default: police, sheriff) bypass all per-door access checks.
3. Per-Door Access Rules
If a door has no authorized users, jobs, or items configured → it is treated as public (anyone can toggle it).
If a door has any restriction set, the player must match at least one:
| Type | What's Checked |
|---|---|
| Users | Player's CitizenID / identifier must be in the door's user list |
| Jobs | Player's active job must be in the door's job list |
| Items | Player must have at least one of the door's required items in inventory |
🔒 Security & Verification Methods
These are the secondary lock layers that apply after gate authorization. They are only triggered when a player is unlocking (locking never requires secondary verification).
PIN Code
A number pad prompt appears in-game. The player must enter the correct PIN.
- Configuration (per door): Set a numeric PIN code in the door creation form
- Player action: Press
Enear the door → PIN pad UI appears → type the code → submit
Fingerprint Scanner
A physical prop (ch_prop_fingerprint_scanner_01d by default) is placed at a configured location. When the player interacts, their character performs a scanning animation.
Security checks:
- If the player is wearing gloves, the scan is rejected automatically
- The scanner verifies the player's CitizenID against the door's authorized users list
Player action: Press E near the door → fingerprint scanner UI appears → animation plays → result shown
Face ID Scanner
A physical security panel prop (hei_prop_hei_securitypanel) is placed at a configured location.
Security checks:
- If the player is wearing a mask or head covering, the scan is rejected automatically
- The scanner verifies the player's CitizenID against the door's authorized users list
Player action: Press E near the door → face ID scanner UI appears → animation plays → result shown
Keycard Reader
A swipe card prop (prop_cs_swipe_card) is physically placed at the door. No player inventory item is required — the player simply interacts and the animation plays.
Player action: Press E near the door → swipe animation plays → door unlocks if authorized
🦹 Illegal Bypass Methods
These systems allow unauthorized players (criminals) to attempt to bypass locked doors using minigames — at the risk of losing their tools.
Lockpicking
Requirements:
- Door must have
canLockpick = true - Door must have a lockpick item configured (default:
lockpick) - Player must have the required item in inventory
How to use:
- Have the configured lockpick item in your inventory
- Use the item from your inventory while standing near a locked door
- A skill check minigame (
ox_lib:skillCheck) launches — press the correct keys in sequence - Success → Door unlocks; item may be removed (based on
RemoveOnSuccess) - Failure → Item may break/be removed (based on
RemoveOnFailandBreakChance)
Difficulty levels:
| Level | Pattern |
|---|---|
easy |
easy, easy |
medium |
easy, medium, easy |
hard |
medium, hard, hard |
Hacking
Requirements:
- Door must have
canHack = true - Door must have a hack item configured (default:
terminal) - Player must have the required item in inventory
How to use:
- Have the configured hacking item in your inventory
- Use the item near a locked door
- The same
ox_lib:skillCheckminigame launches with configured difficulty - Same success/fail logic as lockpicking
Biometric Hacking
Requirements:
- Door must have a fingerprint or face ID scanner AND
canHack = true - Player must have the configured biometric hacking item:
- Face ID bypass:
hacking_kit(by default) - Fingerprint bypass:
lockpick(by default)
- Face ID bypass:
How to use:
- Have the required item in your inventory
- Use the item near the door
- A word-search grid minigame appears in the NUI:
- Find the hidden letters within the time limit
- You have a limited number of mistakes allowed
- Success → Door unlocks; item handled per config
- Failure → Item loss based on config
📡 Remote Controller
Certain doors can be assigned a remote controller — an inventory item that lets an authorized holder toggle the door from a distance.
Setup (Admin)
In the door creation/edit form:
- Enable "Create Remote Controller"
- Set a Remote ID — a unique string that links the remote to this door (e.g.
pd_garage_remote) - Save the door — a
remote_controlleritem is automatically added to the admin's inventory with the Remote ID embedded as metadata
Using the Remote (Player)
- Have the
remote_controlleritem in your inventory - Use the item
- A key-fob animation plays on the character
- If you are within
Config.RemoteDistancemeters (default: 15m), the linked door toggles - If you are too far, you'll receive an error notification
Note: The remote bypasses the normal gate authorization check — whoever holds the item can toggle the door regardless of their job.
⏱️ Auto-Lock System
Doors can be configured to automatically re-lock after being unlocked.
Setting it up: In the door form, set the "Lock Interval" field to a number of seconds (e.g. 30 = re-locks after 30 seconds).
Behavior:
- When a door is unlocked, a server-side timer starts
- After the interval, the door state is set back to locked
- All players receive a real-time state update
- Setting the interval to
0disables auto-lock
🔊 Sound System
When a door is toggled, lock/unlock sounds are played for nearby players (within 15 meters).
Configuration:
Sounds = {
enabled = true,
lock = { file = "lock.mp3", volume = 0.3 },
unlock = { file = "unlock.mp3", volume = 0.3 }
}
file— Audio file served via NUI (place inweb/dist/)volume— Float from0.0to1.0- Alternatively, use
name+setfor GTA native audio (omitfileto use native sounds)
📥 Importing from ox_doorlock
If you're migrating from ox_doorlock, the script includes a built-in import command.
Requirements:
ox_doorlocktable must exist in the database- You must have admin permissions
How to import:
In the F8 console or via server console:
import_ox
Or from the game as an admin:
/import_ox
What gets imported:
- Door name →
doorLabel - Door model hash →
doorHash - Coordinates (single or double)
- Job groups →
jobs - Items →
items - Lock state →
isLockedByDefault - PIN code →
pinCode - Lockpick permission →
canLockpick
After import, the console will report how many doors were successfully migrated. Restart the resource to apply:
restart aty_doorlock
📤 Export API
The import.lua file is not escrow-locked, allowing developers to extend or integrate with aty_doorlock. Key server events:
| Event | Direction | Description |
|---|---|---|
aty_doorlock:server:RequestDoors |
Client → Server | Request full door sync |
aty_doorlock:server:ToggleDoor |
Client → Server | Attempt to toggle a door |
aty_doorlock:server:CreateDoor |
Client → Server | Create a new door (admin) |
aty_doorlock:server:UpdateDoor |
Client → Server | Update door settings (admin) |
aty_doorlock:server:DeleteDoor |
Client → Server | Delete a door (admin) |
aty_doorlock:server:MinigameFail |
Client → Server | Report minigame failure |
aty_doorlock:client:SyncDoors |
Server → Client | Push full door table to client |
aty_doorlock:client:UpdateDoorState |
Server → Client | Update a single door's lock state |
aty_doorlock:client:OpenUI |
Server → Client | Open the admin panel |
🛠️ Troubleshooting
"Doors not loading" / "0 doors loaded"
- Ensure
oxmysqlis started beforeaty_doorlock - Run the
doorlocks.sqlfile manually to confirm the table exists - Check the server console for SQL errors
"You do not have permission to interact with this door"
- The door is restricted — check the door's
users,jobs, oritemsconfiguration - Verify the player's CitizenID or job name matches exactly
- Make sure
Config.MasterJobsincludes the relevant job if you want blanket access
Door won't unlock even with correct PIN
- Ensure the pin is stored as a string (not
0or empty) - Check
Config.Debug = trueand review server console output for toggle details
Scanner prop not appearing in-game
- The prop only spawns within 50 meters of the player
- Ensure a valid GTA prop model is set in
Config.ScannerProps - The coordinates must be set during door creation via the "Place Scanner" flow
Lockpick/hack minigame not launching
- Confirm
canLockpick = trueorcanHack = trueon the door - Confirm the player has the correct item (
lockpick,terminal, orhacking_kit) - Ensure
ox_libis started and theskillCheckexport works
Import command not found
- Wait ~2 seconds after server start (the command registers on a short delay)
- Confirm
server/import.luais included infxmanifest.lua✓ (it is by default)
📁 File Structure
aty_doorlock/
├── client/
│ └── client.lua # Client-side logic: HUD, interaction, NUI callbacks, animations
├── server/
│ ├── server.lua # Server-side logic: DB operations, authorization, sync
│ └── import.lua # ox_doorlock migration utility (not escrow-locked)
├── shared/
│ ├── config.lua # All configurable settings + Notify function
│ └── locale.lua # Locale strings (en/fr, extendable)
├── web/
│ └── dist/ # Compiled NUI (HTML/CSS/JS admin panel + sounds)
├── doorlocks.sql # Database table schema
└── fxmanifest.lua # Resource manifest
📝 Notes & Best Practices
- Door IDs must be unique. Use descriptive names like
pd_front_door,hospital_pharmacy_gate. - Always test your access configuration after saving by swapping to a test character.
- Keep
Config.Debug = trueduring setup; switch tofalsein production to reduce console noise. - The
GlobalTimeoutprevents rapid door-spamming by any player. Increase it if you experience abuse. - If using
ox_inventory, remote controller metadata is automatically read from slot metadata. - Doors loaded on server start default to their
isLockedByDefaultstate — plan accordingly for shops, public areas, etc.
Made with ❤️ by atiysu — part of the [aty] FiveM resource collection.