Skip to content

Your first BS19 resource

This guide builds a small resource from nothing: a /checkin command that gives a survivor one water bottle, at most once an hour. It takes about 15 minutes. You need a running BS19 server, access to its files and the txAdmin console, and a text editor (VS Code works well).

When it works, Writing a resource on top of bs_core shows the next steps: client code, callbacks and the traps to avoid.

In your server’s resources folder, create a folder called [local] (the brackets matter, they make it a category, not a resource) and inside it a folder called bs_checkin. Keep your own resources in [local] so framework updates never overwrite them.

resources/[local]/bs_checkin/
├── fxmanifest.lua
├── config.lua
└── server.lua

The folder name is the resource name. Start it with bs_ so it can’t clash with another script.

Every FiveM resource needs this file. It tells the server which files to load and on which side.

fx_version 'cerulean'
game 'gta5'
lua54 'yes'
name 'bs_checkin'
description 'My first BS19 resource'
shared_scripts {
'@bs_core/shared/sh_bridge.lua', -- gives you BSB (commands, callbacks)
'config.lua',
}
server_scripts { 'server.lua' }
dependencies { 'bs_core', 'bs_inventory' }

The @bs_core/shared/sh_bridge.lua line loads the BS19 bridge into your resource. Without it, BSB does not exist and the server file fails.

Put every value a server owner might want to change in one table, so nobody has to edit your code.

Checkin = {
item = 'water_bottle', -- any item name from bs_inventory's item list
amount = 1,
cooldown = 3600, -- seconds between two check-ins (1 hour)
}
local lastCheckin = {} -- [charId] = os.time() of the last check-in
local function notify(src, kind, message)
TriggerClientEvent('bs:ui:notify', src, { type = kind, message = message })
end
BSB.RegisterCommand('checkin', nil, 'Daily survivor check-in', {}, function(src)
if src == 0 then return print('Run /checkin in game, not in the console.') end
local p = exports.bs_core:GetPlayerSummary(src)
if not p then return notify(src, 'error', 'Pick a character first.') end
local now = os.time()
local last = lastCheckin[p.charId]
if last and now - last < Checkin.cooldown then
local minutes = math.ceil((Checkin.cooldown - (now - last)) / 60)
return notify(src, 'error', ('Come back in %d min.'):format(minutes))
end
local ok, reason = exports.bs_inventory:GiveItem(src, Checkin.item, Checkin.amount)
if not ok then return notify(src, 'error', 'No room: ' .. tostring(reason)) end
lastCheckin[p.charId] = now
notify(src, 'success', ('Welcome back, %s. Here is some water.'):format(p.firstName))
end)

What it does, line by line:

  • BSB.RegisterCommand creates the chat command. The nil means everyone can use it; put an ACE like 'bs.admin' there to limit it to staff.
  • GetPlayerSummary returns nil while the player is still on the character screen, so check it before anything else.
  • The cooldown is stored per character (charId), not per player, so a second character gets its own check-in. It resets when the resource restarts, which is fine for a first resource.
  • Items always go through exports.bs_inventory:GiveItem. It returns false and a reason when the inventory is full. Never write to the database yourself.

Add this line at the end of server.cfg, after the BS19 resources:

ensure bs_checkin

Then, in the txAdmin live console (no server restart needed):

refresh
ensure bs_checkin

refresh makes the server notice the new folder. The console should print Started resource bs_checkin. After you edit a file later, ensure bs_checkin alone reloads it.

  1. Join the server and pick a character.
  2. Press T, type /checkin and press Enter. You get a green notification and a water bottle in your inventory (I).
  3. Type /checkin again. You get a red “Come back in 60 min.” message.
What you seeWhyFix
Couldn't find resource bs_checkinThe server hasn’t seen the folder, or the name differsRun refresh, check the folder is named exactly bs_checkin
attempt to index a nil value (global 'BSB')The bridge line is missingCheck the @bs_core/shared/sh_bridge.lua line in fxmanifest.lua
No such export GetPlayerSummarybs_core isn’t started yetKeep ensure bs_checkin below the BS19 resources in server.cfg
/checkin does nothing, no errorYou’re still on the character screen, or the command was never registeredPick a character, then look at the console for a red [bs_checkin] line
“No room: …”Your inventory is full or too heavyDrop something and try again

Any red error in the console also names the file and line. Fix it, run ensure bs_checkin again, and retry.

  • Change item to bandage in config.lua and run ensure bs_checkin. No code change needed.
  • Give some cash as well: exports.bs_core:AddMoney(src, 'cash', 25, 'checkin').
  • Give XP: exports.bs_core:AddXP(src, 10, 'checkin').
  • Browse the calls you can use in Exports & events.