local QBCore = exports['qb-core']:GetCoreObject() -- Lokale Variablen local licenseCache = {} local cacheTimeout = 300000 -- 5 Minuten -- Debug-Funktion local function debugPrint(message) if Config.Debug then print("^3[License-System Server] " .. message .. "^7") end end -- Spieler-Name abrufen local function getPlayerName(src) local Player = QBCore.Functions.GetPlayer(src) if not Player then return "Unbekannt" end local charinfo = Player.PlayerData.charinfo if charinfo and charinfo.firstname and charinfo.lastname then return charinfo.firstname .. " " .. charinfo.lastname end return "Unbekannt" end -- Berechtigung prüfen local function hasPermission(src) local Player = QBCore.Functions.GetPlayer(src) if not Player then return false end local job = Player.PlayerData.job if not job then return false end return Config.AuthorizedJobs[job.name] or false end -- Cache-Funktionen local function getCachedLicense(citizenid, licenseType) local cacheKey = citizenid .. "_" .. licenseType local cached = licenseCache[cacheKey] if cached and (os.time() * 1000 - cached.timestamp) < cacheTimeout then debugPrint("Cache-Hit für: " .. cacheKey) return cached.data end return nil end local function setCachedLicense(citizenid, licenseType, data) local cacheKey = citizenid .. "_" .. licenseType licenseCache[cacheKey] = { data = data, timestamp = os.time() * 1000 } debugPrint("Lizenz gecacht: " .. cacheKey) end -- Spieler-Name aus JSON extrahieren local function extractPlayerName(charinfo_json) if not charinfo_json then return "Unbekannt" end local success, charinfo = pcall(json.decode, charinfo_json) if success and charinfo and charinfo.firstname and charinfo.lastname then return charinfo.firstname .. " " .. charinfo.lastname end return "Unbekannt" end -- Sichere DB-Operation local function safeDBOperation(operation, errorMessage, maxRetries) maxRetries = maxRetries or 3 local retries = 0 while retries < maxRetries do retries = retries + 1 local success, result = pcall(operation) if success then return result else debugPrint("^3DB-Retry " .. retries .. "/" .. maxRetries .. ": " .. tostring(result) .. "^7") if retries >= maxRetries then debugPrint("^1DB-Fehler: " .. (errorMessage or "Unbekannt") .. "^7") debugPrint("^1Details: " .. tostring(result) .. "^7") return nil end Wait(1000) end end return nil end -- KORRIGIERTE Lizenz-Abfrage (Erweiterte Suche) local function getLicenseFromDB(citizenid, licenseType) debugPrint("=== getLicenseFromDB START ===") debugPrint("CitizenID: " .. tostring(citizenid)) debugPrint("LicenseType: " .. tostring(licenseType)) -- Cache prüfen local cached = getCachedLicense(citizenid, licenseType) if cached then debugPrint("Lizenz aus Cache geladen") return cached end -- ERWEITERTE SUCHE: Erst aktive, dann alle Lizenzen local queries = { -- 1. Suche nach aktiven Lizenzen (is_active = 1) { query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? AND is_active = 1 ORDER BY created_at DESC LIMIT 1", description = "Aktive Lizenz" }, -- 2. Suche nach allen Lizenzen (falls is_active nicht gesetzt) { query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? ORDER BY created_at DESC LIMIT 1", description = "Neueste Lizenz" }, -- 3. Fallback: Suche ohne is_active Bedingung { query = "SELECT * FROM player_licenses WHERE citizenid = ? AND license_type = ? ORDER BY id DESC LIMIT 1", description = "Fallback-Suche" } } local license = nil for i, queryData in ipairs(queries) do debugPrint("Versuche Query " .. i .. ": " .. queryData.description) local result = safeDBOperation(function() return MySQL.query.await(queryData.query, {citizenid, licenseType}) end, "Fehler bei " .. queryData.description) if result and #result > 0 then license = result[1] debugPrint("Lizenz gefunden mit Query " .. i .. ": " .. queryData.description) break else debugPrint("Keine Lizenz mit Query " .. i .. " gefunden") end end if not license then debugPrint("^1Keine Lizenz in DB gefunden für " .. citizenid .. " / " .. licenseType .. "^7") return nil end -- Spieler-Namen abrufen local holderQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local holderResult = safeDBOperation(function() return MySQL.query.await(holderQuery, {citizenid}) end, "Fehler beim Abrufen des Spieler-Namens") if holderResult and #holderResult > 0 then license.holder_name = extractPlayerName(holderResult[1].charinfo) else license.holder_name = "Unbekannt" end -- Aussteller-Namen abrufen if license.issued_by then local issuerQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local issuerResult = safeDBOperation(function() return MySQL.query.await(issuerQuery, {license.issued_by}) end, "Fehler beim Abrufen des Aussteller-Namens") if issuerResult and #issuerResult > 0 then license.issued_by_name = extractPlayerName(issuerResult[1].charinfo) else license.issued_by_name = "System" end else license.issued_by_name = "System" end -- Classes parsen if license.classes then local success, classes = pcall(json.decode, license.classes) if success and type(classes) == "table" then license.classes = classes else license.classes = {} end else license.classes = {} end -- is_active standardisieren (falls nicht gesetzt) if license.is_active == nil then license.is_active = 1 end debugPrint("Lizenz erfolgreich geladen: " .. license.license_type .. " (Active: " .. tostring(license.is_active) .. ")") -- In Cache speichern setCachedLicense(citizenid, licenseType, license) return license end -- Alle Lizenzen eines Spielers abrufen (KORRIGIERT) local function getAllPlayerLicenses(citizenid) debugPrint("=== getAllPlayerLicenses START ===") debugPrint("CitizenID: " .. tostring(citizenid)) -- Erweiterte Suche für alle Lizenzen local queries = { -- 1. Aktive Lizenzen "SELECT * FROM player_licenses WHERE citizenid = ? AND is_active = 1 ORDER BY license_type, created_at DESC", -- 2. Alle Lizenzen (Fallback) "SELECT * FROM player_licenses WHERE citizenid = ? ORDER BY license_type, created_at DESC" } local result = nil for i, query in ipairs(queries) do debugPrint("Versuche Abfrage " .. i .. " für alle Lizenzen") result = safeDBOperation(function() return MySQL.query.await(query, {citizenid}) end, "Fehler bei Abfrage " .. i) if result and #result > 0 then debugPrint("Lizenzen gefunden mit Abfrage " .. i .. ": " .. #result .. " Einträge") break end end if not result or #result == 0 then debugPrint("Keine Lizenzen gefunden für: " .. citizenid) return {} end local licenses = {} local seenTypes = {} -- Spieler-Namen einmal abrufen local holderQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local holderResult = safeDBOperation(function() return MySQL.query.await(holderQuery, {citizenid}) end, "Fehler beim Abrufen des Spieler-Namens") local holderName = "Unbekannt" if holderResult and #holderResult > 0 then holderName = extractPlayerName(holderResult[1].charinfo) end for _, license in ipairs(result) do -- Nur die neueste Lizenz pro Typ nehmen if not seenTypes[license.license_type] then seenTypes[license.license_type] = true license.holder_name = holderName -- Aussteller-Namen abrufen if license.issued_by then local issuerQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local issuerResult = safeDBOperation(function() return MySQL.query.await(issuerQuery, {license.issued_by}) end, "Fehler beim Abrufen des Aussteller-Namens") if issuerResult and #issuerResult > 0 then license.issued_by_name = extractPlayerName(issuerResult[1].charinfo) else license.issued_by_name = "System" end else license.issued_by_name = "System" end -- Classes parsen if license.classes then local success, classes = pcall(json.decode, license.classes) if success and type(classes) == "table" then license.classes = classes else license.classes = {} end else license.classes = {} end -- is_active standardisieren if license.is_active == nil then license.is_active = 1 end table.insert(licenses, license) end end debugPrint("Verarbeitete Lizenzen: " .. #licenses) return licenses end -- Lizenz in Datenbank speichern (KORRIGIERT) local function saveLicenseToDB(citizenid, licenseType, issuedBy, classes) debugPrint("=== saveLicenseToDB START ===") debugPrint("CitizenID: " .. tostring(citizenid)) debugPrint("LicenseType: " .. tostring(licenseType)) debugPrint("IssuedBy: " .. tostring(issuedBy)) local config = Config.LicenseTypes[licenseType] if not config then debugPrint("^1Fehler: Unbekannter Lizenztyp: " .. licenseType .. "^7") return false end -- Spieler-Name abrufen local holderQuery = "SELECT charinfo FROM players WHERE citizenid = ?" local holderResult = safeDBOperation(function() return MySQL.query.await(holderQuery, {citizenid}) end, "Fehler beim Abrufen des Spieler-Namens") local holderName = "Unbekannt" if holderResult and #holderResult > 0 and holderResult[1].charinfo then holderName = extractPlayerName(holderResult[1].charinfo) end -- Datum berechnen local issueDate = os.date("%d.%m.%Y") local expireDate = nil if config.validity_days then local expireTimestamp = os.time() + (config.validity_days * 24 * 60 * 60) expireDate = os.date("%d.%m.%Y", expireTimestamp) end -- Classes zu JSON konvertieren local classesJson = json.encode(classes or {}) -- Alte Lizenz deaktivieren local deactivateQuery = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ?" safeDBOperation(function() return MySQL.query.await(deactivateQuery, {citizenid, licenseType}) end, "Fehler beim Deaktivieren alter Lizenz") -- Neue Lizenz einfügen local insertQuery = [[ INSERT INTO player_licenses (citizenid, license_type, name, issue_date, expire_date, issued_by, is_active, classes, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ]] local createdAt = os.time() -- Unix Timestamp local insertData = { citizenid, licenseType, holderName, issueDate, expireDate, issuedBy, 1, -- is_active = 1 classesJson, createdAt } debugPrint("Führe INSERT-Query aus...") debugPrint("Daten: " .. json.encode(insertData)) local result = safeDBOperation(function() return MySQL.insert.await(insertQuery, insertData) end, "Fehler beim Speichern der Lizenz") if result then debugPrint("Lizenz erfolgreich gespeichert. ID: " .. result) -- Cache invalidieren local cacheKey = citizenid .. "_" .. licenseType licenseCache[cacheKey] = nil return true else debugPrint("^1Fehler beim Speichern der Lizenz^7") return false end end -- Lizenz entziehen local function revokeLicenseInDB(citizenid, licenseType) debugPrint("=== revokeLicenseInDB START ===") debugPrint("CitizenID: " .. tostring(citizenid)) debugPrint("LicenseType: " .. tostring(licenseType)) local query = "UPDATE player_licenses SET is_active = 0 WHERE citizenid = ? AND license_type = ?" local result = safeDBOperation(function() return MySQL.query.await(query, {citizenid, licenseType}) end, "Fehler beim Entziehen der Lizenz") if result then debugPrint("Lizenz erfolgreich entzogen") -- Cache invalidieren local cacheKey = citizenid .. "_" .. licenseType licenseCache[cacheKey] = nil return true else debugPrint("^1Fehler beim Entziehen der Lizenz^7") return false end end -- Cache bereinigen local function cleanupCache() local now = os.time() * 1000 local cleaned = 0 for key, cached in pairs(licenseCache) do if (now - cached.timestamp) > cacheTimeout then licenseCache[key] = nil cleaned = cleaned + 1 end end if cleaned > 0 then debugPrint("Cache bereinigt: " .. cleaned .. " Einträge") end end -- Cache-Cleanup Thread CreateThread(function() while true do Wait(300000) -- 5 Minuten cleanupCache() end end) -- EVENT HANDLER: Lizenz anfordern (KORRIGIERT für Ausweis-Anzeige) RegisterNetEvent('license-system:server:requestLicense', function(targetId) local src = source debugPrint("=== Event: requestLicense ===") debugPrint("Source: " .. src .. ", Target: " .. targetId) if not hasPermission(src) then debugPrint("Keine Berechtigung für Spieler: " .. src) TriggerClientEvent('license-system:client:receiveLicense', src, nil) return end local targetPlayer = QBCore.Functions.GetPlayer(targetId) if not targetPlayer then debugPrint("Ziel-Spieler nicht gefunden: " .. targetId) TriggerClientEvent('license-system:client:receiveLicense', src, nil) return end local citizenid = targetPlayer.PlayerData.citizenid -- PRIORITÄT: Erst nach Ausweis suchen, dann andere Lizenzen local licenseTypes = {"id_card", "driver_license", "weapon_license", "pilot_license"} local foundLicense = nil for _, licenseType in ipairs(licenseTypes) do if Config.LicenseTypes[licenseType] then local license = getLicenseFromDB(citizenid, licenseType) if license then foundLicense = { license = license, config = Config.LicenseTypes[licenseType] } debugPrint("Lizenz gefunden: " .. licenseType) break end end end if foundLicense then debugPrint("Sende Lizenz an Client: " .. foundLicense.license.license_type) TriggerClientEvent('license-system:client:receiveLicense', src, foundLicense) else debugPrint("Keine Lizenz gefunden") TriggerClientEvent('license-system:client:receiveLicense', src, nil) end end) -- EVENT HANDLER: Eigene Lizenz anfordern (KORRIGIERT) RegisterNetEvent('license-system:server:requestMyLicense', function(licenseType) local src = source debugPrint("=== Event: requestMyLicense ===") debugPrint("Source: " .. src .. ", LicenseType: " .. tostring(licenseType)) local Player = QBCore.Functions.GetPlayer(src) if not Player then debugPrint("Spieler nicht gefunden: " .. src) TriggerClientEvent('license-system:client:receiveMyLicense', src, nil, licenseType) return end local citizenid = Player.PlayerData.citizenid -- Falls kein spezifischer Typ angegeben, suche nach Ausweis if not licenseType or licenseType == "" then licenseType = "id_card" debugPrint("Kein Lizenztyp angegeben, verwende: " .. licenseType) end local license = getLicenseFromDB(citizenid, licenseType) if license then local licenseData = { license = license, config = Config.LicenseTypes[licenseType] } debugPrint("Sende eigene Lizenz an Client: " .. licenseType) TriggerClientEvent('license-system:client:receiveMyLicense', src, licenseData, licenseType) else debugPrint("Keine aktive eigene Lizenz gefunden: " .. licenseType) TriggerClientEvent('license-system:client:receiveMyLicense', src, nil, licenseType) end end) -- EVENT HANDLER: Alle Spieler-Lizenzen anfordern RegisterNetEvent('license-system:server:requestPlayerLicenses', function(targetId) local src = source debugPrint("=== Event: requestPlayerLicenses ===") debugPrint("Source: " .. src .. ", Target: " .. targetId) if not hasPermission(src) then debugPrint("Keine Berechtigung für Spieler: " .. src) TriggerClientEvent('license-system:client:receivePlayerLicenses', src, {}, targetId, "Unbekannt") return end local targetPlayer = QBCore.Functions.GetPlayer(targetId) if not targetPlayer then debugPrint("Ziel-Spieler nicht gefunden: " .. targetId) TriggerClientEvent('license-system:client:receivePlayerLicenses', src, {}, targetId, "Unbekannt") return end local citizenid = targetPlayer.PlayerData.citizenid local targetName = getPlayerName(targetId) local licenses = getAllPlayerLicenses(citizenid) debugPrint("Sende " .. #licenses .. " Lizenzen für " .. targetName) TriggerClientEvent('license-system:client:receivePlayerLicenses', src, licenses, targetId, targetName) end) -- EVENT HANDLER: Lizenz ausstellen RegisterNetEvent('license-system:server:issueLicense', function(targetId, licenseType, classes) local src = source debugPrint("=== Event: issueLicense ===") debugPrint("Source: " .. src .. ", Target: " .. targetId .. ", Type: " .. licenseType) if not hasPermission(src) then debugPrint("Keine Berechtigung für Spieler: " .. src) TriggerClientEvent('QBCore:Notify', src, Config.Notifications.no_permission.message, Config.Notifications.no_permission.type) return end local targetPlayer = QBCore.Functions.GetPlayer(targetId) if not targetPlayer then debugPrint("Ziel-Spieler nicht gefunden: " .. targetId) TriggerClientEvent('QBCore:Notify', src, 'Spieler nicht gefunden!', 'error') return end local issuerPlayer = QBCore.Functions.GetPlayer(src) if not issuerPlayer then debugPrint("Aussteller nicht gefunden: " .. src) return end local targetCitizenId = targetPlayer.PlayerData.citizenid local issuerCitizenId = issuerPlayer.PlayerData.citizenid -- Prüfen ob aktive Lizenz bereits existiert local existingLicense = getLicenseFromDB(targetCitizenId, licenseType) if existingLicense and existingLicense.is_active == 1 then debugPrint("Lizenz bereits vorhanden und aktiv") TriggerClientEvent('QBCore:Notify', src, 'Spieler hat bereits eine aktive ' .. (Config.LicenseTypes[licenseType].label or licenseType) .. '!', 'error') return end -- Kosten prüfen local config = Config.LicenseTypes[licenseType] if config.price and config.price > 0 then if issuerPlayer.PlayerData.money.cash < config.price then debugPrint("Nicht genug Geld für Lizenz-Ausstellung") TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Bargeld! Benötigt: $' .. config.price, 'error') return end -- Geld abziehen issuerPlayer.Functions.RemoveMoney('cash', config.price, 'license-issued') TriggerClientEvent('QBCore:Notify', src, 'Lizenz-Gebühr bezahlt: $' .. config.price, 'success') end -- Lizenz in Datenbank speichern local success = saveLicenseToDB(targetCitizenId, licenseType, issuerCitizenId, classes) if success then local targetName = getPlayerName(targetId) local issuerName = getPlayerName(src) debugPrint("Lizenz erfolgreich ausgestellt") -- Benachrichtigungen TriggerClientEvent('QBCore:Notify', src, 'Lizenz erfolgreich ausgestellt für ' .. targetName, 'success') TriggerClientEvent('QBCore:Notify', targetId, 'Du hast eine neue Lizenz erhalten: ' .. config.label, 'success') -- Events senden TriggerClientEvent('license-system:client:licenseIssued', src, targetId, licenseType) TriggerClientEvent('license-system:client:refreshMenu', src) -- Log debugPrint("Lizenz " .. licenseType .. " ausgestellt von " .. issuerName .. " für " .. targetName) else debugPrint("^1Fehler beim Ausstellen der Lizenz^7") TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Ausstellen der Lizenz!', 'error') end end) -- EVENT HANDLER: Lizenz entziehen RegisterNetEvent('license-system:server:revokeLicense', function(targetId, licenseType) local src = source debugPrint("=== Event: revokeLicense ===") debugPrint("Source: " .. src .. ", Target: " .. targetId .. ", Type: " .. licenseType) if not hasPermission(src) then debugPrint("Keine Berechtigung für Spieler: " .. src) TriggerClientEvent('QBCore:Notify', src, Config.Notifications.no_permission.message, Config.Notifications.no_permission.type) return end local targetPlayer = QBCore.Functions.GetPlayer(targetId) if not targetPlayer then debugPrint("Ziel-Spieler nicht gefunden: " .. targetId) TriggerClientEvent('QBCore:Notify', src, 'Spieler nicht gefunden!', 'error') return end local targetCitizenId = targetPlayer.PlayerData.citizenid -- Lizenz entziehen local success = revokeLicenseInDB(targetCitizenId, licenseType) if success then local targetName = getPlayerName(targetId) local issuerName = getPlayerName(src) local config = Config.LicenseTypes[licenseType] debugPrint("Lizenz erfolgreich entzogen") -- Benachrichtigungen TriggerClientEvent('QBCore:Notify', src, 'Lizenz erfolgreich entzogen von ' .. targetName, 'success') TriggerClientEvent('QBCore:Notify', targetId, 'Deine Lizenz wurde entzogen: ' .. (config.label or licenseType), 'error') -- Events senden TriggerClientEvent('license-system:client:licenseRevoked', src, targetId, licenseType) TriggerClientEvent('license-system:client:refreshMenu', src) -- Log debugPrint("Lizenz " .. licenseType .. " entzogen von " .. issuerName .. " für " .. targetName) else debugPrint("^1Fehler beim Entziehen der Lizenz^7") TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Entziehen der Lizenz!', 'error') end end) -- EXPORT FUNKTIONEN (KORRIGIERT) exports('hasLicense', function(citizenid, licenseType) if not citizenid or not licenseType then return false end local license = getLicenseFromDB(citizenid, licenseType) return license ~= nil and (license.is_active == 1 or license.is_active == nil) end) exports('issueLicense', function(citizenid, licenseType, issuedBy, classes) if not citizenid or not licenseType then return false end issuedBy = issuedBy or 'system' return saveLicenseToDB(citizenid, licenseType, issuedBy, classes) end) exports('revokeLicense', function(citizenid, licenseType) if not citizenid or not licenseType then return false end return revokeLicenseInDB(citizenid, licenseType) end) exports('getPlayerLicenses', function(citizenid) if not citizenid then return {} end return getAllPlayerLicenses(citizenid) end) exports('getPlayerLicense', function(citizenid, licenseType) if not citizenid or not licenseType then return nil end return getLicenseFromDB(citizenid, licenseType) end) -- DEBUG COMMAND: Lizenz manuell erstellen RegisterCommand('createlicense', function(source, args, rawCommand) if source == 0 then -- Console only if #args < 2 then print("Usage: createlicense ") return end local citizenid = args[1] local licenseType = args[2] if not Config.LicenseTypes[licenseType] then print("Unbekannter Lizenztyp: " .. licenseType) return end local success = saveLicenseToDB(citizenid, licenseType, 'console', {}) if success then print("Lizenz erfolgreich erstellt: " .. licenseType .. " für " .. citizenid) else print("Fehler beim Erstellen der Lizenz") end end end, true) -- DEBUG COMMAND: Lizenz prüfen RegisterCommand('checklicense', function(source, args, rawCommand) if source == 0 then -- Console only if #args < 2 then print("Usage: checklicense ") return end local citizenid = args[1] local licenseType = args[2] local license = getLicenseFromDB(citizenid, licenseType) if license then print("=== LIZENZ GEFUNDEN ===") print("ID: " .. (license.id or "N/A")) print("CitizenID: " .. (license.citizenid or "N/A")) print("Typ: " .. (license.license_type or "N/A")) print("Name: " .. (license.name or "N/A")) print("Ausstellungsdatum: " .. (license.issue_date or "N/A")) print("Ablaufdatum: " .. (license.expire_date or "N/A")) print("Ausgestellt von: " .. (license.issued_by or "N/A")) print("Aktiv: " .. tostring(license.is_active)) print("Klassen: " .. (license.classes and json.encode(license.classes) or "[]")) print("Erstellt am: " .. (license.created_at or "N/A")) print("=====================") else print("Keine Lizenz gefunden für: " .. citizenid .. " / " .. licenseType) end end end, true) -- INITIALISIERUNG CreateThread(function() debugPrint("License-System Server gestartet (Ausweis-Fix)") -- Warten bis QBCore geladen ist while not QBCore do Wait(100) end debugPrint("QBCore erfolgreich geladen") -- Datenbank-Verbindung testen local testResult = safeDBOperation(function() return MySQL.query.await("SELECT 1 as test") end, "Datenbank-Verbindungstest") if testResult then debugPrint("Datenbank-Verbindung erfolgreich") else debugPrint("^1Datenbank-Verbindung fehlgeschlagen^7") end debugPrint("License-System Server vollständig initialisiert") end) -- CLEANUP AddEventHandler('onResourceStop', function(resourceName) if GetCurrentResourceName() == resourceName then debugPrint("License-System Server gestoppt") licenseCache = {} end end) -- DEBUG COMMANDS RegisterCommand('licensestats', function(source, args, rawCommand) if source == 0 then -- Console only local cacheCount = 0 for _ in pairs(licenseCache) do cacheCount = cacheCount + 1 end print("=== LICENSE SYSTEM STATS ===") print("Cache Entries: " .. cacheCount) print("Config License Types: " .. (Config.LicenseTypes and table.count(Config.LicenseTypes) or 0)) print("============================") end end, true) RegisterCommand('licenseclearcache', function(source, args, rawCommand) if source == 0 then -- Console only local oldCount = 0 for _ in pairs(licenseCache) do oldCount = oldCount + 1 end licenseCache = {} print("License-Cache geleert. Entfernte Einträge: " .. oldCount) end end, true) -- Hilfsfunktion für table.count function table.count(t) local count = 0 for _ in pairs(t) do count = count + 1 end return count end debugPrint("License-System Server vollständig geladen (Ausweis-Fix)")