add basic support for RedM (RSGCore)

This commit is contained in:
Jim Shield
2025-04-07 20:52:59 +01:00
committed by GitHub
parent 4d8305c844
commit 2da2c56705
17 changed files with 552 additions and 244 deletions

View File

@@ -1,9 +1,10 @@
name "Jim_Bridge" name "Jim_RedBridge"
author "Jimathy" author "Jimathy"
version "2.0" version "2.0"
description "Framework Bridge By Jimathy" description "Framework Bridge By Jimathy"
fx_version "cerulean" 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' lua54 'yes'
files { files {

View File

@@ -53,6 +53,9 @@ function onPlayerLoaded(func, onStart)
elseif isStarted(OXCoreExport) then elseif isStarted(OXCoreExport) then
onPlayerFramework = OXCoreExport onPlayerFramework = OXCoreExport
AddEventHandler('ox:playerLoaded', tempFunc) AddEventHandler('ox:playerLoaded', tempFunc)
elseif isStarted(RSGExport) then
onPlayerFramework = RSGExport
AddEventHandler('RSGCore:Client:OnPlayerLoaded', tempFunc)
end end
if onPlayerFramework ~= "" then if onPlayerFramework ~= "" then
@@ -75,6 +78,7 @@ end
function onPlayerUnload(func) function onPlayerUnload(func)
AddEventHandler('QBCore:Client:OnPlayerUnload', function() func() end) AddEventHandler('QBCore:Client:OnPlayerUnload', function() func() end)
AddEventHandler('ox:playerLogout', function() func() end) AddEventHandler('ox:playerLogout', function() func() end)
AddEventHandler('RSGCore:Client:OnPlayerUnload', function() func() end)
--AddEventHandler('esx:playerLogout', 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 -- ^ Only server side for now, need a way to send it to client if not already available

View File

@@ -36,6 +36,10 @@ OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv =
Exports.CodeMInv or "", Exports.CodeMInv or "",
Exports.OrigenInv or "" Exports.OrigenInv or ""
RSGExport, RSGInv =
Exports.RSGExport or "",
Exports.RSGInv or ""
QBMenuExport = Exports.QBMenuExport or "" QBMenuExport = Exports.QBMenuExport or ""
QBTargetExport, OXTargetExport = Exports.QBTargetExport or "", Exports.OXTargetExport 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) debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Items).." ^3Items^2 from ^7"..itemResource)
end end
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 end
if not isStarted(ESXExport) then if not isStarted(ESXExport) then
@@ -167,6 +183,17 @@ elseif isStarted(ESXExport) then
end end
end 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 end
if vehResource == nil then if vehResource == nil then
@@ -239,6 +266,17 @@ elseif isStarted(ESXExport) then
Gangs = Jobs Gangs = Jobs
end end
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 end
if not isStarted(ESXExport) and Jobs then if not isStarted(ESXExport) and Jobs then

View File

@@ -71,6 +71,16 @@ function drawText(image, input, style, oxStyleTable)
icon = nil, icon = nil,
text = text, 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
end end
@@ -91,5 +101,7 @@ function hideText()
ClearAllHelpMessages() ClearAllHelpMessages()
elseif Config.System.drawText == "esx" then elseif Config.System.drawText == "esx" then
ESX.HideUI() ESX.HideUI()
elseif Config.System.drawText == "red" then
TriggerEvent("jim-redui:HideText")
end end
end end

View File

