Complete refactor of handling of framework info

I've moved the framework caching to a new file `frameworkCache.lua`

This now caches the framework data once when `jim_bridge` starts

Then in `coreloader.lua` now, the information that is cached is now called from that script

This also includes better handling of ESX cached data and should stop errors

This greatly optimizes the loading of all my scripts and lowers server load to speed up server start times

I have been testing this for just under a week and 6 different test servers and it appears to work fine
This commit is contained in:
Jim Shield
2025-06-06 00:50:13 +01:00
parent 9c4c92e696
commit de8f7c050c
4 changed files with 380 additions and 312 deletions

View File

@@ -1,25 +1,8 @@
--[[
Resource Initialization Module
--------------------------------
This module initializes and loads shared data (Items, Vehicles, Jobs, Gangs) from the
various frameworks/inventory systems (OX, QB, ESX, etc.). It also corrects export names,
caches framework exports into simple variables, and prints debug information if enabled.
]]
-------------------------------------------------------------
-- Global Variable Initialization
-------------------------------------------------------------
Items, Vehicles, Jobs, Gangs, Core = {}, nil, nil, nil, nil
-------------------------------------------------------------
-- Correct QB Inventory Export
-------------------------------------------------------------
-- Correct ps-invetory to ls-inventory if somehow you still have that
-- Shared Exports Initialization
Exports.PSInv = isStarted("lj-inventory") and "lj-inventory" or Exports.PSInv
-------------------------------------------------------------
-- Framework Exports and Inventory Identifiers
-------------------------------------------------------------
OXLibExport, QBXExport, QBExport, ESXExport, OXCoreExport =
Exports.OXLibExport or "",
Exports.QBXExport or "",
@@ -37,310 +20,83 @@ OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv, TgiannInv =
Exports.OrigenInv or "",
Exports.TgiannInv or ""
RSGExport, RSGInv =
Exports.RSGExport or "",
Exports.RSGInv or ""
RSGExport, RSGInv = Exports.RSGExport or "", Exports.RSGInv or ""
QBMenuExport = Exports.QBMenuExport or ""
QBTargetExport, OXTargetExport = Exports.QBTargetExport or "", Exports.OXTargetExport or ""
-------------------------------------------------------------
-- Debug: Print Found Exports
-------------------------------------------------------------
-- Print a list of all exports that are currently started (if debugMode is enabled).
for _, v in pairs(Exports) do
if isStarted(v) then
debugPrint("^6Bridge^7: '^3"..v.."^7' export found")
end
end
OxPlayer = nil
if isStarted(OXCoreExport) then
if not isServer() then
OxPlayer = Ox.GetPlayer()
end
end
-------------------------------------------------------------
-- Resource Variables for Items, Jobs, and Vehicles
-------------------------------------------------------------
local itemResource, jobResource, vehResource = "", "", ""
-------------------------------------------------------------
-- Loading Items
-------------------------------------------------------------
-- Load and compile shared items from the detected inventory system.
if isStarted(OXInv) then
itemResource = OXInv
Items = exports[OXInv]:Items()
-- Add weapons to Items from QBXCore if available
if isStarted(QBXExport) then
local tempWeapons = exports[QBExport]:GetCoreObject().Shared.Weapons
for k, v in pairs(tempWeapons) do
local tempWeaponInfo = exports[OXInv]:Items(v.name)
local weight = 0
if tempWeaponInfo then
weight = tempWeaponInfo.weight
end
if not Items[v.name] then
Items[v.name] = {
name = v.name,
label = v.label,
type = "weapon",
ammotype = v.ammotype or "AMMO_PISTOL",
weight = weight,
image = v.image or (v.name..".png"),
description = v.label or "",
}
end
end
end
for k, v in pairs(Items) do
if v.client and v.client.image then
Items[k].image = (v.client.image):gsub("nui://"..OXInv.."/web/images/", "")
else
Items[k].image = k..".png"
end
Items[k].hunger = v.client and v.client.hunger or nil
Items[k].thirst = v.client and v.client.thirst or nil
end
elseif isStarted(QBExport) then
itemResource = QBExport
Core = Core or exports[QBExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
CreateThread(function()
while not Items or not next(Items) do
Items = exports[QBExport]:GetCoreObject().Shared.Items
Wait(1000)
end
end)
if isStarted(QBExport) and not isStarted(QBXExport) then
RegisterNetEvent('QBCore:Client:UpdateObject', function()
Core = Core or exports[QBExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
end)
end
elseif isStarted(ESXExport) then
itemResource = ESXExport
CreateThread(function()
if isServer() then
Items = ESX.GetItems()
while not createCallback do Wait(100) end
createCallback(getScript()..":getItems", function(source)
return Items
end)
end
if not isServer() then
Items = triggerCallback(getScript()..":getItems")
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7"..itemResource)
end
end)
elseif isStarted(RSGExport) then
itemResource = RSGExport
Core = Core or exports[RSGExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
RegisterNetEvent('RSGCore:Client:UpdateObject', function()
Core = Core or exports[RSGExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
end)
end
if itemResource == nil then
print("^4ERROR^7: ^2No Item info detected ^7- ^2Check ^3starter^1.^2lua^7")
else
while not Items do Wait(100) end
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7"..itemResource)
end
-------------------------------------------------------------
-- Loading Vehicles
-------------------------------------------------------------
-- Compile vehicles from the detected frameworks into a unified table.
if isStarted(QBXExport) or isStarted(QBExport) then
vehResource = QBExport
Core = Core or exports[QBExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
if isStarted(QBExport) and not isStarted(QBXExport) then
RegisterNetEvent('QBCore:Client:UpdateObject', function()
Core = Core or exports[QBExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
end)
end
elseif isStarted(RSGExport) then
Core = Core or exports[RSGExport]:GetCoreObject()
end
elseif isStarted(OXCoreExport) then
vehResource = OXCoreExport
Vehicles = {}
for k, v in pairs(Ox.GetVehicleData()) do
Vehicles[k] = { model = k, hash = GetHashKey(k), price = v.price, name = v.name, brand = v.make }
end
elseif isStarted(ESXExport) then
vehResource = ESXExport
if IsDuplicityVersion() then
CreateThread(function()
if isServer() then
createCallback(getScript()..":getVehiclesPrices", function(source)
return Vehicles
end)
while not MySQL do Wait(2000) print("^1Waiting for MySQL to exist") end
Vehicles = MySQL.query.await('SELECT model, price, name FROM vehicles')
local cache = nil
local timeout = GetGameTimer() + 5000 -- 5 seconds max wait
-- Wait until jim_bridge is started and export is available
while not cache and GetGameTimer() < timeout do
if GetResourceState("jim_bridge"):find("start") then
local success, result = pcall(function()
return exports["jim_bridge"]:GetSharedData()
end)
if success and result then
cache = result
--print(json.encode(cache, {indent = true}))
end
end
Wait(100)
end
if not isServer() then
--while not triggerCallback do print("waiting") Wait(100) end
local TempVehicles = triggerCallback(getScript()..":getVehiclesPrices")
for _, v in pairs(TempVehicles) do
Vehicles = Vehicles or {}
if not cache then
print("^1ERROR^7: ^2jim_bridge export not available after timeout^7.")
return
end
Items = cache.Items
Vehicles = cache.Vehicles
Jobs = cache.Jobs
Gangs = cache.Gangs
debugPrint("^6Bridge^7: ^2Shared cache successfully loaded from export^7.")
end)
else
local hasCache = false
-- 🔹 Client Side: Request from server
_G.__jimBridgeDataCache = {}
RegisterNetEvent("jim_bridge:receiveCache", function(data)
if not hasCache then
_G.__jimBridgeDataCache = data
hasCache = true
else
return
end
end)
TriggerServerEvent("jim_bridge:requestCache")
CreateThread(function()
while not _G.__jimBridgeDataCache or not next(_G.__jimBridgeDataCache) do Wait(50) end
local cache = _G.__jimBridgeDataCache
Items = cache.Items or {}
Vehicles = cache.Vehicles or {}
Jobs = cache.Jobs or {}
Gangs = cache.Gangs or {}
if isStarted(ESXExport) then
for _, v in pairs(Vehicles) do
Vehicles[v.model] = {
model = v.model,
hash = GetHashKey(v.model),
hash = v.hash,
price = v.price,
name = v.name,
brand = GetMakeNameFromVehicleModel(v.model):lower():gsub("^%l", string.upper)
}
end
end
end)
elseif isStarted(RSGExport) then
vehResource = RSGExport
Core = Core or exports[RSGExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
RegisterNetEvent('RSGCore:Client:UpdateObject', function()
Core = Core or exports[RSGExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
end)
end
if vehResource == nil then
print("^4ERROR^7: ^2No Vehicle info detected ^7- ^2Check ^3starter^1.^2lua^7")
else
while not Vehicles do Wait(1000) end
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..vehResource)
end
-------------------------------------------------------------
-- Loading Jobs and Gangs
-------------------------------------------------------------
-- Compile jobs and gangs from the detected framework.
if isStarted(QBXExport) then
jobResource = QBXExport
Core = Core or exports[QBExport]:GetCoreObject()
Jobs, Gangs = exports[QBXExport]:GetJobs(), exports[QBXExport]:GetGangs()
elseif isStarted(OXCoreExport) then
jobResource = OXCoreExport
CreateThread(function()
if isServer() then
Jobs = {}
createCallback(getScript()..":getOxGroups", function(source)
return Jobs
end)
local tempJobs = MySQL.query.await('SELECT * FROM `ox_groups`')
local tempGrades = MySQL.query.await('SELECT * FROM `ox_group_grades`')
-- Index all grades by group
local gradeMap = {}
for _, grade in pairs(tempGrades) do
gradeMap[grade.group] = gradeMap[grade.group] or {}
gradeMap[grade.group][grade.grade] = {
name = grade.label
}
end
-- Process jobs and attach grades
for _, job in pairs(tempJobs) do
Jobs[job.name] = {
label = job.label,
grades = gradeMap[job.name] or {}
}
end
-- Copy to Gangs
Gangs = Jobs
else
Jobs = triggerCallback(getScript()..":getOxGroups")
Gangs = Jobs
end
end)
elseif isStarted(QBExport) then
jobResource = QBExport
Core = Core or exports[QBExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
if isStarted(QBExport) and not isStarted(QBXExport) then
RegisterNetEvent('QBCore:Client:UpdateObject', function()
Core = exports[QBExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
end)
end
elseif isStarted(ESXExport) then
jobResource = ESXExport
if isServer() then
-- If server, create callback to get jobs
createCallback(getScript()..":getESXJobs", function(source)
return Jobs
end)
-- Populate jobs table with ESX.GetJobs()
Jobs = ESX.GetJobs()
--jsonPrint(Jobs)
--If retreived jobs is empty, wait for ESX to load
while countTable(Jobs) == 0 do
Jobs = ESX.GetJobs()
Wait(100)
end
-- Organise into a table the script can use
for Role, Grades in pairs(Jobs) do
-- Check for "Boss" in name of grades
for grade, info in pairs(Grades.grades) do
--print(grade)
--jsonPrint(info)
if info.label then
--print(info)
if info.label:find("boss") or info.label:find("Boss") then
--print("Found Boss label for:", Grades.label)
Jobs[Role].grades[grade].isBoss = true
goto continue
end
end
end
-- If no roles with "boss" in the name, revert to max grade
-- Count grades
local count = countTable(Grades.grades)
Jobs[Role].grades[tostring(count-1)].isBoss = true
--print(Grades.label.." Grade: "..count.." is Boss")
::continue::
end
-- ESX Default doesn't have gangs, so copy jobs to gangs
Gangs = Jobs
end
-- If client side, trigger callback to get jobs
if not isServer() then
Jobs = triggerCallback(getScript()..":getESXJobs")
Gangs = Jobs
end
elseif isStarted(RSGExport) then
jobResource = RSGExport
Core = Core or exports[RSGExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
RegisterNetEvent('RSGCore:Client:UpdateObject', function()
Core = exports[RSGExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
end)
end
if jobResource == nil then
print("^4ERROR^7: ^2No Job info detected ^7- ^2Check ^3starter^1.^2lua^7")
else
while not Jobs do Wait(1000) end
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Jobs).." ^3Jobs^2 from ^7"..jobResource)
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Gangs).." ^3Gangs^2 from ^7"..jobResource)
end