Compare commits

..

28 Commits

Author SHA1 Message Date
Jim Shield
fea72bba2e hotfix ox_lib progressbars stopping movement 2025-06-23 12:54:24 +01:00
Jim Shield
b364f14260 Version Bump
`2.0.17` - `2.0.18`
2025-06-22 22:16:17 +01:00
Jim Shield
8077ec4f46 Add functions to try and get players inv weights 2025-06-22 20:03:12 +01:00
Jim Shield
e5277574df Rework Auto detection of QBInvNew
It's messy but hopefully it will work as expected
2025-06-22 17:45:33 +01:00
Jim Shield
e0563dd4ce Add extra triggerevent for ps-inventory
They keep changing their event names 🤷‍♀️
added a duplicate with `ps-` at the start in hopes this triggers things correctly when opening a stash
2025-06-22 17:45:04 +01:00
Jim Shield
1987cf3df3 Fix IsAnimal checks getting confused 2025-06-22 16:51:19 +01:00
Jim Shield
9f5145c3b2 Update progressBars.lua 2025-06-22 16:38:02 +01:00
Jim Shield
5921cf8adc ProgressBar default variable fixes 2025-06-22 16:14:32 +01:00
Jim Shield
f154b45076 Enhance built in ui_modules to support RedM 2025-06-21 22:34:03 +01:00
Jim Shield
2c41272c36 Remove ClearStash export call for ps-inv 2025-06-21 18:28:50 +01:00
McKlean
57d4beafed Commit[crafting]: commented print causing errors
- debugPrint was causing crafting to error
2025-06-21 16:32:49 +01:00
McKlean
bdb526bd1e Commit[Billing]: added okok Billing
- Added OKOK's CreateInvoice as a choice for the billing
2025-06-21 14:52:09 +01:00
Jim Shield
bb9dbe248f Update callback.lua 2025-06-21 13:56:49 +01:00
Jim Shield
caf2e7fbed add support for esx_society to openBossMenu() 2025-06-21 13:29:42 +01:00
Jim Shield
d0b8fb16d6 fix for if ox_inv can't find an item when trying to get image 2025-06-21 13:29:01 +01:00
Jim Shield
2e57e66095 Fix confusion with old and new inv shop exports 2025-06-20 23:33:44 +01:00
Jim Shield
05fc856e86 small tidy up 2025-06-20 21:53:44 +01:00
Jim Shield
74e6a679e2 Tidy up onPlayerLoaded for all frameworks 2025-06-20 21:32:08 +01:00
Jim Shield
17db5aa31a Fix QBCore OnPlayerUnload event not triggering 2025-06-20 21:12:53 +01:00
Jim Shield
387c97de71 Fix jpr erroring when clearStash is triggered 2025-06-20 20:56:45 +01:00
Jim Shield
de45491c8c move exploit protection to new file
Moves Auth Token stuff to separate file because it doesn't really need to be in `itemcontrol.lua`

Helps me keep track of it better too

Also added a "cooldown" to workaround people's multicharacter scripts claiming the players loaded more than once and breaking it
2025-06-20 20:55:49 +01:00
Jim Shield
4da4cbfc15 Tidy up and organise several debugPrints better 2025-06-20 18:03:08 +01:00
Jim Shield
9fbf2f2211 Make frameworkCache.lua smurter
Add better checks for if theres errors in ox_inv items and add more prominent error messages all around
2025-06-20 17:47:54 +01:00
Jim Shield
41b2965743 Merge pull request #47 from oosayeroo/main 2025-06-20 13:35:45 +01:00
Jim Shield
a02c11d3cc Update crafting.lua 2025-06-19 22:18:53 +01:00
Jim Shield
c888aa5ecf Fix ox_inv item client info (images) caching 2025-06-19 22:15:49 +01:00
oosayeroo
804327f3aa Merge branch 'jimathy:main' into main 2025-06-18 19:30:56 +01:00
oosayeroo
ba59418b6d return values (boolean)
- added return values on following functions
:fundPlayer
:chargePlayer

- added check for Config.System in Notify.lua
2025-06-18 19:30:21 +01:00
23 changed files with 1028 additions and 370 deletions

View File

@@ -62,8 +62,8 @@ if checkExists(Exports.ESXExport) then
end
-- Initialize variables for caching
local Items, Vehicles, Jobs, Gangs, Core = nil, nil, nil, nil, nil
local itemResource, jobResource, vehResource = "", "", ""
local Items, Vehicles, Jobs, Gangs, Core = {}, {}, {}, {}, nil
local itemResource, jobResource, vehResource = "N/A", "N/A", "N/A"
-- Print just to announce it knows the exports/scripts exist in the server
for _, v in pairs(Exports) do
@@ -80,18 +80,33 @@ if checkExists(Exports.OXInv) then
-- Wait for OX Inventory to start if it's not already started
while GetResourceState(Exports.OXInv) ~= "started" do Wait(100) end
itemResource = Exports.OXInv
Items = exports[Exports.OXInv]:Items()
local success, result = pcall(function()
return exports[Exports.OXInv]:Items()
end)
if success and result then
Items = result
end
if Items == nil or not next(Items) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find "..Exports.OXInv.." ^7Items ^1list^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Items = {} -- Fallback to an empty table
end
-- Get Weapon info and duplicate them if they are uppercase
-- (duplicate incase anything checks for the uppercase version)
for k, v in pairs(Items) do
if k:find("WEAPON") then
Items[k:lower()] = Items[k]
Items[k:lower()].image = k..".png"
if type(k) == "string" then
if k:find("WEAPON") then
Items[k:lower()] = Items[k]
end
else
print("^1ERROR^7: ^1Possible table inside a table, check your items.lua^7?")
print("^1Possible Issue found^7:")
print(json.encode(Items[k], {indent = true}))
end
Items[k].image = (v.client and v.client.image) and v.client.image:gsub("nui://"..Exports.OXInv.."/web/images/", "") or k..".png"
Items[k].hunger = v.client and v.client.hunger
Items[k].thirst = v.client and v.client.thirst
end
elseif checkExists(Exports.QBExport) then
@@ -99,8 +114,11 @@ elseif checkExists(Exports.QBExport) then
itemResource = Exports.QBExport
Core = exports[Exports.QBExport]:GetCoreObject()
Items = Core.Shared.Items
if Items == nil then
print("^1ERROR^7: ^1Can NOT find shared ^7Items ^1table^7, ^1possible error in that file^7?")
if Items == nil or not next(Items) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find "..Exports.QBExport.." ^7Items ^1list^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Items = {} -- Fallback to an empty table
end
@@ -121,8 +139,10 @@ elseif checkExists(Exports.RSGExport) then
itemResource = Exports.RSGExport
Core = exports[Exports.RSGExport]:GetCoreObject()
Items = Core.Shared.Items
if Items == nil then
print("^1ERROR^7: ^1Can NOT find shared ^7Items ^1table^7, ^1possible error in that file^7?")
if Items == nil or not next(Items) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find "..Exports.RSGExport.." ^7Items ^1list^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Items = {} -- Fallback to an empty table
end
@@ -136,8 +156,10 @@ if checkExists(Exports.QBXExport) or checkExists(Exports.QBExport) then
vehResource = Exports.QBExport
Core = Core or exports[Exports.QBExport]:GetCoreObject()
Vehicles = Core.Shared.Vehicles
if Vehicles == nil then
print("^1ERROR^7: ^1Can NOT find shared ^7Vehicles ^1table^7, ^1possible error in that file^7?")
if Vehicles == nil or not next(Vehicles) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find "..Exports.QBExport.." ^7Vehicles ^1list^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Vehicles = {} -- Fallback to an empty table
end
@@ -170,8 +192,10 @@ elseif checkExists(Exports.RSGExport) then
vehResource = Exports.RSGExport
Core = Core or exports[Exports.RSGExport]:GetCoreObject()
Vehicles = Core.Shared.Vehicles
if Vehicles == nil then
if Vehicles == nil or not next(Vehicles) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find shared ^7Vehicles ^1table^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Vehicles = {} -- Fallback to an empty table
end
@@ -185,8 +209,10 @@ if checkExists(Exports.QBXExport) then
jobResource = Exports.QBXExport
Core = Core or exports[Exports.QBXExport]:GetCoreObject()
Jobs, Gangs = exports[Exports.QBXExport]:GetJobs(), exports[Exports.QBXExport]:GetGangs()
if Jobs == nil then
if Jobs == nil or not next(Jobs) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find shared ^7Jobs ^1table^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Jobs = {} -- Fallback to an empty table
end
@@ -252,8 +278,10 @@ elseif checkExists(Exports.RSGExport) then
jobResource = Exports.RSGExport
Core = Core or exports[Exports.RSGExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
if Jobs == nil then
if Jobs == nil or not next(Jobs) then
print("^1--------------------------------------------^7")
print("^1ERROR^7: ^1Can NOT find shared ^7Jobs ^1table^7, ^1possible error in that file^7?")
print("^1--------------------------------------------^7")
Jobs = {} -- Fallback to an empty table
end

View File

@@ -1,6 +1,6 @@
name "Jim_Bridge"
author "Jimathy"
version "2.0.17"
version "2.0.18"
description "Framework Bridge By Jimathy"
fx_version "cerulean"
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'

118
shared/_authToken.lua Normal file
View File

@@ -0,0 +1,118 @@
-------------------------------------------------------------
-- Exploit Auth System
-------------------------------------------------------------
AuthEvent = nil
currentToken = nil
if isServer() then
local AuthEvent = getScript()..":"..keyGen()..keyGen()..keyGen()..keyGen()..":"..keyGen()..keyGen()..keyGen()..keyGen()
validTokens = validTokens or {}
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
return token
end)
function timeOutAuth(token, src)
local token = token
SetTimeout(10000, function()
if token == validTokens[src] then
print("^1--------------------------------------------^7")
print("^7Clearing token for player ^1"..src.."^7", token)
print("^7This shouldn't happen unless a token has been called by a player or script and it hasn't been used")
print("^1--------------------------------------------^7")
end
end)
end
RegisterNetEvent(getScript()..":clearAuthToken", function()
local src = source
debugPrint("^1Auth^7: ^2Manually removing token for Player Source^7:", src, validTokens[src])
validTokens[src] = nil
end)
receivedEvent = {}
authCooldown = {}
createCallback(getScript()..":callback:GetAuthEvent", function(source)
local src = source
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
if authCooldown[src] then
debugPrint("^1Auth^7: ^3Cooldown active^7 for Player ^1"..src.."^7, ignoring additional auth request")
return ""
end
debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent)
authCooldown[src] = true
SetTimeout(5000, function() -- 5 second cooldown
authCooldown[src] = nil
end)
if not receivedEvent[src] then
receivedEvent[src] = true
return AuthEvent
else
print("^1Auth^7: ^1Player ^7"..src.." ^1tried to request auth token more than once^7")
return ""
end
end)
RegisterNetEvent(getScript()..":clearAuthEventRequest", function()
local src = source
debugPrint("^1Auth^7: ^2Manually clearing Auth Event for Player Source^7:", src, AuthEvent)
receivedEvent[src] = nil
end)
-- Multiuse function to check if the generated client token is valid
function checkToken(src, token, genType, name)
if token == nil then
debugPrint("^1Auth^7: ^1No token recieved^7")
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1without an auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1without an auth token^7")
end
return false
else
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])
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1with an incorrect auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1with an incorrect auth token^7")
end
return false
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
return true
end
end
end
else
onPlayerLoaded(function()
debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7")
AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent")
end, true)
onPlayerUnload(function()
debugPrint("^1Auth^7: ^2Clearing Auth Event^7")
TriggerServerEvent(getScript()..":clearAuthEventRequest")
end, true)
end

