Compare commits

...

8 Commits

Author SHA1 Message Date
Jim Shield
0bc3c0f9b4 Update itemcontrol.lua 2025-10-03 17:44:29 +01:00
Jim Shield
672dd7684b Fix ESX authtoken callback saying possible exploit 2025-10-03 13:51:15 +01:00
Jim Shield
c040390d1f Start working on inventory fallback functions
NEEDS TESTING

A lot of ESX stuff not done yet
2025-10-03 12:22:05 +01:00
Jim Shield
26b1f36029 Version Bump
`2.1.04` - `2.1.05`
2025-10-02 12:24:27 +01:00
Jim Shield
331dc94e2f Revert Crafting
I realised in trying to increase readability and optimize, I broke crafting recipes that supported different multiple recipes in the same list

eg. Mining has 3 recipes in the smelter for `goldingot`

This reverts the system back to the previous recipe style but keeps all the fixes/features from the latest updates
2025-10-02 12:20:58 +01:00
Jim Shield
d1dab48acc Fix singleprogress multiplying crafting recipes
Adds a `cloneTable()` function to make a "deep copy" of the crafting recipes when calculating the multiple amounts to be taken when multicrafting
2025-10-02 00:14:13 +01:00
Jim Shield
7e595df143 Remove gta progressbar print from testing 2025-10-01 17:04:59 +01:00
Jim Shield
d791a2e09f quick fix converting old crafting style 2025-10-01 11:42:47 +01:00
7 changed files with 269 additions and 110 deletions

View File

@@ -1,6 +1,6 @@
name "Jim_Bridge"
author "Jimathy"
version "2.1.04"
version "2.1.05"
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

