if Config.Framework ~= "qb" then return end local nameCache = {} Core = { CoreReady = false, JobbyJobs = {}, JobbyJobsReady = false, } Core.__index = Core Core.Functions = {} local databaseReady = false AddEventHandler('codem-phone:database:ready', function() databaseReady = true end) local function CheckQBCoreStatus() local resourceState = GetResourceState('qb-core') return resourceState == "started" or resourceState == "starting" end local QBCore = nil if CheckQBCoreStatus() then local success, result = pcall(function() return exports['qb-core']:GetCoreObject() end) if success and result then QBCore = result Core.CoreReady = true Citizen.CreateThread(function() local timeout = 0 while not databaseReady and timeout < 60000 do Wait(100) timeout = timeout + 100 end if not databaseReady then print('^1[CODEM-PHONE] Framework ERROR: Database initialization timeout!^7') return end local JobbyConfig = LoadFile('config/AppConfig/JobbyConfig.lua') local players = MySQL.query.await('SELECT citizenid, job, charinfo FROM players') for k, v in pairs(JobbyConfig.AllowJobs) do Core.JobbyJobs[k] = { label = QBCore.Shared.Jobs[k] and QBCore.Shared.Jobs[k].label or 'Unknown Job', players = {}, name = k, grades = QBCore.Shared.Jobs[k] and QBCore.Shared.Jobs[k].grades or {}, money = 0, announcements = {}, logs = {}, } local ShowSQl = MySQL.scalar.await( "SELECT 1 FROM information_schema.tables WHERE table_name = 'codem_mphone_jobby_announcements' LIMIT 1") local announcementSql = {} if ShowSQl then announcementSql = MySQL.query.await( 'SELECT id, title, content, created_at FROM codem_mphone_jobby_announcements WHERE jobname = ? ORDER BY created_at DESC LIMIT 15', { k } ) end local ShowLogSQl = MySQL.scalar.await( "SELECT 1 FROM information_schema.tables WHERE table_name = 'codem_mphone_jobby_log' LIMIT 1") local logsSql = {} if ShowLogSQl then logsSql = MySQL.query.await( 'SELECT id, action, amount, playername, phone_number, date FROM codem_mphone_jobby_log WHERE jobname = ? ORDER BY date DESC LIMIT 20', { k } ) end for __, vv in pairs(players) do local jobs = json.decode(vv.job) if jobs and jobs.name and jobs.name == k then local charinfo = vv.charinfo and json.decode(vv.charinfo) or nil local playerName = 'Unknown Player' if charinfo and charinfo.firstname and charinfo.lastname then playerName = charinfo.firstname .. ' ' .. charinfo.lastname end local PhoneNumber = MySQL.query.await( "SELECT phone_number FROM codem_mphone_data WHERE owner = ? LIMIT 1", { vv.citizenid }) local gradeLevel = (jobs.grade and jobs.grade.level) or 0 local gradeName = (jobs.grade and jobs.grade.name) or 'Unknown Grade' Core.JobbyJobs[k].players[#Core.JobbyJobs[k].players + 1] = { name = playerName, grade_level = gradeLevel, grade_name = gradeName, src = false, identifier = vv.citizenid, boss = false, phone_number = PhoneNumber and PhoneNumber[1] and PhoneNumber[1].phone_number or nil, } end end Core.JobbyJobs[k].money = GetJobMoney(k) Core.JobbyJobs[k].announcements = announcementSql or {} Core.JobbyJobs[k].logs = logsSql or {} end Core.JobbyJobsReady = true end) else DebugPrint('Error: QB-Core object could not be retrieved') end else DebugPrint('Error: QB-Core resource not found or not started') return end -- Example job structure from QBCore: -- "realestate": { -- "label": "Real Estate", -- "offDutyPay": false, -- "grades": { -- "3": { -- "payment": 125, -- "name": "Broker" -- }, -- "4": { -- "isboss": true, -- "payment": 150, -- "name": "Manager" -- }, -- "0": { -- "payment": 50, -- "name": "Recruit" -- }, -- "1": { -- "payment": 75, -- "name": "House Sales" -- }, -- "2": { -- "payment": 100, -- "name": "Business Sales" -- } -- }, -- "defaultDuty": true -- } function JobHasIsBossField(job) local AllFrameworkJobs = Core.JobbyJobs or {} if not AllFrameworkJobs[job] then return false end local AllGrades = AllFrameworkJobs[job].grades or {} for _, gradeData in pairs(AllGrades) do if gradeData.isboss == true then return true end end return false end function IsGradeBoss(job, gradeLevel) local AllFrameworkJobs = Core.JobbyJobs or {} if not AllFrameworkJobs[job] then return false end local AllGrades = AllFrameworkJobs[job].grades or {} local gradeData = AllGrades[tonumber(gradeLevel)] or AllGrades[tostring(gradeLevel)] if gradeData and gradeData.isboss == true then return true end return false end function GetHighestGrade(job) local AllFrameworkJobs = Core.JobbyJobs or {} if AllFrameworkJobs[job] then local AllGrades = AllFrameworkJobs[job].grades local highestGrade = -1 for key, _ in pairs(AllGrades) do local gradeNum = tonumber(key) if gradeNum and gradeNum > highestGrade then highestGrade = gradeNum end end return highestGrade else return false end end function IsBoss(job, gradeLevel) if JobHasIsBossField(job) then return IsGradeBoss(job, gradeLevel) else local highestGrade = GetHighestGrade(job) return highestGrade and gradeLevel >= highestGrade end end Core.Functions.GetPlayer = function(playerid) if not playerid then DebugPrint('Error: playerId is required') return nil end if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerid) if success and playerData then return playerData else return false end else return false end end Core.Functions.GetIdentifier = function(playerId) if not playerId then DebugPrint('Error: playerId is required') return nil end if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerId) if success and playerData and playerData.PlayerData then return playerData.PlayerData.citizenid or nil else return false end else return false end end Core.Functions.GetSourceFromIdentifier = function(identifier) if not identifier then DebugPrint('Error: identifier is required') return nil end if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, player = pcall(QBCore.Functions.GetPlayerByCitizenId, identifier) if success and player then return player.PlayerData.source else return false end else return false end end -- Example job data structure from QBCore: --[[ { "payment": 150, "grade": { "payment": 150, "name": "Chief", "isboss": true, "level": 4 }, "type": "leo", "name": "police", "label": "Law Enforcement", "isboss": true, "onduty": true } ]] Core.Functions.GetPlayerJob = function(playerId) if not playerId then DebugPrint('Error: playerId is required') return false end if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerId) if success and playerData and playerData.PlayerData and playerData.PlayerData.job then return { name = playerData.PlayerData.job.name or 'unemployed', label = playerData.PlayerData.job.label or 'Unemployed', onduty = playerData.PlayerData.job.onduty or false, grade_name = playerData.PlayerData.job.grade.name or 'unemployed', grade_level = playerData.PlayerData.job.grade.level or 0, isboss = playerData.PlayerData.job.grade.isboss or false } else return false end else return false end end Core.Functions.IsPlayerAdmin = function(playerId) if not playerId then DebugPrint('Error: playerId is required') return false end local permissions = Config.Permissions or { 'god' } if type(permissions) ~= 'table' or #permissions == 0 then DebugPrint('Warning: Config.Permissions is invalid, using default permissions') permissions = { 'god' } end for _, v in pairs(Config.AdminPermissions) do if QBCore.Functions.HasPermission(playerId, v) or IsPlayerAceAllowed(playerId, 'command') then return true end end return false end AddEventHandler("QBCore:Server:OnJobUpdate", function(src, job) TriggerClientEvent('codem-phone:client:OnJobUpdate', src) OnJobUpdate(src, { jobname = job.name or 'unemployed', onduty = job.onduty or false, }) OnJobbyJobUpdate(src) end) AddEventHandler("QBCore:Server:SetDuty", function(src, onDuty) local playerJob = Core.Functions.GetPlayerJob(src) OnJobUpdate(src, { jobname = playerJob and playerJob.name or 'unemployed', onduty = onDuty or false, }) OnJobbyJobUpdate(src) end) Core.Functions.GetName = function(playerId, nameType) if not playerId then DebugPrint('Error: playerId is required') return 'Unknown' end if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerId) if success and playerData and playerData.PlayerData then local firstname = playerData.PlayerData.charinfo.firstname or "" local lastname = playerData.PlayerData.charinfo.lastname or "" if nameType and nameType:lower() == 'first' then return (firstname):gsub("^%l", string.upper) or 'Unknown' elseif nameType and nameType:lower() == 'full' then return (firstname .. " " .. lastname):gsub("^%l", string.upper) or 'Unknown' end return (firstname .. " " .. lastname):gsub("^%l", string.upper) or 'Unknown' else -- offline player ismini çekmek için Core.Functions.GetName fonksiyonunu çağırırken playerId yerine identifier'ini yaz if nameCache[playerId] then if nameType and nameType:lower() == 'first' then return (nameCache[playerId].firstname):gsub("^%l", string.upper) or 'Unknown' elseif nameType and nameType:lower() == 'full' then return (nameCache[playerId].firstname .. " " .. nameCache[playerId].lastname):gsub("^%l", string.upper) or 'Unknown' end return (nameCache[playerId].firstname .. " " .. nameCache[playerId].lastname):gsub("^%l", string.upper) or 'Unknown' end local result = MySQL.single.await("SELECT charinfo FROM players WHERE citizenid = ? LIMIT 1", { playerId }) if result and result.charinfo then local charinfo = json.decode(result.charinfo) if nameType and nameType:lower() == 'first' then return (charinfo.firstname):gsub("^%l", string.upper) or 'Unknown' elseif nameType and nameType:lower() == 'full' then return (charinfo.firstname .. " " .. charinfo.lastname):gsub("^%l", string.upper) or 'Unknown' end nameCache[playerId] = { firstname = charinfo.firstname, lastname = charinfo.lastname, } return (charinfo.firstname .. " " .. charinfo.lastname):gsub("^%l", string.upper) or 'Unknown' end end else DebugPrint('Error: QB-Core Functions not available') end return 'Unknown' end Core.Functions.GetMoney = function(playerId, moneyType) if not playerId then DebugPrint('Error: playerId is required') return 0 end moneyType = moneyType or 'bank' if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerId) if success and playerData and playerData.PlayerData and playerData.PlayerData.money then return { success = true, money = playerData.PlayerData.money[moneyType] or 0 } else return { success = false, message = 'Error: Player data could not be retrieved - ID: ' .. tostring(playerId) } end else return { success = false, message = 'Error: QB-Core Functions not available' } end end Core.Functions.RemoveMoney = function(playerId, amount, moneyType) if not playerId then DebugPrint('Error: playerId is required') return false end if not amount or amount <= 0 then DebugPrint('Error: amount must be a positive number') return false end moneyType = moneyType or 'bank' if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerId) if success and playerData and playerData.PlayerData and playerData.PlayerData.money then local currentMoney = playerData.PlayerData.money[moneyType] or 0 if currentMoney >= amount then local removeSuccess, removeResult = pcall(function() return playerData.Functions.RemoveMoney(moneyType, amount, "codem-phone") end) if removeSuccess and removeResult then return true else return false end else return false end else return false end else return false end end Core.Functions.AddMoney = function(playerId, amount, moneyType) if not playerId then DebugPrint('Error: playerId is required') return false end if not amount or amount <= 0 then DebugPrint('Error: amount must be a positive number') return false end moneyType = moneyType or 'bank' if QBCore and QBCore.Functions and QBCore.Functions.GetPlayer then local success, playerData = pcall(QBCore.Functions.GetPlayer, playerId) if success and playerData and playerData.PlayerData and playerData.PlayerData.money then local addSuccess, addResult = pcall(function() return playerData.Functions.AddMoney(moneyType, amount, "codem-phone") end) if addSuccess then return addResult else return false end else return false end else return false end end Core.Functions.AddMoneyOffline = function(citizenid, amount, moneyType) if not citizenid then return { success = false, message = "Citizen ID is required." } end if not amount or amount <= 0 then return { success = false, message = "Invalid amount." } end moneyType = moneyType or 'bank' if QBCore and QBCore.Functions then local moneyData = MySQL.scalar.await( "SELECT money FROM players WHERE citizenid = ?", { citizenid } ) if not moneyData then return { success = false, message = "Player not found in database." } end local playerData = json.decode(moneyData) or {} local currentMoney = playerData[moneyType] or 0 playerData[moneyType] = currentMoney + amount local affectedRows = MySQL.update.await( "UPDATE players SET money = ? WHERE citizenid = ?", { json.encode(playerData), citizenid } ) if affectedRows > 0 then return { success = true } else return { success = false, message = "Failed to update money for offline player." } end else return { success = false, message = "Core Functions not available." } end end Core.Functions.SetPlayerJob = function(playerid, jobname, grade) local player = Core.Functions.GetPlayer(playerid) if player then player.Functions.SetJob(jobname, grade) return true else DebugPrint('Error: Player not found - ID: ' .. tostring(playerid)) return false end end Core.Functions.CreateUseableItem = function(itemName, callback) if not itemName or type(itemName) ~= 'string' then DebugPrint('Error: itemName must be a valid string') return end if not callback or type(callback) ~= 'function' then DebugPrint('Error: callback must be a valid function') return end if QBCore and QBCore.Functions and QBCore.Functions.CreateUseableItem then QBCore.Functions.CreateUseableItem(itemName, callback) else DebugPrint('Error: QB-Core Functions not available') end end