View File

@@ -47,22 +47,21 @@ function onPlayerLoaded(func, onStart)
if isStarted(QBExport) or isStarted(QBXExport) then
onPlayerFramework = QBExport
AddEventHandler('QBCore:Client:OnPlayerLoaded', tempFunc)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', tempFunc)
elseif isStarted(ESXExport) then
onPlayerFramework = ESXExport
AddEventHandler('esx:playerLoaded', function()
RegisterNetEvent('esx:playerLoaded', function()
if waitForSharedLoad() then
if isStarted(ESXExport) then Wait(1000) end
tempFunc()
end
end
)
elseif isStarted(OXCoreExport) then
onPlayerFramework = OXCoreExport
AddEventHandler('ox:playerLoaded', tempFunc)
RegisterNetEvent('ox:playerLoaded', tempFunc)
elseif isStarted(RSGExport) then
onPlayerFramework = RSGExport
AddEventHandler('RSGCore:Client:OnPlayerLoaded', tempFunc)
RegisterNetEvent('RSGCore:Client:OnPlayerLoaded', tempFunc)
end
if onPlayerFramework ~= "" then
@@ -83,12 +82,15 @@ end
--- end)
--- ```
function onPlayerUnload(func)
AddEventHandler('QBCore:Client:OnPlayerUnload', function() func() end)
AddEventHandler('ox:playerLogout', function() func() end)
AddEventHandler('RSGCore:Client:OnPlayerUnload', function() func() end)
debugPrint("^6Bridge^7: ^2Registering ^3onPlayerUnload^7()")
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() func() end)
RegisterNetEvent('ox:playerLogout', function() func() end)
RegisterNetEvent('RSGCore:Client:OnPlayerUnload', function() func() end)
RegisterNetEvent('esx:onPlayerLogout', 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
end
-------------------------------------------------------------

View File

@@ -24,8 +24,8 @@
--- ```
function createCallback(callbackName, funct)
if isServer() then
debugPrint("^6Bridge^7: ^3Registering callback^7:", callbackName)
if isStarted(OXLibExport) then
debugPrint("^6Bridge^7: ^2Registering ^4"..OXLibExport.." ^3Callback^7:", callbackName)
lib.callback.register(callbackName, funct)
else
local adaptedFunction = function(source, cb, ...)
@@ -34,12 +34,14 @@ function createCallback(callbackName, funct)
end
if isStarted(QBExport) then
debugPrint("^6Bridge^7: ^2Registering ^4"..QBExport.." ^3Callback^7:", callbackName)
Core = Core or exports[QBExport]:GetCoreObject()
Core.Functions.CreateCallback(callbackName, adaptedFunction)
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^2Registering ^4"..ESXExport.." ^3Callback^7:", callbackName)
ESX.RegisterServerCallback(callbackName, adaptedFunction)
else
print("^6Bridge^7: ^1ERROR^7: ^3Can't find any script to register callback with", callbackName)
print("^1ERROR^7: ^1Can't find any supported framework to register callback with^7: "..callbackName)
end
end
end
@@ -64,7 +66,7 @@ end
--- ```
function triggerCallback(callbackName, ...)
local result = nil
debugPrint("^6Bridge^7: ^3Triggering callback^7:", callbackName)
debugPrint("^6Bridge^7: ^2Triggering ^3Callback^7:", callbackName)
if isStarted(OXLibExport) then
result = lib.callback.await(callbackName, false, ...)
elseif isStarted(QBExport) then

View File

@@ -98,6 +98,15 @@ else
}
end
end
if isStarted(OXInv) then
for k, v in pairsByKeys(Items) do
local tempInfo = exports[OXInv]:Items(k)
if tempInfo and tempInfo.client then
Items[k].image = (tempInfo.client and tempInfo.client.image) and tempInfo.client.image:gsub("nui://"..OXInv.."/web/images/", "") or k..".png"
Items[k].hunger = tempInfo.client and tempInfo.client.hunger
Items[k].thirst = tempInfo.client and tempInfo.client.thirst
end
end
end
end)
end

View File

@@ -110,7 +110,7 @@ function craftingMenu(data)
local label = Items[l] and Items[l].label or "error - "..l
local hasItem = checkStashItem(data.stashName, { [l] = b })
local missingMark = not hasItem and "" or " "
settext = settext..(settext ~= "" and br or "").."[ x"..b.." ] - "..label..(b > 1 and " x"..b or "")..missingMark
settext = settext..(settext ~= "" and br or "").."[ x"..b.." ] - "..label..missingMark
metaTable[Items[l] and Items[l].label or "error - "..l] = b
itemTable[l] = b
@@ -400,7 +400,7 @@ function makeItem(data)
currentToken = nil -- clear client cached token
CreateThread(function()
if data.craft["hasCrafted"] ~= nil then
debugPrint("hasCrafted Found, marking '"..data.item.."' as crafted for player")
debugPrint("^5Bridge^7: ^3hasCrafted ^2Found^7, ^2marking ^7'^4"..data.item.."^7' ^2as crafted for player^7")
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:SetMetadata", "craftedItems", data.craftable.craftedItems)
end
@@ -408,7 +408,7 @@ function makeItem(data)
if data.craft["exp"] ~= nil then
craftingLevel += data.craft["exp"].give
jsonPrint(data.craft["exp"])
debugPrint("exp found, giving exp for '"..data.item.."'")
debugPrint("^6Bridge^7: ^3EXP ^2found^7, ^2giving exp for ^7'^4"..data.item.."^7'")
triggerCallback(getScript()..":server:SetMetadata", "craftingLevel", craftingLevel)
end
end)
@@ -457,9 +457,9 @@ end
--- @usage
RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable, stashName, metadata, token)
local src = source
debugPrint(GetInvokingResource())
-- debugPrint("^6Bridge^7: ^4"..getScript().."^7:^4Crafting^7:^4GetItem ^2invoked by^7: "..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")
debugPrint("^1ERROR^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return
end

View File

@@ -5,7 +5,7 @@
or other type (e.g., coyote). It uses predefined model hashes stored in the AnimalPeds table.
Global Flags:
- isCat, isDog, isBigDog, isSmallDog, isCoyote, isAnimal: Booleans to track the player's
- isCat, isPedDog, isBigDog, isSmallDog, isCoyote, isAnimal: Booleans to track the player's
current animal classification.
When running client-side (not on the server), the module checks the player's Ped after they load.
@@ -26,13 +26,13 @@
]]
-- Global animal classification flags.
isCat, isDog, isBigDog, isSmallDog, isCoyote, isAnimal = false, false, false, false, false, false
isPedCat, isPedDog, isBigDog, isSmallDog, isCoyote, isAnimal = false, false, false, false, false, false
if not isServer() then
onPlayerLoaded(function()
Wait(2000)
Wait(1000)
-- Reset classification flags
isCat, isDog, isBigDog, isSmallDog, isCoyote = false, false, false, false, false
isPedCat, isPedDog, isBigDog, isSmallDog, isCoyote = false, false, false, false, false
-- Check if the player's Ped is an animal.
isPedAnimal()
if isAnimal then
@@ -41,18 +41,18 @@ if not isServer() then
-- Determine if the Ped is a cat:
-- Also treat 'ft-raccoon' as a cat unless it is 'ft-sphynx'
isCat = (isCat(ped) or pedModel == `ft-raccoon`) and (pedModel ~= `ft-sphynx`)
isPedCat = (isCat(ped) == true or pedModel == `ft-raccoon`) and (pedModel ~= `ft-sphynx`)
-- Determine if the Ped is a dog and whether it's big:
isDog, isBigDog = isDog(ped)
isPedDog, isBigDog = isDog(ped)
isSmallDog = not isBigDog
if isDog and pedModel == `a_c_coyote` then isDog = false end
if isPedDog and pedModel == `a_c_coyote` then isPedDog = false end
-- Determine if the Ped is a coyote (special case):
isCoyote = (pedModel == `ft-sphynx` or pedModel == `a_c_coyote`)
-- Special override: if model is 'ft-capmonkey2', treat as a dog.
if pedModel == `ft-capmonkey2` then isDog = true end
if pedModel == `ft-capmonkey2` then isPedDog = true end
end
end, true)
@@ -79,7 +79,7 @@ if not isServer() then
for animalModelHash, _ in pairs(animalCategory) do
if PedModel == animalModelHash then
isAnimal = true
debugPrint("^6Bridge^7: ^2Ped is Animal")
debugPrint("^4isAnimal^7: ^2Ped is ^4Animal")
return true
end
end
@@ -109,6 +109,7 @@ if not isServer() then
local PedModel = GetEntityModel(ped or PlayerPedId())
for modelHash, _ in pairs(AnimalPeds.CatPeds) do
if PedModel == modelHash then
debugPrint("^4isAnimal^7: ^2Ped is ^4Cat")
return true
end
end
@@ -126,8 +127,8 @@ if not isServer() then
---
---@usage
--- ```lua
--- local isDog, isBigDog = isDog()
--- if isDog then
--- local isPedDog, isBigDog = isDog()
--- if isPedDog then
--- if isBigDog then
--- print("Player is a big dog!")
--- else
@@ -151,11 +152,13 @@ if not isServer() then
local PedModel = GetEntityModel(ped or PlayerPedId())
for modelHash, _ in pairs(AnimalPeds.BigDogs) do
if PedModel == modelHash then
debugPrint("^4isAnimal^7: ^2Ped is ^4Dog")
return true, true
end
end
for modelHash, _ in pairs(AnimalPeds.SmallDogs) do
if PedModel == modelHash then
debugPrint("^4isAnimal^7: ^2Ped is ^4Small Dog")
return true, false
end
end

