Merge branch 'qbcore-framework:main' into main

This commit is contained in:
AnthoHansen
2022-07-25 14:23:11 +02:00
committed by GitHub
25 changed files with 370 additions and 291 deletions
+1 -1
View File
@@ -197,5 +197,5 @@ All lua code should be done using all the best practices of proper lua using the
### JavaScript Styleguide
- Use 4 Space indentation
- Use 2 Space indentation
- Don't repeat yourself.. if you're using the same operations in many different places convert them into a function with flexible variables.
+8 -8
View File
@@ -36,7 +36,7 @@ RegisterNetEvent('QBCore:Command:GoToMarker', function()
local blipMarker <const> = GetFirstBlipInfoId(8)
if not DoesBlipExist(blipMarker) then
QBCore.Functions.Notify('No Waypoint Set.', "error",5000)
QBCore.Functions.Notify('No Waypoint Set.', "error", 5000)
return 'marker'
end
@@ -107,12 +107,12 @@ RegisterNetEvent('QBCore:Command:GoToMarker', function()
-- If we can't find the coords, set the coords to the old ones.
-- We don't unpack them before since they aren't in a loop and only called once.
SetPedCoordsKeepVehicle(ped, oldCoords['x'], oldCoords['y'], oldCoords['z'] - 1.0)
QBCore.Functions.Notify('Error While Teleporting.', "error",5000)
QBCore.Functions.Notify('Error While Teleporting.', "error", 5000)
end
-- If Z coord was found, set coords in found coords.
SetPedCoordsKeepVehicle(ped, x, y, groundZ)
QBCore.Functions.Notify('Teleported To Waypoint.', "success",5000)
QBCore.Functions.Notify('Teleported To Waypoint.', "success", 5000)
end)
-- Vehicle Commands
@@ -196,16 +196,16 @@ end)
local function Draw3DText(coords, str)
local onScreen, worldX, worldY = World3dToScreen2d(coords.x, coords.y, coords.z)
local camCoords = GetGameplayCamCoord()
local scale = 200 / (GetGameplayCamFov() * #(camCoords - coords))
local camCoords = GetGameplayCamCoord()
local scale = 200 / (GetGameplayCamFov() * #(camCoords - coords))
if onScreen then
SetTextScale(1.0, 0.5 * scale)
SetTextFont(4)
SetTextColour(255, 255, 255, 255)
SetTextEdge(2, 0, 0, 0, 150)
SetTextProportional(1)
SetTextOutline()
SetTextCentre(1)
SetTextProportional(1)
SetTextOutline()
SetTextCentre(1)
BeginTextCommandDisplayText("STRING")
AddTextComponentSubstringPlayerName(str)
EndTextCommandDisplayText(worldX, worldY)
+1 -1
View File
@@ -396,7 +396,7 @@ function QBCore.Functions.SpawnVehicle(model, cb, coords, isnetworked, teleportI
else
coords = GetEntityCoords(ped)
end
isnetworked = isnetworked or true
isnetworked = isnetworked == nil or isnetworked
QBCore.Functions.LoadModel(model)
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, isnetworked, false)
local netid = NetworkGetNetworkIdFromEntity(veh)
+2 -2
View File
@@ -15,8 +15,8 @@ CreateThread(function()
if (QBCore.PlayerData.metadata['hunger'] <= 0 or QBCore.PlayerData.metadata['thirst'] <= 0) and not QBCore.PlayerData.metadata['isdead'] then
local ped = PlayerPedId()
local currentHealth = GetEntityHealth(ped)
local decreaseTreshold = math.random(5, 10)
SetEntityHealth(ped, currentHealth - decreaseTreshold)
local decreaseThreshold = math.random(5, 10)
SetEntityHealth(ped, currentHealth - decreaseThreshold)
end
end
Wait(QBCore.Config.StatusInterval)
+3 -3
View File
@@ -6,8 +6,8 @@ QBConfig.UpdateInterval = 5 -- how often to update player data in minutes
QBConfig.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.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.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
@@ -30,7 +30,7 @@ QBConfig.Server.WhitelistPermission = 'admin' -- Permission that's able to enter
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
QBConfig.Server.Permissions = { 'god', 'admin', 'mod' } -- Add as many groups as you want here after creating them in your server.cfg
QBConfig.Notify = {}
+25 -25
View File
@@ -5,43 +5,43 @@ description 'QB-Core'
version '1.1.0'
shared_scripts {
'config.lua',
'config.lua',
'shared/locale.lua',
'locale/en.lua', -- replace with desired language
'shared/main.lua',
'shared/items.lua',
'shared/jobs.lua',
'shared/vehicles.lua',
'shared/gangs.lua',
'shared/weapons.lua'
'locale/en.lua', -- replace with desired language
'shared/main.lua',
'shared/items.lua',
'shared/jobs.lua',
'shared/vehicles.lua',
'shared/gangs.lua',
'shared/weapons.lua'
}
client_scripts {
'client/main.lua',
'client/functions.lua',
'client/loops.lua',
'client/events.lua',
'client/drawtext.lua'
'client/main.lua',
'client/functions.lua',
'client/loops.lua',
'client/events.lua',
'client/drawtext.lua'
}
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
'server/functions.lua',
'server/player.lua',
'server/events.lua',
'server/commands.lua',
'server/exports.lua',
'server/debug.lua'
'@oxmysql/lib/MySQL.lua',
'server/main.lua',
'server/functions.lua',
'server/player.lua',
'server/events.lua',
'server/commands.lua',
'server/exports.lua',
'server/debug.lua'
}
ui_page 'html/index.html'
files {
'html/index.html',
'html/css/style.css',
'html/css/drawtext.css',
'html/js/*.js'
'html/index.html',
'html/css/style.css',
'html/css/drawtext.css',
'html/js/*.js'
}
dependency 'oxmysql'
+8 -1
View File
@@ -1,4 +1,5 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap");
:root {
--primary-bg: rgba(23, 23, 23, 90%);
--active-bg: #dc143c;
@@ -15,6 +16,7 @@
font-family: "Poppins", sans-serif !important;
font-weight: 300;
}
.text {
position: absolute;
background: var(--primary-bg);
@@ -47,11 +49,13 @@
left: 45vw;
top: -100px;
}
.top.show {
transition: 0.5s;
top: 10px;
opacity: 1;
}
.top.hide {
transition: 0.5s;
top: -100px;
@@ -62,11 +66,13 @@
top: 50%;
right: -100px;
}
.right.show {
transition: 0.5s;
right: 10px;
opacity: 1;
}
.right.hide {
transition: 0.5s;
right: -100px;
@@ -83,8 +89,9 @@
left: 10px;
opacity: 1;
}
.left.hide {
transition: 0.5s;
left: -100px;
opacity: 0;
}
}
+6 -6
View File
@@ -10,7 +10,7 @@ html::-webkit-scrollbar {
border-left: 0.5rem solid #20bb44;
font-size: 1.5vh;
}
.primary {
background-color: rgba(23, 23, 23, 90%);
border-radius: 10px;
@@ -18,7 +18,7 @@ html::-webkit-scrollbar {
border-left: 5px solid #1c75d2;
font-size: 1.5vh;
}
.error {
background-color: rgba(23, 23, 23, 90%);
border-radius: 10px;
@@ -26,7 +26,7 @@ html::-webkit-scrollbar {
border-left: 5px solid #c10114;
font-size: 1.5vh;
}
.police {
background-color: rgba(23, 23, 23, 90%);
border-radius: 10px;
@@ -34,7 +34,7 @@ html::-webkit-scrollbar {
border-left: 5px solid #2197f2;
font-size: 1.5vh;
}
.ambulance {
background-color: rgba(23, 23, 23, 90%);
border-radius: 10px;
@@ -42,7 +42,7 @@ html::-webkit-scrollbar {
border-left: 5px solid #f44236;
font-size: 1.5vh;
}
}
.success {
@@ -78,4 +78,4 @@ html::-webkit-scrollbar {
border-radius: 10px;
box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
border-left: 5px solid #f44236;
}
}
+9 -35
View File
@@ -1,46 +1,20 @@
<html>
<head>
<link
href="https://fonts.googleapis.com/css2?family=Poppins&display=swap"
rel="stylesheet"
/>
<link
href="https://cdn.jsdelivr.net/npm/quasar@2.1.0/dist/quasar.prod.css"
rel="stylesheet"
type="text/css"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/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.1.0/dist/quasar.umd.prod.js"
defer
></script>
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/quasar@2.1.0/dist/quasar.prod.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/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.1.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/drawtext.css">
</head>
<body style="font-family: 'Poppins', sans-serif">
<div
id="q-app"
style="min-height: 100vh"
></div>
<div id="q-app" style="min-height: 100vh"></div>
<div id="drawtext-container">
<div id="text" class="text"></div>
</div>
</body>
</html>
</html>
-1
View File
@@ -8,7 +8,6 @@ import {
} from "./config.js";
const { useQuasar } = Quasar;
const { onMounted, onUnmounted } = Vue;
const app = Vue.createApp({
+2 -2
View File
@@ -13,13 +13,13 @@ export const DEV_MODE = false;
* Will hold config statically outside of Vue state
* @property {Record<string, NotiVariantData>} VariantDefinitions
* @property {Record<string, any>} NotificationStyling
* */
**/
export let NOTIFY_CONFIG = null;
/**
* Pure function taking a notification type and returning an object
* with style details
* @param variant {string}
* @param {string} variant
* @returns NotiVariantData
**/
export const determineStyleFromVariant = (variant) => {
+93 -93
View File
@@ -1,124 +1,124 @@
let direction = null;
const drawText = async (textData) => {
const text = document.getElementById("text");
let {position} = textData;
switch (textData.position) {
case "left":
addClass(text, position);
direction = "left";
break;
case "top":
addClass(text, position);
direction = "top";
break;
case "right":
addClass(text, position);
direction = "right";
break;
default:
addClass(text, "left");
direction = "left";
break;
}
const text = document.getElementById("text");
let {position} = textData;
switch (textData.position) {
case "left":
addClass(text, position);
direction = "left";
break;
case "top":
addClass(text, position);
direction = "top";
break;
case "right":
addClass(text, position);
direction = "right";
break;
default:
addClass(text, "left");
direction = "left";
break;
}
text.innerHTML = textData.text;
document.getElementById("drawtext-container").style.display = "block";
await sleep(100);
addClass(text, "show");
text.innerHTML = textData.text;
document.getElementById("drawtext-container").style.display = "block";
await sleep(100);
addClass(text, "show");
};
const changeText = async (textData) => {
const text = document.getElementById("text");
let {position} = textData;
const text = document.getElementById("text");
let {position} = textData;
removeClass(text, "show");
addClass(text, "pressed");
addClass(text, "hide");
removeClass(text, "show");
addClass(text, "pressed");
addClass(text, "hide");
await sleep(500);
await sleep(500);
removeClass(text, "left");
removeClass(text, "right");
removeClass(text, "top");
removeClass(text, "bottom");
removeClass(text, "hide");
removeClass(text, "pressed");
switch (textData.position) {
case "left":
addClass(text, position);
direction = "left";
break;
case "top":
addClass(text, position);
direction = "top";
break;
case "right":
addClass(text, position);
direction = "right";
break;
default:
addClass(text, "left");
direction = "left";
break;
}
text.innerHTML = textData.text;
await sleep(100);
text.classList.add("show");
};
const hideText = async () => {
const text = document.getElementById("text");
removeClass(text, "show");
addClass(text, "hide");
setTimeout(() => {
removeClass(text, "left");
removeClass(text, "right");
removeClass(text, "top");
removeClass(text, "bottom");
removeClass(text, "hide");
removeClass(text, "pressed");
switch (textData.position) {
case "left":
addClass(text, position);
direction = "left";
break;
case "top":
addClass(text, position);
direction = "top";
break;
case "right":
addClass(text, position);
direction = "right";
break;
default:
addClass(text, "left");
direction = "left";
break;
}
text.innerHTML = textData.text;
await sleep(100);
text.classList.add("show");
};
const hideText = async () => {
const text = document.getElementById("text");
removeClass(text, "show");
addClass(text, "hide");
setTimeout(() => {
removeClass(text, "left");
removeClass(text, "right");
removeClass(text, "top");
removeClass(text, "bottom");
removeClass(text, "hide");
removeClass(text, "pressed");
document.getElementById("drawtext-container").style.display = "none";
}, 1000);
document.getElementById("drawtext-container").style.display = "none";
}, 1000);
};
const keyPressed = () => {
const text = document.getElementById("text");
addClass(text, "pressed");
const text = document.getElementById("text");
addClass(text, "pressed");
};
window.addEventListener("message", (event) => {
const data = event.data;
const action = data.action;
const textData = data.data;
switch (action) {
case "DRAW_TEXT":
return drawText(textData);
case "CHANGE_TEXT":
return changeText(textData);
case "HIDE_TEXT":
return hideText();
case "KEY_PRESSED":
return keyPressed();
default:
return;
}
const data = event.data;
const action = data.action;
const textData = data.data;
switch (action) {
case "DRAW_TEXT":
return drawText(textData);
case "CHANGE_TEXT":
return changeText(textData);
case "HIDE_TEXT":
return hideText();
case "KEY_PRESSED":
return keyPressed();
default:
return;
}
});
const sleep = (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
return new Promise((resolve) => setTimeout(resolve, ms));
};
const removeClass = (element, name) => {
if (element.classList.contains(name)) {
element.classList.remove(name);
}
if (element.classList.contains(name)) {
element.classList.remove(name);
}
};
const addClass = (element, name) => {
if (!element.classList.contains(name)) {
element.classList.add(name);
}
if (!element.classList.contains(name)) {
element.classList.add(name);
}
};
+8 -2
View File
@@ -7,7 +7,10 @@ local Translations = {
no_access = 'لا يمكن الوصول إلى هذا الأمر',
company_too_poor = 'مسؤول الوظيفة لا يمكلك مال كاف-ي',
item_not_exist = 'عنصر غير موجود',
too_heavy = 'لا يوجد مساحة في جقيبتك'
too_heavy = 'لا يوجد مساحة في جقيبتك',
duplicate_license = 'وجدنا ترخيص روكستار مكرر او موجود مسبقا',
no_valid_license = 'ترخيص روكستار غير صحيح',
not_whitelisted = 'عضويتك غير مفعلة في هذا السيرفر'
},
success = {},
info = {
@@ -15,7 +18,10 @@ local Translations = {
job_info = '%{value} | %{value2} | %{value3}',
gang_info = '%{value} | %{value2}',
on_duty = 'انت الان خارج الخدمة',
off_duty = 'انت الان في الخدمة'
off_duty = 'انت الان في الخدمة',
checking_ban = 'نحن نتحقق اذا كنت محجوب من السيرفر. %s مرحبا',
join_server = '{Server Name} قي %s مرحبا',
checking_whitelisted = 'نتحقق ما اذا كان مسموح لك بالدخول %s مرحبا '
}
}
+15 -9
View File
@@ -2,20 +2,26 @@ local Translations = {
error = {
not_online = 'שחקן לא מחובר',
wrong_format = 'פורמט שגוי',
missing_args = 'יש לכתוב את הפקודה לפי מה שכתוב (x, y, z)',
missing_args2 = 'יש למלא את כל המידע המבוקש',
no_access = 'אין לך גישה לפקודה זו',
company_too_poor = 'העסק שלך שבור',
item_not_exist = 'אייטם לא נמצא',
too_heavy = 'אינבנטורי מלא'
missing_args = '(x, y, z) לא כל פרמטר הוזן',
missing_args2 = '!יש להזין את כל הפרמטרים',
no_access = 'אין גישה לפקודה זו',
company_too_poor = 'המעסיק שלך עני מידי',
item_not_exist = 'פריט לא קיים',
too_heavy = 'אינבנטורי מלא',
duplicate_license = 'Rockstar נמצא שכפול רישיון',
no_valid_license = 'תקף Rockstar לא נמצא רישיון',
not_whitelisted = 'את/ה לא ברשימת המותרים בשרת הזה'
},
success = {},
info = {
received_paycheck = '$%{value} קיבלת משבורת על סך',
received_paycheck = '$%{value} קיבלת תלוש שכר על סך',
job_info = '%{value3} :בתפקיד | %{value2} :דרגה | %{value} :עבודה',
gang_info = '%{value2} :דרגה | %{value} :גאנג',
on_duty = 'אתה בתפקיד כעת',
off_duty = 'ירדת מתפקיד כעת'
on_duty = '!עלית לתפקיד',
off_duty = '!ירדת מהתפקיד',
checking_ban = '.אנחנו בודקים אם את/ה חסום/ה בשרת הזה .%s שלום',
join_server = '.{Server Name}-ל %s ברוך/ה הבא/ה',
checking_whitelisted = '.אנחנו בודקים אם את/ה ברשימת המותרים .%s שלום'
}
}
+13 -7
View File
@@ -2,20 +2,26 @@ local Translations = {
error = {
not_online = 'Игрок не в сети',
wrong_format = 'Неверный формат',
missing_args = 'Введены не все аргументы (x, y, z)',
missing_args = 'Не все аргументы были заполнены (x, y, z)',
missing_args2 = 'Все аргументы должны быть заполнены!',
no_access = 'Нет доступа к этой команде',
company_too_poor = 'Ваш работодатель разорился',
item_not_exist = 'Элемент не существует',
too_heavy = 'Инвентарь слишком полон'
company_too_poor = 'Ваш работодатель без денег',
item_not_exist = 'Вещь не существует',
too_heavy = 'Инвентарь слишком полный',
duplicate_license = 'Найден дубликат лицензии Rockstar',
no_valid_license = 'Не найдена действующая лицензия Rockstar',
not_whitelisted = 'Вы не в белом списке этого сервера'
},
success = {},
info = {
received_paycheck = 'Вы получили зарплату в размере $%{value}',
job_info = 'Задание: %{значение} | Оценка: %{value2} | Обязанность: %{value3}',
gang_info = 'Банда: %{значение} | Оценка: %{value2}',
job_info = 'Задание: %{value} | Оценка: %{value2} | Дежурство: %{value3}',
gang_info = 'Банда: %{value} | Оценка: %{value2}',
on_duty = 'Вы сейчас на дежурстве!',
off_duty = 'Вы сейчас не дежурный!'
off_duty = 'Вы сейчас не дежурный!',
checking_ban = 'Привет %s. Мы проверяем если вы забанены.',
join_server = 'Добро пожаловать %s в {Server Name}.',
checking_whitelisted = 'Привет %s. Мы проверяем если вы в белом списке.'
}
}
+17 -11
View File
@@ -1,21 +1,27 @@
local Translations = {
error = {
not_online = 'Oyuncu çevrimiçi değil',
wrong_format = 'Yanlış birim',
missing_args = 'Her argüman girilmedi (x, y, z)',
missing_args2 = 'Tüm argümanlar doldurulmalıdır!',
no_access = 'Bu komuta erişim yok',
company_too_poor = 'İşvereniniz bozuk',
item_not_exist = 'Öğe mevcut değil',
too_heavy = 'Envanter çok dolu'
not_online = 'Oyuncu çevrimiçi değil.',
wrong_format = 'Yanlış format.',
missing_args = 'Hiçbir argüman girilmedi. (x, y, z)',
missing_args2 = 'Tüm argümanlar doldurulmalıdır.',
no_access = 'Bu komuta erişimin yok.',
company_too_poor = 'Şirketin hiç parası yok.',
item_not_exist = 'Eşya mevcut değil.',
too_heavy = 'Envanter çok dolu',
duplicate_license = 'Aynı rockstar lisansı zaten şu an sunucuda!',
no_valid_license = 'Geçerli bir rockstar lisans bulunamadı.',
not_whitelisted = 'Bu sunucuda whitelistin yok.'
},
success = {},
info = {
received_paycheck = 'Maaş çekinizi aldınız $%{value}',
received_paycheck = '$%{value} tutarında bir maaş çeki aldın.',
job_info = 'İş: %{value} | Seviye: %{value2} | Görev: %{value3}',
gang_info = 'Çete: %{value} | Seviye: %{value2}',
on_duty = 'Şimdi görev başındasın!',
off_duty = 'Şimdi görevden alındın!'
on_duty = 'Mesaiye girdin.',
off_duty = 'Mesaiden çıktın.',
checking_ban = 'Merhaba %s. Banlı mısın diye kontrol ediyoruz.',
join_server = 'Merhaba %s. {Server Name} adlı sunucumuza hoş geldin.',
checking_whitelisted = 'Merhaba %s. Whitelist\'in var mı diye kontrol ediyoruz.'
}
}
+31 -5
View File
@@ -13,17 +13,43 @@ end)
-- Register & Refresh Commands
function QBCore.Commands.Add(name, help, arguments, argsrequired, callback, permission)
function QBCore.Commands.Add(name, help, arguments, argsrequired, callback, permission, ...)
local restricted = true -- Default to restricted for all commands
if not permission then permission = 'user' end -- some commands don't pass permission level
if permission == 'user' then restricted = false end -- allow all users to use command
RegisterCommand(name, callback, restricted) -- Register command within fivem
if not QBCore.Commands.IgnoreList[permission] then -- only create aces for extra perm levels
ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission, name))
RegisterCommand(name, function(source, args, rawCommand) -- Register command within fivem
if argsrequired and #args < #arguments then
return TriggerClientEvent('chat:addMessage', source, {
color = {255, 0, 0},
multiline = true,
args = {"System", Lang:t("error.missing_args2")}
})
end
callback(source, args, rawCommand)
end, restricted)
local extraPerms = ... and table.pack(...) or nil
if extraPerms then
extraPerms[extraPerms.n + 1] = permission -- The `n` field is the number of arguments in the packed table
extraPerms.n += 1
permission = extraPerms
for i = 1, permission.n do
if not QBCore.Commands.IgnoreList[permission[i]] then -- only create aces for extra perm levels
ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission[i], name))
end
end
permission.n = nil
else
permission = tostring(permission:lower())
if not QBCore.Commands.IgnoreList[permission] then -- only create aces for extra perm levels
ExecuteCommand(('add_ace qbcore.%s command.%s allow'):format(permission, name))
end
end
QBCore.Commands.List[name:lower()] = {
name = name:lower(),
permission = tostring(permission:lower()),
permission = permission,
help = help,
arguments = arguments,
argsrequired = argsrequired,
+2 -2
View File
@@ -37,9 +37,9 @@ function QBCore.Debug(tbl, indent)
end
function QBCore.ShowError(resource, msg)
print('\x1b[31m['..resource..':ERROR]\x1b[0m '..msg)
print('\x1b[31m[' .. resource .. ':ERROR]\x1b[0m ' .. msg)
end
function QBCore.ShowSuccess(resource, msg)
print('\x1b[32m['..resource..':LOG]\x1b[0m '..msg)
print('\x1b[32m[' .. resource .. ':LOG]\x1b[0m ' .. msg)
end
+26 -14
View File
@@ -216,31 +216,43 @@ QBCore.Functions.CreateCallback('QBCore:HasItem', function(source, cb, items, am
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return cb(false) end
local isTable = type(items) == 'table'
local isArray = isTable and table.type(items) == 'array' or false
local totalItems = #items
local count = 0
local isArray = isTable and table.type(items) == 'array' or false
local totalItems = #items
local count = 0
local kvIndex = 2
if isTable and not isArray then
if isTable and not isArray then
totalItems = 0
for _ in pairs(items) do totalItems += 1 end
kvIndex = 1
end
if isTable then
for k, v in pairs(items) do
local itemKV = {k, v}
local item = Player.Functions.GetItemByName(itemKV[kvIndex])
for k, v in pairs(items) do
local itemKV = {k, v}
local item = Player.Functions.GetItemByName(itemKV[kvIndex])
if item and ((amount and item.amount >= amount) or (not amount and not isArray and item.amount >= v) or (not amount and isArray)) then
count += 1
end
end
if count == totalItems then
retval = true
end
else -- Single item as string
local item = Player.Functions.GetItemByName(items)
end
if count == totalItems then
retval = true
end
else -- Single item as string
local item = Player.Functions.GetItemByName(items)
if item and not amount or (item and amount and item.amount >= amount) then
retval = true
end
end
end
cb(retval)
end)
-- Vehicle server-side spawning callback (netId)
-- use the netid on the client with the NetworkGetEntityFromNetworkId native
-- convert it to a vehicle via the NetToVeh native
QBCore.Functions.CreateCallback('QBCore:Server:SpawnVehicle', function(source, cb, model, coords, warp)
model = type(model) == 'string' and GetHashKey(model) or model
if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, true)
while not DoesEntityExist(veh) do Wait(0) end
if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
cb(NetworkGetNetworkIdFromEntity(veh))
end)
+16 -2
View File
@@ -10,10 +10,11 @@ local function AddJob(jobName, job)
QBCore.Shared.Jobs[jobName] = job
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1,'Jobs', jobName, job)
TriggerClientEvent('QBCore:Client:OnSharedUpdate', -1, 'Jobs', jobName, job)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.AddJob = AddJob
exports('AddJob', AddJob)
@@ -46,6 +47,7 @@ local function AddJobs(jobs)
TriggerEvent('QBCore:Server:UpdateObject')
return true, message, nil
end
QBCore.Functions.AddJobs = AddJobs
exports('AddJobs', AddJobs)
@@ -65,6 +67,7 @@ local function RemoveJob(jobName)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.RemoveJob = RemoveJob
exports('RemoveJob', RemoveJob)
@@ -84,6 +87,7 @@ local function UpdateJob(jobName, job)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.UpdateJob = UpdateJob
exports('UpdateJob', UpdateJob)
@@ -103,6 +107,7 @@ local function AddItem(itemName, item)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.AddItem = AddItem
exports('AddItem', AddItem)
@@ -119,6 +124,7 @@ local function UpdateItem(itemName, item)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.UpdateItem = UpdateItem
exports('UpdateItem', UpdateItem)
@@ -151,6 +157,7 @@ local function AddItems(items)
TriggerEvent('QBCore:Server:UpdateObject')
return true, message, nil
end
QBCore.Functions.AddItems = AddItems
exports('AddItems', AddItems)
@@ -170,6 +177,7 @@ local function RemoveItem(itemName)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.RemoveItem = RemoveItem
exports('RemoveItem', RemoveItem)
@@ -189,6 +197,7 @@ local function AddGang(gangName, gang)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.AddGang = AddGang
exports('AddGang', AddGang)
@@ -221,6 +230,7 @@ local function AddGangs(gangs)
TriggerEvent('QBCore:Server:UpdateObject')
return true, message, nil
end
QBCore.Functions.AddGangs = AddGangs
exports('AddGangs', AddGangs)
@@ -240,6 +250,7 @@ local function RemoveGang(gangName)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.RemoveGang = RemoveGang
exports('RemoveGang', RemoveGang)
@@ -259,6 +270,7 @@ local function UpdateGang(gangName, gang)
TriggerEvent('QBCore:Server:UpdateObject')
return true, "success"
end
QBCore.Functions.UpdateGang = UpdateGang
exports('UpdateGang', UpdateGang)
@@ -269,6 +281,7 @@ local function GetCoreVersion(InvokingResource)
end
return resourceVersion
end
QBCore.Functions.GetCoreVersion = GetCoreVersion
exports('GetCoreVersion', GetCoreVersion)
@@ -284,6 +297,7 @@ local function ExploitBan(playerId, origin)
'Anti Cheat'
})
DropPlayer(playerId, "You have been banned for cheating. Check our Discord for more information: " .. QBCore.Config.Server.Discord)
TriggerEvent("qb-log:server:CreateLog", "anticheat", "Anti-Cheat", "red", name.." has been banned for exploiting "..origin, true)
TriggerEvent("qb-log:server:CreateLog", "anticheat", "Anti-Cheat", "red", name .. " has been banned for exploiting " .. origin, true)
end
exports('ExploitBan', ExploitBan)
+27 -3
View File
@@ -167,6 +167,30 @@ function QBCore.Functions.GetEntitiesInBucket(bucket --[[ int ]])
end
end
-- Server side vehicle creation with optional callback
-- the CreateVehicle RPC still uses the client for creation so players must be near
function QBCore.Functions.SpawnVehicle(model, cb, coords, warp)
model = type(model) == 'string' and GetHashKey(model) or model
if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
local veh = CreateVehicle(model, coords.x, coords.y, coords.z, coords.w, true, true)
while not DoesEntityExist(veh) do Wait(0) end
if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
if cb then cb(veh) end
end
-- Server side vehicle creation with optional callback
-- the CreateAutomobile native is still experimental but doesn't use client for creation
-- doesn't work for all vehicles!
function QBCore.Functions.CreateVehicle(model, cb, coords, warp)
model = type(model) == 'string' and GetHashKey(model) or model
if not coords then coords = GetEntityCoords(GetPlayerPed(source)) end
local CreateAutomobile = GetHashKey("CREATE_AUTOMOBILE")
local veh = Citizen.InvokeNative(CreateAutomobile, model, coords, coords.w, true, true)
while not DoesEntityExist(veh) do Wait(0) end
if warp then TaskWarpPedIntoVehicle(GetPlayerPed(source), veh, -1) end
if cb then cb(veh) end
end
-- Paychecks (standalone - don't touch)
function PaycheckInterval()
@@ -374,11 +398,11 @@ function QBCore.Functions.HasItem(source, items, amount)
local Player = QBCore.Functions.GetPlayer(source)
if not Player then return false end
local isTable = type(items) == 'table'
local isArray = isTable and table.type(items) == 'array' or false
local totalItems = #items
local isArray = isTable and table.type(items) == 'array' or false
local totalItems = #items
local count = 0
local kvIndex = 2
if isTable and not isArray then
if isTable and not isArray then
totalItems = 0
for _ in pairs(items) do totalItems += 1 end
kvIndex = 1
+9 -9
View File
@@ -600,19 +600,19 @@ function QBCore.Player.DeleteCharacter(source, citizenid)
local result = MySQL.scalar.await('SELECT license FROM players where citizenid = ?', { citizenid })
if license == result then
local query = "DELETE FROM %s WHERE citizenid = ?"
local tableCount = #playertables
local queries = table.create(tableCount, 0)
local tableCount = #playertables
local queries = table.create(tableCount, 0)
for i = 1, tableCount do
local v = playertables[i]
queries[i] = {query = query:format(v.table), values = { citizenid }}
end
for i = 1, tableCount do
local v = playertables[i]
queries[i] = {query = query:format(v.table), values = { citizenid }}
end
MySQL.transaction(queries, function(result2)
if result2 then
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Character Deleted', 'red', '**' .. GetPlayerName(source) .. '** ' .. license .. ' deleted **' .. citizenid .. '**..')
if result2 then
TriggerEvent('qb-log:server:CreateLog', 'joinleave', 'Character Deleted', 'red', '**' .. GetPlayerName(source) .. '** ' .. license .. ' deleted **' .. citizenid .. '**..')
end
end)
end)
else
DropPlayer(source, 'You Have Been Kicked For Exploitation')
TriggerEvent('qb-log:server:CreateLog', 'anticheat', 'Anti-Cheat', 'white', GetPlayerName(source) .. ' Has Been Dropped For Character Deletion Exploit', true)
+5 -6
View File
@@ -44,7 +44,7 @@ end
--- internally for initial population of phrases field.
--- @param phrases table<string, string> - Table of phrase definitions
--- @param prefix string | nil - Optional prefix used for recursive calls
--- @return void
--- @return nil
function Locale:extend(phrases, prefix)
for key, phrase in pairs(phrases) do
local prefixKey = prefix and ('%s.%s'):format(prefix, key) or key
@@ -57,10 +57,9 @@ function Locale:extend(phrases, prefix)
end
end
--- Clear locale instance phrases
--- Might be useful for memory management of large phrase maps.
--- @return void
--- @return nil
function Locale:clear()
self.phrases = {}
end
@@ -69,8 +68,8 @@ end
--- @param phrases table<string, any>
function Locale:replace(phrases)
phrases = phrases or {}
self.clear()
self.extend(phrases)
self:clear()
self:extend(phrases)
end
--- Gets & Sets a locale depending on if an argument is passed
@@ -85,7 +84,7 @@ end
--- Primary translation method for a phrase of given key
--- @param key string - The phrase key to target
--- @param subs table<string, string>
--- @param subs table<string, any> | nil
--- @return string
function Locale:t(key, subs)
local phrase, result
+20 -20
View File
@@ -3,9 +3,9 @@ QBShared = QBShared or {}
local StringCharset = {}
local NumberCharset = {}
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
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
@@ -22,16 +22,16 @@ function QBShared.SplitStr(str, delimiter)
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)
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)
result[#result + 1] = string.sub(str, from)
return result
end
function QBShared.Trim(value)
if not value then return nil end
if not value then return nil end
return (string.gsub(value, '^%s*(.-)%s*$', '%1'))
end
@@ -42,24 +42,24 @@ function QBShared.Round(value, numDecimalPlaces)
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
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.SetDefaultVehicleExtras(vehicle, config)
-- Clear Extras
for i = 1,20 do
for i = 1, 20 do
if DoesExtraExist(vehicle, i) then
SetVehicleExtra(vehicle, i, 1)
end
+23 -23
View File
@@ -1236,7 +1236,7 @@ QBShared.Vehicles = {
['brand'] = 'Vapid',
['model'] = 'peyote2',
['price'] = 40000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `peyote2`,
['shop'] = 'pdm',
},
@@ -3095,7 +3095,7 @@ QBShared.Vehicles = {
['brand'] = 'Imponte',
['model'] = 'deluxo',
['price'] = 55000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `deluxo`,
['shop'] = 'pdm',
},
@@ -3104,7 +3104,7 @@ QBShared.Vehicles = {
['brand'] = 'Weeny',
['model'] = 'dynasty',
['price'] = 25000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `dynasty`,
['shop'] = 'pdm',
},
@@ -3149,7 +3149,7 @@ QBShared.Vehicles = {
['brand'] = 'Dewbauchee',
['model'] = 'jb700',
['price'] = 240000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `jb700`,
['shop'] = 'pdm',
},
@@ -3158,7 +3158,7 @@ QBShared.Vehicles = {
['brand'] = 'Dewbauchee',
['model'] = 'jb7002',
['price'] = 40000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `jb7002`,
['shop'] = 'pdm',
},
@@ -3194,7 +3194,7 @@ QBShared.Vehicles = {
['brand'] = 'Lampadati',
['model'] = 'michelli',
['price'] = 30000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `michelli`,
['shop'] = 'pdm',
},
@@ -3212,7 +3212,7 @@ QBShared.Vehicles = {
['brand'] = 'Vulcar',
['model'] = 'nebula',
['price'] = 22000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `nebula`,
['shop'] = 'pdm',
},
@@ -3221,7 +3221,7 @@ QBShared.Vehicles = {
['brand'] = 'Vapid',
['model'] = 'peyote',
['price'] = 23500,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `peyote`,
['shop'] = 'pdm',
},
@@ -3230,7 +3230,7 @@ QBShared.Vehicles = {
['brand'] = 'Vapid',
['model'] = 'peyote3',
['price'] = 48000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `peyote3`,
['shop'] = 'pdm',
},
@@ -3257,7 +3257,7 @@ QBShared.Vehicles = {
['brand'] = 'Vapid',
['model'] = 'retinue',
['price'] = 32000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `retinue`,
['shop'] = 'pdm',
},
@@ -3266,7 +3266,7 @@ QBShared.Vehicles = {
['brand'] = 'Vapid',
['model'] = 'retinue2',
['price'] = 38000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `retinue2`,
['shop'] = 'pdm',
},
@@ -3275,7 +3275,7 @@ QBShared.Vehicles = {
['brand'] = 'Annis',
['model'] = 'savestra',
['price'] = 67000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `savestra`,
['shop'] = 'pdm',
},
@@ -3284,7 +3284,7 @@ QBShared.Vehicles = {
['brand'] = 'Grotti',
['model'] = 'stinger',
['price'] = 39500,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `stinger`,
['shop'] = 'pdm',
},
@@ -3302,7 +3302,7 @@ QBShared.Vehicles = {
['brand'] = 'Ocelot',
['model'] = 'stromberg',
['price'] = 80000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `stromberg`,
['shop'] = 'pdm',
},
@@ -3311,7 +3311,7 @@ QBShared.Vehicles = {
['brand'] = 'Ocelot',
['model'] = 'swinger',
['price'] = 221000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `swinger`,
['shop'] = 'pdm',
},
@@ -3329,7 +3329,7 @@ QBShared.Vehicles = {
['brand'] = 'Declasse',
['model'] = 'tornado',
['price'] = 21000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `tornado`,
['shop'] = 'pdm',
},
@@ -3338,7 +3338,7 @@ QBShared.Vehicles = {
['brand'] = 'Declasse',
['model'] = 'tornado2',
['price'] = 22000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `tornado2`,
['shop'] = 'pdm',
},
@@ -3347,7 +3347,7 @@ QBShared.Vehicles = {
['brand'] = 'Declasse',
['model'] = 'tornado5',
['price'] = 22000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `tornado5`,
['shop'] = 'pdm',
},
@@ -3356,7 +3356,7 @@ QBShared.Vehicles = {
['brand'] = 'Grotti',
['model'] = 'turismo2',
['price'] = 170000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `turismo2`,
['shop'] = 'pdm',
},
@@ -3365,7 +3365,7 @@ QBShared.Vehicles = {
['brand'] = 'Lampadati',
['model'] = 'viseris',
['price'] = 210000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `viseris`,
['shop'] = 'pdm',
},
@@ -3392,7 +3392,7 @@ QBShared.Vehicles = {
['brand'] = 'Übermacht',
['model'] = 'zion3',
['price'] = 45000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `zion3`,
['shop'] = 'pdm',
},
@@ -3401,7 +3401,7 @@ QBShared.Vehicles = {
['brand'] = 'Rune',
['model'] = 'cheburek',
['price'] = 7000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `cheburek`,
['shop'] = 'pdm',
},
@@ -3410,7 +3410,7 @@ QBShared.Vehicles = {
['brand'] = 'Pegassi',
['model'] = 'toreador',
['price'] = 50000,
['category'] = 'sportsclassic',
['category'] = 'sportsclassics',
['hash'] = `toreador`,
['shop'] = 'pdm',
},