OrigenNetwork
Docs

Custom · origen_graffiti

The custom/ folder lets you extend origen_graffiti without touching the core. All files here are escrow_ignore — they survive updates.

text
custom/
├── client/
│   ├── hooks.lua        — client-side event hooks
│   └── permissions.lua  — client-side permission checks (UX feedback)
└── server/
    ├── hooks.lua        — server-side event hooks
    └── permissions.lua  — server-side permission checks (authoritative)

Client Hooks — custom/client/hooks.lua

Fired by the core on the client side. Add your logic inside each handler.

graffiti:hook:onTagAdded

Fired when the client receives a new tag to render — on save or zone sync.

lua
AddEventHandler('graffiti:hook:onTagAdded', function(row)
    -- row.id         — DB tag ID
    -- row.coords     — vector3 center
    -- row.created_by — license identifier
    -- row.image_url  — public image URL
    -- row.created_at — UTC timestamp string
end)

graffiti:hook:onTagRemoved

Fired when the client removes a tag from the local world.

lua
AddEventHandler('graffiti:hook:onTagRemoved', function(id, coords)
    -- id     — tag DB ID
    -- coords — vector3 where the tag was
end)

graffiti:hook:onCanvasModeChanged

Fired when the local player enters or exits canvas mode (active painting session). Useful to hide/show HUD, radial menus, etc.

lua
AddEventHandler('graffiti:hook:onCanvasModeChanged', function(active, context)
    -- active          — boolean (true = enter canvas, false = exit canvas)
    -- context.state   — current state string
    -- context.sessionId
    -- context.isOwner — boolean
end)

Server Hooks — custom/server/hooks.lua

Fired by the core on the server side. Add your logic inside each handler.

graffiti:hook:onTagCreated

Fired when a player successfully saves a graffiti.

lua
AddEventHandler('graffiti:hook:onTagCreated', function(src, data)
    -- src              — server ID of the player
    -- data.id          — DB tag ID
    -- data.coords      — vector3 center
    -- data.created_by  — license identifier
    -- data.image_url   — public image URL (Fivemanage)
    -- data.created_at  — UTC timestamp string
end)

Example — log graffiti creation:

lua
AddEventHandler('graffiti:hook:onTagCreated', function(src, data)
    print(('[graffiti] Player %s painted tag #%d at %s'):format(
        data.created_by, data.id, tostring(data.coords)
    ))
end)

graffiti:hook:onTagDeleted

Fired when a tag is deleted — by an admin or by a player using an eraser.

lua
AddEventHandler('graffiti:hook:onTagDeleted', function(src, id, coords)
    -- src    — server ID of the player
    -- id     — deleted tag DB ID
    -- coords — vector3 where the tag was
end)

Client Permissions — custom/client/permissions.lua

Called by the core before each action for immediate UX feedback. Returning false cancels the action client-side.

Client checks are for UX only — they can be bypassed. The server permissions are always the authoritative gate.

GraffitiPerms.canPaint(coords)boolean

Called at the start of activateGraffiti(), before any async operation.

lua
function GraffitiPerms.canPaint(coords)
    -- coords — vector3 player position when activating the spray
    return true
end

GraffitiPerms.canErase(coords)boolean

Called just before entering erase mode, after the target tag is identified.

lua
function GraffitiPerms.canErase(coords)
    -- coords — vector3 center of the tag to erase
    return true
end

GraffitiPerms.canShop(coords)boolean

Called when the player presses E near a shop point, before opening the NUI.

lua
function GraffitiPerms.canShop(coords)
    -- coords — vector3 shop location coordinates
    return true
end

Server Permissions — custom/server/permissions.lua

Authoritative checks called server-side before each action. These actually block the operation.

GraffitiPerms.isAdmin(src)boolean

Called on all admin callbacks and commands. Validates against Config.AdminGroups using three fallback layers:

  1. FiveM Ace PermissionsIsPlayerAceAllowed (QBCore, QBX, any ace-based framework)
  2. ESX groupxPlayer.getGroup()
  3. Bridge fallbackFramework.GetIsFrameworkAdmin
lua
function GraffitiPerms.isAdmin(src)
    -- src — server ID
    return true -- or your custom check
end

GraffitiPerms.canPaint(src, coords)boolean

Called in graffiti:server:startSession after distance validation.

lua
function GraffitiPerms.canPaint(src, coords)
    -- src    — server ID
    -- coords — vector3 canvas center
    return true
end

GraffitiPerms.canErase(src, coords)boolean

Called in graffiti:server:deleteWorldTag after reading coords from DB.

lua
function GraffitiPerms.canErase(src, coords)
    -- src    — server ID
    -- coords — vector3 tag coordinates
    return true
end

GraffitiPerms.canShop(src, coords)boolean

Called in graffiti:server:shopBuy before checking player funds.

lua
function GraffitiPerms.canShop(src, coords)
    -- src    — server ID
    -- coords — vector3 player position at purchase time (may be nil)
    return true
end