View File

@@ -30,25 +30,34 @@ validTokens = {}
--- end)
--- ```
function createUseableItem(item, funct)
if isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7es_extended^7", item)
while not ESX do Wait(0) end
ESX.RegisterUsableItem(item, funct)
if doesItemExist(item) then
local itemResource = ""
if isStarted(ESXExport) then
itemResource = ESXExport
while not ESX do Wait(0) end
ESX.RegisterUsableItem(item, funct)
elseif isStarted(QBExport) and not isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qb-core^7", item)
Core.Functions.CreateUseableItem(item, funct)
elseif isStarted(QBExport) and not isStarted(QBXExport) then
itemResource = QBExport
Core.Functions.CreateUseableItem(item, funct)
elseif isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qbx_core^7", item)
exports[QBXExport]:CreateUseableItem(item, funct)
elseif isStarted(QBXExport) then
itemResource = QBXExport
exports[QBXExport]:CreateUseableItem(item, funct)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^1rsg-core^7", item)
Core.Functions.CreateUseableItem(item, funct)
elseif isStarted(RSGExport) then
itemResource = RSGExport
Core.Functions.CreateUseableItem(item, funct)
end
if itemResource ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^3UsableItem^2 with ^4"..itemResource.."^7:", item)
else
debugPrint("^4ERROR^7: No supported framework detected for registering usable item: ^3"..item.."^7")
end
else
print("^4ERROR^7: No supported framework detected for registering usable item: ^3"..item.."^7")
print("^1ERROR^7: ^1Tried to make item usable but it didn't exist^7: "..item)
end
end
@@ -708,8 +717,6 @@ end
-------------------------------------------------------------
-- Server Callback Registration
-------------------------------------------------------------
AuthEvent = nil
currentToken = nil
if isServer() then
createCallback(getScript()..":server:canCarry", function(source, itemTable)
local result = canCarry(itemTable, source)
@@ -735,103 +742,130 @@ if isServer() then
end
return maxCanCarry
end)
end
local AuthEvent = getScript()..":"..keyGen()..keyGen()..keyGen()..keyGen()..":"..keyGen()..keyGen()..keyGen()..keyGen()
validTokens = validTokens or {}
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 ""
function getMaxInvWeight()
local weight = 0
if isStarted(QBInv) then
if checkExportExists(QBInv, "GetMaxWeight") then
return exports[QBInv]:GetMaxWeight()
else
return InventoryWeight
end
end
if isStarted(PSInv) then
if checkExportExists(PSInv, "GetMaxWeight") then
return exports[PSInv]:GetMaxWeight()
else
return InventoryWeight
end
end
if isStarted(RSGInv) then
if checkExportExists(RSGInv, "GetMaxWeight") then
return exports[RSGInv]:GetMaxWeight()
else
return InventoryWeight
end
end
if isStarted(JPRInv) then
if checkExportExists(JPRInv, "GetMaxWeight") then
return exports[JPRInv]:GetMaxWeight()
else
return InventoryWeight
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
return token
end)
function timeOutAuth(token, src)
local token = token
SetTimeout(10000, function()
if token == validTokens[src] then
print("^1--------------------------------------------^7")
print("^7Clearing token for player ^1"..src.."^7", token)
print("^7This shouldn't happen unless a token has been called by a player or script and it hasn't been used")
print("^1--------------------------------------------^7")
end
end)
end
RegisterNetEvent(getScript()..":clearAuthToken", function()
local src = source
debugPrint("^1Auth^7: ^2Manually removing token for Player Source^7:", src, validTokens[src])
validTokens[src] = nil
end)
if isStarted(OXInv) then
return exports[OXInv]:GetPlayerMaxWeight()
end
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 ""
if isStarted(QSInv) then
return InventoryWeight
end
if isStarted(CoreInv) then
return InventoryWeight
end
if isStarted(CodeMInv) then
return InventoryWeight
end
if isStarted(OrigenInv) then
return InventoryWeight
end
if isStarted(TgiannInv) then
return InventoryWeight
end
-- For ESX default inventory (es_extended)
if ESX and isStarted(ESXExport) then
return InventoryWeight
end
return InventoryWeight
end
function getCurrentInvWeight()
local weight = 0
if isStarted(QBInv) or isStarted(PSInv) or isStarted(RSGInv) or isStarted(JPRInv) then
local itemcheck = Core.Functions.GetPlayerData().items
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
end
debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent)
if not receivedEvent[src] then
receivedEvent[src] = true
return AuthEvent
else
print("^1Auth^7: ^1Player ^7"..src.." ^1tried to request auth token more than once^7")
return ""
end
if isStarted(OXInv) then
weight = exports[OXInv]:GetPlayerWeight()
end
if isStarted(QSInv) then
local itemcheck = exports[QSInv]:getUserInventory()
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
end
end)
end
RegisterNetEvent(getScript()..":clearAuthEventRequest", function()
local src = source
debugPrint("^1Auth^7: ^2Manually clearing Auth Event for Player Source^7:", src, AuthEvent)
receivedEvent[src] = nil
end)
if isStarted(CoreInv) then
local itemcheck = exports[CoreInv]:getInventory()
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
end
end
-- Multiuse function to check if the generated client token is valid
function checkToken(src, token, genType, name)
if token == nil then
debugPrint("^1Auth^7: ^1No token recieved^7")
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1without an auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1without an auth token^7")
end
return false
else
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])
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1with an incorrect auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1with an incorrect auth token^7")
end
return false
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
return true
if isStarted(CodeMInv) then
local itemcheck = exports[CodeMInv]:GetClientPlayerInventory()
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
end
end
if isStarted(OrigenInv) then
local itemcheck = exports[OrigenInv]:getPlayerInventory()
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
end
end
if isStarted(TgiannInv) then
local itemcheck = exports[TgiannInv]:GetPlayerItems()
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
end
end
-- For ESX default inventory (es_extended)
if ESX and isStarted(ESXExport) then
local xPlayer = ESX.GetPlayerData() or {}
if xPlayer.inventory then
for _, v in pairs(xPlayer.inventory) do
weight += ((v.weight * v.amount) or 0)
end
end
end
else
onPlayerLoaded(function()
debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7")
AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent")
end, true)
onPlayerUnload(function()
debugPrint("^1Auth^7: ^2Clearing Auth Event^7")
TriggerServerEvent(getScript()..":clearAuthEventRequest")
end, true)
return weight
end
-------------------------------------------------------------

View File

@@ -242,5 +242,8 @@ function openBossMenu(isGang, group)
end
elseif isStarted("qbx_management") then
exports["qbx_management"]:OpenBossMenu(isGang and "gang" or "job")
elseif isStarted("esx_society") then
TriggerEvent('esx_society:openBossMenu', group, function() end, { wash = false })
end
end

View File

@@ -187,7 +187,7 @@ end
--- ```
function playAnim(animDict, animName, duration, flag, ped, speed)
loadAnimDict(animDict)
debugPrint("Attempting to make player play anim", animDict, animName)
debugPrint("^6Bridge^7: ^3playAnim^7() ^2Triggered^7: ", animDict, animName)
TaskPlayAnim(ped and ped or PlayerPedId(), animDict, animName, speed or 8.0, speed or -8.0, duration or 30000, flag or 50, 1, false, false, false)
end
@@ -204,7 +204,7 @@ end
--- stopAnim('amb@world_human_hang_out_street@male_c@base', 'base', PlayerPedId())
--- ```
function stopAnim(animDict, animName, ped)
debugPrint("Stopping anim for "..(ped or PlayerPedId()))
debugPrint("^6Bridge^7: ^3stopAnim^7() ^2Triggered^7: ", animDict, animName)
StopAnimTask(ped or PlayerPedId(), animDict, animName, 0.5)
StopAnimTask(ped or PlayerPedId(), animName, animDict, 0.5)
unloadAnimDict(animDict)

View File

@@ -54,14 +54,14 @@ function makeDistVehicle(data, radius, onEnter, onExit)
onEnter = function()
vehicle = makeVeh(data.model, data.coords)
if onEnter then
debugPrint("makeDistVehicle onEnter running")
debugPrint("^6Bridge^7: ^4makeDistVehicle ^3onEnter^7() ^2running^7")
onEnter(vehicle)
end
end,
onExit = function()
deleteVehicle(vehicle)
if onExit then
debugPrint("makeDistVehicle onExit running")
debugPrint("^6Bridge^7: ^4makeDistVehicle ^3onExit^7() ^2running^7")
onExit(vehicle)
end
end,

View File

@@ -1,4 +1,5 @@
local inProgress = false
local storedPID = nil
--- Displays a progress bar using the configured progress bar system.
---
@@ -48,7 +49,7 @@ function progressBar(data)
label = data.label,
position = data.position or "bottom",
useWhileDead = data.dead or false,
canCancel = data.cancel and data.cancel or true,
canCancel = data.cancel or true,
anim = {
dict = data.dict,
clip = data.anim,
@@ -57,8 +58,8 @@ function progressBar(data)
},
disable = {
combat = data.combat or true,
move = data.movement or false,
car = data.carMovement or false,
move = data.disableMovement or false,
car = data.disableMovement or false,
mouse = data.mouse or false
},
}
@@ -99,8 +100,19 @@ function progressBar(data)
debugMode and 1000 or data.time,
data.dead or false,
data.cancel or true,
{ disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true },
{ animDict = data.dict, anim = data.anim, flags = data.flag or 32, task = data.task }, {}, {},
{
disableMovement = data.disableMovement or false,
disableCarMovement = data.disableMovement or false,
disableMouse = data.disableMouse or false,
disableCombat = data.disableCombat or true,
},
{
animDict = data.dict,
anim = data.anim,
flags = data.flag or 32,
task = data.task
},
{}, {},
function()
result = true
end, function()
@@ -125,14 +137,15 @@ function progressBar(data)
elseif Config.System.ProgressBar == "red" then
-- Currently only uses jim-redui if you choose this option
if exports["jim-redui"]:progressBar({
if exports["jim_bridge"]:redProgressBar({
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,
disableMovement = data.disableMovement or false,
cancel = data.cancel or true,
}) then
result = true
else
@@ -140,73 +153,21 @@ function progressBar(data)
end
elseif Config.System.ProgressBar == "gta" then
loadTextureDict("timerbars")
if inProgress then return false end
inProgress = true
local wait = debugMode and 1000 or data.time
local endTime = GetGameTimer() + wait
local ped = PlayerPedId()
-- Setup Animation/Task if specified
if data.dict then
playAnim(data.dict, data.anim, -1, data.flag or 32)
elseif data.task then
TaskStartScenarioInPlace(ped, data.task, -1, true)
if exports["jim_bridge"]:gtaProgressBar({
label = data.label,
time = debugMode and 1000 or data.time,
dict = data.dict,
anim = data.anim,
flag = data.flag or 32,
task = data.task,
disableMovement = data.disableMovement or false,
cancel = data.cancel or true,
}) then
result = true
else
result = false
end
-- Progress bar rendering loop
CreateThread(function()
while GetGameTimer() < endTime and inProgress do
Wait(0)
local elapsed = GetGameTimer()
local percentage = ((elapsed - (endTime - wait)) / wait) * 100
-- Convert to segmented progress (assuming 5 segments here)
local segments = 5 -- Number of segments in the bar
local segmentProgress = {}
local progressPerSegment = 100 / segments
for i = 1, segments do
local segmentStart = (i - 1) * progressPerSegment
local segmentEnd = i * progressPerSegment
if percentage >= segmentEnd then
segmentProgress[i] = 100
elseif percentage <= segmentStart then
segmentProgress[i] = 0
else
segmentProgress[i] = ((percentage - segmentStart) / progressPerSegment) * 100
end
end
percentage = percentage >= 100 and 100 or percentage
-- Draw your segmented progress bar
ShowGTAProgressBar(segmentProgress, data.label, ("%.0f%%"):format(percentage))
-- Controls to disable during progress
DisablePlayerFiring(ped, true)
DisableControlAction(0, 25, true) -- Disable aim
DisableControlAction(0, 21, true) -- Disable sprint
DisableControlAction(0, 30, true) -- Disable move left/right
DisableControlAction(0, 31, true) -- Disable move forward/back
DisableControlAction(0, 36, true) -- Disable stealth
if data.cancel and (IsControlJustReleased(0, 202) or IsControlJustReleased(0, 177) or IsControlJustReleased(0, 73)) then
inProgress = false
end
end
end)
-- Wait for completion or cancel
while GetGameTimer() < endTime and inProgress do
Wait(100)
end
-- Cleanup animations/tasks
if data.dict then stopAnim(data.dict, data.anim, ped) end
ClearPedTasks(ped)
result = inProgress
inProgress = false
end
while result == nil do
@@ -235,51 +196,6 @@ function progressBar(data)
return result
end
function ShowGTAProgressBar(currentProg, title, level)
local loc = vec2(0.37, 0.90)
local size = vec2(0.3, 0.03)
-- Draw background box
DrawSprite("timerbars", "all_black_bg", loc.x +0.028, loc.y-0.01, 0.15, 0.07, 0.0, 255, 255, 255, 255)
DrawSprite("timerbars", "all_black_bg", loc.x +0.170, loc.y-0.01, 0.15, 0.07, 180.0, 255, 255, 255, 255)
SetTextFont(0)
SetTextProportional(1)
SetTextScale(0.35, 0.35)
SetTextColour(255, 255, 255, 255)
SetTextDropshadow(0, 0, 0, 0, 255)
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
AddTextComponentString(title)
DrawText(loc.x - size.x / 4 + 0.074, loc.y - 0.034) -- Adjust text position
SetTextFont(0)
SetTextProportional(1)
SetTextScale(0.35, 0.25)
SetTextColour(255, 255, 255, 255)
SetTextEntry("STRING")
AddTextComponentString(level)
DrawText(loc.x - size.x / 4 + 0.246, loc.y - 0.030) -- Right-aligned additional text
local segmentWidth = (size.x + 0.05) / (#currentProg * 2) -- Divide the total width by 18 (9 segments * 2 gaps for each)
local gap = segmentWidth / #currentProg -- Smaller gap between segments
for i = 1, #currentProg do
local segmentX = (loc.x - size.x / 4 ) + 0.075 + (i - 1) * (segmentWidth + gap)
local fillPercentage = currentProg[i]
local progressBarWidth = segmentWidth * (fillPercentage / 100)
-- Semi-transparent background for each segment
DrawRect(segmentX + segmentWidth / 2, loc.y, segmentWidth, size.y / 3.4, 100, 100, 100, 255)
-- Filling progress for each segment
if progressBarWidth > 0 then
DrawRect(segmentX + progressBarWidth / 2, loc.y, progressBarWidth, size.y / 3.4, 93, 182, 229, 255) -- Blue progress
end
end
end
--- Stops the current progress bar.
---
--- This function cancels the progress bar based on the configured progress bar system, handling any necessary cleanup.
@@ -289,14 +205,13 @@ function stopProgressBar()
elseif Config.System.ProgressBar == "qb" then
TriggerEvent("progressbar:client:cancel")
elseif Config.System.ProgressBar == "gta" or Config.System.ProgressBar == "red" then
inProgress = false
exports["jim_bridge"]:stopProgressBar()
end
end
-- System to handle sending/sharing progress bars between players --
-- For example, healing someone --
local storedPID = nil
--- Server event handler for starting a shared progress bar.
--- This event is triggered when a player wants to start a progress bar on another player.

View File

@@ -31,6 +31,7 @@
--- triggerNotify("Alert", "You have been warned for misconduct.", "error", playerId)
--- ```
function triggerNotify(title, message, type, src)
if not Config.System or not Config.System.Notify then debugPrint("Notify triggered but not set up") return end
if Config.System.Notify == "okok" then
if not src then
TriggerEvent('okokNotify:Alert', title, message, 6000, type)

