Compare commits

...

70 Commits

Author SHA1 Message Date
Jim Shield
14c2a79673 Version Bump
`2.0.12` - `2.0.13`
2025-05-19 23:39:46 +01:00
Jim Shield
97a1d97678 add random number helper
This function was created to help create random numbers
When you create a table of items with a random hunger value for example
`hunger = math.random(10, 20)` this will be set at script start and never change
using `hunger = {10, 20}` and then calling this function will make it generate a random number every time
It also fallsback if it simply recieved a number instead of a table
-- For example:
-- local hunger = {10, 20}
-- local hungerAmount = GetRandomTiming(hunger)
-- print(hungerAmount) -- number between 10, 20
2025-05-19 19:53:52 +01:00
Jim Shield
5001642504 Update version.txt 2025-05-19 17:14:41 +01:00
Jim Shield
5f413a2823 Update version checkers to support mini changelogs 2025-05-19 17:10:14 +01:00
Jim Shield
4d04682b33 Version Bump
`2.0.11` - `2.0.12`
2025-05-18 22:34:08 +01:00
Jim Shield
cb38d275d1 People were asking how to remove a print
I kept getting people asking how to remove prints because it "was filling up their f8 menu and looked like errors"

So I've made the "success" coreloader prints to be debugmode only.
2025-05-18 16:32:29 +01:00
Jim Shield
84cfe1c97d Fix stash stash opening for some inventories
Mainly older inventories may have had issues with custom stash sizes when opening them

This should fix compatibility with changing slots and max weight with them on trigger
2025-05-18 16:31:30 +01:00
Jim Shield
47b01df621 Remove coords from openGrabBox 2025-05-17 20:38:21 +01:00
Jim Shield
7e073b16ec Update starter.lua 2025-05-17 20:23:32 +01:00
Jim Shield
ab4298fa2d Change coreloader prints to a debugPrint 2025-05-17 19:19:15 +01:00
Jim Shield
7997ea45b7 change "Shared Load Detected" to a debugPrint 2025-05-17 19:16:24 +01:00
Jim Shield
7aa9d90d0d Improve ESX Job cache builder
When collecting Jobs from the server it tries it's best to determine which role is the "Boss"

It checks first of the Job Grade label containing the word "Boss"

If it can't find it, it then uses the highest number grade and adds `.isBoss = true` to it
2025-05-17 16:48:23 +01:00
Jim Shield
520758b355 Version Bump
`2.0.10` - `2.0.11`
2025-05-15 20:20:47 +01:00
Jim Shield
e4e9ef0fb2 add openGrabBox event for items like murderbag 2025-05-15 20:02:39 +01:00
Jim Shield
ada724069b Revert qs-inv server inv grab
Found the real issue that was causing the scripts to not think you had items, basically reverting this change as i didn't like having it in the first place
2025-05-15 19:59:51 +01:00
Jim Shield
9198068a19 Adjust hasItem function for QS-Inv
Apparently qs-inv reports two variables on the item data for how you have
`count` and `amount`
while other inventories appear to only have one of those

I'm assuming for compatibility sake

Apparently the `count` is updated differently, and `hasItem()` was checking for this first

I've swapped round the checks and appears to work better
2025-05-15 19:55:14 +01:00
Jim Shield
263d5160aa Add delay for checking for inventory items on qb
Custom inventories apparently load items separately/later into qbshared

so the script starts thinking there is definitely 0 items but its checking too early, this forces it to wait until its available to continue
2025-05-15 15:31:41 +01:00
Jim Shield
65137207ae add fallback for hasItem if no inventory is found 2025-05-14 23:38:34 +01:00
Jim Shield
3bd9935346 Skip item for sellmenu if item isn't in shared
Adds an item check before creating the sellmenu as to avoid errors
2025-05-14 23:36:46 +01:00
Jim Shield
23e2488cd1 fix typo for qs-inv callback for inventory 2025-05-14 16:09:02 +01:00
Jim Shield
e9bbdd4ce0 Version Bump
`2.0.09` - `2.0.10`
2025-05-13 22:02:37 +01:00
Jim Shield
f5a7ec9291 fix inventory exploit trigger blocking crafting
The inventory exploit check when crafting never released crafting so you couldn't craft again until reconnecting or script restart
2025-05-13 21:57:19 +01:00
Jim Shield
d80ea38a39 Fix sell menu throwing errors on openning
It was checking the wrong table name for amounts and getting `nil`
2025-05-13 21:56:18 +01:00
Jim Shield
e64912622b Testing a fix with QS-INV item checks
So..from what I can gather, QS-Inv doesn't seem to be updating the client cache of the players inventory correctly

This is all speculation, I can't check this myself

When `hasItem()` is used, its essentially reading from the client's cache.
This seemingly is only updated when there is a new item in a slot, **not** when the amount of an item in that slot changes

The only way to circumvent this is a workaround to the players inventory from the server side using a callback. This is painful to do because it can increase server load when checking multiples of items
2025-05-13 17:57:27 +01:00
Jim Shield
04b25e2c06 create waitForSharedLoad() function
This my attempt to aid ESX loading, essentially my scripts server side now need to be locked behind `onResourceStart()` because of ESX

Loading ESX into my scripts was delaying half of it and breaking the other half

This function forcibly waits until everythings loaded and then continues

This shouldn't affect other frameworks loading ability

My tests so far have been a success with it
2025-05-12 22:59:31 +01:00
Jim Shield
51473bf0b8 Version Bump
`2.0.08` - `2.0.09`
2025-05-12 13:52:14 +01:00
Jim Shield
921b973f81 Try and fix ESX loading
So information and request for help.

The issue here is that my scripts require Job and Vehicle information when the script starts, to do a debug check if the job exists for the location.

ESX doesn't share this with the client for some reason, so this requires me to request it from the server side at script ensure.

This is causing issues because it delays loading of the rest of `jim_bridge` while it slowly requests `ESX.GetJobs()` table from server side

This is delayed even more when the script is placed towards the top of the server load order and it needs to load other things like MLO's

As its trying to load this the rest of the script carries on loading with missing information.

So it loads the script thinking there are 0 jobs and breaks it.

If anyone knows of a better way of doing this then please help.
The only partial solution is to start my scripts last in the server load order
2025-05-12 13:51:32 +01:00
Jim Shield
42d08ccf4c Tidy up the stashRemoveItem function 2025-05-12 13:44:37 +01:00
Jim Shield
68412d8006 Enforce numbers when changing stats
if the value ends up being `nil` this *should* force it to 0

Also added a check for if it can actually give `randomReward` before trying to
2025-05-11 14:16:02 +01:00
Jim Shield
4c89ec3190 Version Bump
`2.0.07` - `2.0.08`
2025-05-10 19:55:51 +01:00
Jim Shield
b2fa1ef247 Update starter.lua
Updated and putting into use the core file loader function in starter.lua
2025-05-10 19:54:31 +01:00
Jim Shield
9872c77591 Only allow script version checks for my scripts
Added a check to version check for if "Jimathy" is the author, this then stops it and doesn't check for the versions on my github repositories
2025-05-10 19:20:47 +01:00
Jim Shield
7ecb2f18e9 Refactor ESX Core loading
I realised I was loading ESX the stupidest way

I think I was loading ESX object, then instantly clearing it and then used workarounds to try and reload it (thinking is hard ok)

It should now load correctly and faster

also I realised my custom `onPlayerLoaded()` function was loading too fast, so I've added a delay to it but removed the while loops for esx checks that could potentially break the script
2025-05-07 23:01:29 +01:00
Jim Shield
d0c09f3e00 switch old ps-inv stash call back to old event
older ps didn't call `ps-inventory` for stash, just `inventory`
2025-05-07 21:12:38 +01:00
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
Jim Shield
f9b97b7505 Version bump 2.0.05 2025-05-04 16:24:55 +01:00
Jim Shield
489da64c5e add a new warning for token auth 2025-05-04 15:40:20 +01:00
Jim Shield
07c35cd917 workaround for ox_inventory returning a bool
I think, if ox_inventory checks a stash that doesn't exist yet, it returns a boolean or `nil`

This checks for that and instead returns a table to hopefully stop the scripts from breaking
2025-05-04 15:21:02 +01:00
Jim Shield
3f72a21d75 Update bigMessageInstance.lua 2025-05-03 20:28:13 +01:00
Jim Shield
4ad6170a49 Fix ox_target items variable
Completely overlooked that ox_target item variable is `items` not `item`

changes
```lua
                item = opts[i].item or nil,
```
to:
```lua
                items = opts[i].item or nil,
```
2025-05-03 00:11:28 +01:00
Jim Shield
18df0817b1 Make version checks a bit more obvious
Adds more obvious prints if the current version is outdated

(and also repeats it every 20 minutes)
2025-05-02 22:22:47 +01:00
Jim Shield
0eca7ae29e Fix CodeM item slot check for metadata function
The slot data for CodeM apparently returns as a string, this fixes it trying to compare a string to a number

```lua
            if v.name == item and v.slot <= lowestSlot then
```
to
```lua
            if v.name == item and tonumber(v.slot) <= lowestSlot then
```
2025-05-02 22:20:26 +01:00
Jim Shield
6a5913230f Add better fallbacks for if no metadata table is found
```lua
                durability = v.info.durability
```
to:
```lua
                durability = v.info and v.info.durability or nil
```
2025-05-02 22:16:51 +01:00
Jim Shield
b7a284e051 Fix new duty sync
This should have been placed in a `onPlayerLoaded()` but it was checking at script start for player info before that info was able to be grabbed
2025-05-02 12:29:02 +01:00
Jim Shield
0accdda2dd version bump
`2.0.04`
2025-05-02 11:36:54 +01:00
Jim Shield
37b855d7a7 Better syncing of onDuty variable
Added a check to the script start to get the current players duty (helpful if yours saves the duty through restarts)

Also added core specific triggers for job/duty changes to help keep these in sync
2025-05-02 11:20:09 +01:00
Jim Shield
7432dd5118 revert qbinv dectetion
Wasn't playing as well as I thought it would..
2025-05-01 20:05:00 +01:00
Jim Shield
59ff34c9cc Add exploit protection for :Crafting:GetItem
I unfortunately forgot to add this before when adding the extra exploit protection. Now demands an auth token before allowing crafting results to help reduce exploiters calling it externally
2025-05-01 18:07:39 +01:00
Jim Shield
b81ada265b Better support for RedM's RSG Core
Nothing public uses this yet, but its very similar to QBCore which makes it very for me to support

