Docs

Configuration

All configuration lives in a single file: shared/config.lua. It is the only file you are expected to edit — everything else in the core can stay encrypted (escrow). The file is loaded before the rest of the core, so your settings and overrides are already in place by the time any adapter binds.

Two ideas run through the whole config:

  • Sensible defaults. Every value works out of the box. You can start the resource with an untouched config and tune later.
  • The open hook (Veltar.Overrides). Instead of forking the core, you plug your own systems in through override functions. Return nil to keep Veltar's behavior, or return a value to take over. This is how you attach a custom notification system, bank, inventory, licenses, multijob, and so on — without touching encrypted code.

> How settings are read. Config is evaluated once, at resource start. After editing shared/config.lua you must restart veltar_core (or ensure it fresh) for changes to take effect. There is no live reload.


Veltar.Debug

Enables debug-level logging and unlocks the built-in developer commands. Use it while building or diagnosing, never on a live production server.

Veltar.Debug = false
ValueBehavior
falseProduction mode. debug logs are suppressed and dev commands are not registered (default).
trueVeltar.Log(scope, 'debug', msg) messages print, and /vlaser, /vcoords, /vheading, /vtpw become available.

What the dev commands do (only registered when Debug = true):

CommandPurpose
/vlaserToggles a raycast laser — draws a line + marker where you aim and prints the coordinates, heading, and reverse heading. Ideal for placing props/markers.
/vcoordsPrints your current position as both vector3 and vector4 (copy from the F8 console).
/vheadingPrints your current heading only.
/vtpwTeleports you to the waypoint set on the map.

> Leaving Debug = true on a public server is a security risk — it exposes teleport and coordinate tooling and floods your console. Ship with false.


Veltar.Lang

Language of the core's built-in strings (anti-cheat kick reasons, UI button labels, diagnostic messages). Dictionaries are plain, editable Lua tables in shared/locales/.

Veltar.Lang = 'pl'
ValueBehavior
'pl'Polish (default).
'en'English.
customAny language code for which a shared/locales/<code>.lua file exists.

Adding or editing strings. Each locale file registers a table under Veltar.Locales[<code>]. Copy en.lua, translate the values, and point Veltar.Lang at your new code. Missing keys fall back to the key name itself, so a partial translation never breaks anything.

-- shared/locales/de.lua
Veltar.Locales.de = {
    ['ui.submit'] = 'Bestätigen',
    ['ui.cancel'] = 'Abbrechen',
}

> Locale files are kept out of escrow (escrow_ignore), so your translations survive core updates as long as you keep your copies.


Veltar.InventorySystem

Chooses the inventory adapter. Leave it on auto-detect unless you run something unusual or want to force a specific system during testing.

Veltar.InventorySystem = 'auto'
ValueBehavior
'auto'Detects the running inventory automatically, in a fixed priority order (recommended).
'ox_inventory'ox_inventory — works on ESX, QB and QBox. Supports item metadata.
'qb-inventory'Legacy qb-inventory (through the player object).
'qs-inventory'Quasar inventory. Metadata passed as info.
'ps-inventory'ps-inventory (qb-inventory fork; shares its API).
'codem-inventory'CodeM mInventory.
'jaksam_inventory'Jaksam's inventory.
'esx_addoninventory'Legacy ESX event-based inventory (ESX only).

How auto-detection resolves. At startup the core checks resource states in order — ox_inventoryqs-inventoryqb-inventoryps-inventorycodem-inventoryjaksam_inventory → classic ESX. The first one running wins, and all item calls (AddItem / RemoveItem / HasItem) route to that adapter for the rest of the session.

> If no inventory is detected the core enters a safe NONE mode: item calls return false instead of erroring. Check what was detected with the /veltar command. To completely replace inventory handling with your own system, use Veltar.Overrides.AddItem / RemoveItem / HasItem instead of forcing a value here.


Veltar.SocietyMoney

Backend for company/faction (society) accounts on QB / QBox. On ESX the core always uses esx_addonaccount, so this setting is ignored there.

Veltar.SocietyMoney = 'native'
Veltar.SocietyTable = 'veltar_society_accounts'
ValueBehavior
'native'The core manages its own table (Veltar.SocietyTable) through oxmysql. Zero extra dependencies.
'qb_management'Delegates to the qb-management resource.

About Veltar.SocietyTable. This is the table name used in native mode. It is validated at load (only letters, digits and underscores are accepted) to prevent injection through a mistyped config — an invalid name falls back to the default with a warning.

> native mode requires oxmysql. Balance withdrawals use an atomic conditional UPDATE (... WHERE money >= amount), so two simultaneous withdrawals can never drive an account negative. If you run a custom banking resource, override Veltar.Overrides.GetSocietyMoney / AddSocietyMoney / RemoveSocietyMoney instead.


