Compare commits

..

37 Commits

Author SHA1 Message Date
Jim Shield
f09e34b1b5 Version Bump
`2.0.21` - `2.0.22``

- Support for qs-interface
- Fix polyzone minZ + maxZ handling
- Fix ox_target zone location to match qb-target
- Fix "Waiting for script start" loop bug
- Add condition for fading in entities
- Fix typo breaking scripts on gta skillbar fail
- Fix typo for gksphone invoice event
- Fix latio_ui TextUI placement
- Remove registerShop debug message
- Fix typo in print when removing codem stash item
- Fix function typo from origen inv documenation
2025-07-27 20:00:42 +01:00
Jim Shield
1146639d6f Update notify-discord.yml 2025-07-27 18:50:08 +01:00
Jim Shield
a9ac2e8897 Fix typo for orgien_inv getInventory 2025-07-24 21:49:37 +01:00
Jim Shield
1a1960f5a8 Fix entity blips looking for wrong preview script 2025-07-24 21:48:39 +01:00
Jim Shield
996b135973 Improve ox_target zone creation locations 2025-07-24 19:53:30 +01:00
Jim Shield
9337238832 fix typo in debugprint for codem stash staving 2025-07-23 19:53:07 +01:00
Jim Shield
ee049a953c Make ox_lib polyzone conversion code more accurate 2025-07-23 16:46:10 +01:00
Jim Shield
adfe3e8e08 Remove registerShop debug message
People keep thinking this is a massive error, its literally just stating that there isn't a script found to register a shop. not all inventories have these
2025-07-22 16:00:27 +01:00
Jim Shield
71c9c99db7 fix location typo for lation_ui drawtext 2025-07-22 13:04:46 +01:00
Jim Shield
dd66083f45 fix typo for gks sendPhoneInvoice function
when creating a `phone invoice` the function was checking if `gks-phone` was started, but I believe the script folder name is default `gksphone`
2025-07-22 11:44:32 +01:00
Jim Shield
9ddd6422bd fix typo breaking gta skillcheck if failed 2025-07-22 01:25:14 +01:00
Jim Shield
7d24c274cd Fix ox_lib polyzone maxZ and minZ math 2025-07-20 23:20:43 +01:00
Jim Shield
3911824fc6 Add resourceName sendback for onResource functions 2025-07-17 12:47:36 +01:00
Jim Shield
9729d2fef1 Add condition for stopping entity fade in 2025-07-17 12:40:43 +01:00
Jim Shield
3cb4005889 Merge pull request #51 from oosayeroo/main 2025-07-17 12:39:48 +01:00
Jim Shield
bf759ebaf8 Fix inventory config check to check "starting" scripts 2025-07-17 12:38:31 +01:00
Jim Shield
3d0eb3df65 fix PolyZone support for minZ maxZ 2025-07-17 12:37:41 +01:00
oosayeroo
fe09d0f773 qs notify + progressbar + makeVeh edit 2025-07-16 08:18:55 +01:00
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
29 changed files with 281 additions and 221 deletions

View File

@@ -8,10 +8,10 @@ on:
jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Discord Commits
uses: Sniddl/discord-commits@v1.6
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
template: "avatar-with-link"
include-extras: true
- name: Send commit payload to Discord Bot
run: |
curl -X POST http://${{ secrets.DISCORDBOT }}:3000/github-commits \
-H "Content-Type: application/json" \
-d '${{ toJson(github.event) }}'

View File

@@ -21,12 +21,12 @@ This module provides access and control over player metadata, which is useful fo
print("Player stress level:", stress)
```
- **SetMetadata(player, key, value)**
- **setPlayerMetadata(player, key, value)**
⚠️ Server side only
- 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.
- **Example:**
```lua
SetMetadata(player, "stress", 0)
setPlayerMetadata(player, "stress", 0)
```

View File