Nothing special to note, just improves the integration for future ventures into RedM
2025-05-01 17:49:37 +01:00
Jim Shield
65c9c6c586 Add automated check for QBInv version
Currently if you still have the old qb-inventory or a css edit it would require you to manually edit the starter.lua
```lua
QBInvNew = true
```

I'm testing a change to grab the version and return true of false if its above `2.0.0` (200)
```lua
local qbInvVer = GetResourceMetadata(Exports.QBInv, 'version', nil):gsub("%.", "")
QBInvNew = tonumber(qbInvVer) >= 200
```
If this causes issue's I'll revert this
2025-05-01 17:08:21 +01:00
Jim Shield
278cbb4d34 fix discord bot yml 2025-05-01 13:36:44 +01:00
Jim Shield
381c19e701 add gitbot yml 2025-05-01 00:20:35 +01:00
Jim Shield
fc2ebefc9e fix CodeM server side inventory info grab 2025-04-30 17:54:04 +01:00
Jim Shield
423b75e7d9 Tgiann Inv support added 2025-04-30 17:53:26 +01:00
23 changed files with 1053 additions and 448 deletions

17
.github/workflows/notify-discord.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Discord Commit Notifier
on:
push:
branches:
- '*' # triggers on all branches
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

View File

@@ -1,4 +1,4 @@
function parseVersion(version)
local function parseVersion(version)
local parts = {}
for num in version:gmatch("%d+") do
table.insert(parts, tonumber(num))
@@ -6,7 +6,7 @@ function parseVersion(version)
return parts
end
function compareVersions(current, newest)
local function compareVersions(current, newest)
local currentParts = parseVersion(current)
local newestParts = parseVersion(newest)
for i = 1, math.max(#currentParts, #newestParts) do
@@ -20,28 +20,48 @@ end
function CheckBridgeVersion()
if IsDuplicityVersion() then
CreateThread(function()
Wait(4000)
local currentVersionRaw = GetResourceMetadata("jim_bridge", 'version')
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/jim_bridge/master/version.txt', function(err, newestVersionRaw, headers)
if not newestVersionRaw then
print("^1Unable to run version check for ^7'^3jim_bridge^7' (^3"..currentVersionRaw.."^7)")
return
end
CreateThread(function()
Wait(4000)
local currentVersionRaw = GetResourceMetadata("jim_bridge", 'version')
--PerformHttpRequest('https://raw.githubusercontent.com/jimathy/UpdateVersions/master/test.txt', function(err, body, headers)
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/jim_bridge/master/version.txt', function(err, body, headers)
if not body then
print("^1Unable to run version check for ^7'^3jim_bridge^7' (^3"..currentVersionRaw.."^7)")
return
end
newestVersionRaw = newestVersionRaw:match("[^\r\n]+")
local compareResult = compareVersions(currentVersionRaw, newestVersionRaw)
local lines = {}
for line in body:gmatch("[^\r\n]+") do
table.insert(lines, line)
end
if compareResult == 0 then
print("^7'^3jim_bridge^7' - ^2You are running the latest version^7. ^7(^3"..currentVersionRaw.."^7)")
elseif compareResult < 0 then
print("^7'^3jim_bridge^7' - ^1You are running an outdated version^7! ^7(^3"..currentVersionRaw.."^7 → ^3"..newestVersionRaw.."^7)")
else
print("^7'^3jim_bridge^7' - ^5You are running a newer version ^7(^3"..currentVersionRaw.."^7 ← ^3"..newestVersionRaw.."^7)")
end
end)
end)
end
local newestVersionRaw = lines[1] or "0.0.0"
local changelog = {}
for i = 2, #lines do
table.insert(changelog, lines[i])
end
local compareResult = compareVersions(currentVersionRaw, newestVersionRaw)
if compareResult == 0 then
print("^7'^3jim_bridge^7' - ^2You are running the latest version^7. ^7(^3"..currentVersionRaw.."^7)")
elseif compareResult < 0 then
print("^1----------------------------------------------------------------------^7")
print("^7'^3jim_bridge^7' - ^1You are running an outdated version^7! ^7(^3"..currentVersionRaw.."^7 → ^3"..newestVersionRaw.."^7)")
for _, line in ipairs(changelog) do
print((line:find("http") and "^7" or "^5")..line)
end
print("^1----------------------------------------------------------------------^7")
SetTimeout(1200000, function()
CheckBridgeVersion()
end)
else
print("^7'^3jim_bridge^7' - ^5You are running a newer version ^7(^3"..currentVersionRaw.."^7 ← ^3"..newestVersionRaw.."^7)")
end
end)
end)
end
end
CheckBridgeVersion()

View File

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