Veltar.Admins

Defines who counts as an administrator. This drives Veltar.Bridge.IsAdmin(src) and every admin gate in the core (diagnostics, SecureEvent { admin = true }, protected entity deletion).

Veltar.Admins = {
    groups      = { 'admin', 'superadmin', 'god', 'mod' },
    aces        = { 'veltar.admin' },
    identifiers = {},
}
FieldBehavior
groupsFramework groups treated as admin. Read via ESX getGroup() or QB GetPermission().
acesACE permissions checked with IsPlayerAceAllowed. Grant them in server.cfg, e.g. add_ace group.admin veltar.admin allow.
identifiersAn explicit allow-list of raw identifiers, e.g. { 'license:xxxxxxxx', 'steam:110000...' }.

Resolution order. IsAdmin returns true if any of these match: the player is the server console (source 0), an override says so (Veltar.Overrides.IsAdmin), an ACE matches, the player's group is in groups, or one of their identifiers is in identifiers.

> For a fully custom staff system, implement Veltar.Overrides.IsAdmin(src) — it short-circuits everything above and lets you defer to your own admin resource.


Veltar.AntiCheat

The built-in lightweight anti-cheat. It is intentionally lightweight — it is not a replacement for a dedicated AC, but it closes common holes for scripts built on the core: explosion spam, oversized transactions, entity flooding, HP/armor tampering, and event spoofing.

Veltar.AntiCheat = {
    enabled         = true,
    webhook         = '',
    dropOnDetect    = false,
    explosions      = { block = true, maxPerMinute = 4, blacklist = {} },
    maxMoneyPerTx   = 500000,
    blockMoneyAbove = false,
    maxItemPerTx    = 100,
    blockItemAbove  = false,
    entities = {
        allowClientRequests = true,
        perPlayer   = 8,
        maxDistance = 60.0,
        throttleMs  = 500,
        despawnOnDrop = true,
        blacklist   = {},
    },
    watchdog     = { enabled = true, intervalMs = 30000 },
    saltedEvents = true,
}

Global

FieldBehavior
enabledMaster switch. false disables every check below.
webhookDiscord webhook URL that receives flag embeds. Empty = console logging only.
dropOnDetecttrue kicks a flagged player. Veltar.Overrides.Ban takes priority if defined.

Explosions

FieldBehavior
explosions.blocktrue cancels the offending explosionEvent.
explosions.maxPerMinuteAllowed explosions per player per rolling 60 seconds before a flag.
explosions.blacklistExplosion type IDs that are always blocked and flagged.

Transactions

FieldBehavior
maxMoneyPerTxA single AddMoney above this amount raises a flag. 0 disables the check.
blockMoneyAbovetrue also blocks the over-limit money transaction, not just flags it.
maxItemPerTxSame idea for a single AddItem count.
blockItemAbovetrue also blocks the over-limit item grant.

Entities (client spawn channel)

FieldBehavior
entities.allowClientRequestsfalse fully disables client-side entity spawning. Server-side Veltar.Entities.Create* still works.
entities.perPlayerMaximum number of live entities a single player may own at once.
entities.maxDistanceA client may only create an entity within this radius (metres) of itself.
entities.throttleMsMinimum time between a player's entity requests.
entities.despawnOnDroptrue deletes a player's entities when they disconnect.
entities.blacklistModels blocked in requests and deleted by the entityCreated guard when spawned outside the core.

Integrity

FieldBehavior
watchdog.enabledPeriodic scan flagging players whose HP or armor exceeds the maximum (flag-only, never auto-kicks).
watchdog.intervalMsHow often the scan runs.
saltedEventsEnables per-session tokens for events registered with SecureEvent { salted = true }.

Reacting to flags. A flag always logs to console and, if configured, posts to webhook. Whether it punishes depends on you: set dropOnDetect = true for an automatic kick, or wire Veltar.Overrides.Ban(src, reason) into your ban system for full control.

> Set the entity blacklist. entities.blacklist = { 'rhino', 'cargoplane', 'lazer' } feeds two defenses at once: it rejects those models on the client request channel, and the entityCreated guard deletes them if a cheater spawns them by any other means. Leaving it empty is the single most common reason "the anti-cheat did nothing".


Veltar.Ledger

A transaction audit log. Every successful money/item add or remove is written to the database with actor, amount, and reason — the foundation for economy forensics (dupes, "where did the million come from").

Veltar.Ledger = {
    enabled       = true,
    retentionDays = 14,
}
FieldBehavior
enabledfalse disables the ledger entirely (no table, no writes).
retentionDaysRows older than N days are purged nightly. 0 keeps everything forever.

