Merge branch 'dev' into main

This commit is contained in:
Aura Development
2025-05-08 16:23:14 +03:00
committed by GitHub
80 changed files with 577 additions and 234 deletions
-22
View File
@@ -1,22 +0,0 @@
### Description
<!-- Explain What this PR does -->
---
### Motivation
<!-- Explain why you are making this PR -->
---
### **Implementation Details**
<!-- Explain how your implemenation meets your goal -->
---
### Usage Example
<!-- If you are adding or editing functions/events show usage examples -->
---
### PR Checklist
- [] My commit messages and PR title follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard.
- [] My changes have been tested locally and function as expected.
- [] My PR does not introduce any breaking changes.
- [] I have provided a clear explanation of what my PR does, including the reasoning behind the changes and any relevant context.
+1 -1
View File
@@ -4,6 +4,6 @@ game 'gta5'
author 'ESX-Framework'
description 'Allows resources to Run tasks at specific intervals.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
server_script 'server/main.lua'
@@ -4,7 +4,7 @@ function Adjustments:RemoveHudComponents()
for i = 1, #Config.RemoveHudComponents do
if Config.RemoveHudComponents[i] then
SetHudComponentSize(i, 0.0, 0.0)
SetHudComponentPosition(i, 900, 900)
SetHudComponentPosition(i, 900.0, 900.0)
end
end
end
+23 -24
View File
@@ -14,8 +14,25 @@ Callbacks.id = 0
-- MARK: Internal Functions
-- =============================================
function Callbacks:Trigger(event, cb, invoker, ...)
function Callbacks:Register(name, resource, cb)
self.storage[name] = {
resource = resource,
cb = cb
}
end
function Callbacks:Execute(cb, id, ...)
local success, errorString = pcall(cb, ...)
if not success then
print(("[^1ERROR^7] Failed to execute Callback with RequestId: ^5%s^7"):format(id))
error(errorString)
return
end
end
function Callbacks:Trigger(event, cb, invoker, ...)
self.requests[self.id] = {
await = type(cb) == "boolean",
cb = cb or promise:new()
@@ -29,16 +46,6 @@ function Callbacks:Trigger(event, cb, invoker, ...)
return table.cb
end
function Callbacks:Execute(cb, id, ...)
local success, errorString = pcall(cb, ...)
if not success then
print(("[^1ERROR^7] Failed to execute Callback with RequestId: ^5%s^7"):format(id))
error(errorString)
return
end
end
function Callbacks:ServerRecieve(requestId, invoker, ...)
if not self.requests[requestId] then
return error(("Server Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(requestId, invoker))
@@ -49,21 +56,13 @@ function Callbacks:ServerRecieve(requestId, invoker, ...)
self.requests[requestId] = nil
if callback.await then
callback.cb:resolve({...})
callback.cb:resolve({ ... })
else
self:Execute(callback.cb, requestId, ...)
end
end
function Callbacks:Register(name, resource, cb)
self.storage[name] = {
resource = resource,
cb = cb
}
end
function Callbacks:ClientRecieve(eventName, requestId, invoker, ...)
if not self.storage[eventName] then
return error(("Client Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(eventName, invoker))
end
@@ -130,14 +129,14 @@ end
-- MARK: Events
-- =============================================
ESX.SecureNetEvent("esx:triggerClientCallback", function(...)
Callbacks:ClientRecieve(...)
end)
ESX.SecureNetEvent("esx:serverCallback", function(...)
Callbacks:ServerRecieve(...)
end)
ESX.SecureNetEvent("esx:triggerClientCallback", function(...)
Callbacks:ClientRecieve(...)
end)
AddEventHandler("onResourceStop", function(resource)
for k, v in pairs(Callbacks.storage) do
if v.resource == resource then
+52 -54
View File
@@ -2,17 +2,11 @@ ESX.Scaleform = {}
ESX.Scaleform.Utils = {}
function ESX.Scaleform.ShowFreemodeMessage(title, msg, sec)
local scaleform = ESX.Scaleform.Utils.RequestScaleformMovie("MP_BIG_MESSAGE_FREEMODE")
BeginScaleformMovieMethod(scaleform, "SHOW_SHARD_WASTED_MP_MESSAGE")
ScaleformMovieMethodAddParamTextureNameString(title)
ScaleformMovieMethodAddParamTextureNameString(msg)
EndScaleformMovieMethod()
while sec > 0 do
local scaleform = ESX.Scaleform.Utils.RunMethod("MP_BIG_MESSAGE_FREEMODE", "SHOW_SHARD_WASTED_MP_MESSAGE", false, title, msg)
local endTime = GetGameTimer() + (sec * 1000)
while GetGameTimer() < endTime do
Wait(0)
sec = sec - 0.01
DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
end
@@ -20,30 +14,13 @@ function ESX.Scaleform.ShowFreemodeMessage(title, msg, sec)
end
function ESX.Scaleform.ShowBreakingNews(title, msg, bottom, sec)
local scaleform = ESX.Scaleform.Utils.RequestScaleformMovie("BREAKING_NEWS")
local scaleform = ESX.Scaleform.Utils.RunMethod("BREAKING_NEWS", "SET_TEXT", false, msg, bottom)
ESX.Scaleform.Utils.RunMethod(scaleform, "SET_SCROLL_TEXT", false, 0, 0, title)
ESX.Scaleform.Utils.RunMethod(scaleform, "DISPLAY_SCROLL_TEXT", false, 0, 0)
BeginScaleformMovieMethod(scaleform, "SET_TEXT")
ScaleformMovieMethodAddParamTextureNameString(msg)
ScaleformMovieMethodAddParamTextureNameString(bottom)
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, "SET_SCROLL_TEXT")
ScaleformMovieMethodAddParamInt(0) -- top ticker
ScaleformMovieMethodAddParamInt(0) -- Since this is the first string, start at 0
ScaleformMovieMethodAddParamTextureNameString(title)
EndScaleformMovieMethod()
BeginScaleformMovieMethod(scaleform, "DISPLAY_SCROLL_TEXT")
ScaleformMovieMethodAddParamInt(0) -- Top ticker
ScaleformMovieMethodAddParamInt(0) -- Index of string
EndScaleformMovieMethod()
while sec > 0 do
local endTime = GetGameTimer() + (sec * 1000)
while GetGameTimer() < endTime do
Wait(0)
sec = sec - 0.01
DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
end
@@ -51,22 +28,11 @@ function ESX.Scaleform.ShowBreakingNews(title, msg, bottom, sec)
end
function ESX.Scaleform.ShowPopupWarning(title, msg, bottom, sec)
local scaleform = ESX.Scaleform.Utils.RequestScaleformMovie("POPUP_WARNING")
local scaleform = ESX.Scaleform.Utils.RunMethod("POPUP_WARNING", "SHOW_POPUP_WARNING", false, 500.0, title, msg, bottom, true)
BeginScaleformMovieMethod(scaleform, "SHOW_POPUP_WARNING")
ScaleformMovieMethodAddParamFloat(500.0) -- black background
ScaleformMovieMethodAddParamTextureNameString(title)
ScaleformMovieMethodAddParamTextureNameString(msg)
ScaleformMovieMethodAddParamTextureNameString(bottom)
ScaleformMovieMethodAddParamBool(true)
EndScaleformMovieMethod()
while sec > 0 do
local endTime = GetGameTimer() + (sec * 1000)
while GetGameTimer() < endTime do
Wait(0)
sec = sec - 0.01
DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
end
@@ -74,16 +40,11 @@ function ESX.Scaleform.ShowPopupWarning(title, msg, bottom, sec)
end
function ESX.Scaleform.ShowTrafficMovie(sec)
local scaleform = ESX.Scaleform.Utils.RequestScaleformMovie("TRAFFIC_CAM")
local scaleform = ESX.Scaleform.Utils.RunMethod("TRAFFIC_CAM", "PLAY_CAM_MOVIE", false)
BeginScaleformMovieMethod(scaleform, "PLAY_CAM_MOVIE")
EndScaleformMovieMethod()
while sec > 0 do
local endTime = GetGameTimer() + (sec * 1000)
while GetGameTimer() < endTime do
Wait(0)
sec = sec - 0.01
DrawScaleformMovieFullscreen(scaleform, 255, 255, 255, 255, 0)
end
@@ -99,3 +60,40 @@ function ESX.Scaleform.Utils.RequestScaleformMovie(movie)
return scaleform
end
--- Executes a method on a scaleform movie with optional arguments and return value.
--- The caller is responsible for disposing of the scaleform using `SetScaleformMovieAsNoLongerNeeded`.
---@param scaleform number|string # Scaleform handle or name to request the scaleform movie
---@param methodName string # The method name to call on the scaleform
---@param returnValue? boolean # Whether to return the value from the method
---@param ... number|string|boolean # Arguments to pass to the method
---@return number, number? # The scaleform handle, and the return value if `returnValue` is true
function ESX.Scaleform.Utils.RunMethod(scaleform, methodName, returnValue, ...)
scaleform = type(scaleform) == "number" and scaleform or ESX.Scaleform.Utils.RequestScaleformMovie(scaleform)
BeginScaleformMovieMethod(scaleform, methodName)
local args = { ... }
for i, arg in ipairs(args) do
local typeArg = type(arg)
if typeArg == "number" then
if math.type(arg) == "float" then
ScaleformMovieMethodAddParamFloat(arg)
else
ScaleformMovieMethodAddParamInt(arg)
end
elseif typeArg == "string" then
ScaleformMovieMethodAddParamTextureNameString(arg)
elseif typeArg == "boolean" then
ScaleformMovieMethodAddParamBool(arg)
end
end
if returnValue then
return scaleform, EndScaleformMovieMethodReturnValue()
end
EndScaleformMovieMethod()
return scaleform
end
+3 -2
View File
@@ -3,11 +3,10 @@ fx_version 'cerulean'
game 'gta5'
description 'The Core resource that provides the functionalities for all other resources.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
shared_scripts {
'locale.lua',
'locales/*.lua',
'shared/config/main.lua',
'shared/config/weapons.lua',
@@ -25,6 +24,7 @@ server_scripts {
'server/common.lua',
'server/modules/callback.lua',
'server/classes/player.lua',
'server/classes/vehicle.lua',
'server/classes/overrides/*.lua',
'server/functions.lua',
'server/modules/onesync.lua',
@@ -62,6 +62,7 @@ ui_page {
files {
'imports.lua',
'locales/*.lua',
'locale.js',
'html/ui.html',
+21
View File
@@ -42,6 +42,27 @@ if not IsDuplicityVersion() then -- Only register this event for the client
return error(('\n^1Error loading module (%s)'):format(external[i]))
end
end
else
ESX.Player = setmetatable({}, {
__call = function(_, src)
if type(src) ~= "number" then
src = ESX.GetPlayerIdFromIdentifier(src)
if not src then
return
end
elseif not ESX.IsPlayerLoaded(src) then
return
end
return setmetatable({src = src}, {
__index = function(self, method)
return function(...)
return exports.es_extended:RunStaticPlayerMethod(self.src, method, ...)
end
end
})
end
})
end
if GetResourceState("ox_lib") == "missing" then
+25 -13
View File
@@ -3,21 +3,33 @@ Locales = {}
function Translate(str, ...) -- Translate string
if not str then
error(("Resource ^5%s^1 You did not specify a parameter for the Translate function or the value is nil!"):format(GetInvokingResource() or GetCurrentResourceName()))
return "Given translate function parameter is nil!"
end
if Locales[Config.Locale] then
if Locales[Config.Locale][str] then
return string.format(Locales[Config.Locale][str], ...)
elseif Config.Locale ~= "en" and Locales["en"] and Locales["en"][str] then
return string.format(Locales["en"][str], ...)
else
return "Translation [" .. Config.Locale .. "][" .. str .. "] does not exist"
--- Load the locale file if it hasn't been loaded yet
if Locales[Config.Locale] == nil then
local success, result = pcall(function()
return assert(load(LoadResourceFile(GetCurrentResourceName(), ("locales/%s.lua"):format(Config.Locale))))()
end)
Locales[Config.Locale] = success and result or false
end
local translations = Locales[Config.Locale]
if not translations then
if Config.Locale == "en" then
return "Locale [en] does not exist"
end
elseif Config.Locale ~= "en" and Locales["en"] and Locales["en"][str] then
return string.format(Locales["en"][str], ...)
else
return "Locale [" .. Config.Locale .. "] does not exist"
-- Fall back to English translation if the current locale is not found
Config.Locale = "en"
return Translate(str, ...)
end
if translations[str] then
return translations[str]:format(...)
end
return ("Translation [%s][%s] does not exist"):format(Config.Locale, str)
end
function TranslateCap(str, ...) -- Translate string first char uppercase
@@ -26,4 +38,4 @@ end
_ = Translate
-- luacheck: ignore _U
_U = TranslateCap
_U = TranslateCap
+4 -4
View File
@@ -1,4 +1,4 @@
Locales["cs"] = {
return {
-- Inventory
["inventory"] = "Inventář ( Váha %s / %s )",
["use"] = "Použít",
@@ -223,10 +223,10 @@ Locales["cs"] = {
["weapon_tactilerifle"] = "Service Carbine",
-- Drug Wars DLC
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_acidpackage"] = "Acid Package", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
-- Thrown
["weapon_ball"] = "Míček",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["de"] = {
return {
-- Inventory
["inventory"] = "Inventar ( Gewicht %s / %s )",
["use"] = "Benutzen",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["el"] = {
return {
-- Inventory
["inventory"] = "Αποθήκη ( Βάρος %s / %s )",
["use"] = "Χρήση",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["en"] = {
return {
-- Inventory
["inventory"] = "Inventory ( Weight %s / %s )",
["use"] = "Use",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["es"] = {
return {
-- Inventory
["inventory"] = "Inventario %s / %s",
["use"] = "Usar",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["fi"] = {
return {
-- Inventory
["inventory"] = "Reppu %s / %s",
["use"] = "Käytä",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["fr"] = {
return {
-- Inventory
["inventory"] = "Inventaire ( Poids %s / %s )",
["use"] = "Utiliser",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["he"] = {
return {
-- Inventory
["inventory"] = "מלאי ( משקל %s / %s )",
["use"] = "השתמש",
+4 -4
View File
@@ -1,4 +1,4 @@
Locales["hu"] = {
return {
-- Inventory
["inventory"] = "Inventory ( Súly %s / %s )",
["use"] = "Használ",
@@ -229,10 +229,10 @@ Locales["hu"] = {
["weapon_tactilerifle"] = "Service Carbine",
-- Drug Wars DLC
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_acidpackage"] = "Acid Package", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
-- Thrown
["weapon_ball"] = "Baseball",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["id"] = {
return {
-- Inventory
["inventory"] = "Inventaris ( Berat %s / %s )",
["use"] = "Gunakan",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["it"] = {
return {
-- Inventory
["inventory"] = "Inventario ( Peso %s / %s )",
["use"] = "Usa",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["nl"] = {
return {
-- Inventory
["inventory"] = "Inventaris ( Gewicht %s / %s )",
["use"] = "Gebruik",
+4 -4
View File
@@ -1,4 +1,4 @@
Locales["pl"] = {
return {
-- Inventory
["inventory"] = "ekwipunek %s / %s",
["use"] = "użyj",
@@ -202,10 +202,10 @@ Locales["pl"] = {
["component_luxary_finish"] = "luksusowe wykończenie broni",
-- Drug Wars DLC
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_acidpackage"] = "Acid Package", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
-- Weapon Ammo
["ammo_rounds"] = "nabój/oi",
+4 -4
View File
@@ -1,4 +1,4 @@
Locales["sl"] = {
return {
-- Inventory
["inventory"] = "Shramba ( Teza %s / %s )",
["use"] = "Uporabi",
@@ -229,10 +229,10 @@ Locales["sl"] = {
["weapon_tactilerifle"] = "Service Carbine",
-- Drug Wars DLC
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_acidpackage"] = "Acid Package", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
-- Thrown
["weapon_ball"] = "Baseball",
+4 -4
View File
@@ -1,4 +1,4 @@
Locales["sr"] = {
return {
-- Inventory
["inventory"] = "Inventar ( Težina %s / %s )",
["use"] = "Koristi",
@@ -229,10 +229,10 @@ Locales["sr"] = {
["weapon_tactilerifle"] = "Service Carbine",
-- Drug Wars DLC
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_acidpackage"] = "Acid Package", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
-- Thrown
["weapon_ball"] = "Baseball",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sv"] = {
return {
-- Inventory
["inventory"] = "Inventory ( Vikt %s / %s )",
["use"] = "Använd",
+8 -8
View File
@@ -1,4 +1,4 @@
Locales["tr"] = {
return {
-- Inventory
["inventory"] = "Envanter ( Ağırlık %s / %s )",
["use"] = "Kullan",
@@ -36,10 +36,10 @@ Locales["tr"] = {
["threw_weapon_already"] = "Bu Silaha Zaten Sahipsiniz",
["threw_cannot_pickup"] = "Envanter Dolu, Alınamaz!",
["threw_pickup_prompt"] = "Almak İçin E'ye Basın",
-- Key mapping
["keymap_showinventory"] = "Envanteri Göster",
-- Salary related
["received_salary"] = "Maaşınız Ödendi: $%s",
["received_help"] = "Yardım Çekiniz Ödendi: $%s",
@@ -49,11 +49,11 @@ Locales["tr"] = {
["account_bank"] = "Banka",
["account_black_money"] = "Kirli Para",
["account_money"] = "Nakit",
["act_imp"] = "İşlem Yapılamaz",
["in_vehicle"] = "İşlem Yapılamaz, Oyuncu Araçta",
["not_in_vehicle"] = "İşlem Yapılamaz, Oyuncu Araçta Değil",
-- Commands
["command_bring"] = "Oyuncuyu Yanınıza Getir",
["command_car"] = "Araç Spawn Et",
@@ -119,14 +119,14 @@ Locales["tr"] = {
["command_giveammo_ammo"] = "Mermi Miktarı",
["tpm_nowaypoint"] = "Hiçbir Yol İşareti Ayarlanmadı.",
["tpm_success"] = "Başarıyla Teleport Edildi",
["noclip_message"] = "Noclip %s Yapıldı",
["enabled"] = "~g~Aktif Edildi~s~",
["disabled"] = "~r~Pasif Edildi~s~",
-- Locale settings
["locale_digit_grouping_symbol"] = ",",
["locale_currency"] = "£%s",
["locale_currency"] = "£%s",
-- Silahlar
+4 -4
View File
@@ -1,4 +1,4 @@
Locales["zh-cn"] = {
return {
-- Inventory
["inventory"] = "背包 %s / %s",
["use"] = "使用",
@@ -229,10 +229,10 @@ Locales["zh-cn"] = {
["weapon_tactilerifle"] = "制式卡宾步枪",
-- Drug Wars DLC
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_candycane"] = "Candy Cane", -- not translated
["weapon_acidpackage"] = "Acid Package", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
["weapon_pistolxm3"] = "WM 29 Pistol", -- not translated
["weapon_railgunxm3"] = "Railgun", -- not translated
-- Thrown
["weapon_ball"] = "棒球",
@@ -91,6 +91,11 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
return self.paycheckEnabled
end
---@return boolean
function self.isAdmin()
return Core.IsPlayerAdmin(self.source)
end
---@param coordinates vector4 | vector3 | table
---@return nil
function self.setCoords(coordinates)
@@ -455,6 +460,12 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
return self.weight
end
---@return number
function self.getSource()
return self.source
end
self.getPlayerId = self.getSource
---@return number
function self.getMaxWeight()
return self.maxWeight
@@ -944,3 +955,17 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
return self
end
local function runStaticPlayerMethod(src, method, ...)
local xPlayer = ESX.Players[src]
if not xPlayer then
return
end
if not ESX.IsFunctionReference(xPlayer[method]) then
error(("Attempted to call invalid method on playerId %s: %s"):format(src, method))
end
return xPlayer[method](...)
end
exports("RunStaticPlayerMethod", runStaticPlayerMethod)
@@ -0,0 +1,237 @@
---@class CVehicleData
---@field plate string
---@field netId number
---@field entity number
---@field modelHash number
---@field owner string
---@class CExtendedVehicle
---@field plate string
---@field isValid fun(self:CExtendedVehicle):boolean
---@field new fun(owner:string, plate:string, coords:vector4): CExtendedVehicle?
---@field getFromPlate fun(plate:string):CExtendedVehicle?
---@field getPlate fun(self:CExtendedVehicle):string?
---@field getNetId fun(self:CExtendedVehicle):number?
---@field getEntity fun(self:CExtendedVehicle):number?
---@field getModelHash fun(self:CExtendedVehicle):number?
---@field getOwner fun(self:CExtendedVehicle):string?
---@field setPlate fun(self:CExtendedVehicle, newPlate:string):boolean
---@field setProps fun(self:CExtendedVehicle, newProps:table):boolean
---@field setOwner fun(self:CExtendedVehicle, newOwner:string):boolean
---@field delete fun(self:CExtendedVehicle, garageName:string?, isImpound:boolean?):nil
Core.vehicleClass = {
plate = "",
new = function(owner, plate, coords)
assert(type(owner) == "string", "Expected 'owner' to be a string")
assert(type(plate) == "string", "Expected 'plate' to be a string")
assert(type(coords) == "vector4", "Expected 'coords' to be a vector4")
local xVehicle = Core.vehicleClass.getFromPlate(plate)
if xVehicle then
return xVehicle
end
local vehicleProps = MySQL.scalar.await("SELECT `vehicle` FROM `owned_vehicles` WHERE `stored` = true AND `owner` = ? AND `plate` = ? LIMIT 1", { owner, plate })
if not vehicleProps then
return
end
vehicleProps = json.decode(vehicleProps)
if type(vehicleProps.model) ~= "number" then
vehicleProps.model = joaat(vehicleProps.model)
end
local netId = ESX.OneSync.SpawnVehicle(vehicleProps.model, coords.xyz, coords.w, vehicleProps)
if not netId then
return
end
local entity = NetworkGetEntityFromNetworkId(netId)
if entity <= 0 then
return
end
Entity(entity).state:set("owner", owner, false)
Entity(entity).state:set("plate", plate, false)
---@type CVehicleData
local vehicleData = {
plate = plate,
entity = entity,
netId = netId,
modelHash = vehicleProps.model,
owner = owner,
}
Core.vehicles[plate] = vehicleData
MySQL.update.await("UPDATE `owned_vehicles` SET `stored` = false WHERE `owner` = ? AND `plate` = ?", { owner, plate })
local obj = table.clone(Core.vehicleClass)
obj.plate = plate
TriggerEvent("esx:createdExtendedVehicle", obj)
return obj
end,
getFromPlate = function(plate)
assert(type(plate) == "string", "Expected 'plate' to be a string")
if Core.vehicles[plate] then
local obj = table.clone(Core.vehicleClass)
obj.plate = plate
if obj:isValid() then
return obj
end
end
end,
isValid = function(self)
local vehicleData = Core.vehicles[self.plate]
if not vehicleData then
return false
end
local entity = NetworkGetEntityFromNetworkId(vehicleData.netId)
if entity <= 0 or Entity(entity).state.owner ~= vehicleData.owner or Entity(entity).state.plate ~= vehicleData.plate then
self:delete()
return false
end
vehicleData.entity = entity
return true
end,
getNetId = function(self)
if not self:isValid() then
return
end
return Core.vehicles[self.plate].netId
end,
getEntity = function(self)
if not self:isValid() then
return
end
return Core.vehicles[self.plate].entity
end,
getPlate = function(self)
if not self:isValid() then
return
end
return Core.vehicles[self.plate].plate
end,
getModelHash = function(self)
if not self:isValid() then
return
end
return Core.vehicles[self.plate].modelHash
end,
getOwner = function(self)
if not self:isValid() then
return
end
return Core.vehicles[self.plate].owner
end,
setPlate = function(self, newPlate)
if not self:isValid() then
return false
end
assert(type(newPlate) == "string", "Expected 'plate' to be a string")
local vehicleData = Core.vehicles[self.plate]
local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `plate` = ? WHERE `plate` = ? AND `owner` = ?", { newPlate, vehicleData.plate, vehicleData.owner })
if affectedRows <= 0 then
self:delete()
return false
end
Entity(vehicleData.entity).state:set("plate", newPlate, false)
SetVehicleNumberPlateText(vehicleData.entity, newPlate)
local oldPlate = vehicleData.plate
vehicleData.plate = newPlate
Core.vehicles[newPlate] = table.clone(vehicleData)
Core.vehicles[oldPlate] = nil
TriggerEvent("esx:changedExtendedVehiclePlate", vehicleData.plate, oldPlate)
Wait(0)
return true
end,
setProps = function(self, newProps)
if not self:isValid() then
return false
end
assert(type(newProps) == "table", "Expected 'props' to be a table")
local vehicleData = Core.vehicles[self.plate]
local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `vehicle` = ? WHERE `plate` = ? AND `owner` = ?", json.encode(newProps), vehicleData.plate, vehicleData.owner)
if affectedRows <= 0 then
self:delete()
return false
end
Entity(vehicleData.entity).state:set("VehicleProperties", newProps, true)
return true
end,
setOwner = function(self, newOwner)
if not self:isValid() then
return false
end
assert(type(newOwner) == "string", "Expected 'owner' to be a string")
local vehicleData = Core.vehicles[self.plate]
if vehicleData.owner == newOwner then
return true
end
local affectedRows = MySQL.update.await("UPDATE `owned_vehicles` SET `owner` = ? WHERE owner = ? AND `plate` = ?", { newOwner, vehicleData.owner, vehicleData.plate })
if affectedRows <= 0 then
self:delete()
return false
end
Entity(vehicleData.entity).state:set("owner", newOwner, false)
vehicleData.owner = newOwner
return true
end,
delete = function(self, garageName, isImpound)
if type(garageName) ~= "string" then
garageName = nil
end
if type(isImpound) ~= "boolean" then
isImpound = false
end
local vehicleData = Core.vehicles[self.plate]
if not vehicleData then
return
end
local entity = NetworkGetEntityFromNetworkId(vehicleData.netId)
if entity >= 0 and Entity(entity).state.owner == vehicleData.owner then
DeleteEntity(vehicleData.entity)
end
local query = "UPDATE `owned_vehicles` SET `stored` = true WHERE `plate` = ? AND `owner` = ?"
local queryParams = { vehicleData.plate, vehicleData.owner }
if garageName then
if isImpound then
query = "UPDATE `owned_vehicles` SET `stored` = true, `parking` = NULL, `pound` = ? WHERE `plate` = ? AND `owner` = ?"
else
query = "UPDATE `owned_vehicles` SET `stored` = true, `pound` = NULL, `parking` = ? WHERE `plate` = ? AND `owner` = ?"
end
queryParams = { garageName, vehicleData.plate, vehicleData.owner }
end
MySQL.update.await(query, queryParams)
TriggerEvent("esx:deletedExtendedVehicle", self)
Core.vehicles[self.plate] = nil
end,
}
+2
View File
@@ -11,6 +11,8 @@ Core.PlayerFunctionOverrides = {}
Core.DatabaseConnected = false
Core.playersByIdentifier = {}
---@type table<string, CVehicleData>
Core.vehicles = {}
Core.vehicleTypesByModel = {}
RegisterNetEvent("esx:onPlayerSpawn", function()
+41 -7
View File
@@ -358,6 +358,18 @@ function ESX.GetPlayerFromIdentifier(identifier)
return Core.playersByIdentifier[identifier]
end
---@param identifier string
---@return number playerId
function ESX.GetPlayerIdFromIdentifier(identifier)
return Core.playersByIdentifier[identifier]?.source
end
---@param source number
---@return boolean
function ESX.IsPlayerLoaded(source)
return ESX.Players[source] ~= nil
end
---@param playerId number | string
---@return string
function ESX.GetIdentifier(playerId)
@@ -433,6 +445,11 @@ end
---@param fields table
---@return nil
function ESX.DiscordLogFields(name, title, color, fields)
for i = 1, #fields do
local field = fields[i]
field.value = tostring(field.value)
end
local webHook = Config.DiscordLogs.Webhooks[name] or Config.DiscordLogs.Webhooks.default
local embedData = {
{
@@ -495,7 +512,7 @@ function ESX.RefreshJobs()
if not Jobs then
-- Fallback data, if no jobs exist
ESX.Jobs["unemployed"] = { label = "Unemployed", grades = { ["0"] = { grade = 0, label = "Unemployed", salary = 200, skin_male = {}, skin_female = {} } } }
ESX.Jobs["unemployed"] = { name = "unemployed", label = "Unemployed", whitelisted = false, grades = { ["0"] = { grade = 0, name = "unemployed", label = "Unemployed", salary = 200, skin_male = {}, skin_female = {} } } }
else
ESX.Jobs = Jobs
end
@@ -609,14 +626,31 @@ function ESX.DoesJobExist(job, grade)
return (ESX.Jobs[job] and ESX.Jobs[job].grades[tostring(grade)] ~= nil) or false
end
---@param playerId string | number
---@param playerSrc number
---@return boolean
function Core.IsPlayerAdmin(playerId)
playerId = tostring(playerId)
if (IsPlayerAceAllowed(playerId, "command") or GetConvar("sv_lan", "") == "true") then
function Core.IsPlayerAdmin(playerSrc)
if type(playerSrc) ~= "number" then
return false
end
if IsPlayerAceAllowed(playerSrc --[[@as string]], "command") or GetConvar("sv_lan", "") == "true" then
return true
end
local xPlayer = ESX.Players[playerId]
return (xPlayer and Config.AdminGroups[xPlayer.group] and true) or false
local xPlayer = ESX.GetPlayerFromId(playerSrc)
return xPlayer and Config.AdminGroups[xPlayer.getGroup()] or false
end
---@param owner string
---@param plate string
---@param coords vector4
---@return CExtendedVehicle?
function ESX.CreateExtendedVehicle(owner, plate, coords)
return Core.vehicleClass.new(owner, plate, coords)
end
---@param plate string
---@return CExtendedVehicle?
function ESX.GetExtendedVehicleFromPlate(plate)
return Core.vehicleClass.getFromPlate(plate)
end
+5
View File
@@ -353,6 +353,11 @@ end)
AddEventHandler("esx:playerLogout", function(playerId, cb)
local xPlayer = ESX.GetPlayerFromId(playerId)
local job = xPlayer.getJob().name
Core.JobsPlayerCount[job] = Core.JobsPlayerCount[job] - 1
GlobalState[("%s:count"):format(job)] = Core.JobsPlayerCount[job]
if xPlayer then
TriggerEvent("esx:playerDropped", playerId)
+34 -2
View File
@@ -33,11 +33,17 @@ function Callbacks:Execute(cb, ...)
end
function Callbacks:Trigger(player, event, cb, invoker, ...)
self.requests[self.id] = cb
self.requests[self.id] = {
await = type(cb) == "boolean",
cb = cb or promise:new()
}
local table = self.requests[self.id]
TriggerClientEvent("esx:triggerClientCallback", player, event, self.id, invoker, ...)
self.id += 1
return table.cb
end
function Callbacks:ServerRecieve(player, event, requestId, invoker, ...)
@@ -64,8 +70,12 @@ function Callbacks:RecieveClient(requestId, invoker, ...)
local callback = self.requests[self.currentId]
self:Execute(callback, ...)
self.requests[requestId] = nil
if callback.await then
callback.cb:resolve({ ... })
else
self:Execute(callback.cb, ...)
end
end
-- =============================================
@@ -83,6 +93,28 @@ function ESX.TriggerClientCallback(player, eventName, callback, ...)
Callbacks:Trigger(player, eventName, callback, invoker, ...)
end
---@param player number playerId
---@param eventName string
---@param ... any
---@return any
function ESX.AwaitClientCallback(player, eventName, ...)
local invokingResource = GetInvokingResource()
local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended"
local p = Callbacks:Trigger(player, eventName, false, invoker, ...)
if not p then return end
SetTimeout(15000, function()
if p.state == "pending" then
p:reject("Server Callback Timed Out")
end
end)
Citizen.Await(p)
return table.unpack(p.value)
end
---@param eventName string
---@param callback function
---@return nil
@@ -72,10 +72,10 @@ function ESX.CreateJob(name, label, grades)
{ query = 'INSERT INTO jobs (name, label) VALUES (?, ?)', values = { name, label } }
}
for _, grade in ipairs(grades) do
for _, grade in pairs(grades) do
queries[#queries + 1] = {
query = 'INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)',
values = { name, grade.grade, grade.name, grade.label, grade.salary, '{}', '{}' }
values = { name, grade.grade, grade.name, grade.label, grade.salary, grade.skin_male and json.encode(grade.skin_male) or '{}', grade.skin_female and json.encode(grade.skin_female) or '{}' }
}
end
@@ -90,5 +90,7 @@ function ESX.CreateJob(name, label, grades)
notify("SUCCESS", currentResourceName, 'Job created successfully: `%s`', name)
TriggerEvent('esx:jobCreated', name, ESX.Jobs[name])
return success
end
+4 -5
View File
@@ -1,5 +1,9 @@
Config = {}
local txAdminLocale = GetConvar("txAdmin-locale", "en")
local esxLocale = GetConvar("esx:locale", "invalid")
Config.Locale = (esxLocale ~= "invalid") and esxLocale or (txAdminLocale ~= "custom" and txAdminLocale) or "en"
-- for ox inventory, this will automatically be adjusted, do not change! for other inventories, change to "resource_name"
Config.CustomInventory = false
@@ -60,8 +64,3 @@ if GetResourceState("ox_inventory") ~= "missing" then
end
Config.EnableDefaultInventory = Config.CustomInventory == false -- Display the default Inventory ( F2 )
local txAdminLocale = GetConvar("txAdmin-locale", "en")
local esxLocale = GetConvar("esx:locale", "invalid")
Config.Locale = (esxLocale ~= "invalid") and esxLocale or (txAdminLocale ~= "custom" and txAdminLocale) or "en"
-2
View File
@@ -8,8 +8,6 @@ AddEventHandler("esx:getSharedObject", function(cb)
if ESX.IsFunctionReference(cb) then
cb(ESX)
end
local invokingResource = GetInvokingResource()
print(("^3[WARNING]^0 Resource ^5%s^0 used the ^5getSharedObject^0 event. This is not the recommended way to import ESX. Visit https://docs.esx-legacy.com/tutorials/tutorials-esx/sharedevent to find out why."):format(invokingResource))
end)
-- backwards compatibility (DO NOT TOUCH !)
+1 -1
View File
@@ -1,4 +1,4 @@
version '1.12.4'
version '1.12.2'
author 'ESX-Framework'
description 'A ESX Stylised theme for the chat resource.'
+1 -1
View File
@@ -4,7 +4,7 @@ game 'gta5'
author 'ESX-Framework & Brayden'
description 'A simplistic context menu for ESX.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
ui_page 'index.html'
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'adamant'
game 'gta5'
description 'Allows the player to Pick their characters: Name, Gender, Height and Date-of-birth.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
shared_scripts {
'@es_extended/imports.lua',
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["cs"] = {
return {
["show_registration"] = "zobrazit registracni menu",
["show_active_character"] = "zobrazit aktivni postavy",
["delete_character"] = "smazat svou stavajici postavu a vytvorit novou",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["da"] = {
return {
["show_active_character"] = "Vis aktiv karakter",
["active_character"] = "Aktiv karakter: %s",
["error_active_character"] = "Der opstod en fejl under indhentning af dine data.",
+2 -2
View File
@@ -1,4 +1,4 @@
Locales["de"] = {
return {
["show_active_character"] = "Aktiven Charakter anzeigen",
["active_character"] = "Aktiver Charakter: %s",
["error_active_character"] = "Beim Abrufen deiner Daten ist ein Fehler aufgetreten",
@@ -35,4 +35,4 @@ Locales["de"] = {
["invalid_dob_format"] = "Ungültiges Format (Geburtstag): Bitte versuche es erneut.",
["invalid_sex_format"] = "Ungültiges Format (Geschlecht): Bitte versuche es erneut.",
["invalid_height_format"] = "Ungültiges Format (Körpergröße): Bitte versuche es erneut.",
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["en"] = {
return {
["show_active_character"] = "Show Active Character",
["active_character"] = "Active Character: %s",
["error_active_character"] = "There was an error obtaining your data.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["es"] = {
return {
["show_active_character"] = "Mostrar personaje actual",
["active_character"] = "Personaje actual: %s",
["error_active_character"] = "Se produjo un error al recuperar tu nombre. Por favor contacta con un administrador",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["fi"] = {
return {
["show_active_character"] = "Näytä nykyinen hahmosi",
["active_character"] = "Nykyinen hahmosi: %s",
["error_active_character"] = "Hahmosi hakemisessa ilmeni ongelma. Ota yhteyttä ylläpitoon.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["fr"] = {
return {
["show_active_character"] = "Afficher le personnage actif",
["active_character"] = "Personnage actif: %s",
["error_active_character"] = "Une erreur s'est produite lors de l'obtention de vos données.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["he"] = {
return {
["show_active_character"] = "הצג דמות פעילה",
["active_character"] = "דמות פעילה: %s",
["error_active_character"] = "אירעה שגיאה בקבלת הנתונים שלך.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["hu"] = {
return {
["show_active_character"] = "Aktív karakterek mutatása",
["active_character"] = "Aktív karakter: %s",
["error_active_character"] = "A név nem megfelelő",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["it"] = {
return {
["show_active_character"] = "Mostra Personaggio Attivo",
["active_character"] = "Personaggio Attivo: %s",
["error_active_character"] = "Errore nel recuperare i tuoi dati.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["nl"] = {
return {
["show_active_character"] = "Actieve karakter laten zien",
["active_character"] = "Actief karakter: %s",
["error_active_character"] = "Er is een probleem opgetreden tijdens het verzamelen van uw data.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["pl"] = {
return {
["show_active_character"] = "Pokaż aktywną postać",
["active_character"] = "Aktywna postać: %s",
["error_active_character"] = "Podczas pobierania Twojego imienia wystąpił błąd. Proszę skontaktować się z administratorem.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["pt"] = {
return {
["show_active_character"] = "Mostrar personagem ativa",
["active_character"] = "Personagem ativa: %s",
["error_active_character"] = "Houve um erro a obter os teus dados.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sl"] = {
return {
["show_active_character"] = "Prikaži aktivnega lika",
["active_character"] = "Aktivni lik: %s",
["error_active_character"] = "Prišlo je do napake pri pridobivanju podatkov.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sr"] = {
return {
["show_active_character"] = "Prikazi karaktere",
["active_character"] = "Karakteri: %s",
["error_active_character"] = "Imamo problem sa ucitavanjem karaktera.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sv"] = {
return {
["show_active_character"] = "Visa aktiv karaktär",
["active_character"] = "Aktiv karaktär: %s",
["error_active_character"] = "Det blev ett fel med att ta din data.",
+1 -1
View File
@@ -3,7 +3,7 @@ game 'common'
fx_version 'cerulean'
author 'ESX-Framework'
description 'Allows resources to Run tasks at specific intervals.'
version '1.12.4'
version '1.12.2'
lua54 'yes'
loadscreen 'index.html'
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'adamant'
game 'gta5'
description 'A basic menu system for ESX Legacy.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
client_scripts { '@es_extended/imports.lua', 'client/main.lua' }
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'adamant'
game 'gta5'
description 'A basic input dialog for ESX Legacy.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
client_scripts {
'@es_extended/imports.lua',
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'adamant'
game 'gta5'
description 'A basic table-based menu system for ESX Legacy.'
lua54 'yes'
version '1.12.4'
version '1.12.2'
client_scripts {
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'cerulean'
game 'gta5'
author 'ESX-Framework - Linden - KASH'
description 'Allows players to have multiple characters on the same account.'
version '1.12.4'
version '1.12.2'
lua54 'yes'
dependencies { 'es_extended', 'esx_context', 'esx_identity', 'esx_skin' }
@@ -14,12 +14,12 @@ function Database:GetConnection()
self.name = connectionString:sub(connectionString:find("/") + 1, -1):gsub("[%?]+[%w%p]*$", "")
self.found = true
else
local connectionExtracted = { string.strsplit(";", connectionString) }
for i = 1, #connectionExtracted do
local v = connectionExtracted[i]
if v:match("database") then
self.name = connectionString:sub(connectionString:find("/") + 1, -1):gsub("[%?]+[%w%p]*$", "")
local confPairs = { string.strsplit(";", connectionString) }
for i = 1, #confPairs do
local confPair = confPairs[i]
local key, value = confPair:match("^%s*(.-)%s*=%s*(.-)%s*$")
if key == "database" then
self.name = value
self.found = true
break
end
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'adamant'
game 'gta5'
author 'ESX-Framework'
description 'A beautiful and simple NUI progress bar for ESX'
version '1.12.4'
version '1.12.2'
lua54 'yes'
client_scripts { 'Progress.lua' }
+1 -1
View File
@@ -2,7 +2,7 @@ fx_version 'adamant'
game 'gta5'
description 'Allows players to customise their character\'s appearance'
version '1.12.4'
version '1.12.2'
lua54 'yes'
shared_scripts {
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["da"] = {
return {
["skin_menu"] = "Udseende Menu",
["use_rotate_view"] = "brug Q og E for at dreje kameraet.",
["skin"] = "skift udseende",
+6 -6
View File
@@ -1,6 +1,6 @@
Locales["de"] = {
["skin_menu"] = "Skin Menü",
["use_rotate_view"] = "Drücke Q oder E um deine Ansicht zu ändern.",
["skin"] = "Aussehen ändern",
["saveskin"] = "Aussehen abspeichern",
}
return {
["skin_menu"] = "Skin Menü",
["use_rotate_view"] = "Drücke Q oder E um deine Ansicht zu ändern.",
["skin"] = "Aussehen ändern",
["saveskin"] = "Aussehen abspeichern",
}
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["en"] = {
return {
["skin_menu"] = "Skin Menu",
["use_rotate_view"] = "use Q and E to rotate the view.",
["skin"] = "change skin",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["es"] = {
return {
["skin_menu"] = "Menú de apariencia",
["use_rotate_view"] = "Utiliza Q y E para rotar la vista.",
["skin"] = "Cambiar aspecto",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["fi"] = {
return {
["skin_menu"] = "Ulkonäkö",
["use_rotate_view"] = "Paina Q tai E liikutaaksesi kameraa.",
["skin"] = "Muokkaa ulkonäköä",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["fr"] = {
return {
["skin_menu"] = "menu de Skin",
["use_rotate_view"] = "utilisez Q et E pour tourner la vue.",
["skin"] = "changer de skin",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["he"] = {
return {
["skin_menu"] = "תפריט עור",
["use_rotate_view"] = "השתמש Q ו E כדי לסובב את התצוגה.",
["skin"] = "שנה עור",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["hu"] = {
return {
["skin_menu"] = "Kinézet Menü",
["use_rotate_view"] = "Használd Q vagy E gombokat a forgatáshoz",
["skin"] = "kinézet változtatása",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["it"] = {
return {
["skin_menu"] = "Menu Skin",
["use_rotate_view"] = "usa Q e E per ruotare la visuale.",
["skin"] = "cambia skin",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["nl"] = {
return {
["skin_menu"] = "Kleding Menu",
["use_rotate_view"] = "gebruik Q en E om de camera te draaien.",
["skin"] = "verander outfit",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["pl"] = {
return {
["skin_menu"] = "menu wyglądu",
["use_rotate_view"] = "użyj Q i E aby obrócić ekran.",
["skin"] = "zmień wygląd",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["pt"] = {
return {
["skin_menu"] = "Menu de Skin",
["use_rotate_view"] = "Usa Q e E para rodar a câmara.",
["skin"] = "alterar skin",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sl"] = {
return {
["skin_menu"] = "Oblacilni menu.",
["use_rotate_view"] = "Pritisni Q in E da se obracas s pogledom.",
["skin"] = "Zamenjaj Skin.",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sr"] = {
return {
["skin_menu"] = "Skin Meni",
["use_rotate_view"] = "koristi Q i E da rotiras kameru.",
["skin"] = "promeni skin",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["sv"] = {
return {
["skin_menu"] = "Skin Meny",
["use_rotate_view"] = "Använd Q och E för att rotera.",
["skin"] = "Ända utseende",
+1 -1
View File
@@ -1,4 +1,4 @@
Locales["zh-cn"] = {
return {
["skin_menu"] = "皮肤选单",
["use_rotate_view"] = "使用 Q 和 E 旋转镜头视角.",
["skin"] = "更换皮肤数据",
+1 -1
View File
@@ -3,7 +3,7 @@ fx_version 'adamant'
game 'gta5'
author 'ESX-Framework'
description 'A beautiful and simple Persistent Notification system for ESX.'
version '1.12.4'
version '1.12.2'
lua54 'yes'
client_scripts { 'TextUI.lua' }
+1 -1
View File
@@ -2,7 +2,7 @@ fx_version 'adamant'
game 'gta5'
description 'Saves/loads character appearances for ESX Legacy.'
version '1.12.4'
version '1.12.2'
lua54 'yes'
client_scripts {