@@ -49,17 +49,19 @@ end
local function endTimer(label)
timers[label] = GetGameTimer() - (timers[label] or GetGameTimer())
timers[label] = timers[label] / 1000
timers[label] = "("..(timers[label] / 1000).."s)"
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)
local function checkExists(resourceName)
return GetResourceState(resourceName):find("start") or GetResourceState(resourceName):find("stopped")
end
-- Ensure oxmysql resource is loaded
local fileLoader = assert(load(LoadResourceFile("oxmysql", ('lib/MySQL.lua')), ('@@oxmysql/lib/MySQL.lua')))
fileLoader()
if checkExists(Exports.OXCoreExport) or checkExists(Exports.ESXExport) then
local fileLoader = assert(load(LoadResourceFile("oxmysql", ('lib/MySQL.lua')), ('@@oxmysql/lib/MySQL.lua')))
fileLoader()
end
if checkExists(Exports.OXCoreExport) then
-- Detected OX_Core in server, wait for it to be started if needed
@@ -88,7 +90,6 @@ end
---- Load Items -----
---------------------
-- Items initialization based on detected inventory system
startTimer("Items")
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
@@ -171,7 +172,6 @@ endTimer("Items")
---------------------
--- Load Vehicles ---
---------------------
startTimer("Vehicles")
-- Vehicle loading depending on framework
if checkExists(Exports.QBXExport) then
vehResource = Exports.QBXExport
@@ -215,7 +215,6 @@ endTimer("Vehicles")
---------------------
----- Load Jobs -----
---------------------
startTimer("Jobs")
-- Jobs loading based on framework
if checkExists(Exports.QBXExport) then
jobResource = Exports.QBXExport
@@ -308,8 +307,6 @@ end
-- 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 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)
if data.convars then
return function(path)
@@ -323,12 +320,19 @@ local function getInventoryConfig(resource, data)
if not content then return nil, "Failed to load file" end
local env = {
GetConvar = GetConvar, vector3 = vector3, Citizen = Citizen,
GetResourceState = GetResourceState, exports = exports,
DependencyCheck = DependencyCheck or function() return nil end,
GetConvar = GetConvar,
vector3 = vector3,
vector4 = vector4,
Citizen = Citizen,
GetResourceState = GetResourceState,
exports = exports,
DependencyCheck = function() return nil end,
}
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 pcall(fn) then return nil, "Error executing config file" end
@@ -372,6 +376,10 @@ for script, data in pairs(invWeightTable) do
if checkExists(script) then
if script == Exports.QBInv and GetResourceState(Exports.JPRInv):find("start") then goto skip end
while GetResourceState(script) ~= "started" and GetResourceState(script) ~= "stopped" do
Wait(100)
print("Waiting for script start")
end
local attempts = data.fallback or { data }
local lookup, used, err
@@ -419,17 +427,17 @@ CreateThread(function()
if type(v) ~= "number" then for count in pairs(v) do counts[k] += 1 end end
end
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
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
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"..vehResource:gsub("-", "^7-^4"):gsub("_", "^7_^4").."^2 Loaded ^3"..tostring(counts.Vehicles).."^2 Vehicles ^7("..timers["Vehicles"].."s)")
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.Gangs).."^2 Gangs ^7("..timers["Jobs"].."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"])
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"])
endTimer("Cache")
print("^6FrameworkCache^7: ^2Cache Ready ^7("..timers["Cache"].."s)")
print("^6FrameworkCache^7: ^2Cache Ready ^7"..timers["Cache"])
cacheReady = true
end)

View File

@@ -1,6 +1,6 @@
name "Jim_Bridge"
author "Jimathy"
version "2.0.20"
version "2.0.22"
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.'

View File

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

View File

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

View File