@@ -1,30 +1,31 @@
if gameName ~= "rdr3" then
--[[ --[[
DUI Module (Experimental) DUI Module (Experimental)
-------------------------- --------------------------
This module handles the creation, modification, and removal of custom DUI (Display UI) 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 elements using runtime textures. It supports both client and server functionality to update DUI
images dynamically. images dynamically.
]] ]]
-- Create a runtime texture dictionary on the client if not running on the server. -- Create a runtime texture dictionary on the client if not running on the server.
scriptTxd = not isServer() and CreateRuntimeTxd(getScript()..'scriptTxd') or nil scriptTxd = not isServer() and CreateRuntimeTxd(getScript()..'scriptTxd') or nil
customDUIList = {} customDUIList = {}
------------------------------------------------------------- -------------------------------------------------------------
-- DUI Client Functions -- DUI Client Functions
------------------------------------------------------------- -------------------------------------------------------------
--- Creates or updates a DUI element. --- Creates or updates a DUI element.
--- ---
--- @param name string The unique name for the DUI element. --- @param name string The unique name for the DUI element.
--- @param http string The URL to load into the DUI. --- @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 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. --- @param txd table The runtime texture dictionary where the DUI texture will be created.
--- @usage --- @usage
--- ```lua --- ```lua
--- createDui("logo", "https://example.com/logo.png", { x = 512, y = 256 }, scriptTxd) --- createDui("logo", "https://example.com/logo.png", { x = 512, y = 256 }, scriptTxd)
--- ``` --- ```
function createDui(name, http, size, txd) function createDui(name, http, size, txd)
if not customDUIList[name] then if not customDUIList[name] then
local newDui = CreateDui(http, math.floor(size.x), math.floor(size.y)) local newDui = CreateDui(http, math.floor(size.x), math.floor(size.y))
while not GetDuiHandle(newDui) do Wait(0) end while not GetDuiHandle(newDui) do Wait(0) end
@@ -34,21 +35,21 @@ function createDui(name, http, size, txd)
else else
SetDuiUrl(customDUIList[name], http) SetDuiUrl(customDUIList[name], http)
end end
end end
--- Opens a DUI selection input allowing the user to change the DUI image URL. --- Opens a DUI selection input allowing the user to change the DUI image URL.
--- ---
--- @param data table A table containing DUI data: --- @param data table A table containing DUI data:
--- - name: The key name in the DUI list. --- - name: The key name in the DUI list.
--- - texn: The texture name. --- - texn: The texture name.
--- - texd: The texture dictionary. --- - texd: The texture dictionary.
--- - size: A table with .x and .y dimensions. --- - size: A table with .x and .y dimensions.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- DuiSelect({ name = "logo", texn = "logoTex", texd = "someTxd", size = { x = 512, y = 256 } }) --- DuiSelect({ name = "logo", texn = "logoTex", texd = "someTxd", size = { x = 512, y = 256 } })
--- ``` --- ```
function DuiSelect(data) function DuiSelect(data)
local imagePreview = "" local imagePreview = ""
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn and duiList[data.name][k] then if v.tex.texn == data.texn and duiList[data.name][k] then
@@ -85,34 +86,34 @@ function DuiSelect(data)
TriggerServerEvent(getScript()..":Server:ChangeDUI", data) TriggerServerEvent(getScript()..":Server:ChangeDUI", data)
end end
end end
end end
--- Client event handler to update DUI elements. --- Client event handler to update DUI elements.
RegisterNetEvent(getScript()..":Client:ChangeDUI", function(data) RegisterNetEvent(getScript()..":Client:ChangeDUI", function(data)
debugPrint("^6Bridge^7: ^2Receiving new DUI ^7- ^6"..data.url.."^7") debugPrint("^6Bridge^7: ^2Receiving new DUI ^7- ^6"..data.url.."^7")
if tostring(data.url) ~= "-" then if tostring(data.url) ~= "-" then
createDui(data.texn, tostring(data.url), data.size, scriptTxd) createDui(data.texn, tostring(data.url), data.size, scriptTxd)
AddReplaceTexture(tostring(data.texd), tostring(data.texn), getScript().."scriptTxd", tostring(data.texn)) AddReplaceTexture(tostring(data.texd), tostring(data.texn), getScript().."scriptTxd", tostring(data.texn))
end end
end) end)
--- Client event handler to clear DUI elements. --- Client event handler to clear DUI elements.
RegisterNetEvent(getScript()..":Client:ClearDUI", function(data) RegisterNetEvent(getScript()..":Client:ClearDUI", function(data)
if customDUIList[tostring(data.texn)] then if customDUIList[tostring(data.texn)] then
RemoveReplaceTexture(tostring(data.texd), tostring(data.texn)) RemoveReplaceTexture(tostring(data.texd), tostring(data.texn))
if IsDuiAvailable(customDUIList[tostring(data.texn)]) then if IsDuiAvailable(customDUIList[tostring(data.texn)]) then
SetDuiUrl(customDUIList[data.name], nil) SetDuiUrl(customDUIList[data.name], nil)
end end
end end
end) end)
------------------------------------------------------------- -------------------------------------------------------------
-- DUI Server Functions -- DUI Server Functions
------------------------------------------------------------- -------------------------------------------------------------
--- Server event handler to change DUI settings. --- Server event handler to change DUI settings.
--- If no URL is provided, resets to the preset value. --- If no URL is provided, resets to the preset value.
RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data) RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data)
if not data.url then if not data.url then
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn then if v.tex.texn == data.texn then
@@ -128,10 +129,10 @@ RegisterNetEvent(getScript()..":Server:ChangeDUI", function(data)
end end
debugPrint("^6Bridge^7: ^3DUI^2 Sending new DUI to all players^7 - ^6"..data.url.."^7") debugPrint("^6Bridge^7: ^3DUI^2 Sending new DUI to all players^7 - ^6"..data.url.."^7")
TriggerClientEvent(getScript()..":Client:ChangeDUI", -1, data) TriggerClientEvent(getScript()..":Client:ChangeDUI", -1, data)
end) end)
--- Server event handler to clear DUI settings. --- Server event handler to clear DUI settings.
RegisterNetEvent(getScript()..":Server:ClearDUI", function(data) RegisterNetEvent(getScript()..":Server:ClearDUI", function(data)
if data.url == "-" then if data.url == "-" then
for k, v in pairs(duiList[data.name]) do for k, v in pairs(duiList[data.name]) do
if v.tex.texn == data.texn then if v.tex.texn == data.texn then
@@ -140,26 +141,28 @@ RegisterNetEvent(getScript()..":Server:ClearDUI", function(data)
end end
end end
TriggerClientEvent(getScript()..":Client:ClearDUI", -1, data) TriggerClientEvent(getScript()..":Client:ClearDUI", -1, data)
end) end)
------------------------------------------------------------- -------------------------------------------------------------
-- Resource Cleanup -- Resource Cleanup
------------------------------------------------------------- -------------------------------------------------------------
onResourceStop(function() onResourceStop(function()
for k, v in pairs(duiList or {}) do for k, v in pairs(duiList or {}) do
for i = 1, #v do for i = 1, #v do
RemoveReplaceTexture(tostring(v[i].tex.texd), tostring(v[i].tex.texn)) RemoveReplaceTexture(tostring(v[i].tex.texd), tostring(v[i].tex.texn))
end end
end end
end, true) end, true)
------------------------------------------------------------- -------------------------------------------------------------
-- DUI List Callback (Server) -- DUI List Callback (Server)
------------------------------------------------------------- -------------------------------------------------------------
if isServer() then if isServer() then
createCallback(getScript()..":Server:duiList", function(source) createCallback(getScript()..":Server:duiList", function(source)
return duiList return duiList
end) end)
end
end end

View File

@@ -148,6 +148,14 @@ function getPlayerInv(src)
grabInv = xPlayer.inventory grabInv = xPlayer.inventory
end 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 else
print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3starter^1.^2lua^7") print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3starter^1.^2lua^7")
end end

