Compare commits

...

17 Commits

Author SHA1 Message Date
Jim Shield
c1e38a93bd Version Bump
`2.0.06` - `2.0.07`
2025-05-07 16:42:00 +01:00
Jim Shield
6a3041524a Re-add old qb-inv support for canCarry()
When updating to use the new export for qb-inv, I accidently removed the old functions, this readds them and fixes support for it
2025-05-07 16:38:57 +01:00
Jim Shield
f069db5c61 Update QBInv stash retrieval
Now uses GetInventory to grab the stash from its cache instead of directly from database

Also fixes old qb inv support for stash retrieval
2025-05-07 16:36:18 +01:00
Jim Shield
3b768d5c7d update isStarted() fuction
Add fallback for if somehow the script name being checked was sent as `nil`, if `nil` it returns false
2025-05-07 13:56:26 +01:00
Jim Shield
6b8698353b Expand on the core file loading system
This is still not in use for now, but it WILL be used in the future

I'm getting too many support tickets about the "Failed to load" warning in console about files they don't have/need
(if you don't run `ox_core` don't worry about `ox_core` not loading)

This system is intended to load it through the script instead of `fxmanifest.lua`

It is intended to check if the user has the required script and also warn them if it's not started (load order issue), or just load it as if it were told to in the fxmanifest
2025-05-07 13:55:12 +01:00
Jim Shield
5868312388 fix ps-inv/lj-inv check
If you didn't have either PS-Inventory or LJ-Inventory, this ended up breaking loading as it ended up checking is `nil` was started
2025-05-07 13:32:54 +01:00
Jim Shield
b0b139b179 Rework ps-inventory support
PS-Inv used to be exactly the same as QB-Inv so alot of the function calls were shared

This separates them and makes it easier to make changes to support their inventory

Also unified the calls for server side functions into single functions instead of having separate per inventory

Also moves:
- `invImg()` to inventories.lua
- `registerStash()` to stashcontrol.lua
2025-05-07 12:58:39 +01:00
Jim Shield
4bf4806b9e workaround for a prop claiming it couldn't find W
this is just a quick workaround, if a prop is created without a heading, it auto sets it to 0
2025-05-07 12:54:23 +01:00
Jim Shield
826e745fc3 fallback for the fallback
Not having the server convars added to the server.cfg was causing issues for some users

it should have worked, but this forces things to gta if you don't have any values set for them anywhere

I've added fallbacks to "gta" settings to hopefully stop fivem errors
2025-05-07 01:59:03 +01:00
Jim Shield
bc2867984c Version Bump
`2.0.05` - `2.0.06`
2025-05-06 10:53:34 +01:00
Jim Shield
31633bc61d crafting exploit fixes
This has several changes

When crafting, it now checks if the inventory is open and stops crafting dead and warns the player with a print.

Multicraft now checks if you have space in your inventory for the items and limits the max amount craftable

Also fixes the "title" of the qb-input box when crafting

Also changed the anim flag for the "placing items" to hopefully keep you in place
2025-05-06 00:17:07 +01:00
Jim Shield
1623feacf1 fix multicraft for qb-input side
I forgot to correct the result as qb-input returns strings, this fixes that

Also added a fallback for if the user deletes the value and tries to craft `nil`
2025-05-05 22:52:46 +01:00
Jim Shield
a203657e2a Add event to clear AuthEvent for player
When a player logs out and back in (switches character) it was thinking that the `AuthEvent` was being called more than once, triggering a warning message

This should clear the event when a player unloads and then allows them to request a new one
2025-05-05 20:01:15 +01:00
Jim Shield
1f4a2ee3d9 refactor checkStashItem()
This'll probably break it, (it works for me) but refactored the stash item check, it was calling `stashHasItem()` for every ingredient check, now it sends the whole table of ingredients per item to craft and checks them together instead of separately

Also removes a `Wait()`, as it shouldn't need it with this change..maybe
2025-05-05 12:28:30 +01:00
Jim Shield
e9c54cbdd4 multiCraft() refactor
An attempt to speed up `multiCraft()` function creation logic

Before it created a table of items while it was trying to check them I've separated this so it just gets that out of the way and checks items in it's own `for` loop

