Compare commits

..

19 Commits

Author SHA1 Message Date
Jim Shield
880d2b0233 Version Bump
`2.0.20` - `2.0.21`
2025-07-14 11:29:29 +01:00
Jim Shield
5865d2eeb2 increase authToken timeout from 5 sec to 1 min 2025-07-13 17:41:06 +01:00
Jim Shield
528735abd1 fix anim flag on lation_ui progressbars 2025-07-12 22:24:28 +01:00
Jim Shield
d4df995c71 fix lation_ui progressbars returning true when cancelled 2025-07-12 13:05:10 +01:00
Jim Shield
3b13fa663e Merge pull request #49 from derTweaky/patch-1 2025-07-12 11:31:16 +01:00
derTweaky
e973c64ffd Update makePed.lua
Typo fix
2025-07-12 12:27:31 +02:00
Jim Shield
6ecf10c084 fix inventory config loading if vector4 is present 2025-07-11 21:16:45 +01:00
Jim Shield
79e765fbb0 Stop crafting trying to check blank stash names
Skimmed through the stash checking and editing functions and added more "security" for handling nil or blank stash names
2025-07-11 13:33:44 +01:00
Jim Shield
d4a08d5e2b Rewrite waitForSharedLoad() to fix issues 2025-07-10 22:41:28 +01:00
Jim Shield
eeb3f40018 fix break when trying to fade ents too far away 2025-07-10 22:16:26 +01:00
Jim Shield
e6b4c1d13c Add fade in animations for entity spawning 2025-07-09 15:10:53 +01:00
Jim Shield
6ecbc3392a make breaktool() smarter and add useToolDegrade() 2025-07-09 15:09:41 +01:00
Jim Shield
7f10c394de make cache timeout optional 2025-07-09 15:09:14 +01:00
Jim Shield
fae099fd93 fix progressbar looking for missing function 2025-07-08 11:20:52 +01:00
Jim Shield
64d43b54e9 fix getPlayer() checking users not logged in yet 2025-07-08 00:48:39 +01:00
Jim Shield
d4abdbc93f fix typo stopping mysql cache loading on esx 2025-07-07 17:56:23 +01:00
Jim Shield
b595453efe Rename metahandler functions
Realised I named the player and item metadata functions too closely and made it confusing, this separates them better
2025-07-07 17:47:04 +01:00
Jim Shield
d255034c02 Increase timer again on cache timeout
Also moved around the cache timers to be a bit more accurate (timers start when the cache creation is triggered)
2025-07-07 02:11:36 +01:00
Jim Shield
d6fd2cc28c Fix toggleDuty() for ESX 2025-07-07 00:09:34 +01:00
19 changed files with 185 additions and 185 deletions

View File

@@ -21,12 +21,12 @@ This module provides access and control over player metadata, which is useful fo
print("Player stress level:", stress) print("Player stress level:", stress)
``` ```
- **SetMetadata(player, key, value)** - **setPlayerMetadata(player, key, value)**
⚠️ Server side only ⚠️ Server side only
- Updates or assigns a value to a specific metadata key for a player. - Updates or assigns a value to a specific metadata key for a player.
- The function updates the player's metadata using the active core export. - The function updates the player's metadata using the active core export.
- **Example:** - **Example:**
```lua ```lua
SetMetadata(player, "stress", 0) setPlayerMetadata(player, "stress", 0)
``` ```

View File

