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"
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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 = "<center>- Current Image -<br>" ..
"<img src="..duiList[data.name][k].url.." width=150px><br>" ..
"Size: ["..math.floor(data.size.x)..", "..math.floor(data.size.y).."]<br><br>"
--- 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 = "<center>- Current Image -<br>" ..
"<img src="..duiList[data.name][k].url.." width=150px><br>" ..
"Size: ["..math.floor(data.size.x)..", "..math.floor(data.size.y).."]<br><br>"
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
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))
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)

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
-------------------------------------------------------------

View File

@@ -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
end