@@ -40,6 +40,7 @@ function onPlayerLoaded(func, onStart)
if not loaded then
local tempFunc = function()
Wait(2000)
debugPrint("^6Bridge^7: ^2Executing onPlayerLoaded")
func()
end
@@ -49,7 +50,13 @@ function onPlayerLoaded(func, onStart)
AddEventHandler('QBCore:Client:OnPlayerLoaded', tempFunc)
elseif isStarted(ESXExport) then
onPlayerFramework = ESXExport
AddEventHandler('esx:playerLoaded', tempFunc)
AddEventHandler('esx:playerLoaded', function()
if waitForSharedLoad() then
if isStarted(ESXExport) then Wait(11000) end
tempFunc()
end
end
)
elseif isStarted(OXCoreExport) then
onPlayerFramework = OXCoreExport
AddEventHandler('ox:playerLoaded', tempFunc)
@@ -99,10 +106,14 @@ end
--- end, true)
--- ```
function onResourceStart(func, thisScript)
debugPrint("^6Bridge^7: Registering ^3onResourceStart^7()")
debugPrint("^6Bridge^7: ^2Registering ^3onResourceStart^7()")
AddEventHandler('onResourceStart', function(resourceName)
if getScript() == resourceName and (thisScript or true) then
func()
if waitForSharedLoad() then
debugPrint("^6Bridge^7: ^2Shared Load Detected^7.")
if isStarted(ESXExport) then Wait(10000) end
func()
end
end
end)
end
@@ -138,9 +149,7 @@ function waitForLogin()
local loggedIn = false
if isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^3ESX waitForLogin^7() ^2running^7")
while (GetGameTimer() - startTime) < timeout do
while not ESX do Wait(100) end
local playerData = ESX.GetPlayerData()
if playerData and playerData.job then
loggedIn = true
@@ -175,4 +184,26 @@ function waitForLogin()
debugPrint("^6Bridge^7: ^2Player Login Detected^7.")
return true
end
end
function waitForSharedLoad()
local timeout = 100000 -- 10 seconds in milliseconds
local startTime = GetGameTimer()
local loaded = true
while ((not Jobs or not next(Jobs)) and (not Items or not next(Items)) and (not Vehicles or not next(Vehicles))) and (GetGameTimer() - startTime) < timeout do
print((GetGameTimer() - startTime) < timeout)
Wait(1000)
debugPrint("Waiting for Jobs, Items, and Vehicles to be loaded")
if Jobs and Items and Vehicles then
print("^6Bridge^7: ^2Jobs, Items, and Vehicles Loaded^7.")
loaded = true
break
end
end
if not loaded then
print("^4Error^7: ^2Timeout reached while waiting for shared load^7.")
return false
else
return true
end
end

View File

@@ -15,7 +15,7 @@ function compareVersions(current, newest)
if c < n then return -1
elseif c > n then return 1 end
end
return 0 -- equal
return 0
end
function capitalize(str)
@@ -30,42 +30,66 @@ local scriptAuthor = ("^2by ^4"..GetResourceMetadata(getScript(), 'author', nil)
print(scriptName.." ^7v"..scriptVersion.."^7 - "..scriptDescription.." "..scriptAuthor.."^7")
function CheckVersion()
if isServer() then
if isServer() and GetResourceMetadata(getScript(), 'author', nil) == "Jimathy" then
CreateThread(function()
Wait(4000)
local script = getScript()
local currentVersionRaw = GetResourceMetadata(script, 'version')
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/UpdateVersions/master/'..script..'.txt', function(err, newestVersionRaw, headers)
if not newestVersionRaw then
-- fallback
PerformHttpRequest('https://raw.githubusercontent.com/jimathy/'..script..'/master/version.txt', function(err, fallbackVersionRaw, headers)
if not fallbackVersionRaw then
print("^1Currently unable to run a version check for ^7'^3"..script.."^7' (^3"..currentVersionRaw.."^7)")
return
end
fallbackVersionRaw = fallbackVersionRaw:match("[^\r\n]+"):gsub("v", "")
local lines = {}
for line in fallbackVersionRaw:gmatch("[^\r\n]+") do table.insert(lines, line) end
local fallbackVersion = (lines[1] or "0.0.0"):gsub("v", "")
local changelog = {}
for i = 2, #lines do table.insert(changelog, lines[i]) end
local compareResult = compareVersions(currentVersionRaw, fallbackVersionRaw)
local compareResult = compareVersions(currentVersionRaw, fallbackVersion)
if compareResult == 0 then
print("^7'^3"..script.."^7' - ^2You are running the latest version^7. (^3"..currentVersionRaw.."^7)")
elseif compareResult < 0 then
print("^7'^3"..script.."^7' - ^1You are currently running an outdated version^7! (^3"..currentVersionRaw.."^7 → ^3"..fallbackVersionRaw.."^7)")
print("^1----------------------------------------------------------------------^7")
print("^7'^3"..script.."^7' - ^1You are currently running an outdated version^7! (^3"..currentVersionRaw.."^7 → ^3"..fallbackVersion.."^7)")
if #changelog > 0 then
for _, line in ipairs(changelog) do
print((line:find("http") and "^7" or "^5")..line)
end
end
print("^1----------------------------------------------------------------------^7")
SetTimeout(1200000, function() CheckVersion() end)
else
print("^7'^3"..script.."^7' - ^5You are running a newer version ^7(^3"..currentVersionRaw.."^7 ← ^3"..fallbackVersionRaw.."^7)")
print("^7'^3"..script.."^7' - ^5You are running a newer version ^7(^3"..currentVersionRaw.."^7 ← ^3"..fallbackVersion.."^7)")
end
end)
else
newestVersionRaw = newestVersionRaw:match("[^\r\n]+"):gsub("v", "")
local lines = {}
for line in newestVersionRaw:gmatch("[^\r\n]+") do table.insert(lines, line) end
local newestVersion = (lines[1] or "0.0.0"):gsub("v", "")
local changelog = {}
for i = 2, #lines do table.insert(changelog, lines[i]) end
local compareResult = compareVersions(currentVersionRaw, newestVersionRaw)
if compareResult == 0 then
local compareResult = compareVersions(currentVersionRaw, newestVersion)
if compareResult == 0 then
print("^7'^3"..script.."^7' - ^2You are running the latest version^7. (^3"..currentVersionRaw.."^7)")
elseif compareResult < 0 then
print("^7'^3"..script.."^7' - ^1You are currently running an outdated version^7! (^3"..currentVersionRaw.."^7 → ^3"..newestVersionRaw.."^7)")
print("^1----------------------------------------------------------------------^7")
print("^7'^3"..script.."^7' - ^1You are currently running an outdated version^7! (^3"..currentVersionRaw.."^7 → ^3"..newestVersion.."^7)")
if #changelog > 0 then
for _, line in ipairs(changelog) do
print((line:find("http") and "^7" or "^5")..line)
end
end
print("^1----------------------------------------------------------------------^7")
SetTimeout(1200000, function() CheckVersion() end)
else
print("^7'^3"..script.."^7' - ^5You are running a newer version ^7(^3"..currentVersionRaw.."^7 ← ^3"..newestVersionRaw.."^7)")
print("^7'^3"..script.."^7' - ^5You are running a newer version ^7(^3"..currentVersionRaw.."^7 ← ^3"..newestVersion.."^7)")
end
end
end)
@@ -73,4 +97,4 @@ function CheckVersion()
end
end
CheckVersion()
CheckVersion()

View File

@@ -9,13 +9,13 @@
-------------------------------------------------------------
-- Global Variable Initialization
-------------------------------------------------------------
Items, Vehicles, Jobs, Gangs, Core, ESX = {}, nil, nil, nil, nil, nil
Items, Vehicles, Jobs, Gangs, Core = {}, nil, nil, nil, nil
-------------------------------------------------------------
-- Correct QB Inventory Export
-------------------------------------------------------------
-- Ensure that the QB inventory export is corrected from 'qb-inventory' to 'ps-inventory' or 'lj-inventory' if needed.
Exports.QBInv = (isStarted("ps-inventory") and "ps-inventory") or (isStarted("lj-inventory") and "lj-inventory") or Exports.QBInv
-- Correct ps-invetory to ls-inventory if somehow you still have that
Exports.PSInv = isStarted("lj-inventory") and "lj-inventory" or Exports.PSInv
-------------------------------------------------------------
-- Framework Exports and Inventory Identifiers
@@ -27,14 +27,15 @@ OXLibExport, QBXExport, QBExport, ESXExport, OXCoreExport =
Exports.ESXExport or "",
Exports.OXCoreExport or ""
OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv =
OXInv, QBInv, PSInv, QSInv, CoreInv, CodeMInv, OrigenInv, TgiannInv =
Exports.OXInv or "",
Exports.QBInv or "",
Exports.PSInv or "",
Exports.QSInv or "",
Exports.CoreInv or "",
Exports.CodeMInv or "",
Exports.OrigenInv or ""
Exports.OrigenInv or "",
Exports.TgiannInv or ""
RSGExport, RSGInv =
Exports.RSGExport or "",
@@ -86,6 +87,12 @@ elseif isStarted(QBExport) then
itemResource = QBExport
Core = Core or exports[QBExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
CreateThread(function()
while not Items or not next(Items) do
Items = exports[QBExport]:GetCoreObject().Shared.Items
Wait(1000)
end
end)
if isStarted(QBExport) and not isStarted(QBXExport) then
RegisterNetEvent('QBCore:Client:UpdateObject', function()
Core = Core or exports[QBExport]:GetCoreObject()
@@ -95,13 +102,7 @@ elseif isStarted(QBExport) then
elseif isStarted(ESXExport) then
itemResource = ESXExport
ESX = exports[ESXExport]:getSharedObject()
while ESX == nil do
print("Waiting for ESX")
Wait(0)
end
CreateThread(function()
while not ESX do Wait(0) end
if isServer() then
Items = ESX.GetItems()
while not createCallback do Wait(100) end
@@ -119,12 +120,10 @@ elseif isStarted(RSGExport) then
itemResource = RSGExport
Core = Core or exports[RSGExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
if isStarted(RSGExport) and not isStarted(QBXExport) then
RegisterNetEvent('QBCore:Client:UpdateObject', function()
Core = Core or exports[RSGExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
end)
end
RegisterNetEvent('RSGCore:Client:UpdateObject', function()
Core = Core or exports[RSGExport]:GetCoreObject()
Items = Core and Core.Shared.Items or nil
end)
end
@@ -141,6 +140,7 @@ end
-------------------------------------------------------------
-- Compile vehicles from the detected frameworks into a unified table.
if isStarted(QBXExport) or isStarted(QBExport) then
vehResource = QBExport
Core = Core or exports[QBExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
if isStarted(QBExport) and not isStarted(QBXExport) then
@@ -149,26 +149,23 @@ if isStarted(QBXExport) or isStarted(QBExport) then
Vehicles = Core and Core.Shared.Vehicles
end)
end
vehResource = QBExport
elseif isStarted(OXCoreExport) then
vehResource = OXCoreExport
Vehicles = {}
for k, v in pairs(Ox.GetVehicleData()) do
Vehicles[k] = { model = k, hash = GetHashKey(k), price = v.price, name = v.name, brand = v.make }
end
vehResource = OXCoreExport
elseif isStarted(ESXExport) then
vehResource = ESXExport
CreateThread(function()
if isServer() then
vehResource = ESXExport
createCallback(getScript()..":getVehiclesPrices", function(source)
return Vehicles
end)
while not MySQL do Wait(2000) print("^1Waiting for MySQL to exist") end
Vehicles = MySQL.query.await('SELECT model, price, name FROM vehicles')
--jsonPrint(Vehicles)
--while not createCallback do print("waiting") Wait(100) end
end
if not isServer() then
--while not triggerCallback do print("waiting") Wait(100) end
@@ -187,23 +184,19 @@ elseif isStarted(ESXExport) then
end)
elseif isStarted(RSGExport) then
vehResource = RSGExport
Core = Core or exports[RSGExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
if isStarted(RSGExport) then
RegisterNetEvent('RSGExport:Client:UpdateObject', function()
Core = Core or exports[RSGExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
end)
end
vehResource = RSGExport
RegisterNetEvent('RSGCore:Client:UpdateObject', function()
Core = Core or exports[RSGExport]:GetCoreObject()
Vehicles = Core and Core.Shared.Vehicles
end)
end
if vehResource == nil then
print("^4ERROR^7: ^2No Vehicle info detected ^7- ^2Check ^3starter^1.^2lua^7")
else
CreateThread(function()
while not Vehicles do Wait(1000) print("Waiting") end
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..vehResource)
end)
while not Vehicles do Wait(1000) end
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Vehicles).." ^3Vehicles^2 from ^7"..vehResource)
end
-------------------------------------------------------------
@@ -249,44 +242,69 @@ elseif isStarted(QBExport) then
end
elseif isStarted(ESXExport) then
ESX = exports[ESXExport]:getSharedObject()
jobResource = ESXExport
if isServer() then
-- If server, create callback to get jobs
createCallback(getScript()..":getESXJobs", function(source)
return Jobs
end)
-- Populate jobs table with ESX.GetJobs()
Jobs = ESX.GetJobs()
for k, v in pairs(Jobs) do
local count = countTable(Jobs[k].grades) - 1
Jobs[k].grades[tostring(count)].isBoss = true
--jsonPrint(Jobs)
--If retreived jobs is empty, wait for ESX to load
while countTable(Jobs) == 0 do
Jobs = ESX.GetJobs()
Wait(100)
end
-- Organise into a table the script can use
for Role, Grades in pairs(Jobs) do
-- Check for "Boss" in name of grades
for grade, info in pairs(Grades.grades) do
--print(grade)
--jsonPrint(info)
if info.label then
--print(info)
if info.label:find("boss") or info.label:find("Boss") then
--print("Found Boss label for:", Grades.label)
Jobs[Role].grades[grade].isBoss = true
goto continue
end
end
end
-- If no roles with "boss" in the name, revert to max grade
-- Count grades
local count = countTable(Grades.grades)
Jobs[Role].grades[tostring(count-1)].isBoss = true
--print(Grades.label.." Grade: "..count.." is Boss")
::continue::
end
-- ESX Default doesn't have gangs, so copy jobs to gangs
Gangs = Jobs
end
-- If client side, trigger callback to get jobs
if not isServer() then
Jobs = triggerCallback(getScript()..":getESXJobs")
Gangs = Jobs
end
CreateThread(function()
while not ESX do Wait(0) end
if isServer() then
createCallback(getScript()..":getJobs", function(source)
return Jobs
end)
end
if not isServer() then
Jobs = triggerCallback(getScript()..":getJobs")
Gangs = Jobs
end
end)
elseif isStarted(RSGExport) then
jobResource = RSGExport
Core = Core or exports[RSGExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
if isStarted(RSGExport) and not isStarted(QBXExport) then
RegisterNetEvent('QBCore:Client:UpdateObject', function()
Core = exports[RSGExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
end)
end
RegisterNetEvent('RSGCore:Client:UpdateObject', function()
Core = exports[RSGExport]:GetCoreObject()
Jobs, Gangs = Core.Shared.Jobs, Core.Shared.Gangs
end)
end
if jobResource == nil then
print("^4ERROR^7: ^2No Vehicle info detected ^7- ^2Check ^3starter^1.^2lua^7")
else
while not Jobs do Wait(100) end
while not Jobs do Wait(1000) end
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Jobs).." ^3Jobs^2 from ^7"..jobResource)
debugPrint("^6Bridge^7: ^2Loading ^6"..countTable(Gangs).." ^3Gangs^2 from ^7"..jobResource)
end

View File

@@ -80,11 +80,6 @@ function craftingMenu(data)
-- Build a table of all required ingredients (default quantity is 1).
for i = 1, #Recipes 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
tempCarryTable[k] = Recipes[i].amount or 1
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 "")
metaTable[Items[l] and Items[l].label or "error - "..l] = b
itemTable[l] = b
Wait(0)
--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))
..(Recipes[i]["amount"] > 1 and " x"..Recipes[i]["amount"] or "")
if not disable then
if not canCarryTable[k] then
setheader = setheader.." 📦"
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
local statusEmoji = disable and "" or not canCarryTable[k] and " 📦" or " ✔️"
local isNew = (Recipes[i]["hasCrafted"] ~= nil and craftedItems[k] == nil) and "" or ""
setheader = isNew .. setheader .. statusEmoji
Menu[#Menu + 1] = {
arrow = not disable and canCarryTable[k],
isMenuHeader = disable or not canCarryTable[k],
icon = 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,
metadata = metaTable,
onSelect = (not disable and canCarryTable[k]) and function()
@@ -162,7 +148,7 @@ function craftingMenu(data)
}
end
end
Wait(0)
--Wait(0)
end
end
@@ -208,16 +194,23 @@ end
function multiCraft(data)
local max = 0
local stashName = nil
for i = 1, 100 do
local itemTable = {}
for l, b in pairs(data.craft[data.item]) do
debugPrint("")
itemTable[l] = (b * i)
end
local maxCreation = 100
-- 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
debugPrint("")
local hasItems, stashname = checkStashItem(data.stashName, itemTable)
local hasItems, stashname = checkStashItem(data.stashName, multiItemTable[i])
if hasItems == true then
max += 1
stashName = stashname
@@ -225,31 +218,34 @@ function multiCraft(data)
break
end
else
debugPrint("")
local has, _ = hasItem(itemTable, nil, nil)
-- if not check the players inventory for the items
local has, _ = hasItem(multiItemTable[i], nil, nil)
if has then
max += 1
else
break
end
end
Wait(10)
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 {
type = "slider",
label = "How many to craft?",
label = "How many to craft? "..br.."Max: "..carryMax,
required = true,
default = 1,
min = 1,
max = max
max = carryMax
}) or nil,
((Config.System.Menu == "qb") and {
type = "number",
label = "How many to craft?"..br.."Max: "..max,
name = "amount",
isRecuired = true,
isRequired = true,
default = 1,
}) or nil,
})
@@ -259,14 +255,14 @@ function multiCraft(data)
end
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")
craftingMenu(data)
return
end
end
makeItem({
item = data.item,
craft = data.craft,
@@ -274,7 +270,6 @@ function multiCraft(data)
amount = dialog["amount"] or dialog[1],
coords = data.coords,
stashName = stashName or nil,
--stashTable = data.stashName,
onBack = data.onBack,
metadata = data.metadata,
})
@@ -331,19 +326,23 @@ function makeItem(data)
local crafted, crafting = true, true
local cam = createTempCam(PlayerPedId(), data.coords)
startTempCam(cam)
for i = 1, craftAmount do
for k, v in pairs(data.craft) do
if not excludeKeys[k] then
if type(v) == "table" then
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({
label = "Using "..b.." "..Items[l].label,
time = 1000,
cancel = true,
dict = 'pickup_object',
anim = "putdown_low",
flag = 48,
flag = 49,
icon = l,
}) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[l], "use", b)
@@ -353,6 +352,11 @@ function makeItem(data)
end
Wait(200)
end
if isInventoryOpen() then
--print("^1Error^7: ^2Inventory is open, you tried to break things")
crafted, crafting, CraftLock = false, false, false
return
end
if crafted then
local craftProp = nil
if prop then
@@ -363,6 +367,12 @@ function makeItem(data)
local s = data.sound
PlaySoundFromEntity(s.soundId, s.audioName, PlayerPedId(), s.audioRef, true, 0)
end
if isInventoryOpen() then
--print("^1Error^7: ^2Inventory is open, you tried to break things")
crafted, crafting = false, false
crafted, crafting, CraftLock = false, false, false
return
end
if crafting and progressBar({
label = bartext..((metadata and metadata.label) or Items[data.item].label),
time = bartime,
@@ -371,8 +381,10 @@ function makeItem(data)
anim = anim,
flag = 49,
icon = data.item,
request = true,
}) then
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata)
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil -- clear client cached token
CreateThread(function()
if data.craft["hasCrafted"] ~= nil then
debugPrint("hasCrafted Found, marking '"..data.item.."' as crafted for player")
@@ -412,7 +424,6 @@ function makeItem(data)
end
stopTempCam()
CraftLock = false
lockInv(false)
if canReturn then craftingMenu(data) end
ClearPedTasks(PlayerPedId())
end
@@ -431,8 +442,19 @@ end
--- @param stashName string|table The stash name(s) to remove ingredients from.
--- @param metadata table (optional) Metadata for the crafted item.
--- @usage
RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable, stashName, metadata)
RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable, stashName, metadata, token)
local src = source
debugPrint(GetInvokingResource())
if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return
end
if not checkToken(src, token, "item", ItemMake) then
return
end
local hasItems, hasTable = hasItem(ItemMake, 1, src)
if stashName then
local itemRemove = {}
@@ -441,7 +463,9 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
stashItems = getStash(name)
for k, v in pairs(craftable[ItemMake] or {}) do
for _, b in pairs(stashItems or {}) do
if k == b.name then itemRemove[k] = v end
if k == b.name then
itemRemove[k] = v
end
end
end
end
@@ -449,7 +473,9 @@ RegisterNetEvent(getScript()..":Crafting:GetItem", function(ItemMake, craftable,
stashItems = getStash(stashName)
for k, v in pairs(craftable[ItemMake] or {}) do
for _, b in pairs(stashItems or {}) do
if k == b.name then itemRemove[k] = v end
if k == b.name then
itemRemove[k] = v
end
end
end
end

View File

@@ -21,6 +21,10 @@
--- end
--- ```
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
end
@@ -258,7 +262,7 @@ end
--- ```
function countTable(tbl)
local i = 0
for _ in pairs(tbl) do i = i + 1 end
for _ in pairs(tbl) do i += 1 end
return i
end
@@ -546,6 +550,24 @@ end
RegisterNetEvent(getScript()..":server:sendlog", sendServerLog)
-- This function was created to help create random numbers
-- When you create a table of items with a random hunger value for example
-- `hunger = math.random(10, 20)` this will be set at script start and never change
-- using `hunger = {10, 20}` and then calling this function will make it generate a random number every time
-- It also fallsback if it simply recieved a number instead of a table
-- For example:
-- local hunger = {10, 20}
-- local hungerAmount = GetRandomTiming(hunger)
-- print(hungerAmount) -- number between 10, 20
function GetRandomTiming(tbl)
if type(tbl) == "table" then
return math.random(tbl[1], tbl[2])
else
return tbl
end
end
-------------------------------------------------------------
-- Material and Prop Functions
-------------------------------------------------------------

View File

@@ -15,6 +15,7 @@
function lockInv(toggle)
FreezeEntityPosition(PlayerPedId(), toggle)
LocalPlayer.state:set("inv_busy", toggle, true)
LocalPlayer.state:set("invBusy", toggle, true)
TriggerEvent('inventory:client:busy:status', toggle)
TriggerEvent('canUseInventoryAndHotbar:toggle', not toggle)
end
@@ -49,8 +50,9 @@ function hasItem(items, amount, src)
local count = 0
for _, itemData in pairs(grabInv) do
jsonPrint(itemData)
if itemData and itemData.name == item then
count += (itemData.count or itemData.amount or 1)
count += (itemData.amount or itemData.count or 1)
end
end
foundInv = foundInv:gsub("%-", "^7-^6"):gsub("%_", "^7_^6")
@@ -66,6 +68,9 @@ function hasItem(items, amount, src)
end
return true, hasTable
end
-- if can't find inventory, return false
print("^1Error^7: ^1Can't find players inventory for some reason")
return false, {}
end
--- Retrieves a player's inventory based on the active inventory system.
@@ -120,11 +125,19 @@ function getPlayerInv(src)
elseif isStarted(CodeMInv) then
foundInv = CodeMInv
if src then
grabInv = exports[CodeMInv]:GetInventory(src)
grabInv = exports[CodeMInv]:GetInventory(getPlayer(src).citizenId, src)
else
grabInv = exports[CodeMInv]:getUserInventory()
end
elseif isStarted(TgiannInv) then
foundInv = TgiannInv
if src then
grabInv = exports[TgiannInv]:GetPlayerItems(src)
else
grabInv = exports[TgiannInv]:GetPlayerItems()
end
elseif isStarted(QBInv) then
foundInv = QBInv
if src then
@@ -160,4 +173,91 @@ function getPlayerInv(src)
print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3starter^1.^2lua^7")
end
return grabInv, foundInv
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

@@ -31,57 +31,27 @@ validTokens = {}
--- ```
function createUseableItem(item, funct)
if isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7es_extended", item)
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7es_extended^7", item)
while not ESX do Wait(0) end
ESX.RegisterUsableItem(item, funct)
elseif isStarted(QBExport) and not isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qb-core", item)
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qb-core^7", item)
Core.Functions.CreateUseableItem(item, funct)
elseif isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qbx_core", item)
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^7qbx_core^7", item)
exports[QBXExport]:CreateUseableItem(item, funct)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^2Registering item as ^3Usable^2 with ^1rsg-core^7", item)
Core.Functions.CreateUseableItem(item, funct)
else
print("^4ERROR^7: No supported framework detected for registering usable item: ^3"..item.."^7")
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(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
@@ -162,7 +132,7 @@ end
--- TriggerServerEvent(getScript()..":server:toggleItem", true, "health_potion", 1)
--- ```
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
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return
@@ -174,21 +144,9 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
local src = newsrc or source
if (give == true or give == 1) then
if newsrc == nil then -- must be coming from client this would be blank
if token == nil then
debugPrint("^1Auth^7: ^1No token recieved^7")
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
if newsrc == nil then -- this must be coming from client this would be blank
if not checkToken(src, token, "item", item) then
return
end
end
end
@@ -204,22 +162,32 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
dupeWarn(src, item, amount)
else
if isStarted(OXInv) then invName = OXInv
if isStarted(OXInv) then
invName = OXInv
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)
elseif isStarted(CoreInv) then invName = CoreInv
elseif isStarted(CoreInv) then
invName = CoreInv
exports[CoreInv]:removeItem(src, item, remamount)
elseif isStarted(OrigenInv) then invName = OrigenInv
elseif isStarted(OrigenInv) then
invName = OrigenInv
exports[OrigenInv]:removeItem(src, item, remamount)
elseif isStarted(CodeMInv) then invName = CodeMInv
elseif isStarted(CodeMInv) then
invName = CodeMInv
exports[CodeMInv]:RemoveItem(src, item, remamount)
elseif isStarted(QBInv) then invName = QBInv
elseif isStarted(TgiannInv) then
invName = TgiannInv
exports[TgiannInv]:RemoveItem(src, item, remamount)
elseif isStarted(QBInv) then
invName = QBInv
while remamount > 0 do
if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then
remamount -= 1
@@ -231,7 +199,9 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
if Config.Crafting.showItemBox then
TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "remove", amount or 1)
end
elseif isStarted(PSInv) then invName = PSInv
elseif isStarted(PSInv) then
invName = PSInv
while remamount > 0 do
if Core.Functions.GetPlayer(src).Functions.RemoveItem(item, 1, slot) then
remamount -= 1
@@ -282,6 +252,7 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
else
local amountToAdd = amount or 1
if isStarted(OXInv) then invName = OXInv
jsonPrint(info)
exports[OXInv]:AddItem(src, item, amountToAdd, info, slot)
elseif isStarted(QSInv) then invName = QSInv
@@ -296,22 +267,26 @@ RegisterNetEvent(getScript()..":server:toggleItem", function(give, item, amount,
elseif isStarted(OrigenInv) then invName = OrigenInv
exports[OrigenInv]:addItem(src, item, amountToAdd, info, slot)
elseif isStarted(TgiannInv) then invName = TgiannInv
exports[TgiannInv]:AddItem(src, item, amountToAdd, slot, info)
elseif isStarted(QBInv) then invName = QBInv
if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then
TriggerClientEvent((isStarted(QBInv) and QBInvNew and "qb-" or "").."inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
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
if Core.Functions.GetPlayer(src).Functions.AddItem(item, amountToAdd, nil, info) then
TriggerClientEvent("rsg-inventory:client:ItemBox", src, Items[item], "add", amountToAdd)
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
if invName == "" then
@@ -347,13 +322,13 @@ end)
--- ```lua
--- dupeWarn(playerId, "health_potion")
--- ```
function dupeWarn(src, item, amount)
function dupeWarn(src, item, message)
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
DropPlayer(src, name.."("..tostring(src)..") Kicked for suspected duplicating items: "..item)
DropPlayer(src, name.."("..tostring(src)..") kicked by exploit protection")
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
-------------------------------------------------------------
@@ -410,7 +385,7 @@ function getDurability(item)
if v.name == item then
if v.slot <= lowestSlot then
lowestSlot = v.slot
durability = itemcheck[k].info.durability
durability = itemcheck[k].info and itemcheck[k].info.durability or nil
end
end
end
@@ -422,7 +397,7 @@ function getDurability(item)
if v.slot <= lowestSlot then
debugPrint(v.slot, itemcheck[k].metadata.durability)
lowestSlot = v.slot
durability = v.metadata.durability
durability = v.metadata and v.metadata.durability or nil
end
end
end
@@ -432,7 +407,7 @@ function getDurability(item)
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.info.durability
durability = v.info and v.info.durability or nil
end
end
end
@@ -442,7 +417,7 @@ function getDurability(item)
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.metadata.durability
durability = v.metadata and v.metadata.durability or nil
end
end
end
@@ -450,9 +425,9 @@ function getDurability(item)
if isStarted(CodeMInv) then
local itemcheck = exports[CodeMInv]:GetClientPlayerInventory()
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.info.durability
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
@@ -462,7 +437,17 @@ function getDurability(item)
for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot
durability = v.metadata.durability
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
@@ -524,6 +509,9 @@ RegisterNetEvent(getScript()..":server:setMetaData", function(data)
elseif isStarted(OrigenInv) then
exports[OrigenInv]:setMetadata(src, data.slot, data.metadata)
elseif isStarted(TgiannInv) then
exports[TgiannInv]:UpdateItemMetadata(src, data.item, data.slot, data.metadata)
end
end)
@@ -633,9 +621,31 @@ function canCarry(itemTable, src)
resultTable[k] = exports[OrigenInv]:canCarryItem(src, k, v)
end
elseif isStarted(QBInv) then
elseif isStarted(TgiannInv) then
for k, v in pairs(itemTable) do
resultTable[k] = exports[QBInv]:CanAddItem(src, k, v)
resultTable[k] = exports[TgiannInv]:CanCarryItem(source, k, v)
end
elseif isStarted(QBInv) then
if QBInvNew then
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
elseif isStarted(PSInv) then
@@ -669,13 +679,33 @@ if isServer() then
return result
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()
validTokens = validTokens or {}
createCallback(AuthEvent, function(source)
local src = source
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
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital function was called from an external resource^7")
return ""
@@ -707,22 +737,63 @@ if isServer() then
receivedEvent = {}
createCallback(getScript()..":callback:GetAuthEvent", function(source)
local src = source
debugPrint(GetInvokingResource())
--debugPrint(GetInvokingResource())
if GetInvokingResource() and GetInvokingResource() ~= getScript() and GetInvokingResource() ~= "qb-core" then
debugPrint("^1Error^7: ^1Possible exploit^7, ^1vital callback was called from an external resource^7")
return ""
end
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
else
print("^1Auth^7: ^1Player ^7"..src.." ^1tried to request auth token more than once^7")
return ""
end
end)
RegisterNetEvent(getScript()..":clearAuthEventRequest", function()
local src = source
debugPrint("^1Auth^7: ^2Manually clearing Auth Event for Player Source^7:", src, AuthEvent)
receivedEvent[src] = nil
end)
-- Multiuse function to check if the generated client token is valid
function checkToken(src, token, genType, name)
if token == nil then
debugPrint("^1Auth^7: ^1No token recieved^7")
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1without an auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1without an auth token^7")
end
return false
else
debugPrint("^1Auth^7: ^2Auth token received^7, ^2checking against server cache^7..")
if token ~= validTokens[src] then
debugPrint("^1Auth^7: ^1Tokens don't match! ^7", token, validTokens[src])
if genType == "stash" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1create a stash ^7"..name.." ^1with an incorrect auth token^7")
elseif genType == "item" then
dupeWarn(src, name, "^1Auth Error^7: ^3"..src.." ^1attempted to spawn an item ^7"..name.." ^1with an incorrect auth token^7")
end
return false
else
debugPrint("^1Auth^7: ^2Client and Server Auth tokens match^7!", token, validTokens[src])
validTokens[src] = nil
return true
end
end
end
else
onPlayerLoaded(function()
debugPrint("^1Auth^7: ^2Requesting ^3Auth Event^7")
AuthEvent = triggerCallback(getScript()..":callback:GetAuthEvent")
end, true)
onPlayerUnload(function()
debugPrint("^1Auth^7: ^2Clearing Auth Event^7")
TriggerServerEvent(getScript()..":clearAuthEventRequest")
end, true)
end

View File

@@ -12,8 +12,16 @@
-------------------------------------------------------------
-- Global Duty Status
-------------------------------------------------------------
-- This attempts to sync up with the players framework onDuty variable
-- This stops the script getting confused when one is false and one is true
onDuty = false
if not isServer() then
onPlayerLoaded(function()
onDuty = getPlayer().onDuty
end, true)
end
-------------------------------------------------------------
-- Boss Role Detection
-------------------------------------------------------------
@@ -38,7 +46,7 @@ function makeBossRoles(role)
local data = (Jobs and Jobs[role]) or (Gangs and Gangs[role])
if data then
for grade, info in pairs(data.grades) do
if info.isboss or info.bankAuth then
if info.isboss or info.bankAuth or info.isBoss then
boss[role] = boss[role] and math.min(boss[role], tonumber(grade)) or tonumber(grade)
end
end
@@ -92,9 +100,14 @@ end
--- toggleDuty() -- Player receives a notification of their new duty status.
--- ```
function toggleDuty()
onDuty = not onDuty
if isStarted(QBExport) or isStarted(QBXExport) then
TriggerServerEvent("QBCore:ToggleDuty")
Wait(100)
onDuty = getPlayer().onDuty
elseif isStarted(RSGExport) then
TriggerServerEvent("RSGCore:ToggleDuty")
Wait(100)
onDuty = getPlayer().onDuty
else
if onDuty then
triggerNotify(nil, "Now on duty", "success")
@@ -104,6 +117,15 @@ function toggleDuty()
end
end
-- Framework specific functions to keep duty status synced
RegisterNetEvent("QBCore:Client:OnJobUpdate", function(JobInfo) onDuty = JobInfo.onduty end)
RegisterNetEvent("QBCore:Client:SetDuty", function(duty) onDuty = duty end)
RegisterNetEvent("qbx_core:client:onJobUpdate", function(JobInfo) onDuty = JobInfo.onduty end)
RegisterNetEvent("RSGCore:Client:OnJobUpdate", function(JobInfo) onDuty = JobInfo.onduty end)
RegisterNetEvent("RSGCore:Client:SetDuty", function(duty) onDuty = duty end)
-------------------------------------------------------------
-- Interaction Functions
-------------------------------------------------------------

View File

@@ -23,7 +23,7 @@ local Props = {}
function makeProp(data, freeze, synced)
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)
SetEntityHeading(prop, data.coords.w + 180.0)
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))

