Sal's Kewl Korner Documentation / Sal's Kewl Spawn Selector Discord

Sal's Kewl Spawn Selector — owner's manual

A drop-in replacement for qb-spawn with location previews, job-aware spawn points, per-spawn access rules and an in-game editor that lets an admin place spawns by flying to them. This manual covers installation, configuration, the editor and troubleshooting for server owners.

documents resource version 2.1.0

Overview

The spawn screen is the first thing every player sees, every session. Sal's Kewl Spawn Selector replaces qb-spawn with a menu that shows each location as a tile with its own preview image, a live camera fly-over of the spot under the cursor, and a list that changes per player based on their job, gang, licences, items or citizen ID.

It registers itself as a qb-spawn provider, so resources that expect one keep working.

What it does

  • General and job spawns — everyone sees the general list; police see stations, EMS see hospitals, mechanics see garages.
  • Last location, with anti-abuse: hidden while a player is dead or in laststand, and optionally for a cooldown after combat, so logging out mid-fight is not a free escape.
  • Owned properties through loaf_housing.
  • Favorites and recents, starred by the player and stored in their metadata.
  • Search, for servers with a long list.
  • An in-game editor for admins — see below.

Server-authoritative by design

The client never sends coordinates. It sends an opaque spawn id; the server checks that id against the list that player was actually offered and returns the real coordinates itself. Restricted spawns are never sent to a client who cannot use them, so they cannot be discovered by reading network traffic, and a modified client cannot inject a spawn point, poison its own last location, or refill its own stats.

Requirements

Framework: qb-core, qbx_core or es_extended. Detection is automatic; Config.Framework = "auto" works out which you run. Force it with "qb" or "esx" if detection picks wrong.

There are no hard dependencies. Everything below is optional and detected at runtime, so a missing resource degrades gracefully instead of stopping the resource from starting.

ResourceWhat you lose without it
screenshot-basicThe live camera background behind the menu, and image capture in the spawn editor. Tiles still show their configured images.
loaf_housingThe Properties section. Everything else is unaffected.
illenium-appearanceAppearance loading before the menu opens. Falls back to qb-clothing if that is running.
oxmysqlUsed only by the illenium-appearance lookup.

ESX servers, read this. The framework bridge covers ESX for jobs, metadata, inventory, stats, revive and notifications, but three things are QB-only and will simply never match on ESX: restrict.gangs (ESX has no gang concept), restrict.licenses (ESX licences live in a separate resource), and Config.LastLocation.SuppressWhenDead. Job, grade, citizen ID and item rules all work normally.

Installation

  1. Drop the folder into your resources/ directory as sals_kewlspawnselector.
  2. Add ensure sals_kewlspawnselector to server.cfg, after your framework and any housing or appearance resource.
  3. Open config.lua and set your spawn points — or start the server and place them in-game with the editor.
  4. Restart the server.

Replacing qb-spawn

Remove or comment out ensure qb-spawn in server.cfg and ensure this resource instead. The manifest declares provide 'qb-spawn', so anything that depends on qb-spawn being present is satisfied.

If your multichar or character-creation resource opens the spawn menu itself, point it at this event instead — see Integration.

Check it started cleanly

With Config.ValidateOnStart on (the default), the server console reports the framework it detected and then validates every spawn, naming any that are missing a label, carry invalid coordinates, or point at an image that is not in html/images/:

[sals_kewlspawnselector] Server loaded (v2.1.0, framework: qb).
[sals_kewlspawnselector] Config validation passed.

A missing image is a warning, not an error — the tile falls back to default.png.

Where spawns come from

There are two places spawns can live, and it is worth understanding which one your server is using before you start editing.

config.luaThe file you ship with. The defaults, and the only source until somebody saves in the in-game editor.
data/overrides.jsonWritten by the in-game editor. Layered on top of config.lua every time the resource starts.

The split exists so the editor can never destroy your file. config.lua is never rewritten — your comments, your formatting and your ordering all survive.

