DEV Community

Tack k
Tack k

Posted on

Two Admin Scripts That Saved Me Hours of Server Management in QBCore

The problem with managing a live RP server

Running a QBCore RP server means dealing with two recurring headaches:

  1. Players get stuck in the wrong job, or you need to assign roles fast during a session — and doing it through the database or existing admin menus is slow.
  2. Inactive players accumulate in the database over months. Ghosts with vehicles, characters, and data that will never be used again.

I built two scripts to solve both: lokat_adminjob for real-time job management, and lokat_cleanup for database pruning.


lokat_adminjob — Job assignment from a UI panel

The idea is simple: open a panel with a command, pick a player from the online list, pick a job and grade, and apply it instantly. No database queries, no server restarts, no fumbling through existing admin menus.

Permission system

The script checks permissions in two layers — txAdmin ACE first, then QBCore's native admin/god flags. This means it works whether you're running a txAdmin-managed server or a vanilla QBCore setup.

local function hasAdmin(src)
    if IsPlayerAceAllowed(src, Config.AceName) then
        return true
    end
    if QBCore.Functions.HasPermission(src, 'admin')
    or QBCore.Functions.HasPermission(src, 'god') then
        return true
    end
    return false
end
Enter fullscreen mode Exit fullscreen mode

Permission checks always run server-side. The client never makes the decision — it just sends requests. If someone tries to call the server event directly without permission, they get blocked.

ps-multijob integration

This is the part that saves the most headaches. If a player has the same job as a side job in ps-multijob and you assign it as their main job, you get a conflict. The script handles this automatically — before setting a new main job, it removes any matching side job entry from ps-multijob.

-- Remove conflicting side job before assigning main job
PMJ_RemoveJobByName(target, jobName)
target.Functions.SetJob(jobName, grade)
Enter fullscreen mode Exit fullscreen mode

When removing a job entirely (setting to unemployed), it clears all side jobs too — one clean operation.

What the panel shows

When an admin opens the panel, the server sends a live snapshot: all available jobs with their grade levels, and all currently online players with their current job. The admin selects a player, selects a job and grade, and submits — the change applies immediately with notifications sent to both the admin and the target player.


lokat_cleanup — Inactive player pruning tool

Over time, inactive players pile up in the database. After years of server operation, you end up with hundreds of accounts that haven't logged in for months — each with characters, vehicles, and associated data.

lokat_cleanup is an admin UI that lets you find and delete these accounts safely.

How it works

Open the UI with a command, set the inactivity threshold (default: 60 days), and the script queries the database for accounts where all characters' last_updated timestamp is older than the threshold.

Results are grouped by license (one row per account, not per character) and show:

  • Character names linked to the account
  • Last active date
  • Number of vehicles owned
  • Total character count
-- Group by license, get the most recent activity across all characters
SELECT license FROM players
GROUP BY license
HAVING MAX(last_updated) <= (NOW() - INTERVAL ? DAY)
Enter fullscreen mode Exit fullscreen mode

Safety checks

Before deleting any account, the server checks whether any character on that license is currently online. If they are, the delete is blocked — no accidents.

for _, row in ipairs(rows) do
    local p = QBCore.Functions.GetPlayerByCitizenId(row.citizenid)
    if p then
        cb({ ok = false, error = 'player_online' })
        return
    end
end
Enter fullscreen mode Exit fullscreen mode

You can also choose whether to delete associated vehicles — toggled per deletion.

Search and pagination

With large player databases, listing everything at once isn't practical. The UI supports character name search and pagination. Results can be sorted oldest-first or newest-first.


Config overview

Both scripts use a simple config file. Key settings:

lokat_adminjob:

Config.AceName = 'your_ace_permission_name'
Config.OpenCommand = 'your_command_name'
Config.MultiJob = { Enable = true }
Enter fullscreen mode Exit fullscreen mode

lokat_cleanup:

Config.MinDaysInactiveDefault = 60  -- adjust to your needs
Config.PageSize = 50
Config.UseAcePermission = true
Config.AceName = 'your_ace_permission_name'
Enter fullscreen mode Exit fullscreen mode

Why these exist

Most admin tasks in QBCore require either database access or navigating menus that weren't designed for speed. These two scripts are purpose-built for the specific operations I was doing repeatedly — and they eliminated a lot of friction from day-to-day server management.

Next up: Vol.5 — Building a Custom Vending Machine System for QBCore.


Built with Claude Opus as my coding partner. I handle system design and edge case thinking — the AI handles implementation.

Questions about the implementation? Drop a comment.

Top comments (0)