Skip to main content

v3.0.0

This is a big one. Handcuffs was rebuilt from the ground up. It runs on QBCore now as well as ESX, it stores everything in MySQL, it got a real target menu, and it comes with its own in-game admin dashboard. Most of the config moves into the database, so you can manage everything while the server is running.

New

  • QBCore support. Next to ESX Legacy the script now runs on QBCore. msk_core detects the framework on its own, you don't set anything.
  • Target menu. In v2 Config.Target only registered the undrag key, there were no target options at all. You now get a real target integration for ox_target (recommended) and qb-target: cuff, hardcuff, uncuff, ankletracker, headbag, tape, drag, put in car and put out of car, each one switchable in Config.Target.options. Config.Target.system is set to auto by default, which picks ox_target when it is running and falls back to qb-target. The entries are translated into the dashboard language and the label follows the current state, so the same option reads "Put on headbag" or "Remove headbag" depending on what is going on. Change the language in the dashboard and the text updates live.
  • Admin dashboard. Type /handcuffadmin in-game to open it. The Players tab lists everyone online with their current status and lets you cuff, hardcuff and uncuff them and toggle the ankletracker, headbag and tape with one click. On top of that there are tabs for your items, the job restrictions, all the settings and who is allowed in. You can rename the command with Config.adminCommand.
  • Permission system. You can give your team access to the dashboard without handing them everything. The rights are split per action, so you can let a moderator cuff and uncuff people without also giving them the settings. group.admin can always do it all and group.user can never get in. You manage the groups from the Permissions tab, and Config.dashboardGroups decides which groups may open the dashboard at all.
  • Theme editor. You can recolor the dashboard live from the Settings tab.
  • Discord webhook in the dashboard. The webhook is a normal setting now, so you can paste it in from the Settings tab instead of opening a file.
  • No item needed to remove (optional). New toggles for the headbag and the tape. By default you no longer need an item to take them off. Turn the toggle on if you want a remove item to be required again.
  • Keep the remove items (optional). New toggles so the item you use to remove something is not taken out of the inventory. This covers every remove item now, the ankletracker key, the headbag key, the tape key and the uncuff item (cuff_keys / scissors). Off by default, so keys stay reusable.
  • Escort hint. While you drag a cuffed person around, a small TextUI tells you which key lets them go again. It shows the key you actually have bound, so if you rebind the undrag key in the FiveM settings the hint follows along. Translated into every language.
  • luxu_admin support. luxu_admin v2 keeps its staff groups to itself instead of registering them as ACE principals, so the dashboard could not see them. It now asks luxu_admin directly. You configure it in config/static.lua under Config.LuxuAdmin: turn it on or leave it on auto, rename the resource, require the staff member to be on duty, and map luxu_admin group names onto your dashboard groups.

Changed

  • MySQL instead of database.json. The cuff status, the ankletracker and everything else now live in a msk_handcuffs table through oxmysql. You do not import an .sql file, the table is created on the first start. If you still have an old database.json lying around it gets imported once, automatically, and the original is kept as a backup.
  • Status is readable through statebags. Every status sits in a replicated statebag, so any other resource can read whether someone is cuffed without asking through a callback. Config.MaxDistance is new and every action is measured against it on the server.
  • Everything runs off the database now. The config is imported once on the first start, and after that the database is the source of truth and you edit things from the dashboard. Two tables are created automatically for this: msk_handcuffs_settings and msk_handcuffs_permissions. Your existing msk_handcuffs table with the cuff status stays exactly as it is.
  • Config was split into two files. config/settings.lua holds all the values you can also change in the dashboard, and config/static.lua holds the code parts like the notification, the voice and mute handling, the control blacklist and the prop list.
  • New interface. The headbag blackscreen and the cuff sounds now run through a rebuilt interface that shares one page with the dashboard. Nothing changes for the player.
  • The Discord webhook moved. It used to sit in server/discord.lua and now lives in the config and the dashboard.
  • Default items always work. With Config.RestrictItems on, the default items and options are always usable no matter the job, and the job just adds its own on top.
  • The right key for the right cuffs. Uncuffing only works with the item that matches how the person was cuffed. Cable ties open with scissors, handcuffs open with the cuff keys, nothing else.
  • Clearer messages. When you are missing an item, the notification now names the item's in-game label instead of the internal item name.
  • Items register without a restart. Items you add or change in the dashboard become usable right away, no server restart needed, on ESX, QBCore, ox_inventory and jaksam_inventory.

Security

  • The whole script is server-sided. The client only asks and the server decides everything: the distance between the two players, whether you really carry the right item, your job and the current status. Players can no longer set their own cuff status.
  • The old trick where a cuffed player could free themselves is gone. The auto-uncuff timer and the uncuff on death both run on the server now.

Breaking

  • config.lua is gone and replaced by the config/ folder. Please give your config a quick look after updating and move any custom values over to config/settings.lua, or to config/static.lua for the code parts like the props and the mute function.
  • After the first start the dashboard and the database are in charge. If you change a value in the file later, it will not do anything unless you change it in the dashboard as well.
  • oxmysql is a requirement now.
  • Some exports and events were renamed, and the self-cuff exports (Cuff, Hardcuff, Uncuff) and the admin exports were removed. See Migration from v2.

Changed files

This release is a full rewrite, so replace the entire resource.

New: config/settings.lua, config/static.lua, shared/admin_perms.lua, shared/utils.lua, client/actions.lua, client/ankletracker.lua, client/props.lua, client/admin/ (main, nui, sync), server/database.lua, server/discord.lua, server/versionchecker.lua, server/admin/ (store, permissions, seed, api, command, boot) and the React NUI in web/, built into html/.

Gone: config.lua, database.json, client/functions.lua, client/encrypted.lua, server/functions.lua, server/encrypted.lua, server/discordlog.lua, html/script.js and html/style.css.

Rewritten: fxmanifest.lua, client/main.lua, client/target.lua, server/main.lua, server/commands.lua, translation.lua and html/index.html.