From e77cbba7571ce3f14b31f2989e2db7f70747c112 Mon Sep 17 00:00:00 2001 From: wildesPepega <68642699+wildesPepega@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:41:07 +0200 Subject: [PATCH] Add files via upload --- [core]/es_extended/LICENSE | 6 +- [core]/es_extended/client/functions.lua | 28 ++-- [core]/es_extended/client/main.lua | 24 +-- [core]/es_extended/client/modules/actions.lua | 13 +- [core]/es_extended/common/functions.lua | 33 ++++ [core]/es_extended/common/modules/math.lua | 6 + [core]/es_extended/config.lua | 57 ++++--- [core]/es_extended/fxmanifest.lua | 158 +++++++++--------- [core]/es_extended/html/css/app.css | 6 +- [core]/es_extended/imports.lua | 2 + [core]/es_extended/locale.js | 77 +++++---- [core]/es_extended/locale.lua | 1 + .../server/classes/overrides/oxinventory.lua | 2 +- [core]/es_extended/server/classes/player.lua | 30 +++- [core]/es_extended/server/functions.lua | 109 ++++++------ [core]/es_extended/server/main.lua | 14 +- .../es_extended/server/modules/createJob.lua | 102 +++++++++++ 17 files changed, 409 insertions(+), 259 deletions(-) create mode 100644 [core]/es_extended/server/modules/createJob.lua diff --git a/[core]/es_extended/LICENSE b/[core]/es_extended/LICENSE index a10f2d96e..5f5e070be 100644 --- a/[core]/es_extended/LICENSE +++ b/[core]/es_extended/LICENSE @@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. es_extended - Copyright (C) 2015-2023 Jérémie N'gadi + Copyright (C) 2015-2024 Jérémie N'gadi This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - es_extended Copyright (C) 2015-2023 Jérémie N'gadi + es_extended Copyright (C) 2015-2024 Jérémie N'gadi This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -671,4 +671,4 @@ into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. \ No newline at end of file +. diff --git a/[core]/es_extended/client/functions.lua b/[core]/es_extended/client/functions.lua index d197bccd7..61985de80 100644 --- a/[core]/es_extended/client/functions.lua +++ b/[core]/es_extended/client/functions.lua @@ -505,10 +505,10 @@ function ESX.Game.GetClosestEntity(entities, isPlayerEntities, coords, modelFilt if modelFilter then filteredEntities = {} - - for _, entity in pairs(entities) do - if modelFilter[GetEntityModel(entity)] then - filteredEntities[#filteredEntities + 1] = entity + + for currentEntityIndex = 1, #entities do + if modelFilter[GetEntityModel(entities[currentEntityIndex])] then + filteredEntities[#filteredEntities + 1] = entities[currentEntityIndex] end end end @@ -574,21 +574,15 @@ function ESX.Game.GetVehicleProperties(vehicle) end local doorsBroken, windowsBroken, tyreBurst = {}, {}, {} - local numWheels = tostring(GetVehicleNumberOfWheels(vehicle)) - local TyresIndex = { -- Wheel index list according to the number of vehicle wheels. - ["2"] = { 0, 4 }, -- Bike and cycle. - ["3"] = { 0, 1, 4, 5 }, -- Vehicle with 3 wheels (get for wheels because some 3 wheels vehicles have 2 wheels on front and one rear or the reverse). - ["4"] = { 0, 1, 4, 5 }, -- Vehicle with 4 wheels. - ["6"] = { 0, 1, 2, 3, 4, 5 }, -- Vehicle with 6 wheels. - } - if TyresIndex[numWheels] then - for _, idx in pairs(TyresIndex[numWheels]) do - tyreBurst[tostring(idx)] = IsVehicleTyreBurst(vehicle, idx, false) - end + local wheel_count = GetVehicleNumberOfWheels(vehicle); + + for wheel_index = 0, wheel_count - 1 do + tyreBurst[tostring(wheel_index)] = IsVehicleTyreBurst(vehicle, wheel_index, false) end + for windowId = 0, 7 do -- 13 RollUpWindow(vehicle, windowId) --fix when you put the car away with the window down windowsBroken[tostring(windowId)] = not IsVehicleWindowIntact(vehicle, windowId) @@ -1126,8 +1120,8 @@ function ESX.ShowInventory() { unselectable = true, icon = "fas fa-users", title = "Nearby Players" }, } - for _, playerNearby in ipairs(playersNearby) do - players[GetPlayerServerId(playerNearby)] = true + for currentNearbyPlayerIndex = 1, #playersNearby do + players[GetPlayerServerId(playersNearby[currentNearbyPlayerIndex])] = true end ESX.TriggerServerCallback("esx:getPlayerNames", function(returnedPlayers) diff --git a/[core]/es_extended/client/main.lua b/[core]/es_extended/client/main.lua index 25d005945..27180dd72 100644 --- a/[core]/es_extended/client/main.lua +++ b/[core]/es_extended/client/main.lua @@ -34,7 +34,7 @@ function ESX.SpawnPlayer(skin, coords, cb) end FreezeEntityPosition(playerPed, false) NetworkResurrectLocalPlayer(coords.x, coords.y, coords.z, coords.heading, true, true, false) - TriggerEvent("playerSpawned", coords) + TriggerEvent('playerSpawned', coords) cb() end @@ -211,6 +211,7 @@ AddEventHandler("esx:playerLoaded", function(xPlayer, _, skin) StartServerSyncLoops() end) + RegisterNetEvent("esx:onPlayerLogout") AddEventHandler("esx:onPlayerLogout", function() ESX.PlayerLoaded = false @@ -270,29 +271,13 @@ AddEventHandler("esx:restoreLoadout", function() end end) --- Credit: https://github.com/LukeWasTakenn, https://github.com/LukeWasTakenn/luke_garages/blob/master/client/client.lua#L331-L352 AddStateBagChangeHandler("VehicleProperties", nil, function(bagName, _, value) if not value then return end local netId = bagName:gsub("entity:", "") - local timer = GetGameTimer() - while not NetworkDoesEntityExistWithNetworkId(tonumber(netId)) do - Wait(0) - if GetGameTimer() - timer > 10000 then - return - end - end - local vehicle = NetToVeh(tonumber(netId)) - local timer2 = GetGameTimer() - while NetworkGetEntityOwner(vehicle) ~= PlayerId() do - Wait(0) - if GetGameTimer() - timer2 > 10000 then - return - end - end ESX.Game.SetVehicleProperties(vehicle, value) end) @@ -377,6 +362,11 @@ AddEventHandler("esx:setJob", function(Job) ESX.SetPlayerData("job", Job) end) +RegisterNetEvent("esx:setGroup") +AddEventHandler("esx:setGroup", function(group) + ESX.SetPlayerData("group", group) +end) + if not Config.OxInventory then RegisterNetEvent("esx:createPickup") AddEventHandler("esx:createPickup", function(pickupId, label, coords, itemType, name, components, tintIndex) diff --git a/[core]/es_extended/client/modules/actions.lua b/[core]/es_extended/client/modules/actions.lua index c4ee7eec2..401297d89 100644 --- a/[core]/es_extended/client/modules/actions.lua +++ b/[core]/es_extended/client/modules/actions.lua @@ -24,10 +24,13 @@ local function GetData(vehicle) return displayName, netId end +local function ToggleVehicleStatus(inVehicle, seat) + ESX.SetPlayerData("vehicle", inVehicle) + ESX.SetPlayerData("seat", seat) +end + CreateThread(function() - while not ESX.PlayerLoaded do - Wait(200) - end + while not ESX.PlayerLoaded do Wait(200) end while true do ESX.SetPlayerData("coords", GetEntityCoords(playerPed)) if playerPed ~= PlayerPedId() then @@ -66,11 +69,13 @@ CreateThread(function() isEnteringVehicle = true TriggerEvent("esx:enteringVehicle", vehicle, plate, seat, netId) TriggerServerEvent("esx:enteringVehicle", plate, seat, netId) + ToggleVehicleStatus(vehicle, seat) elseif not DoesEntityExist(GetVehiclePedIsTryingToEnter(playerPed)) and not IsPedInAnyVehicle(playerPed, true) and isEnteringVehicle then -- vehicle entering aborted TriggerEvent("esx:enteringVehicleAborted") TriggerServerEvent("esx:enteringVehicleAborted") isEnteringVehicle = false + ToggleVehicleStatus(false, false) elseif IsPedInAnyVehicle(playerPed, false) then -- suddenly appeared in a vehicle, possible teleport isEnteringVehicle = false @@ -81,6 +86,7 @@ CreateThread(function() current.displayName, current.netId = GetData(current.vehicle) TriggerEvent("esx:enteredVehicle", current.vehicle, current.plate, current.seat, current.displayName, current.netId) TriggerServerEvent("esx:enteredVehicle", current.plate, current.seat, current.displayName, current.netId) + ToggleVehicleStatus(current.vehicle, current.seat) end elseif isInVehicle then if not IsPedInAnyVehicle(playerPed, false) or IsPlayerDead(PlayerId()) then @@ -89,6 +95,7 @@ CreateThread(function() TriggerServerEvent("esx:exitedVehicle", current.plate, current.seat, current.displayName, current.netId) isInVehicle = false current = {} + ToggleVehicleStatus(false,false) end end Wait(200) diff --git a/[core]/es_extended/common/functions.lua b/[core]/es_extended/common/functions.lua index f6414bdc8..0e9adb08f 100644 --- a/[core]/es_extended/common/functions.lua +++ b/[core]/es_extended/common/functions.lua @@ -106,3 +106,36 @@ end function ESX.Round(value, numDecimalPlaces) return ESX.Math.Round(value, numDecimalPlaces) end + +function ESX.ValidateType(value, ...) + local types = { ... } + if #types == 0 then return true end + + local mapType = {} + for i = 1, #types, 1 do + local validateType = types[i] + assert(type(validateType) == "string", "bad argument types, only expected string") -- should never use anyhing else than string + mapType[validateType] = true + end + + local valueType = type(value) + + local matches = mapType[valueType] ~= nil + + if not matches then + local requireTypes = table.concat(types, " or ") + local errorMessage = ("bad value (%s expected, got %s)"):format(requireTypes, valueType) + + return false, errorMessage + end + + return true +end + +function ESX.AssertType(...) + local matches, errorMessage = ESX.ValidateType(...) + + assert(matches, errorMessage) + + return matches +end diff --git a/[core]/es_extended/common/modules/math.lua b/[core]/es_extended/common/modules/math.lua index 9910d17e8..868773b6f 100644 --- a/[core]/es_extended/common/modules/math.lua +++ b/[core]/es_extended/common/modules/math.lua @@ -23,3 +23,9 @@ function ESX.Math.Trim(value) return nil end end + +function ESX.Math.Random(minRange, maxRange) + math.randomseed(GetGameTimer()) + return math.random(minRange or 1, maxRange or 10) +end + diff --git a/[core]/es_extended/config.lua b/[core]/es_extended/config.lua index fa78e4631..3d82a1f00 100644 --- a/[core]/es_extended/config.lua +++ b/[core]/es_extended/config.lua @@ -1,7 +1,7 @@ Config = {} Config.Locale = GetConvar("esx:locale", "en") -Config.OxInventory = GetResourceState("ox_inventory") ~= "missing" +Config.OxInventory = GetResourceState("ox_inventory") ~= 'missing' Config.Accounts = { bank = { @@ -22,13 +22,12 @@ Config.StartingAccountMoney = { bank = 50000 } Config.StartingInventoryItems = false -- table/false ---Config.StartingInventoryItems = { --- bread = 1, --- water = 1 ---} - Config.DefaultSpawns = { -- If you want to have more spawn positions and select them randomly uncomment commented code or add more locations { x = 222.2027, y = -864.0162, z = 30.2922, heading = 1.0 }, + --{x = 224.9865, y = -865.0871, z = 30.2922, heading = 1.0}, + --{x = 227.8436, y = -866.0400, z = 30.2922, heading = 1.0}, + --{x = 230.6051, y = -867.1450, z = 30.2922, heading = 1.0}, + --{x = 233.5459, y = -868.2626, z = 30.2922, heading = 1.0} } Config.AdminGroups = { @@ -39,33 +38,33 @@ Config.AdminGroups = { Config.EnablePaycheck = true -- enable paycheck Config.LogPaycheck = false -- Logs paychecks to a nominated Discord channel via webhook (default is false) Config.EnableSocietyPayouts = false -- pay from the society account that the player is employed at? Requirement: esx_society -Config.MaxWeight = 24 -- the max inventory weight without backpack -Config.PaycheckInterval = 7 * 60000 -- how often to recieve pay checks in milliseconds +Config.MaxWeight = 24 -- the max inventory weight without a backpack +Config.PaycheckInterval = 7 * 60000 -- how often to receive paychecks in milliseconds Config.EnableDebug = false -- Use Debug options? Config.EnableDefaultInventory = true -- Display the default Inventory ( F2 ) Config.EnableWantedLevel = false -- Use Normal GTA wanted Level? Config.EnablePVP = true -- Allow Player to player combat -Config.Multichar = false -Config.Identity = true -- Select a characters identity data before they have loaded in (this happens by default with multichar) +Config.Multichar = GetResourceState("esx_multicharacter") ~= "missing" +Config.Identity = true -- Select a character identity data before they have loaded in (this happens by default with multichar) Config.DistanceGive = 4.0 -- Max distance when giving items, weapons etc. Config.AdminLogging = false -- Logs the usage of certain commands by those with group.admin ace permissions (default is false) -Config.DisableHealthRegeneration = true -- Player will no longer regenerate health -Config.DisableVehicleRewards = true -- Disables Player Recieving weapons from vehicles -Config.DisableNPCDrops = true -- stops NPCs from dropping weapons on death -Config.DisableDispatchServices = true -- Disable Dispatch services -Config.DisableScenarios = true -- Disable Scenarios +Config.DisableHealthRegeneration = false -- Player will no longer regenerate health +Config.DisableVehicleRewards = false -- Disables Player Receiving weapons from vehicles +Config.DisableNPCDrops = false -- stops NPCs from dropping weapons on death +Config.DisableDispatchServices = false -- Disable Dispatch services +Config.DisableScenarios = false -- Disable Scenarios Config.DisableWeaponWheel = false -- Disables default weapon wheel -Config.DisableAimAssist = true -- disables AIM assist (mainly on controllers) -Config.DisableVehicleSeatShuff = true -- Disables vehicle seat shuff +Config.DisableAimAssist = false -- disables AIM assist (mainly on controllers) +Config.DisableVehicleSeatShuff = false -- Disables vehicle seat shuff Config.DisableDisplayAmmo = false -- Disable ammunition display Config.RemoveHudComponents = { - [1] = true, --WANTED_STARS, + [1] = false, --WANTED_STARS, [2] = false, --WEAPON_ICON - [3] = true, --CASH - [4] = true, --MP_CASH + [3] = false, --CASH + [4] = false, --MP_CASH [5] = false, --MP_MESSAGE [6] = false, --VEHICLE_NAME [7] = false, -- AREA_NAME @@ -77,14 +76,22 @@ Config.RemoveHudComponents = { [13] = false, --CASH_CHANGE [14] = false, --RETICLE [15] = false, --SUBTITLE_TEXT - [16] = true, --RADIO_STATIONS - [17] = true, --SAVING_GAME, - [18] = true, --GAME_STREAM + [16] = false, --RADIO_STATIONS + [17] = false, --SAVING_GAME, + [18] = false, --GAME_STREAM [19] = false, --WEAPON_WHEEL [20] = false, --WEAPON_WHEEL_STATS [21] = false, --HUD_COMPONENTS [22] = false, --HUD_WEAPONS } -Config.SpawnVehMaxUpgrades = true -Config.CustomAIPlates = "PEEPO" +Config.SpawnVehMaxUpgrades = true -- admin vehicles spawn with max vehicle settings +Config.CustomAIPlates = "........" -- Custom plates for AI vehicles +-- Pattern string format +--1 will lead to a random number from 0-9. +--A will lead to a random letter from A-Z. +-- . will lead to a random letter or number, with a 50% probability of being either. +--^1 will lead to a literal 1 being emitted. +--^A will lead to a literal A being emitted. +--Any other character will lead to said character being emitted. +-- A string shorter than 8 characters will be padded on the right. diff --git a/[core]/es_extended/fxmanifest.lua b/[core]/es_extended/fxmanifest.lua index b77e87903..7f8055f47 100644 --- a/[core]/es_extended/fxmanifest.lua +++ b/[core]/es_extended/fxmanifest.lua @@ -1,79 +1,79 @@ -fx_version("cerulean") - -game("gta5") -description("ES Extended") -lua54("yes") -version("1.10.5") - -shared_scripts({ - "locale.lua", - "locales/*.lua", - - "config.lua", - "config.weapons.lua", -}) - -server_scripts({ - "@oxmysql/lib/MySQL.lua", - "config.logs.lua", - "server/common.lua", - "server/modules/callback.lua", - "server/classes/player.lua", - "server/classes/overrides/*.lua", - "server/functions.lua", - "server/onesync.lua", - "server/paycheck.lua", - - "server/main.lua", - "server/commands.lua", - - "common/modules/*.lua", - "common/functions.lua", - "server/modules/actions.lua", - "server/modules/npwd.lua", -}) - -client_scripts({ - "client/common.lua", - "client/functions.lua", - "client/wrapper.lua", - "client/modules/callback.lua", - - "client/main.lua", - - "common/modules/*.lua", - "common/functions.lua", - - "common/functions.lua", - "client/modules/actions.lua", - "client/modules/death.lua", - "client/modules/npwd.lua", - "client/modules/scaleform.lua", - "client/modules/streaming.lua", -}) - -ui_page({ - "html/ui.html", -}) - -files({ - "imports.lua", - "locale.js", - "html/ui.html", - - "html/css/app.css", - - "html/js/mustache.min.js", - "html/js/wrapper.js", - "html/js/app.js", - - "html/fonts/pdown.ttf", - "html/fonts/bankgothic.ttf", -}) - -dependencies({ - "/native:0x6AE51D4B", - "/native:0xA61C8FC6", - "oxmysql", - "spawnmanager", -}) +fx_version 'cerulean' + +game 'gta5' +description 'The Core resource that provides the functionalities for all other resources.' +lua54 'yes' +version '1.10.7' + +shared_scripts { + 'locale.lua', + 'locales/*.lua', + + 'config.lua', + 'config.weapons.lua', +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'config.logs.lua', + 'server/common.lua', + 'server/modules/callback.lua', + 'server/classes/player.lua', + 'server/classes/overrides/*.lua', + 'server/functions.lua', + 'server/onesync.lua', + 'server/paycheck.lua', + + 'server/main.lua', + 'server/commands.lua', + + 'common/modules/*.lua', + 'common/functions.lua', + 'server/modules/actions.lua', + 'server/modules/npwd.lua', + 'server/modules/createJob.lua' +} + +client_scripts { + 'client/common.lua', + 'client/functions.lua', + 'client/wrapper.lua', + 'client/modules/callback.lua', + + 'client/main.lua', + + 'common/modules/*.lua', + 'common/functions.lua', + + 'client/modules/actions.lua', + 'client/modules/death.lua', + 'client/modules/npwd.lua', + 'client/modules/scaleform.lua', + 'client/modules/streaming.lua', +} + +ui_page { + 'html/ui.html' +} + +files { + 'imports.lua', + 'locale.js', + 'html/ui.html', + + 'html/css/app.css', + + 'html/js/mustache.min.js', + 'html/js/wrapper.js', + 'html/js/app.js', + + 'html/fonts/pdown.ttf', + 'html/fonts/bankgothic.ttf', +} + +dependencies { + '/native:0x6AE51D4B', + '/native:0xA61C8FC6', + 'oxmysql', + 'spawnmanager', +} diff --git a/[core]/es_extended/html/css/app.css b/[core]/es_extended/html/css/app.css index 1644e6044..6d4b095c9 100644 --- a/[core]/es_extended/html/css/app.css +++ b/[core]/es_extended/html/css/app.css @@ -20,11 +20,7 @@ html { font-size: 2em; font-weight: bold; color: #fff; - text-shadow: - -1px -1px 0 #000, - 1px -1px 0 #000, - -1px 1px 0 #000, - 1px 1px 0 #000; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; } .menu { diff --git a/[core]/es_extended/imports.lua b/[core]/es_extended/imports.lua index a81a71efb..ffb7d4bfa 100644 --- a/[core]/es_extended/imports.lua +++ b/[core]/es_extended/imports.lua @@ -1,5 +1,7 @@ ESX = exports["es_extended"]:getSharedObject() +OnPlayerData = function (key, val, last) end + if not IsDuplicityVersion() then -- Only register this event for the client AddEventHandler("esx:setPlayerData", function(key, val, last) if GetInvokingResource() == "es_extended" then diff --git a/[core]/es_extended/locale.js b/[core]/es_extended/locale.js index dd649aba4..e47e4345c 100644 --- a/[core]/es_extended/locale.js +++ b/[core]/es_extended/locale.js @@ -10,53 +10,56 @@ var locale = []; * */ function _U() { - var args = arguments; - var string = args[0]; - - // Was a string specified? - if (!string) { - console.log("locale.js: no string was parsed"); - return "locale.js: no string was parsed"; - } - - // Has the locale file been set? - if (locale.length === 0) { - console.log("locale.js: no locale has been set"); - return "locale.js: no locale has been set"; - } - - // Does the translation exist? - if (!locale[string]) { - console.log("locale.js: translation [{0}] does not exist".format(string)); - return "locale.js: translation [{0}] does not exist".format(string); - } - - // Do we need to format the string? - if (args.length === 1) { - return capitalize(locale[string]); - } else { - return formatString(args); - } + var args = arguments; + var string = args[0]; + + // Was a string specified? + if (!string) { + console.log('locale.js: no string was parsed'); + return 'locale.js: no string was parsed'; + } + + // Has the locale file been set? + if (locale.length === 0) { + console.log('locale.js: no locale has been set'); + return 'locale.js: no locale has been set'; + } + + // Does the translation exist? + if (!locale[string]) { + console.log('locale.js: translation [{0}] does not exist'.format(string)); + return 'locale.js: translation [{0}] does not exist'.format(string); + } + + // Do we need to format the string? + if (args.length === 1) { + return capitalize(locale[string]); + } else { + return formatString(args); + } } function formatString(args) { - var string = capitalize(locale[args[0]]); + var string = capitalize(locale[args[0]]); - for (var i = 1; i < args.length; i++) { - string = string.replace(/%s/, args[i]); - } + for (var i = 1; i < args.length; i++) { + string = string.replace(/%s/, args[i]); + } - return string; + return string; } function capitalize(string) { - return string[0].toUpperCase() + string.slice(1); + return string[0].toUpperCase() + string.slice(1); } // https://stackoverflow.com/a/35359503 String.prototype.format = function () { - var args = arguments; - return this.replace(/{(\d+)}/g, function (match, number) { - return typeof args[number] != "undefined" ? args[number] : match; - }); + var args = arguments; + return this.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != 'undefined' + ? args[number] + : match + ; + }); }; diff --git a/[core]/es_extended/locale.lua b/[core]/es_extended/locale.lua index 98a323db8..f9a29e9bd 100644 --- a/[core]/es_extended/locale.lua +++ b/[core]/es_extended/locale.lua @@ -25,4 +25,5 @@ function TranslateCap(str, ...) -- Translate string first char uppercase end _ = Translate +-- luacheck: ignore _U _U = TranslateCap diff --git a/[core]/es_extended/server/classes/overrides/oxinventory.lua b/[core]/es_extended/server/classes/overrides/oxinventory.lua index b6e9b53a4..5c8837072 100644 --- a/[core]/es_extended/server/classes/overrides/oxinventory.lua +++ b/[core]/es_extended/server/classes/overrides/oxinventory.lua @@ -140,7 +140,7 @@ Core.PlayerFunctionOverrides.OxInventory = { return function(newWeight) self.maxWeight = newWeight self.triggerEvent("esx:setMaxWeight", self.maxWeight) - return Inventory.Set(self.source, "maxWeight", newWeight) + return Inventory.SetMaxWeight(self.source, newWeight) end end, diff --git a/[core]/es_extended/server/classes/player.lua b/[core]/es_extended/server/classes/player.lua index ad3fd030b..5b36912bd 100644 --- a/[core]/es_extended/server/classes/player.lua +++ b/[core]/es_extended/server/classes/player.lua @@ -1,5 +1,6 @@ local _GetPlayerPed = GetPlayerPed local _GetEntityCoords = GetEntityCoords +local _GetEntityHeading = GetEntityHeading local _ExecuteCommand = ExecuteCommand local _SetEntityCoords = SetEntityCoords local _SetEntityHeading = SetEntityHeading @@ -76,12 +77,24 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, end ---@param vector boolean - ---@return vector3 | table - function self.getCoords(vector) + ---@param heading boolean + ---@return vector3 | vector4 | table + function self.getCoords(vector, heading) local ped = _GetPlayerPed(self.source) - local coordinates = _GetEntityCoords(ped) + local entityCoords = _GetEntityCoords(ped) + local entityHeading = _GetEntityHeading(ped) - return vector and coordinates or { x = coordinates.x, y = coordinates.y, z = coordinates.z } + local coordinates = { x = entityCoords.x, y = entityCoords.y, z = entityCoords.z } + + if vector then + coordinates = (heading and vector4(entityCoords.xyz, entityHeading) or entityCoords) + else + if heading then + coordinates.heading = entityHeading + end + end + + return coordinates end ---@param reason string @@ -127,9 +140,16 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, ---@param newGroup string ---@return void function self.setGroup(newGroup) + local lastGroup = self.group + _ExecuteCommand(("remove_principal identifier.%s group.%s"):format(self.license, self.group)) + self.group = newGroup + + _TriggerEvent("esx:setGroup", self.source, self.group, lastGroup) + self.triggerEvent("esx:setGroup", self.group, lastGroup) Player(self.source).state:set("group", self.group, true) + _ExecuteCommand(("add_principal identifier.%s group.%s"):format(self.license, self.group)) end @@ -475,7 +495,7 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, skin_female = gradeObject.skin_female and json.decode(gradeObject.skin_female) or {}, } - TriggerEvent("esx:setJob", self.source, self.job, lastJob) + _TriggerEvent("esx:setJob", self.source, self.job, lastJob) self.triggerEvent("esx:setJob", self.job, lastJob) Player(self.source).state:set("job", self.job, true) end diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index bfaeb5716..4ed4b39a9 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -4,6 +4,24 @@ function ESX.Trace(msg) end end +--- Triggers an event for one or more clients. +---@param eventName string The name of the event to trigger. +---@param playerIds table|number If a number, represents a single player ID. If a table, represents an array of player IDs. +---@param ... any Additional arguments to pass to the event handler. +function ESX.TriggerClientEvent(eventName, playerIds, ...) + if type(playerIds) == "number" then + TriggerClientEvent(eventName, playerIds, ...) + return + end + + local payload = msgpack.pack_args(...) + local payloadLength = #payload + + for i = 1, #playerIds do + TriggerClientEventInternal(eventName, playerIds[i], payload, payloadLength) + end +end + function ESX.RegisterCommand(name, group, cb, allowConsole, suggestion) if type(name) == "table" then for _, v in ipairs(name) do @@ -106,13 +124,13 @@ function ESX.RegisterCommand(name, group, cb, allowConsole, suggestion) elseif v.type == "any" then newArgs[v.name] = args[k] elseif v.type == "merge" then - local lenght = 0 + local length = 0 for i = 1, k - 1 do - lenght = lenght + string.len(args[i]) + 1 + length = length + string.len(args[i]) + 1 end local merge = table.concat(args, " ") - newArgs[v.name] = string.sub(merge, lenght) + newArgs[v.name] = string.sub(merge, length) elseif v.type == "coordinate" then local coord = tonumber(args[k]:match("(-?%d+%.?%d*)")) if not coord then @@ -181,22 +199,26 @@ function Core.SavePlayer(xPlayer, cb) xPlayer.job.name, xPlayer.job.grade, xPlayer.group, - json.encode(xPlayer.getCoords()), + json.encode(xPlayer.getCoords(false, true)), json.encode(xPlayer.getInventory(true)), json.encode(xPlayer.getLoadout(true)), json.encode(xPlayer.getMeta()), xPlayer.identifier, } - MySQL.prepare("UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?", parameters, function(affectedRows) - if affectedRows == 1 then - print(('[^2INFO^7] Saved player ^5"%s^7"'):format(xPlayer.name)) - TriggerEvent("esx:playerSaved", xPlayer.playerId, xPlayer) - end - if cb then - cb() + MySQL.prepare( + "UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?", + parameters, + function(affectedRows) + if affectedRows == 1 then + print(('[^2INFO^7] Saved player ^5"%s^7"'):format(xPlayer.name)) + TriggerEvent("esx:playerSaved", xPlayer.playerId, xPlayer) + end + if cb then + cb() + end end - end) + ) end function Core.SavePlayers(cb) @@ -223,17 +245,21 @@ function Core.SavePlayers(cb) } end - MySQL.prepare("UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?", parameters, function(results) - if not results then - return - end + MySQL.prepare( + "UPDATE `users` SET `accounts` = ?, `job` = ?, `job_grade` = ?, `group` = ?, `position` = ?, `inventory` = ?, `loadout` = ?, `metadata` = ? WHERE `identifier` = ?", + parameters, + function(results) + if not results then + return + end - if type(cb) == "function" then - return cb() - end + if type(cb) == "function" then + return cb() + end - print(("[^2INFO^7] Saved ^5%s^7 %s over ^5%s^7 ms"):format(#parameters, #parameters > 1 and "players" or "player", ESX.Math.Round((os.time() - startTime) / 1000000, 2))) - end) + print(("[^2INFO^7] Saved ^5%s^7 %s over ^5%s^7 ms"):format(#parameters, #parameters > 1 and "players" or "player", ESX.Math.Round((os.time() - startTime) / 1000000, 2))) + end + ) end ESX.GetPlayers = GetPlayers @@ -398,37 +424,6 @@ function ESX.DiscordLogFields(name, title, color, fields) ) end ---- Create Job at Runtime ---- @param name string ---- @param label string ---- @param grades table -function ESX.CreateJob(name, label, grades) - if not name then - return print("[^3WARNING^7] missing argument `name(string)` while creating a job") - end - - if not label then - return print("[^3WARNING^7] missing argument `label(string)` while creating a job") - end - - if not grades or not next(grades) then - return print("[^3WARNING^7] missing argument `grades(table)` while creating a job!") - end - - local parameters = {} - local job = { name = name, label = label, grades = {} } - - for _, v in pairs(grades) do - job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or "{}", skin_female = v.skin_female or "{}" } - parameters[#parameters + 1] = { name, v.grade, v.name, v.label, v.salary, v.skin_male or "{}", v.skin_female or "{}" } - end - - MySQL.insert("INSERT IGNORE INTO jobs (name, label) VALUES (?, ?)", { name, label }) - MySQL.prepare("INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)", parameters) - - ESX.Jobs[name] = job -end - function ESX.RefreshJobs() local Jobs = {} local jobs = MySQL.query.await("SELECT * FROM jobs") @@ -541,15 +536,7 @@ if not Config.OxInventory then end function ESX.DoesJobExist(job, grade) - grade = tostring(grade) - - if job and grade then - if ESX.Jobs[job] and ESX.Jobs[job].grades[grade] then - return true - end - end - - return false + return (ESX.Jobs[job] and ESX.Jobs[job].grades[tostring(grade)] ~= nil) or false end function Core.IsPlayerAdmin(playerId) diff --git a/[core]/es_extended/server/main.lua b/[core]/es_extended/server/main.lua index e268ec803..4862e7ff6 100644 --- a/[core]/es_extended/server/main.lua +++ b/[core]/es_extended/server/main.lua @@ -164,7 +164,7 @@ function loadESXPlayer(identifier, playerId, isNew) job, grade = "unemployed", "0" end - jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] userData.job = { id = jobObject.id, @@ -239,7 +239,7 @@ function loadESXPlayer(identifier, playerId, isNew) end -- Position - userData.coords = json.decode(result.position) or Config.DefaultSpawns[math.random(#Config.DefaultSpawns)] + userData.coords = json.decode(result.position) or Config.DefaultSpawns[ESX.Math.Random(1,#Config.DefaultSpawns)] -- Skin userData.skin = (result.skin and result.skin ~= "") and json.decode(result.skin) or { sex = userData.sex == "f" and 1 or 0 } @@ -509,19 +509,21 @@ if not Config.OxInventory then if xPlayer.hasWeapon(itemName) then local _, weapon = xPlayer.getWeapon(itemName) local _, weaponObject = ESX.GetWeapon(itemName) - local components, pickupLabel = ESX.Table.Clone(weapon.components) + -- luacheck: ignore weaponPickupLabel + local weaponPickupLabel = "" + local components = ESX.Table.Clone(weapon.components) xPlayer.removeWeapon(itemName) if weaponObject.ammo and weapon.ammo > 0 then local ammoLabel = weaponObject.ammo.label - pickupLabel = ("%s [%s %s]"):format(weapon.label, weapon.ammo, ammoLabel) + weaponPickupLabel = ("%s [%s %s]"):format(weapon.label, weapon.ammo, ammoLabel) xPlayer.showNotification(TranslateCap("threw_weapon_ammo", weapon.label, weapon.ammo, ammoLabel)) else - pickupLabel = ("%s"):format(weapon.label) + weaponPickupLabel = ("%s"):format(weapon.label) xPlayer.showNotification(TranslateCap("threw_weapon", weapon.label)) end - ESX.CreatePickup("item_weapon", itemName, weapon.ammo, pickupLabel, playerId, components, weapon.tintIndex) + ESX.CreatePickup("item_weapon", itemName, weapon.ammo, weaponPickupLabel, playerId, components, weapon.tintIndex) end end end) diff --git a/[core]/es_extended/server/modules/createJob.lua b/[core]/es_extended/server/modules/createJob.lua new file mode 100644 index 000000000..e156fa11a --- /dev/null +++ b/[core]/es_extended/server/modules/createJob.lua @@ -0,0 +1,102 @@ + +local NOTIFY_TYPES = { + INFO = "^5[%s]^7-^6[INFO]^7 %s", + SUCCESS = "^5[%s]^7-^2[SUCCESS]^7 %s", + ERROR = "^5[%s]^7-^1[ERROR]^7 %s" +} + +local function doesJobAndGradesExist(name, grades) + if not ESX.Jobs[name] then + return false + end + + for _, grade in ipairs(grades) do + if not ESX.DoesJobExist(name, grade.grade) then + return false + end + end + + return true +end + +local function generateTransactionQueries(name,grades) + local queries = {} + for _, grade in ipairs(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, '{}', '{}'} + } + end + + return queries +end + +local function generateNewJobTable(name, label, grades) + local job = { name = name, label = label, grades = {} } + for _, v in pairs(grades) do + job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = {}, skin_female = {} } + end + + return job +end + +local function notify(notifyType,resourceName,message,...) + local formattedMessage = string.format(message, ...) + + if not NOTIFY_TYPES[notifyType] then + return print(NOTIFY_TYPES.INFO:format(resourceName,formattedMessage)) + end + + return print(NOTIFY_TYPES[notifyType]:format(resourceName,formattedMessage)) +end + +--- Create Job at Runtime +--- @param name string +--- @param label string +--- @param grades table +function ESX.CreateJob(name, label, grades) + local currentResourceName = GetInvokingResource() + local success = false + + if not name or name == '' then + notify("ERROR",currentResourceName, 'Missing argument `name`') + return + end + if not label or label == '' then + notify("ERROR",currentResourceName, 'Missing argument `label`') + return + end + if not grades or not next(grades) then + notify("ERROR",currentResourceName, 'Missing argument `grades`') + return + end + + local currentJobExist = doesJobAndGradesExist(name, grades) + + if currentJobExist then + notify("ERROR",currentResourceName, 'Job or grades already exists: `%s`', name) + return + end + + MySQL.insert('INSERT IGNORE INTO jobs (name, label) VALUES (?, ?)', {name, label}, function(jobId) + if jobId == nil or jobId == 0 then + notify("ERROR",currentResourceName, 'Failed to insert job: `%s`', name) + return + end + + local queries = generateTransactionQueries(name, grades) + + MySQL.transaction(queries, function(results) + success = results + if not results then + notify("ERROR",currentResourceName, 'Failed to insert one or more grades for job: `%s`', name) + return + end + + ESX.Jobs[name] = generateNewJobTable(name,label,grades) + notify("SUCCESS",currentResourceName, 'Job created successfully: `%s`', name) + end) + end) + + return success +end