From 30c248c76af88cedf1247ca042e26b92963e6ff6 Mon Sep 17 00:00:00 2001 From: Fezz <43589668+FBFezz@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:25:22 +0100 Subject: [PATCH] Revert "feat(xPlayer): made xPlayer's functions hookable" --- .../server/classes/overrides/oxinventory.lua | 219 ++++ .../server/classes/xPlayer/classes.lua | 176 ---- .../server/classes/xPlayer/main.lua | 976 ------------------ .../classes/xPlayer/oxInv_overrides.lua | 132 --- [core]/es_extended/server/functions.lua | 6 +- [core]/es_extended/server/main.lua | 152 ++- [core]/es_extended/server/migration/main.lua | 2 +- .../es_extended/server/modules/getXPlayer.lua | 36 - [core]/es_extended/shared/modules/table.lua | 2 +- [core]/esx_notify/Notify.lua | 14 +- [core]/skinchanger/client/main.lua | 2 +- 11 files changed, 327 insertions(+), 1390 deletions(-) create mode 100644 [core]/es_extended/server/classes/overrides/oxinventory.lua delete mode 100644 [core]/es_extended/server/classes/xPlayer/classes.lua delete mode 100644 [core]/es_extended/server/classes/xPlayer/main.lua delete mode 100644 [core]/es_extended/server/classes/xPlayer/oxInv_overrides.lua delete mode 100644 [core]/es_extended/server/modules/getXPlayer.lua diff --git a/[core]/es_extended/server/classes/overrides/oxinventory.lua b/[core]/es_extended/server/classes/overrides/oxinventory.lua new file mode 100644 index 00000000..c3be26a8 --- /dev/null +++ b/[core]/es_extended/server/classes/overrides/oxinventory.lua @@ -0,0 +1,219 @@ +local Inventory + +if Config.CustomInventory ~= "ox" then return end + +AddEventHandler("ox_inventory:loadInventory", function(module) + Inventory = module +end) + +Core.PlayerFunctionOverrides.OxInventory = { + getInventory = function(self) + return function(minimal) + if not minimal then + return self.inventory + end + + local minimalInventory = {} + + for k, v in pairs(self.inventory) do + if v.count and v.count > 0 then + local metadata = v.metadata + + if v.metadata and next(v.metadata) == nil then + metadata = nil + end + + minimalInventory[#minimalInventory + 1] = { + name = v.name, + count = v.count, + slot = k, + metadata = metadata, + } + end + end + + return minimalInventory + end + end, + + getLoadout = function() + return function() + return {} + end + end, + + setAccountMoney = function(self) + return function(accountName, money, reason) + reason = reason or "unknown" + if money < 0 then return end + local account = self.getAccount(accountName) + + if not account then return end + + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = money + + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:setAccountMoney", self.source, accountName, money, reason) + if Inventory.accounts[accountName] then + Inventory.SetItem(self.source, accountName, money) + end + end + end, + + addAccountMoney = function(self) + return function(accountName, money, reason) + reason = reason or "unknown" + if money < 1 then return end + + local account = self.getAccount(accountName) + if not account then return end + + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = self.accounts[account.index].money + money + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:addAccountMoney", self.source, accountName, money, reason) + if Inventory.accounts[accountName] then + Inventory.AddItem(self.source, accountName, money) + end + end + end, + + removeAccountMoney = function(self) + return function(accountName, money, reason) + reason = reason or "unknown" + if money < 1 then return end + + local account = self.getAccount(accountName) + if not account then return end + + money = account.round and ESX.Math.Round(money) or money + self.accounts[account.index].money = self.accounts[account.index].money - money + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:removeAccountMoney", self.source, accountName, money, reason) + if Inventory.accounts[accountName] then + Inventory.RemoveItem(self.source, accountName, money) + end + end + end, + + getInventoryItem = function(self) + return function(name, metadata) + return Inventory.GetItem(self.source, name, metadata) + end + end, + + addInventoryItem = function(self) + return function(name, count, metadata, slot) + return Inventory.AddItem(self.source, name, count or 1, metadata, slot) + end + end, + + removeInventoryItem = function(self) + return function(name, count, metadata, slot) + return Inventory.RemoveItem(self.source, name, count or 1, metadata, slot) + end + end, + + setInventoryItem = function(self) + return function(name, count, metadata) + return Inventory.SetItem(self.source, name, count, metadata) + end + end, + + canCarryItem = function(self) + return function(name, count, metadata) + return Inventory.CanCarryItem(self.source, name, count, metadata) + end + end, + + canSwapItem = function(self) + return function(firstItem, firstItemCount, testItem, testItemCount) + return Inventory.CanSwapItem(self.source, firstItem, firstItemCount, testItem, testItemCount) + end + end, + + setMaxWeight = function(self) + return function(newWeight) + self.maxWeight = newWeight + self.triggerEvent("esx:setMaxWeight", self.maxWeight) + return Inventory.SetMaxWeight(self.source, newWeight) + end + end, + + addWeapon = function() + return function() end + end, + + addWeaponComponent = function() + return function() end + end, + + addWeaponAmmo = function() + return function() end + end, + + updateWeaponAmmo = function() + return function() end + end, + + setWeaponTint = function() + return function() end + end, + + getWeaponTint = function() + return function() end + end, + + removeWeapon = function() + return function() end + end, + + removeWeaponComponent = function() + return function() end + end, + + removeWeaponAmmo = function() + return function() end + end, + + hasWeaponComponent = function() + return function() + return false + end + end, + + hasWeapon = function() + return function() + return false + end + end, + + hasItem = function(self) + return function(name, metadata) + return Inventory.GetItem(self.source, name, metadata) + end + end, + + getWeapon = function() + return function() end + end, + + syncInventory = function(self) + return function(weight, maxWeight, items, money) + self.weight, self.maxWeight = weight, maxWeight + self.inventory = items + + if not money then return end + for accountName, amount in pairs(money) do + local account = self.getAccount(accountName) + + if account and ESX.Math.Round(account.money) ~= amount then + account.money = amount + self.triggerEvent("esx:setAccountMoney", account) + TriggerEvent("esx:setAccountMoney", self.source, accountName, amount, "Sync account with item") + end + end + end + end, +} diff --git a/[core]/es_extended/server/classes/xPlayer/classes.lua b/[core]/es_extended/server/classes/xPlayer/classes.lua deleted file mode 100644 index b05706a8..00000000 --- a/[core]/es_extended/server/classes/xPlayer/classes.lua +++ /dev/null @@ -1,176 +0,0 @@ ----@class ESXAccount ----@field name string # Account name (e.g., "bank", "money"). ----@field money number # Current balance in this account. ----@field label string # Human-readable label for the account. ----@field round boolean # Whether amounts are rounded for display. ----@field index number # Index of the account in the player's accounts list. - ----@class ESXItem ----@field name string # Item identifier (internal name). ----@field label string # Display name of the item. ----@field weight number # Weight of a single unit of the item. ----@field usable boolean # Whether the item can be used. ----@field rare boolean # Whether the item is rare. ----@field canRemove boolean # Whether the item can be removed from inventory. - ----@class ESXInventoryItem:ESXItem ----@field count number # Number of this item in the player's inventory. - ----@class ESXJob ----@field id number # Job ID. ----@field name string # Job internal name. ----@field label string # Job display label. ----@field grade number # Current grade/rank number. ----@field grade_name string # Name of the current grade. ----@field grade_label string # Label of the current grade. ----@field grade_salary number # Salary for the current grade. ----@field skin_male table # Skin configuration for male characters. ----@field skin_female table # Skin configuration for female characters. ----@field onDuty boolean? # Whether the player is currently on duty. - ----@class ESXWeapon ----@field name string # Weapon identifier (internal name). ----@field label string # Weapon display name. - ----@class ESXInventoryWeapon:ESXWeapon ----@field ammo number # Amount of ammo in the weapon. ----@field components string[] # List of components attached to the weapon. ----@field tintIndex number # Current weapon tint index. - ----@class ESXWeaponComponent ----@field name string # Component identifier (internal name). ----@field label string # Component display name. ----@field hash string|number # Component hash or identifier. - ----@class StaticPlayer ----@field src number # Player's server ID. ---- Money Functions ----@field setMoney fun(money: number) # Set player's cash balance. ----@field getMoney fun(): number # Get player's current cash balance. ----@field addMoney fun(money: number, reason: string) # Add money to the player's cash balance. ----@field removeMoney fun(money: number, reason: string) # Remove money from the player's cash balance. ----@field setAccountMoney fun(accountName: string, money: number, reason?: string) # Set specific account balance. ----@field addAccountMoney fun(accountName: string, money: number, reason?: string) # Add money to an account. ----@field removeAccountMoney fun(accountName: string, money: number, reason?: string) # Remove money from an account. ----@field getAccount fun(account: string): ESXAccount? # Get account data by name. ----@field getAccounts fun(minimal?: boolean): ESXAccount[]|table # Get all accounts, optionally minimal. ---- Inventory Functions ----@field getInventory fun(minimal?: boolean): ESXInventoryItem[]|table # Get inventory, optionally minimal. ----@field getInventoryItem fun(itemName: string): ESXInventoryItem? # Get a specific item from inventory. ----@field addInventoryItem fun(itemName: string, count: number) # Add items to inventory. ----@field removeInventoryItem fun(itemName: string, count: number) # Remove items from inventory. ----@field setInventoryItem fun(itemName: string, count: number) # Set item count in inventory. ----@field getWeight fun(): number # Get current carried weight. ----@field getMaxWeight fun(): number # Get maximum carry weight. ----@field setMaxWeight fun(newWeight: number) # Set maximum carry weight. ----@field canCarryItem fun(itemName: string, count: number): boolean # Check if player can carry more of an item. ----@field canSwapItem fun(firstItem: string, firstItemCount: number, testItem: string, testItemCount: number): boolean # Check if items can be swapped. ----@field hasItem fun(item: string): ESXInventoryItem|false, number? # Check if player has an item. ----@field getLoadout fun(minimal?: boolean): ESXInventoryWeapon[]|table # Get player's weapon loadout. ---- Job Functions ----@field getJob fun(): ESXJob # Get player's current job. ----@field setJob fun(newJob: string, grade: string, onDuty?: boolean) # Set player's job and grade. ----@field setGroup fun(newGroup: string) # Set player's permission group. ----@field getGroup fun(): string # Get player's permission group. ---- Weapon Functions ----@field addWeapon fun(weaponName: string, ammo: number) # Give player a weapon. ----@field removeWeapon fun(weaponName: string) # Remove weapon from player. ----@field hasWeapon fun(weaponName: string): boolean # Check if player has a weapon. ----@field getWeapon fun(weaponName: string): number?, table? # Get weapon ammo & components. ----@field addWeaponAmmo fun(weaponName: string, ammoCount: number) # Add ammo to a weapon. ----@field removeWeaponAmmo fun(weaponName: string, ammoCount: number) # Remove ammo from a weapon. ----@field updateWeaponAmmo fun(weaponName: string, ammoCount: number) # Update ammo count for a weapon. ----@field addWeaponComponent fun(weaponName: string, weaponComponent: string) # Add component to weapon. ----@field removeWeaponComponent fun(weaponName: string, weaponComponent: string) # Remove component from weapon. ----@field hasWeaponComponent fun(weaponName: string, weaponComponent: string): boolean # Check if weapon has component. ----@field setWeaponTint fun(weaponName: string, weaponTintIndex: number) # Set weapon tint. ----@field getWeaponTint fun(weaponName: string): number # Get weapon tint. ---- Player State Functions ----@field getIdentifier fun(): string # Get player's unique identifier. ----@field getSSN fun(): string # Get player's social security number. ----@field getSource fun(): number # Get player source/server ID. ----@field getPlayerId fun(): number # Alias for getSource. ----@field getName fun(): string # Get player's name. ----@field setName fun(newName: string) # Set player's name. ----@field setCoords fun(coordinates: vector4|vector3|table) # Teleport player to coordinates. ----@field getCoords fun(vector?: boolean, heading?: boolean): vector3|vector4|table # Get player's coordinates. ----@field isAdmin fun(): boolean # Check if player is admin. ----@field kick fun(reason: string) # Kick player from server. ----@field getPlayTime fun(): number # Get total playtime in seconds. ----@field set fun(k: string, v: any) # Set custom variable. ----@field get fun(k: string): any # Get custom variable. ---- Metadata Functions ----@field getMeta fun(index?: string, subIndex?: string|table): any # Get metadata value(s). ----@field setMeta fun(index: string, value: any, subValue?: any) # Set metadata value(s). ----@field clearMeta fun(index: string, subValues?: string|table) # Clear metadata value(s). ---- Notification Functions ----@field showNotification fun(msg: string, notifyType?: string, length?: number, title?: string, position?: string) # Show a simple notification. ----@field showAdvancedNotification fun(sender: string, subject: string, msg: string, textureDict: string, iconType: string, flash: boolean, saveToBrief: boolean, hudColorIndex: number) # Show advanced notification. ----@field showHelpNotification fun(msg: string, thisFrame?: boolean, beep?: boolean, duration?: number) # Show help notification. ---- Misc Functions ----@field togglePaycheck fun(toggle: boolean) # Enable/disable paycheck. ----@field isPaycheckEnabled fun(): boolean # Check if paycheck is enabled. ----@field executeCommand fun(command: string) # Execute a server command. ----@field triggerEvent fun(eventName: string, ...) # Trigger client event for this player. - ----@class xPlayer:StaticPlayer ---- Properties ----@field accounts ESXAccount[] # Array of the player's accounts. ----@field coords table # Player's coordinates {x, y, z, heading}. ----@field group string # Player permission group. ----@field identifier string # Unique identifier (usually Steam or license). ----@field license string # Player license string. ----@field inventory ESXInventoryItem[] # Player's inventory items. ----@field job ESXJob # Player's current job. ----@field loadout ESXInventoryWeapon[] # Player's current weapons. ----@field name string # Player's display name. ----@field playerId number # Player's ID (server ID). ----@field source number # Player's source (alias for playerId). ----@field variables table # Custom player variables. ----@field weight number # Current carried weight. ----@field maxWeight number # Maximum carry weight. ----@field metadata table # Custom metadata table. ----@field lastPlaytime number # Last recorded playtime in seconds. ----@field paycheckEnabled boolean # Whether paycheck is enabled. ----@field admin boolean # Whether the player is an admin. - ----@class xPlayerClass:xPlayer ----@field hooks { hookId: string, functionName: string, invokerRes: string, isJustAddition: boolean, functionReference: fun(xPlayer: xPlayer, ...: any): any }[] ----@field addHook fun(self: xPlayerClass, functionName: string, isJustAddition: boolean, functionReference: fun(xPlayer: xPlayer, ...: any): any): string Returns the hookId of the created hook ----@field removeHook fun(self: xPlayerClass, hookId: string): boolean Returns success status ----@field kick function ----@field setMoney function ----@field getMoney function ----@field addMoney function ----@field removeMoney function ----@field getInventory function ----@field getLoadout function ----@field setAccountMoney function ----@field addAccountMoney function ----@field removeAccountMoney function ----@field getInventoryItem function ----@field addInventoryItem function ----@field removeInventoryItem function ----@field setInventoryItem function ----@field canCarryItem function ----@field canSwapItem function ----@field setMaxWeight function ----@field addWeapon function ----@field addWeaponComponent function ----@field addWeaponAmmo function ----@field updateWeaponAmmo function ----@field setWeaponTint function ----@field getWeaponTint function ----@field removeWeapon function ----@field removeWeaponComponent function ----@field removeWeaponAmmo function ----@field hasWeaponComponent function ----@field hasWeapon function ----@field hasItem function ----@field getWeapon function ----@field showNotification function ----@field showAdvancedNotification function ----@field showHelpNotification function ----@field __index fun(self: xPlayerClass, k: string): any ----@field __newindex fun(self: xPlayerClass, k: string, v: any) ----@field __call fun(self: xPlayerClass, xPlayer: xPlayer, functionName): fun(...: any): any Function to convert each function from the xPlayer class to actual xPlayer function (only available to call from es_extended) \ No newline at end of file diff --git a/[core]/es_extended/server/classes/xPlayer/main.lua b/[core]/es_extended/server/classes/xPlayer/main.lua deleted file mode 100644 index 47c5e66e..00000000 --- a/[core]/es_extended/server/classes/xPlayer/main.lua +++ /dev/null @@ -1,976 +0,0 @@ -IsAuthorized = {} - -local hookIdGeneratorRadius = 1e5 -local hookableFunctions = setmetatable({ - 'kick', - 'setMoney', - 'getMoney', - 'addMoney', - 'removeMoney', - 'addAccountMoney', - 'setAccountMoney', - 'removeAccountMoney', - 'getInventoryItem', - 'addInventoryItem', - 'removeInventoryItem', - 'setInventoryItem', - 'hasItem', - 'hasWeapon', - 'hasWeaponComponent', - 'getWeaponTint', - 'setWeaponTint', - 'addWeaponAmmo', - 'getInventory', - 'getLoadout', - 'canCarryItem', - 'canSwapItem', - 'setMaxWeight', - 'addWeapon', - 'addWeaponComponent', - 'updateWeaponAmmo', - 'removeWeapon', - 'removeWeaponComponent', - 'removeWeaponAmmo', - 'getWeapon', - 'showNotification', - 'showAdvancedNotification', - 'showHelpNotification' -}, { - __call = function(self, functionName) - for i=1, #self do - if self[i] == functionName then - return true - end - end - - return false - end -}) - --- Local Functions - -local otherResCheck = function() - return GetInvokingResource() ~= 'es_extended' and not IsAuthorized[#IsAuthorized] -end - ----@param hooks { hookId: string, functionName: string, invokingRes: string, isJustAddition: boolean, functionReference: fun(xPlayer: xPlayer, ...: any): any }[] ----@return string -local generateHookId = function(hooks) - local idText = ('xPlayerHook_%s'):format(math.random(-hookIdGeneratorRadius, hookIdGeneratorRadius)) - - if hooks('hookId', idText) then - local timesExecuted = 0 --2*hookIdGeneratorRadius - while hooks('hookId', idText) do - Wait(0) - - if timesExecuted < 2*hookIdGeneratorRadius then - idText = ('xPlayerHook_%s'):format(math.random(-hookIdGeneratorRadius, hookIdGeneratorRadius)) - timesExecuted += 1 - else - idText = ('xPlayerHook_%s'):format(hookIdGeneratorRadius + 1) - - hookIdGeneratorRadius *= 1e2 - - break - end - end - end - - return idText -end - --- Main Code - -XPlayerClass = setmetatable({ - hooks = setmetatable({}, { - __call = function(self, compareField, compareValue, returnIndex) - if compareField ~= 'hookId' and compareField ~= 'functionName' and compareField ~= 'invokerRes' and compareField ~= 'functionReference' then return error(('Resource %s tried to compare unexisting field in ESX\'s xPlayer hooks.\nStopped the code to prevent other errors.'):format(GetInvokingResource())) end - - for i=1, #self do - if self[i][compareField] == compareValue then - if returnIndex then - return true, i - else - return true - end - end - end - end - }), - - addHook = function(self, functionName, isJustAddition, functionReference) - IsAuthorized[#IsAuthorized+1] = true - - if not self[functionName] or not ESX.IsFunctionReference(functionReference) then - warn(('Resource %s tried to\n%s!'):format(GetInvokingResource(), not self[functionName] and 'add a hook function to missing xPlayer function' or 'add a hook function by providing a non-function for the hook\'s function reference')) - - return false - elseif not hookableFunctions(functionName) then - warn(('Resource %s tried to add a hook for a function which does not support hooks!'):format(GetInvokingResource())) - end - - if not isJustAddition then - if #self.hooks > 0 then - for i=1, #self.hooks do - if self.hooks[i].functionName == functionName then - table.remove(self.hooks, i) - end - end - end - end - - local hookId = generateHookId(self.hooks) - - self.hooks[#self.hooks+1] = { - hookId = hookId, - functionName = functionName, - invokerRes = GetInvokingResource(), - isJustAddition = true, - functionReference = functionReference - } - - table.remove(IsAuthorized, #IsAuthorized) - - return hookId - end, - - removeHook = function(self, hookId) - IsAuthorized[#IsAuthorized+1] = true - - local found , index = self.hooks('hookId', hookId, true) - - if found then - table.remove(self.hooks, index) - end - - table.remove(IsAuthorized, #IsAuthorized) - - return found - end, - - triggerEvent = function(xPlayer, eventName, ...) - assert(type(eventName) == 'string', 'eventName should be string!') - TriggerClientEvent(eventName, xPlayer.source, ...) - end, - - togglePaycheck = function(xPlayer, toggle) - xPlayer.paycheckEnabled = toggle - end, - - isPaycheckEnabled = function(xPlayer) - return xPlayer.paycheckEnabled - end, - - isAdmin = function(xPlayer) - return Core.IsPlayerAdmin(xPlayer.source) - end, - - setCoords = function(xPlayer, coordinates) - local ped = GetPlayerPed(xPlayer.source) - - SetEntityCoords(ped, coordinates.x, coordinates.y, coordinates.z, false, false, false, false) - SetEntityHeading(ped, coordinates.w or coordinates.heading or 0.0) - end, - - getCoords = function(xPlayer, vector, heading) - local ped = GetPlayerPed(xPlayer.source) - local entityCoords = GetEntityCoords(ped) - local entityHeading = GetEntityHeading(ped) - - local coordinates = { x = entityCoords.x, y = entityCoords.y, z = entityCoords.z } - - if vector then - coordinates = (heading and vector4(entityCoords.x, entityCoords.y, entityCoords.z, entityHeading) or entityCoords) - elseif heading then - coordinates.heading = entityHeading - end - - return coordinates - end, - - kick = function(xPlayer, reason) - DropPlayer(tostring(xPlayer.source), reason) - end, - - getPlayTime = function(xPlayer) - return xPlayer.lastPlaytime + GetPlayerTimeOnline(xPlayer.source --[[@as string]]) - end, - - setMoney = function(xPlayer, money) - assert(type(money) == 'number', 'money should be number!') - - xPlayer.setAccountMoney('money', ESX.Math.Round(money)) - end, - - getMoney = function(xPlayer) - return xPlayer.getAccount('money').money - end, - - addMoney = function(xPlayer, money, reason) - xPlayer.addAccountMoney('money', ESX.Math.Round(money), reason) - end, - - removeMoney = function(xPlayer, money, reason) - xPlayer.removeAccountMoney('money', ESX.Math.Round(money), reason) - end, - - ---@deprecated use xPlayer.identifier instead - getIdentifier = function(xPlayer) return xPlayer.identifier end, - - ---@deprecated use xPlayer.ssn instead - getSSN = function(xPlayer) return xPlayer.ssn end, - - setGroup = function(xPlayer, newGroup) - local lastGroup = xPlayer.group - xPlayer.group = newGroup - - xPlayer.triggerEvent('esx:setGroup', xPlayer.group, lastGroup) - Player(xPlayer.source).state:set('group', xPlayer.group, true) - TriggerEvent('esx:setGroup', xPlayer.source, xPlayer.group, lastGroup) - ExecuteCommand(('remove_principal identifier.%s group.%s'):format(xPlayer.license, lastGroup)) - ExecuteCommand(('add_principal identifier.%s group.%s'):format(xPlayer.license, xPlayer.group)) - end, - - ---@deprecated use xPlayer.group instead - getGroup = function(xPlayer) return xPlayer.group end, - - set = function(xPlayer, k, v) - xPlayer.variables[k] = v - - xPlayer.triggerEvent('esx:updatePlayerData', 'variables', xPlayer.variables) - end, - - get = function(xPlayer, k) - return xPlayer.variables[k] - end, - - getAccounts = function(xPlayer, minimal) - if not minimal then - return xPlayer.accounts - end - - local minimalAccounts = {} - - for i = 1, #xPlayer.accounts do - minimalAccounts[xPlayer.accounts[i].name] = xPlayer.accounts[i].money - end - - return minimalAccounts - end, - - getAccount = function(xPlayer, account) - account = string.lower(account) - for i = 1, #xPlayer.accounts do - local accountName = string.lower(xPlayer.accounts[i].name) - if accountName == account then - return xPlayer.accounts[i] - end - end - - return nil - end, - - getInventory = function(xPlayer, minimal) - if minimal then - local minimalInventory = {} - - for _, v in ipairs(xPlayer.inventory) do - if v.count > 0 then - minimalInventory[v.name] = v.count - end - end - - return minimalInventory - end - - return xPlayer.inventory - end, - - ---@deprecated use xPlayer.job instead - getJob = function(xPlayer) - return xPlayer.job - end, - - getLoadout = function(xPlayer, minimal) - if not minimal then - return xPlayer.loadout - end - local minimalLoadout = {} - - for _, v in ipairs(xPlayer.loadout) do - minimalLoadout[v.name] = { ammo = v.ammo } - if v.tintIndex > 0 then - minimalLoadout[v.name].tintIndex = v.tintIndex - end - - if #v.components > 0 then - local components = {} - - for _, component in ipairs(v.components) do - if component ~= 'clip_default' then - components[#components + 1] = component - end - end - - if #components > 0 then - minimalLoadout[v.name].components = components - end - end - end - - return minimalLoadout - end, - - ---@deprecated use xPlayer.name instead - getName = function(xPlayer) return xPlayer.name end, - - setName = function(xPlayer, newName) - xPlayer.name = newName - Player(xPlayer.source).state:set('name', xPlayer.name, true) - end, - - setAccountMoney = function(xPlayer, accountName, money, reason) - reason = reason or 'unknown' - if not tonumber(money) then - return error(('Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1'):format(accountName, xPlayer.playerId, money)) - end - if money >= 0 then - local account = xPlayer.getAccount(accountName) - - if account then - money = account.round and ESX.Math.Round(money) or money - xPlayer.accounts[account.index].money = money - - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:setAccountMoney', xPlayer.source, accountName, money, reason) - else - error(('Tried To Set Invalid Account ^5%s^1 For Player ^5%s^1!'):format(accountName, xPlayer.playerId)) - end - else - error(('Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1'):format(accountName, xPlayer.playerId, money)) - end - end, - - addAccountMoney = function(xPlayer, accountName, money, reason) - reason = reason or 'Unknown' - if not tonumber(money) then - error(('Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1'):format(accountName, xPlayer.playerId, money)) - return - end - if money > 0 then - local account = xPlayer.getAccount(accountName) - if account then - money = account.round and ESX.Math.Round(money) or money - xPlayer.accounts[account.index].money = xPlayer.accounts[account.index].money + money - - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:addAccountMoney', xPlayer.source, accountName, money, reason) - else - error(('Tried To Set Add To Invalid Account ^5%s^1 For Player ^5%s^1!'):format(accountName, xPlayer.playerId)) - end - else - error(('Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1'):format(accountName, xPlayer.playerId, money)) - end - end, - - removeAccountMoney = function(xPlayer, accountName, money, reason) - reason = reason or 'Unknown' - if not tonumber(money) then - error(('Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1'):format(accountName, xPlayer.playerId, money)) - return - end - if money > 0 then - local account = xPlayer.getAccount(accountName) - - if account then - money = account.round and ESX.Math.Round(money) or money - if xPlayer.accounts[account.index].money - money > xPlayer.accounts[account.index].money then - error(('Tried To Underflow Account ^5%s^1 For Player ^5%s^1!'):format(accountName, xPlayer.playerId)) - return - end - xPlayer.accounts[account.index].money = xPlayer.accounts[account.index].money - money - - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:removeAccountMoney', xPlayer.source, accountName, money, reason) - else - error(('Tried To Set Add To Invalid Account ^5%s^1 For Player ^5%s^1!'):format(accountName, xPlayer.playerId)) - end - else - error(('Tried To Set Account ^5%s^1 For Player ^5%s^1 To An Invalid Number -> ^5%s^1'):format(accountName, xPlayer.playerId, money)) - end - end, - - getInventoryItem = function(xPlayer, itemName) - for _, v in ipairs(xPlayer.inventory) do - if v.name == itemName then - return v - end - end - return nil - end, - - addInventoryItem = function(xPlayer, itemName, count) - local item = xPlayer.getInventoryItem(itemName) - - if item then - count = ESX.Math.Round(count) - item.count = item.count + count - xPlayer.weight = xPlayer.weight + (item.weight * count) - - TriggerEvent('esx:onAddInventoryItem', xPlayer.source, item.name, item.count) - xPlayer.triggerEvent('esx:addInventoryItem', item.name, item.count) - end - end, - - removeInventoryItem = function(xPlayer, itemName, count) - local item = xPlayer.getInventoryItem(itemName) - - if item then - count = ESX.Math.Round(count) - if count > 0 then - local newCount = item.count - count - - if newCount >= 0 then - item.count = newCount - xPlayer.weight = xPlayer.weight - (item.weight * count) - - TriggerEvent('esx:onRemoveInventoryItem', xPlayer.source, item.name, item.count) - xPlayer.triggerEvent('esx:removeInventoryItem', item.name, item.count) - end - else - error(('Player ID:^5%s Tried remove a Invalid count -> %s of %s'):format(xPlayer.playerId, count, itemName)) - end - end - end, - - setInventoryItem = function(xPlayer, itemName, count) - local item = xPlayer.getInventoryItem(itemName) - - if item and count >= 0 then - count = ESX.Math.Round(count) - - if count > item.count then - xPlayer.addInventoryItem(item.name, count - item.count) - else - xPlayer.removeInventoryItem(item.name, item.count - count) - end - end - end, - - ---@deprecated use xPlayer.weight instead - getWeight = function(xPlayer) return xPlayer.weight end, - - ---@deprecated use xPlayer.source instead - getSource = function(xPlayer) return xPlayer.source end, - - ---@deprecated use xPlayer.source instead - getPlayerId = function(xPlayer) return xPlayer.source end, - - ---@deprecated use xPlayer.maxWeight instead - getMaxWeight = function(xPlayer) return xPlayer.maxWeight end, - - canCarryItem = function(xPlayer, itemName, count) - if ESX.Items[itemName] then - local currentWeight, itemWeight = xPlayer.weight, ESX.Items[itemName].weight - local newWeight = currentWeight + (itemWeight * count) - - return newWeight <= xPlayer.maxWeight - else - print(('[^3WARNING^7] Item ^5\'%s\'^7 was used but does not exist!'):format(itemName)) - return false - end - end, - - canSwapItem = function(xPlayer, firstItem, firstItemCount, testItem, testItemCount) - local firstItemObject = xPlayer.getInventoryItem(firstItem) - if not firstItemObject then - return false - end - local testItemObject = xPlayer.getInventoryItem(testItem) - if not testItemObject then - return false - end - - if firstItemObject.count >= firstItemCount then - local weightWithoutFirstItem = ESX.Math.Round(xPlayer.weight - (firstItemObject.weight * firstItemCount)) - local weightWithTestItem = ESX.Math.Round(weightWithoutFirstItem + (testItemObject.weight * testItemCount)) - - return weightWithTestItem <= xPlayer.maxWeight - end - - return false - end, - - setMaxWeight = function(xPlayer, newWeight) - xPlayer.maxWeight = newWeight - - xPlayer.triggerEvent('esx:setMaxWeight', xPlayer.maxWeight) - end, - - setJob = function(xPlayer, newJob, grade, onDuty) - grade = tostring(grade) - local lastJob = xPlayer.job - - if not ESX.DoesJobExist(newJob, grade) then - return print(('[ESX] [^3WARNING^7] Ignoring invalid ^5.setJob()^7 usage for ID: ^5%s^7, Job: ^5%s^7'):format(xPlayer.source, newJob)) - end - - if newJob == 'unemployed' then - onDuty = false - end - - if type(onDuty) ~= 'boolean' then - onDuty = Config.DefaultJobDuty - end - - local jobObject, gradeObject = ESX.Jobs[newJob], ESX.Jobs[newJob].grades[grade] - - xPlayer.job = { - id = jobObject.id, - name = jobObject.name, - label = jobObject.label, - onDuty = onDuty, - - grade = tonumber(grade) or 0, - grade_name = gradeObject.name, - grade_label = gradeObject.label, - grade_salary = gradeObject.salary, - - skin_male = gradeObject.skin_male and json.decode(gradeObject.skin_male) or {}, - skin_female = gradeObject.skin_female and json.decode(gradeObject.skin_female) or {}, - } - - xPlayer.metadata.jobDuty = onDuty - TriggerEvent('esx:setJob', xPlayer.source, xPlayer.job, lastJob) - xPlayer.triggerEvent('esx:setJob', xPlayer.job, lastJob) - Player(xPlayer.source).state:set('job', xPlayer.job, true) - end, - - addWeapon = function(xPlayer, weaponName, ammo) - if not xPlayer.hasWeapon(weaponName) then - local weaponLabel = ESX.GetWeaponLabel(weaponName) - - table.insert(xPlayer.loadout, { - name = weaponName, - ammo = ammo, - label = weaponLabel, - components = {}, - tintIndex = 0, - }) - - GiveWeaponToPed(GetPlayerPed(xPlayer.source), joaat(weaponName), ammo, false, false) - xPlayer.triggerEvent('esx:addInventoryItem', weaponLabel, false, true) - xPlayer.triggerEvent('esx:addLoadoutItem', weaponName, weaponLabel, ammo) - end - end, - - addWeaponComponent = function(xPlayer, weaponName, weaponComponent) - local loadoutNum , weapon = xPlayer.getWeapon(weaponName) - - if weapon then - local component = ESX.GetWeaponComponent(weaponName, weaponComponent) - - if component then - if not xPlayer.hasWeaponComponent(weaponName, weaponComponent) then - xPlayer.loadout[loadoutNum].components[#xPlayer.loadout[loadoutNum].components + 1] = weaponComponent - local componentHash = ESX.GetWeaponComponent(weaponName, weaponComponent).hash - GiveWeaponComponentToPed(GetPlayerPed(xPlayer.source), joaat(weaponName), componentHash) - xPlayer.triggerEvent('esx:addInventoryItem', component.label, false, true) - end - end - end - end, - - addWeaponAmmo = function(xPlayer, weaponName, ammoCount) - local _, weapon = xPlayer.getWeapon(weaponName) - - if weapon then - weapon.ammo = weapon.ammo + ammoCount - SetPedAmmo(GetPlayerPed(xPlayer.source), joaat(weaponName), weapon.ammo) - end - end, - - updateWeaponAmmo = function(xPlayer, weaponName, ammoCount) - local _, weapon = xPlayer.getWeapon(weaponName) - - if not weapon then - return - end - - weapon.ammo = ammoCount - - if weapon.ammo <= 0 then - local _, weaponConfig = ESX.GetWeapon(weaponName) - if weaponConfig.throwable then - xPlayer.removeWeapon(weaponName) - end - end - end, - - setWeaponTint = function(xPlayer, weaponName, weaponTintIndex) - local loadoutNum , weapon = xPlayer.getWeapon(weaponName) - - if weapon then - local _, weaponObject = ESX.GetWeapon(weaponName) - - if weaponObject.tints and weaponObject.tints[weaponTintIndex] then - xPlayer.loadout[loadoutNum].tintIndex = weaponTintIndex - xPlayer.triggerEvent('esx:setWeaponTint', weaponName, weaponTintIndex) - xPlayer.triggerEvent('esx:addInventoryItem', weaponObject.tints[weaponTintIndex], false, true) - end - end - end, - - getWeaponTint = function(xPlayer, weaponName) - local _, weapon = xPlayer.getWeapon(weaponName) - - if weapon then - return weapon.tintIndex - end - - return 0 - end, - - removeWeapon = function(xPlayer, weaponName) - local weaponLabel, playerPed = nil, GetPlayerPed(xPlayer.source) - - if not playerPed then - return error('xPlayer.removeWeapon ^5invalid^1 player ped!') - end - - for k, v in ipairs(xPlayer.loadout) do - if v.name == weaponName then - weaponLabel = v.label - - for _, v2 in ipairs(v.components) do - xPlayer.removeWeaponComponent(weaponName, v2) - end - - local weaponHash = joaat(v.name) - RemoveWeaponFromPed(playerPed, weaponHash) - SetPedAmmo(playerPed, weaponHash, 0) - - table.remove(xPlayer.loadout, k) - break - end - end - - if weaponLabel then - xPlayer.triggerEvent('esx:removeInventoryItem', weaponLabel, false, true) - xPlayer.triggerEvent('esx:removeLoadoutItem', weaponName, weaponLabel) - end - end, - - removeWeaponComponent = function(xPlayer, weaponName, weaponComponent) - local loadoutNum , weapon = xPlayer.getWeapon(weaponName) - - if weapon then - local component = ESX.GetWeaponComponent(weaponName, weaponComponent) - - if component then - if xPlayer.hasWeaponComponent(weaponName, weaponComponent) then - for k, v in ipairs(xPlayer.loadout[loadoutNum].components) do - if v == weaponComponent then - table.remove(xPlayer.loadout[loadoutNum].components, k) - break - end - end - - xPlayer.triggerEvent('esx:removeWeaponComponent', weaponName, weaponComponent) - xPlayer.triggerEvent('esx:removeInventoryItem', component.label, false, true) - end - end - end - end, - - removeWeaponAmmo = function(xPlayer, weaponName, ammoCount) - local _, weapon = xPlayer.getWeapon(weaponName) - - if weapon then - weapon.ammo = weapon.ammo - ammoCount - SetPedAmmo(GetPlayerPed(xPlayer.source), joaat(weaponName), weapon.ammo) - end - end, - - hasWeaponComponent = function(xPlayer, weaponName, weaponComponent) - local _, weapon = xPlayer.getWeapon(weaponName) - - if weapon then - for _, v in ipairs(weapon.components) do - if v == weaponComponent then - return true - end - end - - return false - end - - return false - end, - - hasWeapon = function(xPlayer, weaponName) - for _, v in ipairs(xPlayer.loadout) do - if v.name == weaponName then - return true - end - end - - return false - end, - - hasItem = function(xPlayer, item) - for _, v in ipairs(xPlayer.inventory) do - if v.name == item and v.count >= 1 then - return v, v.count - end - end - - return false - end, - - getWeapon = function(xPlayer, weaponName) - for k, v in ipairs(xPlayer.loadout) do - if v.name == weaponName then - return k, v - end - end - - return nil, nil - end, - - showNotification = function(xPlayer, msg, notifyType, length, title, position) - xPlayer.triggerEvent('esx:showNotification', msg, notifyType, length, title, position) - end, - - showAdvancedNotification = function(xPlayer, sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) - xPlayer.triggerEvent('esx:showAdvancedNotification', sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) - end, - - showHelpNotification = function(xPlayer, msg, thisFrame, beep, duration) - xPlayer.triggerEvent('esx:showHelpNotification', msg, thisFrame, beep, duration) - end, - - getMeta = function(xPlayer, index, subIndex) - if not index then - return xPlayer.metadata - end - - if type(index) ~= 'string' then - error('xPlayer.getMeta ^5index^1 should be ^5string^1!') - return - end - - local metaData = xPlayer.metadata[index] - if metaData == nil then - return Config.EnableDebug and error(('xPlayer.getMeta ^5%s^1 not exist!'):format(index)) or nil - end - - if subIndex and type(metaData) == 'table' then - local _type = type(subIndex) - - if _type == 'string' then - local value = metaData[subIndex] - return value - end - - if _type == 'table' then - local returnValues = {} - - for i = 1, #subIndex do - local key = subIndex[i] - if type(key) == 'string' then - returnValues[key] = xPlayer.getMeta(index, key) - else - error(('xPlayer.getMeta subIndex should be ^5string^1 or ^5table^1! that contains ^5string^1, received ^5%s^1!, skipping...'):format(type(key))) - end - end - - return returnValues - end - - error(('xPlayer.getMeta subIndex should be ^5string^1 or ^5table^1!, received ^5%s^1!'):format(_type)) - return - end - - return metaData - end, - - setMeta = function(xPlayer, index, value, subValue) - if not index then - return error('xPlayer.setMeta ^5index^1 is Missing!') - end - - if type(index) ~= 'string' then - return error('xPlayer.setMeta ^5index^1 should be ^5string^1!') - end - - if value == nil then - return error('xPlayer.setMeta value is missing!') - end - - local _type = type(value) - - if not subValue then - if _type ~= 'number' and _type ~= 'string' and _type ~= 'table' then - return error(('xPlayer.setMeta ^5%s^1 should be ^5number^1 or ^5string^1 or ^5table^1!'):format(value)) - end - - xPlayer.metadata[index] = value - else - if _type ~= 'string' then - return error(('xPlayer.setMeta ^5value^1 should be ^5string^1 as a subIndex!'):format(value)) - end - - if not xPlayer.metadata[index] or type(xPlayer.metadata[index]) ~= 'table' then - xPlayer.metadata[index] = {} - end - - xPlayer.metadata[index] = type(xPlayer.metadata[index]) == 'table' and xPlayer.metadata[index] or {} - xPlayer.metadata[index][value] = subValue - end - xPlayer.triggerEvent('esx:updatePlayerData', 'metadata', xPlayer.metadata) - end, - - clearMeta = function(xPlayer, index, subValues) - if not index then - return error('xPlayer.clearMeta ^5index^1 is Missing!') - end - - if type(index) ~= 'string' then - return error('xPlayer.clearMeta ^5index^1 should be ^5string^1!') - end - - local metaData = xPlayer.metadata[index] - if metaData == nil then - if Config.EnableDebug then - error(('xPlayer.clearMeta ^5%s^1 does not exist!'):format(index)) - end - - return - end - - if not subValues then - -- If no subValues is provided, we will clear the entire value in the metaData table - xPlayer.metadata[index] = nil - elseif type(subValues) == 'string' then - -- If subValues is a string, we will clear the specific subValue within the table - if type(metaData) == 'table' then - metaData[subValues] = nil - else - return error(('xPlayer.clearMeta ^5%s^1 is not a table! Cannot clear subValue ^5%s^1.'):format(index, subValues)) - end - elseif type(subValues) == 'table' then - -- If subValues is a table, we will clear multiple subValues within the table - for i = 1, #subValues do - local subValue = subValues[i] - if type(subValue) == 'string' then - if type(metaData) == 'table' then - metaData[subValue] = nil - else - error(('xPlayer.clearMeta ^5%s^1 is not a table! Cannot clear subValue ^5%s^1.'):format(index, subValue)) - end - else - error(('xPlayer.clearMeta subValues should contain ^5string^1, received ^5%s^1, skipping...'):format(type(subValue))) - end - end - else - return error(('xPlayer.clearMeta ^5subValues^1 should be ^5string^1 or ^5table^1, received ^5%s^1!'):format(type(subValues))) - end - xPlayer.triggerEvent('esx:updatePlayerData', 'metadata', xPlayer.metadata) - end, - - executeCommand = function(xPlayer, command) - if type(command) ~= 'string' then - error('xPlayer.executeCommand must be of type string!') - return - end - - xPlayer.triggerEvent('esx:executeCommand', command) - end, - - syncInventory = Config.CustomInventory == 'ox' and function(xPlayer, weight, maxWeight, items, money) - xPlayer.weight, xPlayer.maxWeight = weight, maxWeight - xPlayer.inventory = items - - if not money then return end - for accountName, amount in pairs(money) do - local account = xPlayer.getAccount(accountName) - - if account and ESX.Math.Round(account.money) ~= amount then - account.money = amount - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:setAccountMoney', xPlayer.source, accountName, amount, 'Sync account with item') - end - end - end or nil -}, { - __index = function(self, k) - if otherResCheck() and (k ~= 'addHook' or k ~= 'removeHook') then return end - - return rawget(self, k) - end, - __newindex = function(self, k, v) - if otherResCheck() then return end - - rawset(self, k, v) - end, - __call = function(self, xPlayer, functionName) - if otherResCheck() then return end - - return function(...) - if self.hooks('functionName', functionName) then - for i=1, #self.hooks do - if self.hooks[i].functionName == functionName then - local _, result = pcall(self.hooks[i].functionReference, xPlayer, ...) - if (self.hooks[i].isJustAddition and result == false) or not self.hooks[i].isJustAddition then return end - end - end - end - - return self[functionName](xPlayer, ...) - end - end -}) - -ESX.XPlayerClass = setmetatable({ - addHook = function(functionName, isJustAddition, functionReference) - return exports.es_extended:addXPlayerHook(functionName, isJustAddition, functionReference) - end, - removeHook = function(hookId) - return exports.es_extended:removeXPlayerHook(hookId) - end -}, { - __newindex = nil -}) - --- ox_inventory's overrides - -do - if Config.CustomInventory == 'ox' then - local resName , path = 'es_extended', 'server/classes/xPlayer/oxInv_overrides.lua' - load(LoadResourceFile(resName, path), ('@@%s/%s'):format(resName, path))() --[[@as fun(xPlayer: xPlayer) ]] - end -end - --- Exports - -exports('RunStaticPlayerMethod', function(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('addXPlayerHook', function(functionName, isJustAddition, functionReference) - return XPlayerClass:addHook(functionName, isJustAddition, functionReference) -end) - -exports('removeXPlayerHook', function(hookId) - return XPlayerClass:removeHook(hookId) -end) \ No newline at end of file diff --git a/[core]/es_extended/server/classes/xPlayer/oxInv_overrides.lua b/[core]/es_extended/server/classes/xPlayer/oxInv_overrides.lua deleted file mode 100644 index c390f53d..00000000 --- a/[core]/es_extended/server/classes/xPlayer/oxInv_overrides.lua +++ /dev/null @@ -1,132 +0,0 @@ -local Inventory - --- Event Handlers - -AddEventHandler('ox_inventory:loadInventory', function(module) - Inventory = module -end) - --- Main Code - -do - IsAuthorized[#IsAuthorized+1] = true - - XPlayerClass.getInventory = function(xPlayer, minimal) - if not minimal then - return xPlayer.inventory - end - - local minimalInventory = {} - - for i=1, #xPlayer.inventory do - local curr = xPlayer.inventory[i] - if curr.count and curr.count > 0 then - minimalInventory[#minimalInventory + 1] = { - name = curr.name, - count = curr.count, - slot = i, - } - end - end - - return minimalInventory - end - - XPlayerClass.getLoadout = function() - return {} - end - - XPlayerClass.setAccountMoney = function(xPlayer, accountName, money, reason) - reason = reason or 'unknown' - if money < 0 then return end - local account = xPlayer.getAccount(accountName) - - if not account then return end - - money = account.round and ESX.Math.Round(money) or money - xPlayer.accounts[account.index].money = money - - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:setAccountMoney', xPlayer.source, accountName, money, reason) - if Inventory.accounts[accountName] then - Inventory.SetItem(xPlayer.source, accountName, money) - end - end - - XPlayerClass.addAccountMoney = function(xPlayer, accountName, money, reason) - reason = reason or 'unknown' - if money < 1 then return end - - local account = xPlayer.getAccount(accountName) - if not account then return end - - money = account.round and ESX.Math.Round(money) or money - xPlayer.accounts[account.index].money = xPlayer.accounts[account.index].money + money - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:addAccountMoney', xPlayer.source, accountName, money, reason) - if Inventory.accounts[accountName] then - Inventory.AddItem(xPlayer.source, accountName, money) - end - end - - XPlayerClass.removeAccountMoney = function(xPlayer, accountName, money, reason) - reason = reason or 'unknown' - if money < 1 then return end - - local account = xPlayer.getAccount(accountName) - if not account then return end - - money = account.round and ESX.Math.Round(money) or money - xPlayer.accounts[account.index].money = xPlayer.accounts[account.index].money - money - xPlayer.triggerEvent('esx:setAccountMoney', account) - TriggerEvent('esx:removeAccountMoney', xPlayer.source, accountName, money, reason) - if Inventory.accounts[accountName] then - Inventory.RemoveItem(xPlayer.source, accountName, money) - end - end - - XPlayerClass.getInventoryItem = function(xPlayer, name, metadata) - return Inventory.GetItem(xPlayer.source, name, metadata) - end - - do - local modules = { 'add', 'remove', 'set' } - for i=1, #modules do - local curr = modules[i] - XPlayerClass[('%sInventoryItem'):format(curr)] = function(xPlayer, ...) ---@diagnostic disable-line: param-type-mismatch - local params = { ... } - - if i ~= 3 then params[2] = params[2] or 1 end - - return Inventory[('%s%sItem'):format(curr:sub(1,1):upper(), curr:sub(2, #curr))](xPlayer.source, table.unpack(params)) - end - end - end - - XPlayerClass.canCarryItem = function(xPlayer, name, count, metadata) - return Inventory.CanCarryItem(xPlayer.source, name, count, metadata) - end - - XPlayerClass.canSwapItem = function(xPlayer, firstItem, firstItemCount, testItem, testItemCount) - return Inventory.CanSwapItem(xPlayer.source, firstItem, firstItemCount, testItem, testItemCount) - end - - XPlayerClass.setMaxWeight = function(xPlayer, newWeight) - xPlayer.maxWeight = newWeight - xPlayer.triggerEvent('esx:setMaxWeight', xPlayer.maxWeight) - return Inventory.SetMaxWeight(xPlayer.source, newWeight) - end - - do - local modules = { 'addWeapon', 'addWeaponComponent', 'addWeaponAmmo', 'addWeaponAmmo', 'updateWeaponAmmo', 'setWeaponTint', 'getWeaponTint', 'removeWeapon', 'removeWeaponComponent', 'removeWeaponAmmo', 'getWeapon', 'hasWeaponComponent', 'hasWeapon' } - for i=1, #modules do - XPlayerClass[modules[i]] = i <= (#modules - 2) and function()end or function() return false end - end - end - - XPlayerClass.hasItem = function(xPlayer, name, metadata) - return Inventory.GetItem(xPlayer.source, name, metadata) - end - - table.remove(IsAuthorized, #IsAuthorized) -end \ No newline at end of file diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index 9d8d0053..7ab5f9b4 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -562,7 +562,7 @@ function ESX.RefreshJobs() if not Jobs then -- Fallback data, if no jobs exist - ESX.Jobs["unemployed"] = { name = "unemployed", label = "Unemployed", whitelisted = false, grades = { ["0"] = { grade = 0, name = "unemployed", label = "Unemployed", salary = 200, skin_male = '[]', skin_female = '[]' } } } + ESX.Jobs["unemployed"] = { name = "unemployed", label = "Unemployed", type = "civ", whitelisted = false, grades = { ["0"] = { grade = 0, name = "unemployed", label = "Unemployed", salary = 200, skin_male = {}, skin_female = {} } } } else ESX.Jobs = Jobs end @@ -704,7 +704,7 @@ if not Config.CustomInventory then for itemName, _ in pairs(minimalInv) do if not ESX.Items[itemName] then - xPlayer.setInventoryItem(itemName --[[@as string]], 0) + xPlayer.setInventoryItem(itemName, 0) minimalInv[itemName] = nil end end @@ -714,7 +714,7 @@ if not Config.CustomInventory then for itemName, itemData in pairs(ESX.Items) do xPlayer.inventory[playerInvIndex] = { name = itemName, - count = minimalInv[itemName].count or 0, + count = minimalInv[itemName] or 0, label = itemData.label, weight = itemData.weight, usable = Core.UsableItemsCallbacks[itemName] ~= nil, diff --git a/[core]/es_extended/server/main.lua b/[core]/es_extended/server/main.lua index 89b12502..96c5cc64 100644 --- a/[core]/es_extended/server/main.lua +++ b/[core]/es_extended/server/main.lua @@ -40,7 +40,7 @@ local function createESXPlayer(identifier, playerId, data) end MySQL.prepare(newPlayer, parameters, function() - LoadESXPlayer(identifier, playerId, true) + loadESXPlayer(identifier, playerId, true) end) end @@ -61,7 +61,7 @@ local function onPlayerJoined(playerId) else local result = MySQL.scalar.await("SELECT 1 FROM users WHERE identifier = ?", { identifier }) if result then - LoadESXPlayer(identifier, playerId, false) + loadESXPlayer(identifier, playerId, false) else createESXPlayer(identifier, playerId) end @@ -119,7 +119,7 @@ if Config.Multichar then if data then createESXPlayer(identifier, src, data) else - LoadESXPlayer(identifier, src, false) + loadESXPlayer(identifier, src, false) end end end) @@ -183,57 +183,76 @@ if not Config.Multichar then end) end -function LoadESXPlayer(identifier, playerId, isNew) - local result = MySQL.prepare.await(loadPlayer, { identifier }) - result.accounts = type(result.accounts) == 'string' and json.decode(result.accounts) or {} - - local job = ESX.Jobs[result.job] or ESX.Jobs['unemployed'] - local grade = job.grades[tostring(result.job_grade)] or job.grades['0'] - local userData = { - steamName = GetPlayerName(playerId), - name = ('%s %s'):format(result.firstname, result.lastname), - identifier = identifier, +function loadESXPlayer(identifier, playerId, isNew) + local userData = { accounts = {}, inventory = {}, loadout = {}, - ssn = result.ssn, weight = 0, - job = { - id = job.id, - name = job.name, - label = job.label, - grade = tonumber(grade), - grade_name = grade.name, - grade_label = grade.label, - grade_salary = grade.salary, - skin_male = json.decode(grade.skin_male or '[]'), - skin_female = json.decode(grade.skin_female or '[]'), - }, - group = result.group == 'superadmin' and 'admin' or result.group and result.group or 'user', - coords = json.decode(result.position) or Config.DefaultSpawns[ESX.Math.Random(1,#Config.DefaultSpawns)], - skin = (result.skin and result.skin ~= '') and json.decode(result.skin) or { sex = 0 }, - metadata = (result.metadata and result.metadata ~= '') and json.decode(result.metadata) or {} + name = GetPlayerName(playerId), + identifier = identifier, + firstName = "John", + lastName = "Doe", + dateofbirth = "01/01/2000", + height = 120, + dead = false, } - for k,v in pairs(Config.Accounts) do - v.round = v.round or v.round == nil - local index = #userData.accounts + 1 + local result = MySQL.prepare.await(loadPlayer, { identifier }) + + -- Accounts + local accounts = result.accounts + accounts = (accounts and accounts ~= "") and json.decode(accounts) or {} + + for account, data in pairs(Config.Accounts) do + data.round = data.round or data.round == nil + + local index = #userData.accounts + 1 userData.accounts[index] = { - name = k, - money = result.accounts[k] or Config.StartingAccountMoney[k] or 0, - label = v.label, - round = v.round, + name = account, + money = accounts[account] or Config.StartingAccountMoney[account] or 0, + label = data.label, + round = data.round, index = index, } end - if not Config.CustomInventory then - -- Inventory + -- SSN + userData.ssn = result.ssn + + -- Job + local job, grade = result.job, tostring(result.job_grade) + + if not ESX.DoesJobExist(job, grade) then + print(("[^3WARNING^7] Ignoring invalid job for ^5%s^7 [job: ^5%s^7, grade: ^5%s^7]"):format(identifier, job, grade)) + job, grade = "unemployed", "0" + end + + local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + + userData.job = { + id = jobObject.id, + name = jobObject.name, + label = jobObject.label, + type = jobObject.type, + + grade = tonumber(grade), + grade_name = gradeObject.name, + grade_label = gradeObject.label, + grade_salary = gradeObject.salary, + + skin_male = gradeObject.skin_male and json.decode(gradeObject.skin_male) or {}, + skin_female = gradeObject.skin_female and json.decode(gradeObject.skin_female) or {}, + } + + -- Inventory + if not Config.CustomInventory then + local inventory = (result.inventory and result.inventory ~= "") and json.decode(result.inventory) or {} - local inventory = (result.inventory and result.inventory ~= '') and json.decode(result.inventory) or {} for name, item in pairs(ESX.Items) do - local count = inventory[name] or 0 + local count = inventory[name] or 0 userData.weight += (count * item.weight) + userData.inventory[#userData.inventory + 1] = { name = name, count = count, @@ -244,16 +263,33 @@ function LoadESXPlayer(identifier, playerId, isNew) canRemove = item.canRemove, } end - table.sort(userData.inventory, function(a, b) return a.label < b.label end) + elseif result.inventory and result.inventory ~= "" then + userData.inventory = json.decode(result.inventory) + end - -- Loadout + -- Group + if result.group then + if result.group == "superadmin" then + userData.group = "admin" + print("[^3WARNING^7] ^5Superadmin^7 detected, setting group to ^5admin^7") + else + userData.group = result.group + end + else + userData.group = "user" + end + + -- Loadout + if not Config.CustomInventory then + if result.loadout and result.loadout ~= "" then + + local loadout = json.decode(result.loadout) + for name, weapon in pairs(loadout) do + local label = ESX.GetWeaponLabel(name) - if result.loadout and result.loadout ~= '' then - for name, weapon in pairs(json.decode(result.loadout)) do - local label = ESX.GetWeaponLabel(name) if label then userData.loadout[#userData.loadout + 1] = { name = name, @@ -265,14 +301,21 @@ function LoadESXPlayer(identifier, playerId, isNew) end end end - elseif result.inventory and result.inventory ~= '' then - userData.inventory = json.decode(result.inventory) end - -- xPlayer Creation - local xPlayer = GetXPlayer(playerId, userData) + -- Position + userData.coords = json.decode(result.position) or Config.DefaultSpawns[ESX.Math.Random(1,#Config.DefaultSpawns)] - GlobalState.playerCount += 1 + -- Skin + userData.skin = (result.skin and result.skin ~= "") and json.decode(result.skin) or { sex = userData.sex == "f" and 1 or 0 } + + -- Metadata + userData.metadata = (result.metadata and result.metadata ~= "") and json.decode(result.metadata) or {} + + -- xPlayer Creation + local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.ssn, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, GetPlayerName(playerId), userData.coords, userData.metadata) + + GlobalState["playerCount"] = GlobalState["playerCount"] + 1 ESX.Players[playerId] = xPlayer Core.playersByIdentifier[identifier] = xPlayer @@ -302,12 +345,10 @@ function LoadESXPlayer(identifier, playerId, isNew) end end + TriggerEvent("esx:playerLoaded", playerId, xPlayer, isNew) userData.money = xPlayer.getMoney() userData.maxWeight = xPlayer.getMaxWeight() userData.variables = xPlayer.variables or {} - - TriggerEvent("esx:playerLoaded", playerId, xPlayer, isNew) - xPlayer.triggerEvent("esx:registerSuggestions", Core.RegisteredCommands) xPlayer.triggerEvent("esx:playerLoaded", userData, isNew, userData.skin) if not Config.CustomInventory then @@ -316,10 +357,7 @@ function LoadESXPlayer(identifier, playerId, isNew) setPlayerInventory(playerId, xPlayer, userData.inventory, isNew) end - if not ESX.DoesJobExist(result.job.name, tostring(result.job_grade) == 'NULL' and '0' or result.job_grade) then - warn(('^7Ignoring invalid job for ^5%s^7 [job: ^5%s^7, grade: ^5%s^7]'):format(identifier, result.job, result.grade)) - end - + xPlayer.triggerEvent("esx:registerSuggestions", Core.RegisteredCommands) print(('[^2INFO^0] Player ^5"%s"^0 has connected to the server. ID: ^5%s^7'):format(xPlayer.getName(), playerId)) end diff --git a/[core]/es_extended/server/migration/main.lua b/[core]/es_extended/server/migration/main.lua index cf6e52b3..378894fd 100644 --- a/[core]/es_extended/server/migration/main.lua +++ b/[core]/es_extended/server/migration/main.lua @@ -8,7 +8,7 @@ RegisterCommand("resetmigrations", function(src) DeleteResourceKvp(("esx_migration:%s"):format(version)) end print("^2[SUCCESS]^7 Reset all migrations. This will re-run all migrations on the next server start.") -end, false) +end) local migrationsRan = 0 local restartRequired = false diff --git a/[core]/es_extended/server/modules/getXPlayer.lua b/[core]/es_extended/server/modules/getXPlayer.lua deleted file mode 100644 index a6866844..00000000 --- a/[core]/es_extended/server/modules/getXPlayer.lua +++ /dev/null @@ -1,36 +0,0 @@ ----@param playerId integer ----@param data { identifier: string, ssn: string, group: string, accounts: ESXAccount[], inventory: table, weight: number, job: ESXJob, loadout: ESXInventoryWeapon[], steamName: string, coords: vector4|{x: number, y: number, z: number, heading: number}, metadata: table } ----@return xPlayer -function GetXPlayer(playerId, data) - local xPlayer = { - playerId = playerId, - source = playerId, - variables = {}, - job = {}, - metadata = {}, - maxWeight = Config.MaxWeight, - lastPlaytime = 0, - paycheckEnabled = true, - admin = Core.IsPlayerAdmin(playerId), - state = Player(playerId).state, - license = GetPlayerIdentifierByType(tostring(playerId), 'license') - } - - for k,v in pairs(data) do - xPlayer[k] = v - end - - if type(data.metadata.jobDuty) ~= 'boolean' then - xPlayer.metadata.jobDuty = data.job.name ~= 'unemployed' and Config.DefaultJobDuty or false - end - - IsAuthorized[#IsAuthorized+1] = true - - for k,v in pairs(XPlayerClass) do - if type(v) == 'function' then - xPlayer[k] = XPlayerClass(xPlayer, k) - end - end - - return xPlayer -end \ No newline at end of file diff --git a/[core]/es_extended/shared/modules/table.lua b/[core]/es_extended/shared/modules/table.lua index a80347eb..ab4b147d 100644 --- a/[core]/es_extended/shared/modules/table.lua +++ b/[core]/es_extended/shared/modules/table.lua @@ -225,7 +225,7 @@ function ESX.Table.Sort(t, order) end ---@param t table ----@return any[] +---@return Array function ESX.Table.ToArray(t) local array = {} for _, v in pairs(t) do diff --git a/[core]/esx_notify/Notify.lua b/[core]/esx_notify/Notify.lua index 61ebe881..d690fbd6 100644 --- a/[core]/esx_notify/Notify.lua +++ b/[core]/esx_notify/Notify.lua @@ -64,26 +64,26 @@ RegisterNetEvent("ESX:Notify", Notify) if Debug then RegisterCommand("oldnotify", function() - ESX.ShowNotification('No Waypoint Set.', true, false, 140) ---@diagnostic disable-line: param-type-mismatch - end, false) + ESX.ShowNotification('No Waypoint Set.', true, false, 140) + end) RegisterCommand("notify", function() ESX.ShowNotification("You Received
1x ball!", "success", 3000) - end, false) + end) RegisterCommand("notify1", function() ESX.ShowNotification("Well ~g~Done~s~!", "success", 3000, "Achievement") - end, false) + end) RegisterCommand("notify2", function() ESX.ShowNotification("Information Received", "info", 3000, "System Info") - end, false) + end) RegisterCommand("notify3", function() ESX.ShowNotification("You Did something ~r~WRONG~s~!", "error", 3000, "Error") - end, false) + end) RegisterCommand("notify4", function() ESX.ShowNotification("You Did something ~r~WRONG~s~!", "warning", 3000, "~y~Warning~s~") - end, false) + end) end \ No newline at end of file diff --git a/[core]/skinchanger/client/main.lua b/[core]/skinchanger/client/main.lua index b386ef4b..67be80d5 100644 --- a/[core]/skinchanger/client/main.lua +++ b/[core]/skinchanger/client/main.lua @@ -278,7 +278,7 @@ exports("LoadSkin", function(skin) end) exports("GetData", function(noMax) - return SkinChanger:GetData(noMax) ---@diagnostic disable-line: redundant-return-value + return SkinChanger:GetData(noMax) end) exports("LoadClothes", function(playerSkin, clothesSkin)