@@ -49,17 +49,19 @@ end
local function endTimer(label) local function endTimer(label)
timers[label] = GetGameTimer() - (timers[label] or GetGameTimer()) timers[label] = GetGameTimer() - (timers[label] or GetGameTimer())
timers[label] = timers[label] / 1000 timers[label] = "("..(timers[label] / 1000).."s)"
end end
startTimer("Cache") startTimer("Cache") startTimer("Items") startTimer("Vehicles") startTimer("Jobs") startTimer("InvWeight") startTimer("InvSlots")
-- Helper function to check if resource exists in server (instead of if it is already started) -- Helper function to check if resource exists in server (instead of if it is already started)
local function checkExists(resourceName) local function checkExists(resourceName)
return GetResourceState(resourceName):find("start") or GetResourceState(resourceName):find("stopped") return GetResourceState(resourceName):find("start") or GetResourceState(resourceName):find("stopped")
end end
-- Ensure oxmysql resource is loaded -- Ensure oxmysql resource is loaded
local fileLoader = assert(load(LoadResourceFile("oxmysql", ('lib/MySQL.lua')), ('@@oxmysql/lib/MySQL.lua'))) if checkExists(Exports.OXCoreExport) or checkExists(Exports.ESXExport) then
fileLoader() local fileLoader = assert(load(LoadResourceFile("oxmysql", ('lib/MySQL.lua')), ('@@oxmysql/lib/MySQL.lua')))
fileLoader()
end
if checkExists(Exports.OXCoreExport) then if checkExists(Exports.OXCoreExport) then
-- Detected OX_Core in server, wait for it to be started if needed -- Detected OX_Core in server, wait for it to be started if needed
@@ -88,7 +90,6 @@ end
---- Load Items ----- ---- Load Items -----
--------------------- ---------------------
-- Items initialization based on detected inventory system -- Items initialization based on detected inventory system
startTimer("Items")
if checkExists(Exports.OXInv) then if checkExists(Exports.OXInv) then
-- Wait for OX Inventory to start if it's not already started -- Wait for OX Inventory to start if it's not already started
while GetResourceState(Exports.OXInv) ~= "started" do Wait(100) end while GetResourceState(Exports.OXInv) ~= "started" do Wait(100) end
@@ -171,7 +172,6 @@ endTimer("Items")
--------------------- ---------------------
--- Load Vehicles --- --- Load Vehicles ---
--------------------- ---------------------
startTimer("Vehicles")
-- Vehicle loading depending on framework -- Vehicle loading depending on framework
if checkExists(Exports.QBXExport) then if checkExists(Exports.QBXExport) then
vehResource = Exports.QBXExport vehResource = Exports.QBXExport
@@ -215,7 +215,6 @@ endTimer("Vehicles")
--------------------- ---------------------
----- Load Jobs ----- ----- Load Jobs -----
--------------------- ---------------------
startTimer("Jobs")
-- Jobs loading based on framework -- Jobs loading based on framework
if checkExists(Exports.QBXExport) then if checkExists(Exports.QBXExport) then
jobResource = Exports.QBXExport jobResource = Exports.QBXExport
@@ -308,8 +307,6 @@ end
-- Forcefully load the the specified config file from inventory scripts -- Forcefully load the the specified config file from inventory scripts
-- This allows to get information required for certain functions that need to detect how much space is left in a players inventory -- This allows to get information required for certain functions that need to detect how much space is left in a players inventory
-- This is born from too many tickets of me needing to explain that they need to change "InventoryWeight" to match their inv setting -- This is born from too many tickets of me needing to explain that they need to change "InventoryWeight" to match their inv setting
startTimer("InvWeight")
startTimer("InvSlots")
local function getInventoryConfig(resource, data) local function getInventoryConfig(resource, data)
if data.convars then if data.convars then
return function(path) return function(path)
@@ -323,12 +320,19 @@ local function getInventoryConfig(resource, data)
if not content then return nil, "Failed to load file" end if not content then return nil, "Failed to load file" end
local env = { local env = {
GetConvar = GetConvar, vector3 = vector3, Citizen = Citizen, GetConvar = GetConvar,
GetResourceState = GetResourceState, exports = exports, vector3 = vector3,
DependencyCheck = DependencyCheck or function() return nil end, vector4 = vector4,
Citizen = Citizen,
GetResourceState = GetResourceState,
exports = exports,
DependencyCheck = function() return nil end,
} }
local fn, err = load(content, '@'..data.file, 't', env) local fn, err = load(content, '@'..data.file, 't', env)
--local success, err = xpcall(fn, function(e)
-- print(debug.traceback("Error while executing qs-inventory config:\n" .. tostring(e), 2))
--end)
if not fn then return nil, "Failed to compile config: " .. err end if not fn then return nil, "Failed to compile config: " .. err end
if not pcall(fn) then return nil, "Error executing config file" end if not pcall(fn) then return nil, "Error executing config file" end
@@ -372,6 +376,7 @@ for script, data in pairs(invWeightTable) do
if checkExists(script) then if checkExists(script) then
if script == Exports.QBInv and GetResourceState(Exports.JPRInv):find("start") then goto skip end if script == Exports.QBInv and GetResourceState(Exports.JPRInv):find("start") then goto skip end
while GetResourceState(script) ~= "started" do Wait(100) print("Waiting for script start") end
local attempts = data.fallback or { data } local attempts = data.fallback or { data }
local lookup, used, err local lookup, used, err
@@ -419,17 +424,17 @@ CreateThread(function()
if type(v) ~= "number" then for count in pairs(v) do counts[k] += 1 end end if type(v) ~= "number" then for count in pairs(v) do counts[k] += 1 end end
end end
if cache.InventoryWeight then if cache.InventoryWeight then
print("^6FrameWorkCache^7: ^4"..invResource.."^2 InventoryWeight^7: ^3"..cache.InventoryWeight.."^7 (^3"..(cache.InventoryWeight / 1000).."kg^7) ^7("..timers["InvWeight"].."s)") print("^6FrameWorkCache^7: ^4"..invResource.."^2 InventoryWeight^7: ^3"..cache.InventoryWeight.."^7 (^3"..(cache.InventoryWeight / 1000).."kg^7) ^7"..timers["InvWeight"])
end end
if cache.InventorySlots then if cache.InventorySlots then
print("^6FrameWorkCache^7: ^4"..invResource.."^2 InventorySlots^7: ^3"..cache.InventorySlots.." ^7("..timers["InvSlots"].."s)") print("^6FrameWorkCache^7: ^4"..invResource.."^2 InventorySlots^7: ^3"..cache.InventorySlots.." ^7"..timers["InvSlots"])
end end
print("^6FrameworkCache^7: ^4"..itemResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Items).."^2 Items ^7("..timers["Items"].."s)") print("^6FrameworkCache^7: ^4"..itemResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Items).."^2 Items ^7"..timers["Items"])
print("^6FrameworkCache^7: ^4"..vehResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Vehicles).."^2 Vehicles ^7("..timers["Vehicles"].."s)") print("^6FrameworkCache^7: ^4"..vehResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Vehicles).."^2 Vehicles ^7"..timers["Vehicles"])
print("^6FrameworkCache^7: ^4"..jobResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Jobs).."^2 Jobs ^7("..timers["Jobs"].."s)") print("^6FrameworkCache^7: ^4"..jobResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Jobs).."^2 Jobs ^7"..timers["Jobs"])
print("^6FrameworkCache^7: ^4"..jobResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Gangs).."^2 Gangs ^7("..timers["Jobs"].."s)") print("^6FrameworkCache^7: ^4"..jobResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Gangs).."^2 Gangs ^7"..timers["Jobs"])
endTimer("Cache") endTimer("Cache")
print("^6FrameworkCache^7: ^2Cache Ready ^7("..timers["Cache"].."s)") print("^6FrameworkCache^7: ^2Cache Ready ^7"..timers["Cache"])
cacheReady = true cacheReady = true
end) end)

