Compare commits

...

24 Commits

Author SHA1 Message Date
Jim Shield
37f7eb1116 add testing code for new crafting table style 2025-09-28 03:22:12 +01:00
Jim Shield
145e3aa156 add new module ropeControl.lua
**Needs work** but adds the ability to easily create ropes/wires from one coord to another
2025-09-27 13:01:09 +01:00
Jim Shield
bb176addbf Create setStress function
This allows per framework stress functions to be set, including ESX

For ESX the math is done in this function as their values are insanely high instead of 0 - 100
2025-09-27 12:35:56 +01:00
Jim Shield
178040348e Rework SingleProgress slightly
Realised it wasn't doing the math to take the correct amount of required items, so this fixes it

also if `SingleProgress` is enabled, it won't show the "Ingredient Progress bars" any more
2025-09-27 12:34:46 +01:00
Jim Shield
ee15f3b076 Version Bump
`2.1.02` - `2.1.03`
2025-09-24 23:12:34 +01:00
Jim Shield
6919f038ee Release Notifier Push 2025-09-24 18:20:02 +01:00
Jim Shield
47029da6ed Revert "Version Bump"
This reverts commit f08638812c.
2025-09-24 14:23:43 +01:00
Jim Shield
e1d292d1bf Remove testing debug print 2025-09-24 14:09:19 +01:00
Jim Shield
f08638812c Version Bump
`2.1.02` - `2.1.03`
2025-09-24 13:36:14 +01:00
Jim Shield
de5424c506 Fix getPlayerInv() for CodeM Inventory 2025-09-24 12:30:08 +01:00
Jim Shield
b46d734442 Testing a rework _loaders.lua
Uses more specific functions per framework now for player loading in and out and optimizes use of them
2025-09-24 12:29:48 +01:00
Jim Shield
92ad96e435 Redo math for ox_inv get player current inv weight 2025-09-24 11:59:44 +01:00
Jim Shield
6166314cbf fix ox_inv current inventory weight check 2025-09-23 15:05:46 +01:00
Jim Shield
9fa8f58cfb Make ox_lib progressbars actually return false
I think this was causing progressbars to return true instead of `nil/false` somehow
this *should* make it more certain
2025-09-23 14:59:16 +01:00
Jim Shield
ed997ad8a2 fix typo breaking qb-core /commands 2025-09-23 12:00:40 +01:00
Jim Shield
20cea95783 Set previous active cam inactive
shouldn't be needed but just in case
2025-09-22 21:10:01 +01:00
Jim Shield
0dc5a45b5d Support for esx_society
`esx_society` requires societies to be registered manually before opening. this forces it

also adds full support for charging, funding and retrieving balances in `esx_society`
2025-09-22 21:08:31 +01:00
Jim Shield
54b1280bef Remove debug print 2025-09-21 12:09:12 +01:00
Jim Shield
3ac65d4630 Add "pre support" for jim-shops exploit security 2025-09-21 12:00:05 +01:00
Jim Shield
ed49876c69 Fix cleanup of targets for qb-target
Realised it was trying to remove `nil` when players were unloading/the scripts were ensured
2025-09-21 10:35:22 +01:00
Jim Shield
69d0f07bb6 Potential fix for playerInfo is nil 2025-09-20 17:56:47 +01:00
Jim Shield
b975f318a0 Fix hunger and thirst events
Missed out the math part when adding hunger and thirst to a player when eating items when I reworked the functions

should fix for all frameworks
2025-09-19 23:06:11 +01:00
Jim Shield
ce1df2c205 Version Bump 2025-09-19 17:54:45 +01:00
Jim Shield
75d8146e24 Fix nil print + use .xy for distance check 2025-09-19 17:22:40 +01:00
16 changed files with 801 additions and 277 deletions

71
.github/workflows/notify-release.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Discord Release Notifier
on:
# Manual or UI-published releases
release:
types: [published]
# Releases created by your tag-driven workflow
workflow_run:
workflows: ["Package & Release"] # must match the 'name:' in release.yml
types: [completed]
permissions:
contents: read
jobs:
# 1) Handle manual / UI / non-workflow-created releases
notify-from-release:
if: github.event_name == 'release' && github.event.action == 'published'
runs-on: ubuntu-latest
steps:
- name: Send release payload to Discord Bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-releases
run: |
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@$GITHUB_EVENT_PATH"
# 2) Handle releases created by your 'Package & Release' workflow
# (which wont trigger `on: release` when using GITHUB_TOKEN)
notify-from-workflow-run:
if: >
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Fetch release JSON by tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
OWNER="${GITHUB_REPOSITORY%/*}"
REPO="${GITHUB_REPOSITORY#*/}"
TAG="${{ github.event.workflow_run.head_branch }}"
# head_branch is the tag name for a tag push workflow_run
curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/$OWNER/$REPO/releases/tags/$TAG" \
> release.json
- name: Wrap as 'release' event payload & notify bot
env:
URL: http://${{ secrets.DISCORDBOT }}:3000/github-releases
run: |
set -euo pipefail
jq -n --slurpfile rel release.json \
--arg repo "$GITHUB_REPOSITORY" \
--arg repo_url "https://github.com/$GITHUB_REPOSITORY" \
--arg action "published" '
{ action: $action,
repository: { full_name: $repo, html_url: $repo_url },
release: $rel[0],
sender: { login: "github-actions[bot]" } }' > payload.json
curl -sS -X POST "$URL" \
-H 'Content-Type: application/json' \
--data-binary "@payload.json"

View File

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

@@ -124,7 +124,6 @@ end
function distExploitCheck(table, src)
if forceDisableExplotProtection == true then return true end
if not table then
print("^1Error^7: ^1This wasn^7'^1t reigstered correctly or this is an exploit attempt^1")
return false
@@ -135,7 +134,7 @@ function distExploitCheck(table, src)
local allow = false
for i = 1, #table do
if #(table[i].xyz - srcCoords) <= 10 then
if #(table[i].xy - srcCoords.xy) <= 10 then
return true
else
allow = false
@@ -143,7 +142,7 @@ function distExploitCheck(table, src)
end
if not allow then
print(src and ("^1Src ^3"..src.." ").."^1Tried to open a registered shop/stash from over the distance limit^7")
print(src and ("^1Src ^3"..src.." ") or "", "^1Tried to open a registered shop/stash from over the distance limit^7")
return false
end

View File