View File

@@ -74,6 +74,8 @@ function invImg(item)
imgLink = "nui://"..OrigenInv.."/html/img/"..(Items[item].image or "") imgLink = "nui://"..OrigenInv.."/html/img/"..(Items[item].image or "")
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
imgLink = "nui://"..QBInv.."/html/images/"..(Items[item].image or "") imgLink = "nui://"..QBInv.."/html/images/"..(Items[item].image or "")
elseif isStarted(RSGInv) then
imgLink = "nui://"..RSGInv.."/html/images/"..(Items[item].image or "")
else else
print("^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua") print("^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua")
end end
@@ -99,12 +101,15 @@ end
--- addItem("health_potion", 2, { quality = "high" }) --- addItem("health_potion", 2, { quality = "high" })
--- ``` --- ```
function addItem(item, amount, info, src) 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 if src then
TriggerEvent(getScript()..":server:toggleItem", true, item, amount, src, info) TriggerEvent(getScript()..":server:toggleItem", true, item, amount, src, info)
else 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 currentToken = nil -- clear client cached token
end end
end end
@@ -129,6 +134,7 @@ function removeItem(item, amount, src, slot)
end end
if src then if src then
debugPrint(src)
TriggerEvent(getScript()..":server:toggleItem", false, item, amount, src, nil, slot) TriggerEvent(getScript()..":server:toggleItem", false, item, amount, src, nil, slot)
else else
TriggerServerEvent(getScript()..":server:toggleItem", false, item, amount, nil, nil, slot) TriggerServerEvent(getScript()..":server:toggleItem", false, item, amount, nil, nil, slot)
@@ -155,30 +161,37 @@ end
--- ```lua --- ```lua
--- TriggerServerEvent(getScript()..":server:toggleItem", true, "health_potion", 1) --- 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 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") print("^6Bridge^7: ^1Error^7 - ^2Tried to "..(tostring(give) == "true" and "add" or "remove").." '^3"..item.."^7' but it doesn't exist")
return return
end end
local src = source or newsrc local src = newsrc or source
if (give == true or give == 1) then if (give == true or give == 1) then
if newsrc == nil then -- must be coming from client this would be blank if newsrc == nil then -- must be coming from client this would be blank
if token == nil then
debugPrint("^1Auth^7: ^1No token recieved^7") debugPrint("^1Auth^7: ^1No token recieved^7")
dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token") dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token")
else else
if type(newsrc) ~= "number" then -- checks if the newsrc is a source or token, if number its coming form the server itself 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..") debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
if newsrc ~= validTokens[src] then if token ~= validTokens[src] then
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", newsrc, validTokens[src]) 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") dupeWarn(src, item, "Auth: "..src.." attempted to spawn "..item.." with an incorrect auth token")
else else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", newsrc, validTokens[src]) debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil validTokens[src] = nil
end end
end end
end end
end end
end
local action = (tostring(give) == "true" and "addItem" or "removeItem") local action = (tostring(give) == "true" and "addItem" or "removeItem")
local remamount = amount or 1 local remamount = amount or 1
@@ -230,6 +243,20 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
if Config.Crafting.showItemBox then if Config.Crafting.showItemBox then
TriggerClientEvent("inventory:client:ItemBox", src, Items[item], "remove", amount or 1) TriggerClientEvent("inventory:client:ItemBox", src, Items[item], "remove", amount or 1)
end 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 end
----- -----
-- Fallback for if no inventory found: -- 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) TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
end 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 elseif isStarted(PSInv) then invName = PSInv
if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then
if Config.Crafting.showItemBox then if Config.Crafting.showItemBox then
@@ -601,7 +633,12 @@ function canCarry(itemTable, src)
resultTable[k] = exports[OrigenInv]:canCarryItem(src, k, v) resultTable[k] = exports[OrigenInv]:canCarryItem(src, k, v)
end 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 items = getPlayerInv(src)
local totalWeight = 0 local totalWeight = 0
if not items then return false end if not items then return false end
@@ -616,6 +653,22 @@ function canCarry(itemTable, src)
resultTable[k] = (totalWeight + (itemInfo.weight * v)) <= InventoryWeight resultTable[k] = (totalWeight + (itemInfo.weight * v)) <= InventoryWeight
end end
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
end end
return resultTable return resultTable
@@ -637,6 +690,11 @@ if isServer() then
createCallback(AuthEvent, function(source) createCallback(AuthEvent, function(source)
local src = source local src = source
local token = keyGen()..keyGen()..keyGen()..keyGen() -- Use a secure random generator here 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) debugPrint("^1Auth^7:^2 Player Source^7: "..src.." ^2requested new token^7:", token)
validTokens[src] = token validTokens[src] = token
timeOutAuth(validTokens[src], src) -- Give script 10 seconds, then clear token timeOutAuth(validTokens[src], src) -- Give script 10 seconds, then clear token
@@ -664,6 +722,11 @@ if isServer() then
receivedEvent = {} receivedEvent = {}
createCallback(getScript()..":callback:GetAuthEvent", function(source) createCallback(getScript()..":callback:GetAuthEvent", function(source)
local src = 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) debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent)
if not receivedEvent[src] then receivedEvent[src] = true if not receivedEvent[src] then receivedEvent[src] = true
return AuthEvent return AuthEvent
@@ -673,8 +736,6 @@ if isServer() then
end end
end) end)
else else
onResourceStart(function()
debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7") debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7")
AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent") AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent")
end, true)
end end

