first commit

This commit is contained in:
2026-07-16 09:35:32 +02:00
commit dd0746e2e6
179 changed files with 25679 additions and 0 deletions
+120
View File
@@ -0,0 +1,120 @@
-- 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)