Integrations — Air Hockey | Quasar Store | Quasar Store
Documentation
Integrations
Connect Air Hockey to your FiveM server: ESX, QBCore, Qbox or standalone, cash and bank entry fees, a custom currency, creator permissions, notifications, map tables and 41 languages.
Air Hockey talks to the rest of your server through a handful of small, open files: server/custom/framework/ for money, permissions and names, and client/custom/framework.lua for notifications and the prompt. Everything else is detected on its own:
Layer
Supported
Without it
Framework
es_extended · qb-core · qbx_core
Runs standalone: nobody is charged, and players are listed by their FiveM name.
Money
Cash and bank on ESX, QBCore and Qbox
Every table is free to play.
Custom currency
Config.CanAfford · Config.RemoveMoney
The framework's cash and bank.
Permissions
ACE — command.ahcreator, or your own
Nobody can open the creator.
Notifications
qs-interface
ox_lib notifications titled Air Hockey.
3D prompt
qs-textui
Built-in 3D text over the table.
Map tables
Any prop_airhockey_01 on a map or MLO
Only tables from the creator and the config.
Languages
41 locale files
English.
Every optional integration degrades silently. A missing resource makes its part fall back to the built-in behaviour — nothing errors and nothing needs to be switched off by hand.
The framework is picked from whichever of these is already started when Air Hockey starts:
Resource
Mode
es_extended
esx — ESX
qb-core
qb — QBCore
qbx_core
qb — Qbox, through its QBCore compatibility layer
None of them
standalone
Each mode has one file in server/custom/framework/ — esx.lua, qb.lua and standalone.lua — and only the one matching your server runs. Each defines the same four functions:
Function
Decides
CanAfford(src, amount, method)
Whether a player can pay a table's entry fee — checked before a game against the bot, when a challenge is sent and when it is accepted.
RemoveMoney(src, amount, method)
Takes the entry fee.
HasPermission(src)
Who may open the creator and create, move or delete tables.
GetCharacterName(src)
The name shown in the opponent list and in the challenge window: the character's name on ESX, QBCore and Qbox, the FiveM name standalone.
method is the table's payment method from the creator — 'money' for cash or 'bank' — and maps to cash and the bank account on every framework.
Entry fees can be paid in something other than money — casino chips, a VIP coin, arcade tokens. Define these two functions in config/config.lua and every framework file hands the decision to them, standalone included:
They are only ever called on the server, and never for a free table. method is still passed, so you can use the table's Cash / Bank choice to pick between two currencies of your own.
Define both together. One without the other checks one currency and takes another. Air Hockey never pays anything out, so there is no third function to write.
HasPermission checks the ace in Config.Creator.permission — command.ahcreator unless you set your own. To let your framework's admin groups in as well, extend it in the matching file:
lua
-- server/custom/framework/esx.luafunctionHasPermission(src)local xPlayer = ESX.GetPlayerFromId(src)
if xPlayer and (xPlayer.getGroup() == 'admin'or xPlayer.getGroup() == 'superadmin') thenreturntrueendlocal perm = Config.Creator and Config.Creator.permission or'command.ahcreator'return IsPlayerAceAllowed(src, perm)
end
lua
-- server/custom/framework/qb.luafunctionHasPermission(src)if QBCore.Functions.HasPermission(src, 'admin') thenreturntrueendlocal perm = Config.Creator and Config.Creator.permission or'command.ahcreator'return IsPlayerAceAllowed(src, perm)
end
The same check opens the creator, and the server runs it again for every create, move and delete — a modified client cannot change tables. The debug tools are the exception: they are gated only by Config.Debug.
Many arcades and MLOs already have GTA V's air hockey table. With Config.AutoDetect = true, every player's game looks for the nearest one within Config.StreamDistance every two seconds and makes it playable — no placing, no config line. A see-through table, such as the creator's preview, is never picked up.
The models live in the config. If your map uses a different table, set it in Config.TableModel — the creator places the same model — and calibrate Config.Table for it as shown in Usage.
lua
Config.TableModel = joaat('prop_airhockey_01')
-- Puck: tried in order, the first that exists in the game is used
Config.PuckModels = {
joaat('proair_hoc_puck'),
joaat('prop_air_hoc_puck_01'),
joaat('prop_air_hoc_puck'),
}
Config.PaddleModels = {
[1] = joaat('prop_air_hoc_paddle_01'), -- red (the solo player / the challenger)
[2] = joaat('prop_air_hoc_paddle_02'), -- blue (the bot / the challenged player)
}
If none of the puck models exists in your game, the puck is invisible — /ahcheck shows which ones are valid. See Common Errors.
41 translations ship in locales/: Arabic (ar), Bulgarian (bg), Bengali (bn), Catalan (ca), Czech (cs), Danish (da), German (de), Greek (el), English (en), Spanish (es), Estonian (et), Persian (fa), Finnish (fi), French (fr), Hebrew (he), Hindi (hi), Croatian (hr), Hungarian (hu), Indonesian (id), Italian (it), Japanese (ja), Korean (ko), Lithuanian (lt), Latvian (lv), Malay (ms), Dutch (nl), Norwegian (no), Polish (pl), Portuguese (pt), Romanian (ro), Russian (ru), Slovak (sk), Slovenian (sl), Swedish (sv), Swahili (sw), Thai (th), Turkish (tr), Ukrainian (uk), Urdu (ur), Vietnamese (vi) and Chinese (zh). Pick one with:
lua
Config.Locale = 'es'
One file translates the notifications and the whole interface, the creator included. To adjust a sentence, edit locales/<code>.json and restart the resource. Any key missing from your language falls back to English, and a code with no file falls back to English entirely, with a warning in the F8 console.