View File

@@ -1,6 +1,6 @@
name "Jim_Bridge" name "Jim_Bridge"
author "Jimathy" author "Jimathy"
version "2.0.20" version "2.0.21"
description "Framework Bridge By Jimathy" description "Framework Bridge By Jimathy"
fx_version "cerulean" 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.' rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'

View File

@@ -53,13 +53,13 @@ if isServer() then
if authCooldown[src] then if authCooldown[src] then
debugPrint("^1Auth^7: ^3Cooldown active^7 for Player ^1"..src.."^7, ignoring additional auth request") debugPrint("^1Auth^7: ^3Cooldown active^7 for Player ^1"..src.."^7, ignoring additional auth request")
return "" return AuthEvent
end end
debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent) debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent)
authCooldown[src] = true authCooldown[src] = true
SetTimeout(5000, function() -- 5 second cooldown SetTimeout(60000, function() -- 1 minute cooldown
authCooldown[src] = nil authCooldown[src] = nil
end) end)

View File

@@ -117,7 +117,6 @@ function onResourceStart(func, thisScript)
debugPrint("^6Bridge^7: ^2Shared Load Detected^7.") debugPrint("^6Bridge^7: ^2Shared Load Detected^7.")
hasPrinted = true hasPrinted = true
end end
if isStarted(ESXExport) then Wait(10000) end
func() func()
end end
end end
@@ -194,14 +193,13 @@ end
local messageShown = false local messageShown = false
function waitForSharedLoad() function waitForSharedLoad()
local timeout = 100000 -- 10 seconds in milliseconds local timeout = GetGameTimer() + 900000 -- 15 minutes max wait (had to up this from 2 minutes because of slow servers)
local startTime = GetGameTimer()
local loaded = true
local loop = 0 local loop = 0
while ((not Jobs or not next(Jobs)) or while ((not Jobs or not next(Jobs)) or
(not Items or not next(Items)) or (not Items or not next(Items)) or
(not Vehicles or not next(Vehicles)) (not Vehicles or not next(Vehicles))
) and ((GetGameTimer() - startTime) < timeout) do ) and (timeout and GetGameTimer() < timeout) do
if loop >= 3 and not messageShown then if loop >= 3 and not messageShown then
if (not Jobs or not next(Jobs)) then if (not Jobs or not next(Jobs)) then
print("^4Debug^7: ^2Waiting for ^7Jobs^2 to be loaded") print("^4Debug^7: ^2Waiting for ^7Jobs^2 to be loaded")
@@ -214,19 +212,16 @@ function waitForSharedLoad()
end end
messageShown = true messageShown = true
end end
--print((GetGameTimer() - startTime) < timeout)
Wait(1000) Wait(1000)
if Jobs and Items and Vehicles then
--print("^6Bridge^7: ^2Jobs, Items, and Vehicles Loaded^7.")
loaded = true
break
end
loop += 1 loop += 1
end end
if not loaded then
if Jobs and Items and Vehicles then
debugPrint("^6Bridge^7: ^2Jobs, Items, and Vehicles Loaded^7.")
return true
else
print("^4Error^7: ^1Timeout reached while waiting for shared load^7.") print("^4Error^7: ^1Timeout reached while waiting for shared load^7.")
return false return false
else
return true
end end
end end

View File