View File

@@ -69,7 +69,7 @@ end
function jobCheck(job) function jobCheck(job)
local canDo = true local canDo = true
if Jobs[job] then 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"]) triggerNotify(nil, Loc[Config.Lan].error["not_clockedin"])
canDo = false canDo = false
end end
@@ -92,10 +92,10 @@ end
--- toggleDuty() -- Player receives a notification of their new duty status. --- toggleDuty() -- Player receives a notification of their new duty status.
--- ``` --- ```
function toggleDuty() function toggleDuty()
onDuty = not onDuty
if isStarted(QBExport) or isStarted(QBXExport) then if isStarted(QBExport) or isStarted(QBXExport) then
TriggerServerEvent("QBCore:ToggleDuty") TriggerServerEvent("QBCore:ToggleDuty")
else else
onDuty = not onDuty
if onDuty then if onDuty then
triggerNotify(nil, "Now on duty", "success") triggerNotify(nil, "Now on duty", "success")
else else

View File

@@ -1,3 +1,5 @@
local blipTable = {}
--- Creates a blip at specified coordinates with given properties. --- 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. -- This function adds a map blip at the provided coordinates and sets various display properties such as sprite, color, scale, and more.
@@ -30,14 +32,24 @@
-- local blip = makeBlip(blipData) -- local blip = makeBlip(blipData)
-- ``` -- ```
function makeBlip(data) function makeBlip(data)
local blip = AddBlipForCoord(vec3(data.coords.x, data.coords.y, data.coords.z)) 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 SetBlipCoords(blip, data.coords.x, data.coords.y, data.coords.z) -- Manually set blip coordinates again as sometimes it just refuses
SetBlipAsShortRange(blip, true) SetBlipAsShortRange(blip, true)
SetBlipSprite(blip, data.sprite or 106) SetBlipSprite(blip, data.sprite or 106)
SetBlipColour(blip, data.col or 5) SetBlipColour(blip, data.col or 5)
SetBlipScale(blip, data.scale or 0.7) SetBlipScale(blip, data.scale or 0.7)
SetBlipDisplay(blip, data.disp or 6) SetBlipDisplay(blip, data.disp or 6)
if data.category then SetBlipCategory(blip, data.category) end if data.category then
SetBlipCategory(blip, data.category)
end
BeginTextCommandSetBlipName('STRING') BeginTextCommandSetBlipName('STRING')
AddTextComponentString(tostring(data.name)) AddTextComponentString(tostring(data.name))
EndTextCommandSetBlipName(blip) EndTextCommandSetBlipName(blip)
@@ -54,7 +66,14 @@ function makeBlip(data)
exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false)
end end
end end
end
blipTable[blip] = blip
if DoesBlipExist(blip) then
debugPrint("^6Bridge^7: ^6Blip ^2created^7: '^6"..data.name.."^7' - '"..formatCoord(data.coords).."'") debugPrint("^6Bridge^7: ^6Blip ^2created^7: '^6"..data.name.."^7' - '"..formatCoord(data.coords).."'")
else
print("Error making blip")
end
return blip return blip
end end
@@ -90,8 +109,17 @@ end
-- local blip = makeEntityBlip(blipData) -- local blip = makeEntityBlip(blipData)
-- ``` -- ```
function makeEntityBlip(data) function makeEntityBlip(data)
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) AddBlipForEntity(data.entity)
local blip = GetBlipFromEntity(data.entity) blip = GetBlipFromEntity(data.entity)
blipTable[blip] = blip
SetBlipAsShortRange(blip, true) SetBlipAsShortRange(blip, true)
SetBlipSprite(blip, data.sprite or 106) SetBlipSprite(blip, data.sprite or 106)
SetBlipColour(blip, data.col or 5) SetBlipColour(blip, data.col or 5)
@@ -114,6 +142,21 @@ function makeEntityBlip(data)
exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false) exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false)
end end
end end
end
blipTable[blip] = blip
if DoesBlipExist(blip) then
debugPrint("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'") debugPrint("^6Bridge^7: ^6Blip ^2created for Entity^7: '^6"..data.name.."^7'")
else
print("Error making blip")
end
return blip return blip
end end
if gameName == "rdr3" then
onResourceStop(function()
for k in pairs(blipTable) do
RemoveBlip(k)
end
end, true)
end