View File

@@ -23,15 +23,23 @@ function GetPlayer(source)
if isStarted(QBExport) then
debugPrint("^6Bridge^7: ^3GetPlayer^7() QBExport")
return exports[QBExport]:GetCoreObject().Functions.GetPlayer(source)
elseif isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^3GetPlayer^7() QBOXExport")
return exports[QBXExport]:GetCoreObject().Functions.GetPlayer(source)
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^3GetPlayer^7() ESXExport")
return ESX.GetPlayerFromId(source)
elseif isStarted(OXCoreExport) then
debugPrint("^6Bridge^7: ^3GetPlayer^7() OXCoreExport")
return exports[OXCoreExport]:GetPlayer(source)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^3GetPlayer^7() RSGExport")
return exports[RSGExport]:GetCoreObject().Functions.GetPlayer(source)
end
return nil
end
@@ -58,14 +66,21 @@ function GetMetadata(player, key)
return triggerCallback(getScript()..":server:GetMetadata", key)
else
if isStarted(QBExport) or isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^3GetMetadata^7() QBExport or QBXExport", key)
debugPrint("^6Bridge^7: ^3GetMetadata^7() QBExport/QBXExport", key)
return player.PlayerData.metadata[key]
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^3GetMetadata^7() ESXExport", key)
return player.getMeta(key)
elseif isStarted(OXCoreExport) then
debugPrint("^6Bridge^7: ^3GetMetadata^7() OXCoreExport", key)
return player.get(key)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^3GetMetadata^7() RSGExport", key)
return player.PlayerData.metadata[key]
end
end
return nil
@@ -112,12 +127,19 @@ function SetMetadata(player, key, value)
if isStarted(QBExport) or isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^3SetMetadata^7() using QBExport/QBXExport")
player.Functions.SetMetaData(key, value)
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^3SetMetadata^7() using ESXExport")
player.setMeta(key, value)
elseif isStarted(OXCoreExport) then
debugPrint("^6Bridge^7: ^3SetMetadata^7() using OXCoreExport")
player.set(key, value)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^3SetMetadata^7() using RSGExport")
player.Functions.SetMetaData(key, value)
end
end

