-- JustRP — Server-side core -- All DB operations go through the internal Python API on :8787 local API_BASE = "http://127.0.0.1:8787" -- Должен совпадать с JUSTRP_API_SECRET у Python-API. Задаётся в server.cfg: -- set justrp_api_key "ваш-ключ" local API_KEY = GetConvar("justrp_api_key", "change-me") -- Per-player session state local Sessions = {} -- ─── HTTP helper ──────────────────────────────────────────────────────────── local function apiRequest(method, path, data, cb) PerformHttpRequest( API_BASE .. path, function(status, body, _headers) local ok, result = pcall(json.decode, body or "{}") if ok then cb(status, result) else cb(status, { success = false, error = "parse error" }) end end, method, data and json.encode(data) or "", { ["Content-Type"] = "application/json", ["X-API-Key"] = API_KEY, } ) end -- ─── Player connecting ─────────────────────────────────────────────────────── AddEventHandler("playerConnecting", function(name, setKickReason, deferrals) local src = source local license = GetPlayerIdentifierByType(src, "license") or GetPlayerIdentifierByType(src, "license2") or "license:" .. tostring(src) deferrals.defer() Wait(0) deferrals.update("Checking account…") apiRequest("GET", "/account?license=" .. license, nil, function(status, res) if status == 200 and res.success then if res.account.banned == 1 then deferrals.done("You are banned from JustRP.\nReason: " .. (res.account.ban_reason or "No reason given")) else deferrals.done() end else -- No account yet — let them through, they'll register in-game deferrals.done() end end) end) -- ─── Client ready → start session ─────────────────────────────────────────── RegisterNetEvent("justrp:clientReady") AddEventHandler("justrp:clientReady", function() local src = source local license = GetPlayerIdentifierByType(src, "license") or GetPlayerIdentifierByType(src, "license2") or "license:" .. tostring(src) Sessions[src] = { license = license, accountId = nil, charId = nil } TriggerClientEvent("justrp:startSession", src) end) -- ─── Auth events ──────────────────────────────────────────────────────────── RegisterNetEvent("justrp:auth:register") AddEventHandler("justrp:auth:register", function(username, password) local src = source local ses = Sessions[src] if not ses then return end apiRequest("POST", "/auth/register", { license = ses.license, username = username, password = password, }, function(status, res) if res.success then ses.accountId = res.account_id TriggerClientEvent("justrp:auth:ok", src, res.account_id, res.username) else TriggerClientEvent("justrp:auth:fail", src, res.error or "Unknown error") end end) end) RegisterNetEvent("justrp:auth:login") AddEventHandler("justrp:auth:login", function(username, password) local src = source local ses = Sessions[src] if not ses then return end apiRequest("POST", "/auth/login", { license = ses.license, username = username, password = password, }, function(status, res) if res.success then ses.accountId = res.account_id TriggerClientEvent("justrp:auth:ok", src, res.account_id, res.username) else TriggerClientEvent("justrp:auth:fail", src, res.error or "Unknown error") end end) end) -- ─── Character events ──────────────────────────────────────────────────────── RegisterNetEvent("justrp:chars:load") AddEventHandler("justrp:chars:load", function() local src = source local ses = Sessions[src] if not ses or not ses.accountId then TriggerClientEvent("justrp:chars:list", src, {}) return end apiRequest("GET", "/characters?account_id=" .. ses.accountId, nil, function(status, res) if res.success then TriggerClientEvent("justrp:chars:list", src, res.characters or {}) else TriggerClientEvent("justrp:chars:list", src, {}) end end) end) RegisterNetEvent("justrp:char:create") AddEventHandler("justrp:char:create", function(data) local src = source local ses = Sessions[src] if not ses or not ses.accountId then return end data.account_id = ses.accountId apiRequest("POST", "/character/create", data, function(status, res) if res.success then ses.charId = res.character_id TriggerClientEvent("justrp:char:created", src, res.character_id) else TriggerClientEvent("justrp:char:createFail", src, res.error or "Unknown error") end end) end) RegisterNetEvent("justrp:char:select") AddEventHandler("justrp:char:select", function(charId) local src = source local ses = Sessions[src] if not ses or not ses.accountId then return end apiRequest("GET", "/character?id=" .. tostring(charId), nil, function(status, res) if res.success and res.character then local ch = res.character if ch.account_id ~= ses.accountId then return -- character doesn't belong to this account end ses.charId = charId TriggerClientEvent("justrp:char:loaded", src, ch) end end) end) -- ─── Spawn ─────────────────────────────────────────────────────────────────── RegisterNetEvent("justrp:spawn:request") AddEventHandler("justrp:spawn:request", function(spawnKey) local src = source local ses = Sessions[src] if not ses or not ses.charId then return end local spawns = { legion = { x = -166.7, y = -928.9, z = 31.4, h = 120.0 }, vespucci = { x = -1380.0, y = -1520.0, z = 4.9, h = 75.0 }, sandy = { x = 1843.4, y = 3683.0, z = 34.3, h = 200.0 }, paleto = { x = -165.8, y = 6330.0, z = 31.5, h = 270.0 }, airport = { x = -1037.0, y = -2738.0, z = 20.0, h = 330.0 }, } local pos = spawns[spawnKey] or spawns["legion"] TriggerClientEvent("justrp:spawn:go", src, pos) end) -- ─── Auto-save position every 60s ──────────────────────────────────────────── RegisterNetEvent("justrp:savePosition") AddEventHandler("justrp:savePosition", function(x, y, z, h) local src = source local ses = Sessions[src] if not ses or not ses.charId then return end apiRequest("POST", "/character/save", { character_id = ses.charId, last_x = x, last_y = y, last_z = z, last_heading = h, }, function() end) end) -- ─── Disconnect ────────────────────────────────────────────────────────────── AddEventHandler("playerDropped", function() local src = source Sessions[src] = nil end) print("[JustRP] Server core loaded.")