View File

@@ -159,6 +159,9 @@ function billPlayer(data)
coords = data.coords.xyz,
img = data.img
})
elseif Config.System.Billing == "okok" then
-- TriggerServerEvent("okokBilling:CreateCustomInvoice", target, price, reason, invoiceSource, society, societyName)
TriggerEvent("okokBilling:ToggleCreateInvoice")
end
end
@@ -173,6 +176,7 @@ end
--- chargePlayer(100, "cash", playerId)
--- ```
function chargePlayer(cost, moneyType, newsrc)
local is_success = false
local src = newsrc or source
local fundResource = ""
if cost < 0 then
@@ -181,33 +185,35 @@ function chargePlayer(cost, moneyType, newsrc)
end
if moneyType == "cash" then
if isStarted(OXInv) then fundResource = OXInv
exports[OXInv]:RemoveItem(src, "money", cost)
is_success = exports[OXInv]:RemoveItem(src, "money", cost)
elseif isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost)
is_success = Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost)
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost)
is_success = Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).removeMoney(cost, "")
is_success = true
end
elseif moneyType == "bank" then
if isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost)
is_success = Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost)
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost)
is_success = Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).removeMoney(cost, "")
is_success = true
end
end
@@ -216,6 +222,7 @@ function chargePlayer(cost, moneyType, newsrc)
else
debugPrint("^6Bridge^7: ^2Charging ^2Player^7: '^6"..cost.."^7'", moneyType, fundResource)
end
return is_success
end
RegisterNetEvent(getScript()..":server:ChargePlayer", function(cost, moneyType, newsrc)
debugPrint(GetInvokingResource())
@@ -237,39 +244,42 @@ end)
--- fundPlayer(150, "cash", playerId)
--- ```
function fundPlayer(fund, moneyType, newsrc)
local is_success = false
local src = newsrc or source
local fundResource = ""
if moneyType == "cash" then
if isStarted(OXInv) then
fundResource = OXInv
exports[OXInv]:AddItem(src, "money", fund)
is_success = exports[OXInv]:AddItem(src, "money", fund)
elseif isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.AddMoney("cash", fund)
is_success = Core.Functions.GetPlayer(src).Functions.AddMoney("cash", fund)
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.AddMoney("cash", fund)
is_success = Core.Functions.GetPlayer(src).Functions.AddMoney("cash", fund)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).addMoney(fund, "")
is_success = true
end
elseif moneyType == "bank" then
if isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.AddMoney("bank", fund)
is_success = Core.Functions.GetPlayer(src).Functions.AddMoney("bank", fund)
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.AddMoney("bank", fund)
is_success = Core.Functions.GetPlayer(src).Functions.AddMoney("bank", fund)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).addMoney(fund, "")
is_success = true
end
end
@@ -278,6 +288,7 @@ function fundPlayer(fund, moneyType, newsrc)
else
debugPrint("^6Bridge^7: ^2Funding Player: '^2"..fund.."^7'", moneyType, fundResource)
end
return is_success
end
-------------------------------------------------------------

