Developer

3 min readUpdated 3 weeks ago

Overview

All integration hooks live in the open/ folder. These files are never escrowed and can be freely modified. The system also exposes server-side functions and custom events for external integrations.

Server Handlers

Located in open/server.lua.

Item Distribution

open/server.lua
1function OpenServer.BeforeGiveItem(src, item, amount)
2    -- Return false to block the item from being given
3    return true
4end

Called before the system gives a reward item (from quiz profiles or crafting). Return false to block.

Action Completion

open/server.lua
1function OpenServer.OnActionComplete(src, actionType, data)
2    -- actionType is the executed action's trigger type ('client' or 'server')
3    -- data = { terminalId, actionId, event, args }
4end

Fires after an action-panel button executes successfully. Use it for XP, battle-pass progress, or auditing.

Client Handlers

Located in open/client.lua.

UI Access Control

open/client.lua
1function OpenClient.BeforeOpenUI(data)
2    -- Return false to prevent the terminal UI from opening
3    return true
4end

Action Panel Integration

The actions app type triggers custom events on your server or client. Your external script just registers the handler:

your_script/server.lua
1RegisterNetEvent('myScript:lockdown', function(args)
2    local level = args.level
3    -- Lock all doors, trigger alarm, etc.
4end)
your_script/client.lua
1RegisterNetEvent('myScript:triggerAlarm', function(args)
2    local zone = args.zone
3    -- Play alarm sound, flash screen, etc.
4end)

Quiz Gating

Apps of type locked_folder can be gated behind quiz completion:

  • requireQuiz = true: Requires ANY quiz on this terminal to be completed
  • requireQuiz = 'quiz_id': Requires a SPECIFIC quiz to be completed
  • requiredProfile = 'tactician': Requires a specific profile result from the quiz

Quiz Rewards

When a player confirms their profile, rewards are distributed automatically:

  • money: Cash via Bridge
  • items: Items via Bridge (array of { name, amount })
  • vehicle: Registers a vehicle ({ name = "model" }) to the player using Config.Vehicles settings
  • job: Sets the player's job via Bridge ({ name, grade })

Server Exports

GetGoatProfile(identifier, terminalId) returns the quiz profile id a player was assigned on a terminal, or nil if they have not completed it. Reads from cache, falls back to the database.

your_script/server.lua
1local profile = exports.ml_terminal_system:GetGoatProfile(identifier, 'my_terminal')
2if profile == 'tactician' then
3    -- grant tactician perks
4end
  • identifier: the framework player identifier (from Bridge.GetPlayerId(src))
  • terminalId: the base terminal ID (without any _locN suffix)

Config Validation

All terminal configs are validated at startup via Config.ValidateAll(). A failure logs a descriptive [ERROR] for that terminal. Validated fields:

  • label: Required
  • model: Required
  • coords or locations: At least one required
  • apps[].name and apps[].type: Required per app
  • Quiz questions/profiles are NOT validated here, they merge from config_questions.lua by terminal ID at startup.
  • kiosk.mode and kiosk.app: Required if kiosk section exists