View File

@@ -20,16 +20,16 @@ local Peds = {}
-- ``` -- ```
function makeDistPed(data, coords, freeze, collision, scenario, anim, synced) function makeDistPed(data, coords, freeze, collision, scenario, anim, synced)
local zoneCoords = type(data) == "table" and data.coords or coords local zoneCoords = type(data) == "table" and data.coords or coords
local randName = keyGen()..keyGen()
createCirclePoly({ createCirclePoly({
name = keyGen()..keyGen(), name = randName,
coords = vec3(zoneCoords.x, zoneCoords.y, zoneCoords.z - 1.03), coords = vec3(zoneCoords.x, zoneCoords.y, zoneCoords.z - 1.03),
radius = 50.0, radius = 50.0,
onEnter = function() onEnter = function()
Peds[#Peds + 1] = makePed(data, coords, freeze, collision, scenario, anim, synced) Peds[randName] = makePed(data, coords, freeze, collision, scenario, anim, synced)
end, end,
onExit = function() onExit = function()
DeletePed(Peds[#Peds]) DeletePed(Peds[randName])
end, end,
debug = debugMode, debug = debugMode,
}) })
@@ -114,8 +114,15 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
else else
model = data model = data
loadModel(model) loadModel(model)
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) ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false)
end end
end
SetEntityInvincible(ped, true) SetEntityInvincible(ped, true)
SetBlockingOfNonTemporaryEvents(ped, true) SetBlockingOfNonTemporaryEvents(ped, true)
@@ -127,10 +134,13 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
loadAnimDict(anim[1]) loadAnimDict(anim[1])
TaskPlayAnim(ped, anim[1], anim[2], 0.5, 1.0, -1, 1, 0.2, 0, 0, 0) TaskPlayAnim(ped, anim[1], anim[2], 0.5, 1.0, -1, 1, 0.2, 0, 0, 0)
end end
if DoesEntityExist(ped) then
debugPrint("^6Bridge^7: ^1Ped ^2Created^7: '^6"..ped.."^7' | ^2Hash^7: ^7'^5"..(model).."^7' | ^2Coord^7: "..formatCoord(coords)) 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) unloadModel(model)
Peds[#Peds + 1] = ped Peds[keyGen()..keyGen()] = ped
return ped return ped
end end
@@ -229,4 +239,8 @@ function GenerateRandomPedData(data)
end end
--- Cleans up all created Peds when the resource stops. --- Cleans up all created Peds when the resource stops.
onResourceStop(function() for i = 1, #Peds do DeletePed(Peds[i]) end end, true) onResourceStop(function()
for k in pairs(Peds) do
DeletePed(Peds[k])
end
end, true)

View File

@@ -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)) debugPrint("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..data.prop.."^7' | ^2Coord^7: "..formatCoord(data.coords))
SetModelAsNoLongerNeeded(data.prop) SetModelAsNoLongerNeeded(data.prop)
Props[#Props + 1] = prop Props[keyGen()..keyGen()] = prop
return prop return prop
end end
@@ -52,16 +52,16 @@ end
--- makeDistProp(propData, true, false) --- makeDistProp(propData, true, false)
--- ``` --- ```
function makeDistProp(data, freeze, synced, range) function makeDistProp(data, freeze, synced, range)
local prop = nil local name = keyGen()..keyGen()
createCirclePoly({ createCirclePoly({
name = keyGen()..keyGen(), name = name,
coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03), coords = vec3(data.coords.x, data.coords.y, data.coords.z - 1.03),
radius = range or 50.0, radius = range or 50.0,
onEnter = function() onEnter = function()
prop = makeProp(data, freeze, synced) Props[name] = makeProp(data, freeze, synced)
end, end,
onExit = function() onExit = function()
destroyProp(prop) destroyProp(Props[name])
end, end,
debug = debugMode, debug = debugMode,
}) })
@@ -87,4 +87,8 @@ function destroyProp(entity)
end end
--- Cleans up all created props when the resource stops. --- 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)