View File

@@ -175,18 +175,12 @@ function openShop(data)
TriggerEvent("codem-inventory:openshop", data.shop)
elseif isStarted(QBInv) then
if QBInvNew then
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
else
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
end
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
elseif isStarted(PSInv) then
if QBInvNew then
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
else
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
end
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
elseif isStarted(RSGInv) then
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
@@ -195,10 +189,10 @@ function openShop(data)
end
RegisterNetEvent(getScript()..':server:openServerShop', function(data)
if isStarted(QBInv) then
if isStarted(QBInv) and checkExportExists(QBInv, "OpenShop") then
exports[QBInv]:OpenShop(source, data)
end
if isStarted(PSInv) then
if isStarted(PSInv) and checkExportExists(PSInv, "OpenShop") then
exports[PSInv]:OpenShop(source, data)
end
if isStarted(TgiannInv) then
@@ -221,8 +215,9 @@ end)
--- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons")
--- ```
function registerShop(name, label, items, society)
local shopResource = ""
if isStarted(OXInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Store^7:", name, label)
shopResource = OXInv
exports[OXInv]:RegisterShop(name, {
name = label,
inventory = items,
@@ -230,11 +225,11 @@ function registerShop(name, label, items, society)
})
elseif isStarted(TgiannInv) then
debugPrint("^6Bridge^7: ^2Registering ^3Tgiann ^2Store^7:", name, label)
shopResource = TgiannInv
exports[TgiannInv]:RegisterShop(name, items)
elseif isStarted(QBInv) and QBInvNew then
debugPrint("^6Bridge^7: ^2Registering ^3QB ^2Store^7:", name, label)
elseif isStarted(QBInv) and checkExportExists(QBInv, "CreateShop") then
shopResource = QBInv
exports[QBInv]:CreateShop({
name = name,
label = label,
@@ -243,8 +238,8 @@ function registerShop(name, label, items, society)
society = society,
})
elseif isStarted(PSInv) and QBInvNew then
debugPrint("^6Bridge^7: ^2Registering ^3PS ^2Store^7:", name, label)
elseif isStarted(PSInv) and checkExportExists(PSInv, "CreateShop") then
shopResource = PSInv
exports[PSInv]:CreateShop({
name = name,
label = label,
@@ -254,7 +249,7 @@ function registerShop(name, label, items, society)
})
elseif isStarted(RSGInv) then
debugPrint("^6Bridge^7: ^2Registering ^3RSG ^2Store^7:", name, label)
shopResource = RSGInv
exports[RSGInv]:CreateShop({
name = name,
label = label,
@@ -263,4 +258,9 @@ function registerShop(name, label, items, society)
society = society,
})
end
if shopResource ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^5"..shopResource.." ^3Store^7:", name, "^4Label^7: "..label)
else
debugPrint("^1ERROR^7: ^1Couldn't find supported inventory to register shop^7:", name)
end
end

View File

@@ -192,6 +192,7 @@ function openStash(data)
slots = data.slots or 40
})
else
TriggerEvent("ps-inventory:client:SetCurrentStash", data.stash)
TriggerEvent("inventory:client:SetCurrentStash", data.stash)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, {
slots = data.slots or 50,
@@ -243,18 +244,14 @@ end)
function clearStash(stashId)
if isStarted(JPRInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..JPRInv.."^2 Stash^7", stashId)
if QBInvNew then
exports[JPRInv]:ClearStash(stashId)
else
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashId,
['items'] = json.encode({})
})
end
debugPrint("^5Bridge^7: ^2Clearing ^3"..JPRInv.."^2 Stash^7", stashId)
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashId,
['items'] = json.encode({})
})
elseif isStarted(QBInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..QBInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..QBInv.."^2 Stash^7", stashId)
if QBInvNew then
exports[QBInv]:ClearStash(stashId)
else
@@ -265,43 +262,38 @@ function clearStash(stashId)
end
elseif isStarted(OXInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..OXInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..OXInv.."^2 Stash^7", stashId)
exports[OXInv]:ClearInventory(stashId)
elseif isStarted(PSInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..PSInv.."^2 Stash^7", stashId)
if QBInvNew then
exports[PSInv]:ClearStash(stashId)
else
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashId,
['items'] = json.encode({})
})
end
debugPrint("^5Bridge^7: ^2Clearing ^3"..PSInv.."^2 Stash^7", stashId)
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashId,
['items'] = json.encode({})
})
elseif isStarted(QSInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..QSInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..QSInv.."^2 Stash^7", stashId)
exports[QSInv]:ClearOtherInventory('stash', stashId)
elseif isStarted(CoreInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..CoreInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..CoreInv.."^2 Stash^7", stashId)
exports[CoreInv]:clearInventory("stash-"..stashId)
elseif isStarted(CodeMInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..CodeMInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..CodeMInv.."^2 Stash^7", stashId)
exports[CodeMInv]:ClearInventory(stashId)
elseif isStarted(OrigenInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..OrigenInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..OrigenInv.."^2 Stash^7", stashId)
exports[OrigenInv]:ClearInventory(stashId)
elseif isStarted(TgiannInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..TgiannInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..TgiannInv.."^2 Stash^7", stashId)
exports["tgiann-inventory"]:DeleteInventory("stash", stashId)
elseif isStarted(RSGInv) then
debugPrint("^5Bridge^7: ^2Cleared ^3"..RSGInv.."^2 Stash^7", stashId)
debugPrint("^5Bridge^7: ^2Clearing ^3"..RSGInv.."^2 Stash^7", stashId)
exports[RSGInv]:ClearStash(stashId)
end
@@ -644,27 +636,25 @@ end
--- )
--- ```
function registerStash(name, label, slots, weight, owner, coords)
local stashResource = ""
if isStarted(OXInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Stash^7:", name, label, owner or nil)
stashResource = OXInv
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
--elseif isStarted(QSInv) then
-- debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label)
-- exports[QSInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
--elseif isStarted(CoreInv) then
-- debugPrint("^6Bridge^7: ^2Registering ^3CoreInv ^2Stash^7:", name, label)
-- exports[CoreInv]:openHolder(nil, name, 'stash', nil, nil, false, nil)
elseif isStarted(OrigenInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OrigenInv ^2Stash^7:", name, label)
stashResource = OrigenInv
exports["origen_inventory"]:registerStash(name, label, slots or 50, weight or 4000000)
elseif isStarted(TgiannInv) then
debugPrint("^6Bridge^7: ^2Registering ^3TgiannInv ^2Stash^7:", name, label)
stashResource = TgiannInv
exports[TgiannInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
end
if stashResource ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^4"..stashResource.." ^3Stash^7:", name, "^4Label^7: "..label)
else
debugPrint("^1ERROR^7: ^1Couldn't find supported inventory to register stash^7:", name)
end
end
if isServer() then

View File

@@ -21,24 +21,29 @@
--- })
--- ```
function registerCommand(command, options)
local commandResource = ""
if isStarted(OXLibExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..OXLibExport, command)
commandResource = OXLibExport
lib.addCommand(command, { help = options[1], restricted = options[5] and "group."..options[5] or nil }, options[4])
elseif isStarted(QBExport) and not isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..QBExport, command)
commandResource = QBExport
Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] or nil)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..RSGExport, command)
commandResource = RSGExport
Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] or nil)
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7ESX Legacy", command)
commandResource = ESXExport
ESX.RegisterCommand(command, options[5] or 'admin', function(xPlayer, args, showError)
options[4](xPlayer.source, args, showError)
end, false, { help = options[1] })
end
if commandResource ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^4"..commandResource.."^7:", "^7/"..command)
else
print("^1ERROR^7: ^1Couldn't find supported framework to register command^7:", "/"..command)
end
end

View File

@@ -177,7 +177,7 @@ for _, v in pairs({ -- This is a specific load order
'effects.lua',
--'warmenu.lua',
'_authToken.lua',
-- Do version check last
'_scriptversioncheck.lua'
}) do
@@ -191,16 +191,46 @@ for _, v in pairs({ -- This is a specific load order
end
end
-- Auto Detection of Old/New QBInv/PSInv versions --
if isStarted(QBInv) then
if not checkExportExists(QBInv, "HasItem") then
print("^6Bridge^7: ^2Can^7'^2t ^2find new QBInv export^7, ^2forcing ^1QBInvNew ^2to ^1false^7")
QBInvNew = false
if isServer() then
if not checkExportExists(QBInv, "CreateShop") then
print("^6Bridge^7: ^2Can^7'^2t ^2find new ^4"..QBInv.."^2 export^7, ^2forcing ^1QBInvNew ^2to ^1false^7")
QBInvNew = false
end
else
if checkExportExists(QBInv, "GetTrunkSize") then
print("^6Bridge^7: ^2Found old ^4"..QBInv.."^3 export^7, ^2forcing ^1QBInvNew ^2to ^1false^7")
QBInvNew = false
end
end
end
if isStarted(PSInv) then
if not checkExportExists(PSInv, "HasItem") then
print("^6Bridge^7: ^2Can^7't ^2find new PSInv export^7, ^2forcing ^1QBInvNew ^2to ^1false^7")
QBInvNew = false
if isServer() then
if not checkExportExists(PSInv, "CreateShop") then
print("^6Bridge^7: ^2Can^7'^2t ^2find new ^4"..PSInv.."^2 export^7, ^2forcing ^1QBInvNew ^2to ^1false^7")
QBInvNew = false
end
else
local function versionCompare(v1, v2)
local split = function(v) local t = {} for s in v:gmatch("[^.]+") do t[#t+1] = tonumber(s) end return t end
local a, b = split(v1), split(v2)
for i = 1, math.max(#a, #b) do
local ai, bi = a[i] or 0, b[i] or 0
if ai > bi then return true
elseif ai < bi then return false end
end
return true
end
if versionCompare(GetResourceMetadata("ps-inventory", "version", 0), "1.0.6") then
print("^6Bridge^7: ^4"..PSInv.."^2 Version above ^31.0.6^7, ^2forcing ^1QBInvNew ^2to ^1true^7")
QBInvNew = true
else
print("^6Bridge^7: ^4"..PSInv.."^2 Version ^1below ^31.0.6^7, ^2forcing ^1QBInvNew ^2to ^1false^7")
QBInvNew = false
end
end
end

View File

@@ -2,13 +2,15 @@ local notifications = {}
local spacing = 60 -- vertical spacing between notifications
local activeDrawing = false -- flag for drawing loop state
if not HasStreamedTextureDictLoaded("timerbars") then
while not HasStreamedTextureDictLoaded("timerbars") do
RequestStreamedTextureDict("timerbars")
Wait(5)
end
local function loadTextureDict(dict)
if not HasStreamedTextureDictLoaded(dict) then
while not HasStreamedTextureDictLoaded(dict) do RequestStreamedTextureDict(dict) Wait(5) end
end
end
--- GTA Section ---
local notifTypes = {
success = "✔️",
error = "",
@@ -35,12 +37,13 @@ function gtaNotify(title, message, emoji, src)
-- This allows it to be silent until the first notifcation is called, then the loop starts
if not activeDrawing then
activeDrawing = true
StartDrawingLoop()
StartGTADrawingLoop()
end
end
-- Drawing loop as a separate controlled thread
function StartDrawingLoop()
function StartGTADrawingLoop()
--loadTextureDict("timerbars")
CreateThread(function()
while #notifications > 0 do
local currentTime = GetGameTimer()
@@ -87,14 +90,14 @@ function StartDrawingLoop()
if not notif.title or notif.title == "" then
moveMessage = true
else
drawNotiText(8, 0.4, vec2(0.75, 0.975), notif.title, vec2(posX, posY))
drawGTANotiText(8, 0.4, vec2(0.75, 0.975), notif.title, vec2(posX, posY))
end
-- Message text
drawNotiText(4, 0.3, vec2(0.75, 0.975), notif.message, vec2(posX, posY + (moveMessage and 0.015 or 0.03)))
drawGTANotiText(4, 0.3, vec2(0.75, 0.975), notif.message, vec2(posX, posY + (moveMessage and 0.015 or 0.03)))
-- Emoji
drawNotiText(0, 0.3, vec2(0.75, 0.995), notif.emoji, vec2(posX, posY + 0.015))
drawGTANotiText(0, 0.3, vec2(0.75, 0.995), notif.emoji, vec2(posX, posY + 0.015))
::continue::
end
@@ -104,7 +107,7 @@ function StartDrawingLoop()
end)
end
function drawNotiText(font, scale, wrap, string, pos)
function drawGTANotiText(font, scale, wrap, string, pos)
SetTextFont(font)
SetTextScale(scale, scale)
SetTextWrap(wrap.x, wrap.y)
@@ -116,5 +119,148 @@ function drawNotiText(font, scale, wrap, string, pos)
DrawText(pos.x, pos.y)
end
RegisterNetEvent("jim-bridge:Notify", gtaNotify)
exports("Notify", gtaNotify)
------------------
-- REDM SECTION --
------------------
---
---
local REDMnotifTypes = {
success = vec3(0, 150, 0),
error = vec3(150, 0, 0),
warning = vec3(0, 150, 150),
police = vec3(0, 0, 150),
ambulance = vec3(0, 0, 150),
}
function redNotify(title, message, style)
local notif = {
title = title and CreateVarString(10, "LITERAL_STRING", title) or nil,
message = message and CreateVarString(10, "LITERAL_STRING", message) or nil,
state = "enter",
startTime = GetGameTimer(),
style = REDMnotifTypes[style] or vec3(0, 0, 0),
progress = 0,
holdTime = 8000,
slideDuration = 100,
currentOffset = 0,
}
table.insert(notifications, notif)
-- Activate drawing loop if not already running
if not activeDrawing then
activeDrawing = true
StartREDMDrawingLoop()
end
end
-- Drawing loop as a separate controlled thread
function StartREDMDrawingLoop()
CreateThread(function()
loadTextureDict("generic_textures")
while #notifications > 0 do
local currentTime = GetGameTimer()
-- Update notifications vertical offset
for i, notif in ipairs(notifications) do
local target = (#notifications - i) * spacing
notif.currentOffset += (target - notif.currentOffset) * 0.1
end
for i = #notifications, 1, -1 do
local notif = notifications[i]
if notif.state == "enter" then
local elapsed = currentTime - notif.startTime
notif.progress = math.min(elapsed / notif.slideDuration, 1.0)
if notif.progress >= 1.0 then
notif.state = "hold"
notif.holdStart = currentTime
end
elseif notif.state == "hold" then
if currentTime - notif.holdStart >= notif.holdTime then
notif.state = "exit"
notif.exitStart = currentTime
end
elseif notif.state == "exit" then
local elapsed = currentTime - notif.exitStart
notif.progress = 1.0 - math.min(elapsed / notif.slideDuration, 1.0)
if notif.progress <= 0 then
table.remove(notifications, i)
goto continue
end
end
local startX, targetX = 1.0, 0.8
local posX = startX - (startX - targetX) * notif.progress
local posY = 0.05 + (notif.currentOffset / 1080)
-- Background sprite
DrawSprite("generic_textures", "inkroller_1a", posX + 0.09, posY + 0.025, 0.2, 0.053, 180.0, notif.style.x, notif.style.y, notif.style.z, 150)
-- Title text
local moveMessage = false
if not notif.title or notif.title == "" then
moveMessage = true
else
drawREDMNotiText(1, 0.4, vec2(0.75, 0.975), notif.title, vec2(posX, posY))
end
-- Message text
drawREDMNotiText(6, 0.3, vec2(0.75, 0.975), notif.message, vec2(posX, posY + (moveMessage and 0.0145 or 0.025)))
::continue::
end
Wait(0)
end
activeDrawing = false -- No notifications left, pause drawing
end)
end
function drawREDMNotiText(font, scale, wrap, string, pos)
SetTextFontForCurrentCommand(font)
SetTextScale(scale, scale)
SetTextColor(255, 255, 255, 255)
SetTextWrap(wrap.x, wrap.y)
SetTextJustification(2)
SetTextDropshadow(1, 0, 0, 0, 200)
DisplayText(string, pos.x, pos.y)
end
-- Exports --
-- Example:
-- TriggerEvent("jim_bridge:Notify", nil, "Short test message", "success")
--
-- exports["jim_bridge"]:Notify(nil, "Short test message", "success")
--
RegisterNetEvent("jim_bridge:RedNotify", redNotify)
RegisterNetEvent("jim_bridge:GTANotify", gtaNotify)
RegisterNetEvent("jim_bridge:Notify", function(...)
if GetCurrentGameName() == "rdr3" then
redNotify(...)
else
gtaNotify(...)
end
end)
function Notify(...)
if GetCurrentGameName() == "rdr3" then
redNotify(...)
else
gtaNotify(...)
end
end
exports("Notify", Notify)
-- Example testing notifications (can remove after testing)
--CreateThread(function()
-- TriggerEvent("jim_bridge:Notify", nil, "Short test message", "success")
-- Wait(3000)
-- TriggerEvent("jim_bridge:Notify", "Error!", "This is a longer example message to show stacking.", "error")
-- Wait(3000)
-- TriggerEvent("jim_bridge:Notify", "Test!", "This notification has to 'type' set.", nil )
-- Wait(4000)
--end)

344
ui_modules/progressbar.lua Normal file
View File

@@ -0,0 +1,344 @@
local inProgress = false
local function loadTextureDict(dict)
if not HasStreamedTextureDictLoaded(dict) then
while not HasStreamedTextureDictLoaded(dict) do RequestStreamedTextureDict(dict) Wait(5) end
end
end
function redProgressBar(data)
local ped = PlayerPedId()
local result = nil
loadTextureDict("generic_textures")
if inProgress then return false end
inProgress = true
local wait = debugMode and 1000 or data.time
local endTime = GetGameTimer() + wait
LocalPlayer.state:set("inv_busy", true, true)
TriggerEvent('inventory:client:busy:status', true)
TriggerEvent('canUseInventoryAndHotbar:toggle', not true)
-- Setup Animation/Task if specified
if data.dict then
playAnim(data.dict, data.anim, -1, data.flag or 32)
elseif data.task then
TaskStartScenarioInPlace(ped, data.task, -1, true)
end
-- Progress bar rendering loop
CreateThread(function()
while GetGameTimer() < endTime and inProgress do
Wait(0)
local elapsed = GetGameTimer()
local percentage = ((elapsed - (endTime - wait)) / wait) * 100
-- Convert to segmented progress (assuming 5 segments here)
local segments = 1 -- Number of segments in the bar
local segmentProgress = {}
local progressPerSegment = 100 / segments
for i = 1, segments do
local segmentStart = (i - 1) * progressPerSegment
local segmentEnd = i * progressPerSegment
if percentage >= segmentEnd then
segmentProgress[i] = 100
elseif percentage <= segmentStart then
segmentProgress[i] = 0
else
segmentProgress[i] = ((percentage - segmentStart) / progressPerSegment) * 100
end
end
percentage = percentage >= 100 and 100 or percentage
-- Draw your segmented progress bar
ShowRedProgressBar(segmentProgress, data.label, ("%.0f%%"):format(percentage))
-- Controls to disable during progress
if data.disableMouse then
DisableControlAction(0, `INPUT_LOOK_LR`, true)
DisableControlAction(0, `INPUT_LOOK_UD`, true)
DisableControlAction(0, `INPUT_VEH_MOUSE_CONTROL_OVERRIDE`, true)
end
if data.disableMovement then
DisableControlAction(0, `INPUT_MOVE_LR`, true)
DisableControlAction(0, `INPUT_MOVE_UD`, true)
DisableControlAction(0, `INPUT_DUCK`, true)
DisableControlAction(0, `INPUT_SPRINT`, true)
end
if data.disableCarMovement then
DisableControlAction(0, `INPUT_VEH_MOVE_LEFT_ONLY`, true)
DisableControlAction(0, `INPUT_VEH_MOVE_RIGHT_ONLY`, true)
DisableControlAction(0, `INPUT_VEH_ACCELERATE`, true)
DisableControlAction(0, `INPUT_VEH_BRAKE`, true)
DisableControlAction(0, `INPUT_VEH_EXIT`, true)
end
if data.disableCombat then
DisablePlayerFiring(PlayerId(), true)
DisableControlAction(0, `INPUT_ATTACK`, true)
DisableControlAction(0, `INPUT_AIM`, true)
DisableControlAction(0, `INPUT_OPEN_WHEEL_MENU`, true)
DisableControlAction(0, `INPUT_DETONATE`, true)
DisableControlAction(0, `INPUT_THROW_GRENADE`, true)
DisableControlAction(0, `INPUT_MELEE_ATTACK`, true)
DisableControlAction(0, `INPUT_MELEE_GRAPPLE_ATTACK`, true)
end
if data.cancel and (
IsControlJustReleased(0, `INPUT_FRONTEND_RS`) or
IsControlJustReleased(0, `INPUT_SWITCH_SHOULDER`) or
IsControlJustReleased(0, `INPUT_GAME_MENU_TAB_RIGHT_SECONDARY`) or
IsControlJustReleased(0, `INPUT_FRONTEND_CANCEL`) or
IsControlJustReleased(0, `INPUT_GAME_MENU_CANCEL`) or
IsControlJustReleased(0, `INPUT_FRONTEND_RRIGHT`) or
IsControlJustReleased(0, `INPUT_QUIT`) or
IsControlJustReleased(0, `INPUT_MINIGAME_QUIT`)
) then
inProgress = false
end
end
end)
-- Wait for completion or cancel
while GetGameTimer() < endTime and inProgress do
Wait(100)
end
-- Cleanup animations/tasks
if data.dict then
stopAnim(data.dict, data.anim, ped)
end
if data.task then
ClearPedTasks(ped)
end
result = inProgress
inProgress = false
while result == nil do Wait(10) end
-- Cleanup
FreezeEntityPosition(ped, false)
LocalPlayer.state:set("inv_busy", false, true)
TriggerEvent('inventory:client:busy:status', false)
TriggerEvent('canUseInventoryAndHotbar:toggle', not false)
return result
end
function ShowRedProgressBar(currentProg, title, level)
local loc = vec2(0.40, 0.90)
local size = vec2(0.3, 0.03)
-- Draw background box
DrawSprite("generic_textures", "inkroller_1a", loc.x+0.1, loc.y-0.01, 0.25, 0.07, 180.0, 0, 0, 0, 200)
SetTextFontForCurrentCommand(6)
SetTextScale(0.35, 0.35)
SetTextColor(255, 255, 255, 255)
SetTextDropshadow(1, 0, 0, 0, 200)
BgDisplayText(title, loc.x - size.x / 4 + 0.074, loc.y - 0.034)
SetTextFontForCurrentCommand(1)
SetTextScale(0.35, 0.35)
SetTextColor(255, 255, 255, 255)
SetTextDropshadow(1, 0, 0, 0, 200)
BgDisplayText(level, loc.x - size.x / 4 + 0.246, loc.y - 0.030)
local segmentWidth = (size.x + 0.05) / (#currentProg * 2) -- Divide the total width by 18 (9 segments * 2 gaps for each)
local gap = segmentWidth / #currentProg -- Smaller gap between segments
for i = 1, #currentProg do
local segmentX = (loc.x - size.x / 4 ) + 0.075 + (i - 1) * (segmentWidth + gap)
local fillPercentage = currentProg[i]
local progressBarWidth = segmentWidth * (fillPercentage / 100)
-- Semi-transparent background for each segment
DrawRect(segmentX + segmentWidth / 2, loc.y, segmentWidth, size.y / 3.4, 100, 100, 100, 255)
-- Filling progress for each segment
if progressBarWidth > 0 then
DrawRect(segmentX + progressBarWidth / 2, loc.y, progressBarWidth, size.y / 3.4, 255, 0, 0, 200) -- Blue progress
end
end
end
function gtaProgressBar(data)
local ped = PlayerPedId()
local result = nil
loadTextureDict("timerbars")
if inProgress then return false end
inProgress = true
local wait = debugMode and 1000 or data.time
local endTime = GetGameTimer() + wait
-- Setup Animation/Task if specified
if data.dict then
playAnim(data.dict, data.anim, -1, data.flag or 32)
elseif data.task then
TaskStartScenarioInPlace(ped, data.task, -1, true)
end
-- Progress bar rendering loop
CreateThread(function()
while GetGameTimer() < endTime and inProgress do
Wait(0)
local elapsed = GetGameTimer()
local percentage = ((elapsed - (endTime - wait)) / wait) * 100
-- Convert to segmented progress (assuming 5 segments here)
local segments = 1 -- Number of segments in the bar
local segmentProgress = {}
local progressPerSegment = 100 / segments
for i = 1, segments do
local segmentStart = (i - 1) * progressPerSegment
local segmentEnd = i * progressPerSegment
if percentage >= segmentEnd then
segmentProgress[i] = 100
elseif percentage <= segmentStart then
segmentProgress[i] = 0
else
segmentProgress[i] = ((percentage - segmentStart) / progressPerSegment) * 100
end
end
percentage = percentage >= 100 and 100 or percentage
-- Draw your segmented progress bar
ShowGTAProgressBar(segmentProgress, data.label, ("%.0f%%"):format(percentage))
-- Controls to disable during progress
DisablePlayerFiring(ped, true)
DisableControlAction(0, 25, true) -- Disable aim
DisableControlAction(0, 21, true) -- Disable sprint
DisableControlAction(0, 30, true) -- Disable move left/right
DisableControlAction(0, 31, true) -- Disable move forward/back
DisableControlAction(0, 36, true) -- Disable stealth
if data.cancel and (IsControlJustReleased(0, 202) or IsControlJustReleased(0, 177) or IsControlJustReleased(0, 73)) then
inProgress = false
end
end
end)
-- Wait for completion or cancel
while GetGameTimer() < endTime and inProgress do
Wait(100)
end
-- Cleanup animations/tasks
if data.dict then
stopAnim(data.dict, data.anim, ped)
end
if data.task then
ClearPedTasks(ped)
end
result = inProgress
inProgress = false
while result == nil do Wait(10) end
-- Cleanup
FreezeEntityPosition(ped, false)
LocalPlayer.state:set("inv_busy", false, true)
TriggerEvent('inventory:client:busy:status', false)
TriggerEvent('canUseInventoryAndHotbar:toggle', not false)
return result
end
function ShowGTAProgressBar(currentProg, title, level)
local loc = vec2(0.37, 0.90)
local size = vec2(0.3, 0.03)
-- Draw background box
DrawSprite("timerbars", "all_black_bg", loc.x +0.028, loc.y-0.01, 0.15, 0.07, 0.0, 255, 255, 255, 255)
DrawSprite("timerbars", "all_black_bg", loc.x +0.170, loc.y-0.01, 0.15, 0.07, 180.0, 255, 255, 255, 255)
SetTextFont(0)
SetTextProportional(1)
SetTextScale(0.35, 0.35)
SetTextColour(255, 255, 255, 255)
SetTextDropshadow(0, 0, 0, 0, 255)
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
AddTextComponentString(title)
DrawText(loc.x - size.x / 4 + 0.074, loc.y - 0.034) -- Adjust text position
SetTextFont(0)
SetTextProportional(1)
SetTextScale(0.35, 0.25)
SetTextColour(255, 255, 255, 255)
SetTextEntry("STRING")
AddTextComponentString(level)
DrawText(loc.x - size.x / 4 + 0.246, loc.y - 0.030) -- Right-aligned additional text
local segmentWidth = (size.x + 0.05) / (#currentProg * 2) -- Divide the total width by 18 (9 segments * 2 gaps for each)
local gap = segmentWidth / #currentProg -- Smaller gap between segments
for i = 1, #currentProg do
local segmentX = (loc.x - size.x / 4 ) + 0.075 + (i - 1) * (segmentWidth + gap)
local fillPercentage = currentProg[i]
local progressBarWidth = segmentWidth * (fillPercentage / 100)
-- Semi-transparent background for each segment
DrawRect(segmentX + segmentWidth / 2, loc.y, segmentWidth, size.y / 3.4, 100, 100, 100, 255)
-- Filling progress for each segment
if progressBarWidth > 0 then
DrawRect(segmentX + progressBarWidth / 2, loc.y, progressBarWidth, size.y / 3.4, 93, 182, 229, 255) -- Blue progress
end
end
end
function stopProgressBar() inProgress = false end
function isProgressBar() return inProgress end
function progressBar(...)
if GetCurrentGameName() == "rdr3" then
return redProgressBar(...)
else
return gtaProgressBar(...)
end
end
exports("progressBar", function(...)
return progressBar(...)
end)
exports("gtaProgressBar", function(...)
return gtaProgressBar(...)
end)
exports("redProgressBar", function(...)
return redProgressBar(...)
end)
exports("stopProgressBar", stopProgressBar)
exports("isProgressBar", isProgressBar)
--RegisterCommand("testprog", function()
-- print("test")
-- if progressBar({
-- label = "Processing...",
-- time = 10000,
-- disableMovement = true,
-- --dict = "amb@world_human_hang_out_street@female_hold_arm@base",
-- --anim = "base",
-- --flag = 49,
-- cancel = true,
-- }) then
-- Notify("Success!", "Short test message", "success")
-- else
-- Notify("Error!", "This is a longer example message to show stacking.", "error")
-- end
--end)

View File

@@ -79,7 +79,7 @@ function gtaSkillCheck()
-- Draw stationary cursor at result position
DrawRect(x - width / 2 + cursorPos * width, y, 0.002, height + 0.01, 255, 255, 255, 255)
-- Display result text
drawSuccessText(x, y, result and "Success" or "Failed", result and 114 or 228, result and 204 or 52, result and 144 or 52)
drawGTASuccessText(x, y, result and "Success" or "Failed", result and 114 or 228, result and 204 or 52, result and 144 or 52)
end
if result then
successes += 1
@@ -94,7 +94,7 @@ function gtaSkillCheck()
return successes == barsRequired
end
function drawSuccessText(x, y, text, r, g, b)
function drawGTASuccessText(x, y, text, r, g, b)
SetTextFont(8)
SetTextScale(0.45, 0.45)
SetTextColour(r, g, b, 255)
@@ -118,4 +118,10 @@ function createScaleBars(x, y, width, height)
DrawRect(x, y, width, height, 100, 100, 100, 255)
end
exports("skillCheck", gtaSkillCheck)
exports("skillCheck", function(...)
if GetCurrentGameName() == "rdr3" then
--redSkillCheck(...)
else
gtaSkillCheck(...)
end
end)

View File

@@ -1,6 +1,17 @@
2.0.17
2.0.18
- Fix progressbars getting stuck on ox_lib
- #BlameMcklean for this one
- Fix ox_inv client item caching (images)
- Add better checks if errors in ox_inv items and add more prominent error messages all around
- Tidy up several debugPrints
- Move AuthEvents to new file
- Fix clearStash error with PSInv and JPRInv
- Add extra trigger event for PSInv when opening stash (hopefully fix missing items for some)
- Fix onPlayerUnloaded() not triggering
- Add support for esx_society in openBossMenu()
- Added support for okokbilling to billPlayer()
- Rework progressBar and ui_modules folder
- Rework isAnimal.lua to be more automated and smarter
- Rework/Fix auto detection of QBInvNew
- Add new functions to get players current Inventory Weight
https://github.com/jimathy/jim_bridge