@@ -34,10 +34,10 @@ end
if IsDuplicityVersion() then
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
while not cache and GetGameTimer() < timeout do
while not cache and (timeout and GetGameTimer() < timeout) do
if GetResourceState("jim_bridge"):find("start") then
local success, result = pcall(function()
return exports["jim_bridge"]:GetSharedData()
@@ -49,7 +49,7 @@ if IsDuplicityVersion() then
Wait(100)
end
if not cache then
if timeout and not cache then
print("^1ERROR^7: ^2jim_bridge export not available after timeout^7.")
return
end

View File

@@ -89,7 +89,7 @@ function craftingMenu(data)
-- Check if the player can carry the required items (server callback).
local canCarryTable = triggerCallback(getScript()..':server:canCarry', tempCarryTable)
local usingStash = data.stashName ~= nil
local usingStash = data.stashName ~= nil and data.stashName ~= ""
Menu[#Menu+1] = {
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
if data.craft["hasCrafted"] ~= nil then
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:SetMetadata", "craftedItems", data.craftable.craftedItems)
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end
if data.craft["exp"] ~= nil then
craftingLevel += data.craft["exp"].give * craftAmount
triggerCallback(getScript()..":server:SetMetadata", "craftingLevel", craftingLevel)
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end
if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
@@ -448,11 +448,11 @@ function makeItem(data)
currentToken = nil
if data.craft["hasCrafted"] ~= nil then
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:SetMetadata", "craftedItems", data.craftable.craftedItems)
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end
if data.craft["exp"] ~= nil then
craftingLevel += data.craft["exp"].give
triggerCallback(getScript()..":server:SetMetadata", "craftingLevel", craftingLevel)
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end
if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)

View File

@@ -52,7 +52,7 @@ function drawText(image, input, style, oxStyleTable)
keybind = nil,
icon = (image and radarTable[image] or image) or nil,
iconColor = '#3B82F6',
position = 'center-left'
position = 'left-center'
})
elseif Config.System.drawText == "gta" then

View File

@@ -111,7 +111,7 @@ function getPlayerInv(src)
if src then
grabInv = exports[OrigenInv]:getInventory(src)
else
grabInv = exports[OrigenInv]:getInventory()
grabInv = exports[OrigenInv]:GetInventory()
end
elseif isStarted(CoreInv) then
@@ -232,6 +232,7 @@ function invImg(item)
elseif isStarted(PSInv) then
imgLink = "nui://"..PSInv.."/html/images/"..(Items[item].image or "")
elseif isStarted(TgiannInv) then
imgLink = "nui://inventory_images/images/"..(Items[item].image or "")

View File

@@ -376,130 +376,73 @@ end
--- ```lua
--- breakTool({ item = "drill", damage = 10 })
--- ```
function breakTool(data) -- WIP
local durability, slot = getDurability(data.item)
if not durability then durability = 100 end
durability -= data.damage
if durability <= 0 then
removeItem(data.item, 1)
function breakTool(data)
local metadata, slot = getItemMetadata(data.item)
metadata = metadata or {}
if not metadata.durability then metadata.durability = 100 end
metadata.durability -= data.damage
if metadata.durability <= 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:setMetaData", { item = data.item, slot = slot, metadata = { durability = durability } })
TriggerServerEvent(getScript()..":server:setItemMetaData", { item = data.item, slot = slot, metadata = metadata })
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.
--- @return number|nil number The durability, or nil if not found.
--- @return number|nil number The slot number, or nil if not found.
--- @param data table Contains:
--- - item (string): The tool's name.
--- - damage (number): The damage % to apply.
---
--- @usage
--- ```lua
--- local durability, slot = getDurability("drill")
--- if durability then
--- print("Durability:", durability)
--- print("Slot:", slot)
--- end
--- useToolDegrade({ item = "drill", maxUse = 10 })
--- ```
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 durability = nil
if isStarted(QBInv) or isStarted(PSInv) or isStarted(RSGInv) or isStarted(JPRInv) then
local itemcheck = Core.Functions.GetPlayerData().items
local chosenSlot = slot
local metadata = {}
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
if v.name == item then
if v.slot <= lowestSlot then
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
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
return metadata, lowestSlot
end
--- Server event handler to set metadata for an item.
@@ -513,9 +456,9 @@ end
---
--- @usage
--- ```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
if isStarted(QBInv) or isStarted(PSInv) or isStarted(RSGInv) or isStarted(JPRInv) then
--debugPrint(src, data.item, 1, data.slot)

View File

@@ -104,16 +104,31 @@ function toggleDuty()
TriggerServerEvent("QBCore:ToggleDuty")
Wait(100)
onDuty = getPlayer().onDuty
elseif isStarted(RSGExport) then
TriggerServerEvent("RSGCore:ToggleDuty")
Wait(100)
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
triggerNotify(nil, "Now on duty", "success")
else
triggerNotify(nil, "Now off duty", "success")
end
else
onDuty = not onDuty
if onDuty then
triggerNotify(nil, "Now on duty", "success")
else
triggerNotify(nil, "Now off duty", "success")
end
end
end

View File

@@ -187,7 +187,7 @@ end
--- ```
function playAnim(animDict, animName, duration, flag, ped, speed)
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)
end
@@ -238,4 +238,25 @@ function playGameSound(audioBank, soundSet, soundRef, coords, synced, range)
PlaySoundFromEntity(soundId, soundRef, coords, soundSet, synced, 1.0)
end
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