View File

@@ -78,6 +78,11 @@ function sendPhoneMail(data)
TriggerServerEvent(getScript()..":jpr:SendMail", mailData)
end,
},
{ name = "ef-phone",
send = function(mailData)
TriggerServerEvent('qb-phone:server:sendNewMail', mailData)
end,
},
}
local activePhone = nil

View File

@@ -111,10 +111,16 @@ end)
function setThirst(src, thirst)
if isStarted(ESXExport) then
TriggerClientEvent('esx_status:add', src, 'thirst', thirst)
elseif isStarted(QBExport) or isStarted(QBXExport) then
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, thirst, Player.PlayerData.metadata.thirst)
elseif isStarted(RSGExport) then
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, thirst, Player.PlayerData.metadata.thirst)
end
end
@@ -130,10 +136,16 @@ end
function setHunger(src, hunger)
if isStarted(ESXExport) then
TriggerClientEvent('esx_status:add', src, 'hunger', hunger)
elseif isStarted(QBExport) or isStarted(QBXExport) then
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.hunger)
elseif isStarted(RSGExport) then
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.hunger)
end
end
@@ -161,20 +173,31 @@ function chargePlayer(cost, moneyType, newsrc)
if moneyType == "cash" then
if isStarted(OXInv) then fundResource = OXInv
exports[OXInv]:RemoveItem(src, "money", cost)
elseif isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost)
elseif isStarted(RSGExport) then
fundResource = QBExport
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("cash", cost)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).removeMoney(cost, "")
end
elseif moneyType == "bank" then
if isStarted(QBExport) or isStarted(QBXExport) then fundResource = QBExport
if isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost)
elseif isStarted(ESXExport) then fundResource = ESXExport
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.RemoveMoney("bank", cost)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).removeMoney(cost, "")
end
end
@@ -212,17 +235,29 @@ function fundPlayer(fund, moneyType, newsrc)
if isStarted(OXInv) then
fundResource = OXInv
exports[OXInv]:AddItem(src, "money", fund)
elseif isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.AddMoney("cash", fund)
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.AddMoney("cash", fund)
elseif isStarted(ESXExport) then
fundResource = ESXExport
PlayESX.GetPlayerFromId(src).addMoney(fund, "")
ESX.GetPlayerFromId(src).addMoney(fund, "")
end
elseif moneyType == "bank" then
if isStarted(QBExport) or isStarted(QBXExport) then
fundResource = QBExport
Core.Functions.GetPlayer(src).Functions.AddMoney("bank", fund)
elseif isStarted(RSGExport) then
fundResource = RSGExport
Core.Functions.GetPlayer(src).Functions.AddMoney("bank", fund)
elseif isStarted(ESXExport) then
fundResource = ESXExport
ESX.GetPlayerFromId(src).addMoney(fund, "")
@@ -266,17 +301,17 @@ function ConsumeSuccess(itemName, type, data)
if isStarted(ESXExport) then
if hunger then
TriggerServerEvent(getScript()..":server:setNeed", "hunger", hunger * 10000)
TriggerServerEvent(getScript()..":server:setNeed", "hunger", tonumber(hunger) * 10000)
end
if thirst then
TriggerServerEvent(getScript()..":server:setNeed", "thirst", thirst * 10000)
TriggerServerEvent(getScript()..":server:setNeed", "thirst", tonumber(thirst) * 10000)
end
else
if hunger then
TriggerServerEvent(getScript()..":server:setNeed", "hunger", Core.Functions.GetPlayerData().metadata["hunger"] + hunger)
TriggerServerEvent(getScript()..":server:setNeed", "hunger", Core.Functions.GetPlayerData().metadata["hunger"] + tonumber(hunger))
end
if thirst then
TriggerServerEvent(getScript()..":server:setNeed", "thirst", Core.Functions.GetPlayerData().metadata["thirst"] + thirst)
TriggerServerEvent(getScript()..":server:setNeed", "thirst", Core.Functions.GetPlayerData().metadata["thirst"] + tonumber(thirst))
end
end
@@ -290,7 +325,9 @@ function ConsumeSuccess(itemName, type, data)
end
end
getRandomReward(itemName)
if Config.Reward then
getRandomReward(itemName)
end
end
-------------------------------------------------------------
@@ -380,6 +417,35 @@ 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
local jobinfo = player.PlayerData.job
if jobinfo.name == job then
hasJobFlag = true
duty = player.PlayerData.job.onduty
if grade and not (grade <= jobinfo.grade.level) then hasJobFlag = false end
end
local ganginfo = player.PlayerData.gang
if ganginfo.name == job then
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end
end
else
local jobinfo = exports[RSGExport]:GetPlayer(src).PlayerData.job
if jobinfo.name == job then
hasJobFlag = true
duty = exports[RSGExport]:GetPlayer(src).PlayerData.job.onduty
if grade and not (grade <= jobinfo.grade.level) then hasJobFlag = false end
end
local ganginfo = exports[RSGExport]:GetPlayer(src).PlayerData.gang
if ganginfo.name == job then
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end
end
end
else
print("^4ERROR^7: ^2No Core detected for hasJob ^7- ^2Check ^3starter^1.^2lua^7")
end
@@ -425,6 +491,22 @@ function hasJob(job, source, grade)
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end
end
elseif isStarted(RSGExport) then
local info = nil
Core.Functions.GetPlayerData(function(PlayerData) info = PlayerData end)
local jobinfo = info.job
if jobinfo.name == job then
hasJobFlag = true
duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then hasJobFlag = false end
end
local ganginfo = info.gang
if ganginfo.name == job then
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then hasJobFlag = false end
end
else
print("^4ERROR^7: ^2No Core detected for hasJob() ^7- ^2Check ^3starter^1.^2lua^7")
end