View File

@@ -17,12 +17,14 @@ function makeVeh(model, coords)
loadModel(model) loadModel(model)
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false) local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false)
SetVehicleHasBeenOwnedByPlayer(veh, true) SetVehicleHasBeenOwnedByPlayer(veh, true)
if gameName ~= "rdr3" then
SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true) SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true)
Wait(100) Wait(100)
SetVehicleNeedsToBeHotwired(veh, false) SetVehicleNeedsToBeHotwired(veh, false)
SetVehRadioStation(veh, 'OFF') SetVehRadioStation(veh, 'OFF')
SetVehicleFuelLevel(veh, 100.0) SetVehicleFuelLevel(veh, 100.0)
SetVehicleModKit(veh, 0) SetVehicleModKit(veh, 0)
end
SetVehicleOnGroundProperly(veh) SetVehicleOnGroundProperly(veh)
debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords)) debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords))

View File

@@ -93,6 +93,22 @@ function progressBar(data)
end 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 elseif Config.System.ProgressBar == "gta" then
loadTextureDict("timerbars") loadTextureDict("timerbars")
if inProgress then return false end if inProgress then return false end

View File

@@ -76,6 +76,15 @@ function triggerNotify(title, message, type, src)
else else
TriggerClientEvent("jim-nui:client:notify'", src, type, message) TriggerClientEvent("jim-nui:client:notify'", src, type, message)
end 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
end end