Also added a `maxCreation` variable that users can edit if needed which decides how many of an item can be created (I'll change this soon probably to tie into the config options in scripts for multicraft again soon

Also removed a few `Wait()`s that were there to help it not get confused, but after testing I believe this didn't make a difference, let me know if there's any issues with stuff like it saying it can craft when you dont have the items
2025-05-05 12:24:38 +01:00
Jim Shield
4e8a15590f make a checkToken() event its own function
Several events were calling very similar check token events, so I've just moved them to one to help unify it and help future debugging
2025-05-05 11:44:51 +01:00
Jim Shield
c745d51832 Fix up dupwarn and additem auth messages
Forgot to update this, now prints an optional message if available

and made dupeWarn kick message less specific
2025-05-04 20:33:51 +01:00
13 changed files with 502 additions and 298 deletions

View File

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

@@ -99,7 +99,7 @@ end
--- end, true) --- end, true)
--- ``` --- ```
function onResourceStart(func, thisScript) function onResourceStart(func, thisScript)
debugPrint("^6Bridge^7: Registering ^3onResourceStart^7()") debugPrint("^6Bridge^7: ^2Registering ^3onResourceStart^7()")
AddEventHandler('onResourceStart', function(resourceName) AddEventHandler('onResourceStart', function(resourceName)
if getScript() == resourceName and (thisScript or true) then if getScript() == resourceName and (thisScript or true) then
func() func()

View File

@@ -14,8 +14,8 @@ Items, Vehicles, Jobs, Gangs, Core, ESX = {}, nil, nil, nil, nil, nil
------------------------------------------------------------- -------------------------------------------------------------
-- Correct QB Inventory Export -- Correct QB Inventory Export
------------------------------------------------------------- -------------------------------------------------------------
-- Ensure that the QB inventory export is corrected from 'qb-inventory' to 'ps-inventory' or 'lj-inventory' if needed. -- Correct ps-invetory to ls-inventory if somehow you still have that
Exports.QBInv = (isStarted("ps-inventory") and "ps-inventory") or (isStarted("lj-inventory") and "lj-inventory") or Exports.QBInv Exports.PSInv = isStarted("lj-inventory") and "lj-inventory" or Exports.PSInv
------------------------------------------------------------- -------------------------------------------------------------
-- Framework Exports and Inventory Identifiers -- Framework Exports and Inventory Identifiers

View File

@@ -80,11 +80,6 @@ function craftingMenu(data)
-- Build a table of all required ingredients (default quantity is 1). -- Build a table of all required ingredients (default quantity is 1).
for i = 1, #Recipes do for i = 1, #Recipes do
for k in pairs(Recipes[i]) do for k in pairs(Recipes[i]) do
if k == "hasCrafted" and not data.craftable.craftedItems then
-- Retreive list of already crafted items from playermetadata to see if we should class this recipe as "new"
craftedItems = GetMetadata(nil, "craftedItems") or {}
data.craftable.craftedItems = craftedItems
end
if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then
tempCarryTable[k] = Recipes[i].amount or 1 tempCarryTable[k] = Recipes[i].amount or 1
end end
@@ -114,7 +109,7 @@ function craftingMenu(data)
settext = settext..(settext ~= "" and br or "")..(Items[l] and Items[l].label or "error - "..l)..(b > 1 and " x"..b or "") settext = settext..(settext ~= "" and br or "")..(Items[l] and Items[l].label or "error - "..l)..(b > 1 and " x"..b or "")
metaTable[Items[l] and Items[l].label or "error - "..l] = b metaTable[Items[l] and Items[l].label or "error - "..l] = b
itemTable[l] = b itemTable[l] = b
Wait(0) --Wait(0)
end end
while not canCarryTable do Wait(0) end while not canCarryTable do Wait(0) end
@@ -122,25 +117,16 @@ function craftingMenu(data)
setheader = ((metadata and metadata.label) or (Items[tostring(k)] and Items[tostring(k)].label) or "error - "..tostring(k)) setheader = ((metadata and metadata.label) or (Items[tostring(k)] and Items[tostring(k)].label) or "error - "..tostring(k))
..(Recipes[i]["amount"] > 1 and " x"..Recipes[i]["amount"] or "") ..(Recipes[i]["amount"] > 1 and " x"..Recipes[i]["amount"] or "")
if not disable then local statusEmoji = disable and "" or not canCarryTable[k] and " 📦" or " ✔️"
if not canCarryTable[k] then local isNew = (Recipes[i]["hasCrafted"] ~= nil and craftedItems[k] == nil) and "" or ""
setheader = setheader.." 📦" setheader = isNew .. setheader .. statusEmoji
else
setheader = setheader.." ✔️"
end
elseif not canCarryTable[k] then
setheader = setheader.." 📦"
end
if Recipes[i]["hasCrafted"] ~= nil and craftedItems[k] == nil then
setheader = ""..setheader
end
Menu[#Menu + 1] = { Menu[#Menu + 1] = {
arrow = not disable and canCarryTable[k], arrow = not disable and canCarryTable[k],
isMenuHeader = disable or not canCarryTable[k], isMenuHeader = disable or not canCarryTable[k],
icon = invImg((metadata and metadata.image) or tostring(k)), icon = invImg((metadata and metadata.image) or tostring(k)),
image = invImg((metadata and metadata.image) or tostring(k)), image = invImg((metadata and metadata.image) or tostring(k)),
header = setheader..((disable or not canCarryTable[k]) and "" or ""), header = setheader,
txt = (isStarted(QBMenuExport) or disable) and settext or nil, txt = (isStarted(QBMenuExport) or disable) and settext or nil,
metadata = metaTable, metadata = metaTable,
onSelect = (not disable and canCarryTable[k]) and function() onSelect = (not disable and canCarryTable[k]) and function()
@@ -162,7 +148,7 @@ function craftingMenu(data)
} }
end end
end end
Wait(0) --Wait(0)
end end
end end
@@ -208,16 +194,23 @@ end
function multiCraft(data) function multiCraft(data)
local max = 0 local max = 0
local stashName = nil local stashName = nil
for i = 1, 100 do local maxCreation = 100
local itemTable = {}
for l, b in pairs(data.craft[data.item]) do
debugPrint("")
itemTable[l] = (b * i)
end
-- Generate item table to check against stash or inventory
-- takes into account the ingredients needed for multiple items
local multiItemTable = {}
for i = 1, maxCreation do
multiItemTable[i] = {}
for l, b in pairs(data.craft[data.item]) do
multiItemTable[i][l] = (b * i)
end
end
for i = 1, maxCreation do
-- if its received a stash name, check if the items are in the stash
if data.stashName then if data.stashName then
debugPrint("") local hasItems, stashname = checkStashItem(data.stashName, multiItemTable[i])
local hasItems, stashname = checkStashItem(data.stashName, itemTable)
if hasItems == true then if hasItems == true then
max += 1 max += 1
stashName = stashname stashName = stashname
@@ -225,31 +218,34 @@ function multiCraft(data)
break break
end end
else else
debugPrint("") -- if not check the players inventory for the items
local has, _ = hasItem(itemTable, nil, nil) local has, _ = hasItem(multiItemTable[i], nil, nil)
if has then if has then
max += 1 max += 1
else else
break break
end end
end end
Wait(10)
end end
local dialog = createInput(data.craftable.Header, { local carryMax = triggerCallback(getScript()..":server:getMaxCarryCraft", {
item = data.item,
max = max
})
local dialog = createInput(data.craftable.Header..(Config.System.Menu == "qb" and ": "..br.."How many to craft? "..br.."Max: "..carryMax or ""), {
((Config.System.Menu == "ox") and { ((Config.System.Menu == "ox") and {
type = "slider", type = "slider",
label = "How many to craft?", label = "How many to craft? "..br.."Max: "..carryMax,
required = true, required = true,
default = 1, default = 1,
min = 1, min = 1,
max = max max = carryMax
}) or nil, }) or nil,
((Config.System.Menu == "qb") and { ((Config.System.Menu == "qb") and {
type = "number", type = "number",
label = "How many to craft?"..br.."Max: "..max,
name = "amount", name = "amount",
isRecuired = true, isRequired = true,
default = 1, default = 1,
}) or nil, }) or nil,
}) })
@@ -259,14 +255,14 @@ function multiCraft(data)
end end
if Config.System.Menu == "qb" then if Config.System.Menu == "qb" then
if dialog["amount"] > max or dialog["amount"] < 1 or dialog["amount"] == nil or dialog["amount"] == "" then dialog["amount"] = tonumber(dialog["amount"])
if dialog["amount"] > carryMax or dialog["amount"] < 1 or dialog["amount"] == nil or dialog["amount"] == "" then
triggerNotify(nil, "Invalid Amount", "error") triggerNotify(nil, "Invalid Amount", "error")
craftingMenu(data) craftingMenu(data)
return return
end end
end end
makeItem({ makeItem({
item = data.item, item = data.item,
craft = data.craft, craft = data.craft,
@@ -274,7 +270,6 @@ function multiCraft(data)
amount = dialog["amount"] or dialog[1], amount = dialog["amount"] or dialog[1],
coords = data.coords, coords = data.coords,
stashName = stashName or nil, stashName = stashName or nil,
--stashTable = data.stashName,
onBack = data.onBack, onBack = data.onBack,
metadata = data.metadata, metadata = data.metadata,
}) })
@@ -331,19 +326,23 @@ function makeItem(data)
local crafted, crafting = true, true local crafted, crafting = true, true
local cam = createTempCam(PlayerPedId(), data.coords) local cam = createTempCam(PlayerPedId(), data.coords)
startTempCam(cam) startTempCam(cam)
for i = 1, craftAmount do for i = 1, craftAmount do
for k, v in pairs(data.craft) do for k, v in pairs(data.craft) do
if not excludeKeys[k] then if not excludeKeys[k] then
if type(v) == "table" then if type(v) == "table" then
for l, b in pairs(v) do for l, b in pairs(v) do
if isInventoryOpen() then
print("^1Error^7: ^2Inventory is open, you tried to break things")
crafted, crafting = false, false
return
end
if crafting and progressBar({ if crafting and progressBar({
label = "Using "..b.." "..Items[l].label, label = "Using "..b.." "..Items[l].label,
time = 1000, time = 1000,
cancel = true, cancel = true,
dict = 'pickup_object', dict = 'pickup_object',
anim = "putdown_low", anim = "putdown_low",
flag = 48, flag = 49,
icon = l, icon = l,
}) then }) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[l], "use", b) TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[l], "use", b)
@@ -353,6 +352,11 @@ function makeItem(data)
end end
Wait(200) Wait(200)
end end
if isInventoryOpen() then
print("^1Error^7: ^2Inventory is open, you tried to break things")
crafted, crafting = false, false
return
end
if crafted then if crafted then
local craftProp = nil local craftProp = nil
if prop then if prop then
@@ -363,6 +367,11 @@ function makeItem(data)
local s = data.sound local s = data.sound
PlaySoundFromEntity(s.soundId, s.audioName, PlayerPedId(), s.audioRef, true, 0) PlaySoundFromEntity(s.soundId, s.audioName, PlayerPedId(), s.audioRef, true, 0)
end end
if isInventoryOpen() then
print("^1Error^7: ^2Inventory is open, you tried to break things")
crafted, crafting = false, false
return
end
if crafting and progressBar({ if crafting and progressBar({
label = bartext..((metadata and metadata.label) or Items[data.item].label), label = bartext..((metadata and metadata.label) or Items[data.item].label),
time = bartime, time = bartime,
@@ -414,7 +423,6 @@ function makeItem(data)
end end
stopTempCam() stopTempCam()
CraftLock = false CraftLock = false
lockInv(false)
if canReturn then craftingMenu(data) end if canReturn then craftingMenu(data) end
ClearPedTasks(PlayerPedId()) ClearPedTasks(PlayerPedId())
end end
@@ -441,17 +449,8 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
return return
end end
if token == nil then if not checkToken(src, token, "item", ItemMake) then
debugPrint("^1Auth^7: ^1No token recieved^7") return
dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token")
else
if token ~= validTokens[src] then
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src])
dupeWarn(src, item, "Auth: "..src.." attempted to trigger server only events with an incorrect auth token")
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
end
end end

View File

@@ -21,6 +21,10 @@
--- end --- end
--- ``` --- ```
function isStarted(script) function isStarted(script)
if not script then
print("^1Error^7: ^1Tried to check if ^3nil^2 was started^7, ^1returning ^4false^7")
return false
end
return GetResourceState(script):find("start") ~= nil return GetResourceState(script):find("start") ~= nil
end end

View File

@@ -15,6 +15,7 @@
function lockInv(toggle) function lockInv(toggle)
FreezeEntityPosition(PlayerPedId(), toggle) FreezeEntityPosition(PlayerPedId(), toggle)
LocalPlayer.state:set("inv_busy", toggle, true) LocalPlayer.state:set("inv_busy", toggle, true)
LocalPlayer.state:set("invBusy", toggle, true)
TriggerEvent('inventory:client:busy:status', toggle) TriggerEvent('inventory:client:busy:status', toggle)
TriggerEvent('canUseInventoryAndHotbar:toggle', not toggle) TriggerEvent('canUseInventoryAndHotbar:toggle', not toggle)
end end
@@ -169,3 +170,91 @@ function getPlayerInv(src)
end end
return grabInv, foundInv return grabInv, foundInv
end end
function isInventoryOpen()
if isStarted(OXInv) then
return LocalPlayer.state.invBusy
elseif isStarted(QSInv) then
return exports[QSInv]:inInventory()
elseif isStarted(OrigenInv) then
return exports[OrigenInv]:IsInventoryOpen()
elseif isStarted(CoreInv) then
return exports[CoreInv]:isInventoryOpen()
elseif isStarted(CodeMInv) then
return false
-- CodeM doesn't have a function to check if the inventory is open
-- No idea what it uses, so it just skips the check
elseif isStarted(TgiannInv) then
return exports[TgiannInv]:IsInventoryActive()
elseif isStarted(QBInv) then
return LocalPlayer.state.inv_busy
elseif isStarted(PSInv) then
return LocalPlayer.state.inv_busy
elseif ESX and isStarted(ESXExport) then
return false
elseif isStarted(RSGInv) then
return LocalPlayer.state.inv_busy
end
end
-------------------------------------------------------------
-- Item Image Retrieval
-------------------------------------------------------------
--- Retrieves the NUI link for an item's image from the active inventory system.
---
--- @param item string The item name.
--- @return string string A `nui://` link to the item's image, or an empty string if not found.
---
--- @usage
--- ```lua
--- local imageLink = invImg("health_potion")
--- if imageLink ~= "" then print(imageLink) end
--- ```
function invImg(item)
local imgLink = ""
if item ~= "" and Items[item] then
if isStarted(OXInv) then
imgLink = "nui://"..OXInv.."/web/images/"..(Items[item].image or "")
elseif isStarted(QSInv) then
imgLink = "nui://"..QSInv.."/html/images/"..(Items[item].image or "")
elseif isStarted(CoreInv) then
imgLink = "nui://"..CoreInv.."/html/img/"..(Items[item].image or "")
elseif isStarted(CodeMInv) then
imgLink = "nui://"..CodeMInv.."/html/itemimages/"..(Items[item].image or "")
elseif isStarted(OrigenInv) then
imgLink = "nui://"..OrigenInv.."/html/img/"..(Items[item].image or "")
elseif isStarted(QBInv) then
imgLink = "nui://"..QBInv.."/html/images/"..(Items[item].image or "")
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 "")
elseif isStarted(RSGInv) then
imgLink = "nui://"..RSGInv.."/html/images/"..(Items[item].image or "")
else
print("^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua")
end
end
return imgLink
end

View File

@@ -52,53 +52,6 @@ function createUseableItem(item, funct)
end end
end end
-------------------------------------------------------------
-- Item Image Retrieval
-------------------------------------------------------------
--- Retrieves the NUI link for an item's image from the active inventory system.
---
--- @param item string The item name.
--- @return string string A `nui://` link to the item's image, or an empty string if not found.
---
--- @usage
--- ```lua
--- local imageLink = invImg("health_potion")
--- if imageLink ~= "" then print(imageLink) end
--- ```
function invImg(item)
local imgLink = ""
if item ~= "" and Items[item] then
if isStarted(OXInv) then
imgLink = "nui://"..OXInv.."/web/images/"..(Items[item].image or "")
elseif isStarted(QSInv) then
imgLink = "nui://"..QSInv.."/html/images/"..(Items[item].image or "")
elseif isStarted(CoreInv) then
imgLink = "nui://"..CoreInv.."/html/img/"..(Items[item].image or "")
elseif isStarted(CodeMInv) then
imgLink = "nui://"..CodeMInv.."/html/itemimages/"..(Items[item].image or "")
elseif isStarted(OrigenInv) then
imgLink = "nui://"..OrigenInv.."/html/img/"..(Items[item].image or "")
elseif isStarted(QBInv) then
imgLink = "nui://"..QBInv.."/html/images/"..(Items[item].image or "")
elseif isStarted(TgiannInv) then
imgLink = "nui://inventory_images/images/"..(Items[item].image or "")
elseif isStarted(RSGInv) then
imgLink = "nui://"..RSGInv.."/html/images/"..(Items[item].image or "")
else
print("^4ERROR^7: ^2No Inventory detected for invImg - Check starter.lua")
end
end
return imgLink
end
------------------------------------------------------------- -------------------------------------------------------------
-- Adding and Removing Items -- Adding and Removing Items
@@ -179,7 +132,7 @@ end
--- TriggerServerEvent(getScript()..":server:toggleItem", true, "health_potion", 1) --- TriggerServerEvent(getScript()..":server:toggleItem", true, "health_potion", 1)
--- ``` --- ```
RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount, newsrc, info, slot, token) RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount, newsrc, info, slot, token)
debugPrint(GetInvokingResource()) --debugPrint(GetInvokingResource())
if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7") debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return return
@@ -191,21 +144,9 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
local src = newsrc or source local src = newsrc or source
if (give == true or give == 1) then if (give == true or give == 1) then
if newsrc == nil then -- must be coming from client this would be blank if newsrc == nil then -- this must be coming from client this would be blank
if token == nil then if not checkToken(src, token, "item", item) then
debugPrint("^1Auth^7: ^1No token recieved^7") return
dupeWarn(src, item, "Auth: Player "..src.." attempted to spawn "..item.." without an auth token")
else
if type(token) ~= "number" then -- checks if the newsrc is a source or token, if number its coming form the server itself
debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
if token ~= validTokens[src] then
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src])
dupeWarn(src, item, "Auth: "..src.." attempted to spawn "..item.." with an incorrect auth token")
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
end
end
end end
end end
end end
@@ -221,25 +162,32 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
dupeWarn(src, item, amount) dupeWarn(src, item, amount)
else else
if isStarted(OXInv) then invName = OXInv if isStarted(OXInv) then
invName = OXInv
exports[OXInv]:RemoveItem(src, item, remamount, nil) exports[OXInv]:RemoveItem(src, item, remamount, nil)
elseif isStarted(QSInv) then invName = QSInv elseif isStarted(QSInv) then
invName = QSInv
exports[QSInv]:RemoveItem(src, item, remamount) exports[QSInv]:RemoveItem(src, item, remamount)
elseif isStarted(CoreInv) then invName = CoreInv elseif isStarted(CoreInv) then
invName = CoreInv
exports[CoreInv]:removeItem(src, item, remamount) exports[CoreInv]:removeItem(src, item, remamount)
elseif isStarted(OrigenInv) then invName = OrigenInv elseif isStarted(OrigenInv) then
invName = OrigenInv
exports[OrigenInv]:removeItem(src, item, remamount) exports[OrigenInv]:removeItem(src, item, remamount)
elseif isStarted(CodeMInv) then invName = CodeMInv elseif isStarted(CodeMInv) then
invName = CodeMInv
exports[CodeMInv]:RemoveItem(src, item, remamount) exports[CodeMInv]:RemoveItem(src, item, remamount)
elseif isStarted(TgiannInv) then invName = TgiannInv elseif isStarted(TgiannInv) then
invName = TgiannInv
exports[TgiannInv]:RemoveItem(src, item, remamount) exports[TgiannInv]:RemoveItem(src, item, remamount)
elseif isStarted(QBInv) then invName = QBInv elseif isStarted(QBInv) then
invName = QBInv
while remamount > 0 do while remamount > 0 do
if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then
remamount -= 1 remamount -= 1
@@ -251,7 +199,9 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
if Config.Crafting.showItemBox then if Config.Crafting.showItemBox then
TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "remove", amount or 1) TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "remove", amount or 1)
end end
elseif isStarted(PSInv) then invName = PSInv
elseif isStarted(PSInv) then
invName = PSInv
while remamount > 0 do while remamount > 0 do
if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then
remamount -= 1 remamount -= 1
@@ -324,17 +274,18 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "add", amountToAdd) TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
end end
elseif isStarted(PSInv) then invName = PSInv
if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then
if Config.Crafting.showItemBox then
TriggerClientEvent("ps-inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
end
end
elseif isStarted(RSGInv) then invName = RSGInv elseif isStarted(RSGInv) then invName = RSGInv
if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then
TriggerClientEvent("rsg-inventory:client:ItemBox", src, Items[item], "add", amountToAdd) TriggerClientEvent("rsg-inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
end end
elseif isStarted(PSInv) then invName = PSInv
if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then
if Config.Crafting.showItemBox then
TriggerClientEvent("inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
end
end
end end
if invName == "" then if invName == "" then
@@ -370,13 +321,13 @@ end)
--- ```lua --- ```lua
--- dupeWarn(playerId, "health_potion") --- dupeWarn(playerId, "health_potion")
--- ``` --- ```
function dupeWarn(src, item, amount) function dupeWarn(src, item, message)
local name = getPlayer(src).name local name = getPlayer(src).name
print("^5DupeWarn^7: "..name.." (^1"..tostring(src).."^7) ^2Tried to remove item '^3"..item.."^7'^2 but it wasn't there^7") print(message or "^5DupeWarn^7: "..name.." (^1"..tostring(src).."^7) ^2Tried to remove item '^3"..item.."^7'^2 but it wasn't there^7")
if not debugMode then if not debugMode then
DropPlayer(src, name.."("..tostring(src)..") Kicked for suspected duplicating items: "..item) DropPlayer(src, name.."("..tostring(src)..") kicked by exploit protection")
end end
print("^5DupeWarn^7: "..name.."(^1"..tostring(src).."^7) ^2Dropped from server - exploit protection detected an item not being found in players inventory^7") print("^5DupeWarn^7: "..name.."(^1"..tostring(src).."^7) ^2Dropped from server - exploit protection^7")
end end
------------------------------------------------------------- -------------------------------------------------------------
@@ -675,8 +626,25 @@ function canCarry(itemTable, src)
end end
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
for k, v in pairs(itemTable) do if QBInvNew then
resultTable[k] = exports[QBInv]:CanAddItem(src, k, v) for k, v in pairs(itemTable) do
resultTable[k] = exports[QBInv]:CanAddItem(src, k, v)
end
else
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 and not Player.Offline then
resultTable[k] = true
else
resultTable[k] = (totalWeight + (itemInfo.weight * v)) <= InventoryWeight
end
end
end end
elseif isStarted(PSInv) then elseif isStarted(PSInv) then
@@ -710,13 +678,33 @@ if isServer() then
return result return result
end) end)
createCallback(getScript()..":server:getMaxCarryCraft", function(source, data)
local src = source
local item = data.item
local max = data.max or 100
local maxCanCarry = 0
for i = 1, max do
local checkTable = {
[item] = i
}
local result = canCarry(checkTable, src)
if result[item] == true then
maxCanCarry = i
else
break
end
end
return maxCanCarry
end)
local AuthEvent = getScript()..":"..keyGen()..keyGen()..keyGen()..keyGen()..":"..keyGen()..keyGen()..keyGen()..keyGen() local AuthEvent = getScript()..":"..keyGen()..keyGen()..keyGen()..keyGen()..":"..keyGen()..keyGen()..keyGen()..keyGen()
validTokens = validTokens or {} validTokens = validTokens or {}
createCallback(AuthEvent, function(source) createCallback(AuthEvent, function(source)
local src = source local src = source
local token = keyGen()..keyGen()..keyGen()..keyGen() -- Use a secure random generator here local token = keyGen()..keyGen()..keyGen()..keyGen() -- Use a secure random generator here
debugPrint(GetInvokingResource()) --debugPrint(GetInvokingResource())
if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7") debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return "" return ""
@@ -748,22 +736,63 @@ if isServer() then
receivedEvent = {} receivedEvent = {}
createCallback(getScript()..":callback:GetAuthEvent", function(source) createCallback(getScript()..":callback:GetAuthEvent", function(source)
local src = source local src = source
debugPrint(GetInvokingResource()) --debugPrint(GetInvokingResource())
if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital callback was called from an external resource^7") debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital callback was called from an external resource^7")
return "" return ""
end end
debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent) debugPrint("^1Auth^7: ^2Player Source^7: "..src.." ^2requested ^3AuthEvent^7", AuthEvent)
if not receivedEvent[src] then receivedEvent[src] = true if not receivedEvent[src] then
receivedEvent[src] = true
return AuthEvent return AuthEvent
else else
print("^1Auth^7: ^1Player ^7"..src.." ^1tried to request auth token more than once^7") print("^1Auth^7: ^1Player ^7"..src.." ^1tried to request auth token more than once^7")
return "" return ""
end end
end) end)
RegisterNetEvent(getScript()..":clearAuthEventRequest", function()
local src = source
debugPrint("^1Auth^7: ^2Manually clearing Auth Event for Player Source^7:", src, AuthEvent)
receivedEvent[src] = nil
end)
-- Multiuse function to check if the generated client token is valid
function checkToken(src, token, genType, name)
if token == nil then
debugPrint("^1Auth^7: ^1No token recieved^7")
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1without an auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1without an auth token^7")
end
return false
else
debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
if token ~= validTokens[src] then
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src])
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1with an incorrect auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1with an incorrect auth token^7")
end
return false
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
return true
end
end
end
else else
onPlayerLoaded(function() onPlayerLoaded(function()
debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7") debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7")
AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent") AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent")
end, true) end, true)
onPlayerUnload(function()
debugPrint("^1Auth^7: ^2Clearing Auth Event^7")
TriggerServerEvent(getScript()..":clearAuthEventRequest")
end, true)
end end