View File

@@ -149,8 +149,8 @@ function BigMessage:ShowColoredShard(msg, desc, textColor, bgColor, duration, ma
BeginScaleformMovieMethod(self.scaleform, "SHOW_SHARD_CENTERED_MP_MESSAGE")
ScaleformMovieMethodAddParamPlayerNameString(msg)
ScaleformMovieMethodAddParamPlayerNameString(desc)
ScaleformMovieMethodAddParamInt(bgColor)
ScaleformMovieMethodAddParamInt(textColor)
ScaleformMovieMethodAddParamInt(bgColor)
EndScaleformMovieMethod()
self.duration = duration

View File

@@ -30,15 +30,17 @@ function sellMenu(data)
for k, v in pairs(data.sellTable.Items) do itemList[k] = 1 end
local _, hasTable = hasItem(itemList)
for k, v in pairsByKeys(data.sellTable.Items) do
Menu[#Menu + 1] = {
isMenuHeader = not hasTable[k].hasItem,
icon = invImg(k),
header = Items[k].label..(hasTable[k].hasItem and "💰 (x"..hasTable[k].count..")" or ""),
txt = Loc[Config.Lan].info["sell_all"]..v.." "..Loc[Config.Lan].info["sell_each"],
onSelect = function()
sellAnim({ item = k, price = v, ped = data.ped, onBack = function() sellMenu(data) end })
end,
}
if Items[k] then
Menu[#Menu + 1] = {
isMenuHeader = not hasTable[k].hasItem,
icon = invImg(k),
header = Items[k].label..(hasTable[k].hasItem and "💰 (x"..hasTable[k].count..")" or ""),
txt = Loc[Config.Lan].info["sell_all"]..v.." "..Loc[Config.Lan].info["sell_each"],
onSelect = function()
sellAnim({ item = k, price = v, ped = data.ped, onBack = function() sellMenu(data) end })
end,
}
end
end
else
for k, v in pairsByKeys(data.sellTable) do
@@ -48,7 +50,9 @@ function sellMenu(data)
header = k,
txt = "Amount of items: "..countTable(v.Items),
onSelect = function()
v.onBack = function() sellMenu(origData) end
v.onBack = function()
sellMenu(origData)
end
v.sellTable = data.sellTable[k]
sellMenu(v)
end,
@@ -57,8 +61,8 @@ function sellMenu(data)
end
end
openMenu(Menu, {
header = data.sellTable.Header or "Amount of items: "..countTable(data.sellTable.Items),
headertxt = data.sellTable.Header and "Amount of items: "..countTable(data.sellTable.Items) or "",
header = data.sellTable.Header or "Amount of items: "..countTable(data.sellTable.Items or data.sellTable),
headertxt = data.sellTable.Header and "Amount of items: "..countTable(data.sellTable.Items or data.sellTable),
canClose = true,
onBack = data.onBack,
})
@@ -105,12 +109,14 @@ function sellAnim(data)
TriggerServerEvent(getScript().."Sellitems", data)
lookEnt(data.ped)
local dict = "mp_common"
playAnim(dict, "givetake2_a", 0.3, 2)
playAnim(dict, "givetake2_b", 0.3, 2, data.ped)
playAnim(dict, "givetake2_a", 0.3, 48)
playAnim(dict, "givetake2_b", 0.3, 48, data.ped)
Wait(2000)
StopAnimTask(PlayerPedId(), dict, "givetake2_a", 0.5)
StopAnimTask(data.ped, dict, "givetake2_b", 0.5)
if data.onBack then data.onBack() end
if data.onBack then
data.onBack()
end
end
--- Server event handler for processing item sales.
@@ -157,29 +163,45 @@ function openShop(data)
elseif isStarted(OXInv) then
exports[OXInv]:openInventory('shop', { type = data.shop })
elseif isStarted(QSInv) then
elseif isStarted(QSInv) or isStarted(CodeMInv) then
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
elseif isStarted(TgiannInv) then
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
elseif isStarted(QBInv) 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
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
end
elseif isStarted(RSGInv) then
TriggerServerEvent(getScript()..':server:OpenShopNewRSG', data.shop)
TriggerServerEvent(getScript()..':server:openServerShop', data.shop)
end
lookEnt(data.coords)
end
--- Server event handler for opening a shop using the new QB inventory system.
RegisterNetEvent(getScript()..':server:OpenShopNewQB', function(data)
exports[QBInv]:OpenShop(source, data)
end)
RegisterNetEvent(getScript()..':server:OpenShopNewRSG', function(data)
exports[RSGInv]:OpenShop(source, data)
RegisterNetEvent(getScript()..':server:openServerShop', function(data)
if isStarted(QBInv) then
exports[QBInv]:OpenShop(source, data)
end
if isStarted(PSInv) then
exports[PSInv]:OpenShop(source, data)
end
if isStarted(TgiannInv) then
exports[TgiannInv]:OpenShop(source, data)
end
if isStarted(RSGInv) then
exports[RSGInv]:OpenShop(source, data)
end
end)
--- Registers a shop with the active inventory system.
@@ -201,6 +223,11 @@ function registerShop(name, label, items, society)
inventory = items,
society = society,
})
elseif isStarted(TgiannInv) then
debugPrint("^6Bridge^7: ^2Registering ^3Tgiann ^2Store^7:", name, label)
exports[TgiannInv]:RegisterShop(name, items)
elseif isStarted(QBInv) and QBInvNew then
debugPrint("^6Bridge^7: ^2Registering ^3QB ^2Store^7:", name, label)
exports[QBInv]:CreateShop({
@@ -211,6 +238,16 @@ function registerShop(name, label, items, 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
debugPrint("^6Bridge^7: ^2Registering ^3RSG ^2Store^7:", name, label)
exports[RSGInv]:CreateShop({

View File

@@ -47,19 +47,19 @@ function GetStashTimeout(stashName, stop)
stashCache[stashName] = { items = {}, timeout = 0 }
stash = stashCache[stashName]
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
-- If there are already items in cache, skip recheck.
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
end
-- If timeout has expired, update the stash items from the server.
if stashCache[stashName].timeout <= 0 then
stashCache[stashName].items = triggerCallback(getScript()..':server:GetStashItems', stashName)
stashCache[stashName].timeout = 15000 -- Timeout in milliseconds.
stashCache[stashName].timeout = 10000 -- Timeout in milliseconds.
CreateThread(function()
while stashCache[stashName] and stashCache[stashName].timeout > 0 do
stashCache[stashName].timeout -= 1000
@@ -90,20 +90,12 @@ function checkStashItem(stashes, itemTable)
end
if type(stashes) == "table" then
local successes = 0
local itemCount = countTable(itemTable)
debugPrint("^6Bridge^7: ^2Checking multiple stashes for ingredients^7")
-- Iterate over each provided stash name.
for _, name in pairs(stashes) do
Wait(10) -- Delay to avoid multiple callbacks issues.
GetStashTimeout(name)
for item, amount in pairs(itemTable) do
debugPrint("^6Bridge^7: ^2Checking "..(name and " '^3"..name.."^7'" or "").." ingredients - ^6"..item.."^7")
if stashhasItem(stashCache[name].items, item, amount) then
successes += 1
if successes == itemCount then
return true, name
end
end
if stashhasItem(stashCache[name].items, itemTable, nil) then
return true, name
end
end
else
@@ -151,9 +143,17 @@ function openStash(data)
elseif isStarted(OrigenInv) then
exports[OrigenInv]:openInventory('stash', data.stash, { label = data.label })
elseif isStarted(TgiannInv) then
TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash,
label = data.label,
maxweight = data.maxWeight or 600000,
slots = data.slots or 40
})
elseif isStarted(QBInv) then
if QBInvNew then
TriggerServerEvent(getScript()..':server:OpenStashQB', {
TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash,
label = data.label,
maxweight = data.maxWeight or 600000,
@@ -161,11 +161,30 @@ function openStash(data)
})
else
TriggerEvent("inventory:client:SetCurrentStash", data.stash)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, {
slots = data.slots or 50,
maxWeight = data.maxWeight or 600000
})
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("inventory:server:OpenInventory", "stash", data.stash, {
slots = data.slots or 50,
maxWeight = data.maxWeight or 600000
})
end
elseif isStarted(RSGInv) then
TriggerServerEvent(getScript()..':server:OpenStashRSG', {
TriggerServerEvent(getScript()..':server:openServerStash', {
stashName = data.stash,
label = data.label,
maxweight = data.maxWeight or 600000,
@@ -175,19 +194,32 @@ function openStash(data)
else
--Fallback to these commands
TriggerEvent("inventory:client:SetCurrentStash", data.stash)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, data.stashOptions)
TriggerServerEvent("inventory:server:OpenInventory", "stash", data.stash, {
slots = data.slots or 50,
maxWeight = data.maxWeight or 600000
})
end
lookEnt(data.coords)
end
-- Register an event for opening QB stashes.
RegisterNetEvent(getScript()..':server:OpenStashQB', function(data)
exports[QBInv]:OpenInventory(source, data.stashName, data)
end)
RegisterNetEvent(getScript()..':server:OpenStashRSG', function(data)
exports[RSGInv]:OpenInventory(source, data.stashName, data)
-- Wrapper function for opening stash from the server.
-- Messy but not much else I can do about it.
RegisterNetEvent(getScript()..":server:openServerStash", function(data)
local src = source
if isStarted(TgiannInv) then
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)
@@ -216,7 +248,9 @@ function getStash(stashName)
local stashItems, items = {}, {}
if isStarted(OXInv) then
stashResource = OXInv
stashItems = exports[OXInv]:Inventory(stashName).items
local stash = exports[OXInv]:Inventory(stashName)
-- Add fallback if ox can't find the stash and returns a boolean
stashItems = type(stash) == "table" and stash.items or {}
elseif isStarted(QSInv) then
stashResource = QSInv
@@ -234,6 +268,10 @@ function getStash(stashName)
stashResource = OrigenInv
stashItems = exports[OrigenInv]:getInventory(stashName)
elseif isStarted(TgiannInv) then
stashResource = TgiannInv
stashItems = exports[TgiannInv]:GetSecondaryInventoryItems("stash", stashName)
elseif isStarted(PSInv) then
stashResource = PSInv
local result = MySQL.scalar.await('SELECT items FROM stashitems WHERE stash = ?', { stashName })
@@ -241,8 +279,13 @@ function getStash(stashName)
elseif isStarted(QBInv) then
stashResource = QBInv
local result = MySQL.scalar.await("SELECT items FROM "..(QBInvNew and "inventories" or "stashitem").." WHERE identifier = ?", { stashName })
if result then stashItems = json.decode(result) end
if QBInvNew then
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
stashResource = RSGInv
@@ -298,39 +341,27 @@ function stashRemoveItem(stashItems, stashName, items)
if type(stashName) ~= "table" then
stashName = { stashName }
end
if isStarted(OXInv) then
for k, v in pairs(items) do
if type(stashName) == "table" then
for _, name in pairs(stashName) do
local success = exports[OXInv]:RemoveItem(name, k, v)
if success then
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v)
break
end
for _, name in pairs(stashName) do
local success = exports[OXInv]:RemoveItem(name, k, v)
if success then
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OXInv, k, v)
break
end
else
exports[OXInv]:RemoveItem(stashName, k, v)
end
end
elseif isStarted(QSInv) 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)
exports[QSInv]:RemoveItemIntoStash(stashName[1], k, v, l)
end
end
end
exports[QSInv]:RemoveItemIntoStash(stashName[1], k, v)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QSInv, k, v)
end
elseif isStarted(CoreInv) then
for k, v in pairs(items) do
exports[CoreInv]:removeItemExact(stashName, k, v)
exports[CoreInv]:removeItemExact(stashName[1], k, v)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..CoreInv, k, v)
end
@@ -348,34 +379,21 @@ function stashRemoveItem(stashItems, stashName, items)
end
end
end
exports[CodeMInv]:UpdateStash(stashName, stashItems)
exports[CodeMInv]:UpdateStash(stashName[1], stashItems)
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3CodeM^2 stash ^7'^6"..stashName.."^7'")
elseif isStarted(OrigenInv) then
for k, v in pairs(items) do
exports[OrigenInv]:RemoveFromStash(stashName, k, v)
exports[OrigenInv]:RemoveFromStash(stashName[1], k, v)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..OrigenInv, k, v)
end
elseif isStarted(PSInv) then
elseif isStarted(TgiannInv) 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
local itemData = exports[TgiannInv]:GetItemByNameFromSecondaryInventory("stash", stashName[1], k)
exports[TgiannInv]:RemoveItemFromSecondaryInventory("stash", stashName[1], k, v, itemData.slot, nil)
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..TgiannInv, k, v)
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
if QBInvNew then
@@ -383,11 +401,6 @@ function stashRemoveItem(stashItems, stashName, items)
exports[QBInv]:RemoveItem(stashName[1], k, v, false, 'crafting')
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash ^7'^6"..stashName[1].."^7'")
MySQL.Async.insert('INSERT INTO inventories (identifier, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashName[1],
['items'] = json.encode(stashItems)
})
else
for k, v in pairs(items) do
for l in pairs(stashItems) do
@@ -402,13 +415,38 @@ function stashRemoveItem(stashItems, stashName, items)
end
end
end
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash '^6"..stashName.."^7'")
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3QB^2 stash '^6"..stashName[1].."^7'")
MySQL.Async.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
['stash'] = stashName,
['stash'] = stashName[1],
['items'] = json.encode(stashItems)
})
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 ^3PS^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(RSGInv) then
for k, v in pairs(items) do
exports[RSGInv]:RemoveItem(stashName[1], k, v, false, 'crafting')
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..RSGInv, k, v)
end
else
print("^4ERROR^7: ^2No Inventory detected ^7- ^2Check ^3starter^1.^2lua^7")
end
@@ -433,7 +471,7 @@ RegisterNetEvent(getScript()..":server:stashRemoveItem", stashRemoveItem)
--- local hasAll, details = stashhasItem(currentStashItems, { iron = 2, wood = 5 })
--- ```
function stashhasItem(stashItems, items, amount)
local invs = { OXInv, QSInv, CoreInv, CodeMInv, OrigenInv, QBInv, PSInv }
local invs = { OXInv, QSInv, CoreInv, CodeMInv, OrigenInv, TgiannInv, QBInv, PSInv, RSGInv }
local foundInv = ""
for _, inv in ipairs(invs) do
if isStarted(inv) then
@@ -464,3 +502,90 @@ function stashhasItem(stashItems, items, amount)
return true, hasTable
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
RegisterNetEvent(getScript()..":openGrabBox", function(data)
if isStarted(OXInv) then
return
end
local id = ""
if data.metadata then
id = data.metadata.id
elseif data.info then
id = data.info.id
end
openStash({
stash = id,
})
end)

View File

@@ -121,7 +121,7 @@ function createEntityTarget(entity, opts, dist)
options[i] = {
icon = opts[i].icon,
label = opts[i].label,
item = opts[i].item or nil,
items = opts[i].item or nil,
groups = opts[i].job or opts[i].gang,
onSelect = opts[i].action,
distance = dist,
@@ -230,7 +230,7 @@ function createBoxTarget(data, opts, dist)
options[i] = {
icon = opts[i].icon,
label = opts[i].label,
item = opts[i].item or nil,
items = opts[i].item or nil,
groups = opts[i].job or opts[i].gang,
onSelect = opts[i].onSelect or opts[i].action,
distance = dist,
@@ -336,7 +336,7 @@ function createCircleTarget(data, opts, dist)
options[i] = {
icon = opts[i].icon,
label = opts[i].label,
item = opts[i].item or nil,
items = opts[i].item or nil,
groups = opts[i].job or opts[i].gang,
onSelect = opts[i].onSelect or opts[i].action,
distance = dist,
@@ -418,7 +418,7 @@ function createModelTarget(models, opts, dist)
options[i] = {
icon = opts[i].icon,
label = opts[i].label,
item = opts[i].item or nil,
items = opts[i].item or nil,
groups = opts[i].job or opts[i].gang,
onSelect = opts[i].action,
distance = dist,

View File

@@ -108,6 +108,7 @@ function getVehicleProperties(vehicle)
if isStarted(QBExport) and not isStarted(QBXExport) then
properties = Core.Functions.GetVehicleProperties(vehicle)
debugPrint("^6Bridge^7: ^2Getting Vehicle Properties ^7[^6"..QBExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..properties.model.."^7] - [^3"..properties.plate.."^7]")
elseif isStarted(OXLibExport) then
properties = lib.getVehicleProperties(vehicle)
debugPrint("^6Bridge^7: ^2Getting Vehicle Properties ^7[^6"..OXLibExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..properties.model.."^7] - [^3"..properties.plate.."^7]")
@@ -134,6 +135,7 @@ function setVehicleProperties(vehicle, props)
if isStarted(QBExport) and not isStarted(QBXExport) then
Core.Functions.SetVehicleProperties(vehicle, props)
debugPrint("^6Bridge^7: ^2Setting Vehicle Properties ^7[^6"..QBExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]")
elseif isStarted(OXLibExport) then
lib.setVehicleProperties(vehicle, props, false)
debugPrint("^6Bridge^7: ^2Setting Vehicle Properties ^7[^6"..OXLibExport.."^7] - [^3"..vehicle.."^7] - [^3"..GetEntityModel(vehicle).."^7/^3"..props.model.."^7] - [^3"..props.plate.."^7]")

View File

@@ -21,85 +21,24 @@
--- })
--- ```
function registerCommand(command, options)
if isStarted(OXLibExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..OXLibExport, command)
lib.addCommand(command, { help = options[1], restricted = options[5] and "group."..options[5] or nil }, options[4])
elseif isStarted(QBExport) and not isStarted(QBXExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..QBExport, command)
Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] or nil)
elseif isStarted(RSGExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7"..RSGExport, command)
Core.Commands.Add(command, options[1], options[2], options[3], options[4], options[5] or nil)
elseif isStarted(ESXExport) then
debugPrint("^6Bridge^7: ^2Registering ^3Command^2 with ^7ESX Legacy", command)
ESX.RegisterCommand(command, options[5] or 'admin', function(xPlayer, args, showError)
options[4](xPlayer.source, args, showError)
end, false, { help = options[1] })
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)
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)
--- ```
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 ~= 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
end

View File

@@ -13,6 +13,7 @@ Exports = {
CoreInv = "core_inventory",
CodeMInv = "codem-inventory",
OrigenInv = "origen_inventory",
TgiannInv = "tgiann-inventory",
OXLibExport = "ox_lib",
@@ -29,7 +30,12 @@ Exports = {
-- Required variables
debugMode = Config.System.Debug
-- Check server convars for hard set defaults
QBInvNew = true
InventoryWeight = 120000
-- [[ Server.Cfg Convar Check ]]--
-- Check server convars for hard set defaults, otherwise it uses per script configurations
if Config and Config.System then
if Config.System.Debug then
if GetConvar("jim_DisableDebug", "false") == "true" then
@@ -41,38 +47,70 @@ if Config and Config.System then
end
Config.System.Menu = GetConvar("jim_menuScript", Config.System.Menu)
Config.System.Notify = GetConvar("jim_notifyScript", Config.System.Notify)
Config.System.ProgressBar = GetConvar("jim_progressBarScript", Config.System.ProgressBar)
Config.System.drawText = GetConvar("jim_drawTextScript", Config.System.drawText)
Config.System.skillCheck = GetConvar("jim_skillCheckScript", Config.System.skillCheck)
Config.System.Notify = GetConvar("jim_notifyScript", Config.System.Notify or "gta")
Config.System.ProgressBar = GetConvar("jim_progressBarScript", Config.System.ProgressBar or "gta")
Config.System.drawText = GetConvar("jim_drawTextScript", Config.System.drawText or "gta")
Config.System.skillCheck = GetConvar("jim_skillCheckScript", Config.System.skillCheck or "gta")
if GetConvar("jim_dontUseTarget", "false") == "true" then
Config.System.DontUseTarget = true
end
end
QBInvNew = true
-- Load the core files here instead of in fxmanifests
-- Forcefully loads the files and quietly, compared to fxmanifest complaining if they don't exist when you don't need them all
local filesToLoad = {
Shared = {
[Exports.OXLibExport] = { "init.lua" },
[Exports.OXCoreExport] = { "lib/init.lua" },
[Exports.ESXExport] = { "imports.lua" },
[Exports.QBXExport] = { "modules/playerdata.lua" },
},
Client = {
["PolyZone"] = { "client.lua", "BoxZone.lua", "EntityZone.lua", "CircleZone.lua", "ComboZone.lua" },
["warmenu"] = { "warmenu.lua", },
},
}
InventoryWeight = 120000
-- Shared framework file loader
for Type, ScriptTable in pairs(filesToLoad) do
if Type == "Client" and IsDuplicityVersion() then
goto continue
else
for scriptName, files in pairs(ScriptTable) do
local state = GetResourceState(scriptName)
-- if the resource is started, load the file
if state == "started" then
-- Force items into a table if they are not
if type(files) == "string" then
files = { files }
end
for _, file in pairs(files) do
--print("^5CoreLoader^7: '"..scriptName.."/"..file.."' ^2into ^7'"..GetCurrentResourceName().."' ...")
local fileLoader = assert(load(LoadResourceFile(scriptName, (file)), ('@@'..scriptName..'/'..file)))
fileLoader()
if debugMode then
print("^5CoreLoader^7: ^2loaded ^1Core ^2file^7: ^3"..scriptName.."^7/^3"..(file):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").." ^2into ^7'"..GetCurrentResourceName().."'")
end
end
end
-- Testing loading the core files here instead of in fxmanifests
--for k, v in pairs({ -- This is a specific load order
-- [Exports.OXLibExport] = "init.lua",
-- [Exports.OXCoreExport] = "lib/init.lua",
-- [Exports.ESXExport] = "imports.lua",
-- [Exports.QBXExport] = "modules/playerdata.lua",
--}) do
-- if GetResourceState(k) == "started" then
-- print("^5Loading^7: '"..k.."/"..v.."' ^2into ^7'"..GetCurrentResourceName().."' ...")
-- local fileLoader = assert(load(LoadResourceFile(k, (v)), ('@@'..k..'/'..v)))
-- fileLoader()
-- print("^2Success^7: ^2loaded ^1Core ^2file^7: ^3"..k.."^7/^3"..(v):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").."^7")
-- else
-- if debugMode then
-- print("^3Warning^7: ^3"..k.." ^2not found^7, ^2skipping")
-- end
-- end
--end
-- if script is in server, but not started warn the user
if state == "uninitialized" or state == "stopped" then
print("^5CoreLoader^7: ^3"..scriptName.." ^1 found but it wasn't started^7.")
print("^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("^5CoreLoader^7: ^3"..scriptName.." ^2not found^7, ^2skipping")
end
end
end
end
::continue::
end
-- Load files here into the invoking script
for _, v in pairs({ -- This is a specific load order
@@ -82,7 +120,7 @@ for _, v in pairs({ -- This is a specific load order
'_eventDebug.lua',
'callback.lua',
'coreloader.lua', -- needs to be second to load all core related stuff before everything else
'coreloader.lua',
'duifunctions.lua',
@@ -143,4 +181,4 @@ for _, v in pairs({ -- This is a specific load order
if debugMode then
print("^5Success^7: ^2loaded file^7: ^3"..(v):gsub("/", "^7/^3"):gsub("%.lua", "^7.lua").."^7")
end
end
end

View File

@@ -1 +1,5 @@
2.0.03
2.0.13
- Add `GetRandomTiming()` function needed for restaurant scripts without jim-consuambles
https://github.com/jimathy/jim_bridge