diff --git a/fxmanifest.lua b/fxmanifest.lua index 9c0f698..6f71174 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -1,9 +1,10 @@ -name "Jim_Bridge" +name "Jim_RedBridge" author "Jimathy" version "2.0" description "Framework Bridge By Jimathy" fx_version "cerulean" -game "gta5" +rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' +games { 'gta5', 'rdr3' } lua54 'yes' files { diff --git a/shared/_loaders.lua b/shared/_loaders.lua index c92a227..20d1fc4 100644 --- a/shared/_loaders.lua +++ b/shared/_loaders.lua @@ -53,6 +53,9 @@ function onPlayerLoaded(func, onStart) elseif isStarted(OXCoreExport) then onPlayerFramework = OXCoreExport AddEventHandler('ox:playerLoaded', tempFunc) + elseif isStarted(RSGExport) then + onPlayerFramework = RSGExport + AddEventHandler('RSGCore:Client:OnPlayerLoaded', tempFunc) end if onPlayerFramework ~= "" then @@ -75,6 +78,7 @@ end function onPlayerUnload(func) AddEventHandler('QBCore:Client:OnPlayerUnload', function() func() end) AddEventHandler('ox:playerLogout', function() func() end) + AddEventHandler('RSGCore:Client:OnPlayerUnload', function() func() end) --AddEventHandler('esx:playerLogout', function() func() end) -- ^ Only server side for now, need a way to send it to client if not already available diff --git a/shared/coreloader.lua b/shared/coreloader.lua index 5b1d086..b81a659 100644 --- a/shared/coreloader.lua +++ b/shared/coreloader.lua @@ -36,6 +36,10 @@ OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv = Exports.CodeMInv or "", Exports.OrigenInv or "" +RSGExport, RSGInv = + Exports.RSGExport or "", + Exports.RSGInv or "" + QBMenuExport = Exports.QBMenuExport or "" QBTargetExport, OXTargetExport = Exports.QBTargetExport or "", Exports.OXTargetExport or "" @@ -112,6 +116,18 @@ elseif isStarted(ESXExport) then 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 + if isStarted(RSGExport) and not isStarted(QBXExport) then + RegisterNetEvent('QBCore:Client:UpdateObject', function() + Core = Core or exports[RSGExport]:GetCoreObject() + Items = Core and Core.Shared.Items or nil + end) + end + end if not isStarted(ESXExport) then @@ -167,6 +183,17 @@ elseif isStarted(ESXExport) then end end end) + +elseif isStarted(RSGExport) then + Core = Core or exports[RSGExport]:GetCoreObject() + Vehicles = Core and Core.Shared.Vehicles + if isStarted(RSGExport) then + RegisterNetEvent('RSGExport:Client:UpdateObject', function() + Core = Core or exports[RSGExport]:GetCoreObject() + Vehicles = Core and Core.Shared.Vehicles + end) + end + vehResource = RSGExport end if vehResource == nil then @@ -239,6 +266,17 @@ elseif isStarted(ESXExport) then Gangs = Jobs end end) + +elseif isStarted(RSGExport) then + jobResource = RSGExport + Core = Core or exports[RSGExport]:GetCoreObject() + Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs + if isStarted(RSGExport) and not isStarted(QBXExport) then + RegisterNetEvent('QBCore:Client:UpdateObject', function() + Core = exports[RSGExport]:GetCoreObject() + Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs + end) + end end if not isStarted(ESXExport) and Jobs then diff --git a/shared/drawText.lua b/shared/drawText.lua index 6d6fd85..17a30fb 100644 --- a/shared/drawText.lua +++ b/shared/drawText.lua @@ -71,6 +71,16 @@ function drawText(image, input, style, oxStyleTable) icon = nil, text = text, }) + + elseif Config.System.drawText == "red" then + -- Concatenate input lines and apply GTA style formatting. + for i = 1, #input do + if input[i] ~= "" then + text = text..input[i].."\n~q~" + end + end + TriggerEvent("jim-redui:DrawText", text) + end end @@ -91,5 +101,7 @@ function hideText() ClearAllHelpMessages() elseif Config.System.drawText == "esx" then ESX.HideUI() + elseif Config.System.drawText == "red" then + TriggerEvent("jim-redui:HideText") end end \ No newline at end of file diff --git a/shared/duifunctions.lua b/shared/duifunctions.lua index ff5d777..ea9ffc1 100644 --- a/shared/duifunctions.lua +++ b/shared/duifunctions.lua @@ -1,165 +1,168 @@ +if gameName ~= "rdr3" then --[[ - DUI Module (Experimental) - -------------------------- - This module handles the creation, modification, and removal of custom DUI (Display UI) - elements using runtime textures. It supports both client and server functionality to update DUI - images dynamically. -]] + DUI Module (Experimental) + -------------------------- + This module handles the creation, modification, and removal of custom DUI (Display UI) + elements using runtime textures. It supports both client and server functionality to update DUI + images dynamically. + ]] --- Create a runtime texture dictionary on the client if not running on the server. -scriptTxd = not isServer() and CreateRuntimeTxd(getScript()..'scriptTxd') or nil -customDUIList = {} + -- Create a runtime texture dictionary on the client if not running on the server. + scriptTxd = not isServer() and CreateRuntimeTxd(getScript()..'scriptTxd') or nil + customDUIList = {} -------------------------------------------------------------- --- DUI Client Functions -------------------------------------------------------------- + ------------------------------------------------------------- + -- DUI Client Functions + ------------------------------------------------------------- ---- Creates or updates a DUI element. ---- ---- @param name string The unique name for the DUI element. ---- @param http string The URL to load into the DUI. ---- @param size table A table with .x and .y fields specifying the DUI dimensions. ---- @param txd table The runtime texture dictionary where the DUI texture will be created. ---- @usage ---- ```lua ---- createDui("logo", "https://example.com/logo.png", { x = 512, y = 256 }, scriptTxd) ---- ``` -function createDui(name, http, size, txd) - if not customDUIList[name] then - local newDui = CreateDui(http, math.floor(size.x), math.floor(size.y)) - while not GetDuiHandle(newDui) do Wait(0) end - CreateRuntimeTextureFromDuiHandle(txd, name, GetDuiHandle(newDui)) - customDUIList[name] = newDui - SetDuiUrl(customDUIList[name], http) - else - SetDuiUrl(customDUIList[name], http) - end -end - ---- Opens a DUI selection input allowing the user to change the DUI image URL. ---- ---- @param data table A table containing DUI data: ---- - name: The key name in the DUI list. ---- - texn: The texture name. ---- - texd: The texture dictionary. ---- - size: A table with .x and .y dimensions. ---- ---- @usage ---- ```lua ---- DuiSelect({ name = "logo", texn = "logoTex", texd = "someTxd", size = { x = 512, y = 256 } }) ---- ``` -function DuiSelect(data) - local imagePreview = "" - for k, v in pairs(duiList[data.name]) do - if v.tex.texn == data.texn and duiList[data.name][k] then - imagePreview = "
- Current Image -
" .. - "
" .. - "Size: ["..math.floor(data.size.x)..", "..math.floor(data.size.y).."]