The two layer differently, and the difference matters:

  • Spawn lists — once an admin saves in the editor, data/overrides.json owns Config.SpawnLocations and Config.JobSpawns outright. Editing those blocks in config.lua afterwards will appear to do nothing.
  • Settings — merged key by key, so anything you never touched in the editor still comes from config.lua.

It tells you when this bites. If you edit the spawn lists in config.lua after the editor has saved, the resource notices at start and says so in the server console, and the editor shows a banner. You will not be left wondering why the file you just edited did nothing.

Putting the file back in charge

Either one works:

  • Press Reset to config.lua in the editor, or
  • delete data/overrides.json and restart the resource.

Making in-game work permanent

Press Export as Lua in the editor. It generates a config.lua-shaped block; paste it over the matching blocks at the bottom of the file, then delete data/overrides.json.

If you would rather never deal with any of this, set Config.Editor.Enabled = false and config.lua is the only source, always.

In-game spawn editor

New in 2.1.0. An admin runs /spawnedit and gets a full editor over the game: add, rename, reorder, duplicate and delete spawns without touching config.lua or restarting anything.

Permission is checked server-side against Config.Editor.Permission, the same way the spawn command is. The client only ever asks; the server decides whether the editor opens at all.

The free-cam

Every spawn needs two positions — where the player lands, and where the preview camera sits — and both are miserable to guess by hand. Press Place with free-cam on any spawn and fly to the spot instead:

KeyAction
W A S DFly
Q / EUp / down
Shift / CtrlFaster / slower
GDrop the spawn point here, snapped to the ground
CSet the preview camera to this exact view
XCapture the tile image from this view
EnterBack to the editor

A live coordinate readout sits in the corner while you fly, and your character is put back exactly where they were standing when you exit.

Capturing tile images

X screenshots the current view, downscales it, and saves it into html/images/ under a filename derived from the spawn's name. This needs screenshot-basic running — the same optional resource the menu backgrounds use. Turn the whole feature off with Config.Editor.AllowImageCapture = false.

A freshly captured image cannot be served from disk until the resource restarts, because FiveM expands a manifest's file list once at start. Until then the picture travels inline with the spawn data so players see it immediately, and the resource drops the inline copy by itself on the next start once the file is being served properly. You do not have to do anything.

Access rules and per-spawn actions

The full access rule set is editable per spawn as plain comma-separated fields, so you can gate a spawn behind a job, a gang, an item or a licence without writing Lua. Teleport & test drops you on the spawn point to check it before you commit.

Settings tab

With Config.Editor.AllowSettings on, the editor also exposes the runtime settings — menu theme and search, feature toggles, favorites, on-spawn stats and the last-location rules. Saving applies them on the server and pushes them to every connected player straight away.

Framework, locale, debug and command settings are deliberately not editable in-game. They are read once when the resource starts, so changing them at runtime would tell you something untrue. Those stay in config.lua.

Editor settings

Config.Editor = {
    Enabled = true,             -- Master switch for the editor
    Command = "spawnedit",      -- Command that opens it
    Permission = "god",         -- "god", "admin", "mod" or "all"
    AllowSettings = true,       -- Also allow editing settings, not just spawns
    AllowImageCapture = true,   -- Allow screenshotting tile images
    MaxSpawns = 200,            -- Safety cap on how many spawns can be saved
    ImageWidth = 640,           -- Captured images are downscaled to this width
    ImageQuality = 0.82,        -- JPEG quality for captured images (0.1 - 1.0)
    MaxImageSizeKB = 512        -- Reject a captured image larger than this
}

Do not set Permission = "all". That hands every player on your server the ability to rewrite your spawn configuration.

Everything the editor sends is re-validated on the server before it is stored — coordinates, labels, job lists, access rules, settings and images alike. If a second admin saves while you have the editor open, your save is refused rather than silently overwriting their work; reopen the editor to pick up their changes.

Spawn & job spawn config

Coordinates use the v4(x, y, z, heading) helper defined at the top of config.lua. cameraCoords is where the preview camera sits when a player hovers the tile; leave it out and the camera defaults to 30 m directly above the spawn.