@@ -34,10 +34,10 @@ end
if IsDuplicityVersion() then if IsDuplicityVersion() then
local cache = nil local cache = nil
local timeout = GetGameTimer() + 120000 -- 2 minutes max wait (had to up this from 5 seconds because of slow servers) local timeout = GetGameTimer() + 900000 -- 15 minutes max wait (had to up this from 2 minutes because of slow servers)
-- Wait until jim_bridge is started and export is available -- Wait until jim_bridge is started and export is available
while not cache and GetGameTimer() < timeout do while not cache and (timeout and GetGameTimer() < timeout) do
if GetResourceState("jim_bridge"):find("start") then if GetResourceState("jim_bridge"):find("start") then
local success, result = pcall(function() local success, result = pcall(function()
return exports["jim_bridge"]:GetSharedData() return exports["jim_bridge"]:GetSharedData()
@@ -49,7 +49,7 @@ if IsDuplicityVersion() then
Wait(100) Wait(100)
end end
if not cache then if timeout and not cache then
print("^1ERROR^7: ^2jim_bridge export not available after timeout^7.") print("^1ERROR^7: ^2jim_bridge export not available after timeout^7.")
return return
end end

View File

@@ -89,7 +89,7 @@ function craftingMenu(data)
-- Check if the player can carry the required items (server callback). -- Check if the player can carry the required items (server callback).
local canCarryTable = triggerCallback(getScript()..':server:canCarry', tempCarryTable) local canCarryTable = triggerCallback(getScript()..':server:canCarry', tempCarryTable)
local usingStash = data.stashName ~= nil local usingStash = data.stashName ~= nil and data.stashName ~= ""
Menu[#Menu+1] = { Menu[#Menu+1] = {
icon = usingStash and "fas fa-boxes-stacked" or "fas fa-person", icon = usingStash and "fas fa-boxes-stacked" or "fas fa-person",
@@ -411,11 +411,11 @@ function makeItem(data)
-- handle metadata and experience in a single go -- handle metadata and experience in a single go
if data.craft["hasCrafted"] ~= nil then if data.craft["hasCrafted"] ~= nil then
data.craftable.craftedItems[data.item] = true data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:SetMetadata", "craftedItems", data.craftable.craftedItems) triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end end
if data.craft["exp"] ~= nil then if data.craft["exp"] ~= nil then
craftingLevel += data.craft["exp"].give * craftAmount craftingLevel += data.craft["exp"].give * craftAmount
triggerCallback(getScript()..":server:SetMetadata", "craftingLevel", craftingLevel) triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end end
if data.craftable.Recipes[1].oneUse == true then if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot) removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
@@ -448,11 +448,11 @@ function makeItem(data)
currentToken = nil currentToken = nil
if data.craft["hasCrafted"] ~= nil then if data.craft["hasCrafted"] ~= nil then
data.craftable.craftedItems[data.item] = true data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:SetMetadata", "craftedItems", data.craftable.craftedItems) triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end end
if data.craft["exp"] ~= nil then if data.craft["exp"] ~= nil then
craftingLevel += data.craft["exp"].give craftingLevel += data.craft["exp"].give
triggerCallback(getScript()..":server:SetMetadata", "craftingLevel", craftingLevel) triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end end
if data.craftable.Recipes[1].oneUse == true then if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot) removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)

View File