" + --- Creates or updates a DUI element. + --- + --- @param name string The unique name for the DUI element. + --- @param http string The URL to load into the DUI. + --- @param size table A table with .x and .y fields specifying the DUI dimensions. + --- @param txd table The runtime texture dictionary where the DUI texture will be created. + --- @usage + --- ```lua + --- createDui("logo", "https://example.com/logo.png", { x = 512, y = 256 }, scriptTxd) + --- ``` + function createDui(name, http, size, txd) + if not customDUIList[name] then + local newDui = CreateDui(http, math.floor(size.x), math.floor(size.y)) + while not GetDuiHandle(newDui) do Wait(0) end + CreateRuntimeTextureFromDuiHandle(txd, name, GetDuiHandle(newDui)) + customDUIList[name] = newDui + SetDuiUrl(customDUIList[name], http) + else + SetDuiUrl(customDUIList[name], http) end end - local dialog = exports['qb-input']:ShowInput({ - header = imagePreview..Loc[Config.Lan].menu["dui_new"], - submitText = Loc[Config.Lan].menu["dui_change"], - inputs = { { type = 'text', isRequired = true, name = 'url', text = Loc[Config.Lan].menu["dui_url"] } } - }) - if dialog and dialog.url then - data.url = dialog.url - -- Scan URL for valid image extension and banned words. - local searchList = { "png", "jpg", "jpeg", "gif", "webp", "bmp" } - local banList = { "porn" } - local searchFound = false - for _, ext in pairs(searchList) do - if string.find(tostring(data.url), ext) then - searchFound = true - break - end - end - for _, banned in pairs(banList) do - if string.find(tostring(data.url), banned) then - searchFound = false - print("BANNED WORD: "..banned) - break - end - end - if searchFound then - TriggerServerEvent(getScript()..":Server:ChangeDUI", data) - end - end -end ---- Client event handler to update DUI elements. -RegisterNetEvent(getScript()..":Client:ChangeDUI", function(data) - debugPrint("^6Bridge^7: ^2Receiving new DUI ^7- ^6"..data.url.."^7") - if tostring(data.url) ~= "-" then - createDui(data.texn, tostring(data.url), data.size, scriptTxd) - AddReplaceTexture(tostring(data.texd), tostring(data.texn), getScript().."scriptTxd", tostring(data.texn)) - end -end) - ---- Client event handler to clear DUI elements. -RegisterNetEvent(getScript()..":Client:ClearDUI", function(data) - if customDUIList[tostring(data.texn)] then - RemoveReplaceTexture(tostring(data.texd), tostring(data.texn)) - if IsDuiAvailable(customDUIList[tostring(data.texn)]) then - SetDuiUrl(customDUIList[data.name], nil) - end - end -end) - -------------------------------------------------------------- --- DUI Server Functions -------------------------------------------------------------- - ---- Server event handler to change DUI settings. ---- If no URL is provided, resets to the preset value. -RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data) - if not data.url then + --- Opens a DUI selection input allowing the user to change the DUI image URL. + --- + --- @param data table A table containing DUI data: + --- - name: The key name in the DUI list. + --- - texn: The texture name. + --- - texd: The texture dictionary. + --- - size: A table with .x and .y dimensions. + --- + --- @usage + --- ```lua + --- DuiSelect({ name = "logo", texn = "logoTex", texd = "someTxd", size = { x = 512, y = 256 } }) + --- ``` + function DuiSelect(data) + local imagePreview = "" for k, v in pairs(duiList[data.name]) do - if v.tex.texn == data.texn then - debugPrint("^6Bridge^7: ^2Preset: ^6"..tostring(duiList[data.name][k].preset).."^7") - data.url = duiList[data.name][k].preset + if v.tex.texn == data.texn and duiList[data.name][k] then + imagePreview = "
- Current Image -
" .. + "
" .. + "Size: ["..math.floor(data.size.x)..", "..math.floor(data.size.y).."]