View File

@@ -133,16 +133,19 @@ function makeEntityBlip(data)
AddTextComponentString(tostring(data.name))
EndTextCommandSetBlipName(blip)
-- Handle preview image if certain resources are running
if isStarted("fs_smallresources") or isStarted("blip-info") or isStarted("blipinfo") then
if isStarted("jim-blipcontroller") then
if data.preview then
local txname = string.gsub(tostring(data.name..'preview'), "[ ()~]", "")
local txname = string.gsub(tostring(data.name..'preview'..string.gsub(data.coords.z, "%.", "")), "[ ()~]", "")
if data.preview:find("http") or data.preview:find("nui") then
createDui(txname, data.preview, vec2(512, 256), scriptTxd)
else
CreateRuntimeTextureFromImage(scriptTxd, txname, data.preview)
end
exports["fs_smallresources"]:SetBlipInfoImage(blip, getScript()..'previewTxd', txname)
exports["fs_smallresources"]:SetBlipInfoTitle(blip, data.name, false)
exports["jim-blipcontroller"]:ShowBlipInfo(blip, {
title = data.name,
dict = getScript()..'scriptTxd',
tex = txname,
})
end
end
end

View File

@@ -55,14 +55,14 @@ end
-- ```lua
-- local ped = makePed(pedData, pedCoords, true, false, nil, {'animDict', 'animName'}, true)
-- ```
function makePed(data, coords, freeze, collision, scenario, anim, synced)
function makePed(data, coords, freeze, collision, scenario, anim, synced, fade)
local ped = nil
local model = nil
if type(data) == "table" then
model = 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)
SetEntityAlpha(ped, 0, false)
-- 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)
@@ -116,6 +116,7 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
loadModel(model)
if gameName == "rdr3" then
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
SetEntityAlpha(ped, 255, false) -- SetEntityAlpha
SetRandomOutfitVariation(ped, true) -- Invisible without
@@ -141,6 +142,11 @@ function makePed(data, coords, freeze, collision, scenario, anim, synced)
end
unloadModel(model)
Peds[keyGen()..keyGen()] = ped
if fade ~= false then
CreateThread(function()
fadeInEnt(ped)
end)
end
return ped
end
@@ -243,4 +249,4 @@ onResourceStop(function()
for k in pairs(Peds) do
DeletePed(Peds[k])
end
end, true)
end, true)

View File