@@ -376,130 +376,73 @@ end
--- ```lua --- ```lua
--- breakTool({ item = "drill", damage = 10 }) --- breakTool({ item = "drill", damage = 10 })
--- ``` --- ```
function breakTool(data) -- WIP function breakTool(data)
local durability, slot = getDurability(data.item) local metadata, slot = getItemMetadata(data.item)
if not durability then durability = 100 end metadata = metadata or {}
durability -= data.damage if not metadata.durability then metadata.durability = 100 end
if durability <= 0 then metadata.durability -= data.damage
removeItem(data.item, 1) if metadata.durability <= 0 then
removeItem(data.item, 1, nil, slot)
local breakId = GetSoundId() local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0) PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
else else
TriggerServerEvent(getScript()..":server:setMetaData", { item = data.item, slot = slot, metadata = { durability = durability } }) TriggerServerEvent(getScript()..":server:setItemMetaData", { item = data.item, slot = slot, metadata = metadata })
end end
end end
--- Retrieves the durability and slot number of an item in a player's inventory.
--- Reduces the uses of a tool by a specified damage amount.
--- ---
--- Searches through the player's inventory for the specified item. --- If uses reaches zero or below, the tool is removed and a break sound is played.
--- ---
--- @param item string The item name. --- @param data table Contains:
--- @return number|nil number The durability, or nil if not found. --- - item (string): The tool's name.
--- @return number|nil number The slot number, or nil if not found. --- - damage (number): The damage % to apply.
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- local durability, slot = getDurability("drill") --- useToolDegrade({ item = "drill", maxUse = 10 })
--- if durability then
--- print("Durability:", durability)
--- print("Slot:", slot)
--- end
--- ``` --- ```
function getDurability(item) function useToolDegrade(data) -- WIP
local metadata, slot = getItemMetadata(data.item)
metadata = metadata or {}
if not metadata["Uses Left"] then metadata["Uses Left"] = data.maxUse end
metadata["Uses Left"] -= 1
if metadata["Uses Left"] <= 0 then
removeItem(data.item, 1, nil, slot)
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
else
TriggerServerEvent(getScript()..":server:setItemMetaData", { item = data.item, slot = slot, metadata = metadata })
end
end
function getItemMetadata(item, slot, src)
local lowestSlot = 100 local lowestSlot = 100
local durability = nil local chosenSlot = slot
if isStarted(QBInv) or isStarted(PSInv) or isStarted(RSGInv) or isStarted(JPRInv) then local metadata = {}
local itemcheck = Core.Functions.GetPlayerData().items
local itemcheck = getPlayerInv(src)
if chosenSlot then
for k, v in pairs(itemcheck) do
if v.name == item and v.slot == chosenSlot then
lowestSlot = v.slot
metadata = itemcheck[k].info or itemcheck[k].metadata or {}
debugPrint("^6Bridge^7: ^2Found metadata for item ^3"..item.." ^2in slot ^3"..lowestSlot.."^7")
end
end
else
for k, v in pairs(itemcheck) do for k, v in pairs(itemcheck) do
if v.name == item then if v.name == item then
if v.slot <= lowestSlot then if v.slot <= lowestSlot then
lowestSlot = v.slot lowestSlot = v.slot
durability = itemcheck[k].info and itemcheck[k].info.durability or nil metadata = itemcheck[k].info or itemcheck[k].metadata or {}
end end
end end
end end
end end
return metadata, lowestSlot
if isStarted(OXInv) then
local itemcheck = exports[OXInv]:Search('slots', item)
for k, v in pairs(itemcheck) do
if v.slot <= lowestSlot then
debugPrint(v.slot, itemcheck[k].metadata.durability)
lowestSlot = v.slot
durability = v.metadata and v.metadata.durability or nil
end
end
end
if isStarted(QSInv) then
local itemcheck = exports[QSInv]:getUserInventory()
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.info and v.info.durability or nil
end
end
end
if isStarted(CoreInv) then
local itemcheck = exports[CoreInv]:getInventory()
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.metadata and v.metadata.durability or nil
end
end
end
if isStarted(CodeMInv) then
local itemcheck = exports[CodeMInv]:GetClientPlayerInventory()
for _, v in pairs(itemcheck) do
if v.name == item and tonumber(v.slot) <= lowestSlot then
lowestSlot = tonumber(v.slot)
durability = v.info and v.info.durability or nil
end
end
end
if isStarted(OrigenInv) then
local itemcheck = exports[OrigenInv]:getPlayerInventory()
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.metadata and v.metadata.durability or nil
end
end
end
if isStarted(TgiannInv) then
local itemcheck = exports[TgiannInv]:GetPlayerItems()
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.metadata and v.metadata.durability or nil
end
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 ipairs(xPlayer.inventory) do
if v.name == item then
-- Optionally use a slot field if available; otherwise, use the index
if v.slot and v.slot <= lowestSlot then
lowestSlot = v.slot
end
if v.metadata and v.metadata.durability then
durability = v.metadata.durability
end
end
end
end
end
return durability, lowestSlot
end end
--- Server event handler to set metadata for an item. --- Server event handler to set metadata for an item.
@@ -513,9 +456,9 @@ end
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- TriggerServerEvent("script:server:setMetaData", { item = "drill", slot = 5, metadata = { durability = 80 } }) --- TriggerServerEvent("script:server:setItemMetaData", { item = "drill", slot = 5, metadata = { durability = 80 } })
--- ``` --- ```
RegisterNetEvent(getScript()..":server:setMetaData", function(data, src) RegisterNetEvent(getScript()..":server:setItemMetaData", function(data, src)
local src = src or source local src = src or source
if isStarted(QBInv) or isStarted(PSInv) or isStarted(RSGInv) or isStarted(JPRInv) then if isStarted(QBInv) or isStarted(PSInv) or isStarted(RSGInv) or isStarted(JPRInv) then
--debugPrint(src, data.item, 1, data.slot) --debugPrint(src, data.item, 1, data.slot)

View File

@@ -104,16 +104,31 @@ function toggleDuty()
TriggerServerEvent("QBCore:ToggleDuty") TriggerServerEvent("QBCore:ToggleDuty")
Wait(100) Wait(100)
onDuty = getPlayer().onDuty onDuty = getPlayer().onDuty
elseif isStarted(RSGExport) then elseif isStarted(RSGExport) then
TriggerServerEvent("RSGCore:ToggleDuty") TriggerServerEvent("RSGCore:ToggleDuty")
Wait(100) Wait(100)
onDuty = getPlayer().onDuty onDuty = getPlayer().onDuty
else
elseif isStarted(ESXExport) then
local tempJob = ESX.GetPlayerData().job
tempJob.onDuty = not onDuty
ESX.SetPlayerData("job", tempJob)
onDuty = getPlayer().onDuty
if onDuty then if onDuty then
triggerNotify(nil, "Now on duty", "success") triggerNotify(nil, "Now on duty", "success")
else else
triggerNotify(nil, "Now off duty", "success") triggerNotify(nil, "Now off duty", "success")
end end
else
onDuty = not onDuty
if onDuty then
triggerNotify(nil, "Now on duty", "success")
else
triggerNotify(nil, "Now off duty", "success")
end
end end
end end

View File

@@ -187,7 +187,7 @@ end
--- ``` --- ```
function playAnim(animDict, animName, duration, flag, ped, speed) function playAnim(animDict, animName, duration, flag, ped, speed)
loadAnimDict(animDict) loadAnimDict(animDict)
debugPrint("^6Bridge^7: ^3playAnim^7() ^2Triggered^7: ", animDict, animName) debugPrint("^6Bridge^7: ^3playAnim^7() ^2Triggered^7: ", animDict, animName, flag)
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) 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 end
@@ -238,4 +238,25 @@ function playGameSound(audioBank, soundSet, soundRef, coords, synced, range)
PlaySoundFromEntity(soundId, soundRef, coords, soundSet, synced, 1.0) PlaySoundFromEntity(soundId, soundRef, coords, soundSet, synced, 1.0)
end end
ReleaseScriptAudioBank(audioBank) ReleaseScriptAudioBank(audioBank)
end
-- Experimental, add fade in for spawned entities
function fadeInEnt(ent, duration)
if not DoesEntityExist(ent) then return end
duration = duration or 500 -- in ms
local fadeSteps = 20
local stepTime = duration / fadeSteps
SetEntityAlpha(ent, 0, false)
SetEntityVisible(ent, true, false)
SetEntityLocallyInvisible(ent) -- sometimes helps prevent "pop-in" in early frames
for i = 1, fadeSteps do
Wait(stepTime)
local newAlpha = math.floor((i / fadeSteps) * 255)
SetEntityAlpha(ent, newAlpha, false)
end
-- Restore full visibility
ResetEntityAlpha(ent)
end end

View File

@@ -62,7 +62,7 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
model = data.model model = data.model
loadModel(data.model) loadModel(data.model)
ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced and synced or false, false) ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.03, coords.w, synced and synced or false, false)
SetEntityAlpha(ped, 0, false)
-- Inheritance -- Inheritance
SetPedHeadBlendData(ped, data.custom.faceFather, data.custom.faceMother, data.custom.raceShape, data.custom.skinFather, data.custom.skinMother, data.custom.raceSkin, data.custom.faceMix or 0, data.custom.skinMix or 0, data.custom.raceMix or 0, false) SetPedHeadBlendData(ped, data.custom.faceFather, data.custom.faceMother, data.custom.raceShape, data.custom.skinFather, data.custom.skinMother, data.custom.raceSkin, data.custom.faceMix or 0, data.custom.skinMix or 0, data.custom.raceMix or 0, false)
@@ -116,6 +116,7 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
loadModel(model) loadModel(model)
if gameName == "rdr3" then if gameName == "rdr3" then
ped = CreatePed(model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false) ped = CreatePed(model, coords.x, coords.y, coords.z - 1.03, coords.w, synced or false, false)
SetEntityAlpha(ped, 0, false)
SetEntityVisible(ped, 1) -- SetEntityVisible SetEntityVisible(ped, 1) -- SetEntityVisible
SetEntityAlpha(ped, 255, false) -- SetEntityAlpha SetEntityAlpha(ped, 255, false) -- SetEntityAlpha
SetRandomOutfitVariation(ped, true) -- Invisible without SetRandomOutfitVariation(ped, true) -- Invisible without
@@ -141,6 +142,10 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
end end
unloadModel(model) unloadModel(model)
Peds[keyGen()..keyGen()] = ped Peds[keyGen()..keyGen()] = ped
CreateThread(function()
fadeInEnt(ped)
end)
return ped return ped
end end
@@ -243,4 +248,4 @@ onResourceStop(function()
for k in pairs(Peds) do for k in pairs(Peds) do
DeletePed(Peds[k]) DeletePed(Peds[k])
end end
end, true) end, true)