General spawns

Shown to everyone, unless you add a restrict block.

Config.SpawnLocations = {
    {
        label = "Downtown Plaza",
        coords = v4(215.80, -810.30, 30.70, 338.70),
        image = "downtown_plaza.png",
        cameraCoords = v4(221.94, -821.05, 30.35, 338.70)
    },
}

Job spawns

Only shown to players whose job is in the jobs list. Always use the array form, even for one job.

Config.JobSpawns = {
    {
        jobs = { "police", "bcso", "lspd" },
        label = "Police HQ",
        coords = v4(635.01, 3.46, 82.74, 50.54),
        cameraCoords = v4(667.92, -27.50, 82.54, 50.54),
        image = "police_hq.png"
    },
}

By default the player's job label is prefixed to the tile title (Police — Police HQ). Turn that off with Config.UI.HideJobNameInSpawns = true.

Images

Images live in html/images/ and are named in the spawn's image field. A missing file falls back to default.png rather than showing a broken tile. Tiles render at roughly 200×120, so there is nothing to gain from very large source images — and every player downloads them on first join.

Access rules

Any spawn — general or job — can carry an optional restrict table. A player sees the spawn only if they pass every rule present. Rules are evaluated server-side, so a spawn a player cannot use is never sent to them.

{
    label = "VIP Lounge",
    coords = v4(x, y, z, h),
    image = "vip.png",
    restrict = {
        jobs       = { "police", "sheriff" }, -- job must be one of these
        minGrade   = 2,                       -- job grade must be >= this
        gangs      = { "ballas" },            -- gang must be one of these
        citizenids = { "ABC12345" },          -- citizenid must be one of these
        licenses   = { "weapon" },            -- must hold one of these licences
        items      = { "vip_pass" },          -- must carry one of these items
    }
}

Rules combine with AND; the lists inside each rule are OR. The example above means a police or sheriff of grade 2 or higher, who is in the Ballas, whose citizen ID is ABC12345, who holds a weapon licence and is carrying a VIP pass — which is probably nobody. Use one or two rules, not all six.

The jobs = { … } shorthand on a job spawn still works and is equivalent to restrict.jobs.

All six are editable in the in-game editor without writing Lua. See the ESX note for the two rules that do not apply there.

Settings reference

Everything below lives in config.lua. The groups marked editor can also be changed in-game on the editor's Settings tab.

General

SettingDefaultWhat it does
Config.DebugfalseVerbose client and server logging. Ships off; turn it on only while diagnosing something.
Config.Locale"en"Active language file in locales/.
Config.ValidateOnStarttrueCheck spawns and images at start and report problems.
Config.Framework"auto""auto", "qb" or "esx".

Menu — editor

SettingDefaultWhat it does
UI.Theme"dark""dark" or "light".
UI.showCancelButtonfalseLet a player back out of the normal spawn flow.
UI.HideJobNameInSpawnsfalseDrop the job label prefix from job spawn titles.
UI.EnableSearchtrueShow the search box.
UI.PreviewSettleTime250Milliseconds to let the camera settle before the background screenshot.

Features — editor

SettingDefaultWhat it does
Features.EnableHousingtrueShow owned properties (needs loaf_housing).
Features.UseIlleniumAppearancetrueLoad appearance via illenium-appearance.
Features.EnableDynamicBackgroundstrueLive screenshot behind the menu (needs screenshot-basic).

Favorites & recents — editor

SettingDefaultWhat it does
Favorites.EnabledtrueLet players star spawns and see a Recent row.
Favorites.MaxRecents4How many recent spawns to remember.

On spawn — editor

Applied server-side from config, never from anything the client sends.

SettingDefaultWhat it does
Spawn.SetStatstrueSet hunger and thirst on spawn.
Spawn.Food / Spawn.Water100The values used when SetStats is on.
Spawn.SetHealthtrueRestore health on spawn.
Spawn.SetArmor / ArmorValuefalse / 0Give armor on spawn.
Spawn.Invincible.EnabledtrueBrief invincibility so a player cannot die the instant they load in.
Spawn.Invincible.Duration1000How long, in milliseconds.

