-- d4rk_tablet — Bridge Server -- Token holen (Shared-Secret), Dienst + Positionen an /bridge/* pushen, Dispatch-Export. local onDuty = {} -- [src] = { citizenid, name, callsign, department } --- HTTP POST an das Backend (mit Shared-Secret-Header). local function post(path, body, cb) PerformHttpRequest(Config.BackendUrl .. path, function(status, res) if cb then cb(status, res) end end, 'POST', json.encode(body), { ['Content-Type'] = 'application/json', ['x-bridge-secret'] = Config.Secret, }) end --- Baut den Auth-Body aus den QBox-Charakterdaten. local function authBody(player) local pd = player.PlayerData local job = pd.job or {} local grade = job.grade or {} return { license = pd.license, citizenid = pd.citizenid, name = ('%s %s'):format(pd.charinfo.firstname, pd.charinfo.lastname), job = job.name, gradeLevel = grade.level or 0, callsign = pd.metadata and pd.metadata.callsign or nil, } end -- ── Token holen (Client öffnet Tablet) ── lib.callback.register('d4rk_tablet:getAuth', function(source) local player = exports.qbx_core:GetPlayer(source) if not player then return nil end if not Config.JobDepartments[player.PlayerData.job.name] then return nil end -- kein Behörden-Job local p = promise.new() post('/auth/fivem', authBody(player), function(status, res) if status == 200 and res then local ok, data = pcall(json.decode, res) if ok and data and data.token then p:resolve({ token = data.token, user = data.user }) return end end p:resolve(nil) end) return Citizen.Await(p) end) -- ── Dienststatus ── local function setDuty(src, isOn) local player = exports.qbx_core:GetPlayer(src) if not player then return end local jobName = player.PlayerData.job.name local department = Config.JobDepartments[jobName] if not department then return end if isOn then onDuty[src] = { citizenid = player.PlayerData.citizenid, name = ('%s %s'):format(player.PlayerData.charinfo.firstname, player.PlayerData.charinfo.lastname), callsign = player.PlayerData.metadata and player.PlayerData.metadata.callsign or nil, department = department, } end local o = onDuty[src] or { citizenid = player.PlayerData.citizenid, name = ('%s %s'):format(player.PlayerData.charinfo.firstname, player.PlayerData.charinfo.lastname), department = department, } post('/bridge/officer/duty', { citizenid = o.citizenid, name = o.name, callsign = o.callsign, department = o.department, onDuty = isOn, }) if not isOn then onDuty[src] = nil end end -- QBox-Dienstwechsel (best effort) + Fallback-Command RegisterNetEvent('QBCore:Server:SetDuty', function(src, isOn) setDuty(src, isOn == true) end) lib.addCommand('mdtduty', { help = 'MDT: Dienststatus umschalten' }, function(source) setDuty(source, onDuty[source] == nil) end) AddEventHandler('playerDropped', function() local src = source if onDuty[src] then setDuty(src, false) end end) -- ── Server-seitiger Positions-Push (vertraut Client nicht) ── CreateThread(function() while true do Wait(Config.PositionInterval) for src, info in pairs(onDuty) do local ped = GetPlayerPed(src) if ped and ped ~= 0 then local c = GetEntityCoords(ped) post('/bridge/officer/position', { citizenid = info.citizenid, coords = { x = c.x, y = c.y, z = c.z }, }) end end end end) -- ── Positionsziel an einen Officer senden (von der Leitstelle via Web → Socket → hier) ── RegisterNetEvent('d4rk_tablet:relayWaypoint', function() end) -- Platzhalter M8 (Socket→Bridge) -- ── Dispatch-Export für andere Resourcen ── -- exports.d4rk_tablet:createDispatch({ code='10-90', title='Banküberfall', department='police', priority='high', location='...', coords={x=,y=,z=} }) exports('createDispatch', function(data) post('/bridge/dispatch', data) end)