@@ -7,14 +7,22 @@ AuthEvent = nil
currentToken = nil
if isServer() then
local excludeRes = {
[Exports.QBExport] = true,
[Exports.ESXExport] = true,
[Exports.VorpExport] = true,
}
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() ~= Exports.QBExport and GetInvokingResource() ~= Exports.VorpExport then
local invokingRes = GetInvokingResource()
debugPrint(invokingRes)
if invokingRes and invokingRes ~= getScript() and not excludeRes[invokingRes] then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return ""
end
@@ -47,9 +55,9 @@ if isServer() then
createCallback(getScript()..":callback:GetAuthEvent", function(source)
local src = source
--debugPrint(GetInvokingResource())
local invokingRes = GetInvokingResource()
if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= Exports.QBExport and GetInvokingResource() ~= Exports.VorpExport then
if invokingRes and invokingRes ~= getScript() and not excludeRes[invokingRes] then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital callback was called from an external resource^7")
return ""
end

View File

@@ -65,7 +65,7 @@ local excludeKeys = {
--- ```
function craftingMenu(data)
if CraftLock then return end
local data = cloneTable(data)
-- Job or gang check; exit if not authorized.
if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end
@@ -80,48 +80,48 @@ function craftingMenu(data)
data.stashName = data.stashTable or data.stashName
-- Wrapper to convert old style crafting recipes to be handled by the menu properly
if data.craftable.Recipes[1] then -- assume old style crafting table
local compatTable = {}
local id = 0
for k, v in ipairs(data.craftable.Recipes) do
local Recipe = v
for l, b in pairs(Recipe) do
id += 1
if doesItemExist(l) then
compatTable[l] = {
ingredients = b,
id = id,
info = {
amount = Recipe.amount or 1,
metadata = Recipe.metadata or nil,
job = Recipe.job or nil,
gang = Recipe.gang or nil,
hasCrafted = Recipe.hasCrafted or nil,
},
}
end
end
end
data.craftable.Recipes = compatTable
end
--if data.craftable.Recipes[1] then -- assume old style crafting table
-- local compatTable = {}
-- local id = 0
-- for k, v in ipairs(data.craftable.Recipes) do
-- local Recipe = v
-- for l, b in pairs(Recipe) do
-- if doesItemExist(l) then
-- id += 1
-- compatTable[l] = {
-- ingredients = b,
-- id = id,
-- info = {
-- amount = Recipe.amount or 1,
-- metadata = Recipe.metadata or nil,
-- job = Recipe.job or nil,
-- gang = Recipe.gang or nil,
-- hasCrafted = Recipe.hasCrafted or nil,
-- },
-- }
-- end
-- end
-- end
-- data.craftable.Recipes = compatTable
--end
-- Convert to array
local RecipesArray = {}
for k, v in pairs(data.craftable.Recipes) do
RecipesArray[v.id] = { [k] = v }
end
--local RecipesArray = {}
--for k, v in pairs(data.craftable.Recipes) do
-- RecipesArray[v.id] = { [k] = v }
--end
local Menu = {}
local Recipes = data.craftable.Recipes
local Recipes = cloneTable(data.craftable.Recipes)
local craftedItems = {}
local tempCarryTable = {}
-- Build a temporary table of all required ingredients (default quantity is 1).
for i = 1, #RecipesArray do
for k, v in pairs(RecipesArray[i]) do
if doesItemExist(k) then
if not v.info.amount then v.info.amount = 1 end
tempCarryTable[k] = tempCarryTable[k] and (tempCarryTable[k] < v.info.amount) or v.info.amount
for i = 1, #Recipes do
for k, v in pairs(Recipes[i]) do
if not excludeKeys[k] then
if not Recipes[i].amount then Recipes[i].amount = 1 end
tempCarryTable[k] = tempCarryTable[k] and (tempCarryTable[k] < Recipes[i].amount) or Recipes[i].amount
end
end
end
@@ -136,27 +136,29 @@ function craftingMenu(data)
header = "Material Source: "..(usingStash and "Job Stash" or "Player Inventory"),
disabled = true,
}
for i = 1, #RecipesArray do
for i = 1, #Recipes do
local menuId = #Menu+1
local item = ""
for k in pairs(RecipesArray[i]) do
local Recipe = {}
for k, v in pairs(Recipes[i]) do
if not excludeKeys[k] then
item = k
Recipe = Recipes[i]
Recipe.amount = Recipe.amount or 1
break
end
end
local Recipe = RecipesArray[i][item]
-- Job Check
local hasGroup = true
if Recipe.info.job then
for l, b in pairs(Recipe.info.job) do
if Recipe.job then
for l, b in pairs(Recipe.job) do
hasGroup = hasJob(l, nil, b)
if hasGroup then goto skipcheck end
end
end
if Recipe.info.gang then
for l, b in pairs(Recipe.info.gang) do
if Recipe.gang then
for l, b in pairs(Recipe.gang) do
hasGroup = hasJob(l, nil, b)
if hasGroup then goto skipcheck end
end
@@ -165,12 +167,11 @@ function craftingMenu(data)
-- if has group requirement, continue
if hasGroup then
local setheader, settext, disable, metadata = "", "", false, (Recipe.info.metadata or Recipe.info.info or nil)
local setheader, settext, disable, metadata = "", "", false, (Recipe.metadata or Recipe.info or nil)
local itemTable = {}
local metaTable = {}
-- Build ingredient details.
for l, b in pairs(Recipe.ingredients) do
for l, b in pairs(Recipe[item]) do
local label = getItemLabel(l)
local hasItem = checkStashItem(data.stashName, { [l] = b })
local missingMark = not hasItem and "" or " "
@@ -182,17 +183,16 @@ function craftingMenu(data)
-- Make sure "canCarryTable" exists
while not canCarryTable do Wait(10) end
disable = not checkStashItem(data.stashName, itemTable)
setheader = ((metadata and metadata.label) or getItemLabel(item))
..(Recipe.info.amount > 1 and " x"..Recipe.info.amount or "")
..(Recipe.amount > 1 and " x"..Recipe.amount or "")
local statusEmoji = disable and " " or not canCarryTable[item] and " 📦" or " ✔️"
local isNew = (Recipe.info.hasCrafted ~= nil and craftedItems[item] == nil) and "" or ""
local isNew = (Recipe.hasCrafted ~= nil and craftedItems[item] == nil) and "" or ""
setheader = isNew .. setheader .. statusEmoji
-- Build menu option using info
Menu[#Menu + 1] = {
Menu[menuId] = {
arrow = isOx() and (not disable and canCarryTable[item]),
isMenuHeader = disable or not canCarryTable[item],
icon = invImg((metadata and metadata.image) or item),
@@ -203,9 +203,10 @@ function craftingMenu(data)
onSelect = (not disable and canCarryTable[item]) and function()
local transdata = {
item = item,
craft = RecipesArray[i][item],
craft = Recipe,
craftable = data.craftable,
coords = data.coords,
amount = Recipe.amount,
stashName = data.stashName,
onBack = data.onBack,
metadata = metadata,
@@ -270,7 +271,7 @@ function multiCraft(data)
for i = 1, maxCreation do
multiItemTable[i] = {}
for l, b in pairs(data.craft.ingredients) do
for l, b in pairs(data.craft[data.item]) do
multiItemTable[i][l] = (b * i)
end
end
@@ -376,7 +377,10 @@ end
--- })
--- ```
function makeItem(data)
function makeItem(origData)
local data = cloneTable(origData)
local Ped = PlayerPedId()
if CraftLock then return end
CraftLock = true
@@ -391,7 +395,7 @@ function makeItem(data)
local craftAmount = (data.amount and data.amount ~= 1) and data.amount or 1
local metadata = data.metadata or nil
local prop = data.craftable.Anims and data.craftable.Anims.prop or nil
jsonPrint(prop)
local canReturn = true
local crafted, crafting = true, true
@@ -413,12 +417,12 @@ function makeItem(data)
if not Config.Crafting.SingleProgress then -- if SingleProgress is disabled, dont do ingredient progressbars
-- Run ingredient check and usage separately first
for i = 1, craftAmount do
for k, v in pairs(data.craft.ingredients) do
for k, v in pairs(data.craft[data.item]) do
if isInventoryOpen() then
print("^1Error^7: ^2Inventory is open, you tried to break things")
stopCam(0)
ClearPedTasks(Ped)
if canReturn then craftingMenu(data) end
if canReturn then craftingMenu(origData) end
CraftLock = false
return
end
@@ -440,11 +444,7 @@ function makeItem(data)
end
if not crafted then
stopCam(0)
ClearPedTasks(Ped)
if canReturn then craftingMenu(data) end
CraftLock = false
return
goto finishEarly
end
if crafting and progressBar({
@@ -459,22 +459,19 @@ function makeItem(data)
}) then
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil
if data.craft.info.hasCrafted ~= nil then
if data.craft.hasCrafted ~= nil then
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end
if data.craft.info.exp ~= nil then
if data.craft.exp ~= nil then
craftingLevel += data.craft.exp.give
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end
--if data.craftable.Recipes[1].oneUse == true then
-- removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
-- local breakId = GetSoundId()
-- PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
-- canReturn = false
--end
if data.requiredItemfunc then
data.requiredItemfunc()
if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
canReturn = false
end
else
break
@@ -492,19 +489,19 @@ function makeItem(data)
icon = data.item,
request = true,
}) then
data.craft.info.amount = craftAmount
for k, v in pairs(data.craft.ingredients) do
data.craft.amount *= craftAmount
for k, v in pairs(data.craft[data.item]) do
-- multiply igredient requirement in sent crafting table for removal
data.craft.ingredients[k] = (v * craftAmount)
data.craft[data.item][k] = (v * craftAmount)
end
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil -- clear client cached token
-- handle metadata and experience in a single go
if data.craft.info.hasCrafted ~= nil then
if data.craft.hasCrafted ~= nil then
data.craftable.craftedItems[data.item] = true
triggerCallback(getScript()..":server:setPlayerMetadata", "craftedItems", data.craftable.craftedItems)
end
if data.craft.info.exp ~= nil then
if data.craft.exp ~= nil then
craftingLevel += data.craft["exp"].give * craftAmount
triggerCallback(getScript()..":server:setPlayerMetadata", "craftingLevel", craftingLevel)
end
@@ -514,20 +511,22 @@ function makeItem(data)
-- PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
-- canReturn = false
--end
if data.sound then
StopSound(data.sound.soundId)
end
if data.requiredItemfunc then
data.requiredItemfunc()
end
end
end
::finishEarly::
if craftProp then destroyProp(craftProp) end
if data.sound then
StopSound(data.sound.soundId)
end
if data.requiredItemfunc then
data.requiredItemfunc()
end
--Wait(500)
stopCam(0)
CraftLock = false
if canReturn then craftingMenu(data) end
if canReturn then craftingMenu(origData) end
ClearPedTasks(Ped)
end
@@ -564,7 +563,7 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
if type(stashName) == "table" then
for _, name in pairs(stashName) do
stashItems = getStash(name)
for k, v in pairs(craftable.ingredients) do
for k, v in pairs(craftable[ItemMake]) do
for _, b in pairs(stashItems or {}) do
if k == b.name then
itemRemove[k] = v
@@ -574,7 +573,7 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
end
else
stashItems = getStash(stashName)
for k, v in pairs(craftable.ingredients) do
for k, v in pairs(craftable[ItemMake]) do
for _, b in pairs(stashItems or {}) do
if k == b.name then
itemRemove[k] = v
@@ -584,13 +583,13 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
end
stashRemoveItem(stashItems, stashName, itemRemove)
else
if craftable then
for k, v in pairs(craftable.ingredients or {}) do
if craftable[ItemMake] then
for k, v in pairs(craftable[ItemMake]) do
removeItem(tostring(k), v, src)
end
end
end
addItem(ItemMake, craftable.info.amount or 1, metadata, src)
addItem(ItemMake, craftable.amount or 1, metadata, src)
-- Optionally, add experience here:
-- for example:
-- if isStarted("core_skills") then exports["core_skills"]:AddExperience(src, 2) end

