OPX//77
Guides

Convert from FiveM

Last updated on

How FiveM, ESX and QBCore habits map onto Open77 and opx_infinity — what stays, what changes, and where each familiar framework call now lives.

The runtime shape of Open77 is close to FiveM: CreateThread, Wait, RegisterNetEvent, TriggerServerEvent, RegisterCommand and exports all exist. The natives do not: Open77 has its own Open77.* API. And OPX//77 is not ESX or QBCore, even where the names look familiar.

For the old opx77_* resources, read From opx77_* to opx_infinity instead.

Decide where your code goes

Your codePut it in
Gameplay that needs money, jobs, items, vehiclesa module inside opx_infinity — the only place the contracts are reachable
Something independent: a job, a shop, a log toola separate resource using the creator exports

Runtime habits

FiveM habitOpen77 / OPX//77
Natives such as GetPlayerPed, SetEntityCoordsDifferent API. Look up each one with the Open77 devkit (open77_fivem_equivalent); never guess a name.
while true do ... Wait(0) end on the clientOPX.Scheduler.Every. The client has a per-resume instruction budget; an overrun stops the loop silently.
require / shared Lua modules on the serverNot available on the server. Shared helpers are in lib/.
Metatables / classes in shared codeNot available on the client. Use plain tables.
CfxLua syntax (vectors, backtick hashes, ?., +=)Plain Lua 5.4 only.
TriggerEvent to talk to another resource on the clientDoes not leave the resource on Open77.
ExecuteCommand with console authorityNeeds runtime.commands, and restricted commands are refused.
NUI page per resource, SendNUIMessageOne shared WebUI page; OPX.UI.Send on a named channel. See The WebUI page.
fxmanifest.luaopen77.lua, a manifest DSL with a permissions { } block. List every script on its own line.
Server ACE permissionsACL rights in acl.jsonc; a restricted command checks command.<name>. See Permissions.
oxmysqlThe platform's MySQL bridge (MySQL), wrapped by OPX.Storage.

ESX / QBCore calls

The character API is QBCore-shaped (PlayerData, citizenId, Functions), but reached through the character contract, server side, inside opx_infinity.

local character = OPX.Api.Get('character')
local player = character.GetPlayer(source)
ESX / QBCoreOPX//77 (server, inside a module)
QBCore.Functions.GetPlayer(src) / ESX.GetPlayerFromId(src)character.GetPlayer(source)
Player.PlayerDataplayer.PlayerData — see the Player object
Player.Functions.AddMoney('bank', n, reason) / xPlayer.addAccountMoneycharacter.AddMoney(source, 'BANK', n, reason) — answers ok, code
Player.Functions.RemoveMoneycharacter.RemoveMoney
Player.Functions.SetJob(job, grade)character.SetJob (yields)
Player.Functions.SetMetaDatacharacter.SetMetadata
QBCore.Functions.GetPlayers()character.GetPlayers()
exports['qb-inventory']:AddItem / xPlayer.addInventoryItemthe inventory contract
QBCore.Functions.Notify / ESX.ShowNotificationOPX.Notify (server) or OPX.Toast.Show (client)
QBCore.Functions.CreateCallbacka network event pair, or OPX.UI.On plus OPX.UI.Answer for the page; on the client, Lib.Callback in opx_lib
qb-menu / esx_menu_defaultthe menu module
qb-input / esx_dialogthe form module
qb-target / ox_targetthe target module
qb-garagesthe garages module
money hooks / onMoneyChangeOPX.Hooks money:beforeAdd and friends

Money types are upper case (EDDIES, BANK), from MONEY.TYPES.

A short checklist

  1. Move the code into a module folder, or decide it stays a separate resource.
  2. Replace every native using the devkit.
  3. Replace client loops with scheduler jobs.
  4. Replace framework calls with contract calls (table above).
  5. Re-check every network payload on the server.
  6. Move text into locales.lua (English and French).
  7. List every file in open77.lua; add the permissions your natives need.
  8. Run lua tests/run.lua.

On this page