Browse docs
Doorlock
These optional integrations belong to sky_jobcreator. Start your integration after Creator and add dependency "sky_jobcreator" to its manifest. Doorlock is disabled by default and can be enabled in its settings.
Read doors
GetDoor(id) and GetDoors() are available on the client and server.
local door = exports["sky_jobcreator"]:GetDoor(12)
local doors = exports["sky_jobcreator"]:GetDoors()
Pass a numeric door ID. GetDoor returns a copied door definition or nil; GetDoors returns a list sorted by ID. Disabled/unavailable gameplay returns nil or an empty list. The client reads its current synchronized snapshot, so use the server for authoritative decisions.
Returned doors include id, label, locked, defaultLocked, revision, generation, coordinates, leaves and presentation settings. hasPin indicates a saved credential. oxId is the separate optional OX compatibility ID; securityState contains the installed level and damaged flag. The lockpick profile in gameplay snapshots is the currently effective profile. Credentials, allowed-player identifiers and ACE rules are not included in these public snapshots. A pending door is exposed as locked.
Server only: GetDoorlockStatus() returns { ready, enabled, error?, resource? }. A competing door resource is reported as provider_conflict; a disabled feature reports disabled.
provider_conflict also remains set after a detected provider stops. Creator saves disabled
activation as a precaution; the administrator must explicitly enable it again. Do not infer
active gameplay from the resource's started state or retry state changes until the status
reports enabled = true.
Custom Doorlock providers can identify themselves in their manifest:
sky_doorlock_provider "my_doorlock"
The active resource is then treated as a competing writer. Standard provide aliases are
also recognized. An unknown renamed resource without recognizable provider metadata cannot
be detected reliably. Creator's own OX alias is excluded from this check.
Change a door's state
Server only. This is a trusted integration call. Authorize the caller in your own script before using it; do not expose it through an unrestricted network event.
local result = exports["sky_jobcreator"]:SetDoorState(12, false)
if not result.success then
print("Door state was not confirmed:", result.error)
end
true locks the door; false unlocks it. Returns { success = true, data = door } or { success = false, error, pending? }. The existing persistence, synchronization and auto-lock settings apply. Treat an unknown/pending result as uncertain; do not automatically repeat the write.
Start forced entry
Forced entry starts by using the configured inventory item. Creator registers its usable action through the selected Sky Base inventory integration. There is no forced-entry command, keybind or direct target action.
Server only: custom inventory integrations can forward a validated item-use callback:
-- Call inside your inventory's authenticated usable-item callback.
local function useDoorTool(playerId, itemName)
local result = exports["sky_jobcreator"]:UseDoorlockItem(playerId, itemName)
if not result.success then
print("Door tool was not started:", result.error)
end
end
Pass the connected server ID and exact configured item name. This is a trusted server integration; never forward arbitrary client input to it. Creator verifies the character, active runtime and item ownership, then starts the normal nearby-door flow. A successful response confirms item-use dispatch, not a completed minigame or unlocked door. Observe the completed-attempt events below for that outcome.
Only enabled methods for the used item can be selected. One matching method starts directly; several open the normal choice. Amount, provider, character, range, instance, cooldown and server result checks still apply. A use is accepted once and expires if it is not started promptly. It does not bypass tool consumption or grant normal job/PIN access.
The older client LockpickDoor(doorId?, methodId?) export remains available for compatibility, but cannot start a standalone attempt: without the server-issued inventory use it returns item_use_required. Migrate custom item actions to UseDoorlockItem; direct target/command calls are no longer the entry point.
Read method IDs from GetDoor(doorId).lockpick.methods. Each entry has its own id, enabled, provider, tool and attempt settings. The method ID identifies a configured alternative at that door; it is not the provider ID. An omitted lockpick object means forced entry is disabled. Older single-method definitions are automatically represented as one legacy entry.
The item flow submits the minigame result through the existing door owner. A planted explosive keeps the door locked until its accepted countdown completes. An uncertain result does not mean it is safe to repeat a write.
Minigame results originate on the client. The server validates context, inventory and attempt timing; Crime's custom hacks also use their server-owned challenge result. A client skill-check success alone is not proof against a modified client.
Observe completed attempts
These are local server events for trusted resource integrations. Use AddEventHandler, not RegisterNetEvent.
AddEventHandler("sky_jobcreator:doorlocks:breachArmed", function(playerId, doorId, seconds, methodId)
-- React to an accepted charge before its countdown finishes.
end)
AddEventHandler("sky_jobcreator:doorlocks:lockpickFinished", function(playerId, doorId, success, toolRemoved, methodId)
-- React to a confirmed completed attempt.
end)
playerId is a server ID. For a charge that detonates after its original character has left, it is 0. Failed completed attempts emit success = false; cancellation, rejected context and uncertain writes do not emit a confirmed completion. Explosives emit their successful completion when the door is actually unlocked, after the armed event.
The trailing methodId identifies the configured alternative. Existing handlers using the earlier arguments continue to work.
Observe dispatch alarms
Configure built-in alarm rules in the Doorlock editor. An optional integration can observe the result of an alarm dispatch:
AddEventHandler("sky_jobcreator:doorlocks:alarm", function(doorId, trigger, sourceId, state, errorCode, methodId)
if state == "rejected" or state == "unknown" then
print("Door alarm dispatch:", doorId, state, errorCode)
end
end)
This is a local server event, not a client-triggered alarm API. trigger is attempt, failed, success or armed. sourceId correlates that dispatch request; it is separate from the private attempt credential.
| State | Meaning |
|---|---|
created | Jobs Base confirmed creating the incident |
queued | Jobs Base is starting and has already queued the request |
rejected | The dispatch API returned an explicit rejection; errorCode gives its reason |
unknown | The dispatch outcome was not confirmed; do not replay it as a new alarm |
No alarm event is emitted when its trigger is disabled, its chance does not pass, the door cooldown suppresses it, or the door context is invalidated before submission. A created incident does not confirm that a particular player saw its notification. Dispatch authorization and recipient delivery remain Jobs Base responsibilities.
Register a minigame provider
Use the registrar when a different minigame library should appear in the Doorlock editor. This is optional developer integration; server owners using the included OX/Crime methods do not need to register anything.
local Sky_Jobcreator = exports["sky_jobcreator"]:Get()
local catalog = Sky_Jobcreator.FW.GetLockpicks()
The same operations are available as direct RegisterLockpick, UnregisterLockpick and GetLockpicks exports. Register the same ID on the client and server of your integration resource, after Creator starts.
FW.RegisterLockpick(id, adapter) returns true, or false, error. IDs contain letters, digits, _ or - and are at most 64 characters. Registration is owned by the calling resource; another resource cannot replace or remove it. Re-register after Creator restarts. Stopping your integration removes its registrations.
| Adapter field | Side | Contract |
|---|---|---|
label, resource | Both | Display label and the resource that must be running |
hideWhenUnavailable | Both | Optional boolean; hide the entry when its owner/provider is stopped |
family, variant | Both | Optional IDs for grouping variants in the editor |
variantLabel | Both | Optional readable game name within its library |
supportsDifficulty, supportsRounds | Both | Optional booleans; set false to hide a setting the game does not use |
manualCancel | Both | Optional boolean; the library's UI must finish using its own controls after an attempt is cancelled |
minimumTimeLimit | Both | Optional minimum attempt limit, 8–120 seconds |
run(challenge) | Client, required | Run your minigame and return { success = boolean, cancelled?, error?, evidence? } |
cancel() | Client, required | Make run return cancelled. Close only UI/focus/props you own; use manualCancel if a third-party library cannot close remotely |
prepare(playerId, challenge) | Server, optional | Return provider data, or nil, error; data is supplied to the client as challenge.providerData |
verify(playerId, challenge, result) | Server, optional | Return exactly true to accept successful play |
release(playerId, challenge) | Server, optional | Clean up a prepared provider session on completion, rejection or cancellation |
explosive | Server, optional | Use Creator's delayed charge flow after a successful action |
The challenge contains token, label, duration, minimumDuration, difficulty (1–5), rounds (2–8), seed, location and distance. The built-in OX method can additionally carry skillCheck = { checks, inputs } for individual rounds, described below. Keep server secrets out of providerData. Provider callbacks may yield, but must return and support cooperative cancellation; cancellation cannot forcibly stop arbitrary code inside another resource. A resource restart invalidates its in-flight attempts.
FW.GetLockpicks() returns { id, label, available, family?, variant?, variantLabel?, minimumTimeLimit?, manualCancel?, supportsDifficulty?, supportsRounds? }[]. FW.UnregisterLockpick(id) returns true, or false, error, and only removes the caller's entry.
Client only: FW.RunLockpick(id, challenge) and FW.CancelLockpick() also have direct exports. RunLockpick runs presentation only and returns the provider result; it does not unlock a door, consume an item or create an authorized door attempt. Use the inventory item flow for gameplay. Only the current caller, adapter owner or Creator can cancel its active run.
Select door objects
Client only, for an administrative editor integration:
exports["sky_jobcreator"]:SelectDoorObjects(
{ minLeaves = 1, maxLeaves = 2 },
function(result)
if result.success then
-- result.data: leaves, x, y, z, bucket
end
end,
function(selecting)
-- Hide your editor while selecting; restore it afterwards.
end
)
Creator administration permission and an enabled Doorlock runtime are required. Bounds are 1–8; multiple = false defaults the maximum to one. Confirming selects physical door data; this call does not save a door definition. Cancellation, timeout and provider conflicts return { success = false, error }.
Manage installed equipment
Client only, yielding. ManageDoorSecurity(doorId?, action?, level?) uses the closest door when the ID is omitted. Without an action it opens the equipment-action chooser. Supported actions are install, repair and remove; level selects the installation target when supplied.
CreateThread(function()
local result = exports["sky_jobcreator"]:ManageDoorSecurity()
if not result.success then
print("Equipment action did not complete:", result.error)
end
end)
Management jobs/ACEs, current level, damage, range, inventory, duration and player context are checked by the server. This export grants no permissions. A cancelled action does not install equipment. A partial/uncertain item deduction or write returns a pending result; do not retry it automatically.
Observe confirmed changes with the local server event:
AddEventHandler("sky_jobcreator:doorlocks:securityChanged", function(playerId, doorId, action, level, damaged)
-- The accepted equipment state has been stored and synchronized.
end)
sky_jobcreator:doorlocks:phoneAlarmResult(doorId, alarmSourceId, playerId, status) reports client_accepted, fallback, rejected or unknown. client_accepted is the recipient client’s integration report; it does not prove a player saw the notification. No event argument contains the PIN or a phone delivery token.
Create, update and delete definitions
Trusted server integrations only. These use the same validation, revision checks and storage as the editor:
These exports require Doorlock to be enabled. While it is disabled, use the Creator editor to manage saved definitions.
| Export | Arguments | Result |
|---|---|---|
CreateDoor | definition, pin?, requestId? | { success, data?, error?, pending?, committed? } |
UpdateDoor | id, revision, definition, pin? | Same result shape |
DeleteDoor | id, revision | { success, error?, pending?, committed? } |
Pass a complete Creator definition, including label, a leaves array with each leaf’s model, x, y, z, heading, the interaction x, y, z, and its access/presentation settings. Keep the full definition in your trusted integration; the public GetDoor snapshot omits private ACL fields and must not be round-tripped as a complete update. Updates require the current revision. Pass a new PIN separately; omitting it retains the existing credential. CreateDoor can generate its request ID, or your integration can keep one stable request ID for reconciliation.
The calling resource must be running. Do not forward these exports through an unrestricted client event. A conflict requires a fresh read and an explicit new decision. A pending or committed-but-unconfirmed response is not permission to replay a mutation.
Access fields in a definition
Set the access member of the complete definition passed to CreateDoor or UpdateDoor:
definition.access = {
mode = "any",
jobs = {
{ name = "police", grades = { 0, 2, 7 }, requireDuty = true },
},
timeZone = "Europe/Berlin",
jobHours = {
{ from = 22 * 60, to = 2 * 60, days = { 1, 2, 3, 4, 5 } },
{ allDay = true, days = { 6 } },
},
}
| Field | Contract |
|---|---|
jobs[].minGrade | Minimum rank, inclusive. Omit or use 0 when supplying grades. |
jobs[].grades | Optional non-empty list of up to 100 distinct integer ranks, 0–1000. Only those ranks match; higher ranks do not automatically match. |
timeZone | Optional IANA zone, up to 64 characters. Omit for server local time. Invalid zones return invalid_timezone; there is no fallback to a different zone. |
jobHours, pinHours, itemHours | Up to 16 windows per method. An absent or empty list imposes no time restriction on that method. |
Window from, to | Integer minutes after midnight, 0–1439. Start is included, end excluded. An end before the start continues into the next day. Equal times are invalid unless allDay is true. |
Window days | Optional non-empty list of distinct weekdays: Monday 1 through Sunday 7. These are the days the window starts; omit for every day. |
Window allDay | Optional boolean. true covers the entire selected day; from/to can then be omitted and are saved as 0. |
The example permits ranks 0, 2 and 7 on duty: Monday–Friday overnight and all Saturday, using Berlin time. Friday's overnight window continues until Saturday 02:00. PIN and item windows are configured separately. Player/ACE alternatives keep their own access semantics; a time window is not an automatic closing schedule. IANA zones apply daylight-saving changes using the server clock.
Keep existing OX integrations
This opt-in setting lets existing calls such as exports.ox_doorlock:getDoor(id) reach Creator without installing another bridge resource.
- Back up your existing OX resource and door data. Preview/import supported doors while Creator Doorlock is disabled.
- Stop the original
ox_doorlockand remove its automatic start entry from your server configuration. Keep its files and backup. - In Creator’s
fxmanifest.lua, uncommentprovide "ox_doorlock". Enable Creator’s Doorlock feature in its settings. Saved settings take precedence over the config default. - Restart Creator to apply the manifest change, then start your OX-dependent integrations after it.
Both the feature and the optional provide are disabled in a fresh package. Do not run two door runtimes together. To return to original OX, disable Creator Doorlock, comment the provide line again and restart Creator before starting OX.
provide is a static Cfx replacement declaration: GetResourceState("ox_doorlock") can report started while Creator’s Doorlock feature is disabled. Use GetDoorlockStatus() when your script needs to know whether Creator gameplay is active.
| Side | Available OX exports |
|---|---|
| Server | getDoor, getAllDoors, getDoorFromName, createDoor, editDoor, removeDoor, setDoorState, registerHook, removeResourceHook |
| Client | getClosestDoor, getClosestDoorId, getDoorIdFromEntity, useClosestDoor, pickClosestDoor |
removeHooks is also accepted as an alias of removeResourceHook. The familiar OX 0/1 states and export return shapes are used. Imported OX IDs are retained; other doors receive persistent compatibility IDs. OX IDs and Creator IDs are different namespaces: use door.oxId for OX calls, and door.id for Creator calls.
getClosestDoor() includes the full safe OX projection, current distance, the localized zone, and the resolved hash/entity for a single door or for each entry in doors. hasPasscode is a boolean; the credential is never returned. createDoor can derive the midpoint of a double door when shared coordinates are omitted, and uses its coordinates as the fallback name.
When Creator is the selected OX provider, it sets a local Entity(entity).state.doorId compatibility ID for its loaded doors when that field is free. Existing foreign values are preserved. Direct integrations can use getDoorIdFromEntity(entity) to resolve Creator's own registration. Entity state is not permission evidence.
Switch providers in order: disable/stop Creator before starting original OX, and stop original OX before enabling Creator. Starting both together is unsupported; an identical numeric entity-state value cannot identify which resource last wrote it. Restart dependent integrations after selecting their provider.
Local server TriggerEvent("ox_doorlock:setState", oxId, state) remains a trusted state setter. Network requests keep player, range, access and PIN checks. An unbound client lockpick=true flag cannot unlock a door. pickClosestDoor does not start a standalone attempt; inventory integrations use UseDoorlockItem for the item-based flow.
The compatibility layer emits ox_doorlock:loaded, the local server ox_doorlock:stateChanged(playerId, oxId, locked, usedItem) after accepted changes, and client ox_doorlock:editDoorlock(oxId, definition?) updates. Existing ox_doorlock:setState client listeners receive confirmed 0/1 state updates.
registerHook("doorAuthorization", callback, options?) keeps the original calling resource as the owner. Payload fields are source, door, lockpick and authorised; door is the full safe OX projection. options.nameFilter is a Lua pattern. options.print = true logs the hook ID and calling resource without dumping credentials. nil keeps the access result, true grants it, and false or a callback error rejects it. Hooks are removed when their owner stops, and a grant cannot survive that stop during a pending write.
For a door with one enabled OX method, the full OX projection includes lockpickDifficulty. editDoor(oxId, { lockpickDifficulty = { "easy", { areaSize = 25, speedMultiplier = 1.8 }, "hard" } }) updates that method's ordered rounds while preserving its tool and possible keys. Use 1–32 rounds; custom areaSize is 1–360 degrees and speedMultiplier is 0.1–10. Configure the method and its tool in Creator first. Multiple methods and enabled security-tier profiles must be edited in Creator; the OX interface does not choose a method or flatten those profiles.
Trusted Creator definitions can set skillCheck on an ox_lib method:
skillCheck = {
checks = { "easy", { areaSize = 25, speedMultiplier = 1.8 }, "hard" },
inputs = { "w", "a", "s", "d" },
}
inputs contains 1–16 distinct lowercase letters or digits. skillCheck overrides that method's numeric difficulty and rounds; omitting it keeps the shared-difficulty behavior. The same settings are available in each installed-security level's lockpick profile. They are specific to the OX adapter.
Unsupported definitions are rejected explicitly. Current limits include automatic import of OX lockpick tools/global defaults, item metadata, mixed PIN/character/item policies and custom OX audio assets. OX edits cannot flatten Creator duty, exact-rank, access-hours, account-identifier or combined-access rules. Exact-rank rules are omitted from OX's minimum-grade groups projection; that projection is not a complete Creator access policy. Use the Creator editor or a complete native definition for those fields. Private OX administration/NUI callbacks and arbitrary inventory-removal events are not reproduced.