View File

@@ -651,6 +651,29 @@ function lookEnt(entity)
end
end
-- Function to clone tables, to use when referencing tables that need to be hard set
function cloneTable(obj, opts, seen)
if type(obj) ~= "table" then return obj end
seen = seen or {}
if seen[obj] then return seen[obj] end
local copy = {}
seen[obj] = copy
-- Copy entries
for k, v in pairs(obj) do
local k2 = (opts and opts.copy_keys) and cloneTable(k, opts, seen) or k
copy[k2] = cloneTable(v, opts, seen)
end
-- Preserve metatable unless told not to
if not (opts and opts.strip_meta) then
local mt = getmetatable(obj)
if mt ~= nil then setmetatable(copy, mt) end
end
return copy
end
-------------------------------------------------------------
-- Material and Prop Functions

View File

@@ -1147,7 +1147,7 @@ local InvFunc = {
function(itemTable, src)
local resultTable = {}
for k, v in pairs(itemTable) do
resultTable[k] = exports[OXInv]:CanCarryItem(src, k, v)
resultTable[k] = exports[RSGInv]:CanCarryItem(src, k, v)
end
return resultTable
end,
@@ -1301,6 +1301,20 @@ function hasItem(items, amount, src)
end
end
end
-- Fallback to default hasItem function
if not hasTable or not next(hasTable) then
for item, amt in pairs(items) do
local count = 0
for _, itemData in pairs(grabInv) do
if itemData and itemData.name == item then
count += (itemData.amount or itemData.count or 1)
end
end
hasTable[item] = { hasItem = count >= amt, count = count }
end
end
for _, v in pairs(hasTable) do
if not v.hasItem then
return false, hasTable
@@ -1334,7 +1348,28 @@ function getPlayerInv(src)
break
end
end
if foundInv == "" then
-- Fallback to framework functions
if not grabInv then
if isStarted(QBExport) then
if src then
grabInv = Core.Functions.GetPlayer(src).PlayerData.items
else
grabInv = Core.Functions.GetPlayerData().items
end
elseif isStarted(ESXExport) then
if src then
local xPlayer = ESX.GetPlayerFromId(src)
grabInv = xPlayer and xPlayer.getInventory() or {}
else
local xPlayer = ESX.GetPlayerData()
grabInv = xPlayer and xPlayer.inventory or {}
end
end
--jsonPrint(grabInv)
end
if grabInv == nil then
print("^4ERROR^7: ^2No Supported Inventory detected ^7- ^2Check ^3starter^1.^2lua^7")
end
return grabInv, foundInv
@@ -1423,6 +1458,17 @@ function createUseableItem(item, funct)
return
end
end
-- Fallback to framework functiosn
if isStarted(QBExport) then
debugPrint("^6Bridge^7: ^2Registering ^3UsableItem^2 with ^4"..QBExport.."^7:", item)
Core.Functions.CreateUseableItem(item, funct)
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^2Registering ^3UsableItem^2 with ^4"..ESXExport.."^7:", item)
while not ESX do Wait(0) end
ESX.RegisterUsableItem(item, funct)
end
debugPrint("^4ERROR^7: No supported framework detected for registering usable item: ^3"..item.."^7")
else
print("^1ERROR^7: ^1Tried to make item usable but it didn't exist^7: "..item)
@@ -1448,7 +1494,7 @@ end
--- addItem("health_potion", 2, { quality = "high" })
--- ```
function addItem(item, amount, info, src)
if not Items[item] then
if not doesItemExist(item) then
print("^6Bridge^7: ^1Error^7 - ^2Tried to give ^7'^3"..item.."^7'^2 but it doesn't exist")
return
end
@@ -1477,7 +1523,7 @@ end
--- removeItem("health_potion", 1)
--- ```
function removeItem(item, amount, src, slot)
if not Items[item] then
if not doesItemExist(item) then
print("^6Bridge^7: ^1Error^7 - ^2Tried to remove ^7'^3"..item.."^7'^2 but it doesn't exist")
return
end
@@ -1725,9 +1771,22 @@ RegisterNetEvent(getScript()..":server:setItemMetaData", function(data, src)
local inv = InvFunc[i]
if isStarted(inv.invName) then
inv.setItemMetadata(data, src)
break
return
end
end
-- Fallback functions
if isStarted(QBExport) or isStarted(QBXExport) then -- if qbcore or qbxcore, just use core functions
local Player = Core.Functions.GetPlayer(src)
Player.PlayerData.items[data.slot].info = data.metadata
if data.metadata.durability then
Player.PlayerData.items[data.slot].description = "HP : "..data.metadata.durability
end
Player.Functions.SetInventory(Player.PlayerData.items)
elseif ESX and isStarted(ESXExport) then -- if esx then use core functions
--?
end
end)
-------------------------------------------------------------
@@ -1804,6 +1863,22 @@ function canCarry(itemTable, src)
return inv.canCarry(itemTable, src)
end
end
-- Fallback to default canCarry function
local items = getPlayerInv(src)
local totalWeight = 0
if not items then return false end
for _, item in pairs(items) do
totalWeight += (item.weight * item.amount)
end
for k, v in pairs(itemTable) do
local itemInfo = Items[k]
if not itemInfo then
resultTable[k] = true
else
resultTable[k] = (totalWeight + (itemInfo.weight * v)) <= InventoryWeight
end
end
return resultTable
end
@@ -1855,6 +1930,11 @@ function getMaxInvWeight()
break
end
end
-- Fallback function
if weight == 0 then
weight = InventoryWeight
end
return weight
end
@@ -1877,6 +1957,13 @@ function getCurrentInvWeight(src)
end
end
-- fallback function
if weight == 0 then
local itemcheck = getPlayerInv(src)
for _, v in pairs(itemcheck) do
weight += ((v.weight * (v.amount or v.count)) or 0)
end
end
return weight
end
@@ -2185,7 +2272,6 @@ end
--- local items = getStash("playerStash")
--- ```
function getStash(stashName)
local stashResource = ""
if stashName == "" or type(stashName) ~= "string" then
print("^6Bridge^7: ^2Stash name was not a string ^3"..stashName.."^7(^3"..type(stashName).."^7)")
return {}
@@ -2201,6 +2287,19 @@ function getStash(stashName)
end
end
-- Fallback to sql checks if no supported inventory found
if not stashItems or not next(stashItems) then
if isStarted(QBExport) or isStarted(QBXExport) then
local result = MySQL.scalar.await('SELECT items FROM stashitems WHERE stash = ?', { stashName })
if result then
stashItems = json.decode(result)
end
elseif ESX and isStarted(ESXExport) then -- if esx then use core functions
--?
end
end
if stashItems then
for _, item in pairs(stashItems) do
local itemInfo = Items[item.name:lower()]
@@ -2224,7 +2323,7 @@ function getStash(stashName)
end
debugPrint("^6Bridge^7: ^3GetStashItems^7: ^2Stash information for '^6"..stashName.."^7' retrieved")
end
jsonPrint(items)
--jsonPrint(items)
return items
end
@@ -2261,10 +2360,37 @@ function stashRemoveItem(stashItems, stashName, items)
end
end
-- Fallback to core functions
if isStarted(QBExport) then
local stashItems = getStash(stashName[1])
for k, v in pairs(items) do
for l in pairs(stashItems) do
if stashItems[l].name == k then
if (stashItems[l].amount - v) <= 0 then
stashItems[l] = nil
else
debugPrint("^6Bridge^7: ^2Removing ^3"..PSInv.." ^2Stash item^7:", k, v)
stashItems[l].amount -= v
end
end
end
end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QBCORE^2 stash ^7'^6"..stashName[1].."^7'")
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashName[1],
['items'] = json.encode(stashItems)
})
elseif isStarted(ESXExport) then
--?
end
print("^4ERROR^7: ^2No supported Inventory detected ^7- ^2Check ^3starter^1.^2lua^7")
end
RegisterNetEvent(getScript()..":server:stashRemoveItem", stashRemoveItem)
function stashAddItem(stashItems, stashName, items)
-- wip
end
-------------------------------------------------------------
-- Stash Item Availability Check
-------------------------------------------------------------
@@ -2394,7 +2520,7 @@ RegisterNetEvent(getScript()..":openGrabBox", function(data)
local id = data.metadata and data.metadata.id or data.info and data.info.id or ""
if isStarted(OXInv) then
-- this SHOLD be handled within ox_inventory if set up right
return
end
@@ -2646,10 +2772,17 @@ function openShop(data)
if isStarted(inv.invName) then
inv.openShop(data.shop, data.items.label, data.items)
lookEnt(data.coords)
break
return
end
end
if isStarted(QBExport) then
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
elseif isStarted(ESXExport) then
--?
end
end
RegisterNetEvent(getScript()..':server:openServerShop', function(shopName)

View File

@@ -231,7 +231,6 @@ function gtaProgressBar(data)
while result == nil do Wait(10) end
inProgress = false
print(tostring(result))
-- Cleanup animations/tasks
if data.dict then
stopAnim(data.dict, data.anim, ped)
@@ -240,7 +239,6 @@ function gtaProgressBar(data)
ClearPedTasks(ped)
end
-- Cleanup
FreezeEntityPosition(ped, false)

View File

@@ -1,9 +1,7 @@
2.1.04
2.1.05
- Crafting fixes (prop/sound/remove ingredients)
- "SingleProgress" is now one progressbar
- Add ropeControl.lua - to help create and edit custom ropes/wires
- Support for new crafting recipe style
- create setStress() multiframework function
- Fix "true/false" print from built-in gta progressbars
- Revert Crafting system to previous style (I was too quick to do this)
- Fix singleprogress multiplying crafting recipes
https://github.com/jimathy/jim_bridge/releases/latest