From d97b4166882c1d90c63fa7bd8c20c1843e649b40 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 7 Aug 2025 23:58:44 +0200 Subject: [PATCH 1/2] update --- .../[Max]/Fx_autoupdate/client.lua | 6 + .../[Max]/Fx_autoupdate/config.lua | 35 +++ .../[Max]/Fx_autoupdate/fxmanifest.lua | 21 ++ .../[Developer]/[Max]/Fx_autoupdate/main.lua | 265 ++++++++++++++++++ 4 files changed, 327 insertions(+) create mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/client.lua create mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/config.lua create mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua create mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/main.lua diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/client.lua b/resources/[Developer]/[Max]/Fx_autoupdate/client.lua new file mode 100644 index 000000000..7638499cd --- /dev/null +++ b/resources/[Developer]/[Max]/Fx_autoupdate/client.lua @@ -0,0 +1,6 @@ +-- Client-seitige Funktionen (falls benötigt) +RegisterNetEvent('fx-updater:showUpdateNotification') +AddEventHandler('fx-updater:showUpdateNotification', function(message) + -- Hier könntest du eine schöne UI-Benachrichtigung anzeigen + TriggerEvent('chatMessage', '[FX-UPDATER]', {255, 165, 0}, message) +end) diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/config.lua b/resources/[Developer]/[Max]/Fx_autoupdate/config.lua new file mode 100644 index 000000000..78001b1c9 --- /dev/null +++ b/resources/[Developer]/[Max]/Fx_autoupdate/config.lua @@ -0,0 +1,35 @@ +Config = {} + +-- Update Einstellungen +Config.CheckInterval = 60 * 60 * 1000 -- Prüfe alle 60 Minuten (in ms) +Config.AutoUpdate = false -- Automatisches Update (false = nur benachrichtigen) +Config.RequiredArtifact = 18214 -- Gewünschte FX Version +Config.BackupEnabled = true -- Backup vor Update erstellen + +-- Berechtigungen +Config.AllowedGroups = { + 'god', + 'admin', + 'superadmin' +} + +-- Pfade (relativ zum Server-Root) +Config.ServerPath = './' -- Server Hauptordner +Config.BackupPath = './backups/' -- Backup Ordner + +-- Benachrichtigungen +Config.Notifications = { + updateAvailable = 'Neues FXServer Update verfügbar! Artifact: %s', + updateStarted = 'FXServer Update wird gestartet...', + updateCompleted = 'FXServer Update abgeschlossen! Server wird neu gestartet.', + updateFailed = 'FXServer Update fehlgeschlagen: %s', + noPermission = 'Du hast keine Berechtigung für diesen Befehl!', + currentVersion = 'Aktuelle FXServer Version: %s' +} + +-- Discord Webhook (optional) +Config.DiscordWebhook = { + enabled = false, + url = '', -- Deine Discord Webhook URL + botName = 'FXServer Updater' +} diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua b/resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua new file mode 100644 index 000000000..4042c9a9f --- /dev/null +++ b/resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua @@ -0,0 +1,21 @@ +fx_version 'cerulean' +game 'gta5' + +author 'Duck' +description 'FXServer Auto-Update' +version '1.0.0' + +shared_scripts { + 'config.lua' +} + +server_scripts { + 'main.lua' +} + +client_scripts { + 'client.lua' +} + +-- Nur Admins können das Script verwenden +server_only 'yes' diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/main.lua b/resources/[Developer]/[Max]/Fx_autoupdate/main.lua new file mode 100644 index 000000000..945c19a8d --- /dev/null +++ b/resources/[Developer]/[Max]/Fx_autoupdate/main.lua @@ -0,0 +1,265 @@ +local QBCore = exports['qb-core']:GetCoreObject() +local currentArtifact = GetConvar('version', 'unknown') +local updateInProgress = false + +-- Hilfsfunktionen +local function hasPermission(source) + local Player = QBCore.Functions.GetPlayer(source) + if not Player then return false end + + for _, group in pairs(Config.AllowedGroups) do + if QBCore.Functions.HasPermission(source, group) then + return true + end + end + return false +end + +local function sendDiscordLog(message) + if not Config.DiscordWebhook.enabled then return end + + PerformHttpRequest(Config.DiscordWebhook.url, function(err, text, headers) end, 'POST', json.encode({ + username = Config.DiscordWebhook.botName, + content = message + }), { ['Content-Type'] = 'application/json' }) +end + +local function notifyAdmins(message) + local players = QBCore.Functions.GetPlayers() + for _, playerId in pairs(players) do + if hasPermission(playerId) then + TriggerClientEvent('QBCore:Notify', playerId, message, 'primary', 10000) + end + end +end + +local function getCurrentArtifact() + -- Versuche aktuelle Version aus verschiedenen Quellen zu ermitteln + local version = GetConvar('version', '') + if version and version ~= '' then + local artifact = string.match(version, 'v1%.0%.0%.(%d+)') + if artifact then + return tonumber(artifact) + end + end + return nil +end + +local function checkForUpdates() + if updateInProgress then return end + + print('[FX-Updater] Prüfe auf Updates...') + + PerformHttpRequest('https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/', function(errorCode, resultData, resultHeaders) + if errorCode == 200 then + -- Parse die neueste Artifact-Nummer aus der HTML-Antwort + local latestArtifact = nil + for artifact in string.gmatch(resultData, '(%d+)%-[a-f0-9]+/') do + local num = tonumber(artifact) + if not latestArtifact or num > latestArtifact then + latestArtifact = num + end + end + + if latestArtifact and latestArtifact >= Config.RequiredArtifact then + local currentArt = getCurrentArtifact() + if not currentArt or latestArtifact > currentArt then + local message = string.format(Config.Notifications.updateAvailable, latestArtifact) + print('[FX-Updater] ' .. message) + notifyAdmins(message) + sendDiscordLog('🔄 ' .. message) + + if Config.AutoUpdate then + Citizen.SetTimeout(5000, function() + performUpdate(latestArtifact) + end) + end + end + end + else + print('[FX-Updater] Fehler beim Prüfen auf Updates: ' .. errorCode) + end + end, 'GET', '', {}) +end + +local function createBackup() + if not Config.BackupEnabled then return true end + + local timestamp = os.date('%Y%m%d_%H%M%S') + local backupDir = Config.BackupPath .. 'backup_' .. timestamp + + -- Erstelle Backup-Verzeichnis + os.execute('mkdir -p "' .. backupDir .. '"') + + -- Sichere wichtige Dateien + os.execute('cp server.cfg "' .. backupDir .. '/"') + os.execute('cp -r resources "' .. backupDir .. '/"') + os.execute('cp -r server-data "' .. backupDir .. '/" 2>/dev/null || true') + + print('[FX-Updater] Backup erstellt: ' .. backupDir) + return true +end + +function performUpdate(targetArtifact) + if updateInProgress then return end + updateInProgress = true + + print('[FX-Updater] Starte Update auf Artifact ' .. targetArtifact) + notifyAdmins(Config.Notifications.updateStarted) + sendDiscordLog('🔄 Update gestartet auf Artifact ' .. targetArtifact) + + -- Warnung an alle Spieler + TriggerClientEvent('chatMessage', -1, '[SERVER]', {255, 165, 0}, 'Server wird in 30 Sekunden für ein Update neu gestartet!') + + Citizen.SetTimeout(30000, function() + -- Backup erstellen + if not createBackup() then + print('[FX-Updater] Backup fehlgeschlagen!') + updateInProgress = false + return + end + + -- Download-URL erstellen + local downloadUrl = string.format( + 'https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/%d-*/fx.tar.xz', + targetArtifact + ) + + -- Update-Script erstellen und ausführen + local updateScript = [[ +#!/bin/bash +echo "FXServer Update gestartet..." + +# Download neue Version +wget -O fx-new.tar.xz "]] .. downloadUrl .. [[" + +if [ $? -eq 0 ]; then + # Entpacken + mkdir -p temp-update + cd temp-update + tar -xf ../fx-new.tar.xz + cd .. + + # Installation + cp temp-update/run.sh ./ + cp -r temp-update/alpine ./ + chmod +x run.sh + chmod +x alpine/opt/cfx-server/FXServer + + # Aufräumen + rm -rf temp-update fx-new.tar.xz + + echo "Update abgeschlossen, starte Server..." + # Server neu starten + ./run.sh +exec server.cfg & +else + echo "Download fehlgeschlagen!" + exit 1 +fi +]] + + -- Script in Datei schreiben + local file = io.open('update_fx.sh', 'w') + if file then + file:write(updateScript) + file:close() + + -- Script ausführbar machen und ausführen + os.execute('chmod +x update_fx.sh') + + -- Server beenden und Update starten + print('[FX-Updater] Server wird beendet für Update...') + notifyAdmins(Config.Notifications.updateCompleted) + sendDiscordLog('✅ Update wird durchgeführt, Server startet neu...') + + Citizen.SetTimeout(2000, function() + os.execute('./update_fx.sh') + os.exit() -- Server beenden + end) + else + print('[FX-Updater] Konnte Update-Script nicht erstellen!') + updateInProgress = false + end + end) +end + +-- Events +RegisterNetEvent('fx-updater:checkUpdate', function() + local src = source + if not hasPermission(src) then + TriggerClientEvent('QBCore:Notify', src, Config.Notifications.noPermission, 'error') + return + end + + checkForUpdates() +end) + +RegisterNetEvent('fx-updater:forceUpdate', function(targetArtifact) + local src = source + if not hasPermission(src) then + TriggerClientEvent('QBCore:Notify', src, Config.Notifications.noPermission, 'error') + return + end + + targetArtifact = targetArtifact or Config.RequiredArtifact + performUpdate(targetArtifact) +end) + +RegisterNetEvent('fx-updater:getVersion', function() + local src = source + if not hasPermission(src) then + TriggerClientEvent('QBCore:Notify', src, Config.Notifications.noPermission, 'error') + return + end + + local current = getCurrentArtifact() or 'Unbekannt' + local message = string.format(Config.Notifications.currentVersion, current) + TriggerClientEvent('QBCore:Notify', src, message, 'primary') +end) + +-- Commands +QBCore.Commands.Add('fxupdate', 'Prüfe auf FXServer Updates', {}, false, function(source, args) + if not hasPermission(source) then + TriggerClientEvent('QBCore:Notify', source, Config.Notifications.noPermission, 'error') + return + end + + TriggerEvent('fx-updater:checkUpdate') +end, Config.AllowedGroups) + +QBCore.Commands.Add('fxforceupdate', 'Erzwinge FXServer Update', {{name = 'artifact', help = 'Artifact Nummer (optional)'}}, false, function(source, args) + if not hasPermission(source) then + TriggerClientEvent('QBCore:Notify', source, Config.Notifications.noPermission, 'error') + return + end + + local targetArtifact = args[1] and tonumber(args[1]) or Config.RequiredArtifact + TriggerEvent('fx-updater:forceUpdate', targetArtifact) +end, Config.AllowedGroups) + +QBCore.Commands.Add('fxversion', 'Zeige aktuelle FXServer Version', {}, false, function(source, args) + if not hasPermission(source) then + TriggerClientEvent('QBCore:Notify', source, Config.Notifications.noPermission, 'error') + return + end + + TriggerEvent('fx-updater:getVersion') +end, Config.AllowedGroups) + +-- Auto-Check Timer +if Config.CheckInterval > 0 then + Citizen.CreateThread(function() + while true do + Citizen.Wait(Config.CheckInterval) + checkForUpdates() + end + end) +end + +-- Beim Server-Start prüfen +Citizen.CreateThread(function() + Citizen.Wait(10000) -- Warte 10 Sekunden nach Server-Start + checkForUpdates() +end) + +print('[FX-Updater] Resource gestartet!') From 93953fd951169d80f9f90c747eb52b9a4ab32cdf Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 8 Aug 2025 02:06:22 +0200 Subject: [PATCH 2/2] revert d97b4166882c1d90c63fa7bd8c20c1843e649b40 revert update --- .../[Max]/Fx_autoupdate/client.lua | 6 - .../[Max]/Fx_autoupdate/config.lua | 35 --- .../[Max]/Fx_autoupdate/fxmanifest.lua | 21 -- .../[Developer]/[Max]/Fx_autoupdate/main.lua | 265 ------------------ 4 files changed, 327 deletions(-) delete mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/client.lua delete mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/config.lua delete mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua delete mode 100644 resources/[Developer]/[Max]/Fx_autoupdate/main.lua diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/client.lua b/resources/[Developer]/[Max]/Fx_autoupdate/client.lua deleted file mode 100644 index 7638499cd..000000000 --- a/resources/[Developer]/[Max]/Fx_autoupdate/client.lua +++ /dev/null @@ -1,6 +0,0 @@ --- Client-seitige Funktionen (falls benötigt) -RegisterNetEvent('fx-updater:showUpdateNotification') -AddEventHandler('fx-updater:showUpdateNotification', function(message) - -- Hier könntest du eine schöne UI-Benachrichtigung anzeigen - TriggerEvent('chatMessage', '[FX-UPDATER]', {255, 165, 0}, message) -end) diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/config.lua b/resources/[Developer]/[Max]/Fx_autoupdate/config.lua deleted file mode 100644 index 78001b1c9..000000000 --- a/resources/[Developer]/[Max]/Fx_autoupdate/config.lua +++ /dev/null @@ -1,35 +0,0 @@ -Config = {} - --- Update Einstellungen -Config.CheckInterval = 60 * 60 * 1000 -- Prüfe alle 60 Minuten (in ms) -Config.AutoUpdate = false -- Automatisches Update (false = nur benachrichtigen) -Config.RequiredArtifact = 18214 -- Gewünschte FX Version -Config.BackupEnabled = true -- Backup vor Update erstellen - --- Berechtigungen -Config.AllowedGroups = { - 'god', - 'admin', - 'superadmin' -} - --- Pfade (relativ zum Server-Root) -Config.ServerPath = './' -- Server Hauptordner -Config.BackupPath = './backups/' -- Backup Ordner - --- Benachrichtigungen -Config.Notifications = { - updateAvailable = 'Neues FXServer Update verfügbar! Artifact: %s', - updateStarted = 'FXServer Update wird gestartet...', - updateCompleted = 'FXServer Update abgeschlossen! Server wird neu gestartet.', - updateFailed = 'FXServer Update fehlgeschlagen: %s', - noPermission = 'Du hast keine Berechtigung für diesen Befehl!', - currentVersion = 'Aktuelle FXServer Version: %s' -} - --- Discord Webhook (optional) -Config.DiscordWebhook = { - enabled = false, - url = '', -- Deine Discord Webhook URL - botName = 'FXServer Updater' -} diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua b/resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua deleted file mode 100644 index 4042c9a9f..000000000 --- a/resources/[Developer]/[Max]/Fx_autoupdate/fxmanifest.lua +++ /dev/null @@ -1,21 +0,0 @@ -fx_version 'cerulean' -game 'gta5' - -author 'Duck' -description 'FXServer Auto-Update' -version '1.0.0' - -shared_scripts { - 'config.lua' -} - -server_scripts { - 'main.lua' -} - -client_scripts { - 'client.lua' -} - --- Nur Admins können das Script verwenden -server_only 'yes' diff --git a/resources/[Developer]/[Max]/Fx_autoupdate/main.lua b/resources/[Developer]/[Max]/Fx_autoupdate/main.lua deleted file mode 100644 index 945c19a8d..000000000 --- a/resources/[Developer]/[Max]/Fx_autoupdate/main.lua +++ /dev/null @@ -1,265 +0,0 @@ -local QBCore = exports['qb-core']:GetCoreObject() -local currentArtifact = GetConvar('version', 'unknown') -local updateInProgress = false - --- Hilfsfunktionen -local function hasPermission(source) - local Player = QBCore.Functions.GetPlayer(source) - if not Player then return false end - - for _, group in pairs(Config.AllowedGroups) do - if QBCore.Functions.HasPermission(source, group) then - return true - end - end - return false -end - -local function sendDiscordLog(message) - if not Config.DiscordWebhook.enabled then return end - - PerformHttpRequest(Config.DiscordWebhook.url, function(err, text, headers) end, 'POST', json.encode({ - username = Config.DiscordWebhook.botName, - content = message - }), { ['Content-Type'] = 'application/json' }) -end - -local function notifyAdmins(message) - local players = QBCore.Functions.GetPlayers() - for _, playerId in pairs(players) do - if hasPermission(playerId) then - TriggerClientEvent('QBCore:Notify', playerId, message, 'primary', 10000) - end - end -end - -local function getCurrentArtifact() - -- Versuche aktuelle Version aus verschiedenen Quellen zu ermitteln - local version = GetConvar('version', '') - if version and version ~= '' then - local artifact = string.match(version, 'v1%.0%.0%.(%d+)') - if artifact then - return tonumber(artifact) - end - end - return nil -end - -local function checkForUpdates() - if updateInProgress then return end - - print('[FX-Updater] Prüfe auf Updates...') - - PerformHttpRequest('https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/', function(errorCode, resultData, resultHeaders) - if errorCode == 200 then - -- Parse die neueste Artifact-Nummer aus der HTML-Antwort - local latestArtifact = nil - for artifact in string.gmatch(resultData, '(%d+)%-[a-f0-9]+/') do - local num = tonumber(artifact) - if not latestArtifact or num > latestArtifact then - latestArtifact = num - end - end - - if latestArtifact and latestArtifact >= Config.RequiredArtifact then - local currentArt = getCurrentArtifact() - if not currentArt or latestArtifact > currentArt then - local message = string.format(Config.Notifications.updateAvailable, latestArtifact) - print('[FX-Updater] ' .. message) - notifyAdmins(message) - sendDiscordLog('🔄 ' .. message) - - if Config.AutoUpdate then - Citizen.SetTimeout(5000, function() - performUpdate(latestArtifact) - end) - end - end - end - else - print('[FX-Updater] Fehler beim Prüfen auf Updates: ' .. errorCode) - end - end, 'GET', '', {}) -end - -local function createBackup() - if not Config.BackupEnabled then return true end - - local timestamp = os.date('%Y%m%d_%H%M%S') - local backupDir = Config.BackupPath .. 'backup_' .. timestamp - - -- Erstelle Backup-Verzeichnis - os.execute('mkdir -p "' .. backupDir .. '"') - - -- Sichere wichtige Dateien - os.execute('cp server.cfg "' .. backupDir .. '/"') - os.execute('cp -r resources "' .. backupDir .. '/"') - os.execute('cp -r server-data "' .. backupDir .. '/" 2>/dev/null || true') - - print('[FX-Updater] Backup erstellt: ' .. backupDir) - return true -end - -function performUpdate(targetArtifact) - if updateInProgress then return end - updateInProgress = true - - print('[FX-Updater] Starte Update auf Artifact ' .. targetArtifact) - notifyAdmins(Config.Notifications.updateStarted) - sendDiscordLog('🔄 Update gestartet auf Artifact ' .. targetArtifact) - - -- Warnung an alle Spieler - TriggerClientEvent('chatMessage', -1, '[SERVER]', {255, 165, 0}, 'Server wird in 30 Sekunden für ein Update neu gestartet!') - - Citizen.SetTimeout(30000, function() - -- Backup erstellen - if not createBackup() then - print('[FX-Updater] Backup fehlgeschlagen!') - updateInProgress = false - return - end - - -- Download-URL erstellen - local downloadUrl = string.format( - 'https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/%d-*/fx.tar.xz', - targetArtifact - ) - - -- Update-Script erstellen und ausführen - local updateScript = [[ -#!/bin/bash -echo "FXServer Update gestartet..." - -# Download neue Version -wget -O fx-new.tar.xz "]] .. downloadUrl .. [[" - -if [ $? -eq 0 ]; then - # Entpacken - mkdir -p temp-update - cd temp-update - tar -xf ../fx-new.tar.xz - cd .. - - # Installation - cp temp-update/run.sh ./ - cp -r temp-update/alpine ./ - chmod +x run.sh - chmod +x alpine/opt/cfx-server/FXServer - - # Aufräumen - rm -rf temp-update fx-new.tar.xz - - echo "Update abgeschlossen, starte Server..." - # Server neu starten - ./run.sh +exec server.cfg & -else - echo "Download fehlgeschlagen!" - exit 1 -fi -]] - - -- Script in Datei schreiben - local file = io.open('update_fx.sh', 'w') - if file then - file:write(updateScript) - file:close() - - -- Script ausführbar machen und ausführen - os.execute('chmod +x update_fx.sh') - - -- Server beenden und Update starten - print('[FX-Updater] Server wird beendet für Update...') - notifyAdmins(Config.Notifications.updateCompleted) - sendDiscordLog('✅ Update wird durchgeführt, Server startet neu...') - - Citizen.SetTimeout(2000, function() - os.execute('./update_fx.sh') - os.exit() -- Server beenden - end) - else - print('[FX-Updater] Konnte Update-Script nicht erstellen!') - updateInProgress = false - end - end) -end - --- Events -RegisterNetEvent('fx-updater:checkUpdate', function() - local src = source - if not hasPermission(src) then - TriggerClientEvent('QBCore:Notify', src, Config.Notifications.noPermission, 'error') - return - end - - checkForUpdates() -end) - -RegisterNetEvent('fx-updater:forceUpdate', function(targetArtifact) - local src = source - if not hasPermission(src) then - TriggerClientEvent('QBCore:Notify', src, Config.Notifications.noPermission, 'error') - return - end - - targetArtifact = targetArtifact or Config.RequiredArtifact - performUpdate(targetArtifact) -end) - -RegisterNetEvent('fx-updater:getVersion', function() - local src = source - if not hasPermission(src) then - TriggerClientEvent('QBCore:Notify', src, Config.Notifications.noPermission, 'error') - return - end - - local current = getCurrentArtifact() or 'Unbekannt' - local message = string.format(Config.Notifications.currentVersion, current) - TriggerClientEvent('QBCore:Notify', src, message, 'primary') -end) - --- Commands -QBCore.Commands.Add('fxupdate', 'Prüfe auf FXServer Updates', {}, false, function(source, args) - if not hasPermission(source) then - TriggerClientEvent('QBCore:Notify', source, Config.Notifications.noPermission, 'error') - return - end - - TriggerEvent('fx-updater:checkUpdate') -end, Config.AllowedGroups) - -QBCore.Commands.Add('fxforceupdate', 'Erzwinge FXServer Update', {{name = 'artifact', help = 'Artifact Nummer (optional)'}}, false, function(source, args) - if not hasPermission(source) then - TriggerClientEvent('QBCore:Notify', source, Config.Notifications.noPermission, 'error') - return - end - - local targetArtifact = args[1] and tonumber(args[1]) or Config.RequiredArtifact - TriggerEvent('fx-updater:forceUpdate', targetArtifact) -end, Config.AllowedGroups) - -QBCore.Commands.Add('fxversion', 'Zeige aktuelle FXServer Version', {}, false, function(source, args) - if not hasPermission(source) then - TriggerClientEvent('QBCore:Notify', source, Config.Notifications.noPermission, 'error') - return - end - - TriggerEvent('fx-updater:getVersion') -end, Config.AllowedGroups) - --- Auto-Check Timer -if Config.CheckInterval > 0 then - Citizen.CreateThread(function() - while true do - Citizen.Wait(Config.CheckInterval) - checkForUpdates() - end - end) -end - --- Beim Server-Start prüfen -Citizen.CreateThread(function() - Citizen.Wait(10000) -- Warte 10 Sekunden nach Server-Start - checkForUpdates() -end) - -print('[FX-Updater] Resource gestartet!')