" + end + end + local dialog = exports['qb-input']:ShowInput({ + header = imagePreview..Loc[Config.Lan].menu["dui_new"], + submitText = Loc[Config.Lan].menu["dui_change"], + inputs = { { type = 'text', isRequired = true, name = 'url', text = Loc[Config.Lan].menu["dui_url"] } } + }) + if dialog and dialog.url then + data.url = dialog.url + -- Scan URL for valid image extension and banned words. + local searchList = { "png", "jpg", "jpeg", "gif", "webp", "bmp" } + local banList = { "porn" } + local searchFound = false + for _, ext in pairs(searchList) do + if string.find(tostring(data.url), ext) then + searchFound = true + break + end + end + for _, banned in pairs(banList) do + if string.find(tostring(data.url), banned) then + searchFound = false + print("BANNED WORD: "..banned) + break + end + end + if searchFound then + TriggerServerEvent(getScript()..":Server:ChangeDUI", data) end end end - for k, v in pairs(duiList[data.name]) do - if v.tex.texn == data.texn then - duiList[data.name][k].url = data.url + + --- Client event handler to update DUI elements. + RegisterNetEvent(getScript()..":Client:ChangeDUI", function(data) + debugPrint("^6Bridge^7: ^2Receiving new DUI ^7- ^6"..data.url.."^7") + if tostring(data.url) ~= "-" then + createDui(data.texn, tostring(data.url), data.size, scriptTxd) + AddReplaceTexture(tostring(data.texd), tostring(data.texn), getScript().."scriptTxd", tostring(data.texn)) end - end - debugPrint("^6Bridge^7: ^3DUI^2 Sending new DUI to all players^7 - ^6"..data.url.."^7") - TriggerClientEvent(getScript()..":Client:ChangeDUI", -1, data) -end) - ---- Server event handler to clear DUI settings. -RegisterNetEvent(getScript()..":Server:ClearDUI", function(data) - if data.url == "-" then - for k, v in pairs(duiList[data.name]) do - if v.tex.texn == data.texn then - duiList[data.name][k].url = "-" - end - end - end - TriggerClientEvent(getScript()..":Client:ClearDUI", -1, data) -end) - -------------------------------------------------------------- --- Resource Cleanup -------------------------------------------------------------- - -onResourceStop(function() - for k, v in pairs(duiList or {}) do - for i = 1, #v do - RemoveReplaceTexture(tostring(v[i].tex.texd), tostring(v[i].tex.texn)) - end - end -end, true) - -------------------------------------------------------------- --- DUI List Callback (Server) -------------------------------------------------------------- - -if isServer() then - createCallback(getScript()..":Server:duiList", function(source) - return duiList end) + + --- Client event handler to clear DUI elements. + RegisterNetEvent(getScript()..":Client:ClearDUI", function(data) + if customDUIList[tostring(data.texn)] then + RemoveReplaceTexture(tostring(data.texd), tostring(data.texn)) + if IsDuiAvailable(customDUIList[tostring(data.texn)]) then + SetDuiUrl(customDUIList[data.name], nil) + end + end + end) + + ------------------------------------------------------------- + -- DUI Server Functions + ------------------------------------------------------------- + + --- Server event handler to change DUI settings. + --- If no URL is provided, resets to the preset value. + RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data) + if not data.url then + for k, v in pairs(duiList[data.name]) do + if v.tex.texn == data.texn then + debugPrint("^6Bridge^7: ^2Preset: ^6"..tostring(duiList[data.name][k].preset).."^7") + data.url = duiList[data.name][k].preset + end + end + end + for k, v in pairs(duiList[data.name]) do + if v.tex.texn == data.texn then + duiList[data.name][k].url = data.url + end + end + debugPrint("^6Bridge^7: ^3DUI^2 Sending new DUI to all players^7 - ^6"..data.url.."^7") + TriggerClientEvent(getScript()..":Client:ChangeDUI", -1, data) + end) + + --- Server event handler to clear DUI settings. + RegisterNetEvent(getScript()..":Server:ClearDUI", function(data) + if data.url == "-" then + for k, v in pairs(duiList[data.name]) do + if v.tex.texn == data.texn then + duiList[data.name][k].url = "-" + end + end + end + TriggerClientEvent(getScript()..":Client:ClearDUI", -1, data) + end) + + ------------------------------------------------------------- + -- Resource Cleanup + ------------------------------------------------------------- + + onResourceStop(function() + for k, v in pairs(duiList or {}) do + for i = 1, #v do + RemoveReplaceTexture(tostring(v[i].tex.texd), tostring(v[i].tex.texn)) + end + end + end, true) + + ------------------------------------------------------------- + -- DUI List Callback (Server) + ------------------------------------------------------------- + + if isServer() then + createCallback(getScript()..":Server:duiList", function(source) + return duiList + end) + end + end \ No newline at end of file diff --git a/shared/inventories.lua b/shared/inventories.lua index ab4b07d..348cb65 100644 --- a/shared/inventories.lua +++ b/shared/inventories.lua @@ -148,6 +148,14 @@ function getPlayerInv(src) grabInv = xPlayer.inventory end + elseif isStarted(RSGInv) then + foundInv = RSGInv + if src then + grabInv = Core.Functions.GetPlayer(src).PlayerData.items + else + grabInv = Core.Functions.GetPlayerData().items + end + else print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3starter^1.^2lua^7") end diff --git a/shared/itemcontrol.lua b/shared/itemcontrol.lua index 7707b31..eb966f5 100644 --- a/shared/itemcontrol.lua +++ b/shared/itemcontrol.lua @@ -74,6 +74,8 @@ function invImg(item) imgLink = "nui://"..OrigenInv.."/html/img/"..(Items[item].image or "") elseif isStarted(QBInv) then imgLink = "nui://"..QBInv.."/html/images/"..(Items[item].image or "") + elseif isStarted(RSGInv) then + imgLink = "nui://"..RSGInv.."/html/images/"..(Items[item].image or "") else print("^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua") end @@ -99,12 +101,15 @@ end --- addItem("health_potion", 2, { quality = "high" }) --- ``` function addItem(item, amount, info, src) - if not Items[item] then print("^6Bridge^7: ^1Error^7 - ^2Tried to give ^7'^3"..item.."^7'^2 but it doesn't exist") return end + if not Items[item] then + print("^6Bridge^7: ^1Error^7 - ^2Tried to give ^7'^3"..item.."^7'^2 but it doesn't exist") + return + end if src then TriggerEvent(getScript()..":server:toggleItem", true, item, amount, src, info) else - TriggerServerEvent(getScript()..":server:toggleItem", true, item, amount, currentToken, info) + TriggerServerEvent(getScript()..":server:toggleItem", true, item, amount, nil, info, nil, currentToken) currentToken = nil -- clear client cached token end end @@ -129,6 +134,7 @@ function removeItem(item, amount, src, slot) end if src then + debugPrint(src) TriggerEvent(getScript()..":server:toggleItem", false, item, amount, src, nil, slot) else TriggerServerEvent(getScript()..":server:toggleItem", false, item, amount, nil, nil, slot) @@ -155,26 +161,33 @@ end --- ```lua --- TriggerServerEvent(getScript()..":server:toggleItem", true, "health_potion", 1) --- ``` -RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount, newsrc, info, slot) +RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount, newsrc, info, slot, token) + debugPrint(GetInvokingResource()) + if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then + debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7") + return + end if not Items[item] then print("^6Bridge^7: ^1Error^7 - ^2Tried to "..(tostring(give) == "true" and "add" or "remove").." '^3"..item.."^7' but it doesn't exist") return end - local src = source or newsrc + local src = newsrc or source if (give == true or give == 1) then if newsrc == nil then -- must be coming from client this would be blank - debugPrint("^1Auth^7: ^1No token recieved^7") - dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token") - else - if type(newsrc) ~= "number" then -- checks if the newsrc is a source or token, if number its coming form the server itself - debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..") - if newsrc ~= validTokens[src] then - debugPrint("^1Auth^7: ^1Tokens don't match! ^7", newsrc, validTokens[src]) - dupeWarn(src, item, "Auth: "..src.." attempted to spawn "..item.." with an incorrect auth token") - else - debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", newsrc, validTokens[src]) - validTokens[src] = nil + if token == nil then + debugPrint("^1Auth^7: ^1No token recieved^7") + dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token") + else + if type(token) ~= "number" then -- checks if the newsrc is a source or token, if number its coming form the server itself + debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..") + if token ~= validTokens[src] then + debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src]) + dupeWarn(src, item, "Auth: "..src.." attempted to spawn "..item.." with an incorrect auth token") + else + debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src]) + validTokens[src] = nil + end end end end @@ -230,6 +243,20 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount, if Config.Crafting.showItemBox then TriggerClientEvent("inventory:client:ItemBox", src, Items[item], "remove", amount or 1) end + + elseif isStarted(RSGInv) then invName = RSGInv + while remamount > 0 do + if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then + remamount -= 1 + else + print("^1Error removing "..item.." Amount left: "..remamount) + break + end + end + if Config.Crafting.showItemBox then + TriggerClientEvent("rsg-inventory:client:ItemBox", src, Items[item], "remove", amount or 1) + end + end ----- -- Fallback for if no inventory found: @@ -274,6 +301,11 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount, TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "add", amountToAdd) end + elseif isStarted(RSGInv) then invName = RSGInv + if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then + TriggerClientEvent("rsg-inventory:client:ItemBox", src, Items[item], "add", amountToAdd) + end + elseif isStarted(PSInv) then invName = PSInv if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then if Config.Crafting.showItemBox then @@ -601,7 +633,12 @@ function canCarry(itemTable, src) resultTable[k] = exports[OrigenInv]:canCarryItem(src, k, v) end - elseif isStarted(QBInv) or isStarted(PSInv) then + elseif isStarted(QBInv) then + for k, v in pairs(itemTable) do + resultTable[k] = exports[QBInv]:CanAddItem(src, k, v) + end + + elseif isStarted(PSInv) then local items = getPlayerInv(src) local totalWeight = 0 if not items then return false end @@ -616,6 +653,22 @@ function canCarry(itemTable, src) resultTable[k] = (totalWeight + (itemInfo.weight * v)) <= InventoryWeight end end + + elseif isStarted(RSGInv) then + local items = getPlayerInv(src) + local totalWeight = 0 + if not items then return false end + for _, item in pairs(items) do + totalWeight += (item.weight * item.amount) + end + for k, v in pairs(itemTable) do + local itemInfo = Items[k] + if not itemInfo then + resultTable[k] = true + else + resultTable[k] = (totalWeight + (itemInfo.weight * v)) <= InventoryWeight + end + end end end return resultTable @@ -637,6 +690,11 @@ if isServer() then createCallback(AuthEvent, function(source) local src = source local token = keyGen()..keyGen()..keyGen()..keyGen() -- Use a secure random generator here + debugPrint(GetInvokingResource()) + if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then + debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7") + return "" + end debugPrint("^1Auth^7:^2 Player Source^7: "..src.." ^2requested new token^7:", token) validTokens[src] = token timeOutAuth(validTokens[src], src) -- Give script 10 seconds, then clear token @@ -664,6 +722,11 @@ if isServer() then receivedEvent = {} createCallback(getScript()..":callback:GetAuthEvent", function(source) local src = source + debugPrint(GetInvokingResource()) + if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then + debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital callback was called from an external resource^7") + return "" + end debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent) if not receivedEvent[src] then receivedEvent[src] = true return AuthEvent @@ -673,8 +736,6 @@ if isServer() then end end) else - onResourceStart(function() - debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7") - AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent") - end, true) + debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7") + AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent") end diff --git a/shared/jobfunctions.lua b/shared/jobfunctions.lua index b338a3f..36cbb58 100644 --- a/shared/jobfunctions.lua +++ b/shared/jobfunctions.lua @@ -69,7 +69,7 @@ end function jobCheck(job) local canDo = true if Jobs[job] then - if not hasJob(job) or not onDuty then + if not hasJob(job) or not getPlayer().onDuty then triggerNotify(nil, Loc[Config.Lan].error["not_clockedin"]) canDo = false end @@ -92,10 +92,10 @@ end --- toggleDuty() -- Player receives a notification of their new duty status. --- ``` function toggleDuty() + onDuty = not onDuty if isStarted(QBExport) or isStarted(QBXExport) then TriggerServerEvent("QBCore:ToggleDuty") else - onDuty = not onDuty if onDuty then triggerNotify(nil, "Now on duty", "success") else diff --git a/shared/make/makeBlip.lua b/shared/make/makeBlip.lua index b773eae..52c9dbd 100644 --- a/shared/make/makeBlip.lua +++ b/shared/make/makeBlip.lua @@ -1,3 +1,5 @@ +local blipTable = {} + --- Creates a blip at specified coordinates with given properties. -- -- This function adds a map blip at the provided coordinates and sets various display properties such as sprite, color, scale, and more. @@ -30,31 +32,48 @@ -- local blip = makeBlip(blipData) -- ``` function makeBlip(data) - local blip = AddBlipForCoord(vec3(data.coords.x, data.coords.y, data.coords.z)) - SetBlipCoords(blip, data.coords.x, data.coords.y, data.coords.z) -- Manually set blip coordinates again as sometimes it just refuses - SetBlipAsShortRange(blip, true) - SetBlipSprite(blip, data.sprite or 106) - SetBlipColour(blip, data.col or 5) - SetBlipScale(blip, data.scale or 0.7) - SetBlipDisplay(blip, data.disp or 6) - if data.category then SetBlipCategory(blip, data.category) end - BeginTextCommandSetBlipName('STRING') - AddTextComponentString(tostring(data.name)) - EndTextCommandSetBlipName(blip) - -- Handle preview image if certain resources are running - if isStarted("fs_smallresources") or isStarted("blip_info") or isStarted("blipinfo") then - if data.preview then - local txname = string.gsub(tostring(data.name..'preview'..string.gsub(data.coords.z, "%.", "")), "[ ()~]", "") - if data.preview:find("http") or data.preview:find("nui") then - createDui(txname, data.preview, vec2(512, 256), scriptTxd) - else - CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview) + local blip = nil + if gameName == "rdr3" then + blip = BlipAddForCoords(1664425300, data.coords.x, data.coords.y, data.coords.z) + SetBlipSprite(blip, data.sprite or `blip_shop_market_stall`) + SetBlipScale(blip, data.scale or 0.2) + SetBlipName(blip, data.name) + --BlipSetStyle(blip, data.col or `BLIP_STYLE_CREATOR_DEFAULT`) + else + blip = AddBlipForCoord(vec3(data.coords.x, data.coords.y, data.coords.z)) + SetBlipCoords(blip, data.coords.x, data.coords.y, data.coords.z) -- Manually set blip coordinates again as sometimes it just refuses + SetBlipAsShortRange(blip, true) + SetBlipSprite(blip, data.sprite or 106) + SetBlipColour(blip, data.col or 5) + SetBlipScale(blip, data.scale or 0.7) + SetBlipDisplay(blip, data.disp or 6) + if data.category then + SetBlipCategory(blip, data.category) + end + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(tostring(data.name)) + EndTextCommandSetBlipName(blip) + -- Handle preview image if certain resources are running + if isStarted("fs_smallresources") or isStarted("blip_info") or isStarted("blipinfo") then + if data.preview then + local txname = string.gsub(tostring(data.name..'preview'..string.gsub(data.coords.z, "%.", "")), "[ ()~]", "") + if data.preview:find("http") or data.preview:find("nui") then + createDui(txname, data.preview, vec2(512, 256), scriptTxd) + else + CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview) + end + exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'scriptTxd', txname) + exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) end - exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'scriptTxd', txname) - exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) end end - debugPrint("^6Bridge^7: ^6Blip ^2created^7: '^6"..data.name.."^7' - '"..formatCoord(data.coords).."'") + blipTable[blip] = blip + + if DoesBlipExist(blip) then + debugPrint("^6Bridge^7: ^6Blip ^2created^7: '^6"..data.name.."^7' - '"..formatCoord(data.coords).."'") + else + print("Error making blip") + end return blip end @@ -90,30 +109,54 @@ end -- local blip = makeEntityBlip(blipData) -- ``` function makeEntityBlip(data) - AddBlipForEntity(data.entity) - local blip = GetBlipFromEntity(data.entity) - SetBlipAsShortRange(blip, true) - SetBlipSprite(blip, data.sprite or 106) - SetBlipColour(blip, data.col or 5) - SetBlipScale(blip, data.scale or 0.7) - SetBlipDisplay(blip, data.disp or 6) - if data.category then SetBlipCategory(blip, data.category) end - BeginTextCommandSetBlipName('STRING') - AddTextComponentString(tostring(data.name)) - EndTextCommandSetBlipName(blip) - -- Handle preview image if certain resources are running - if isStarted("fs_smallresources") or isStarted("blip-info") or isStarted("blipinfo") then - if data.preview then - local txname = string.gsub(tostring(data.name..'preview'), "[ ()~]", "") - if data.preview:find("http") or data.preview:find("nui") then - createDui(txname, data.preview, vec2(512, 256), scriptTxd) - else - CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview) + local blip = nil + if gameName == "rdr3" then + blip = BlipAddForEntity(1664425300, data.entity) + SetBlipSprite(blip, data.sprite or `blip_ambient_coach`) + SetBlipScale(blip, data.scale or 0.2) + SetBlipName(blip, data.name) + + else + AddBlipForEntity(data.entity) + blip = GetBlipFromEntity(data.entity) + blipTable[blip] = blip + SetBlipAsShortRange(blip, true) + SetBlipSprite(blip, data.sprite or 106) + SetBlipColour(blip, data.col or 5) + SetBlipScale(blip, data.scale or 0.7) + SetBlipDisplay(blip, data.disp or 6) + if data.category then SetBlipCategory(blip, data.category) end + BeginTextCommandSetBlipName('STRING') + AddTextComponentString(tostring(data.name)) + EndTextCommandSetBlipName(blip) + -- Handle preview image if certain resources are running + if isStarted("fs_smallresources") or isStarted("blip-info") or isStarted("blipinfo") then + if data.preview then + local txname = string.gsub(tostring(data.name..'preview'), "[ ()~]", "") + if data.preview:find("http") or data.preview:find("nui") then + createDui(txname, data.preview, vec2(512, 256), scriptTxd) + else + CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview) + end + exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'previewTxd', txname) + exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) end - exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'previewTxd', txname) - exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) end end - debugPrint("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'") + blipTable[blip] = blip + + if DoesBlipExist(blip) then + debugPrint("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'") + else + print("Error making blip") + end return blip +end + +if gameName == "rdr3" then + onResourceStop(function() + for k in pairs(blipTable) do + RemoveBlip(k) + end + end, true) end \ No newline at end of file diff --git a/shared/make/makePed.lua b/shared/make/makePed.lua index 0457b89..5910d6e 100644 --- a/shared/make/makePed.lua +++ b/shared/make/makePed.lua @@ -20,16 +20,16 @@ local Peds = {} -- ``` function makeDistPed(data, coords, freeze, collision, scenario, anim, synced) local zoneCoords = type(data) == "table" and data.coords or coords - + local randName = keyGen()..keyGen() createCirclePoly({ - name = keyGen()..keyGen(), + name = randName, coords = vec3(zoneCoords.x, zoneCoords.y, zoneCoords.z - 1.03), radius = 50.0, onEnter = function() - Peds[#Peds + 1] = makePed(data, coords, freeze, collision, scenario, anim, synced) + Peds[randName] = makePed(data, coords, freeze, collision, scenario, anim, synced) end, onExit = function() - DeletePed(Peds[#Peds]) + DeletePed(Peds[randName]) end, debug = debugMode, }) @@ -114,7 +114,14 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced) else model = data loadModel(model) - ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false) + if gameName == "rdr3" then + ped = CreatePed(model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false) + SetEntityVisible(ped, 1) -- SetEntityVisible + SetEntityAlpha(ped, 255, false) -- SetEntityAlpha + SetRandomOutfitVariation(ped, true) -- Invisible without + else + ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false) + end end SetEntityInvincible(ped, true) @@ -127,10 +134,13 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced) loadAnimDict(anim[1]) TaskPlayAnim(ped, anim[1], anim[2], 0.5, 1.0, -1, 1, 0.2, 0, 0, 0) end - - debugPrint("^6Bridge^7: ^1Ped ^2Created^7: '^6"..ped.."^7' | ^2Hash^7: ^7'^5"..(model).."^7' | ^2Coord^7: "..formatCoord(coords)) + if DoesEntityExist(ped) then + debugPrint("^6Bridge^7: ^1Ped ^2Created^7: '^6"..ped.."^7' | ^2Hash^7: ^7'^5"..(model).."^7' | ^2Coord^7: "..formatCoord(coords)) + else + print("error ped") + end unloadModel(model) - Peds[#Peds + 1] = ped + Peds[keyGen()..keyGen()] = ped return ped end @@ -229,4 +239,8 @@ function GenerateRandomPedData(data) end --- Cleans up all created Peds when the resource stops. -onResourceStop(function() for i = 1, #Peds do DeletePed(Peds[i]) end end, true) \ No newline at end of file +onResourceStop(function() + for k in pairs(Peds) do + DeletePed(Peds[k]) + end +end, true) \ No newline at end of file diff --git a/shared/make/makeProp.lua b/shared/make/makeProp.lua index 6067d3a..e95c304 100644 --- a/shared/make/makeProp.lua +++ b/shared/make/makeProp.lua @@ -28,7 +28,7 @@ function makeProp(data, freeze, synced) debugPrint("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..data.prop.."^7' | ^2Coord^7: "..formatCoord(data.coords)) SetModelAsNoLongerNeeded(data.prop) - Props[#Props + 1] = prop + Props[keyGen()..keyGen()] = prop return prop end @@ -52,16 +52,16 @@ end --- makeDistProp(propData, true, false) --- ``` function makeDistProp(data, freeze, synced, range) - local prop = nil + local name = keyGen()..keyGen() createCirclePoly({ - name = keyGen()..keyGen(), + name = name, coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03), radius = range or 50.0, onEnter = function() - prop = makeProp(data, freeze, synced) + Props[name] = makeProp(data, freeze, synced) end, onExit = function() - destroyProp(prop) + destroyProp(Props[name]) end, debug = debugMode, }) @@ -87,4 +87,8 @@ function destroyProp(entity) end --- Cleans up all created props when the resource stops. -onResourceStop(function() for i = 1, #Props do destroyProp(Props[i]) end end, true) +onResourceStop(function() + for k in pairs(Props) do + destroyProp(Props[k]) + end +end, true) diff --git a/shared/make/makeVeh.lua b/shared/make/makeVeh.lua index e08c04f..6403c4d 100644 --- a/shared/make/makeVeh.lua +++ b/shared/make/makeVeh.lua @@ -17,12 +17,14 @@ function makeVeh(model, coords) loadModel(model) local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false) SetVehicleHasBeenOwnedByPlayer(veh, true) - SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true) - Wait(100) - SetVehicleNeedsToBeHotwired(veh, false) - SetVehRadioStation(veh, 'OFF') - SetVehicleFuelLevel(veh, 100.0) - SetVehicleModKit(veh, 0) + if gameName ~= "rdr3" then + SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true) + Wait(100) + SetVehicleNeedsToBeHotwired(veh, false) + SetVehRadioStation(veh, 'OFF') + SetVehicleFuelLevel(veh, 100.0) + SetVehicleModKit(veh, 0) + end SetVehicleOnGroundProperly(veh) debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords)) diff --git a/shared/make/progressBars.lua b/shared/make/progressBars.lua index 7e425b0..e9e6d4c 100644 --- a/shared/make/progressBars.lua +++ b/shared/make/progressBars.lua @@ -93,6 +93,22 @@ function progressBar(data) end }) + elseif Config.System.ProgressBar == "red" then + -- Currently only uses jim-redui if you choose this option + if exports["jim-redui"]:progressBar({ + label = data.label, + time = debugMode and 1000 or data.time, + dict = data.dict, + anim = data.anim, + flag = data.flag or 32, + task = data.task, + cancel = true, + }) then + result = true + else + result = false + end + elseif Config.System.ProgressBar == "gta" then loadTextureDict("timerbars") if inProgress then return false end diff --git a/shared/notify.lua b/shared/notify.lua index 962d61b..d1b9532 100644 --- a/shared/notify.lua +++ b/shared/notify.lua @@ -76,6 +76,15 @@ function triggerNotify(title, message, type, src) else TriggerClientEvent("jim-nui:client:notify'", src, type, message) end + + elseif Config.System.Notify == "red" then + if isStarted("jim-redui") then + if not src then + TriggerEvent("jim-redui:Notify", title, message, type) + else + TriggerClientEvent("jim-redui:Notify", src, title, message, type) + end + end end end diff --git a/shared/playerfunctions.lua b/shared/playerfunctions.lua index d846f2b..1afd28d 100644 --- a/shared/playerfunctions.lua +++ b/shared/playerfunctions.lua @@ -161,9 +161,14 @@ function chargePlayer(cost, moneyType, newsrc) if moneyType == "cash" then if isStarted(OXInv) then fundResource = OXInv exports[OXInv]:RemoveItem(src, "money", cost) - elseif isStarted(QBExport) or isStarted(QBXExport) then fundResource = QBExport + elseif isStarted(QBExport) or isStarted(QBXExport) then + fundResource = QBExport Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost) - elseif isStarted(ESXExport) then fundResource = ESXExport + elseif isStarted(RSGExport) then + fundResource = QBExport + Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost) + elseif isStarted(ESXExport) then + fundResource = ESXExport ESX.GetPlayerFromId(src).removeMoney(cost, "") end elseif moneyType == "bank" then @@ -532,6 +537,27 @@ function getPlayer(source) citizenId = info.citizenid, } end + elseif isStarted(RSGExport) then + if Core.Functions.GetPlayer then + local info = Core.Functions.GetPlayer(src).PlayerData + Player = { + firstname = info.charinfo.firstname, + lastname = info.charinfo.lastname, + name = info.charinfo.firstname.." "..info.charinfo.lastname, + cash = info.money["cash"], + bank = info.money["bank"], + source = info.source, + job = info.job.name, + jobBoss = info.job.isboss, + jobInfo = info.job, + gang = info.gang.name, + gangBoss = info.gang.isboss, + gangInfo = info.gang, + onDuty = info.job.onduty, + account = info.charinfo.account, + citizenId = info.citizenid, + } + end else print("^4ERROR^7: ^2No Core detected for getPlayer() - Check starter.lua") end @@ -614,6 +640,26 @@ function getPlayer(source) account = info.charinfo.account, citizenId = info.citizenid, } + elseif isStarted(RSGExport) then + local info = nil + Core.Functions.GetPlayerData(function(PlayerData) info = PlayerData end) + Player = { + firstname = info.charinfo.firstname, + lastname = info.charinfo.lastname, + name = info.charinfo.firstname.." "..info.charinfo.lastname, + cash = info.money["cash"], + bank = info.money["bank"], + source = info.source, + job = info.job.name, + jobBoss = info.job.isboss, + jobInfo = info.job, + gang = info.gang.name, + gangBoss = info.gang.isboss, + gangInfo = info.gang, + onDuty = info.job.onduty, + account = info.charinfo.account, + citizenId = info.citizenid, + } else print("^4ERROR^7: ^2No Core detected for hasJob ^7- ^2Check ^3starter^1.^2lua^7") end diff --git a/shared/scaleforms/scaleform_basic.lua b/shared/scaleforms/scaleform_basic.lua index 15100c2..253f1d9 100644 --- a/shared/scaleforms/scaleform_basic.lua +++ b/shared/scaleforms/scaleform_basic.lua @@ -78,6 +78,47 @@ function makeInstructionalButtons(info) DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0) end +-- EXPERIMENTAL -- +-- RedM Button Prompts -- +-- Creates the promot, then shows it, this needs to be run in a loop +local promptGroups = {} + +function makeRedInstructionalButtons(info, title) + if not promptGroups[title] then -- Create group if not exists + promptGroups[title] = { + title = CreateVarString(10, 'LITERAL_STRING', title), + id = GetRandomIntInRange(0, 0xffffff), + prompts = {}, + } + for i = 1, #info do + promptGroups[title].prompts[i] = { + keys = info[i].keys, + text = info[i].text, + } + local keyTitle = CreateVarString(10, 'LITERAL_STRING', info[i].text) + -- Create one prompt per entry + local promptSet = UiPromptRegisterBegin() + -- Register all keys for this prompt + for k = 1, #info[i].keys do + PromptSetControlAction(promptSet, info[i].keys[k]) + end + PromptSetText(promptSet, keyTitle) + PromptSetEnabled(promptSet, true) + PromptSetVisible(promptSet, true) + PromptSetGroup(promptSet, promptGroups[title].id) + PromptRegisterEnd(promptSet) + end + end + PromptSetActiveGroupThisFrame(promptGroups[title].id, promptGroups[title].title) +end + +onResourceStop(function() + for k, v in pairs(promptGroups) do + print("^5GTAUI^7: ^2Removing Prompt Group^7: ^3" .. k .. "^7") + PromptDelete(promptGroups[k].id, 1) + end +end, true) + ------------------------------------------------------------- -- Debug Text Display Functionality ------------------------------------------------------------- diff --git a/starter.lua b/starter.lua index 12f7552..076043a 100644 --- a/starter.lua +++ b/starter.lua @@ -1,3 +1,5 @@ +gameName = not IsDuplicityVersion() and GetCurrentGameName() + Exports = { QBExport = "qb-core", QBXExport = "qbx_core", @@ -17,7 +19,11 @@ Exports = { QBMenuExport = "qb-menu", QBTargetExport = "qb-target", - OXTargetExport = "ox_target" + OXTargetExport = "ox_target", + + -- REDM + RSGExport = "rsg-core", + RSGInv = "rsg-inventory" } -- Required variables @@ -95,4 +101,4 @@ for _, v in pairs({ -- This is a specific load order if debugMode then print("^5Success^7: ^2loaded file^7: ^3"..(v):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").."^7") end -end \ No newline at end of file +end