lr_boilerplate/main.lua

427 lines
12 KiB
Lua
Raw Normal View History

2023-12-11 14:13:07 +07:00
Framework = nil
2023-12-27 07:14:37 +07:00
if Config.Framework == 'esx' then
2023-12-11 14:13:07 +07:00
Framework = exports["es_extended"]:getSharedObject()
2023-12-27 07:14:37 +07:00
elseif Config.Framework == "qb" then
2023-12-11 14:13:07 +07:00
Framework = exports['qb-core']:GetCoreObject()
2024-02-28 16:11:14 +07:00
elseif Config.Framework == "ProjectStarboy" then
Framework = CORE
2023-12-27 07:14:37 +07:00
else
Framework = {}
Framework.Functions = {}
Framework.Functions.GetPlayerData = function()
return {}
end
2023-12-11 14:13:07 +07:00
end
2024-04-08 12:37:20 +07:00
---@class Main
---@field impls table<string, Impl>
---@field initializedImpls table<string, Impl>
2023-12-05 13:55:38 +07:00
Main = {}
2023-12-10 04:48:31 +07:00
ResourceName = GetCurrentResourceName()
local RegisteredEvents = {}
2023-12-27 07:14:37 +07:00
if IsDuplicityVersion() then
2023-12-05 13:55:38 +07:00
function GetGameTimer()
return os.clock() * 1000
end
2023-12-10 04:48:31 +07:00
else
RegisterNUICallback('AppReady', function(data, cb)
2024-01-12 17:45:08 +07:00
cb(Config.Settings or {})
2023-12-10 04:48:31 +07:00
NuiReady = true
end)
2023-12-05 13:55:38 +07:00
end
2024-04-08 12:37:20 +07:00
---Init main class
---@return Main
2023-12-05 13:55:38 +07:00
function Main:Init()
local o = {}
2023-12-27 07:14:37 +07:00
setmetatable(o, { __index = Main })
2023-12-05 13:55:38 +07:00
o.impls = {}
2023-12-05 15:00:07 +07:00
o.initializedImpls = {}
2023-12-05 13:55:38 +07:00
o.lastTimeImplRegistered = 0
2024-02-20 10:37:12 +07:00
o.onReadyCallbacks = {}
2023-12-05 13:55:38 +07:00
o.ready = false
if not IsDuplicityVersion() then
o.playerId = PlayerId()
o.playerPed = PlayerPedId()
o.playerCoords = GetEntityCoords(o.playerPed)
o.playerHeading = GetEntityHeading(o.playerPed)
2023-12-10 04:48:31 +07:00
o.playerServerId = GetPlayerServerId(o.playerId)
2023-12-05 13:55:38 +07:00
o:Thread1()
2023-12-10 04:48:31 +07:00
else
2024-04-08 12:37:20 +07:00
o.ClientImpls = {}
for k, v in pairs(Config.EnableModules) do
if v then
local path = "client/impl/" .. k .. ".impl.lua"
local source = LoadResourceFile(ResourceName, path)
if source == nil then
self:LogWarning("Failed to load %s", path)
else
--[[ self:LogInfo("Loading %s", path)
self:LogInfo("Loaded %s", source) ]]
o.ClientImpls[k] = source
2023-12-10 04:48:31 +07:00
end
end
end
2024-04-08 12:37:20 +07:00
lib.callback.register(ResourceName .. ":getClientImpl", function(source, implName)
return o.ClientImpls[implName]
end)
2023-12-05 13:55:38 +07:00
end
o:Exports()
2023-12-10 04:48:31 +07:00
o:RegisterCommands()
o:RegisterEvents()
2023-12-05 13:55:38 +07:00
return o
end
2023-12-27 07:14:37 +07:00
2024-02-20 10:37:12 +07:00
function Main:ListenOnReady(handler)
if self.ready then return handler() end
table.insert(self.onReadyCallbacks, handler)
end
2023-12-05 13:55:38 +07:00
if not IsDuplicityVersion() then
function Main:Thread1()
2024-04-08 12:37:20 +07:00
self.playerServerId = GetPlayerServerId(self.playerId)
2023-12-05 13:55:38 +07:00
Citizen.CreateThread(function()
while true do
self.playerId = PlayerId()
self.playerPed = PlayerPedId()
self.playerCoords = GetEntityCoords(self.playerPed)
self.playerHeading = GetEntityHeading(self.playerPed)
Citizen.Wait(1000)
end
end)
end
end
2023-12-10 04:48:31 +07:00
function Main:RegisterCommands()
if not IsDuplicityVersion() then
2023-12-27 07:14:37 +07:00
RegisterCommand("toggledebug:" .. ResourceName, function(source, args, rawCommand)
2023-12-10 04:48:31 +07:00
Config.Debug = not Config.Debug
self:LogInfo("Debug %s", Config.Debug)
2023-12-27 07:14:37 +07:00
end, false)
RegisterCommand("toggledev:" .. ResourceName, function(source, args, rawCommand)
2023-12-10 04:48:31 +07:00
Config.Dev = not Config.Dev
self:LogInfo("Dev %s", Config.Dev)
SendNUIMessage({
action = "updateServerState",
data = {
isDev = Config.Dev,
}
})
2023-12-27 07:14:37 +07:00
end, false)
RegisterCommand("implinfo:" .. ResourceName, function(source, args, rawCommand)
2023-12-10 04:48:31 +07:00
self:ImplInfo()
2023-12-27 07:14:37 +07:00
end, false)
2023-12-10 04:48:31 +07:00
RegisterCommand("test", function()
TriggerEvent("test")
2023-12-27 07:14:37 +07:00
end, false)
2023-12-10 04:48:31 +07:00
else
2023-12-27 07:14:37 +07:00
RegisterCommand("reload:" .. ResourceName, function(source, args, rawCommand)
if Config.ClientLazyLoad == false then return print("Lazyload was disabled") end
2023-12-10 04:48:31 +07:00
local implName = args[1]
local mode = args[2]
2023-12-27 07:14:37 +07:00
if mode == nil then
2023-12-10 04:48:31 +07:00
mode = "0"
end
self:LogInfo("Restarting impl: %s | side: %s (0: both, 1: client, 2: server)", implName, mode)
if mode == "0" or mode == "2" then
local svImpl = self:GetImpl(implName)
if svImpl then
svImpl:Destroy()
self.impls[implName] = nil
self.initializedImpls[implName] = nil
end
local source = LoadResourceFile(ResourceName, "server/impl/" .. implName .. ".impl.lua")
if source == nil then
2024-04-08 12:37:20 +07:00
self:LogWarning("Failed to load %s", ResourceName, "server/impl/" .. implName .. ".impl.lua")
2023-12-10 04:48:31 +07:00
else
self:LogInfo("Loading %s", implName)
load(source)()
end
end
if mode == "0" or mode == "1" then
local clSource = LoadResourceFile(ResourceName, "client/impl/" .. implName .. ".impl.lua")
if clSource == nil then
2024-04-08 12:37:20 +07:00
self:LogWarning("Failed to load %s", ResourceName, "client/impl/" .. implName .. ".impl.lua")
2023-12-10 04:48:31 +07:00
else
self:LogInfo("Loading %s", "client/impl/" .. implName .. ".impl.lua")
2023-12-27 07:14:37 +07:00
TriggerClientEvent(ResourceName .. ":restartClientImpl", -1, implName, clSource)
2023-12-10 04:48:31 +07:00
end
end
end, true)
end
end
function Main:RegisterEvents()
2023-12-27 07:14:37 +07:00
RegisterNetEvent(ResourceName .. ":restartClientImpl", function(implName, source)
2023-12-10 04:48:31 +07:00
local clImpl = self:GetImpl(implName)
if clImpl then
clImpl:Destroy()
self.impls[implName] = nil
self.initializedImpls[implName] = nil
end
load(source)()
end)
end
2023-12-05 13:55:38 +07:00
function Main:LogError(msg, ...)
print(("[^1ERROR^0] " .. msg):format(...))
end
function Main:LogWarning(msg, ...)
print(("[^3WARNING^0] " .. msg):format(...))
end
function Main:LogSuccess(msg, ...)
if not Config.Debug then return end
print(("[^2INFO^0] " .. msg):format(...))
end
function Main:LogInfo(msg, ...)
if not Config.Debug then return end
print(("[^5INFO^0] " .. msg):format(...))
end
function Main:CheckValidImpl(name, impl)
if not impl then
self:LogError("Impl %s is nil", name)
return false
end
if not impl.Init then
self:LogError("Impl %s missing Init function", name)
return false
end
return true
end
function Main:RegisterImpl(name, impl)
2024-01-15 10:46:41 +07:00
if impl.implType == "impl" and (Config.EnableModules[name] == nil or not Config.EnableModules[name].enabled) then
2023-12-10 04:48:31 +07:00
self:LogWarning("Impl %s not enabled", name)
return
end
2023-12-05 13:55:38 +07:00
if self.impls[name] then
self:LogWarning("Impl %s already registered", name)
return
end
if not self:CheckValidImpl(name, impl) then
return
end
self.impls[name] = impl
self.lastTimeImplRegistered = GetGameTimer()
2023-12-27 07:14:37 +07:00
2023-12-05 13:55:38 +07:00
self:LogSuccess("Impl %s registered", name)
2023-12-27 07:14:37 +07:00
if self.ready then
2023-12-10 04:48:31 +07:00
Citizen.CreateThread(function()
self:LogSuccess("Impl %s hot reloading", name)
Wait(1000)
self.initializedImpls[name] = impl(self)
if not self.initializedImpls[name] then
self:LogError("Impl %s failed to hot reload", name)
return
end
self.initializedImpls[name]:OnReady()
self:LogSuccess("Impl %s hot reloaded", name)
end)
2023-12-05 13:55:38 +07:00
end
end
function Main:InitImpl()
2024-02-24 09:53:57 +07:00
if Config.Dependencies then
for k, v in ipairs(Config.Dependencies) do
local p = promise.new()
TriggerEvent(('%s:onReady'):format(v), function()
p:resolve()
end)
Citizen.Await(p)
end
end
2023-12-27 07:14:37 +07:00
if not IsDuplicityVersion() then
if Config.ClientLazyLoad then
for k, v in pairs(Config.EnableModules) do
if v.enabled and v.priority == 1 and v.client then
self:LogInfo("Loading %s", k)
local source = lib.callback.await(ResourceName .. ":getClientImpl", false, k)
if source ~= nil then
self:LogInfo("Loaded %s", k)
load(source)()
end
2023-12-11 15:06:29 +07:00
end
2023-12-10 04:48:31 +07:00
end
2023-12-27 07:14:37 +07:00
for name, impl in pairs(self.impls) do
2024-01-15 10:46:41 +07:00
if impl.implType ~= "impl" or (Config.EnableModules[name] and Config.EnableModules[name].priority == 1) then
2023-12-27 07:14:37 +07:00
self.initializedImpls[name] = impl(self)
end
2023-12-13 00:21:40 +07:00
end
2023-12-27 07:14:37 +07:00
self:LogInfo("All priority 1 initialized")
for name, impl in pairs(self.initializedImpls) do
2024-01-15 10:46:41 +07:00
if impl.implType ~= "impl" or (Config.EnableModules[name] and Config.EnableModules[name].priority == 1) then
2023-12-27 07:14:37 +07:00
impl:OnReady()
end
end
else
for name, impl in pairs(self.impls) do
2024-01-15 10:46:41 +07:00
if impl.implType ~= "impl" or (Config.EnableModules[name] and Config.EnableModules[name].priority == 1) then
2023-12-27 07:14:37 +07:00
self.initializedImpls[name] = impl(self)
end
end
self:LogInfo("All priority 1 initialized")
for name, impl in pairs(self.initializedImpls) do
2024-01-15 10:46:41 +07:00
if impl.implType ~= "impl" or (Config.EnableModules[name] and Config.EnableModules[name].priority == 1) then
2023-12-27 07:14:37 +07:00
impl:OnReady()
end
2023-12-13 00:21:40 +07:00
end
end
else
for name, impl in pairs(self.impls) do
self.initializedImpls[name] = impl(self)
end
for name, impl in pairs(self.initializedImpls) do
impl:OnReady()
end
2023-12-10 04:48:31 +07:00
end
2023-12-13 00:21:40 +07:00
end
function Main:InitImplAfterPlayerLoaded()
2023-12-27 07:14:37 +07:00
if not IsDuplicityVersion() then
2023-12-13 00:21:40 +07:00
for k, v in pairs(Config.EnableModules) do
if v.enabled and v.priority == 2 and v.client then
self:LogInfo("Loading %s", k)
2023-12-27 07:14:37 +07:00
if Config.ClientLazyLoad then
local source = lib.callback.await(ResourceName .. ":getClientImpl", false, k)
if source ~= nil then
self:LogInfo("Loaded %s", k)
load(source)()
end
else
if self.initializedImpls[k] then
self.initializedImpls[k]:OnReady()
end
2023-12-13 00:21:40 +07:00
end
end
end
for name, impl in pairs(self.impls) do
if Config.EnableModules[name] and Config.EnableModules[name].priority == 2 then
self.initializedImpls[name] = impl(self)
end
end
self:LogInfo("All priority 2 initialized")
for name, impl in pairs(self.initializedImpls) do
if Config.EnableModules[name] and Config.EnableModules[name].priority == 2 then
impl:OnReady()
end
end
2023-12-10 04:48:31 +07:00
SendNUIMessage({
action = "updateServerState",
data = {
isDev = Config.Dev,
}
})
end
2023-12-13 00:21:40 +07:00
self.ready = true
2024-02-20 10:37:12 +07:00
for k, v in ipairs(self.onReadyCallbacks) do
v()
end
self.onReadyCallbacks = {}
2023-12-05 13:55:38 +07:00
end
function Main:GetImpl(name)
2023-12-05 15:00:07 +07:00
if not self.initializedImpls[name] then
2023-12-05 13:55:38 +07:00
self:LogError("Impl %s not found", name)
return
end
2023-12-05 15:00:07 +07:00
return self.initializedImpls[name]
2023-12-05 13:55:38 +07:00
end
function Main:ImplCall(name, func, ...)
local impl = self:GetImpl(name)
if not impl then
return
end
if not impl[func] then
2023-12-27 07:14:37 +07:00
self:LogError("Impl %s missing function %s - args %s", name, func, json.encode({ ... }))
2023-12-05 13:55:38 +07:00
return
end
return impl[func](impl, ...)
end
function Main:ImplInfo()
for name, impl in pairs(self.impls) do
2023-12-10 04:48:31 +07:00
local debug = debug.getinfo(impl.OnReady, "S")
2023-12-05 13:55:38 +07:00
self:LogInfo("Impl %s - %s", name, debug.short_src)
end
end
function Main:Exports()
exports("ImplCall", function(name, func, ...)
return self:ImplCall(name, func, ...)
end)
end
main = Main:Init()
2024-02-24 09:53:57 +07:00
AddEventHandler(("%s:onReady"):format(GetCurrentResourceName()), function(handler)
local invokingResource = GetInvokingResource()
main:LogInfo(invokingResource)
2024-02-20 10:37:12 +07:00
main:ListenOnReady(handler)
end)
2024-01-15 10:46:41 +07:00
--[[ local origAddEventHandler = AddEventHandler
2023-12-10 04:48:31 +07:00
function AddEventHandler(eventName, ...)
2023-12-27 07:14:37 +07:00
if RegisteredEvents[eventName] then
2023-12-10 04:48:31 +07:00
main:LogWarning("Event %s already registered. Removing", eventName)
RemoveEventHandler(RegisteredEvents[eventName])
end
RegisteredEvents[eventName] = origAddEventHandler(eventName, ...)
2023-12-27 07:14:37 +07:00
return RegisteredEvents[eventName]
2023-12-10 04:48:31 +07:00
end
local origRegisterNetEvent = RegisterNetEvent
function RegisterNetEvent(eventName, ...)
2023-12-27 07:14:37 +07:00
if RegisteredEvents[eventName] then
2023-12-10 04:48:31 +07:00
main:LogWarning("Event %s already registered. Removing", eventName)
RemoveEventHandler(RegisteredEvents[eventName])
end
RegisteredEvents[eventName] = origRegisterNetEvent(eventName, ...)
2023-12-27 07:14:37 +07:00
return RegisteredEvents[eventName]
2024-01-15 10:46:41 +07:00
end ]]
2023-12-10 04:48:31 +07:00
2023-12-05 13:55:38 +07:00
Citizen.CreateThread(function()
while GetGameTimer() < main.lastTimeImplRegistered + 1000 do
Citizen.Wait(0)
end
2023-12-27 07:14:37 +07:00
while Framework == nil do
2023-12-11 15:06:29 +07:00
main:LogInfo("Waiting for Framework")
2023-12-10 04:48:31 +07:00
Wait(100)
2024-04-11 15:31:34 +07:00
if Config.Framework == 'esx' then
Framework = exports["es_extended"]:getSharedObject()
elseif Config.Framework == "qb" then
Framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == "ProjectStarboy" then
Framework = CORE
else
Framework = {}
Framework.Functions = {}
Framework.Functions.GetPlayerData = function()
return {}
end
end
2023-12-10 04:48:31 +07:00
end
2023-12-13 00:21:40 +07:00
main:InitImpl()
2023-12-10 04:48:31 +07:00
if not IsDuplicityVersion() then
2023-12-11 14:13:07 +07:00
if Config.Framework == 'esx' then
2023-12-27 07:14:37 +07:00
while not Framework.IsPlayerLoaded() do
2023-12-11 14:13:07 +07:00
Wait(100)
end
2023-12-27 07:14:37 +07:00
elseif Config.Framework == 'qb' then
2023-12-11 14:13:07 +07:00
local player = Framework.Functions.GetPlayerData()
2023-12-27 07:14:37 +07:00
while player == nil do
2023-12-11 14:13:07 +07:00
Wait(100)
player = Framework.Functions.GetPlayerData()
end
2023-12-10 04:48:31 +07:00
end
2023-12-27 07:14:37 +07:00
while not NuiReady and Config.Nui do
2023-12-10 04:48:31 +07:00
Wait(100)
end
end
2023-12-13 00:21:40 +07:00
main:InitImplAfterPlayerLoaded()
2023-12-05 13:55:38 +07:00
end)