Reading the ledger. From the server console or as an admin, run /veltar ledger <src|identifier> [limit] to print a player's most recent transactions with timestamps.

> Requires oxmysql. If it is missing (or enabled = false) the ledger silently stays off with a console notice — no crash. Writes happen after the underlying transaction succeeds, so a rejected RemoveMoney is not logged.


Veltar.VersionCheck

Optional startup check that compares your installed version against a remote endpoint and prints a console notice if a newer one exists.

Veltar.VersionCheck = { enabled = false, url = '' }
FieldBehavior
enabledtrue runs the check ~5 seconds after boot.
urlAn endpoint that returns the latest version as plain text (e.g. the string 2.4.0).

> This is purely informational — it never blocks startup, downloads, or modifies anything. If the endpoint is unreachable it logs a debug line and moves on.


Veltar.UI.Config

Theme and placement of the built-in React UI: progress bar, TextUI, notifications, and NUI sounds. These values are pulled by the UI at startup, so changing them only needs a resource restart — no rebuild.

Veltar.UI.Config = {
    ProgressBar = { theme = 'darkBlack', bottomOffset = 1 },
    TextUI      = { theme = 'darkBlack', bottomOffset = 5.5 },
    Notify      = { theme = 'darkBlack', duration = 5000 },
    Sound       = { defaultVolume = 0.5 },
}
FieldBehavior
themeColor scheme, one of: orange, darkGray, darkBlack, navy, green, purple, red.
bottomOffsetDistance from the bottom of the screen, in vw (viewport-width) units.
Notify.durationDefault notification lifetime, in milliseconds.
Sound.defaultVolumeDefault NUI audio volume, 0.01.0.

Notification priority. Veltar.Bridge.Notify prefers the Veltar React UI, then falls back to ox_lib, then to the framework's native notification — so notifications keep working even if you strip the UI.

> The UI is prebuilt in ui/dist. You only need to rebuild (cd ui && npm install && npm run build) if you edit the React source in ui/src. Changing themes/offsets here does not require a rebuild.


Veltar.Overrides

The heart of Veltar's extensibility. Every core action and getter passes through Veltar.Overrides.* first, letting you attach your own phone, bank, inventory, licenses, multijob, admin, ban, dispatch, society, and stash systems without editing encrypted code.

Veltar.Overrides.AddMoney = function(src, account, amount, reason)
    -- exports['my_bank']:Add(src, account, amount, reason)
    -- return true
    return nil
end

The contract.

Return valueMeaning
nilPassthrough — Veltar runs its built-in logic (ESX/QB/OX).
true (for actions: Notify/AddItem/AddMoney/SetJob/…)"I handled it." Veltar does not run the default.
a value (for getters: GetPlayer/GetMoney/HasItem/…)Veltar uses your value. false and 0 count as deliberate answers — only nil means passthrough.

Getter vs action example:

-- ACTION: take over notifications entirely with your phone
Veltar.Overrides.Notify = function(src, message, ntype)
    exports['my_phone']:Send(src, message)
    return true                       -- Veltar skips its own notify
end

-- GETTER: report a balance from your bank
Veltar.Overrides.GetMoney = function(src, account)
    return exports['my_bank']:Balance(src, account)   -- 0 is a valid answer
end

Available override groups: notifications, inventory (AddItem/RemoveItem/HasItem), economy (AddMoney/RemoveMoney/GetMoney), player (GetPlayer/GetPlayerByIdentifier), jobs (SetJob), licenses, duty, multijob (SetSecondJob/GetSecondJob/GetJobs/HasJob), admin/ban (IsAdmin/Ban), phone (PhoneNotify), dispatch (DispatchAlert), society, stash, and status.

> Errors are contained. Every override runs inside pcall. If your code throws, Veltar prints a warning naming the override and falls back to the default logic — a bug in this open file can never crash the encrypted core. This is why the overrides file is the only one safe to hand to a server owner.


Applying changes

Configuration is read once at resource start, so restart the resource after editing.

# fresh start
ensure veltar_core

# live console
restart veltar_core

Verifying your configuration

Confirm the core detected everything you expect with the diagnostic command (server console, or admin in-game):

/veltar
Output lineWhat it tells you
FrameworkESX / QB / NONE — did your framework get detected?
InventoryWhich inventory adapter is active (or NONE).
Society / Phone / DispatchDetected backend for each subsystem.
ox_lib / oxmysql / ReactUI / ACWhether each dependency and feature is live.

You can also smoke-test the UI end to end:

/veltar test notify
/veltar test progress
/veltar test textui
/veltar test sound

> If a value looks wrong here (e.g. Inventory: NONE when you run ox_inventory), the usual cause is start order — the inventory must be ensured before veltar_core. See the Installation page.