diff --git a/client/events.lua b/client/events.lua index c172c16..f08e019 100644 --- a/client/events.lua +++ b/client/events.lua @@ -164,7 +164,7 @@ RegisterNetEvent('QBCore:Client:VehicleInfo', function(info) local hasKeys = true if GetResourceState('qb-vehiclekeys') == 'started' then - hasKeys = exports['qb-vehiclekeys']:HasKeys() + hasKeys = exports['qb-vehiclekeys']:HasKeys(plate) end local data = { @@ -208,7 +208,9 @@ end) -- Client Callback RegisterNetEvent('QBCore:Client:TriggerClientCallback', function(name, ...) - QBCore.Functions.TriggerClientCallback(name, function(...) + if not QBCore.ClientCallbacks[name] then return end + + QBCore.ClientCallbacks[name](function(...) TriggerServerEvent('QBCore:Server:TriggerClientCallback', name, ...) end, ...) end) @@ -216,7 +218,12 @@ end) -- Server Callback RegisterNetEvent('QBCore:Client:TriggerCallback', function(name, ...) if QBCore.ServerCallbacks[name] then - QBCore.ServerCallbacks[name](...) + QBCore.ServerCallbacks[name].promise:resolve(...) + + if QBCore.ServerCallbacks[name].callback then + QBCore.ServerCallbacks[name].callback(...) + end + QBCore.ServerCallbacks[name] = nil end end) diff --git a/client/functions.lua b/client/functions.lua index 4b4bda1..f6bca00 100644 --- a/client/functions.lua +++ b/client/functions.lua @@ -6,14 +6,26 @@ function QBCore.Functions.CreateClientCallback(name, cb) QBCore.ClientCallbacks[name] = cb end -function QBCore.Functions.TriggerClientCallback(name, cb, ...) - if not QBCore.ClientCallbacks[name] then return end - QBCore.ClientCallbacks[name](cb, ...) -end +function QBCore.Functions.TriggerCallback(name, ...) + local cb = nil + local args = { ... } -function QBCore.Functions.TriggerCallback(name, cb, ...) - QBCore.ServerCallbacks[name] = cb - TriggerServerEvent('QBCore:Server:TriggerCallback', name, ...) + if QBCore.Shared.IsFunction(args[1]) then + cb = args[1] + table.remove(args, 1) + end + + QBCore.ServerCallbacks[name] = { + callback = cb, + promise = promise.new() + } + + TriggerServerEvent('QBCore:Server:TriggerCallback', name, table.unpack(args)) + + if cb == nil then + Citizen.Await(QBCore.ServerCallbacks[name].promise) + return QBCore.ServerCallbacks[name].promise.value + end end function QBCore.Debug(resource, obj, depth) @@ -36,6 +48,13 @@ function QBCore.Functions.HasItem(items, amount) return exports['qb-inventory']:HasItem(items, amount) end +---Returns the full character name +---@return string +function QBCore.Functions.GetName() + local charinfo = QBCore.PlayerData.charinfo + return charinfo.firstname .. ' ' .. charinfo.lastname +end + ---@param entity number - The entity to look at ---@param timeout number - The time in milliseconds before the function times out ---@param speed number - The speed at which the entity should turn @@ -43,16 +62,13 @@ end function QBCore.Functions.LookAtEntity(entity, timeout, speed) local involved = GetInvokingResource() if not DoesEntityExist(entity) then - turnPromise:reject(involved .. ' :^1 Entity does not exist') - return turnPromise.value + return involved .. ' :^1 Entity does not exist' end - if not type(entity) == 'number' then - turnPromise:reject(involved .. ' :^1 Entity must be a number') - return turnPromise.value + if type(entity) ~= 'number' then + return involved .. ' :^1 Entity must be a number' end - if not type(speed) == 'number' then - turnPromise:reject(involved .. ' :^1 Speed must be a number') - return turnPromise.value + if type(speed) ~= 'number' then + return involved .. ' :^1 Speed must be a number' end if speed > 5.0 then speed = 5.0 end if timeout > 5000 then timeout = 5000 end @@ -62,7 +78,7 @@ function QBCore.Functions.LookAtEntity(entity, timeout, speed) local dx = targetPos.x - playerPos.x local dy = targetPos.y - playerPos.y local targetHeading = GetHeadingFromVector_2d(dx, dy) - local turnSpeed = speed + local turnSpeed local startTimeout = GetGameTimer() while true do local currentHeading = GetEntityHeading(ped) @@ -569,7 +585,7 @@ function QBCore.Functions.SetVehicleProperties(vehicle, props) SetVehicleEngineHealth(vehicle, props.engineHealth + 0.0) end if props.tankHealth then - SetVehiclePetrolTankHealth(vehicle, props.tankHealth) + SetVehiclePetrolTankHealth(vehicle, props.tankHealth + 0.0) end if props.fuelLevel then SetVehicleFuelLevel(vehicle, props.fuelLevel + 0.0) @@ -578,7 +594,7 @@ function QBCore.Functions.SetVehicleProperties(vehicle, props) SetVehicleDirtLevel(vehicle, props.dirtLevel + 0.0) end if props.oilLevel then - SetVehicleOilLevel(vehicle, props.oilLevel) + SetVehicleOilLevel(vehicle, props.oilLevel + 0.0) end if props.color1 then if type(props.color1) == 'number' then @@ -1078,3 +1094,12 @@ function QBCore.Functions.GetGroundHash(entity) local retval, success, endCoords, surfaceNormal, materialHash, entityHit = GetShapeTestResultEx(num) return materialHash, entityHit, surfaceNormal, endCoords, success, retval 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('Hello Player!') diff --git a/client/main.lua b/client/main.lua index 7407a6d..05d3b68 100644 --- a/client/main.lua +++ b/client/main.lua @@ -5,10 +5,46 @@ QBCore.Shared = QBShared QBCore.ClientCallbacks = {} QBCore.ServerCallbacks = {} -exports('GetCoreObject', function() - return QBCore -end) +-- Get the full QBCore object (default behavior): +-- local QBCore = GetCoreObject() --- To use this export in a script instead of manifest method --- Just put this line of code below at the very top of the script --- local QBCore = exports['qb-core']: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) diff --git a/config.lua b/config.lua index f0dbf8d..3c77309 100644 --- a/config.lua +++ b/config.lua @@ -8,6 +8,7 @@ QBConfig.StatusInterval = 5000 -- how often to check hu 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 diff --git a/fxmanifest.lua b/fxmanifest.lua index bc0da07..924a561 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -3,7 +3,7 @@ game 'gta5' lua54 'yes' author 'Kakarot' description 'Core resource for the framework, contains all the core functionality and features' -version '1.2.6' +version '1.3.0' shared_scripts { 'config.lua', diff --git a/locale/np.lua b/locale/np.lua new file mode 100644 index 0000000..ee88330 --- /dev/null +++ b/locale/np.lua @@ -0,0 +1,133 @@ +local Translations = { + error = { + not_online = 'खिलाडी अनलाइन छैन', + wrong_format = 'गलत ढाँचा', + missing_args = 'सबै तर्कहरू प्रविष्ट गरिएको छैन (x, y, z)', + missing_args2 = 'सबै तर्कहरू पूरा गर्नुपर्छ!', + no_access = 'यस आदेशको लागि पहुँच छैन', + company_too_poor = 'तपाईंको नियोक्ता टाट पल्टेको छ', + item_not_exist = 'वस्तु अवस्थित छैन', + too_heavy = 'इन्वेन्टरी धेरै भरिएको छ', + location_not_exist = 'स्थान अवस्थित छैन', + duplicate_license = '[QBCORE] - दोहोरिएको रकस्टार लाइसेन्स भेटियो', + no_valid_license = '[QBCORE] - मान्य रकस्टार लाइसेन्स भेटिएन', + not_whitelisted = '[QBCORE] - तपाईं यस सर्भरको लागि सेतो सूचीमा हुनुहुन्न', + server_already_open = 'सर्भर पहिले नै खुल्ला छ', + server_already_closed = 'सर्भर पहिले नै बन्द छ', + no_permission = 'तपाईंलाई यसका लागि अनुमति छैन।', + no_waypoint = 'वेपॉइंट सेट गरिएको छैन।', + tp_error = 'टेलिपोर्ट गर्दा त्रुटि।', + ban_table_not_found = '[QBCORE] - डाटाबेसमा प्रतिबन्ध तालिका फेला पार्न सकेन। कृपया तपाईंले SQL फाइल सही रूपमा आयात गरेको सुनिश्चित गर्नुहोस्।', + connecting_database_error = '[QBCORE] - डाटाबेससँग जडान गर्दा त्रुटि भयो। कृपया SQL सर्भर चलिरहेको छ र server.cfg फाइलमा विवरणहरू सही छन् भन्ने सुनिश्चित गर्नुहोस्।', + connecting_database_timeout = '[QBCORE] - डाटाबेस जडानले समय समाप्त गर्यो। कृपया SQL सर्भर चलिरहेको छ र server.cfg फाइलमा विवरणहरू सही छन् भन्ने सुनिश्चित गर्नुहोस्।', + }, + success = { + server_opened = 'सर्भर खोलियो', + server_closed = 'सर्भर बन्द भयो', + teleported_waypoint = 'वेपॉइंटमा टेलिपोर्ट भयो।', + }, + info = { + received_paycheck = 'तपाईंले $%{value} को तलब प्राप्त गर्नुभयो', + job_info = 'काम: %{value} | ग्रेड: %{value2} | ड्युटी: %{value3}', + gang_info = 'ग्याङ: %{value} | ग्रेड: %{value2}', + on_duty = 'तपाईं अब ड्युटीमा हुनुहुन्छ!', + off_duty = 'तपाईं अब ड्युटीबाट बाहिर हुनुहुन्छ!', + checking_ban = 'नमस्ते %s। हामी तपाईं प्रतिबन्धित हुनुहुन्छ कि छैन जाँच गर्दैछौं।', + join_server = 'स्वागत छ %s {Server Name} मा।', + checking_whitelisted = 'नमस्ते %s। हामी तपाईंको अनुमतिहरू जाँच्दैछौं।', + exploit_banned = 'तपाईंलाई धोकाधडीको लागि प्रतिबन्ध लगाइएको छ। थप जानकारीका लागि हाम्रो डिस्कर्ड हेर्नुहोस्: %{discord}', + exploit_dropped = 'धोकाधडीको लागि तपाईंलाई निकालिएको छ', + }, + command = { + tp = { + help = 'खिलाडी वा निर्देशांकमा टेलिपोर्ट गर्नुहोस् (केवल प्रशासक)', + params = { + x = { name = 'id/x', help = 'खिलाडीको ID वा X स्थिति' }, + y = { name = 'y', help = 'Y स्थिति' }, + z = { name = 'z', help = 'Z स्थिति' }, + }, + }, + tpm = { help = 'मार्करमा टेलिपोर्ट गर्नुहोस् (केवल प्रशासक)' }, + togglepvp = { help = 'सर्भरमा PVP सक्रिय/निष्क्रिय गर्नुहोस् (केवल प्रशासक)' }, + addpermission = { + help = 'खिलाडीलाई अनुमति दिनुहोस् (केवल देवता)', + params = { + id = { name = 'id', help = 'खिलाडीको ID' }, + permission = { name = 'permission', help = 'अनुमतिका स्तर' }, + }, + }, + removepermission = { + help = 'खिलाडीबाट अनुमति हटाउनुहोस् (केवल देवता)', + params = { + id = { name = 'id', help = 'खिलाडीको ID' }, + permission = { name = 'permission', help = 'अनुमतिका स्तर' }, + }, + }, + openserver = { help = 'सबैलाई सर्भर खोल्नुहोस् (केवल प्रशासक)' }, + closeserver = { + help = 'अनुमति बिना मानिसहरूलाई सर्भर बन्द गर्नुहोस् (केवल प्रशासक)', + params = { + reason = { name = 'reason', help = 'बन्द गर्ने कारण (वैकल्पिक)' }, + }, + }, + car = { + help = 'सवारी साधन उत्पन्न गर्नुहोस् (केवल प्रशासक)', + params = { + model = { name = 'model', help = 'सवारी साधनको मोडल नाम' }, + }, + }, + dv = { help = 'सवारी साधन मेटाउनुहोस् (केवल प्रशासक)' }, + dvall = { help = 'सबै सवारी साधन मेटाउनुहोस् (केवल प्रशासक)' }, + dvp = { help = 'सबै NPC मेटाउनुहोस् (केवल प्रशासक)' }, + dvo = { help = 'सबै वस्तुहरू मेटाउनुहोस् (केवल प्रशासक)' }, + givemoney = { + help = 'खिलाडीलाई पैसा दिनुहोस् (केवल प्रशासक)', + params = { + id = { name = 'id', help = 'खिलाडीको ID' }, + moneytype = { name = 'moneytype', help = 'पैसाको प्रकार (नगद, बैंक, क्रिप्टो)' }, + amount = { name = 'amount', help = 'पैसाको रकम' }, + }, + }, + setmoney = { + help = 'खिलाडीको पैसा सेट गर्नुहोस् (केवल प्रशासक)', + params = { + id = { name = 'id', help = 'खिलाडीको ID' }, + moneytype = { name = 'moneytype', help = 'पैसाको प्रकार (नगद, बैंक, क्रिप्टो)' }, + amount = { name = 'amount', help = 'पैसाको रकम' }, + }, + }, + job = { help = 'तपाईंको काम जाँच्नुहोस्' }, + setjob = { + help = 'खिलाडीलाई काम दिनुहोस् (केवल प्रशासक)', + params = { + id = { name = 'id', help = 'खिलाडीको ID' }, + job = { name = 'job', help = 'कामको नाम' }, + grade = { name = 'grade', help = 'कामको स्तर' }, + }, + }, + gang = { help = 'तपाईंको ग्याङ जाँच्नुहोस्' }, + setgang = { + help = 'खिलाडीलाई ग्याङ दिनुहोस् (केवल प्रशासक)', + params = { + id = { name = 'id', help = 'खिलाडीको ID' }, + gang = { name = 'gang', help = 'ग्याङको नाम' }, + grade = { name = 'grade', help = 'ग्याङको स्तर' }, + }, + }, + ooc = { help = 'OOC च्याट सन्देश' }, + me = { + help = 'स्थानीय सन्देश देखाउनुहोस्', + params = { + message = { name = 'message', help = 'पठाउनको लागि सन्देश' } + }, + }, + }, +} + +if GetConvar('qb_locale', 'en') == 'np' then + Lang = Locale:new({ + phrases = Translations, + warnOnMissing = true, + fallbackLang = Locale:new({ phrases = {}, warnOnMissing = true }) -- Fallback to empty locale if needed + }) +end diff --git a/locale/tr.lua b/locale/tr.lua index 9acc97e..d123721 100644 --- a/locale/tr.lua +++ b/locale/tr.lua @@ -1,28 +1,127 @@ local Translations = { error = { - 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.' + not_online = 'Oyuncu çevrimdışı', + wrong_format = 'Hatalı format', + missing_args = 'Tüm argümanlar girilmedi (x, y, z)', + missing_args2 = 'Tüm argümanlar doldurulmalıdır!', + no_access = 'Bu komut için erişiminiz yok', + company_too_poor = 'İşvereniniz iflas etti', + item_not_exist = 'Eşya mevcut değil', + too_heavy = 'Envanter çok dolu', + location_not_exist = 'Konum mevcut değil', + duplicate_license = '[QBCORE] - Aynı Rockstar Lisansı Bulundu', + no_valid_license = '[QBCORE] - Geçerli Rockstar Lisansı Bulunamadı', + not_whitelisted = '[QBCORE] - Bu sunucu için beyaz listedesiniz', + server_already_open = 'Sunucu zaten açık', + server_already_closed = 'Sunucu zaten kapalı', + no_permission = 'Bu işlem için yetkiniz yok...', + no_waypoint = 'Bir işaret noktası ayarlanmamış.', + tp_error = 'Taşınırken hata oluştu.', + ban_table_not_found = '[QBCORE] - Veritabanında yasaklılar tablosu bulunamadı. Lütfen SQL dosyasının doğru şekilde yüklendiğinden emin olun.', + connecting_database_error = '[QBCORE] - Veritabanına bağlanırken hata oluştu. SQL sunucusunun çalıştığından ve server.cfg dosyasındaki bilgilerin doğru olduğundan emin olun.', + connecting_database_timeout = '[QBCORE] - Veritabanı bağlantısı zaman aşımına uğradı. SQL sunucusunun çalıştığından ve server.cfg dosyasındaki bilgilerin doğru olduğundan emin olun.', + }, + success = { + server_opened = 'Sunucu açıldı', + server_closed = 'Sunucu kapandı', + teleported_waypoint = 'İşaret noktasına taşındınız.', }, - success = {}, info = { - received_paycheck = '$%{value} tutarında bir maaş çeki aldın.', - job_info = 'İş: %{value} | Seviye: %{value2} | Görev: %{value3}', + received_paycheck = 'Maaşınızı $%{value} aldınız', + job_info = 'İş: %{value} | Seviye: %{value2} | Görevde: %{value3}', gang_info = 'Çete: %{value} | Seviye: %{value2}', - 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.' - } + on_duty = 'Artık görevdeyiniz!', + off_duty = 'Artık görev dışında oldunuz!', + checking_ban = 'Merhaba %s. Yasaklı olup olmadığınızı kontrol ediyoruz.', + join_server = 'Hoşgeldiniz %s, {Sunucu Adı}\'na.', + checking_whitelisted = 'Merhaba %s. İzin durumunuzu kontrol ediyoruz.', + exploit_banned = 'Hile yaptığınız için yasaklandınız. Daha fazla bilgi için Discord\'umuza göz atın: %{discord}', + exploit_dropped = 'Hile yapmaktan dolayı sunucudan atıldınız', + }, + command = { + tp = { + help = 'Oyuncuya veya Koordinatlara TP (Sadece Admin)', + params = { + x = { name = 'id/x', help = 'Oyuncu ID\'si veya X konumu' }, + y = { name = 'y', help = 'Y konumu' }, + z = { name = 'z', help = 'Z konumu' }, + }, + }, + tpm = { help = 'İşaret noktasına TP (Sadece Admin)' }, + togglepvp = { help = 'Sunucuda PVP modunu aç/kapat (Sadece Admin)' }, + addpermission = { + help = 'Oyuncuya Yetki Ver (Tanrı Yetkisi)', + params = { + id = { name = 'id', help = 'Oyuncu ID\'si' }, + permission = { name = 'permission', help = 'Yetki seviyesi' }, + }, + }, + removepermission = { + help = 'Oyuncudan Yetki Al (Tanrı Yetkisi)', + params = { + id = { name = 'id', help = 'Oyuncu ID\'si' }, + permission = { name = 'permission', help = 'Yetki seviyesi' }, + }, + }, + openserver = { help = 'Sunucuyu herkes için aç (Sadece Admin)' }, + closeserver = { + help = 'Sunucuyu yetkisi olmayanlar için kapat (Sadece Admin)', + params = { + reason = { name = 'reason', help = 'Kapanma nedeni (isteğe bağlı)' }, + }, + }, + car = { + help = 'Araç Spawn Et (Sadece Admin)', + params = { + model = { name = 'model', help = 'Araç model adı' }, + }, + }, + dv = { help = 'Aracı Sil (Sadece Admin)' }, + dvall = { help = 'Tüm Araçları Sil (Sadece Admin)' }, + dvp = { help = 'Tüm Pedleri Sil (Sadece Admin)' }, + dvo = { help = 'Tüm Objeleri Sil (Sadece Admin)' }, + givemoney = { + help = 'Bir Oyuncuya Para Ver (Sadece Admin)', + params = { + id = { name = 'id', help = 'Oyuncu ID\'si' }, + moneytype = { name = 'moneytype', help = 'Para türü (nakit, banka, kripto)' }, + amount = { name = 'amount', help = 'Verilecek para miktarı' }, + }, + }, + setmoney = { + help = 'Oyuncunun Para Miktarını Ayarla (Sadece Admin)', + params = { + id = { name = 'id', help = 'Oyuncu ID\'si' }, + moneytype = { name = 'moneytype', help = 'Para türü (nakit, banka, kripto)' }, + amount = { name = 'amount', help = 'Para miktarı' }, + }, + }, + job = { help = 'İşinizi Kontrol Edin' }, + setjob = { + help = 'Bir Oyuncunun İşini Ayarla (Sadece Admin)', + params = { + id = { name = 'id', help = 'Oyuncu ID\'si' }, + job = { name = 'job', help = 'İş adı' }, + grade = { name = 'grade', help = 'İş seviyesi' }, + }, + }, + gang = { help = 'Çetenizi Kontrol Edin' }, + setgang = { + help = 'Bir Oyuncunun Çetesini Ayarla (Sadece Admin)', + params = { + id = { name = 'id', help = 'Oyuncu ID\'si' }, + gang = { name = 'gang', help = 'Çete adı' }, + grade = { name = 'grade', help = 'Çete seviyesi' }, + }, + }, + ooc = { help = 'OOC Sohbet Mesajı' }, + me = { + help = 'Yerel mesaj gönder', + params = { + message = { name = 'message', help = 'Gönderilecek mesaj' } + }, + }, + }, } if GetConvar('qb_locale', 'en') == 'tr' then diff --git a/server/commands.lua b/server/commands.lua index 5f90980..368736f 100644 --- a/server/commands.lua +++ b/server/commands.lua @@ -104,8 +104,9 @@ QBCore.Commands.Add('tp', Lang:t('command.tp.help'), { { name = Lang:t('command. 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) + TriggerClientEvent('QBCore:Command:TeleportToCoords', source, x, y, z, heading) else TriggerClientEvent('QBCore:Notify', source, Lang:t('error.wrong_format'), 'error') end diff --git a/server/events.lua b/server/events.lua index f741bef..00b0fa5 100644 --- a/server/events.lua +++ b/server/events.lua @@ -18,13 +18,21 @@ AddEventHandler('playerDropped', function(reason) QBCore.Players[src] = nil end) +AddEventHandler("onResourceStop", function(resName) + for i,v in pairs(QBCore.UsableItems) do + if v.resource == resName then + QBCore.UsableItems[i] = nil + end + end +end) + -- Player Connecting local readyFunction = MySQL.ready local databaseConnected, bansTableExists = readyFunction == nil, readyFunction == nil if readyFunction ~= nil then MySQL.ready(function() databaseConnected = true - + local DatabaseInfo = QBCore.Functions.GetDatabaseInfo() if not DatabaseInfo or not DatabaseInfo.exists then return end @@ -117,15 +125,23 @@ end) -- Client Callback RegisterNetEvent('QBCore:Server:TriggerClientCallback', function(name, ...) if QBCore.ClientCallbacks[name] then - QBCore.ClientCallbacks[name](...) + QBCore.ClientCallbacks[name].promise:resolve(...) + + if QBCore.ClientCallbacks[name].callback then + QBCore.ClientCallbacks[name].callback(...) + end + QBCore.ClientCallbacks[name] = nil end end) -- Server Callback RegisterNetEvent('QBCore:Server:TriggerCallback', function(name, ...) + if not QBCore.ServerCallbacks[name] then return end + local src = source - QBCore.Functions.TriggerCallback(name, src, function(...) + + QBCore.ServerCallbacks[name](src, function(...) TriggerClientEvent('QBCore:Client:TriggerCallback', src, name, ...) end, ...) end) diff --git a/server/functions.lua b/server/functions.lua index c4ae93b..8f81093 100644 --- a/server/functions.lua +++ b/server/functions.lua @@ -394,33 +394,30 @@ function QBCore.Functions.CreateVehicle(source, model, vehtype, coords, warp) return veh end ----Paychecks (standalone - don't touch) function PaycheckInterval() - if next(QBCore.Players) then - 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 - 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 QBCore.Config.Money.PayCheckSociety then - local account = exports['qb-banking']:GetAccountBalance(Player.PlayerData.job.name) - if account ~= 0 then -- Checks if player is employed by a society - if account < payment then -- Checks if company has enough money to pay society - TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('error.company_too_poor'), 'error') - else - Player.Functions.AddMoney('bank', payment, 'paycheck') - exports['qb-banking']:RemoveMoney(Player.PlayerData.job.name, payment, 'Employee Paycheck') - TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment })) - end - else - Player.Functions.AddMoney('bank', payment, 'paycheck') - TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment })) - end + if not next(QBCore.Players) then return end + for _, Player in pairs(QBCore.Players) do + if not Player then return end + local payment = QBShared.Jobs[Player.PlayerData.job.name]['grades'][tostring(Player.PlayerData.job.grade.level)].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 QBCore.Config.Money.PayCheckSociety then + local account = exports['qb-banking']:GetAccountBalance(Player.PlayerData.job.name) + if account ~= 0 then + if account < payment then + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('error.company_too_poor'), 'error') else Player.Functions.AddMoney('bank', payment, 'paycheck') + exports['qb-banking']:RemoveMoney(Player.PlayerData.job.name, payment, 'Employee Paycheck') TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment })) end + else + Player.Functions.AddMoney('bank', payment, 'paycheck') + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment })) end + else + Player.Functions.AddMoney('bank', payment, 'paycheck') + TriggerClientEvent('QBCore:Notify', Player.PlayerData.source, Lang:t('info.received_paycheck', { value = payment })) end end end @@ -434,9 +431,26 @@ end ---@param source any ---@param cb function ---@param ... any -function QBCore.Functions.TriggerClientCallback(name, source, cb, ...) - QBCore.ClientCallbacks[name] = cb - TriggerClientEvent('QBCore:Client:TriggerClientCallback', source, name, ...) +function QBCore.Functions.TriggerClientCallback(name, source, ...) + local cb = nil + local args = { ... } + + if QBCore.Shared.IsFunction(args[1]) then + cb = args[1] + table.remove(args, 1) + end + + QBCore.ClientCallbacks[name] = { + callback = cb, + promise = promise.new() + } + + TriggerClientEvent('QBCore:Client:TriggerClientCallback', source, name, table.unpack(args)) + + if cb == nil then + Citizen.Await(QBCore.ClientCallbacks[name].promise) + return QBCore.ClientCallbacks[name].promise.value + end end ---Create Server Callback @@ -446,23 +460,32 @@ function QBCore.Functions.CreateCallback(name, cb) QBCore.ServerCallbacks[name] = cb end ----Trigger Serv er Callback ----@param name string ----@param source any ----@param cb function ----@param ... any -function QBCore.Functions.TriggerCallback(name, source, cb, ...) - if not QBCore.ServerCallbacks[name] then return end - QBCore.ServerCallbacks[name](source, cb, ...) -end - -- Items ---Create a usable item ---@param item string ---@param data function function QBCore.Functions.CreateUseableItem(item, data) - QBCore.UsableItems[item] = data + local rawFunc = nil + + if type(data) == 'table' then + if rawget(data, '__cfx_functionReference') then + rawFunc = data + elseif data.cb and rawget(data.cb, '__cfx_functionReference') then + rawFunc = data.cb + elseif data.callback and rawget(data.callback, '__cfx_functionReference') then + rawFunc = data.callback + end + elseif type(data) == 'function' then + rawFunc = data + end + + if rawFunc then + QBCore.UsableItems[item] = { + func = rawFunc, + resource = GetInvokingResource() + } + end end ---Checks if the given item is usable @@ -628,23 +651,23 @@ end function QBCore.Functions.GetDatabaseInfo() local details = { exists = false, - database = "", + database = '', } - local connectionString = GetConvar("mysql_connection_string", "") + local connectionString = GetConvar('mysql_connection_string', '') - if connectionString == "" then + if connectionString == '' then return details - elseif connectionString:find("mysql://") then + elseif connectionString:find('mysql://') then connectionString = connectionString:sub(9, -1) - details.database = connectionString:sub(connectionString:find("/") + 1, -1):gsub("[%?]+[%w%p]*$", "") + details.database = connectionString:sub(connectionString:find('/') + 1, -1):gsub('[%?]+[%w%p]*$', '') details.exists = true return details else - connectionString = { string.strsplit(";", connectionString) } + connectionString = { string.strsplit(';', connectionString) } for i = 1, #connectionString do local v = connectionString[i] - if v:match("database") then + if v:match('database') then details.database = v:sub(10, #v) details.exists = true return details @@ -702,3 +725,12 @@ function QBCore.Functions.PrepForSQL(source, data, pattern) 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!') diff --git a/server/main.lua b/server/main.lua index 368dc05..d6228e5 100644 --- a/server/main.lua +++ b/server/main.lua @@ -4,10 +4,46 @@ QBCore.Shared = QBShared QBCore.ClientCallbacks = {} QBCore.ServerCallbacks = {} -exports('GetCoreObject', function() - return QBCore -end) +-- Get the full QBCore object (default behavior): +-- local QBCore = GetCoreObject() --- To use this export in a script instead of manifest method --- Just put this line of code below at the very top of the script --- local QBCore = exports['qb-core']: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) diff --git a/server/player.lua b/server/player.lua index 7b3363f..4f73c0d 100644 --- a/server/player.lua +++ b/server/player.lua @@ -253,6 +253,11 @@ function QBCore.Player.CreatePlayer(PlayerData, Offline) return QBCore.Functions.HasItem(self.PlayerData.source, items, amount) end + function self.Functions.GetName() + local charinfo = self.PlayerData.charinfo + return charinfo.firstname .. ' ' .. charinfo.lastname + end + function self.Functions.SetJobDuty(onDuty) self.PlayerData.job.onduty = not not onDuty TriggerEvent('QBCore:Server:OnJobUpdate', self.PlayerData.source, self.PlayerData.job) @@ -341,6 +346,7 @@ function QBCore.Player.CreatePlayer(PlayerData, Offline) end end end + if self.PlayerData.money[moneytype] - amount < QBCore.Config.Money.MinusLimit then return false end self.PlayerData.money[moneytype] = self.PlayerData.money[moneytype] - amount if not self.Offline then diff --git a/shared/items.lua b/shared/items.lua index b6f93a8..84de923 100644 --- a/shared/items.lua +++ b/shared/items.lua @@ -50,13 +50,13 @@ QBShared.Items = { weapon_pistolxm3 = { name = 'weapon_pistolxm3', label = 'Pistol XM3', weight = 1000, type = 'weapon', ammotype = 'AMMO_PISTOL', image = 'weapon_pistolxm3.png', unique = true, useable = true, description = 'Pistol XM3' }, -- Submachine Guns - weapon_microsmg = { name = 'weapon_microsmg', label = 'Micro SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_microsmg.png', unique = true, useable = false, description = 'A handheld light weight machine gun' }, - weapon_smg = { name = 'weapon_smg', label = 'SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_smg.png', unique = true, useable = false, description = 'A handheld light weight machine gun' }, + weapon_microsmg = { name = 'weapon_microsmg', label = 'Micro SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_microsmg.png', unique = true, useable = false, description = 'A handheld light weight machine gun' }, + weapon_smg = { name = 'weapon_smg', label = 'SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_smg.png', unique = true, useable = false, description = 'A handheld light weight machine gun' }, weapon_smg_mk2 = { name = 'weapon_smg_mk2', label = 'SMG Mk II', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_smg_mk2.png', unique = true, useable = true, description = 'SMG MK2' }, - weapon_assaultsmg = { name = 'weapon_assaultsmg', label = 'Assault SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_assaultsmg.png', unique = true, useable = false, description = 'An assault version of a handheld light weight machine gun' }, - weapon_combatpdw = { name = 'weapon_combatpdw', label = 'Combat PDW', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_combatpdw.png', unique = true, useable = false, description = 'A combat version of a handheld light weight machine gun' }, + weapon_assaultsmg = { name = 'weapon_assaultsmg', label = 'Assault SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_assaultsmg.png', unique = true, useable = false, description = 'An assault version of a handheld light weight machine gun' }, + weapon_combatpdw = { name = 'weapon_combatpdw', label = 'Combat PDW', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_combatpdw.png', unique = true, useable = false, description = 'A combat version of a handheld light weight machine gun' }, weapon_machinepistol = { name = 'weapon_machinepistol', label = 'Tec-9', weight = 1000, type = 'weapon', ammotype = 'AMMO_PISTOL', image = 'weapon_machinepistol.png', unique = true, useable = false, description = 'A self-loading pistol capable of burst or fully automatic fire' }, - weapon_minismg = { name = 'weapon_minismg', label = 'Mini SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_minismg.png', unique = true, useable = false, description = 'A mini handheld light weight machine gun' }, + weapon_minismg = { name = 'weapon_minismg', label = 'Mini SMG', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_minismg.png', unique = true, useable = false, description = 'A mini handheld light weight machine gun' }, weapon_raycarbine = { name = 'weapon_raycarbine', label = 'Unholy Hellbringer', weight = 1000, type = 'weapon', ammotype = 'AMMO_SMG', image = 'weapon_raycarbine.png', unique = true, useable = true, description = 'Weapon Raycarbine' }, -- Shotguns @@ -74,7 +74,7 @@ QBShared.Items = { -- Assault Rifles weapon_assaultrifle = { name = 'weapon_assaultrifle', label = 'Assault Rifle', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_assaultrifle.png', unique = true, useable = false, description = 'A rapid-fire, magazine-fed automatic rifle designed for infantry use' }, weapon_assaultrifle_mk2 = { name = 'weapon_assaultrifle_mk2', label = 'Assault Rifle Mk II', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_assaultrifle_mk2.png', unique = true, useable = true, description = 'Assault Rifle MK2' }, - weapon_carbinerifle = { name = 'weapon_carbinerifle', label = 'Carbine Rifle', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_carbinerifle.png', unique = true, useable = false, description = 'A light weight automatic rifle' }, + weapon_carbinerifle = { name = 'weapon_carbinerifle', label = 'Carbine Rifle', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_carbinerifle.png', unique = true, useable = false, description = 'A light weight automatic rifle' }, weapon_carbinerifle_mk2 = { name = 'weapon_carbinerifle_mk2', label = 'Carbine Rifle Mk II', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_carbinerifle_mk2.png', unique = true, useable = true, description = 'Carbine Rifle MK2' }, weapon_advancedrifle = { name = 'weapon_advancedrifle', label = 'Advanced Rifle', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_advancedrifle.png', unique = true, useable = false, description = 'An assault version of a rapid-fire, magazine-fed automatic rifle designed for infantry use' }, weapon_specialcarbine = { name = 'weapon_specialcarbine', label = 'Special Carbine', weight = 1000, type = 'weapon', ammotype = 'AMMO_RIFLE', image = 'weapon_specialcarbine.png', unique = true, useable = false, description = 'An extremely versatile assault rifle for any combat situation' }, diff --git a/shared/main.lua b/shared/main.lua index af21db8..b514dd5 100644 --- a/shared/main.lua +++ b/shared/main.lua @@ -68,6 +68,14 @@ function QBShared.ChangeVehicleExtra(vehicle, extra, enable) 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 diff --git a/shared/vehicles.lua b/shared/vehicles.lua index bf6bf87..b745c09 100644 --- a/shared/vehicles.lua +++ b/shared/vehicles.lua @@ -765,7 +765,9 @@ local Vehicles = { { model = 'formula', name = 'PR4', brand = 'Progen', price = 100000, category = 'openwheel', type = 'automobile', shop = 'none' }, } +QBShared.VehicleHashes = QBShared.VehicleHashes or {} for i = 1, #Vehicles do + local hash = joaat(Vehicles[i].model) QBShared.Vehicles[Vehicles[i].model] = { spawncode = Vehicles[i].model, name = Vehicles[i].name, @@ -773,8 +775,9 @@ for i = 1, #Vehicles do model = Vehicles[i].model, price = Vehicles[i].price, category = Vehicles[i].category, - hash = joaat(Vehicles[i].model), + hash = hash, type = Vehicles[i].type, shop = Vehicles[i].shop } + QBShared.VehicleHashes[hash] = QBShared.Vehicles[Vehicles[i].model] end