🔑 Physical Keys
Requirements
- ox_inventory - Physical keys only work with ox_inventory. If you use a different inventory system, physical keys will be automatically disabled.
Configuration
Enable physical keys in your config.lua:
luaPhysicalKeys = { Enabled = true, -- Enable physical key system (requires ox_inventory) ItemName = 'housing_key', -- The item name for physical keys in ox_inventory KeychainItemName = 'keychain', -- The item name for the keychain in ox_inventory KeychainSlots = 5, -- The number of slots in the keychain KeychainMaxWeight = 1000, -- The maximum weight of the keychain -- Bitting code configuration BittingCodeLength = 5, -- Length of the random bitting code portion (e.g., 63323) -- Key types that can be issued KeyTypes = { MainEntrance = true, -- Keys for main property entrance (Shell/IPL) InteractablePoints = true, -- Keys for individual interactable points Doors = true, -- Keys for individual MLO doors MasterKey = true, -- Master key that unlocks everything }, -- Allow re-keying (changing lock cylinders) AllowRekey = true, -- Cost to change the lock cylinder of a lock (0 for free) RekeyPrice = 500, -- Key wax system (allows players to make impressions of keys) KeyWax = { Enabled = true, -- Enable key wax functionality BlankItemName = 'key_wax', -- Blank key wax item name UsedItemName = 'key_wax_used', -- Used key wax (with bitting code imprint) item name }, -- Ped configuration for key distribution -- You can add multiple locksmiths with different settings LockSmiths = { { Enabled = true, -- Enable this locksmith ped CreateInvalidKeys = true, -- Allow creating invalid keys CreateKeyByBittingCode = true, -- Allow creating a key by bitting code SellKeyWax = false, -- Allow buying blank key wax from this locksmith KeyWaxPrice = 500, -- Price for one blank key wax SellKeychain = false, -- Allow buying keychains from this locksmith KeychainPrice = 750, -- Price for one keychain KeyByBittingCodePrice = 1000, -- Price for a key by bitting code KeyPrice = 1000, -- Price for a key Model = 'IG_Benny_02', -- Ped model to use for key distribution Coords = vector4(169.9714, -1799.5154, 29.3159, 318.0738), -- Location for this ped }, -- Example of additional locksmith (uncomment and modify to add more): { Enabled = true, CreateInvalidKeys = false, -- This locksmith doesn't create invalid keys CreateKeyByBittingCode = true, SellKeyWax = true, KeyWaxPrice = 750, -- Different key wax pricing per locksmith SellKeychain = true, KeychainPrice = 1000, KeyByBittingCodePrice = 1500, -- Higher price KeyPrice = 800, -- Lower key price Model = 's_m_m_autoshop_02', -- Different ped model Coords = vector4(-401.3177, -450.8532, 37.3349, 194.9187), -- Different location }, }, },
Adding Items to ox_inventory
Add the following items to your ox_inventory/data/items.lua:
lua['housing_key'] = { label = 'Property Key', weight = 50, stack = false, close = true, description = 'A key for a property lock', consume = 0, }, ['keychain'] = { label = 'Keychain', weight = 50, stack = false, close = false, consume = 0, buttons = { { label = "Rename", action = function(slot) local newName = lib.inputDialog("Rename Keychain", { { type = "input", label = "New Name", default = "Keychain" } }) if not newName then return end lib.callback.await('nolag_properties:server:physicalKeys:renameKeychain', false, slot, newName[1]) end } } }, ['key_wax'] = { label = 'Key impressioning wax', description = 'Use this to impression keys. Impressioning is the process of creating a copy of a key by pressing it into wax.', weight = 10, consume = 0, unique = true, client = { image = 'key_wax.png', } }, ['key_wax_used'] = { label = 'Used key impressioning wax', description = 'Use this to impression keys. Impressioning is the process of creating a copy of a key by pressing it into wax.', weight = 10, consume = 0, unique = true, client = { export = 'nolag_properties.getBittingCode', image = 'key_wax.png', } },
Key Types
Main Entrance Key (E)
- Available for Shell and IPL properties
- Unlocks the main entrance door
Interactable Point Key (P)
- Available for all property types
- Unlocks specific interactable points (inventory, wardrobe, etc.)
Door Key (D)
- Available for MLO properties
- Unlocks specific doors within the property
Master Key (M)
- Available for all property types
- Unlocks all doors and interactable points on the property
Bitting Code Format
Each key has a unique bitting code that identifies which lock it opens:
PPPPPP_T_LLLL_RRRRR
PPPPPP- Property ID (6 digits, zero-padded)T- Lock Type (E=Entrance, P=Point, D=Door, M=Master)LLLL- Lock ID (4 digits, zero-padded)RRRRR- Random code (5 digits by default)
Example: 000001_E_0000_63323 means:
- Property ID: 1
- Lock Type: Entrance
- Lock ID: 0
- Random Code: 63323
Re-keying
When a lock is re-keyed:
- A new bitting code is generated
- All existing keys for that lock become invalid
- New keys must be issued with the new bitting code
This simulates changing the lock cylinder in real life.
Managing Keys
Keys can be managed through the property management menu:
- Open the property management menu
- Go to the "Physical Keys" tab
- Select a lock to issue keys or re-key
Exports
The following exports are available for integration:
lua-- Check if physical keys are enabled local enabled = exports.nolag_properties:PhysicalKeys_IsEnabled() -- Check if a player has a valid key local hasKey = exports.nolag_properties:PhysicalKeys_PlayerHasKey(source, propertyId, lockType, lockId) -- Issue a key to a player local success, error = exports.nolag_properties:PhysicalKeys_IssueKey(source, propertyId, lockType, lockId) -- Validate a key metadata against a lock local valid = exports.nolag_properties:PhysicalKeys_ValidateKey(keyMetadata, propertyId, lockType, lockId) -- Re-key a lock local newCode, error = exports.nolag_properties:PhysicalKeys_RekeyLock(propertyId, lockType, lockId) -- Get all available locks for a property local locks = exports.nolag_properties:PhysicalKeys_GetAvailableLocks(propertyId)