QBCore에서 서버 관리 시간을 절약해 준 두 개의 Admin Scripts

발행: (2026년 3월 19일 AM 02:25 GMT+9)
6 분 소요
원문: Dev.to

Source: Dev.to

라이브 RP 서버 관리의 문제점

QBCore RP 서버를 운영한다는 것은 두 가지 반복적인 골칫거리를 다루는 것을 의미합니다:

  • 플레이어가 잘못된 직업에 갇히거나 세션 중에 빠르게 역할을 할당해야 할 때—데이터베이스나 기존 관리자 메뉴를 통해 수행하면 느립니다.
  • 비활성 플레이어가 몇 달 동안 데이터베이스에 쌓입니다. 차량, 캐릭터, 그리고 다시는 사용되지 않을 데이터가 있는 유령 같은 존재들.

두 가지 문제를 해결하기 위해 두 개의 스크립트를 만들었습니다: lokat_adminjob은 실시간 직업 관리를, lokat_cleanup은 데이터베이스 정리를 담당합니다.

lokat_adminjob — UI 패널을 통한 작업 할당

권한 시스템

스크립트는 두 단계로 권한을 확인합니다 — 먼저 txAdmin ACE를 확인하고, 그 다음 QBCore의 기본 admin/god 플래그를 확인합니다. 이는 txAdmin이 관리하는 서버와 기본 vanilla QBCore 설정 모두에서 작동합니다.

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

권한 검사는 항상 서버 측에서 실행되며, 클라이언트는 요청만 보냅니다. 서버 이벤트를 호출하려는 무단 시도는 차단됩니다.

ps‑multijob 통합

플레이어가 ps‑multijob에서 사이드 잡과 동일한 직업을 가지고 있고, 이를 메인 잡으로 지정하면 충돌이 발생합니다. 스크립트는 이를 자동으로 처리합니다 — 새로운 메인 잡을 설정하기 전에 일치하는 사이드 잡 항목을 제거합니다.

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

직업을 완전히 제거할 때(실업 상태로 설정) 모든 사이드 잡도 함께 삭제됩니다 — 한 번의 깔끔한 작업입니다.

패널에 표시되는 내용

관리자가 패널을 열면 서버가 실시간 스냅샷을 전송합니다:

  • 모든 사용 가능한 직업과 해당 등급 레벨.
  • 현재 온라인인 모든 플레이어와 그들의 현재 직업.

관리자는 플레이어를 선택하고, 직업과 등급을 고른 뒤 제출합니다. 변경 사항은 즉시 적용되며, 알림이 관리자와 대상 플레이어 모두에게 전송됩니다.

Source:

lokat_cleanup — 비활성 플레이어 정리 도구

작동 방식

명령어로 UI를 열고 비활성 임계값을 설정합니다(기본값: 60 일). 스크립트는 모든 캐릭터의 last_updated 타임스탬프가 임계값보다 오래된 계정을 데이터베이스에서 조회합니다.

결과는 라이선스별로 그룹화되어(계정당 한 행) 다음과 같이 표시됩니다:

  • 계정에 연결된 캐릭터 이름
  • 마지막 활동 날짜
  • 보유 차량 수
  • 전체 캐릭터 수
-- 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)

안전 검사

계정을 삭제하기 전에 서버는 해당 라이선스의 어떤 캐릭터가 현재 온라인인지 확인합니다. 온라인 상태라면 삭제가 차단됩니다.

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

연관된 차량을 함께 삭제할지 여부도 선택할 수 있으며, 삭제마다 토글할 수 있습니다.

검색 및 페이지네이션

플레이어 데이터베이스가 큰 경우, UI는 캐릭터 이름 검색, 페이지네이션, 정렬(오래된 순 또는 최신 순)을 지원합니다.

설정 개요

두 스크립트 모두 간단한 설정 파일을 사용합니다.

lokat_adminjob

Config.AceName = 'your_ace_permission_name'
Config.OpenCommand = 'your_command_name'
Config.MultiJob = { Enable = true }

lokat_cleanup

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

왜 이것들이 존재하는가

QBCore의 대부분 관리 작업은 직접 데이터베이스에 접근하거나 속도를 위해 설계되지 않은 메뉴를 탐색해야 합니다. 이 두 스크립트는 제가 반복해서 수행한 특정 작업을 위해 맞춤 제작된 것으로, 일상적인 서버 관리에서 많은 마찰을 없애줍니다.

다음 편: Vol.5 — QBCore용 맞춤 자판기 시스템 구축.

0 조회
Back to Blog

관련 글

더 보기 »

Razorpay 결제 분할 라우트

Razorpay Route란 무엇인가요? Razorpay Route는 Razorpay에서 제공하는 기능으로, 들어오는 자금을 다양한 판매자, 벤더, 제3자에게 분배할 수 있게 해줍니다.