View File

@@ -23,7 +23,7 @@ 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)
SetEntityHeading(prop, data.coords.w + 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))

View File

@@ -161,31 +161,41 @@ function openShop(data)
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items) TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
elseif isStarted(TgiannInv) then elseif isStarted(TgiannInv) then
TriggerServerEvent(getScript()..':server:OpenShopTgiann', data.shop) TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop) TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
else
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
end
elseif isStarted(PSInv) then
if QBInvNew then
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
else else
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items) TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
end end
elseif isStarted(RSGInv) then elseif isStarted(RSGInv) then
TriggerServerEvent(getScript()..':server:OpenShopRSG', data.shop) TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
end end
lookEnt(data.coords) lookEnt(data.coords)
end end
RegisterNetEvent(getScript()..':server:OpenShopNewQB', function(data) RegisterNetEvent(getScript()..':server:openServerShop', function(data)
exports[QBInv]:OpenShop(source, data) if isStarted(QBInv) then
end) exports[QBInv]:OpenShop(source, data)
end
RegisterNetEvent(getScript()..':server:OpenShopTgiann', function(data) if isStarted(PSInv) then
exports[TgiannInv]:OpenShop(source, data) exports[PSInv]:OpenShop(source, data)
end) end
if isStarted(TgiannInv) then
RegisterNetEvent(getScript()..':server:OpenShopRSG', function(data) exports[TgiannInv]:OpenShop(source, data)
exports[RSGInv]:OpenShop(source, data) end
if isStarted(RSGInv) then
exports[RSGInv]:OpenShop(source, data)
end
end) end)
--- Registers a shop with the active inventory system. --- Registers a shop with the active inventory system.
@@ -222,6 +232,16 @@ function registerShop(name, label, items, society)
society = society, society = society,
}) })
elseif isStarted(PSInv) and QBInvNew then
debugPrint("^6Bridge^7: ^2Registering ^3PS ^2Store^7:", name, label)
exports[PSInv]:CreateShop({
name = name,
label = label,
slots = #items,
items = items,
society = society,
})
elseif isStarted(RSGInv) then elseif isStarted(RSGInv) then
debugPrint("^6Bridge^7: ^2Registering ^3RSG ^2Store^7:", name, label) debugPrint("^6Bridge^7: ^2Registering ^3RSG ^2Store^7:", name, label)
exports[RSGInv]:CreateShop({ exports[RSGInv]:CreateShop({

View File

@@ -47,19 +47,19 @@ function GetStashTimeout(stashName, stop)
stashCache[stashName] = { items = {}, timeout = 0 } stashCache[stashName] = { items = {}, timeout = 0 }
stash = stashCache[stashName] stash = stashCache[stashName]
else else
debugPrint("^6Bridge^7: ^2Local Stash ^7'^3"..stashName.."^7'^2 cache found^7") debugPrint("^6Bridge^7: ^2Local Stash for ^7'^3"..stashName.."^7'^2 cache found^7")
end end
-- If there are already items in cache, skip recheck. -- If there are already items in cache, skip recheck.
if countTable(stashCache[stashName].items) > 0 then if countTable(stashCache[stashName].items) > 0 then
debugPrint("^6Bridge^7: '^3"..stashName.." ^2Items found in cache, skipping recheck") debugPrint("^6Bridge^7: '^3"..stashName.."^7' ^2Items found in local cache, skipping server recheck")
return true return true
end end
-- If timeout has expired, update the stash items from the server. -- If timeout has expired, update the stash items from the server.
if stashCache[stashName].timeout <= 0 then if stashCache[stashName].timeout <= 0 then
stashCache[stashName].items = triggerCallback(getScript()..':server:GetStashItems', stashName) stashCache[stashName].items = triggerCallback(getScript()..':server:GetStashItems', stashName)
stashCache[stashName].timeout = 15000 -- Timeout in milliseconds. stashCache[stashName].timeout = 10000 -- Timeout in milliseconds.
CreateThread(function() CreateThread(function()
while stashCache[stashName] and stashCache[stashName].timeout > 0 do while stashCache[stashName] and stashCache[stashName].timeout > 0 do
stashCache[stashName].timeout -= 1000 stashCache[stashName].timeout -= 1000
@@ -90,20 +90,12 @@ function checkStashItem(stashes, itemTable)
end end
if type(stashes) == "table" then if type(stashes) == "table" then
local successes = 0 debugPrint("^6Bridge^7: ^2Checking multiple stashes for ingredients^7")
local itemCount = countTable(itemTable)
-- Iterate over each provided stash name. -- Iterate over each provided stash name.
for _, name in pairs(stashes) do for _, name in pairs(stashes) do
Wait(10) -- Delay to avoid multiple callbacks issues.
GetStashTimeout(name) GetStashTimeout(name)
for item, amount in pairs(itemTable) do if stashhasItem(stashCache[name].items, itemTable, nil) then
debugPrint("^6Bridge^7: ^2Checking "..(name and " '^3"..name.."^7'" or "").." ingredients - ^6"..item.."^7") return true, name
if stashhasItem(stashCache[name].items, item, amount) then
successes += 1
if successes == itemCount then
return true, name
end
end
end end
end end
else else
@@ -152,7 +144,7 @@ function openStash(data)
exports[OrigenInv]:openInventory('stash', data.stash, { label = data.label }) exports[OrigenInv]:openInventory('stash', data.stash, { label = data.label })
elseif isStarted(TgiannInv) then elseif isStarted(TgiannInv) then
TriggerServerEvent(getScript()..':server:OpenStashTgiann', { TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash, stashName = data.stash,
label = data.label, label = data.label,
maxweight = data.maxWeight or 600000, maxweight = data.maxWeight or 600000,
@@ -161,7 +153,7 @@ function openStash(data)
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
TriggerServerEvent(getScript()..':server:OpenStashQB', { TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash, stashName = data.stash,
label = data.label, label = data.label,
maxweight = data.maxWeight or 600000, maxweight = data.maxWeight or 600000,
@@ -172,8 +164,21 @@ function openStash(data)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions) TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions)
end end
elseif isStarted(PSInv) then
if QBInvNew then
TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash,
label = data.label,
maxweight = data.maxWeight or 600000,
slots = data.slots or 40
})
else
TriggerEvent("inventory:client:SetCurrentStash", data.stash)
TriggerServerEvent("ps-inventory:server:OpenInventory", "stash", data.stash, data.stashOptions)
end
elseif isStarted(RSGInv) then elseif isStarted(RSGInv) then
TriggerServerEvent(getScript()..':server:OpenStashRSG', { TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash, stashName = data.stash,
label = data.label, label = data.label,
maxweight = data.maxWeight or 600000, maxweight = data.maxWeight or 600000,
@@ -189,16 +194,23 @@ function openStash(data)
lookEnt(data.coords) lookEnt(data.coords)
end end
RegisterNetEvent(getScript()..':server:OpenStashTgiann', function(data)
exports[TgiannInv]:OpenInventory(source, 'stash', data.stashName, data)
end)
RegisterNetEvent(getScript()..':server:OpenStashQB', function(data) -- Wrapper function for opening stash from the server.
exports[QBInv]:OpenInventory(source, data.stashName, data) -- Messy but not much else I can do about it.
end) RegisterNetEvent(getScript()..":server:openServerStash", function(data)
local src = source
RegisterNetEvent(getScript()..':server:OpenStashRSG', function(data) if isStarted(TgiannInv) then
exports[RSGInv]:OpenInventory(source, data.stashName, data) exports[TgiannInv]:OpenInventory(source, 'stash', data.stashName, data)
end
if isStarted(QBInv) then
exports[QBInv]:OpenInventory(source, data.stashName, data)
end
if isStarted(PSInv) then
exports[PSInv]:OpenInventory(source, data.stashName, data)
end
if isStarted(RSGInv) then
exports[RSGInv]:OpenInventory(source, data.stashName, data)
end
end) end)
@@ -258,8 +270,13 @@ function getStash(stashName)
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
stashResource = QBInv stashResource = QBInv
local result = MySQL.scalar.await("SELECT items FROM "..(QBInvNew and "inventories" or "stashitem").." WHERE identifier = ?", { stashName }) if QBInvNew then
if result then stashItems = json.decode(result) end local result = exports[QBInv]:GetInventory(stashName) or {}
stashItems = result.items or {}
else
local result = MySQL.scalar.await("SELECT items FROM stashitems WHERE stash = ?", { stashName })
if result then stashItems = json.decode(result) end
end
elseif isStarted(RSGInv) then elseif isStarted(RSGInv) then
stashResource = RSGInv stashResource = RSGInv
@@ -338,7 +355,7 @@ function stashRemoveItem(stashItems, stashName, items)
debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v) debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
stashItems[l] = nil stashItems[l] = nil
else else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QSInv, k, v)
exports[QSInv]:RemoveItemIntoStash(stashName[1], k, v, l) exports[QSInv]:RemoveItemIntoStash(stashName[1], k, v, l)
end end
end end
@@ -381,26 +398,6 @@ function stashRemoveItem(stashItems, stashName, items)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..TgiannInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..TgiannInv, k, v)
end end
elseif isStarted(PSInv) then
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
debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
stashItems[l] = nil
else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
stashItems[l].amount -= v
end
end
end
end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'")
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashName,
['items'] = json.encode(stashItems)
})
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
for k, v in pairs(items) do for k, v in pairs(items) do
@@ -433,6 +430,27 @@ function stashRemoveItem(stashItems, stashName, items)
}) })
end end
elseif isStarted(PSInv) then
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
debugPrint("^6Bridge^7: ^2None of this item left in stash ^3Stash^7", k, v)
stashItems[l] = nil
else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..PSInv, k, v)
stashItems[l].amount -= v
end
end
end
end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName.."^7'")
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashName,
['items'] = json.encode(stashItems)
})
elseif isStarted(RSGInv) then elseif isStarted(RSGInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
exports[RSGInv]:RemoveItem(stashName[1], k, v, false, 'crafting') exports[RSGInv]:RemoveItem(stashName[1], k, v, false, 'crafting')
@@ -498,3 +516,75 @@ function stashhasItem(stashItems, items, amount)
return true, hasTable return true, hasTable
end end
--- Registers a stash with the active inventory system.
--- Supports either OXInv or QSInv.
---
--- @param name string Unique stash identifier.
--- @param label string Display name for the stash.
--- @param slots number|nil (Optional) Number of slots (default 50).
--- @param weight number|nil (Optional) Maximum weight (default 4000000).
--- @param owner string|nil (Optional) Owner identifier for personal stashes.
--- @param coords table|nil (Optional) Coordinates for the stash location.
--- @usage
--- ```lua
--- registerStash(
--- "playerStash",
--- "Player Stash",
--- 100,
--- 8000000,
--- "player123",
--- { x = 100.0, y = 200.0, z = 30.0 }
--- )
--- ```
function registerStash(name, label, slots, weight, owner, coords)
if isStarted(OXInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Stash^7:", name, label, owner or nil)
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
elseif isStarted(QSInv) then
debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label)
exports[QSInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
--elseif isStarted(CoreInv) then
-- debugPrint("^6Bridge^7: ^2Registering ^3CoreInv ^2Stash^7:", name, label)
-- exports[CoreInv]:openHolder(nil, name, 'stash', nil, nil, false, nil)
elseif isStarted(OrigenInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OrigenInv ^2Stash^7:", name, label)
exports["origen_inventory"]:registerStash(name, label, slots or 50, weight or 4000000)
elseif isStarted(TgiannInv) then
debugPrint("^6Bridge^7: ^2Registering ^3TgiannInv ^2Stash^7:", name, label)
exports[TgiannInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
end
end
if isServer() then
--- Registers an event to create an OX stash from the server.
--- When triggered, it calls registerStash with the provided parameters.
---
--- @event server:makeOXStash
--- @param name string Unique stash identifier.
--- @param label string Display name for the stash.
--- @param slots number|nil (Optional) Number of slots.
--- @param weight number|nil (Optional) Maximum weight.
--- @param owner string|nil (Optional) Owner identifier.
--- @param coords table|nil (Optional) Stash coordinates.
--- @usage
--- ```lua
--- TriggerEvent(getScript()..":server:makeOXStash", name, label, slots, weight, owner, coords, token)
--- ```
RegisterNetEvent(getScript()..":server:makeOXStash", function(name, label, slots, weight, owner, coords, token)
local src = source or nil
if src then
if not checkToken(src, token, "stash", name) then
return
end
end
registerStash(name, label, slots, weight, owner, coords)
end)
end

View File

@@ -42,80 +42,3 @@ function registerCommand(command, options)
end end
end end
--- Registers a stash with the active inventory system.
--- Supports either OXInv or QSInv.
---
--- @param name string Unique stash identifier.
--- @param label string Display name for the stash.
--- @param slots number|nil (Optional) Number of slots (default 50).
--- @param weight number|nil (Optional) Maximum weight (default 4000000).
--- @param owner string|nil (Optional) Owner identifier for personal stashes.
--- @param coords table|nil (Optional) Coordinates for the stash location.
--- @usage
--- ```lua
--- registerStash(
--- "playerStash",
--- "Player Stash",
--- 100,
--- 8000000,
--- "player123",
--- { x = 100.0, y = 200.0, z = 30.0 }
--- )
--- ```
function registerStash(name, label, slots, weight, owner, coords)
if isStarted(OXInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OX ^2Stash^7:", name, label, owner or nil)
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
elseif isStarted(QSInv) then
debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label)
exports[QSInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
--elseif isStarted(CoreInv) then
-- debugPrint("^6Bridge^7: ^2Registering ^3CoreInv ^2Stash^7:", name, label)
-- exports[CoreInv]:openHolder(nil, name, 'stash', nil, nil, false, nil)
elseif isStarted(OrigenInv) then
debugPrint("^6Bridge^7: ^2Registering ^3OrigenInv ^2Stash^7:", name, label)
exports["origen_inventory"]:registerStash(name, label, slots or 50, weight or 4000000)
elseif isStarted(TgiannInv) then
debugPrint("^6Bridge^7: ^2Registering ^3TgiannInv ^2Stash^7:", name, label)
exports[TgiannInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
end
end
if isServer() then
--- Registers an event to create an OX stash from the server.
--- When triggered, it calls registerStash with the provided parameters.
---
--- @event server:makeOXStash
--- @param name string Unique stash identifier.
--- @param label string Display name for the stash.
--- @param slots number|nil (Optional) Number of slots.
--- @param weight number|nil (Optional) Maximum weight.
--- @param owner string|nil (Optional) Owner identifier.
--- @param coords table|nil (Optional) Stash coordinates.
--- @usage
--- ```lua
--- TriggerEvent(getScript()..":server:makeOXStash", name, label, slots, weight, owner, coords, token)
--- ```
RegisterNetEvent(getScript()..":server:makeOXStash", function(name, label, slots, weight, owner, coords, token)
local src = source or nil
if src then
debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
if token == nil then
debugPrint("^1Auth^7: ^1Token not received^7")
elseif token ~= validTokens[src] then
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src])
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
end
end
registerStash(name, label, slots, weight, owner, coords)
end)
end

View File

@@ -47,10 +47,10 @@ if Config and Config.System then
end end
Config.System.Menu = GetConvar("jim_menuScript", Config.System.Menu) Config.System.Menu = GetConvar("jim_menuScript", Config.System.Menu)
Config.System.Notify = GetConvar("jim_notifyScript", Config.System.Notify) Config.System.Notify = GetConvar("jim_notifyScript", Config.System.Notify or "gta")
Config.System.ProgressBar = GetConvar("jim_progressBarScript", Config.System.ProgressBar) Config.System.ProgressBar = GetConvar("jim_progressBarScript", Config.System.ProgressBar or "gta")
Config.System.drawText = GetConvar("jim_drawTextScript", Config.System.drawText) Config.System.drawText = GetConvar("jim_drawTextScript", Config.System.drawText or "gta")
Config.System.skillCheck = GetConvar("jim_skillCheckScript", Config.System.skillCheck) Config.System.skillCheck = GetConvar("jim_skillCheckScript", Config.System.skillCheck or "gta")
if GetConvar("jim_dontUseTarget", "false") == "true" then if GetConvar("jim_dontUseTarget", "false") == "true" then
Config.System.DontUseTarget = true Config.System.DontUseTarget = true
@@ -58,23 +58,73 @@ if Config and Config.System then
end end
-- Testing loading the core files here instead of in fxmanifests -- Testing loading the core files here instead of in fxmanifests
-- Forcefully loads the files and quietly, compared to fxmanifest complaining if they don't exist -- Forcefully loads the files and quietly, compared to fxmanifest complaining if they don't exist when you don't need them all
-- This may be better button would require more refinement maybe
--[[ --[[
-- Shared framework file loader
for k, v in pairs({ -- This is a specific load order for k, v in pairs({ -- This is a specific load order
[Exports.OXLibExport] = "init.lua", [Exports.OXLibExport] = "init.lua",
[Exports.OXCoreExport] = "lib/init.lua", [Exports.OXCoreExport] = "lib/init.lua",
[Exports.ESXExport] = "imports.lua", [Exports.ESXExport] = "imports.lua",
[Exports.QBXExport] = "modules/playerdata.lua", [Exports.QBXExport] = "modules/playerdata.lua",
}) do }) do
if GetResourceState(k) == "started" then local state = GetResourceState(k)
print("^5Loading^7: '"..k.."/"..v.."' ^2into ^7'"..GetCurrentResourceName().."' ...") -- if the resource is started, load the file
local fileLoader = assert(load(LoadResourceFile(k, (v)), ('@@'..k..'/'..v))) if state == "started" then
fileLoader() if type(v) == "string" then
print("^2Success^7: ^2loaded ^1Core ^2file^7: ^3"..k.."^7/^3"..(v):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").."^7") v = { v }
else end
for _, file in pairs(v) do
--print("^5CoreLoader^7: '"..k.."/"..file.."' ^2into ^7'"..GetCurrentResourceName().."' ...")
local fileLoader = assert(load(LoadResourceFile(k, (file)), ('@@'..k..'/'..file)))
fileLoader()
print("^5CoreLoader^7: ^2loaded ^1Core ^2file^7: ^3"..k.."^7/^3"..(file):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").."^7")
end
end
-- if script is in server, but not started warn the user
if state == "uninitialized" or state == "stopped" then
print("^5CoreLoader^7: ^3"..k.." ^1 found but it wasn't started^7. ^1Check your ^3server^7.^3cfg ^1load order^7")
end
-- debugging only, if the script is missing, warn the user
if state == "missing" then
if debugMode then if debugMode then
print("^3Warning^7: ^3"..k.." ^2not found^7, ^2skipping") print("^5CoreLoader^7: ^3"..k.." ^2not found^7, ^2skipping")
end
end
end
-- Client only file loader
if not IsDuplicityVersion() then
for k, v in pairs({ -- This is a specific load order
["PolyZone"] = { "client.lua", "BoxZone.lua", "EntityZone.lua", "CircleZone.lua", "ComboZone.lua" },
["warmenu"] = { "warmenu.lua", },
}) do
local state = GetResourceState(k)
-- if the resource is started, load the file
if state == "started" then
if type(v) == "string" then
v = { v }
end
for _, file in pairs(v) do
--print("^5CoreLoader^7: '"..k.."/"..file.."' ^2into ^7'"..GetCurrentResourceName().."' ...")
local fileLoader = assert(load(LoadResourceFile(k, (file)), ('@@'..k..'/'..file)))
fileLoader()
print("^5CoreLoader^7: ^2loaded ^1Core ^2file^7: ^3"..k.."^7/^3"..(file):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").."^7")
end
end
-- if script is in server, but not started warn the user
if state == "uninitialized" or state == "stopped" then
print("^5CoreLoader^7: ^3"..k.." ^1 found but it wasn't started^7. ^1Check your ^3server^7.^3cfg ^1load order^7")
end
-- debugging only, if the script is missing, warn the user
if state == "missing" then
if debugMode then
print("^3Warning^7: ^3"..k.." ^2not found^7, ^2skipping")
end
end end
end end
end end

View File

@@ -1 +1 @@
2.0.05 2.0.07