@@ -27,6 +27,132 @@ local function _debouncedRun(func)
end)
end
local frameworkLoadFunc = {
{ framework = Exports.QBXExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.isLoggedIn
end,
},
{ framework = Exports.QBExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('QBCore:Client:OnPlayerUnload', func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.isLoggedIn
end,
},
{ framework = Exports.ESXExport,
onPlayerLoaded =
function(func)
RegisterNetEvent("esx:playerLoaded", function()
-- make sure shared has loaded (because sql)
if waitForSharedLoad() then func() end
end)
end,
onPlayerUnload =
function(func)
RegisterNetEvent("esx:onPlayerLogout", func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while (GetGameTimer() - startTime) < timeout do
local playerData = ESX.GetPlayerData()
if playerData and playerData.job then
return true
end
Wait(100)
end
end,
},
{ framework = Exports.OXCoreExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('ox:playerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('ox:playerLogout', func)
end,
waitforLogin =
function(timeout)
if OxPlayer["stateId"] then
return true
end
while not OxPlayer["stateId"] do
Wait(1000)
if OxPlayer.get["stateId"] then
return true
end
end
end,
},
{ framework = Exports.RSGExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('RSGCore:Client:OnPlayerLoaded', func)
end,
onPlayerUnload =
function(func)
RegisterNetEvent('RSGCore:Client:OnPlayerUnload', func)
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.isLoggedIn
end,
},
{ framework = Exports.VorpExport,
onPlayerLoaded =
function(func)
RegisterNetEvent('vorp_core:Client:OnPlayerSpawned', func)
end,
onPlayerUnload =
function(func)
--??
end,
waitforLogin =
function(timeout)
local startTime = GetGameTimer()
while not LocalPlayer.state.IsInSession and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
return LocalPlayer.state.IsInSession
end,
},
}
-------------------------------------------------------------
-- Player Loaded and Unloaded Events
-------------------------------------------------------------
@@ -44,9 +170,6 @@ end
--- end, true)
--- ```
function onPlayerLoaded(func, onStart)
local onPlayerFramework = ""
local loaded = false
if onStart then
onResourceStart(function()
if not waitForLogin() then return end
@@ -59,34 +182,16 @@ function onPlayerLoaded(func, onStart)
_debouncedRun(func)
end
if isStarted(QBExport) or isStarted(QBXExport) then
onPlayerFramework = QBExport
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', handler)
elseif isStarted(ESXExport) then
onPlayerFramework = ESXExport
RegisterNetEvent('esx:playerLoaded', function()
if waitForSharedLoad() then handler() end
end)
elseif isStarted(OXCoreExport) then
onPlayerFramework = OXCoreExport
RegisterNetEvent('ox:playerLoaded', handler)
elseif isStarted(RSGExport) then
onPlayerFramework = RSGExport
RegisterNetEvent('RSGCore:Client:OnPlayerLoaded', handler)
elseif isStarted(VorpExport) then
onPlayerFramework = VorpExport
RegisterNetEvent('vorp_core:Client:OnPlayerSpawned', handler)
end
if onPlayerFramework ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^3onPlayerLoaded^7()^2 with ^3" .. onPlayerFramework .. "^7")
else
print("^4ERROR^7: No supported core detected for onPlayerLoaded - Check starter.lua")
for i = 1, #frameworkLoadFunc do
local data = frameworkLoadFunc[i]
jsonPrint(data)
if isStarted(data.framework) then
debugPrint("^6Bridge^7: ^2Registering ^3"..data.framework.." ^5onPlayerLoaded^7()")
data.onPlayerLoaded(handler)
return
end
end
print("^1ERROR^7: ^1No supported core detected for onPlayerLoaded - Check starter.lua^7")
end
--- Executes a function when the player character is unloaded.
@@ -99,15 +204,15 @@ end
--- end)
--- ```
function onPlayerUnload(func)
debugPrint("^6Bridge^7: ^2Registering ^3onPlayerUnload^7()")
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() func() end)
RegisterNetEvent('ox:playerLogout', function() func() end)
RegisterNetEvent('RSGCore:Client:OnPlayerUnload', function() func() end)
RegisterNetEvent('esx:onPlayerLogout', function() func() end)
for i = 1, #frameworkLoadFunc do
local data = frameworkLoadFunc[i]
if isStarted(data.framework) then
debugPrint("^6Bridge^7: ^2Registering ^3"..data.framework.." ^5onPlayerUnload^7()")
data.onPlayerUnload(func)
return
end
end
print("^1ERROR^7: ^1No supported core detected for onPlayerUnload - Check starter.lua^7")
end
-------------------------------------------------------------
@@ -166,51 +271,18 @@ end
--- @usage
--- waitForLogin()
function waitForLogin()
local timeout = 10000 -- 10 seconds in milliseconds
local startTime = GetGameTimer()
local loggedIn = false
if isStarted(ESXExport) then
while (GetGameTimer() - startTime) < timeout do
local playerData = ESX.GetPlayerData()
if playerData and playerData.job then
loggedIn = true
break
for i = 1, #frameworkLoadFunc do
local data = frameworkLoadFunc[i]
if isStarted(data.framework) then
debugPrint("^6Bridge^7: ^2Waiting for ^3"..data.framework.."^2 player login^7.")
local result = data.waitforLogin(10000)
if result == true then
debugPrint("^6Bridge^7: ^3"..data.framework.."^2 Player Login Detected^7.")
else
print("^4Error^7: ^2Timeout reached while waiting for player login^7.")
end
Wait(100)
return result
end
elseif isStarted(OXCoreExport) then
if OxPlayer["stateId"] then
loggedIn = true
end
while not OxPlayer["stateId"] do
Wait(1000)
debugPrint("Waiting for stateId to class as logged in")
if OxPlayer.get["stateId"] then
loggedIn = true
break
end
end
elseif isStarted(VorpExport) then
-- For other frameworks, use LocalPlayer.state.isLoggedIn.
while not LocalPlayer.state.IsInSession and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
loggedIn = LocalPlayer.state.IsInSession
else
-- For other frameworks, use LocalPlayer.state.isLoggedIn.
while not LocalPlayer.state.isLoggedIn and (GetGameTimer() - startTime) < timeout do
Wait(100)
end
loggedIn = LocalPlayer.state.isLoggedIn
end
if not loggedIn then
print("^4Error^7: ^2Timeout reached while waiting for player login^7.")
return false
else
debugPrint("^6Bridge^7: ^2Player Login Detected^7.")
return true
end
end

View File

@@ -17,7 +17,7 @@ local excludeKeys = {
amount = true, metadata = true, description = true, info = true,
job = true, gang = true, oneUse = true, slot = true,
blueprintRef = true, craftingLevel = true, craftedItems = true,
hasCrafted = true, exp = true, anim = true, time = true,
hasCrafted = true, exp = true, anim = true, time = true, id = true,
}
-------------------------------------------------------------
@@ -72,6 +72,25 @@ function craftingMenu(data)
-- Normalize stash name.
data.stashName = data.stashTable or data.stashName
-- Wrapper to convert new style crafting recipes to be handled by the menu properly
--if not data.craftTable.Recipes[1] then -- in theory if not a numbered table its the new style
-- local compatTable = {}
-- for k, v in pairs(data.craftTable.Recipes) do
-- for l, b in pairs(v) do
-- if not excludeKeys[l] then
-- compatTable[data.craftTable.Recipes[k].info.id or #compatTable+1] = {
-- [l] = v.ingredients,
-- amount = v.info and v.info.amount or 1,
-- metadata = v.info and v.info.metadata or nil,
-- job = v.info and v.info.job or nil,
-- gang = v.info and v.info.gang or nil
-- }
-- end
-- end
-- end
-- data.craftTable.Recipes = compatTable
--end
local Menu = {}
local Recipes = data.craftable.Recipes
local craftedItems = {}
@@ -80,7 +99,7 @@ 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 ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" then
if k ~= "amount" and k ~= "metadata" and k ~= "job" and k ~= "gang" and k == "id" then
tempCarryTable[k] = Recipes[i].amount or 1
end
end
@@ -323,6 +342,7 @@ end
--- ```
function makeItem(data)
local Ped = PlayerPedId()
if CraftLock then return end
CraftLock = true
data.stashName = data.stashTable or data.stashName
@@ -339,40 +359,42 @@ function makeItem(data)
local canReturn = true
local crafted, crafting = true, true
local cam = createTempCam(PlayerPedId(), data.coords)
local cam = createTempCam(Ped, data.coords)
startTempCam(cam)
-- Calculate total bartime if SingleProgress is enabled
local totalBartime = bartime * craftAmount
local totalBartime = (bartime * craftAmount)
-- Run ingredient check and usage separately first
for i = 1, craftAmount do
for k, v in pairs(data.craft) do
if not excludeKeys[k] and 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")
stopTempCam()
ClearPedTasks(PlayerPedId())
if canReturn then craftingMenu(data) end
CraftLock = false
return
if not Config.Crafting.SingleProgress then -- if SingleProgress is disabled, dont do ingredient progressbars
-- Run ingredient check and usage separately first
for i = 1, craftAmount do
for k, v in pairs(data.craft) do
if not excludeKeys[k] and 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")
stopTempCam()
ClearPedTasks(Ped)
if canReturn then craftingMenu(data) end
CraftLock = false
return
end
if crafting and progressBar({
label = "Using "..b.." "..getItemLabel(l),
time = 800,
cancel = true,
dict = 'pickup_object',
anim = "putdown_low",
flag = 49,
icon = l,
}) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[l], "use", b)
else
crafted, crafting = false, false
break
end
Wait(200)
end
if crafting and progressBar({
label = "Using "..b.." "..getItemLabel(l),
time = 1000,
cancel = true,
dict = 'pickup_object',
anim = "putdown_low",
flag = 49,
icon = l,
}) then
TriggerEvent((isStarted(QBInv) and QBInvNew and "qb-" or "")..'inventory:client:ItemBox', Items[l], "use", b)
else
crafted, crafting = false, false
break
end
Wait(200)
end
end
end
@@ -380,7 +402,7 @@ function makeItem(data)
if not crafted then
stopTempCam()
ClearPedTasks(PlayerPedId())
ClearPedTasks(Ped)
if canReturn then craftingMenu(data) end
CraftLock = false
return
@@ -391,11 +413,11 @@ function makeItem(data)
local craftProp = nil
if prop then
craftProp = makeProp({ prop = prop.model, coords = vec4(0, 0, 0, 0), true, true })
AttachEntityToEntity(craftProp, PlayerPedId(), GetPedBoneIndex(PlayerPedId(), prop.bone), prop.pos.x, prop.pos.y, prop.pos.z, prop.rot.x, prop.rot.y, prop.rot.z, true, true, false, true, 1, true)
AttachEntityToEntity(craftProp, Ped, GetPedBoneIndex(Ped, prop.bone), prop.pos.x, prop.pos.y, prop.pos.z, prop.rot.x, prop.rot.y, prop.rot.z, true, true, false, true, 1, true)
end
if data.sound then
local s = data.sound
PlaySoundFromEntity(s.soundId, s.audioName, PlayerPedId(), s.audioRef, true, 0)
PlaySoundFromEntity(s.soundId, s.audioName, Ped, s.audioRef, true, 0)
end
if crafting and progressBar({
label = bartext..((metadata and metadata.label) or getItemLabel(data.item)).." x"..craftAmount,
@@ -408,6 +430,10 @@ function makeItem(data)
request = true,
}) then
data.craft.amount = craftAmount
for k, v in pairs(data.craft[data.item]) do
-- multiply igredient requirement in sent crafting table for removal
data.craft[data.item][k] = (v * craftAmount)
end
TriggerServerEvent(getScript()..":Crafting:GetItem", data.item, data.craft, data.stashName, metadata, currentToken)
currentToken = nil -- clear client cached token
-- handle metadata and experience in a single go
@@ -422,7 +448,7 @@ function makeItem(data)
if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
canReturn = false
end
if data.sound then
@@ -459,7 +485,7 @@ function makeItem(data)
if data.craftable.Recipes[1].oneUse == true then
removeItem("craftrecipe", 1, nil, data.craftable.Recipes[1].slot)
local breakId = GetSoundId()
PlaySoundFromEntity(breakId, "Drill_Pin_Break", PlayerPedId(), "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
PlaySoundFromEntity(breakId, "Drill_Pin_Break", Ped, "DLC_HEIST_FLEECA_SOUNDSET", 1, 0)
canReturn = false
end
if data.requiredItemfunc then
@@ -475,7 +501,7 @@ function makeItem(data)
stopTempCam()
CraftLock = false
if canReturn then craftingMenu(data) end
ClearPedTasks(PlayerPedId())
ClearPedTasks(Ped)
end

View File

@@ -56,7 +56,7 @@ local InvFunc = {
local weight = 0
local itemcheck = getPlayerInv(src)
for _, v in pairs(itemcheck) do
weight += ((v.weight * v.amount) or 0)
weight += v.weight
end
return weight
end,
@@ -88,7 +88,6 @@ local InvFunc = {
inventory = items,
society = society,
})
debugPrint("^6Bridge^7: ^2Registering ^5"..OXInv.." ^3Store^7:", name, "^4Label^7: "..label)
end,
openStash =
function(data)
@@ -123,7 +122,6 @@ local InvFunc = {
registerStash =
function(name, label, slots, weight, owner, coords)
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
debugPrint("^6Bridge^7: ^2Registering ^4"..OXInv.." ^3Stash^7:", name, "^4Label^7: "..label)
end,
},
@@ -322,7 +320,6 @@ local InvFunc = {
registerStash =
function(name, label, slots, weight, owner, coords)
exports[OrigenInv]:registerStash(name, label, slots or 50, weight or 4000000)
debugPrint("^6Bridge^7: ^2Registering ^4"..OrigenInv.." ^3Stash^7:", name, "^4Label^7: "..label)
end,
},
@@ -344,7 +341,7 @@ local InvFunc = {
local count = 0
for _, itemData in pairs(invCache) do
if itemData and itemData.name == item then
count += (itemData.amount or itemData.count or 1)
count += (itemData.amount or 0)
end
end
return count >= amount, count
@@ -387,7 +384,7 @@ local InvFunc = {
if src then
grabInv = exports[CodeMInv]:GetInventory(getPlayer(src).citizenId, src)
else
grabInv = exports[CodeMInv]:getUserInventory()
grabInv = exports[CodeMInv]:GetClientPlayerInventory()
end
return grabInv
end,
@@ -514,7 +511,6 @@ local InvFunc = {
registerShop =
function(name, label, items, society)
exports[TgiannInv]:RegisterShop(name, items)
debugPrint("^6Bridge^7: ^2Registering ^5"..TgiannInv.." ^3Store^7:", name, "^4Label^7: "..label)
end,
openStash =
function(data)
@@ -548,7 +544,6 @@ local InvFunc = {
registerStash =
function(name, label, slots, weight, owner, coords)
exports[TgiannInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
debugPrint("^6Bridge^7: ^2Registering ^4"..TgiannInv.." ^3Stash^7:", name, "^4Label^7: "..label)
end,
},
@@ -841,7 +836,6 @@ local InvFunc = {
items = items,
society = society,
})
debugPrint("^6Bridge^7: ^2Registering ^5"..QBInv.." ^3Store^7:", name, "^4Label^7: "..label)
end
end,
openStash =
@@ -1040,7 +1034,6 @@ local InvFunc = {
items = items,
society = society,
})
debugPrint("^6Bridge^7: ^2Registering ^5"..PSInv.." ^3Store^7:", name, "^4Label^7: "..label)
end
end,
openStash =
@@ -1206,7 +1199,6 @@ local InvFunc = {
items = items,
society = society,
})
debugPrint("^6Bridge^7: ^2Registering ^5"..RSGInv.." ^3Store^7:", name, "^4Label^7: "..label)
end,
openStash =
function(data)
@@ -1287,6 +1279,7 @@ end
function hasItem(items, amount, src)
local amount = amount and amount or 1
local grabInv, foundInv = getPlayerInv(src)
if type(items) ~= "table" then items = { [items] = amount and amount or 1, } end
local hasTable = {}
@@ -2357,6 +2350,7 @@ function registerStash(name, label, slots, weight, owner, coords)
local inv = InvFunc[i]
if isStarted(inv.invName) then
inv.registerStash(name, label, slots, weight, owner, coords)
debugPrint("^6Bridge^7: ^2Registering ^4"..inv.invName.." ^3Stash^7:", name, "^4Label^7: "..label, coords and "- ^4Coord^7: "..formatCoord(coords) or "NO COORD SET")
break
end
end
@@ -2396,17 +2390,17 @@ if isServer() then
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
local Ped = PlayerPedId()
local id = data.metadata and data.metadata.id or data.info and data.info.id or ""
if isStarted(OXInv) then
return
end
openStash({
stash = id,
coords = GetEntityCoords(Ped)
})
end)
@@ -2487,6 +2481,7 @@ function sellMenu(data)
sellMenu(origData)
end
v.sellTable = data.sellTable[k]
v.name = data.name
sellMenu(v)
end,
}
@@ -2522,7 +2517,7 @@ end
--- ```
function sellAnim(data, token)
if not hasItem(data.item, 1) then
triggerNotify(nil, Loc[Config.Lan].error["dont_have"].." "..getItemLabel(data.item), "error")
triggerNotify(nil, (Loc[Config.Lan].error["dont_have"] or "You don't have any") .." "..getItemLabel(data.item), "error")
return
end
@@ -2589,8 +2584,8 @@ RegisterNetEvent(getScript()..":Sellitems", function(data, token)
end)
function registerSellShop(name, coords)
if coords and type(coords) == "vector3" then
print("Registered Sell Shop "..name.." Correctly")
if coords then
debugPrint("^6Bridge^7: ^2Registering ^3Sell Store^7: "..name, coords and "- ^4Coord^7: "..formatCoord(coords) or "NO COORD SET")
sellShopExploitCheck[name] = sellShopExploitCheck[name] or {}
sellShopExploitCheck[name][#sellShopExploitCheck[name]+1] = coords
end
@@ -2690,16 +2685,22 @@ end)
--- registerShop("weaponShop", "Weapon Shop", weaponItems, "society_weapons")
--- ```
function registerShop(name, label, items, society, coords)
local shopResource = ""
-- ensure tables exist
shopExploitCheck = shopExploitCheck or {}
shopExploitCheck[name] = shopExploitCheck[name] or {}
if isStarted("jim-shops") then
-- Add support for new jim-shops registration export
if checkExportExists("jim-shops", "registerShop") then
exports["jim-shops"]:registerShop(name, label, items, society, coords)
end
end
for i = 1, #InvFunc do
local inv = InvFunc[i]
if isStarted(inv.invName) then
shopResource = inv.invName
inv.registerShop(name, label, items, society)
debugPrint("^6Bridge^7: ^2Registering ^5"..inv.invName.." ^3Store^7:", name, "^4Label^7: "..label, coords and "- ^4Coord^7: "..formatCoord(coords) or "NO COORD SET")
break
end
end
@@ -2710,10 +2711,4 @@ function registerShop(name, label, items, society, coords)
else
print("^3Warning^7: ^1Store ^4"..name.." ^1doesn^7'^1t have coords^7, ^1this is exploitable^7, ^1add coords to ^3regiterShop^7()")
end
if shopResource ~= "" then
debugPrint("^6Bridge^7: ^2Registering ^5"..shopResource.." ^3Store^7:", name, "^4Label^7: "..label)
else
-- debugPrint("^1ERROR^7: ^1Couldn't find supported inventory to register shop^7:", name)
end
end

View File

@@ -33,6 +33,7 @@ local bossMenuFunc = {
{ name = "esx_society",
openBossMenu = function(isGang, group)
TriggerServerEvent(getScript()..":registerESXSociety", isGang, group)
TriggerEvent('esx_society:openBossMenu', group, function() end, { wash = false })
end,
},
@@ -60,6 +61,20 @@ function openBossMenu(isGang, group)
end
end
-- Register ESX Society account in the server
RegisterNetEvent(getScript()..":registerESXSociety", function(group)
local checkExist = exports.esx_society:GetSociety(group)
if checkExist == nil then
exports.esx_society:registerSociety(
group,
Gangs[group] and Gangs[group].label or Jobs[group] and Jobs[group].label,
group,
group,
group,
{type = "public"}
)
end
end)
-------------------------------------------------------------
-- Global Duty Status

View File

@@ -71,6 +71,7 @@ function startTempCam(cam, renderTime, loadScene, filter, switchCam)
-- if moving from a cached previous cam, or you've sent a camre id for it to switch from, interpolate to it
if switchCam or cachePrevCam then
SetCamActiveWithInterp(cam, cachePrevCam, renderTime or 1000, 0, 0)
SetCamActive(cachePrevCam, false) -- Set previous cam inactive (shouldn't be needed but just in case)
else
SetCamActive(cam, true)
end

View File

@@ -52,7 +52,7 @@ local progressFunc = {
if exports[OXLibExport]:progressBar(options) then
return true
else
print("^1progressBar was not successful")
return false
end
end
end,

255
shared/make/ropeControl.lua Normal file
View File

@@ -0,0 +1,255 @@
if not isServer() then
local RopeCache = {
nextId = 1,
byId = {},
byHandle = {},
}
function loadRopeTextures()
RopeLoadTextures()
local tries = 0
while not RopeAreTexturesLoaded() and tries < 200 do
Wait(0)
tries += 1
end
return RopeAreTexturesLoaded()
end
function maybeUnloadTextures()
local anyLeft = false
local all = GetAllRopes()
if all and type(all) == "table" then
for _, _ in ipairs(all) do anyLeft = true break end
end
if not anyLeft then
RopeUnloadTextures()
end
end
function registerRope(ropeHandle, startCoords, endCoords, opts)
if not ropeHandle or ropeHandle == 0 then return nil end
local id = RopeCache.nextId
RopeCache.nextId = id + 1
local rec = {
handle = ropeHandle,
startCoords = startCoords,
endCoords = endCoords,
type = opts.ropeType,
rate = opts.lengthChangeRate,
breakable = opts.breakable,
createdAt = GetGameTimer()
}
RopeCache.byId[id] = rec
RopeCache.byHandle[ropeHandle] = id
debugPrint("^5Debug^7: 2Registered Rope^7'^3"..id.."^7' - '^3"..ropeHandle.."^7'")
return id
end
function resolve(id)
if type(id) ~= "number" then return nil, "rope id must be a number" end
local rec = RopeCache.byId[id]
if not rec then return nil, "rope id not found" end
if not DoesRopeExist(rec.handle) then
-- stale; clean mapping
RopeCache.byHandle[rec.handle] = nil
RopeCache.byId[id] = nil
return nil, "rope no longer exists"
end
return rec
end
--- Create a rope pinned between two coordinates.
--- @param startCoords vector3|table start coord
--- @param endCoords vector3|table end coord
--- @param opts table|nil { ropeType=0..7, breakable=false, collision=true, lockFromFront=false, lengthChangeRate=1.0, timeMultiplier=1.0, slack=0.0, preset=nil }
--- @return integer ropeId
function ropeCreateLine(startCoords, endCoords, opts)
startCoords = type(startCoords) == "number" and GetEntityCoords(startCoords) or startCoords
endCoords = type(endCoords) == "number" and GetEntityCoords(endCoords) or endCoords
opts = opts or {}
local length = #(startCoords - endCoords)
local mid = (startCoords + endCoords) * 0.5
local ropeType = opts.ropeType or 1 -- 0..7 (see ropedata.xml types)
local initLength = length + (opts.slack or 0.0)
local maxLength = initLength -- allow droop equal to init
local minLength = 0.0
local lengthChangeRate = opts.lengthChangeRate or 1.0
local collisionOn = (opts.collision ~= false)
local lockFromFront = (opts.lockFromFront == true)
local timeMultiplier = opts.timeMultiplier or 1.0
local breakable = (opts.breakable == true)
local rope = AddRope(mid.x, mid.y, mid.z, 0.0, 0.0, 0.0, maxLength, ropeType, initLength, minLength, lengthChangeRate, false, collisionOn, lockFromFront, timeMultiplier, breakable, 0)
if not rope or rope == 0 or not DoesRopeExist(rope) then
debugPrint("^1AddRope failed")
return nil
end
-- Optional preset (e.g., "ropeFamily3") if provided.
if opts.preset then
-- Best-effort; if invalid it just won't change.
pcall(function() LoadRopeData(rope, tostring(opts.preset)) end)
end
ActivatePhysics(rope)
-- Pin both ends to the given coords.
local count = GetRopeVertexCount(rope)
if count and count >= 2 then
PinRopeVertex(rope, 0, startCoords.x, startCoords.y, startCoords.z)
PinRopeVertex(rope, count - 1, endCoords.x, endCoords.y, endCoords.z)
end
local id = registerRope(rope, startCoords, endCoords, {
ropeType = ropeType,
lengthChangeRate = lengthChangeRate,
breakable = breakable
})
return id
end
--- Delete and unregister a rope.
--- @param id integer
function ropeDelete(id)
local rec, err = resolve(id)
if not rec then return false, err end
local rope = rec.handle
if DoesRopeExist(rope) then
DeleteRope(rope)
end
RopeCache.byHandle[rope] = nil
RopeCache.byId[id] = nil
debugPrint(("deleted rope id=%s"):format(id))
maybeUnloadTextures()
return true
end
--- Force rope to a specific length (instant snap).
--- @param id integer
--- @param newLength number
function ropeSetLength(id, newLength)
local rec, err = resolve(id)
if not rec then return false, err end
RopeForceLength(rec.handle, newLength)
return true
end
--- Smoothly wind the rope (shorten over time).
--- @param id integer
function ropeStartWinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StartRopeWinding(rec.handle)
return true
end
--- Stop winding (if winding).
function ropeStopWinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StopRopeWinding(rec.handle)
return true
end
--- Smoothly unwind the rope from the front (lengthen over time).
function ropeStartUnwinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StartRopeUnwindingFront(rec.handle)
return true
end
--- Stop unwinding (if unwinding).
function ropeStopUnwinding(id)
local rec, err = resolve(id)
if not rec then return false, err end
StopRopeUnwindingFront(rec.handle)
return true
end
--- Change the wind speed (length change rate).
--- @param id integer
--- @param rate number (units per sec; try 0.5..5.0)
function ropeSetRate(id, rate)
local rec, err = resolve(id)
if not rec then return false, err end
SetRopeLengthChangeRate(rec.handle, rate)
rec.rate = rate
return true
end
--- Move end endpoint to a new coordinate (re-pins the vertex).
--- @param id integer
--- @param pos vector3|table
function ropeMoveEnd(id, pos)
local rec, err = resolve(id)
if not rec then return false, err end
pos = type(pos) == "number" and GetEntityCoords(pos) or pos
local rope = rec.handle
local count = GetRopeVertexCount(rope)
if not count or count < 2 then return false, "invalid vertex count" end
PinRopeVertex(rope, count - 1, pos.x, pos.y, pos.z)
rec.endCoord = pos
return true
end
--- Move start endpoint to a new coordinate (re-pins the vertex).
--- @param id integer
--- @param pos vector3|table
function ropeMoveStart(id, pos)
local rec, err = resolve(id)
if not rec then return false, err end
pos = type(pos) == "number" and GetEntityCoords(pos) or pos
local rope = rec.handle
local count = GetRopeVertexCount(rope)
if not count or count < 2 then return false, "invalid vertex count" end
PinRopeVertex(rope, 0, pos.x, pos.y, pos.z)
rec.startCoord = pos
return true
end
--- Re-pin both endpoints in one call.
function ropeSetEnds(ropeId, startCoord, endCoord)
startCoord = type(startCoord) == "number" and GetEntityCoords(startCoord) or startCoord
endCoord = type(endCoord) == "number" and GetEntityCoords(endCoord) or endCoord
local rec, err = resolve(ropeId)
if not rec then return false, err end
local rope = rec.handle
local count = GetRopeVertexCount(rope)
if not count or count < 2 then
return false, "invalid vertex count"
end
PinRopeVertex(rope, 0, startCoord.x, startCoord.y, startCoord.z)
PinRopeVertex(rope, count - 1, endCoord.x, endCoord.y, endCoord.z)
rec.startCoord = startCoord
rec.endCoord = endCoord
return true
end
function ropeExists(id)
local rec = RopeCache.byId[id]
return rec and DoesRopeExist(rec.handle) or false
end
onResourceStart(function()
loadRopeTextures()
end)
onResourceStop(function()
for id, rec in pairs(RopeCache.byId) do
if rec.handle and DoesRopeExist(rec.handle) then
DeleteRope(rec.handle)
end
RopeCache.byHandle[rec.handle] = nil
RopeCache.byId[id] = nil
end
maybeUnloadTextures()
end)
end

View File

@@ -16,14 +16,26 @@ local hungerThirstFunc = {
setThirst =
function(src, thirst)
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, thirst)
local newThirst = Player.PlayerData.metadata.thirst + thirst
newThirst = (newThirst >= 100.0 and 100.0) or (newThirst <= 0 and 0) or newThirst
Player.Functions.SetMetaData('thirst', newThirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, newThirst)
end,
setHunger =
function(src, hunger)
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.thirst)
local newHunger = Player.PlayerData.metadata.hunger + hunger
newHunger = (newHunger >= 100.0 and 100.0) or (newHunger <= 0 and 0) or newHunger
Player.Functions.SetMetaData('hunger', newHunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, newHunger, Player.PlayerData.metadata.thirst)
end,
setStress =
function(src, stress)
local Player = Core.Functions.GetPlayer(src)
local newStress = Player.PlayerData.metadata.stress + stress
newStress = (newStress >= 100.0 and 100.0)or (newStress <= 0 and 0) or newStress
Player.Functions.SetMetaData('stress', newStress)
TriggerClientEvent('hud:client:UpdateStress', src, newStress)
end,
},
@@ -31,14 +43,26 @@ local hungerThirstFunc = {
setThirst =
function(src, thirst)
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, thirst)
local newThirst = Player.PlayerData.metadata.thirst + thirst
newThirst = (newThirst >= 100.0 and 100.0) or (newThirst <= 0 and 0) or newThirst
Player.Functions.SetMetaData('thirst', newThirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, newThirst)
end,
setHunger =
function(src, hunger)
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.thirst)
local newHunger = Player.PlayerData.metadata.hunger + hunger
newHunger = (newHunger >= 100.0 and 100.0) or (newHunger <= 0 and 0) or newHunger
Player.Functions.SetMetaData('hunger', newHunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, newHunger, Player.PlayerData.metadata.thirst)
end,
setStress =
function(src, stress)
local Player = Core.Functions.GetPlayer(src)
local newStress = Player.PlayerData.metadata.stress + stress
newStress = (newStress >= 100.0 and 100.0)or (newStress <= 0 and 0) or newStress
Player.Functions.SetMetaData('stress', newStress)
TriggerClientEvent('hud:client:UpdateStress', src, newStress)
end,
},
@@ -46,25 +70,41 @@ local hungerThirstFunc = {
setThirst =
function(src, thirst)
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('thirst', thirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, thirst)
local newThirst = Player.PlayerData.metadata.thirst + thirst
newThirst = (newThirst >= 100.0 and 100.0) or (newThirst <= 0 and 0) or newThirst
Player.Functions.SetMetaData('thirst', newThirst)
TriggerClientEvent("hud:client:UpdateNeeds", src, Player.PlayerData.metadata.hunger, newThirst)
end,
setHunger =
function(src, hunger)
local Player = Core.Functions.GetPlayer(src)
Player.Functions.SetMetaData('hunger', hunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, hunger, Player.PlayerData.metadata.thirst)
local newHunger = Player.PlayerData.metadata.hunger + hunger
newHunger = (newHunger >= 100.0 and 100.0) or (newHunger <= 0 and 0) or newHunger
Player.Functions.SetMetaData('hunger', newHunger)
TriggerClientEvent("hud:client:UpdateNeeds", src, newHunger, Player.PlayerData.metadata.thirst)
end,
setStress =
function(src, stress)
local Player = Core.Functions.GetPlayer(src)
local newStress = Player.PlayerData.metadata.stress + stress
newStress = (newStress >= 100.0 and 100.0) or (newStress <= 0 and 0) or newStress
Player.Functions.SetMetaData('stress', newStress)
TriggerClientEvent('hud:client:UpdateStress', src, newStress)
end,
},
{ framework = ESXExport,
setThirst =
function(src, thirst)
TriggerClientEvent('esx_status:add', src, 'thirst', thirst)
TriggerClientEvent('esx_status:add', src, 'thirst', tonumber(thirst) * 10000)
end,
setHunger =
function(src, hunger)
TriggerClientEvent('esx_status:add', src, 'hunger', hunger)
TriggerClientEvent('esx_status:add', src, 'hunger', tonumber(hunger) * 10000)
end,
setStress =
function(src, stress)
TriggerClientEvent("esx_status:add", src, "stress", tonumber(stress) * 10000)
end,
},
}
@@ -114,6 +154,26 @@ function setHunger(src, hunger)
end
end
--- Sets the player's stress level.
---
--- @param src number The player's server ID.
--- @param stress number The new stress level.
---
--- @usage
--- ```lua
--- setStress(playerId, 60)
--- ```
function setStress(src, stress)
for i = 1, #hungerThirstFunc do
local framework = hungerThirstFunc[i]
if isStarted(framework.framework) then
debugPrint("^4Debug^7: ^2Adding ^3"..framework.framework.." ^2stress^7: ^3"..stress.." ^2to player^7: ^3"..src.."^7")
framework.setStress(src, stress)
return
end
end
end
--- Server event handler for urinal usage.
--- Decreases player's thirst by a random amount.
RegisterNetEvent(getScript()..":server:Urinal", function()
@@ -372,19 +432,21 @@ local hasGroupFunc = {
local hasJobFlag, duty = false, true
local playerInfo = GetPlayer(src)
local jobinfo = playerInfo.job or playerInfo.PlayerData.job
if jobinfo.name == group then
if jobinfo and jobinfo.name == group then
hasJobFlag = true
duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then
hasJobFlag = false
end
return hasJobFlag, duty
end
local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang
if ganginfo.name == group then
if ganginfo and ganginfo.name == group then
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then
hasJobFlag = false
end
return hasJobFlag, duty
end
return hasJobFlag, duty
end,
@@ -396,7 +458,7 @@ local hasGroupFunc = {
local hasJobFlag, duty = false, true
local playerInfo = GetPlayer(src)
local jobinfo = playerInfo.job or playerInfo.PlayerData.job
if jobinfo.name == group then
if jobinfo and jobinfo.name == group then
hasJobFlag = true
duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then
@@ -404,7 +466,7 @@ local hasGroupFunc = {
end
end
local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang
if ganginfo.name == group then
if ganginfo and ganginfo.name == group then
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then
hasJobFlag = false
@@ -434,26 +496,6 @@ local hasGroupFunc = {
end,
},
{ framework = OXCoreExport,
hasGroup =
function(group, grade, src)
local hasJobFlag, duty = false, true
if src then
local chunk = assert(load(LoadResourceFile('ox_core', ('imports/%s.lua'):format('server')), ('@@ox_core/%s'):format(file)))
chunk()
local player = Ox.GetPlayer(src)
for k, v in pairs(player.getGroups()) do
if k == group then hasJobFlag = true end
end
end
local info = OxPlayer.getGroups()
for k, v in pairs(info) do
if k == group then hasJobFlag = true break end
end
return hasJobFlag, duty
end,
},
{ framework = ESXExport,
hasGroup =
function(group, grade, src)
@@ -479,7 +521,7 @@ local hasGroupFunc = {
local hasJobFlag, duty = false, true
local playerInfo = GetPlayer(src)
local jobinfo = playerInfo.job or playerInfo.PlayerData.job
if jobinfo.name == group then
if jobinfo and jobinfo.name == group then
hasJobFlag = true
duty = jobinfo.onduty
if grade and not (grade <= jobinfo.grade.level) then
@@ -487,7 +529,7 @@ local hasGroupFunc = {
end
end
local ganginfo = playerInfo.gang or playerInfo.PlayerData.gang
if ganginfo.name == group then
if ganginfo and ganginfo.name == group then
hasJobFlag = true
if grade and not (grade <= ganginfo.grade.level) then
hasJobFlag = false

View File

@@ -12,52 +12,6 @@
]]
local societyFunc = {
{ bankName = "qb-banking",
getAccount =
function(society)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
return exports["qb-banking"]:GetAccountBalance(society)
end,
chargeSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0) Wait(150) -- make new account if return "null"
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0) Wait(150) -- make new account if return "null"
end
end
exports["qb-banking"]:RemoveMoney(society, amount)
end,
fundSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
exports["qb-banking"]:AddMoney(society, amount)
end,
},
{ bankName = "Renewed-Banking",
getAccount =
function(society)
@@ -129,6 +83,115 @@ local societyFunc = {
end
end,
},
{ bankName = "qb-banking",
getAccount =
function(society)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
return exports["qb-banking"]:GetAccountBalance(society)
end,
chargeSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0) Wait(150) -- make new account if return "null"
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0) Wait(150) -- make new account if return "null"
end
end
exports["qb-banking"]:RemoveMoney(society, amount)
end,
fundSociety =
function(society, amount)
if not exports["qb-banking"]:GetAccount(society) then
if Jobs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateJobAccount(society, 0)
Wait(150)
elseif Gangs[society] then
print("^6Bridge^7: ^2Making new bank account in ^7'^3qb-banking^7' ^2for ^7'^3"..society.."^7'")
exports["qb-banking"]:CreateGangAccount(society, 0)
Wait(150)
end
end
exports["qb-banking"]:AddMoney(society, amount)
end,
},
{ bankName = "esx_society",
getAccount =
function(society)
local checkExist = exports.esx_society:GetSociety(society)
if checkExist == nil then
print("^6Bridge^7: ^2Making new bank account in ^7'^3esx_society^7' ^2for ^7'^3"..society.."^7'")
exports.esx_society:registerSociety(
society,
Gangs[society] and Gangs[society].label or Jobs[society] and Jobs[society].label,
society,
society,
society,
{type = "public"}
)
end
local p = promise.new()
TriggerEvent('esx_addonaccount:getSharedAccount', checkExist.account, function(account)
p:resolve(account.money)
end)
local newAmount = Citizen.Await(p)
return newAmount
end,
chargeSociety =
function(society, amount)
local checkExist = exports.esx_society:GetSociety(society)
if checkExist == nil then
print("^6Bridge^7: ^2Making new bank account in ^7'^3esx_society^7' ^2for ^7'^3"..society.."^7'")
exports.esx_society:registerSociety(
society,
Gangs[society] and Gangs[society].label or Jobs[society] and Jobs[society].label,
society,
society,
society,
{type = "public"}
)
end
TriggerEvent('esx_addonaccount:getSharedAccount', checkExist.account, function(account)
if amount > 0 and account.money >= amount then
account.removeMoney(amount)
end
end)
end,
fundSociety =
function(society, amount)
local checkExist = exports.esx_society:GetSociety(society)
if checkExist == nil then
print("^6Bridge^7: ^2Making new bank account in ^7'^3esx_society^7' ^2for ^7'^3"..society.."^7'")
exports.esx_society:registerSociety(
society,
Gangs[society] and Gangs[society].label or Jobs[society] and Jobs[society].label,
society,
society,
society,
{type = "public"}
)
end
TriggerEvent('esx_addonaccount:getSharedAccount', checkExist.account, function(account)
account.addMoney(amount)
end)
end,
},
}
@@ -200,14 +263,4 @@ function fundSociety(society, amount)
end
print("^1Error^7: ^3FundSociety^7: ^2No supported banking script found")
end
-- other
if isStarted("esx_society") then
createCallback(getScript()..":getESXSocietyAccount", function(source, society)
-- Example query adjust table/field names to match your esx_society implementation.
local result = MySQL.scalar.await('SELECT money FROM society_money WHERE society = ?', { society })
return result or 0
end)
end

View File

@@ -33,7 +33,7 @@ local targetFunc = {
canInteract = opts[i].canInteract or nil,
}
end
exports[OXTargetExport]:addLocalEntity(entity, options)
return exports[OXTargetExport]:addLocalEntity(entity, options)
end,
boxTarget =
@@ -105,7 +105,7 @@ local targetFunc = {
canInteract = opts[i].canInteract or nil,
}
end
exports[OXTargetExport]:addModel(models, options)
return exports[OXTargetExport]:addModel(models, options)
end,
removeTargetEntity =
@@ -128,7 +128,7 @@ local targetFunc = {
entityTarget =
function(entity, opts, dist)
local options = { options = opts, distance = dist }
exports[QBTargetExport]:AddTargetEntity(entity, options)
return exports[QBTargetExport]:AddTargetEntity(entity, options)
end,
boxTarget =
@@ -148,7 +148,7 @@ local targetFunc = {
modelTarget =
function(models, opts, dist)
local options = { options = opts, distance = dist }
exports[QBTargetExport]:AddTargetModel(models, options)
return exports[QBTargetExport]:AddTargetModel(models, options)
end,
removeTargetEntity =
@@ -213,11 +213,10 @@ local targetFunc = {
-- Tables for storing created targets for the fallback system and zone management.
local TextTargets = {} -- For fallback DrawText3D targets.
local targetEntities = {} -- For entity targets.
local boxTargets = {} -- For box-shaped zone targets.
local circleTargets = {} -- For circular zone targets.
local modelTargets = {}
-------------------------------------------------------------
-- Entity Target Creation
-------------------------------------------------------------
@@ -442,7 +441,7 @@ function createModelTarget(models, opts, dist)
if isStarted(script.targetName) then
debugPrint("^6Bridge^7: ^2Creating new ^3Model ^2target with ^6"..script.targetName.."^7")
local target = script.modelTarget(models, opts, dist)
circleTargets[#circleTargets + 1] = target
modelTargets[#modelTargets + 1] = target
return target
end
end
@@ -553,7 +552,7 @@ local function CleanupTargets()
if isStarted(OXTargetExport) then
exports[OXTargetExport]:removeZone(boxTargets[i], true)
elseif isStarted(QBTargetExport) then
exports[QBTargetExport]:RemoveZone(boxTargets[i].name)
exports[QBTargetExport]:RemoveZone(boxTargets[i])
end
end
-- Remove circle zone targets.
@@ -561,7 +560,7 @@ local function CleanupTargets()
if isStarted(OXTargetExport) then
exports[OXTargetExport]:removeZone(circleTargets[i], true)
elseif isStarted(QBTargetExport) then
exports[QBTargetExport]:RemoveZone(circleTargets[i].name)
exports[QBTargetExport]:RemoveZone(circleTargets[i])
end
end
end

View File

@@ -1,4 +1,3 @@
--- Registers a command with the active command system.
--- This function supports multiple command systems (OXLib, qb-core, ESX Legacy).
---
@@ -47,7 +46,7 @@ function registerCommand(command, options)
optionTable.helpInfo,
optionTable.subText,
optionTable.argsRequired,
optionTable.funt,
optionTable.funct,
optionTable.restriction or nil
)
@@ -57,7 +56,7 @@ function registerCommand(command, options)
optionTable.helpInfo,
optionTable.subText,
optionTable.argsRequired,
optionTable.funt,
optionTable.funct,
optionTable.restriction or nil
)

View File

@@ -176,6 +176,7 @@ for _, v in pairs({ -- This is a specific load order
'scaleEntity.lua',
'vehicles.lua',
'effects.lua',
'make/ropeControl.lua',
--'warmenu.lua',
'_authToken.lua',

View File

@@ -1,17 +1,13 @@
2.1.01
2.1.03
- Script Overhaul, replace whole script
- Very alpha support for VorpCore
- Improve security
- Removal of Quasar Script Support
- Support Tgiann-inv's new item system
- Refactor most multi-functions to be more optimized and smarter
- Added multifunction bossmenu and clothing functions
- Added ability to supress update notifcations in fxmanfiest.lua
- Added coordinate checks to registerStash, registerShop and sellShop
- Optimize and Enhance built-in progressbar + target functions
- Improve weird multicharacter issue triggering onPlayerLoaded more than once
- Scripts that use this will need updating too, as things like stashes won't open
- **Hotfix for stores and stashes not registering properly**
- Fix hunger and thirst math (add instead of set)
- Fix cleanup of targets qb-targets on unload
- Add support for new jim-shops exploit protection
- Add full support for esx_society (fixes esx bossmenu errors)
- Fix possible issue with qb-core /command registering
- Make ox_lib progressbars return false correctly
- Fix ox_inv players current weight checks
- User alternate function for inventory retreival for CodeM Inv
- Rework _loaders.lua tobe more organised/optimizied
https://github.com/jimathy/jim_bridge/releases/latest