mirror of
https://github.com/qbcore-fivem/qb-core.git
synced 2026-08-28 17:01:16 +00:00
Refactor core structure and notification UI
Major refactor to centralize QBCore and replace the web UI stack: - Move QBConfig into a unified QBCore.Config and initialize QBCore.PlayerData; add shared/functions.lua. - Remove legacy client/main.lua and server/main.lua exports and update fxmanifest to include shared/functions and drop those main scripts. - Update client event handling: adapt player data events to QBCore:Client:OnPlayerUpdated and trigger job/gang update events; remove deprecated exploitable handlers. - Web UI rewrite: remove Vue/Quasar dependency and config module; implement a lightweight vanilla JS notification system (html/js/app.js) with updated html and css assets, plus drawtext tweaks. - CSS overhaul for notification styling and animations; HTML head/meta/font cleanup. - Server fixes: use QBCore.Shared.Locations in teleport command and strengthen numeric parsing/validation for coords. - Add .gitattributes for consistent text/eol handling and small code cleanups (thread/comment removal). These changes consolidate config/shared logic under QBCore, simplify the frontend dependencies, and fix a few parsing/event issues.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
# Lua and web files - always treat as text
|
||||
*.lua text eol=lf
|
||||
*.js text eol=lf
|
||||
*.html text eol=lf
|
||||
*.css text eol=lf
|
||||
*.json text eol=lf
|
||||
*.xml text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.md text eol=lf
|
||||
+1
-1
@@ -29,7 +29,7 @@ local function changeText(text, position)
|
||||
end
|
||||
|
||||
local function keyPressed()
|
||||
CreateThread(function() -- Not sure if a thread is needed but why not eh?
|
||||
CreateThread(function()
|
||||
SendNUIMessage({
|
||||
action = 'KEY_PRESSED',
|
||||
})
|
||||
|
||||
+9
-18
@@ -1,6 +1,3 @@
|
||||
-- Player load and unload handling
|
||||
-- New method for checking if logged in across all scripts (optional)
|
||||
-- if LocalPlayer.state['isLoggedIn'] then
|
||||
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
||||
ShutdownLoadingScreenNui()
|
||||
LocalPlayer.state:set('isLoggedIn', true, false)
|
||||
@@ -17,6 +14,7 @@ RegisterNetEvent('QBCore:Client:PvpHasToggled', function(pvp_state)
|
||||
SetCanAttackFriendly(PlayerPedId(), pvp_state, false)
|
||||
NetworkSetFriendlyFireOption(pvp_state)
|
||||
end)
|
||||
|
||||
-- Teleport Commands
|
||||
|
||||
RegisterNetEvent('QBCore:Command:TeleportToPlayer', function(coords)
|
||||
@@ -182,30 +180,23 @@ end)
|
||||
|
||||
-- Other stuff
|
||||
|
||||
RegisterNetEvent('QBCore:Player:SetPlayerData', function(val)
|
||||
RegisterNetEvent('QBCore:Client:OnPlayerUpdated', function(key, val)
|
||||
if key == 'all' then
|
||||
QBCore.PlayerData = val
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Player:UpdatePlayerDataField', function(key, val)
|
||||
if QBCore.PlayerData and key then
|
||||
TriggerEvent('QBCore:Player:SetPlayerData', val)
|
||||
TriggerEvent('QBCore:Client:OnJobUpdate', val.job)
|
||||
TriggerEvent('QBCore:Client:OnGangUpdate', val.gang)
|
||||
elseif QBCore.PlayerData and key then
|
||||
QBCore.PlayerData[key] = val
|
||||
if key == 'job' then TriggerEvent('QBCore:Client:OnJobUpdate', val) end
|
||||
if key == 'gang' then TriggerEvent('QBCore:Client:OnGangUpdate', val) end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Player:UpdatePlayerData', function()
|
||||
TriggerServerEvent('QBCore:UpdatePlayer')
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Notify', function(text, type, length, icon)
|
||||
QBCore.Functions.Notify(text, type, length, icon)
|
||||
end)
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon.
|
||||
RegisterNetEvent('QBCore:Client:UseItem', function(item)
|
||||
QBCore.Debug(string.format('%s triggered QBCore:Client:UseItem by ID %s with the following data. This event is deprecated due to exploitation, and will be removed soon. Check qb-inventory for the right use on this event.', GetInvokingResource(), GetPlayerServerId(PlayerId())))
|
||||
QBCore.Debug(item)
|
||||
end)
|
||||
|
||||
RegisterNUICallback('getNotifyConfig', function(_, cb)
|
||||
cb(QBCore.Config.Notify)
|
||||
end)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
QBCore.PlayerData = {}
|
||||
QBCore.Functions = {}
|
||||
|
||||
-- Callbacks
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
QBCore = {}
|
||||
QBCore.PlayerData = {}
|
||||
QBCore.Config = QBConfig
|
||||
QBCore.Shared = QBShared
|
||||
QBCore.ClientCallbacks = {}
|
||||
QBCore.ServerCallbacks = {}
|
||||
|
||||
-- Get the full QBCore object (default behavior):
|
||||
-- local QBCore = GetCoreObject()
|
||||
|
||||
-- Get only specific parts of QBCore:
|
||||
-- local QBCore = GetCoreObject({'Players', 'Config'})
|
||||
|
||||
local function GetCoreObject(filters)
|
||||
if not filters then return QBCore end
|
||||
local results = {}
|
||||
for i = 1, #filters do
|
||||
local key = filters[i]
|
||||
if QBCore[key] then
|
||||
results[key] = QBCore[key]
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
exports('GetCoreObject', GetCoreObject)
|
||||
|
||||
local function GetSharedItems()
|
||||
return QBShared.Items
|
||||
end
|
||||
exports('GetSharedItems', GetSharedItems)
|
||||
|
||||
local function GetSharedVehicles()
|
||||
return QBShared.Vehicles
|
||||
end
|
||||
exports('GetSharedVehicles', GetSharedVehicles)
|
||||
|
||||
local function GetSharedWeapons()
|
||||
return QBShared.Weapons
|
||||
end
|
||||
exports('GetSharedWeapons', GetSharedWeapons)
|
||||
|
||||
local function GetSharedJobs()
|
||||
return QBShared.Jobs
|
||||
end
|
||||
exports('GetSharedJobs', GetSharedJobs)
|
||||
|
||||
local function GetSharedGangs()
|
||||
return QBShared.Gangs
|
||||
end
|
||||
exports('GetSharedGangs', GetSharedGangs)
|
||||
+35
-34
@@ -1,30 +1,31 @@
|
||||
QBConfig = {}
|
||||
QBCore = {}
|
||||
QBCore.Config = {}
|
||||
|
||||
QBConfig.MaxPlayers = GetConvarInt('sv_maxclients', 48) -- Gets max players from config file, default 48
|
||||
QBConfig.DefaultSpawn = vector4(-1035.71, -2731.87, 12.86, 0.0)
|
||||
QBConfig.UpdateInterval = 5 -- how often to update player data in minutes
|
||||
QBConfig.StatusInterval = 5000 -- how often to check hunger/thirst status in milliseconds
|
||||
QBCore.Config.MaxPlayers = GetConvarInt('sv_maxclients', 48) -- Gets max players from config file, default 48
|
||||
QBCore.Config.DefaultSpawn = vector4(-1035.71, -2731.87, 12.86, 0.0)
|
||||
QBCore.Config.UpdateInterval = 5 -- how often to update player data in minutes
|
||||
QBCore.Config.StatusInterval = 5000 -- how often to check hunger/thirst status in milliseconds
|
||||
|
||||
QBConfig.Money = {}
|
||||
QBConfig.Money.MoneyTypes = { cash = 500, bank = 5000, crypto = 0 } -- type = startamount - Add or remove money types for your server (for ex. blackmoney = 0), remember once added it will not be removed from the database!
|
||||
QBConfig.Money.DontAllowMinus = { 'cash', 'crypto' } -- Money that is not allowed going in minus
|
||||
QBConfig.Money.MinusLimit = -5000 -- The maximum amount you can be negative
|
||||
QBConfig.Money.PayCheckTimeOut = 10 -- The time in minutes that it will give the paycheck
|
||||
QBConfig.Money.PayCheckSociety = false -- If true paycheck will come from the society account that the player is employed at, requires qb-management
|
||||
QBCore.Config.Money = {}
|
||||
QBCore.Config.Money.MoneyTypes = { cash = 500, bank = 5000, crypto = 0 } -- type = startamount - Add or remove money types for your server (for ex. blackmoney = 0), remember once added it will not be removed from the database!
|
||||
QBCore.Config.Money.DontAllowMinus = { 'cash', 'crypto' } -- Money that is not allowed going in minus
|
||||
QBCore.Config.Money.MinusLimit = -5000 -- The maximum amount you can be negative
|
||||
QBCore.Config.Money.PayCheckTimeOut = 10 -- The time in minutes that it will give the paycheck
|
||||
QBCore.Config.Money.PayCheckSociety = false -- If true paycheck will come from the society account that the player is employed at, requires qb-management
|
||||
|
||||
QBConfig.Player = {}
|
||||
QBConfig.Player.HungerRate = 4.2 -- Rate at which hunger goes down.
|
||||
QBConfig.Player.ThirstRate = 3.8 -- Rate at which thirst goes down.
|
||||
QBConfig.Player.Bloodtypes = {
|
||||
QBCore.Config.Player = {}
|
||||
QBCore.Config.Player.HungerRate = 4.2 -- Rate at which hunger goes down.
|
||||
QBCore.Config.Player.ThirstRate = 3.8 -- Rate at which thirst goes down.
|
||||
QBCore.Config.Player.Bloodtypes = {
|
||||
'A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-',
|
||||
}
|
||||
|
||||
QBConfig.Player.PlayerDefaults = {
|
||||
QBCore.Config.Player.PlayerDefaults = {
|
||||
citizenid = function() return QBCore.Player.CreateCitizenId() end,
|
||||
cid = 1,
|
||||
money = function()
|
||||
local moneyDefaults = {}
|
||||
for moneytype, startamount in pairs(QBConfig.Money.MoneyTypes) do
|
||||
for moneytype, startamount in pairs(QBCore.Config.Money.MoneyTypes) do
|
||||
moneyDefaults[moneytype] = startamount
|
||||
end
|
||||
return moneyDefaults
|
||||
@@ -76,7 +77,7 @@ QBConfig.Player.PlayerDefaults = {
|
||||
rep = {},
|
||||
currentapartment = nil,
|
||||
callsign = 'NO CALLSIGN',
|
||||
bloodtype = function() return QBConfig.Player.Bloodtypes[math.random(1, #QBConfig.Player.Bloodtypes)] end,
|
||||
bloodtype = function() return QBCore.Config.Player.Bloodtypes[math.random(1, #QBCore.Config.Player.Bloodtypes)] end,
|
||||
fingerprint = function() return QBCore.Player.CreateFingerId() end,
|
||||
walletid = function() return QBCore.Player.CreateWalletId() end,
|
||||
criminalrecord = {
|
||||
@@ -100,27 +101,27 @@ QBConfig.Player.PlayerDefaults = {
|
||||
InstalledApps = {}
|
||||
}
|
||||
},
|
||||
position = QBConfig.DefaultSpawn,
|
||||
position = QBCore.Config.DefaultSpawn,
|
||||
items = {},
|
||||
}
|
||||
|
||||
QBConfig.Server = {} -- General server config
|
||||
QBConfig.Server.Closed = false -- Set server closed (no one can join except people with ace permission 'qbadmin.join')
|
||||
QBConfig.Server.ClosedReason = 'Server Closed' -- Reason message to display when people can't join the server
|
||||
QBConfig.Server.Uptime = 0 -- Time the server has been up.
|
||||
QBConfig.Server.Whitelist = false -- Enable or disable whitelist on the server
|
||||
QBConfig.Server.WhitelistPermission = 'admin' -- Permission that's able to enter the server when the whitelist is on
|
||||
QBConfig.Server.PVP = true -- Enable or disable pvp on the server (Ability to shoot other players)
|
||||
QBConfig.Server.Discord = '' -- Discord invite link
|
||||
QBConfig.Server.CheckDuplicateLicense = true -- Check for duplicate rockstar license on join
|
||||
QBConfig.Server.Permissions = { 'god', 'admin', 'mod' } -- Add as many groups as you want here after creating them in your server.cfg
|
||||
QBCore.Config.Server = {} -- General server config
|
||||
QBCore.Config.Server.Closed = false -- Set server closed (no one can join except people with ace permission 'qbadmin.join')
|
||||
QBCore.Config.Server.ClosedReason = 'Server Closed' -- Reason message to display when people can't join the server
|
||||
QBCore.Config.Server.Uptime = 0 -- Time the server has been up.
|
||||
QBCore.Config.Server.Whitelist = false -- Enable or disable whitelist on the server
|
||||
QBCore.Config.Server.WhitelistPermission = 'admin' -- Permission that's able to enter the server when the whitelist is on
|
||||
QBCore.Config.Server.PVP = true -- Enable or disable pvp on the server (Ability to shoot other players)
|
||||
QBCore.Config.Server.Discord = '' -- Discord invite link
|
||||
QBCore.Config.Server.CheckDuplicateLicense = true -- Check for duplicate rockstar license on join
|
||||
QBCore.Config.Server.Permissions = { 'god', 'admin', 'mod' } -- Add as many groups as you want here after creating them in your server.cfg
|
||||
|
||||
QBConfig.Commands = {} -- Command Configuration
|
||||
QBConfig.Commands.OOCColor = { 255, 151, 133 } -- RGB color code for the OOC command
|
||||
QBCore.Config.Commands = {} -- Command Configuration
|
||||
QBCore.Config.Commands.OOCColor = { 255, 151, 133 } -- RGB color code for the OOC command
|
||||
|
||||
QBConfig.Notify = {}
|
||||
QBCore.Config.Notify = {}
|
||||
|
||||
QBConfig.Notify.NotificationStyling = {
|
||||
QBCore.Config.Notify.NotificationStyling = {
|
||||
group = false, -- Allow notifications to stack with a badge instead of repeating
|
||||
position = 'right', -- top-left | top-right | bottom-left | bottom-right | top | bottom | left | right | center
|
||||
progress = true -- Display Progress Bar
|
||||
@@ -129,7 +130,7 @@ QBConfig.Notify.NotificationStyling = {
|
||||
-- These are how you define different notification variants
|
||||
-- The "color" key is background of the notification
|
||||
-- The "icon" key is the css-icon code, this project uses `Material Icons` & `Font Awesome`
|
||||
QBConfig.Notify.VariantDefinitions = {
|
||||
QBCore.Config.Notify.VariantDefinitions = {
|
||||
success = {
|
||||
classes = 'success',
|
||||
icon = 'check_circle'
|
||||
|
||||
+1
-2
@@ -11,6 +11,7 @@ shared_scripts {
|
||||
'locale/en.lua',
|
||||
'locale/*.lua',
|
||||
'shared/main.lua',
|
||||
'shared/functions.lua',
|
||||
'shared/items.lua',
|
||||
'shared/jobs.lua',
|
||||
'shared/vehicles.lua',
|
||||
@@ -20,7 +21,6 @@ shared_scripts {
|
||||
}
|
||||
|
||||
client_scripts {
|
||||
'client/main.lua',
|
||||
'client/functions.lua',
|
||||
'client/loops.lua',
|
||||
'client/events.lua',
|
||||
@@ -29,7 +29,6 @@ client_scripts {
|
||||
|
||||
server_scripts {
|
||||
'@oxmysql/lib/MySQL.lua',
|
||||
'server/main.lua',
|
||||
'server/functions.lua',
|
||||
'server/player.lua',
|
||||
'server/events.lua',
|
||||
|
||||
+3
-30
@@ -1,35 +1,8 @@
|
||||
:root {
|
||||
/* Typography */
|
||||
--font-primary: "Exo 2", sans-serif;
|
||||
--font-weight-regular: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-bold: 700;
|
||||
--font-weight-light: 300;
|
||||
/* Colors */
|
||||
--md-primary: #1c75d2;
|
||||
--md-primary-container: #6facec;
|
||||
--md-error: #c10114;
|
||||
--md-error-container: #fe4255;
|
||||
--md-success: #20bb44;
|
||||
--md-success-container: #6ae587;
|
||||
--md-warning: #ff9800;
|
||||
--md-warning-container: #ffc107;
|
||||
--md-info: #2197f2;
|
||||
--md-info-container: #7ac1f7;
|
||||
--md-surface: #fffbff;
|
||||
--md-on-surface: #1c1b1f;
|
||||
|
||||
/* Custom Variables */
|
||||
--primary-bg: rgba(23, 23, 23, 90%);
|
||||
--active-bg: var(--md-error);
|
||||
--font-color: white;
|
||||
|
||||
/* Elevation */
|
||||
--primary-bg: #211f26;
|
||||
--active-bg: #c10114;
|
||||
--font-color: #e6e1e5;
|
||||
--md-elevation-1: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);
|
||||
|
||||
/* Border Radius */
|
||||
--md-radius-small: 5px;
|
||||
--md-radius-medium: 10px;
|
||||
--md-radius-extra-small: 0.15rem;
|
||||
}
|
||||
|
||||
|
||||
+93
-117
@@ -1,49 +1,8 @@
|
||||
:root {
|
||||
/* Typography */
|
||||
--font-primary: "Exo 2", sans-serif;
|
||||
--font-weight-regular: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-bold: 700;
|
||||
--font-weight-light: 300;
|
||||
|
||||
/* Colors */
|
||||
--md-primary: #0061a4;
|
||||
--md-on-primary: #ffffff;
|
||||
--md-primary-container: #d1e4ff;
|
||||
--md-on-primary-container: #001d36;
|
||||
|
||||
--md-error: #ba1a1a;
|
||||
--md-on-error: #ffffff;
|
||||
--md-error-container: #ffdad6;
|
||||
--md-on-error-container: #410002;
|
||||
|
||||
--md-success: #006e1c;
|
||||
--md-on-success: #ffffff;
|
||||
--md-success-container: #9df996;
|
||||
--md-on-success-container: #002106;
|
||||
|
||||
--md-warning: #7d5800;
|
||||
--md-on-warning: #ffffff;
|
||||
--md-warning-container: #ffdf93;
|
||||
--md-on-warning-container: #271900;
|
||||
|
||||
--md-info: #0062a1;
|
||||
--md-on-info: #ffffff;
|
||||
--md-info-container: #d0e4ff;
|
||||
--md-on-info-container: #001d35;
|
||||
|
||||
/* Surface colors */
|
||||
--md-surface: #fcfcff;
|
||||
--md-on-surface: #1a1c1e;
|
||||
--md-surface-variant: #dfe2eb;
|
||||
--md-on-surface-variant: #43474e;
|
||||
|
||||
/* Elevation */
|
||||
--md-elevation-1: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);
|
||||
|
||||
/* Border Radius */
|
||||
--md-radius-small: 4px;
|
||||
--md-radius-medium: 8px;
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -55,94 +14,111 @@ html::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (width: 3840px) and (height: 2160px) {
|
||||
.success {
|
||||
background-color: rgba(23, 23, 23, 90%);
|
||||
color: var(--md-on-surface);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
border-left: 0.5rem solid var(--md-success);
|
||||
font-size: 1.5vh;
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: rgba(23, 23, 23, 90%);
|
||||
color: var(--md-on-surface);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
border-left: 5px solid var(--md-primary);
|
||||
font-size: 1.5vh;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: rgba(23, 23, 23, 90%);
|
||||
color: var(--md-on-surface);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
border-left: 5px solid var(--md-error);
|
||||
font-size: 1.5vh;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: rgba(23, 23, 23, 90%);
|
||||
color: var(--md-on-surface);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
border-left: 5px solid var(--md-warning);
|
||||
font-size: 1.5vh;
|
||||
}
|
||||
|
||||
.police {
|
||||
background-color: rgba(23, 23, 23, 90%);
|
||||
color: var(--md-on-surface);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
border-left: 5px solid var(--md-info);
|
||||
font-size: 1.5vh;
|
||||
}
|
||||
|
||||
.ambulance {
|
||||
background-color: rgba(23, 23, 23, 90%);
|
||||
color: var(--md-on-surface);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
border-left: 5px solid var(--md-error);
|
||||
font-size: 1.5vh;
|
||||
}
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: var(--md-success-container);
|
||||
color: var(--md-on-success-container);
|
||||
padding: 12px 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
--accent: #006e1c;
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: var(--md-primary-container);
|
||||
color: var(--md-on-primary-container);
|
||||
padding: 12px 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
--accent: #0061a4;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: var(--md-warning-container);
|
||||
color: var(--md-on-warning-container);
|
||||
padding: 12px 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
--accent: #7d5800;
|
||||
}
|
||||
|
||||
.error {
|
||||
background-color: var(--md-error-container);
|
||||
color: var(--md-on-error-container);
|
||||
padding: 12px 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
--accent: #ba1a1a;
|
||||
}
|
||||
|
||||
.police {
|
||||
background-color: var(--md-info-container);
|
||||
color: var(--md-on-info-container);
|
||||
padding: 12px 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
--accent: #0062a1;
|
||||
}
|
||||
.ambulance {
|
||||
--accent: #006874;
|
||||
}
|
||||
|
||||
.success,
|
||||
.primary,
|
||||
.warning,
|
||||
.error,
|
||||
.police,
|
||||
.ambulance {
|
||||
background-color: var(--md-error-container);
|
||||
color: var(--md-on-error-container);
|
||||
background-color: #211f26;
|
||||
color: #e6e1e5;
|
||||
padding: 12px 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
box-shadow: var(--md-elevation-1);
|
||||
}
|
||||
|
||||
.notify-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
border-radius: 0;
|
||||
min-width: 280px;
|
||||
max-width: 400px;
|
||||
opacity: 0;
|
||||
transform: translateX(16px);
|
||||
transition:
|
||||
opacity 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.notify-item.notify-show {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.notify-item.notify-hide {
|
||||
opacity: 0;
|
||||
transform: translateX(16px);
|
||||
transition:
|
||||
opacity 0.3s ease,
|
||||
transform 0.3s ease;
|
||||
}
|
||||
|
||||
.notify-icon {
|
||||
color: var(--accent);
|
||||
flex-shrink: 0;
|
||||
font-size: 20px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.notify-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.notify-message {
|
||||
font-size: clamp(12px, 1.1vw, 16px);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.notify-multiline {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.notify-caption {
|
||||
font-size: clamp(10px, 0.9vw, 14px);
|
||||
margin-top: 2px;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.notify-progress {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
background: var(--accent);
|
||||
opacity: 0.35;
|
||||
animation: notify-shrink linear forwards;
|
||||
}
|
||||
|
||||
@keyframes notify-shrink {
|
||||
from {
|
||||
width: 100%;
|
||||
}
|
||||
to {
|
||||
width: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -1,18 +1,18 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>qb-core</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Exo+2:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/quasar@2.12.0/dist/quasar.prod.css" rel="stylesheet" type="text/css" />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css" />
|
||||
<link href="css/style.css" rel="stylesheet" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/quasar@2.12.0/dist/quasar.umd.prod.js" defer></script>
|
||||
<script type="module" src="js/app.js"></script>
|
||||
<script src="js/drawtext.js"></script>
|
||||
<link rel="stylesheet" href="css/style.css" />
|
||||
<link rel="stylesheet" href="css/drawtext.css" />
|
||||
<script type="module" src="js/app.js"></script>
|
||||
<script src="js/drawtext.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="q-app" style="min-height: 100vh"></div>
|
||||
<div id="drawtext-container">
|
||||
<div id="text" class="text"></div>
|
||||
</div>
|
||||
|
||||
+102
-47
@@ -1,65 +1,120 @@
|
||||
import { determineStyleFromVariant, fetchNotifyConfig, NOTIFY_CONFIG } from "./config.js";
|
||||
let NOTIFY_CONFIG = null;
|
||||
|
||||
const { useQuasar } = Quasar;
|
||||
const { onMounted, onUnmounted } = Vue;
|
||||
const defaultConfig = {
|
||||
NotificationStyling: {
|
||||
group: false,
|
||||
position: "right",
|
||||
progress: true,
|
||||
},
|
||||
VariantDefinitions: {
|
||||
success: { classes: "success", icon: "check_circle" },
|
||||
primary: { classes: "primary", icon: "notifications" },
|
||||
warning: { classes: "warning", icon: "warning" },
|
||||
error: { classes: "error", icon: "error" },
|
||||
police: { classes: "police", icon: "local_police" },
|
||||
ambulance: { classes: "ambulance", icon: "fas fa-ambulance" },
|
||||
},
|
||||
};
|
||||
|
||||
const fetchNui = async (evName, data) => {
|
||||
const resourceName = window.GetParentResourceName();
|
||||
|
||||
const rawResp = await fetch(`https://${resourceName}/${evName}`, {
|
||||
const resp = await fetch(`https://${resourceName}/${evName}`, {
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=UTF8",
|
||||
},
|
||||
headers: { "Content-Type": "application/json; charset=UTF8" },
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
return await rawResp.json();
|
||||
return resp.json();
|
||||
};
|
||||
|
||||
window.fetchNui = fetchNui;
|
||||
const determineStyleFromVariant = (variant) => {
|
||||
return NOTIFY_CONFIG.VariantDefinitions[variant] ?? NOTIFY_CONFIG.VariantDefinitions["primary"];
|
||||
};
|
||||
|
||||
const app = Vue.createApp({
|
||||
setup() {
|
||||
const $q = useQuasar();
|
||||
const fetchNotifyConfig = async () => {
|
||||
try {
|
||||
NOTIFY_CONFIG = await fetchNui("getNotifyConfig", {});
|
||||
if (!NOTIFY_CONFIG) NOTIFY_CONFIG = defaultConfig;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch notification config, using default", error);
|
||||
NOTIFY_CONFIG = defaultConfig;
|
||||
}
|
||||
};
|
||||
|
||||
const showNotif = async ({ data }) => {
|
||||
const POSITION_MAP = {
|
||||
"top-left": { top: "16px", left: "16px" },
|
||||
"top-right": { top: "16px", right: "16px" },
|
||||
top: { top: "16px", left: "50%", transform: "translateX(-50%)" },
|
||||
"bottom-left": { bottom: "16px", left: "16px" },
|
||||
"bottom-right": { bottom: "16px", right: "16px" },
|
||||
bottom: { bottom: "16px", left: "50%", transform: "translateX(-50%)" },
|
||||
left: { top: "50%", left: "16px", transform: "translateY(-50%)" },
|
||||
right: { top: "50%", right: "16px", transform: "translateY(-50%)" },
|
||||
center: { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
|
||||
};
|
||||
|
||||
let container = null;
|
||||
|
||||
const getContainer = () => {
|
||||
if (container) return container;
|
||||
const pos = NOTIFY_CONFIG.NotificationStyling.position ?? "right";
|
||||
const isBottom = pos.startsWith("bottom");
|
||||
container = document.createElement("div");
|
||||
container.id = "notify-container";
|
||||
Object.assign(container.style, {
|
||||
position: "fixed",
|
||||
display: "flex",
|
||||
flexDirection: isBottom ? "column-reverse" : "column",
|
||||
gap: "8px",
|
||||
zIndex: "9999",
|
||||
maxWidth: "400px",
|
||||
pointerEvents: "none",
|
||||
...(POSITION_MAP[pos] ?? POSITION_MAP["right"]),
|
||||
});
|
||||
document.body.appendChild(container);
|
||||
return container;
|
||||
};
|
||||
|
||||
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
const showNotif = async ({ data }) => {
|
||||
if (data?.action !== "notify") return;
|
||||
|
||||
const { text, length, type, caption, icon: dataIcon } = data;
|
||||
let { classes, icon } = determineStyleFromVariant(type);
|
||||
|
||||
if (dataIcon) {
|
||||
icon = dataIcon;
|
||||
}
|
||||
|
||||
if (!NOTIFY_CONFIG) {
|
||||
console.error("The notification config did not load properly, trying again for next time");
|
||||
await fetchNotifyConfig();
|
||||
if (NOTIFY_CONFIG) return showNotif({ data });
|
||||
}
|
||||
|
||||
$q.notify({
|
||||
message: text,
|
||||
multiLine: text.length > 100,
|
||||
group: NOTIFY_CONFIG.NotificationStyling.group ?? false,
|
||||
progress: NOTIFY_CONFIG.NotificationStyling.progress ?? true,
|
||||
position: NOTIFY_CONFIG.NotificationStyling.position ?? "right",
|
||||
timeout: length,
|
||||
caption,
|
||||
classes,
|
||||
icon,
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
window.addEventListener("message", showNotif);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("message", showNotif);
|
||||
});
|
||||
return {};
|
||||
},
|
||||
});
|
||||
const { text: message, type, length: duration = 5000, caption } = data;
|
||||
const style = determineStyleFromVariant(type ?? "primary");
|
||||
const showProgress = NOTIFY_CONFIG.NotificationStyling.progress && duration > 0;
|
||||
|
||||
app.use(Quasar, { config: {} });
|
||||
app.mount("#q-app");
|
||||
const isFa = style.icon.startsWith("fa");
|
||||
const iconHtml = isFa ? `<i class="notify-icon ${style.icon}"></i>` : `<span class="notify-icon material-icons">${style.icon}</span>`;
|
||||
|
||||
const item = document.createElement("div");
|
||||
item.className = `notify-item ${style.classes}`;
|
||||
item.innerHTML = `
|
||||
${iconHtml}
|
||||
<div class="notify-content">
|
||||
<div class="notify-message${!caption ? " notify-multiline" : ""}">${message}</div>
|
||||
${caption ? `<div class="notify-caption">${caption}</div>` : ""}
|
||||
</div>
|
||||
${showProgress ? `<div class="notify-progress" style="animation-duration:${duration}ms"></div>` : ""}
|
||||
`;
|
||||
|
||||
const c = getContainer();
|
||||
c.appendChild(item);
|
||||
|
||||
await sleep(10);
|
||||
item.classList.add("notify-show");
|
||||
|
||||
if (duration > 0) {
|
||||
setTimeout(() => {
|
||||
item.classList.remove("notify-show");
|
||||
item.classList.add("notify-hide");
|
||||
setTimeout(() => item.remove(), 350);
|
||||
}, duration);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("message", showNotif);
|
||||
window.addEventListener("load", fetchNotifyConfig);
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
export let NOTIFY_CONFIG = null;
|
||||
|
||||
const defaultConfig = {
|
||||
NotificationStyling: {
|
||||
group: true,
|
||||
position: "top-right",
|
||||
progress: true,
|
||||
},
|
||||
VariantDefinitions: {
|
||||
success: {
|
||||
classes: "success",
|
||||
icon: "done",
|
||||
},
|
||||
primary: {
|
||||
classes: "primary",
|
||||
icon: "info",
|
||||
},
|
||||
error: {
|
||||
classes: "error",
|
||||
icon: "dangerous",
|
||||
},
|
||||
police: {
|
||||
classes: "police",
|
||||
icon: "local_police",
|
||||
},
|
||||
ambulance: {
|
||||
classes: "ambulance",
|
||||
icon: "fas fa-ambulance",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const determineStyleFromVariant = (variant) => {
|
||||
const variantData = NOTIFY_CONFIG.VariantDefinitions[variant];
|
||||
if (!variantData) throw new Error(`Style of type: ${variant}, does not exist in the config`);
|
||||
return variantData;
|
||||
};
|
||||
|
||||
export const fetchNotifyConfig = async () => {
|
||||
try {
|
||||
NOTIFY_CONFIG = await window.fetchNui("getNotifyConfig", {});
|
||||
if (!NOTIFY_CONFIG) {
|
||||
NOTIFY_CONFIG = defaultConfig;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch notification config, using default", error);
|
||||
NOTIFY_CONFIG = defaultConfig;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("load", async () => {
|
||||
await fetchNotifyConfig();
|
||||
});
|
||||
+13
-9
@@ -92,7 +92,7 @@ QBCore.Commands.Add('tp', Lang:t('command.tp.help'), { { name = Lang:t('command.
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
|
||||
end
|
||||
else
|
||||
local location = QBShared.Locations[args[1]]
|
||||
local location = QBCore.Shared.Locations[args[1]]
|
||||
if location then
|
||||
TriggerClientEvent('QBCore:Command:TeleportToCoords', source, location.x, location.y, location.z, location.w)
|
||||
else
|
||||
@@ -101,12 +101,12 @@ QBCore.Commands.Add('tp', Lang:t('command.tp.help'), { { name = Lang:t('command.
|
||||
end
|
||||
else
|
||||
if args[1] and args[2] and args[3] then
|
||||
local x = tonumber((args[1]:gsub(',', ''))) + .0
|
||||
local y = tonumber((args[2]:gsub(',', ''))) + .0
|
||||
local z = tonumber((args[3]:gsub(',', ''))) + .0
|
||||
local heading = args[4] and tonumber((args[4]:gsub(',', ''))) + .0 or false
|
||||
if x ~= 0 and y ~= 0 and z ~= 0 then
|
||||
TriggerClientEvent('QBCore:Command:TeleportToCoords', source, x, y, z, heading)
|
||||
local x = tonumber((args[1]:gsub(',', '')))
|
||||
local y = tonumber((args[2]:gsub(',', '')))
|
||||
local z = tonumber((args[3]:gsub(',', '')))
|
||||
local heading = args[4] and tonumber((args[4]:gsub(',', ''))) or false
|
||||
if x and y and z then
|
||||
TriggerClientEvent('QBCore:Command:TeleportToCoords', source, x + .0, y + .0, z + .0, heading and heading + .0 or false)
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('error.wrong_format'), 'error')
|
||||
end
|
||||
@@ -240,7 +240,9 @@ end, 'admin')
|
||||
-- Job
|
||||
|
||||
QBCore.Commands.Add('job', Lang:t('command.job.help'), {}, false, function(source)
|
||||
local PlayerJob = QBCore.Functions.GetPlayer(source).PlayerData.job
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
if not Player then return end
|
||||
local PlayerJob = Player.PlayerData.job
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('info.job_info', { value = PlayerJob.label, value2 = PlayerJob.grade.name, value3 = PlayerJob.onduty }))
|
||||
end, 'user')
|
||||
|
||||
@@ -256,7 +258,9 @@ end, 'admin')
|
||||
-- Gang
|
||||
|
||||
QBCore.Commands.Add('gang', Lang:t('command.gang.help'), {}, false, function(source)
|
||||
local PlayerGang = QBCore.Functions.GetPlayer(source).PlayerData.gang
|
||||
local Player = QBCore.Functions.GetPlayer(source)
|
||||
if not Player then return end
|
||||
local PlayerGang = Player.PlayerData.gang
|
||||
TriggerClientEvent('QBCore:Notify', source, Lang:t('info.gang_info', { value = PlayerGang.label, value2 = PlayerGang.grade.name }))
|
||||
end, 'user')
|
||||
|
||||
|
||||
+18
-12
@@ -9,36 +9,42 @@ local function tPrint(tbl, indent)
|
||||
print(formatting)
|
||||
tPrint(v, indent + 1)
|
||||
elseif tblType == 'boolean' then
|
||||
print(('%s^1 %s ^0'):format(formatting, v))
|
||||
print(('%s ^1%s^0'):format(formatting, v))
|
||||
elseif tblType == 'function' then
|
||||
print(('%s^9 %s ^0'):format(formatting, v))
|
||||
print(('%s ^9%s^0'):format(formatting, v))
|
||||
elseif tblType == 'number' then
|
||||
print(('%s^5 %s ^0'):format(formatting, v))
|
||||
print(('%s ^5%s^0'):format(formatting, v))
|
||||
elseif tblType == 'string' then
|
||||
print(("%s ^2'%s' ^0"):format(formatting, v))
|
||||
print(('%s ^2\'%s\'^0'):format(formatting, v))
|
||||
elseif tblType == 'nil' then
|
||||
print(('%s ^8nil^0'):format(formatting))
|
||||
else
|
||||
print(('%s^2 %s ^0'):format(formatting, v))
|
||||
print(('%s ^2%s^0'):format(formatting, tostring(v)))
|
||||
end
|
||||
end
|
||||
else
|
||||
print(('%s ^0%s'):format(string.rep(' ', indent), tbl))
|
||||
print(('%s ^0%s'):format(string.rep(' ', indent), tostring(tbl)))
|
||||
end
|
||||
end
|
||||
|
||||
RegisterServerEvent('QBCore:DebugSomething', function(tbl, indent, resource)
|
||||
print(('\x1b[4m\x1b[36m[ %s : DEBUG]\x1b[0m'):format(resource))
|
||||
RegisterNetEvent('QBCore:DebugSomething', function(tbl, indent, resource)
|
||||
resource = resource or 'unknown'
|
||||
print(('^4[ %s : DEBUG]^0'):format(resource))
|
||||
tPrint(tbl, indent)
|
||||
print('\x1b[4m\x1b[36m[ END DEBUG ]\x1b[0m')
|
||||
print('^4[ END DEBUG ]^0')
|
||||
end)
|
||||
|
||||
function QBCore.Debug(tbl, indent)
|
||||
TriggerEvent('QBCore:DebugSomething', tbl, indent, GetInvokingResource() or 'qb-core')
|
||||
local resource = GetInvokingResource() or 'qb-core'
|
||||
print(('^4[ %s : DEBUG]^0'):format(resource))
|
||||
tPrint(tbl, indent)
|
||||
print('^4[ END DEBUG ]^0')
|
||||
end
|
||||
|
||||
function QBCore.ShowError(resource, msg)
|
||||
print('\x1b[31m[' .. resource .. ':ERROR]\x1b[0m ' .. msg)
|
||||
print(('^1[%s:ERROR]^0 %s'):format(resource, msg))
|
||||
end
|
||||
|
||||
function QBCore.ShowSuccess(resource, msg)
|
||||
print('\x1b[32m[' .. resource .. ':LOG]\x1b[0m ' .. msg)
|
||||
print(('^2[%s:LOG]^0 %s'):format(resource, msg))
|
||||
end
|
||||
|
||||
+39
-34
@@ -10,16 +10,18 @@ end)
|
||||
AddEventHandler('playerDropped', function(reason)
|
||||
local src = source
|
||||
if not QBCore.Players[src] then return end
|
||||
local Player = QBCore.Players[src]
|
||||
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Dropped', 'red', '**' .. GetPlayerName(src) .. '** (' .. Player.PlayerData.license .. ') left..' .. '\n **Reason:** ' .. reason)
|
||||
TriggerEvent('QBCore:Server:PlayerDropped', Player)
|
||||
Player.Functions.Save()
|
||||
QBCore.Player_Buckets[Player.PlayerData.license] = nil
|
||||
local player = QBCore.Players[src]
|
||||
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Dropped', 'red', '**' .. GetPlayerName(src) .. '** (' .. player.PlayerData.license .. ') left..' .. '\n **Reason:** ' .. reason)
|
||||
player.Functions.Save()
|
||||
TriggerEvent('QBCore:Server:PlayerDropped', src)
|
||||
TriggerEvent('QBCore:Server:OnPlayerUnload', src)
|
||||
QBCore.Player_Buckets[player.PlayerData.license] = nil
|
||||
QBCore.PlayersByCitizenId[player.PlayerData.citizenid] = nil
|
||||
QBCore.Players[src] = nil
|
||||
end)
|
||||
|
||||
AddEventHandler("onResourceStop", function(resName)
|
||||
for i,v in pairs(QBCore.UsableItems) do
|
||||
AddEventHandler('onResourceStop', function(resName)
|
||||
for i, v in pairs(QBCore.UsableItems) do
|
||||
if v.resource == resName then
|
||||
QBCore.UsableItems[i] = nil
|
||||
end
|
||||
@@ -36,7 +38,7 @@ if readyFunction ~= nil then
|
||||
local DatabaseInfo = QBCore.Functions.GetDatabaseInfo()
|
||||
if not DatabaseInfo or not DatabaseInfo.exists then return end
|
||||
|
||||
local result = MySQL.query.await('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = "bans";', {DatabaseInfo.database})
|
||||
local result = MySQL.query.await('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = "bans";', { DatabaseInfo.database })
|
||||
if result and result[1] then
|
||||
bansTableExists = true
|
||||
end
|
||||
@@ -124,7 +126,7 @@ end)
|
||||
|
||||
-- Client Callback
|
||||
RegisterNetEvent('QBCore:Server:TriggerClientCallback', function(name, ...)
|
||||
local ClientCallback = QBCore.ClientCallbacks[name..source]
|
||||
local ClientCallback = QBCore.ClientCallbacks[name .. source]
|
||||
if ClientCallback then
|
||||
ClientCallback.promise:resolve(...)
|
||||
|
||||
@@ -132,7 +134,7 @@ RegisterNetEvent('QBCore:Server:TriggerClientCallback', function(name, ...)
|
||||
ClientCallback.callback(...)
|
||||
end
|
||||
|
||||
QBCore.ClientCallbacks[name..source] = nil
|
||||
QBCore.ClientCallbacks[name .. source] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -149,8 +151,12 @@ end)
|
||||
|
||||
-- Player
|
||||
|
||||
local updateCooldowns = {}
|
||||
RegisterNetEvent('QBCore:UpdatePlayer', function()
|
||||
local src = source
|
||||
local now = GetGameTimer()
|
||||
if updateCooldowns[src] and (now - updateCooldowns[src]) < 10000 then return end
|
||||
updateCooldowns[src] = now
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
local newHunger = Player.PlayerData.metadata['hunger'] - QBCore.Config.Player.HungerRate
|
||||
@@ -161,8 +167,9 @@ RegisterNetEvent('QBCore:UpdatePlayer', function()
|
||||
if newThirst <= 0 then
|
||||
newThirst = 0
|
||||
end
|
||||
Player.Functions.SetMetaData('thirst', newThirst)
|
||||
Player.Functions.SetMetaData('hunger', newHunger)
|
||||
Player.PlayerData.metadata['hunger'] = newHunger
|
||||
Player.PlayerData.metadata['thirst'] = newThirst
|
||||
Player.Functions.UpdateClient('metadata', Player.PlayerData.metadata)
|
||||
TriggerClientEvent('hud:client:UpdateNeeds', src, newHunger, newThirst)
|
||||
Player.Functions.Save()
|
||||
end)
|
||||
@@ -183,6 +190,24 @@ RegisterNetEvent('QBCore:ToggleDuty', function()
|
||||
TriggerClientEvent('QBCore:Client:SetDuty', src, Player.PlayerData.job.onduty)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('QBCore:Server:OnPlayerLoaded', function()
|
||||
local src = source
|
||||
if not QBCore.Players[src] then return end
|
||||
TriggerClientEvent('QBCore:Client:OnPlayerLoaded', src)
|
||||
end)
|
||||
|
||||
-- Central server-side data change handler — re-fires legacy events for backward compat
|
||||
AddEventHandler('QBCore:Server:OnPlayerUpdated', function(src, key, val)
|
||||
if key == 'job' then
|
||||
TriggerEvent('QBCore:Server:OnJobUpdate', src, val)
|
||||
elseif key == 'gang' then
|
||||
TriggerEvent('QBCore:Server:OnGangUpdate', src, val)
|
||||
elseif key == 'all' then
|
||||
TriggerEvent('QBCore:Server:OnJobUpdate', src, val.job)
|
||||
TriggerEvent('QBCore:Server:OnGangUpdate', src, val.gang)
|
||||
end
|
||||
end)
|
||||
|
||||
-- BaseEvents
|
||||
|
||||
-- Vehicles
|
||||
@@ -224,26 +249,6 @@ RegisterServerEvent('baseevents:leftVehicle', function(veh, seat, modelName)
|
||||
TriggerClientEvent('QBCore:Client:VehicleInfo', src, data)
|
||||
end)
|
||||
|
||||
-- Items
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon.
|
||||
RegisterNetEvent('QBCore:Server:UseItem', function(item)
|
||||
print(string.format('%s triggered QBCore:Server:UseItem by ID %s with the following data. This event is deprecated due to exploitation, and will be removed soon. Check qb-inventory for the right use on this event.', GetInvokingResource(), source))
|
||||
QBCore.Debug(item)
|
||||
end)
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. function(itemName, amount, slot)
|
||||
RegisterNetEvent('QBCore:Server:RemoveItem', function(itemName, amount)
|
||||
local src = source
|
||||
print(string.format('%s triggered QBCore:Server:RemoveItem by ID %s for %s %s. This event is deprecated due to exploitation, and will be removed soon. Adjust your events accordingly to do this server side with player functions.', GetInvokingResource(), src, amount, itemName))
|
||||
end)
|
||||
|
||||
-- This event is exploitable and should not be used. It has been deprecated, and will be removed soon. function(itemName, amount, slot, info)
|
||||
RegisterNetEvent('QBCore:Server:AddItem', function(itemName, amount)
|
||||
local src = source
|
||||
print(string.format('%s triggered QBCore:Server:AddItem by ID %s for %s %s. This event is deprecated due to exploitation, and will be removed soon. Adjust your events accordingly to do this server side with player functions.', GetInvokingResource(), src, amount, itemName))
|
||||
end)
|
||||
|
||||
-- Non-Chat Command Calling (ex: qb-adminmenu)
|
||||
|
||||
RegisterNetEvent('QBCore:CallCommand', function(command, args)
|
||||
@@ -269,7 +274,7 @@ end)
|
||||
-- convert it to a vehicle via the NetToVeh native
|
||||
QBCore.Functions.CreateCallback('QBCore:Server:SpawnVehicle', function(source, cb, model, coords, warp)
|
||||
local veh = QBCore.Functions.SpawnVehicle(source, model, coords, warp)
|
||||
cb(NetworkGetNetworkIdFromEntity(veh))
|
||||
cb(DoesEntityExist(veh) and NetworkGetNetworkIdFromEntity(veh) or nil)
|
||||
end)
|
||||
|
||||
-- Use this for long distance vehicle spawning
|
||||
@@ -278,7 +283,7 @@ end)
|
||||
-- convert it to a vehicle via the NetToVeh native
|
||||
QBCore.Functions.CreateCallback('QBCore:Server:CreateVehicle', function(source, cb, model, coords, warp)
|
||||
local veh = QBCore.Functions.CreateAutomobile(source, model, coords, warp)
|
||||
cb(NetworkGetNetworkIdFromEntity(veh))
|
||||
cb(DoesEntityExist(veh) and NetworkGetNetworkIdFromEntity(veh) or nil)
|
||||
end)
|
||||
|
||||
--QBCore.Functions.CreateCallback('QBCore:HasItem', function(source, cb, items, amount)
|
||||
|
||||
+18
-66
@@ -3,11 +3,11 @@ local function SetMethod(methodName, handler)
|
||||
if type(methodName) ~= 'string' then
|
||||
return false, 'invalid_method_name'
|
||||
end
|
||||
|
||||
if QBCore.Functions[methodName] ~= nil then
|
||||
return false, 'method_exists'
|
||||
end
|
||||
QBCore.Functions[methodName] = handler
|
||||
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
@@ -19,11 +19,11 @@ local function SetField(fieldName, data)
|
||||
if type(fieldName) ~= 'string' then
|
||||
return false, 'invalid_field_name'
|
||||
end
|
||||
|
||||
if QBCore[fieldName] ~= nil then
|
||||
return false, 'field_exists'
|
||||
end
|
||||
QBCore[fieldName] = data
|
||||
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
|
||||
return true, 'success'
|
||||
end
|
||||
|
||||
@@ -52,32 +52,16 @@ exports('AddJob', AddJob)
|
||||
|
||||
-- Multiple Add Jobs
|
||||
local function AddJobs(jobs)
|
||||
local shouldContinue = true
|
||||
local message = 'success'
|
||||
local errorItem = nil
|
||||
|
||||
for key, value in pairs(jobs) do
|
||||
if type(key) ~= 'string' then
|
||||
message = 'invalid_job_name'
|
||||
shouldContinue = false
|
||||
errorItem = jobs[key]
|
||||
break
|
||||
if type(key) ~= 'string' then return false, 'invalid_job_name', value end
|
||||
if QBCore.Shared.Jobs[key] then return false, 'job_exists', value end
|
||||
end
|
||||
|
||||
if QBCore.Shared.Jobs[key] then
|
||||
message = 'job_exists'
|
||||
shouldContinue = false
|
||||
errorItem = jobs[key]
|
||||
break
|
||||
end
|
||||
|
||||
for key, value in pairs(jobs) do
|
||||
QBCore.Shared.Jobs[key] = value
|
||||
end
|
||||
|
||||
if not shouldContinue then return false, message, errorItem end
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Jobs', jobs)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, message, nil
|
||||
return true, 'success', nil
|
||||
end
|
||||
|
||||
QBCore.Functions.AddJobs = AddJobs
|
||||
@@ -162,32 +146,16 @@ exports('UpdateItem', UpdateItem)
|
||||
|
||||
-- Multiple Add Items
|
||||
local function AddItems(items)
|
||||
local shouldContinue = true
|
||||
local message = 'success'
|
||||
local errorItem = nil
|
||||
|
||||
for key, value in pairs(items) do
|
||||
if type(key) ~= 'string' then
|
||||
message = 'invalid_item_name'
|
||||
shouldContinue = false
|
||||
errorItem = items[key]
|
||||
break
|
||||
if type(key) ~= 'string' then return false, 'invalid_item_name', value end
|
||||
if QBCore.Shared.Items[key] then return false, 'item_exists', value end
|
||||
end
|
||||
|
||||
if QBCore.Shared.Items[key] then
|
||||
message = 'item_exists'
|
||||
shouldContinue = false
|
||||
errorItem = items[key]
|
||||
break
|
||||
end
|
||||
|
||||
for key, value in pairs(items) do
|
||||
QBCore.Shared.Items[key] = value
|
||||
end
|
||||
|
||||
if not shouldContinue then return false, message, errorItem end
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Items', items)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, message, nil
|
||||
return true, 'success', nil
|
||||
end
|
||||
|
||||
QBCore.Functions.AddItems = AddItems
|
||||
@@ -235,32 +203,16 @@ exports('AddGang', AddGang)
|
||||
|
||||
-- Multiple Add Gangs
|
||||
local function AddGangs(gangs)
|
||||
local shouldContinue = true
|
||||
local message = 'success'
|
||||
local errorItem = nil
|
||||
|
||||
for key, value in pairs(gangs) do
|
||||
if type(key) ~= 'string' then
|
||||
message = 'invalid_gang_name'
|
||||
shouldContinue = false
|
||||
errorItem = gangs[key]
|
||||
break
|
||||
if type(key) ~= 'string' then return false, 'invalid_gang_name', value end
|
||||
if QBCore.Shared.Gangs[key] then return false, 'gang_exists', value end
|
||||
end
|
||||
|
||||
if QBCore.Shared.Gangs[key] then
|
||||
message = 'gang_exists'
|
||||
shouldContinue = false
|
||||
errorItem = gangs[key]
|
||||
break
|
||||
end
|
||||
|
||||
for key, value in pairs(gangs) do
|
||||
QBCore.Shared.Gangs[key] = value
|
||||
end
|
||||
|
||||
if not shouldContinue then return false, message, errorItem end
|
||||
TriggerClientEvent('QBCore:Client:OnSharedUpdateMultiple', -1, 'Gangs', gangs)
|
||||
TriggerEvent('QBCore:Server:UpdateObject')
|
||||
return true, message, nil
|
||||
return true, 'success', nil
|
||||
end
|
||||
|
||||
QBCore.Functions.AddGangs = AddGangs
|
||||
|
||||
+33
-43
@@ -55,12 +55,7 @@ end
|
||||
---@param citizenid string
|
||||
---@return table?
|
||||
function QBCore.Functions.GetPlayerByCitizenId(citizenid)
|
||||
for _, Player in pairs(QBCore.Players) do
|
||||
if Player.PlayerData.citizenid == citizenid then
|
||||
return Player
|
||||
end
|
||||
end
|
||||
return nil
|
||||
return QBCore.PlayersByCitizenId[citizenid]
|
||||
end
|
||||
|
||||
---Get offline player by citizen id
|
||||
@@ -304,16 +299,12 @@ end
|
||||
---@return table|boolean
|
||||
function QBCore.Functions.GetPlayersInBucket(bucket)
|
||||
local curr_bucket_pool = {}
|
||||
if QBCore.Player_Buckets and next(QBCore.Player_Buckets) then
|
||||
for _, v in pairs(QBCore.Player_Buckets) do
|
||||
if v.bucket == bucket then
|
||||
curr_bucket_pool[#curr_bucket_pool + 1] = v.id
|
||||
end
|
||||
end
|
||||
return curr_bucket_pool
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
---Will return an array of all the entities inside the current bucket
|
||||
@@ -322,16 +313,12 @@ end
|
||||
---@return table|boolean
|
||||
function QBCore.Functions.GetEntitiesInBucket(bucket)
|
||||
local curr_bucket_pool = {}
|
||||
if QBCore.Entity_Buckets and next(QBCore.Entity_Buckets) then
|
||||
for _, v in pairs(QBCore.Entity_Buckets) do
|
||||
if v.bucket == bucket then
|
||||
curr_bucket_pool[#curr_bucket_pool + 1] = v.id
|
||||
end
|
||||
end
|
||||
return curr_bucket_pool
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
---Server side vehicle creation with optional callback
|
||||
@@ -347,14 +334,24 @@ function QBCore.Functions.SpawnVehicle(source, model, coords, warp)
|
||||
if not coords then coords = GetEntityCoords(ped) end
|
||||
local heading = coords.w and coords.w or 0.0
|
||||
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, heading, true, true)
|
||||
while not DoesEntityExist(veh) do Wait(0) end
|
||||
if warp then
|
||||
while GetVehiclePedIsIn(ped) ~= veh do
|
||||
local t = 0
|
||||
while not DoesEntityExist(veh) and t < 1000 do
|
||||
Wait(0)
|
||||
t += 1
|
||||
end
|
||||
if warp then
|
||||
t = 0
|
||||
while GetVehiclePedIsIn(ped) ~= veh and t < 100 do
|
||||
Wait(0)
|
||||
t += 1
|
||||
TaskWarpPedIntoVehicle(ped, veh, -1)
|
||||
end
|
||||
end
|
||||
while NetworkGetEntityOwner(veh) ~= source do Wait(0) end
|
||||
t = 0
|
||||
while NetworkGetEntityOwner(veh) ~= source and t < 1000 do
|
||||
Wait(0)
|
||||
t += 1
|
||||
end
|
||||
return veh
|
||||
end
|
||||
|
||||
@@ -373,7 +370,11 @@ function QBCore.Functions.CreateAutomobile(source, model, coords, warp)
|
||||
local heading = coords.w and coords.w or 0.0
|
||||
local CreateAutomobile = `CREATE_AUTOMOBILE`
|
||||
local veh = Citizen.InvokeNative(CreateAutomobile, model, coords, heading, true, true)
|
||||
while not DoesEntityExist(veh) do Wait(0) end
|
||||
local t = 0
|
||||
while not DoesEntityExist(veh) and t < 1000 do
|
||||
Wait(0)
|
||||
t += 1
|
||||
end
|
||||
if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
|
||||
return veh
|
||||
end
|
||||
@@ -395,7 +396,11 @@ function QBCore.Functions.CreateVehicle(source, model, vehtype, coords, warp)
|
||||
if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
|
||||
local heading = coords.w and coords.w or 0.0
|
||||
local veh = CreateVehicleServerSetter(model, vehtype, coords, heading)
|
||||
while not DoesEntityExist(veh) do Wait(0) end
|
||||
local t = 0
|
||||
while not DoesEntityExist(veh) and t < 1000 do
|
||||
Wait(0)
|
||||
t += 1
|
||||
end
|
||||
if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
|
||||
return veh
|
||||
end
|
||||
@@ -408,9 +413,11 @@ function PaycheckInterval()
|
||||
CreateThread(function()
|
||||
for _, Player in pairs(QBCore.Players) do
|
||||
if Player then
|
||||
local payment = QBShared.Jobs[Player.PlayerData.job.name]['grades'][tostring(Player.PlayerData.job.grade.level)].payment
|
||||
local jobData = QBCore.Shared.Jobs[Player.PlayerData.job.name]
|
||||
local gradeData = jobData and jobData['grades'][tostring(Player.PlayerData.job.grade.level)]
|
||||
local payment = gradeData and gradeData.payment
|
||||
if not payment then payment = Player.PlayerData.job.payment end
|
||||
if Player.PlayerData.job and payment > 0 and (QBShared.Jobs[Player.PlayerData.job.name].offDutyPay or Player.PlayerData.job.onduty) then
|
||||
if Player.PlayerData.job and payment > 0 and (QBCore.Shared.Jobs[Player.PlayerData.job.name].offDutyPay or Player.PlayerData.job.onduty) then
|
||||
if QBCore.Config.Money.PayCheckSociety then
|
||||
local account = exports['qb-banking']:GetAccountBalance(Player.PlayerData.job.name)
|
||||
if account ~= 0 then
|
||||
@@ -463,7 +470,9 @@ function QBCore.Functions.TriggerClientCallback(name, source, ...)
|
||||
|
||||
if cb == nil then
|
||||
Citizen.Await(QBCore.ClientCallbacks[name .. source].promise)
|
||||
return QBCore.ClientCallbacks[name .. source].promise.value
|
||||
local value = QBCore.ClientCallbacks[name .. source].promise.value
|
||||
QBCore.ClientCallbacks[name .. source] = nil
|
||||
return value
|
||||
end
|
||||
end
|
||||
|
||||
@@ -538,7 +547,7 @@ function QBCore.Functions.Kick(source, reason, setKickReason, deferrals)
|
||||
for _ = 0, 4 do
|
||||
while true do
|
||||
if source then
|
||||
if GetPlayerPing(source) >= 0 then
|
||||
if GetPlayerPing(source) < 0 then
|
||||
break
|
||||
end
|
||||
CreateThread(function()
|
||||
@@ -723,27 +732,8 @@ function QBCore.Functions.Notify(source, text, type, length)
|
||||
TriggerClientEvent('QBCore:Notify', source, text, type, length)
|
||||
end
|
||||
|
||||
---???? ... ok
|
||||
---@param source any
|
||||
---@param data any
|
||||
---@param pattern any
|
||||
---@return boolean
|
||||
function QBCore.Functions.PrepForSQL(source, data, pattern)
|
||||
data = tostring(data)
|
||||
local src = source
|
||||
local player = QBCore.Functions.GetPlayer(src)
|
||||
local result = string.match(data, pattern)
|
||||
if not result or string.len(result) ~= string.len(data) then
|
||||
TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'SQL Exploit Attempted', 'red', string.format('%s attempted to exploit SQL!', player.PlayerData.license))
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
for functionName, func in pairs(QBCore.Functions) do
|
||||
if type(func) == 'function' then
|
||||
exports(functionName, func)
|
||||
end
|
||||
end
|
||||
-- Access a specific function directly:
|
||||
-- exports['qb-core']:Notify(source, 'Hello Player!')
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
QBCore = {}
|
||||
QBCore.Config = QBConfig
|
||||
QBCore.Shared = QBShared
|
||||
QBCore.ClientCallbacks = {}
|
||||
QBCore.ServerCallbacks = {}
|
||||
|
||||
-- Get the full QBCore object (default behavior):
|
||||
-- local QBCore = GetCoreObject()
|
||||
|
||||
-- Get only specific parts of QBCore:
|
||||
-- local QBCore = GetCoreObject({'Players', 'Config'})
|
||||
|
||||
local function GetCoreObject(filters)
|
||||
if not filters then return QBCore end
|
||||
local results = {}
|
||||
for i = 1, #filters do
|
||||
local key = filters[i]
|
||||
if QBCore[key] then
|
||||
results[key] = QBCore[key]
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
exports('GetCoreObject', GetCoreObject)
|
||||
|
||||
local function GetSharedItems()
|
||||
return QBShared.Items
|
||||
end
|
||||
exports('GetSharedItems', GetSharedItems)
|
||||
|
||||
local function GetSharedVehicles()
|
||||
return QBShared.Vehicles
|
||||
end
|
||||
exports('GetSharedVehicles', GetSharedVehicles)
|
||||
|
||||
local function GetSharedWeapons()
|
||||
return QBShared.Weapons
|
||||
end
|
||||
exports('GetSharedWeapons', GetSharedWeapons)
|
||||
|
||||
local function GetSharedJobs()
|
||||
return QBShared.Jobs
|
||||
end
|
||||
exports('GetSharedJobs', GetSharedJobs)
|
||||
|
||||
local function GetSharedGangs()
|
||||
return QBShared.Gangs
|
||||
end
|
||||
exports('GetSharedGangs', GetSharedGangs)
|
||||
+467
-466
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,172 @@
|
||||
local StringCharset = {}
|
||||
local NumberCharset = {}
|
||||
|
||||
QBCore.Shared.StarterItems = {
|
||||
['phone'] = { amount = 1, item = 'phone' },
|
||||
['id_card'] = { amount = 1, item = 'id_card' },
|
||||
['driver_license'] = { amount = 1, item = 'driver_license' },
|
||||
}
|
||||
|
||||
for i = 48, 57 do NumberCharset[#NumberCharset + 1] = string.char(i) end
|
||||
for i = 65, 90 do StringCharset[#StringCharset + 1] = string.char(i) end
|
||||
for i = 97, 122 do StringCharset[#StringCharset + 1] = string.char(i) end
|
||||
|
||||
function QBCore.Shared.RandomStr(length)
|
||||
if length <= 0 then return '' end
|
||||
return QBCore.Shared.RandomStr(length - 1) .. StringCharset[math.random(1, #StringCharset)]
|
||||
end
|
||||
|
||||
function QBCore.Shared.RandomInt(length)
|
||||
if length <= 0 then return '' end
|
||||
return QBCore.Shared.RandomInt(length - 1) .. NumberCharset[math.random(1, #NumberCharset)]
|
||||
end
|
||||
|
||||
function QBCore.Shared.SplitStr(str, delimiter)
|
||||
local result = {}
|
||||
local from = 1
|
||||
local delim_from, delim_to = string.find(str, delimiter, from)
|
||||
while delim_from do
|
||||
result[#result + 1] = string.sub(str, from, delim_from - 1)
|
||||
from = delim_to + 1
|
||||
delim_from, delim_to = string.find(str, delimiter, from)
|
||||
end
|
||||
result[#result + 1] = string.sub(str, from)
|
||||
return result
|
||||
end
|
||||
|
||||
function QBCore.Shared.Trim(value)
|
||||
if not value then return nil end
|
||||
return (string.gsub(value, '^%s*(.-)%s*$', '%1'))
|
||||
end
|
||||
|
||||
function QBCore.Shared.FirstToUpper(value)
|
||||
if not value then return nil end
|
||||
return (value:gsub('^%l', string.upper))
|
||||
end
|
||||
|
||||
function QBCore.Shared.Round(value, numDecimalPlaces)
|
||||
if not numDecimalPlaces then return math.floor(value + 0.5) end
|
||||
local power = 10 ^ numDecimalPlaces
|
||||
return math.floor((value * power) + 0.5) / (power)
|
||||
end
|
||||
|
||||
function QBCore.Shared.ChangeVehicleExtra(vehicle, extra, enable)
|
||||
if DoesExtraExist(vehicle, extra) then
|
||||
if enable then
|
||||
SetVehicleExtra(vehicle, extra, false)
|
||||
if not IsVehicleExtraTurnedOn(vehicle, extra) then
|
||||
QBCore.Shared.ChangeVehicleExtra(vehicle, extra, enable)
|
||||
end
|
||||
else
|
||||
SetVehicleExtra(vehicle, extra, true)
|
||||
if IsVehicleExtraTurnedOn(vehicle, extra) then
|
||||
QBCore.Shared.ChangeVehicleExtra(vehicle, extra, enable)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function QBCore.Shared.IsFunction(value)
|
||||
if type(value) == 'table' then
|
||||
return value.__cfx_functionReference ~= nil and type(value.__cfx_functionReference) == 'string'
|
||||
end
|
||||
|
||||
return type(value) == 'function'
|
||||
end
|
||||
|
||||
function QBCore.Shared.SetDefaultVehicleExtras(vehicle, config)
|
||||
for i = 1, 20 do
|
||||
if DoesExtraExist(vehicle, i) then
|
||||
SetVehicleExtra(vehicle, i, 1)
|
||||
end
|
||||
end
|
||||
|
||||
for id, enabled in pairs(config) do
|
||||
if type(enabled) ~= 'boolean' then
|
||||
enabled = true
|
||||
end
|
||||
|
||||
QBCore.Shared.ChangeVehicleExtra(vehicle, tonumber(id), enabled)
|
||||
end
|
||||
end
|
||||
|
||||
QBCore.Shared.MaleNoGloves = {
|
||||
[0] = true,
|
||||
[1] = true,
|
||||
[2] = true,
|
||||
[3] = true,
|
||||
[4] = true,
|
||||
[5] = true,
|
||||
[6] = true,
|
||||
[7] = true,
|
||||
[8] = true,
|
||||
[9] = true,
|
||||
[10] = true,
|
||||
[11] = true,
|
||||
[12] = true,
|
||||
[13] = true,
|
||||
[14] = true,
|
||||
[15] = true,
|
||||
[18] = true,
|
||||
[26] = true,
|
||||
[52] = true,
|
||||
[53] = true,
|
||||
[54] = true,
|
||||
[55] = true,
|
||||
[56] = true,
|
||||
[57] = true,
|
||||
[58] = true,
|
||||
[59] = true,
|
||||
[60] = true,
|
||||
[61] = true,
|
||||
[62] = true,
|
||||
[112] = true,
|
||||
[113] = true,
|
||||
[114] = true,
|
||||
[118] = true,
|
||||
[125] = true,
|
||||
[132] = true
|
||||
}
|
||||
|
||||
QBCore.Shared.FemaleNoGloves = {
|
||||
[0] = true,
|
||||
[1] = true,
|
||||
[2] = true,
|
||||
[3] = true,
|
||||
[4] = true,
|
||||
[5] = true,
|
||||
[6] = true,
|
||||
[7] = true,
|
||||
[8] = true,
|
||||
[9] = true,
|
||||
[10] = true,
|
||||
[11] = true,
|
||||
[12] = true,
|
||||
[13] = true,
|
||||
[14] = true,
|
||||
[15] = true,
|
||||
[19] = true,
|
||||
[59] = true,
|
||||
[60] = true,
|
||||
[61] = true,
|
||||
[62] = true,
|
||||
[63] = true,
|
||||
[64] = true,
|
||||
[65] = true,
|
||||
[66] = true,
|
||||
[67] = true,
|
||||
[68] = true,
|
||||
[69] = true,
|
||||
[70] = true,
|
||||
[71] = true,
|
||||
[129] = true,
|
||||
[130] = true,
|
||||
[131] = true,
|
||||
[135] = true,
|
||||
[142] = true,
|
||||
[149] = true,
|
||||
[153] = true,
|
||||
[157] = true,
|
||||
[161] = true,
|
||||
[165] = true
|
||||
}
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
QBShared = QBShared or {}
|
||||
QBShared.Gangs = {
|
||||
QBCore.Shared.Gangs = {
|
||||
none = { label = 'No Gang', grades = { ['0'] = { name = 'Unaffiliated' } } },
|
||||
lostmc = {
|
||||
label = 'The Lost MC',
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
QBShared = QBShared or {}
|
||||
QBShared.Items = {
|
||||
QBCore.Shared.Items = {
|
||||
-- WEAPONS
|
||||
-- Melee
|
||||
weapon_unarmed = { name = 'weapon_unarmed', label = 'Fists', weight = 1000, type = 'weapon', ammotype = nil, image = 'placeholder.png', unique = true, useable = false, description = 'Fisticuffs' },
|
||||
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
QBShared = QBShared or {}
|
||||
QBShared.ForceJobDefaultDutyAtLogin = true -- true: Force duty state to jobdefaultDuty | false: set duty state from database last saved
|
||||
QBShared.Jobs = {
|
||||
QBCore.Shared.ForceJobDefaultDutyAtLogin = true -- true: Force duty state to jobdefaultDuty | false: set duty state from database last saved
|
||||
QBCore.Shared.Jobs = {
|
||||
unemployed = { label = 'Civilian', defaultDuty = true, offDutyPay = false, grades = { ['0'] = { name = 'Freelancer', payment = 10 } } },
|
||||
bus = { label = 'Bus', defaultDuty = true, offDutyPay = false, grades = { ['0'] = { name = 'Driver', payment = 50 } } },
|
||||
judge = { label = 'Honorary', defaultDuty = true, offDutyPay = false, grades = { ['0'] = { name = 'Judge', payment = 100 } } },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
QBShared.Locations = {
|
||||
QBCore.Shared.Locations = {
|
||||
-- Base game MLO interiors
|
||||
aircraft_carrier_int = vector4(3081.0042, -4693.6875, 15.2623, 76.8169),
|
||||
apt_1_int = vector4(-1452.4602, -540.2056, 74.0443, 31.9129),
|
||||
|
||||
+18
-175
@@ -1,185 +1,28 @@
|
||||
QBShared = QBShared or {}
|
||||
QBCore.Shared = {}
|
||||
QBCore.ClientCallbacks = {}
|
||||
QBCore.ServerCallbacks = {}
|
||||
|
||||
local StringCharset = {}
|
||||
local NumberCharset = {}
|
||||
|
||||
QBShared.StarterItems = {
|
||||
['phone'] = { amount = 1, item = 'phone' },
|
||||
['id_card'] = { amount = 1, item = 'id_card' },
|
||||
['driver_license'] = { amount = 1, item = 'driver_license' },
|
||||
}
|
||||
|
||||
for i = 48, 57 do NumberCharset[#NumberCharset + 1] = string.char(i) end
|
||||
for i = 65, 90 do StringCharset[#StringCharset + 1] = string.char(i) end
|
||||
for i = 97, 122 do StringCharset[#StringCharset + 1] = string.char(i) end
|
||||
|
||||
function QBShared.RandomStr(length)
|
||||
if length <= 0 then return '' end
|
||||
return QBShared.RandomStr(length - 1) .. StringCharset[math.random(1, #StringCharset)]
|
||||
--- @param filters ('Config'|'Shared'|'ClientCallbacks'|'ServerCallbacks'|'PlayerData'|'Functions'|'Players'|'PlayersByCitizenId'|'Player_Buckets'|'Entity_Buckets'|'UsableItems'|'Commands')[]?
|
||||
--- @return table
|
||||
local function GetCoreObject(filters)
|
||||
if not filters then return QBCore end
|
||||
local results = {}
|
||||
for i = 1, #filters do
|
||||
local key = filters[i]
|
||||
if QBCore[key] then
|
||||
results[key] = QBCore[key]
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
exports('GetCoreObject', GetCoreObject)
|
||||
|
||||
function QBShared.RandomInt(length)
|
||||
if length <= 0 then return '' end
|
||||
return QBShared.RandomInt(length - 1) .. NumberCharset[math.random(1, #NumberCharset)]
|
||||
end
|
||||
|
||||
function QBShared.SplitStr(str, delimiter)
|
||||
local result = {}
|
||||
local from = 1
|
||||
local delim_from, delim_to = string.find(str, delimiter, from)
|
||||
while delim_from do
|
||||
result[#result + 1] = string.sub(str, from, delim_from - 1)
|
||||
from = delim_to + 1
|
||||
delim_from, delim_to = string.find(str, delimiter, from)
|
||||
end
|
||||
result[#result + 1] = string.sub(str, from)
|
||||
return result
|
||||
end
|
||||
|
||||
function QBShared.Trim(value)
|
||||
if not value then return nil end
|
||||
return (string.gsub(value, '^%s*(.-)%s*$', '%1'))
|
||||
end
|
||||
|
||||
function QBShared.FirstToUpper(value)
|
||||
if not value then return nil end
|
||||
return (value:gsub("^%l", string.upper))
|
||||
end
|
||||
|
||||
function QBShared.Round(value, numDecimalPlaces)
|
||||
if not numDecimalPlaces then return math.floor(value + 0.5) end
|
||||
local power = 10 ^ numDecimalPlaces
|
||||
return math.floor((value * power) + 0.5) / (power)
|
||||
end
|
||||
|
||||
function QBShared.ChangeVehicleExtra(vehicle, extra, enable)
|
||||
if DoesExtraExist(vehicle, extra) then
|
||||
if enable then
|
||||
SetVehicleExtra(vehicle, extra, false)
|
||||
if not IsVehicleExtraTurnedOn(vehicle, extra) then
|
||||
QBShared.ChangeVehicleExtra(vehicle, extra, enable)
|
||||
end
|
||||
else
|
||||
SetVehicleExtra(vehicle, extra, true)
|
||||
if IsVehicleExtraTurnedOn(vehicle, extra) then
|
||||
QBShared.ChangeVehicleExtra(vehicle, extra, enable)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function QBShared.IsFunction(value)
|
||||
if type(value) == 'table' then
|
||||
return value.__cfx_functionReference ~= nil and type(value.__cfx_functionReference) == "string"
|
||||
end
|
||||
|
||||
return type(value) == 'function'
|
||||
end
|
||||
|
||||
function QBShared.SetDefaultVehicleExtras(vehicle, config)
|
||||
-- Clear Extras
|
||||
for i = 1, 20 do
|
||||
if DoesExtraExist(vehicle, i) then
|
||||
SetVehicleExtra(vehicle, i, 1)
|
||||
end
|
||||
end
|
||||
|
||||
for id, enabled in pairs(config) do
|
||||
if type(enabled) ~= 'boolean' then
|
||||
enabled = true
|
||||
end
|
||||
|
||||
QBShared.ChangeVehicleExtra(vehicle, tonumber(id), enabled)
|
||||
end
|
||||
end
|
||||
|
||||
QBShared.MaleNoGloves = {
|
||||
[0] = true,
|
||||
[1] = true,
|
||||
[2] = true,
|
||||
[3] = true,
|
||||
[4] = true,
|
||||
[5] = true,
|
||||
[6] = true,
|
||||
[7] = true,
|
||||
[8] = true,
|
||||
[9] = true,
|
||||
[10] = true,
|
||||
[11] = true,
|
||||
[12] = true,
|
||||
[13] = true,
|
||||
[14] = true,
|
||||
[15] = true,
|
||||
[18] = true,
|
||||
[26] = true,
|
||||
[52] = true,
|
||||
[53] = true,
|
||||
[54] = true,
|
||||
[55] = true,
|
||||
[56] = true,
|
||||
[57] = true,
|
||||
[58] = true,
|
||||
[59] = true,
|
||||
[60] = true,
|
||||
[61] = true,
|
||||
[62] = true,
|
||||
[112] = true,
|
||||
[113] = true,
|
||||
[114] = true,
|
||||
[118] = true,
|
||||
[125] = true,
|
||||
[132] = true
|
||||
}
|
||||
|
||||
QBShared.FemaleNoGloves = {
|
||||
[0] = true,
|
||||
[1] = true,
|
||||
[2] = true,
|
||||
[3] = true,
|
||||
[4] = true,
|
||||
[5] = true,
|
||||
[6] = true,
|
||||
[7] = true,
|
||||
[8] = true,
|
||||
[9] = true,
|
||||
[10] = true,
|
||||
[11] = true,
|
||||
[12] = true,
|
||||
[13] = true,
|
||||
[14] = true,
|
||||
[15] = true,
|
||||
[19] = true,
|
||||
[59] = true,
|
||||
[60] = true,
|
||||
[61] = true,
|
||||
[62] = true,
|
||||
[63] = true,
|
||||
[64] = true,
|
||||
[65] = true,
|
||||
[66] = true,
|
||||
[67] = true,
|
||||
[68] = true,
|
||||
[69] = true,
|
||||
[70] = true,
|
||||
[71] = true,
|
||||
[129] = true,
|
||||
[130] = true,
|
||||
[131] = true,
|
||||
[135] = true,
|
||||
[142] = true,
|
||||
[149] = true,
|
||||
[153] = true,
|
||||
[157] = true,
|
||||
[161] = true,
|
||||
[165] = true
|
||||
}
|
||||
|
||||
--- Get a shared item from a shared field
|
||||
--- @param namespace 'Vehicles' | 'VehicleHashes' | 'Items' | 'Gangs' | 'Jobs' | 'Locations' | 'Weapons'
|
||||
--- @param item string
|
||||
--- @return table
|
||||
function GetShared(namespace, item)
|
||||
return QBCore.Shared[namespace]?[item]
|
||||
local ns = QBCore.Shared[namespace]
|
||||
return ns and ns[item]
|
||||
end
|
||||
|
||||
exports('GetShared', GetShared)
|
||||
+4
-5
@@ -1,5 +1,4 @@
|
||||
QBShared = QBShared or {}
|
||||
QBShared.Vehicles = QBShared.Vehicles or {}
|
||||
QBCore.Shared.Vehicles = QBCore.Shared.Vehicles or {}
|
||||
|
||||
local Vehicles = {
|
||||
--- Compacts (0)
|
||||
@@ -765,10 +764,10 @@ local Vehicles = {
|
||||
{ model = 'formula', name = 'PR4', brand = 'Progen', price = 100000, category = 'openwheel', type = 'automobile', shop = 'none' },
|
||||
}
|
||||
|
||||
QBShared.VehicleHashes = QBShared.VehicleHashes or {}
|
||||
QBCore.Shared.VehicleHashes = QBCore.Shared.VehicleHashes or {}
|
||||
for i = 1, #Vehicles do
|
||||
local hash = joaat(Vehicles[i].model)
|
||||
QBShared.Vehicles[Vehicles[i].model] = {
|
||||
QBCore.Shared.Vehicles[Vehicles[i].model] = {
|
||||
spawncode = Vehicles[i].model,
|
||||
name = Vehicles[i].name,
|
||||
brand = Vehicles[i].brand,
|
||||
@@ -779,5 +778,5 @@ for i = 1, #Vehicles do
|
||||
type = Vehicles[i].type,
|
||||
shop = Vehicles[i].shop
|
||||
}
|
||||
QBShared.VehicleHashes[hash] = QBShared.Vehicles[Vehicles[i].model]
|
||||
QBCore.Shared.VehicleHashes[hash] = QBCore.Shared.Vehicles[Vehicles[i].model]
|
||||
end
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
QBShared = QBShared or {}
|
||||
QBShared.Weapons = {
|
||||
QBCore.Shared.Weapons = {
|
||||
-- // WEAPONS
|
||||
-- Melee
|
||||
[`weapon_unarmed`] = { name = 'weapon_unarmed', label = 'Fists', weapontype = 'Melee', ammotype = nil, damagereason = 'Melee killed / Whacked / Executed / Beat down / Murdered / Battered' },
|
||||
|
||||
Reference in New Issue
Block a user