Last location — editor

SettingDefaultWhat it does
LastLocation.EnabledtrueOffer the player's last saved position.
LastLocation.SuppressWhenDeadtrueHide it while they are dead or in laststand. QB only.
LastLocation.TrackCombatfalseWatch for combat so the option can be withheld afterwards.
LastLocation.CombatCooldownSeconds300How long to withhold it after combat. Needs TrackCombat.

TrackCombat is the setting that stops players from logging out in a fight and dropping straight back onto the same spot. It is off by default because it runs a lightweight client-side check; turn it on if combat logging is a problem on your server.

Commands

Both are permission-gated, and both check permission on the server.

CommandDoesDefault permission
/sals_testspawnOpens the spawn selector on demand. Name, permission and cancel-button behaviour are set in Config.Command. god
/spawneditOpens the spawn editor. Set in Config.Editor.god

Permission levels are "god", "admin", "mod" and "all". On QB these map to the framework's own permission system; on ESX they map to ACE principals. Set enabled / Enabled to false to remove either command entirely.

Integration

Opening the selector from another resource

The normal spawn flow — multichar, character creation, respawn — is driven by one client event:

-- Server-side, for a specific player:
TriggerClientEvent('sals_kewlspawnselector:openSelector', playerId)

-- Client-side, e.g. from your own multichar handler:
TriggerEvent('sals_kewlspawnselector:openSelector')

When a player finishes spawning, the resource fires sals_kewlspawnselector:spawned on the client for your scripts to listen for.

Customisation files

Two files exist to be edited and are kept separate from the rest so they survive updates:

client_customize.luaAppearance loading and the housing lookup. Replace CustomFunctions.GetPlayerHouses to support a housing resource other than loaf_housing — it returns a list of { propertyId, label, coords, image, cameraCoords }.
server_customize.luaCanOpenMenu(src) — return false to block the menu for a player. OnPlayerSpawned(src, key) — runs after a spawn is committed.

Translations

No user-facing text is hardcoded. locales/en.lua is the baseline; copy it to locales/<code>.lua, translate the values, and set Config.Locale. Missing keys fall back to English, so a partial translation is safe to ship.

Troubleshooting

SymptomWhat to check
Edits to config.lua spawns do nothing The in-game editor has saved, so data/overrides.json owns the spawn lists. The server console says so at start. See Where spawns come from.
Players fall through the map The z in that spawn's coordinates is below the floor. Stand on the spot and use Use my position in the editor, or G in the free-cam, which snaps to ground level.
Black screen, no menu Check the server console for a config validation failure, and that ensure sals_kewlspawnselector comes after your framework in server.cfg. If another resource also handles spawning, they will fight — qb-spawn in particular must not be running.
Job spawns do not appear Job names in jobs = { … } must match your framework's internal job names exactly, not the display labels. Turn on Config.Debug to see the job the server read for that player.
Properties do not appear loaf_housing must be started and Config.Features.EnableHousing on. Another housing resource needs CustomFunctions.GetPlayerHouses adapted — see Integration.
Tiles show the default image The named file is not in html/images/. Start-up validation names every spawn this affects. Filenames are case-sensitive on Linux servers.
No live background behind the menu screenshot-basic is not running, or Config.Features.EnableDynamicBackgrounds is off.
/spawnedit does nothing Permission is checked server-side — you are not in the group named by Config.Editor.Permission. The editor also refuses to open while the normal spawn menu is up, since the two would fight over the camera.
A captured image will not save The resource folder must be writable by the server process. The editor reports the failure on screen and the server console names the file it could not write.

When something is not behaving, Config.Debug = true logs the spawn flow on both sides. Turn it back off afterwards — it is noisy.

Support

Support, release news and coupon codes are on Discord. Purchases are handled by Tebex, who own the checkout, billing support and refunds.

The resource ships its own copy of this manual at docs/help.html inside the download, including the full changelog.