View File

@@ -23,12 +23,16 @@ local Props = {}
function makeProp(data, freeze, synced) function makeProp(data, freeze, synced)
loadModel(data.prop) loadModel(data.prop)
local prop = CreateObject(data.prop, data.coords.x, data.coords.y, data.coords.z-1.03, synced and synced or false, synced and synced or false, false) local prop = CreateObject(data.prop, data.coords.x, data.coords.y, data.coords.z-1.03, synced and synced or false, synced and synced or false, false)
SetEntityAlpha(veh, 0, false)
SetEntityHeading(prop, (data.coords.w or 0) + 180.0) SetEntityHeading(prop, (data.coords.w or 0) + 180.0)
FreezeEntityPosition(prop, freeze or false) FreezeEntityPosition(prop, freeze or false)
debugPrint("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..data.prop.."^7' | ^2Coord^7: "..formatCoord(data.coords)) debugPrint("^6Bridge^7: ^1Prop ^2Created^7: '^6"..prop.."^7' | ^2Hash^7: ^7'^6"..data.prop.."^7' | ^2Coord^7: "..formatCoord(data.coords))
SetModelAsNoLongerNeeded(data.prop) SetModelAsNoLongerNeeded(data.prop)
Props[keyGen()..keyGen()] = prop Props[keyGen()..keyGen()] = prop
CreateThread(function()
fadeInEnt(prop)
end)
return prop return prop
end end

View File

@@ -18,18 +18,22 @@ function makeVeh(model, coords)
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false) local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false)
SetVehicleHasBeenOwnedByPlayer(veh, true) SetVehicleHasBeenOwnedByPlayer(veh, true)
if gameName ~= "rdr3" then if gameName ~= "rdr3" then
SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true) SetEntityAlpha(veh, 0, false)
SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true)
Wait(100) Wait(100)
SetVehicleNeedsToBeHotwired(veh, false) SetVehicleNeedsToBeHotwired(veh, false)
SetVehRadioStation(veh, 'OFF') SetVehRadioStation(veh, 'OFF')
SetVehicleFuelLevel(veh, 100.0) SetVehicleFuelLevel(veh, 100.0)
SetVehicleModKit(veh, 0) SetVehicleModKit(veh, 0)
end end
SetVehicleOnGroundProperly(veh) SetVehicleOnGroundProperly(veh)
debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords)) debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords))
unloadModel(model) unloadModel(model)
Vehicles[#Vehicles + 1] = veh Vehicles[#Vehicles + 1] = veh
CreateThread(function()
fadeInEnt(veh)
end)
return veh return veh
end end

View File

@@ -150,6 +150,7 @@ function progressBar(data)
anim = { anim = {
dict = data.dict, dict = data.dict,
clip = data.anim, clip = data.anim,
flag = data.flag
}, },
prop = { prop = {
model = data.prop and data.prop.model, model = data.prop and data.prop.model,
@@ -160,7 +161,7 @@ function progressBar(data)
}) then }) then
result = true result = true
else else
result = true result = false
end end
elseif Config.System.ProgressBar == "red" then elseif Config.System.ProgressBar == "red" then