View File

@@ -161,9 +161,14 @@ function chargePlayer(cost, moneyType, newsrc)
if moneyType == "cash" then if moneyType == "cash" then
if isStarted(OXInv) then fundResource = OXInv if isStarted(OXInv) then fundResource = OXInv
exports[OXInv]:RemoveItem(src, "money", cost) 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) 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, "") ESX.GetPlayerFromId(src).removeMoney(cost, "")
end end
elseif moneyType == "bank" then elseif moneyType == "bank" then
@@ -532,6 +537,27 @@ function getPlayer(source)
citizenId = info.citizenid, citizenId = info.citizenid,
} }
end 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 else
print("^4ERROR^7: ^2No Core detected for getPlayer() - Check starter.lua") print("^4ERROR^7: ^2No Core detected for getPlayer() - Check starter.lua")
end end
@@ -614,6 +640,26 @@ function getPlayer(source)
account = info.charinfo.account, account = info.charinfo.account,
citizenId = info.citizenid, 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 else
print("^4ERROR^7: ^2No Core detected for hasJob ^7- ^2Check ^3starter^1.^2lua^7") print("^4ERROR^7: ^2No Core detected for hasJob ^7- ^2Check ^3starter^1.^2lua^7")
end end

View File

@@ -78,6 +78,47 @@ function makeInstructionalButtons(info)
DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0) DrawScaleformMovieFullscreen(build, 255, 255, 255, 255, 0)
end 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 -- Debug Text Display Functionality
------------------------------------------------------------- -------------------------------------------------------------

View File

@@ -1,3 +1,5 @@
gameName = not IsDuplicityVersion() and GetCurrentGameName()
Exports = { Exports = {
QBExport = "qb-core", QBExport = "qb-core",
QBXExport = "qbx_core", QBXExport = "qbx_core",
@@ -17,7 +19,11 @@ Exports = {
QBMenuExport = "qb-menu", QBMenuExport = "qb-menu",
QBTargetExport = "qb-target", QBTargetExport = "qb-target",
OXTargetExport = "ox_target" OXTargetExport = "ox_target",
-- REDM
RSGExport = "rsg-core",
RSGInv = "rsg-inventory"
} }
-- Required variables -- Required variables