Hacks in Your Scripts
The ten hacking minigames are not only for Command Prompt. Any resource can put one in front of a door, a vault or a terminal, and get a result it can trust: a win is checked on the server, so a modified client cannot skip the hack.
There are three ways to do it:
| Use it when | You call | |
|---|---|---|
| From the server | Your server code decides when the hack happens | RunHack |
| From the client | Your robbery's flow runs on the client (a target option, an animation, then the hack) | StartHack, then ConsumeHackProof on the server |
| At a computer | The player has to sit at a security PC and break in from Command Prompt | A target in configs/server/targets.lua |
How a Win Is Verified
A player never gets to say "I won". Every run, from Command Prompt or from your script, goes the same way:
- The server starts the run. It reads the difficulty's settings from
configs/shared/hacks.lua, works out the least time the game can be played in and how many milestones it has, and hands the client a token. Formaze,pipe,typingandsignalit also generates the puzzle itself and keeps the answer. - The client plays, reporting each milestone in order. Milestones that come faster than a person could play are refused.
- The client submits the win. The server checks that the token is still good, that every milestone arrived, that the run took at least the minimum time, and that the puzzle's answer is right.
- Only then does something happen: at a computer, the next step of a breach or its reward; for your script, a proof.
A proof is good once, only for the player who played it, and only for ProofTTL seconds (120). The minimum play time is worked out from the same settings as the difficulty, so a harder preset is also a longer proof of play.
From the Server: RunHack
The simplest way. Your server code asks for a hack, the player plays it, and the call returns true only for a verified win. There is no proof to handle: the server redeems it itself.
RegisterNetEvent('my-robbery:server:hackVault', function()
local src = source
-- your usual checks first: near the vault, has the item, enough police, not on cooldown
if exports['sd-computers']:RunHack(src, 'pipe', 'hard') then
-- open the door, start the loot
end
end)RunHack waits while the player plays, so call it from an event handler or a thread, as above. It returns false straight away if that player already has a hack window open.
From the Client: StartHack
When your robbery's flow runs on the client, open the hack there and send the proof to the server, which redeems it before giving anything. This is a straight swap for another minigame resource:
-- client: before
exports['some-minigame']:Start(function(success)
if success then TriggerServerEvent('my-robbery:server:openVault') end
end)
-- client: after
local won, proof = exports['sd-computers']:StartHack({ game = 'pipe', difficulty = 'hard', title = 'Vault Door' })
if won then
TriggerServerEvent('my-robbery:server:openVault', proof)
end-- server
RegisterNetEvent('my-robbery:server:openVault', function(proof)
local src = source
local info = exports['sd-computers']:ConsumeHackProof(src, proof, { game = 'pipe', difficulty = 'hard' })
if not info then return end -- no proof, someone else's, already used, expired, or an easier game
-- check src is really at the vault, then open it
end)Redeem the proof on the server
Most robberies trust a bare TriggerServerEvent sent after their minigame, so anyone with an executor can fire that event and skip the hack altogether. Swapping only the client half looks the same in game but stays exactly that exploitable. The server half, ConsumeHackProof, is what closes it. The expect table also stops a proof from an easy run being used for a hard lock.
At a Computer: Breach Targets
For a heist where the hack happens at a computer - a bank's security office, a server room - add a breach target. The player types breach <command> in Command Prompt, plays every step in order, and the server fires your event when the last one is won:
-- configs/server/targets.lua
{
id = 'pacific_vault_lock',
computers = { 'pacific_security_pc' }, -- a computer id from computers.lua
command = 'vault-lock', -- the player types: breach vault-lock
label = 'Pacific Standard - vault time lock',
hidden = true, -- not listed by `targets`: they need the intel
steps = {
{ game = 'maze', difficulty = 'hard' },
{ game = 'cipher', difficulty = 'hard' },
},
requires = { item = 'trojan_usb', count = 1, consume = true },
cooldown = 3600,
failCooldown = 120,
exclusive = true,
alert = { chance = 60, onFail = true, title = 'Vault Intrusion', code = '10-90', jobs = { 'police' } },
reward = { event = 'my-robbery:server:vaultUnlocked' },
},-- your robbery, server side
AddEventHandler('my-robbery:server:vaultUnlocked', function(src, info)
-- info = { target = 'pacific_vault_lock', computer = 'pacific_security_pc', instance = 'pacific_security_pc' }
-- unlock the vault door
end)AddEventHandler, not RegisterNetEvent
The reward event is fired on the server with TriggerEvent. Listen with AddEventHandler: an event that is never registered as a net event cannot be fired by a client.
Every successful breach also fires sd-computers:server:breachCompleted, if you would rather hear about all of them in one place. Put a target like this on a location computer: a prop computer's position comes from the player's client, so the server cannot prove they are really there.
Things to Know
- A run from your script is not tied to a place. sd-computers proves the player won the game, not that they were standing at your vault. Check where they are on the server, as you would without it.
- One run at a time per player. Starting a new one voids the one in progress, and two starts by the same player need a second between them.
StartHackreturnsfalsewhile its window is already open. - Difficulty is a preset, not a setting per call.
'easy','medium'and'hard'are the presets inconfigs/shared/hacks.lua; changing one changes it for every robbery and for Command Prompt. - Taking a game out of
Gamesinconfigs/shared/hacks.luaturns it off for the exports too.Practice = falsedoes not: it only stops practice runs in Command Prompt. - Leave a trail.
AddLogwrites to a computer's System Logs: log "Vault door opened" to the bank's security PC, and whoever looks into it afterwards finds it in that computer's Event Viewer.
exports['sd-computers']:AddLog('pacific_security_pc', 'warning', 'Vault Control', 'Vault time lock overridden', { door = 'Main vault' })The Minigames
| Key | Game | Key | Game |
|---|---|---|---|
maze | Network Maze | evasion | Highway Evasion |
capture | Node Capture | typing | Code Injection |
cipher | Cipher Lock | signal | Signal Replay |
snake | Data Worm | pipe | Packet Routing |
firewall | Firewall Defense | breakout | ICE Breaker |