View File

@@ -58,9 +58,9 @@ end
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- local myMeta = GetMetadata(player, "myKey") --- local myMeta = getPlayerMetadata(player, "myKey")
--- ``` --- ```
function GetMetadata(player, key) function getPlayerMetadata(player, key)
if not player then if not player then
debugPrint("^6Bridge^7: ^3GetMetadata^7() calling server: "..key) debugPrint("^6Bridge^7: ^3GetMetadata^7() calling server: "..key)
return triggerCallback(getScript()..":server:GetMetadata", key) return triggerCallback(getScript()..":server:GetMetadata", key)
@@ -98,11 +98,11 @@ createCallback(getScript()..":server:GetMetadata", function(source, key)
if type(key) == "table" then if type(key) == "table" then
local Metadata = {} local Metadata = {}
for _, k in ipairs(key) do for _, k in ipairs(key) do
Metadata[k] = GetMetadata(player, k) Metadata[k] = getPlayerMetadata(player, k)
end end
return Metadata return Metadata
elseif type(key) == "string" then elseif type(key) == "string" then
return GetMetadata(player, key) return getPlayerMetadata(player, key)
end end
end) end)
@@ -120,9 +120,9 @@ end)
--- ---
--- @usage --- @usage
--- ```lua --- ```lua
--- SetMetadata(player, "myKey", "newValue") --- setPlayerMetadata(player, "myKey", "newValue")
--- ``` --- ```
function SetMetadata(player, key, value) function setPlayerMetadata(player, key, value)
debugPrint("^6Bridge^7: ^3SetMetadata^7() setting metadata for key: "..key) debugPrint("^6Bridge^7: ^3SetMetadata^7() setting metadata for key: "..key)
if isStarted(QBExport) or isStarted(QBXExport) then if isStarted(QBExport) or isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^3SetMetadata^7() using QBExport/QBXExport") debugPrint("^6Bridge^7: ^3SetMetadata^7() using QBExport/QBXExport")
@@ -144,14 +144,14 @@ function SetMetadata(player, key, value)
end end
-- Register a server callback for setting metadata. -- Register a server callback for setting metadata.
createCallback(getScript()..":server:SetMetadata", function(source, key, value) createCallback(getScript()..":server:setPlayerMetadata", function(source, key, value)
debugPrint("SetMetadata callback triggered for source:", source, "key:", key, "value:", value) debugPrint("SetMetadata callback triggered for source:", source, "key:", key, "value:", value)
local player = GetPlayer(source) local player = GetPlayer(source)
--[[if not player then --[[if not player then
print("Error setting metadata: player not found for source "..tostring(source)) print("Error setting metadata: player not found for source "..tostring(source))
return false return false
end]] end]]
SetMetadata(player, key, value) setPlayerMetadata(player, key, value)
print("Metadata set successfully.", key) print("Metadata set successfully.", key)
return true return true
end) end)

View File

@@ -412,7 +412,7 @@ function hasJob(job, source, grade)
elseif isStarted(QBExport) and not isStarted(QBXExport) then elseif isStarted(QBExport) and not isStarted(QBXExport) then
if Core.Functions.GetPlayer then if Core.Functions.GetPlayer then
local player = Core.Functions.GetPlayer(src) local player = Core.Functions.GetPlayer(src)
if not player then print("Player not found for src: "..src) end if not player then goto skip end
local jobinfo = player.PlayerData.job local jobinfo = player.PlayerData.job
if jobinfo.name == job then if jobinfo.name == job then
hasJobFlag = true hasJobFlag = true
@@ -437,11 +437,10 @@ function hasJob(job, source, grade)
if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end
end end
end end
elseif isStarted(RSGExport) then elseif isStarted(RSGExport) then
if Core.Functions.GetPlayer then if Core.Functions.GetPlayer then
local player = Core.Functions.GetPlayer(src) local player = Core.Functions.GetPlayer(src)
if not player then print("Player not found for src: "..src) end if not player then goto skip end
local jobinfo = player.PlayerData.job local jobinfo = player.PlayerData.job
if jobinfo.name == job then if jobinfo.name == job then
hasJobFlag = true hasJobFlag = true
@@ -531,6 +530,7 @@ function hasJob(job, source, grade)
print("^4ERROR^7: ^2No Core detected for hasJob() ^7- ^2Check ^3starter^1.^2lua^7") print("^4ERROR^7: ^2No Core detected for hasJob() ^7- ^2Check ^3starter^1.^2lua^7")
end end
end end
::skip::
return hasJobFlag, duty return hasJobFlag, duty
end end