@@ -20,15 +20,21 @@ local Props = {}
--- }
--- local prop = makeProp(propData, true, false)
--- ```
function makeProp(data, freeze, synced)
function makeProp(data, freeze, synced, fade)
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)
SetEntityAlpha(veh, 0, false)
SetEntityHeading(prop, (data.coords.w or 0) + 180.0)
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))
SetModelAsNoLongerNeeded(data.prop)
Props[keyGen()..keyGen()] = prop
if fade ~= false then
CreateThread(function()
fadeInEnt(prop)
end)
end
return prop
end

View File

@@ -13,23 +13,29 @@ local Vehicles = {}
--- ```lua
--- local vehicle = makeVeh('adder', vector4(123.4, 567.8, 90.1, 180.0))
--- ```
function makeVeh(model, coords)
function makeVeh(model, coords, synced, fade)
loadModel(model)
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, false)
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, synced ~= false, false)
SetVehicleHasBeenOwnedByPlayer(veh, true)
if gameName ~= "rdr3" then
SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true)
SetEntityAlpha(veh, 0, false)
SetNetworkIdCanMigrate(NetworkGetNetworkIdFromEntity(veh), true)
Wait(100)
SetVehicleNeedsToBeHotwired(veh, false)
SetVehRadioStation(veh, 'OFF')
SetVehicleFuelLevel(veh, 100.0)
SetVehicleModKit(veh, 0)
end
SetVehicleOnGroundProperly(veh)
debugPrint("^6Bridge^7: ^1Veh ^2Created^7: '^6"..veh.."^7' | ^2Hash^7: ^7'^6"..model.."^7' | ^2Coord^7: "..formatCoord(coords))
unloadModel(model)
Vehicles[#Vehicles + 1] = veh
if fade ~= false then
CreateThread(function()
fadeInEnt(veh)
end)
end
return veh
end
@@ -52,7 +58,7 @@ function makeDistVehicle(data, radius, onEnter, onExit)
coords = vec3(data.coords.x, data.coords.y, data.coords.z),
radius = radius,
onEnter = function()
vehicle = makeVeh(data.model, data.coords)
vehicle = makeVeh(data.model, data.coords, false)
if onEnter then
debugPrint("^6Bridge^7: ^4makeDistVehicle ^3onEnter^7() ^2running^7")
onEnter(vehicle)

View File

@@ -119,6 +119,27 @@ function progressBar(data)
result = false
end, data.icon)
elseif Config.System.ProgressBar == "qs" then -- documentation left intact based on qs interface
local qs_success = exports['qs-interface']:ProgressBar({
duration = debugMode and 1000 or data.time, -- Duration of the progress bar (in milliseconds)
label = data.label, -- Text that will appear on the progress bar
position = 'bottom', -- Position of the progress bar on the screen (e.g., 'top', 'bottom', 'center')
useWhileDead = data.dead or false, -- Whether the progress bar shows when the player is dead (true/false)
canCancel = data.cancel or true, -- Whether the player can cancel the progress (true/false)
disable = data.disableMovement or false, -- Whether to disable player controls during the progress (true/false)
anim = { -- Animation to be played while the progress is happening
dict = data.dict,
clip = data.anim,
flag = data.flag or 32 -- Optional animation flags
},
prop = nil -- Optional prop to show alongside the progress bar (can be nil)
})
if qs_success then
result = true
else
result = false
end
elseif Config.System.ProgressBar == "esx" then
ESX.Progressbar(data.label, debugMode and 1000 or data.time, {
FreezePlayer = true,
@@ -150,6 +171,7 @@ function progressBar(data)
anim = {
dict = data.dict,
clip = data.anim,
flag = data.flag
},
prop = {
model = data.prop and data.prop.model,
@@ -160,7 +182,7 @@ function progressBar(data)
}) then
result = true
else
result = true
result = false
end
elseif Config.System.ProgressBar == "red" then

View File

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

View File

@@ -44,6 +44,12 @@ function triggerNotify(title, message, type, src)
else
TriggerClientEvent("QBCore:Notify", src, message, type)
end
elseif Config.System.Notify == "qs" then
if not src then
exports['qs-interface']:AddNotify(message, title, 6000)
else
TriggerClientEvent('interface:notification', src, message, title, 6000)
end
elseif Config.System.Notify == "ox" then
if not src then
TriggerEvent('ox_lib:notify', { title = title, description = message, type = type or "success" })

View File

@@ -171,7 +171,7 @@ function sendPhoneInvoice(data)
end
},
{
name = "gks-phone",
name = "gksphone",
send = function(mailData)
-- Defensive check for required fields
local required = { "billedCitizenid", "amount", "job", "name", "billerCitizenid", "label" }
@@ -197,7 +197,6 @@ function sendPhoneInvoice(data)
}
}
-- Check each phone system in order and use the first active one.
for _, phone in ipairs(phoneSystems) do
if isStarted(phone.name) then

View File

@@ -412,7 +412,7 @@ function hasJob(job, source, grade)
elseif isStarted(QBExport) and not isStarted(QBXExport) then
if Core.Functions.GetPlayer then
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
if jobinfo.name == job then
hasJobFlag = true
@@ -437,11 +437,10 @@ function hasJob(job, source, grade)
if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end
end
end
elseif isStarted(RSGExport) then
if Core.Functions.GetPlayer then
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
if jobinfo.name == job then
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")
end
end
::skip::
return hasJobFlag, duty
end

View File

@@ -44,19 +44,34 @@ function createPoly(data)
local Location = nil
if isStarted(OXLibExport) then
debugPrint("^6Bridge^7: ^2Creating new poly with ^7'^4"..OXLibExport.."^7': "..data.name)
-- Convert 2D points to 3D with a fixed Z coordinate (e.g., 12.0)
data.minZ = data.minZ or 12.0
data.maxZ = data.maxZ or 1000.0
data.thickness = ((data.maxZ / 2) - (data.minZ / 2)) * 2
local mid = data.maxZ - ((data.maxZ / 2) - (data.minZ / 2))
for i = 1, #data.points do
data.points[i] = vec3(data.points[i].x, data.points[i].y, 12.0)
data.points[i] = vec3(data.points[i].x, data.points[i].y, mid)
end
data.thickness = 1000 -- Set a default thickness value
Location = lib.zones.poly(data)
elseif isStarted("PolyZone") then
debugPrint("^6Bridge^7: ^2Creating new poly with ^7'^4PolyZone^7': "..data.name)
Location = PolyZone:Create(data.points, { name = data.name, debugPoly = data.debug })
Location = PolyZone:Create(data.points, {
name = data.name,
minZ = data.minZ or nil,
maxZ = data.maxZ or nil,
debugPoly = data.debug
})
Location:onPlayerInOut(function(isPointInside)
if isPointInside then data.onEnter() else data.onExit() end
if isPointInside then
data.onEnter()
else
data.onExit()
end
end)
else
print("^4ERROR^7: ^2No PolyZone creation script detected ^7- ^2Check ^3exports^1.^2lua^7")
end

View File

@@ -261,6 +261,6 @@ function registerShop(name, label, items, society)
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)
-- debugPrint("^1ERROR^7: ^1Couldn't find supported inventory to register shop^7:", name)
end
end

View File

@@ -15,6 +15,9 @@ local stash
-- If running on the server, create a callback to retrieve stash items.
if isServer() then
createCallback(getScript()..':server:GetStashItems', function(source, stashName)
if stashName == nil or stashName == "" then
return {}
end
stash = getStash(stashName)
return stash
end)
@@ -35,9 +38,9 @@ local stashCache = {}
--- local cached = GetStashTimeout("playerStash")
--- ```
function GetStashTimeout(stashName, stop)
if stop then
if stop or (stashName == nil or stashName == "") then
stashCache = {}
return
return false
end
-- 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 })
--- ```
function checkStashItem(stashes, itemTable)
if not stashes then
if not stashes or stashes == "" then
return hasItem(itemTable), nil
end
@@ -317,7 +320,7 @@ end
--- ```
function getStash(stashName)
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)")
return {}
end
@@ -420,6 +423,10 @@ end
--- stashRemoveItem(currentItems, "playerStash", { iron = 2, wood = 5 })
--- ```
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
stashName = { stashName }
end
@@ -462,7 +469,7 @@ function stashRemoveItem(stashItems, stashName, items)
end
end
exports[CodeMInv]:UpdateStash(stashName[1], stashItems)
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3CodeM^2 stash ^7'^6"..stashName.."^7'")
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3CodeM^2 stash ^7'^6"..stashName[1].."^7'")
elseif isStarted(OrigenInv) then
for k, v in pairs(items) do

View File

@@ -158,19 +158,25 @@ function createBoxTarget(data, opts, dist)
icon = opts[i].icon,
label = opts[i].label,
items = opts[i].item or nil,
groups = opts[i].job or opts[i].gang,
groups = opts[i].groups or opts[i].job or opts[i].gang,
onSelect = opts[i].onSelect or opts[i].action,
distance = dist,
canInteract = opts[i].canInteract or nil,
}
end
if not data[5].useZ then
local z = data[2].z + math.abs(data[5].maxZ - data[5].minZ) / 2
data[2] = vec3(data[2].x, data[2].y, z)
end
data[5].maxZ = data[5].maxZ or (data[2].z + 0.80)
data[5].minZ = data[5].minZ or data[2].z - 1.05
local thickness = ((data[5].maxZ / 2) - (data[5].minZ / 2)) * 2
local mid = data[5].maxZ - ((data[5].maxZ / 2) - (data[5].minZ / 2))
--if not data[5].useZ then
-- local z = data[2].z + math.abs(data[5].maxZ - data[5].minZ) / 2
data[2] = vec3(data[2].x, data[2].y, mid) -- force the coord to middle of the minZ and maxZ
--end
local target = exports[OXTargetExport]:addBoxZone({
coords = data[2],
size = vec3(data[4], data[3], (data[5].useZ or not data[5].maxZ) and data[2].z or math.abs(data[5].maxZ - data[5].minZ)),
size = vec3(data[4], data[3], thickness), -- size uses the math to determine how high it needs to be
rotation = data[5].heading,
debug = data[5].debugPoly,
options = options

View File

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

View File

@@ -53,7 +53,7 @@ function gtaSkillCheck()
DrawRect(x - width / 2 + (highlightStart + highlightSize / 2) * width, y, highlightSize * width, height+0.001, 228, 52, 52, 255)
DrawRect(x - width / 2 + cursorPos * width, y, 0.002, height + 0.01, 255, 255, 255, 255)
drawSuccessText(x, y, "Failed", 228, 52, 52)
drawGTASuccessText(x, y, "Failed", 228, 52, 52)
end
return false
end

View File

@@ -1,14 +1,15 @@
2.0.20
2.0.22
- Add Full support for lation_ui
- Add "Open Wheel" to searchCar()
- Increase timeout for cache timer from 5 seconds to 2 minutes
- Fix GTA progressbar erroring on playAnim()
- Add Igredient location indicator when crafting
- Fix JPRInv checks breaking early when caching framework info
- Enhance doesItemExist() and add getItemLabel() function
- Add Support for old qb-inventory config loading
- Fix typo in cancarry when using Tgiann Inv
- Add support for single progressBar when crafting
- Support for qs-interface
- Fix polyzone minZ + maxZ handling
- Fix ox_target zone location to match qb-target
- Fix "Waiting for script start" loop bug
- Add condition for fading in entities
- Fix typo breaking scripts on gta skillbar fail
- Fix typo for gksphone invoice event
- Fix latio_ui TextUI placement
- Remove registerShop debug message
- Fix typo in print when removing codem stash item
- Fix function typo from origen inv documenation
https://github.com/jimathy/jim_bridge