View File

@@ -15,6 +15,9 @@ local stash
-- If running on the server, create a callback to retrieve stash items. -- If running on the server, create a callback to retrieve stash items.
if isServer() then if isServer() then
createCallback(getScript()..':server:GetStashItems', function(source, stashName) createCallback(getScript()..':server:GetStashItems', function(source, stashName)
if stashName == nil or stashName == "" then
return {}
end
stash = getStash(stashName) stash = getStash(stashName)
return stash return stash
end) end)
@@ -35,9 +38,9 @@ local stashCache = {}
--- local cached = GetStashTimeout("playerStash") --- local cached = GetStashTimeout("playerStash")
--- ``` --- ```
function GetStashTimeout(stashName, stop) function GetStashTimeout(stashName, stop)
if stop then if stop or (stashName == nil or stashName == "") then
stashCache = {} stashCache = {}
return return false
end end
-- Retrieve cache for this stash, or initialize if not present. -- Retrieve cache for this stash, or initialize if not present.
@@ -85,7 +88,7 @@ end
--- local found, stashName = checkStashItem({"playerStash", "storageStash"}, { iron = 2, wood = 5 }) --- local found, stashName = checkStashItem({"playerStash", "storageStash"}, { iron = 2, wood = 5 })
--- ``` --- ```
function checkStashItem(stashes, itemTable) function checkStashItem(stashes, itemTable)
if not stashes then if not stashes or stashes == "" then
return hasItem(itemTable), nil return hasItem(itemTable), nil
end end
@@ -317,7 +320,7 @@ end
--- ``` --- ```
function getStash(stashName) function getStash(stashName)
local stashResource = "" local stashResource = ""
if type(stashName) ~= "string" then if stashName == "" or type(stashName) ~= "string" then
print("^6Bridge^7: ^2Stash name was not a string ^3"..stashName.."^7(^3"..type(stashName).."^7)") print("^6Bridge^7: ^2Stash name was not a string ^3"..stashName.."^7(^3"..type(stashName).."^7)")
return {} return {}
end end
@@ -420,6 +423,10 @@ end
--- stashRemoveItem(currentItems, "playerStash", { iron = 2, wood = 5 }) --- stashRemoveItem(currentItems, "playerStash", { iron = 2, wood = 5 })
--- ``` --- ```
function stashRemoveItem(stashItems, stashName, items) function stashRemoveItem(stashItems, stashName, items)
if stashName == "" or stashName == nil then
print("^1ERROR^7: ^1stashRemoveItem triggered but stashName was empty^7")
return
end
if type(stashName) ~= "table" then if type(stashName) ~= "table" then
stashName = { stashName } stashName = { stashName }
end end

View File

@@ -22,7 +22,7 @@ end
local function stopAnim(animDict, animName, ped) local function stopAnim(animDict, animName, ped)
StopAnimTask(ped or PlayerPedId(), animDict, animName, 0.5) StopAnimTask(ped or PlayerPedId(), animDict, animName, 0.5)
StopAnimTask(ped or PlayerPedId(), animName, animDict, 0.5) StopAnimTask(ped or PlayerPedId(), animName, animDict, 0.5)
unloadAnimDict(animDict) RemoveAnimDict(animDict)
end end
function redProgressBar(data) function redProgressBar(data)

View File

@@ -1,14 +1,14 @@
2.0.20 2.0.21
- Add Full support for lation_ui - Fix toggleDuty() for ESX users
- Add "Open Wheel" to searchCar() - Rename metadata handler functions
- Increase timeout for cache timer from 5 seconds to 2 minutes - Add useToolDegrade() to force limited uses for items
- Fix GTA progressbar erroring on playAnim() - Make breakTool() smarter
- Add Igredient location indicator when crafting - Fix getPlayer() not checking if player data exists yet on qbcore
- Fix JPRInv checks breaking early when caching framework info - Fix inbuilt gta progressbar error when stopping animations
- Enhance doesItemExist() and add getItemLabel() function - lation_ui support fixes
- Add Support for old qb-inventory config loading - Add fade in animations for created entities
- Fix typo in cancarry when using Tgiann Inv - Fix waitForSharedLoad() not announcing when an error occurs
- Add support for single progressBar when crafting - Incrase authToken timeout from 5 seconds to 1 minute
https://github.com/jimathy/jim_bridge https://github.com/jimathy/jim_bridge