Files
esx_core/client/main.lua
T
ElPumpo f89e051756 BREAKING COMMIT - Player loading improvements (read description!)
This commit implements a new way of saving and getting player coords.

Player coords are synced with its assigned xPlayer, the syncing interval is defined in the configuration file.
Also coords wont sync if the player is too close to their previous location.

Existing servers must change their database to account for the new length of the position varchar, at 53 chars max. There's also a column default value specified in the sql file.

New xPlayer functions:
- .getCoords()
- .setCoords() (x,y,z,heading (optional) table
- .updateCoords()

The last one is used for syncing coords from client (interval). The second one will teleport the player. First one is a renamed .getLastPosition()
2020-01-12 22:13:30 +01:00

537 lines
14 KiB
Lua

local isLoadoutLoaded, isPaused, isDead, isFirstSpawn, pickups = false, false, false, true, {}
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
ESX.PlayerLoaded = true
ESX.PlayerData = xPlayer
if Config.EnableHud then
for k,v in ipairs(xPlayer.accounts) do
local accountTpl = '<div><img src="img/accounts/' .. v.name .. '.png"/>&nbsp;{{money}}</div>'
ESX.UI.HUD.RegisterElement('account_' .. v.name, k - 1, 0, accountTpl, {
money = 0
})
ESX.UI.HUD.UpdateElement('account_' .. v.name, {
money = ESX.Math.GroupDigits(v.money)
})
end
local jobTpl = '<div>{{job_label}} - {{grade_label}}</div>'
if xPlayer.job.grade_label == '' then
jobTpl = '<div>{{job_label}}</div>'
end
ESX.UI.HUD.RegisterElement('job', #xPlayer.accounts, 0, jobTpl, {
job_label = '',
grade_label = ''
})
ESX.UI.HUD.UpdateElement('job', {
job_label = xPlayer.job.label,
grade_label = xPlayer.job.grade_label
})
else
TriggerEvent('es:setMoneyDisplay', 0.0)
end
end)
RegisterNetEvent('esx:setMaxWeight')
AddEventHandler('esx:setMaxWeight', function(newMaxWeight)
ESX.PlayerData.maxWeight = newMaxWeight
end)
AddEventHandler('playerSpawned', function()
while not ESX.PlayerLoaded do
Citizen.Wait(10)
end
TriggerEvent('esx:restoreLoadout')
if isFirstSpawn then
ESX.Game.Teleport(PlayerPedId(), ESX.PlayerData.coords)
isFirstSpawn = false
end
isLoadoutLoaded, isDead = true, false
if Config.EnablePvP then
SetCanAttackFriendly(PlayerPedId(), true, false)
NetworkSetFriendlyFireOption(true)
end
end)
AddEventHandler('esx:onPlayerDeath', function() isDead = true end)
AddEventHandler('skinchanger:loadDefaultModel', function() isLoadoutLoaded = false end)
AddEventHandler('skinchanger:modelLoaded', function()
while not ESX.PlayerLoaded do
Citizen.Wait(1)
end
TriggerEvent('esx:restoreLoadout')
end)
AddEventHandler('esx:restoreLoadout', function()
local playerPed = PlayerPedId()
local ammoTypes = {}
RemoveAllPedWeapons(playerPed, true)
for k,v in ipairs(ESX.PlayerData.loadout) do
local weaponName = v.name
local weaponHash = GetHashKey(weaponName)
GiveWeaponToPed(playerPed, weaponHash, 0, false, false)
local ammoType = GetPedAmmoTypeFromWeapon(playerPed, weaponHash)
for k2,v2 in ipairs(v.components) do
local componentHash = ESX.GetWeaponComponent(weaponName, v2).hash
GiveWeaponComponentToPed(playerPed, weaponHash, componentHash)
end
if not ammoTypes[ammoType] then
AddAmmoToPed(playerPed, weaponHash, v.ammo)
ammoTypes[ammoType] = true
end
end
isLoadoutLoaded = true
end)
RegisterNetEvent('esx:setAccountMoney')
AddEventHandler('esx:setAccountMoney', function(account)
for k,v in ipairs(ESX.PlayerData.accounts) do
if v.name == account.name then
ESX.PlayerData.accounts[k] = account
break
end
end
if Config.EnableHud then
ESX.UI.HUD.UpdateElement('account_' .. account.name, {
money = ESX.Math.GroupDigits(account.money)
})
end
end)
RegisterNetEvent('es:activateMoney')
AddEventHandler('es:activateMoney', function(money)
ESX.PlayerData.money = money
end)
RegisterNetEvent('esx:addInventoryItem')
AddEventHandler('esx:addInventoryItem', function(item, count)
for k,v in ipairs(ESX.PlayerData.inventory) do
if v.name == item.name then
ESX.PlayerData.inventory[k] = item
break
end
end
ESX.UI.ShowInventoryItemNotification(true, item, count)
if ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then
ESX.ShowInventory()
end
end)
RegisterNetEvent('esx:removeInventoryItem')
AddEventHandler('esx:removeInventoryItem', function(item, count)
for k,v in ipairs(ESX.PlayerData.inventory) do
if v.name == item.name then
ESX.PlayerData.inventory[k] = item
break
end
end
ESX.UI.ShowInventoryItemNotification(false, item, count)
if ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then
ESX.ShowInventory()
end
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
ESX.PlayerData.job = job
end)
RegisterNetEvent('esx:addWeapon')
AddEventHandler('esx:addWeapon', function(weaponName, ammo)
local playerPed = PlayerPedId()
local weaponHash = GetHashKey(weaponName)
GiveWeaponToPed(playerPed, weaponHash, ammo, false, false)
end)
RegisterNetEvent('esx:addWeaponComponent')
AddEventHandler('esx:addWeaponComponent', function(weaponName, weaponComponent)
local playerPed = PlayerPedId()
local weaponHash = GetHashKey(weaponName)
local componentHash = ESX.GetWeaponComponent(weaponName, weaponComponent).hash
GiveWeaponComponentToPed(playerPed, weaponHash, componentHash)
end)
RegisterNetEvent('esx:setWeaponAmmo')
AddEventHandler('esx:setWeaponAmmo', function(weaponName, weaponAmmo)
local playerPed = PlayerPedId()
local weaponHash = GetHashKey(weaponName)
SetPedAmmo(playerPed, weaponHash, weaponAmmo)
end)
RegisterNetEvent('esx:removeWeapon')
AddEventHandler('esx:removeWeapon', function(weaponName, ammo)
local playerPed = PlayerPedId()
local weaponHash = GetHashKey(weaponName)
RemoveWeaponFromPed(playerPed, weaponHash)
if ammo then
local pedAmmo = GetAmmoInPedWeapon(playerPed, weaponHash)
local finalAmmo = math.floor(pedAmmo - ammo)
SetPedAmmo(playerPed, weaponHash, finalAmmo)
else
SetPedAmmo(playerPed, weaponHash, 0) -- remove leftover ammo
end
end)
RegisterNetEvent('esx:removeWeaponComponent')
AddEventHandler('esx:removeWeaponComponent', function(weaponName, weaponComponent)
local playerPed = PlayerPedId()
local weaponHash = GetHashKey(weaponName)
local componentHash = ESX.GetWeaponComponent(weaponName, weaponComponent).hash
RemoveWeaponComponentFromPed(playerPed, weaponHash, componentHash)
end)
RegisterNetEvent('esx:teleport')
AddEventHandler('esx:teleport', function(coords)
local playerPed = PlayerPedId()
-- ensure decmial number
coords.x = coords.x + 0.0
coords.y = coords.y + 0.0
coords.z = coords.z + 0.0
ESX.Game.Teleport(playerPed, coords)
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
if Config.EnableHud then
ESX.UI.HUD.UpdateElement('job', {
job_label = job.label,
grade_label = job.grade_label
})
end
end)
RegisterNetEvent('esx:spawnVehicle')
AddEventHandler('esx:spawnVehicle', function(vehicle)
local model = (type(vehicle) == 'number' and vehicle or GetHashKey(vehicle))
if IsModelInCdimage(model) then
local playerPed = PlayerPedId()
local coords = GetEntityCoords(playerPed)
ESX.Game.SpawnVehicle(model, coords, 90.0, function(vehicle)
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
end)
else
TriggerEvent('chat:addMessage', { args = { '^1SYSTEM', 'Invalid vehicle model.' } })
end
end)
RegisterNetEvent('esx:createPickup')
AddEventHandler('esx:createPickup', function(pickupId, label, playerId, type, name, components)
local playerPed = GetPlayerPed(GetPlayerFromServerId(playerId))
local entityCoords, forward, pickupObject = GetEntityCoords(playerPed), GetEntityForwardVector(playerPed)
local objectCoords = (entityCoords + forward * 1.0)
if type == 'item_weapon' then
ESX.Streaming.RequestWeaponAsset(GetHashKey(name))
pickupObject = CreateWeaponObject(GetHashKey(name), 50, objectCoords, true, 1.0, 0)
for k,v in ipairs(components) do
local component = ESX.GetWeaponComponent(name, v)
GiveWeaponComponentToWeaponObject(pickupObject, component.hash)
end
else
ESX.Game.SpawnLocalObject('prop_money_bag_01', objectCoords, function(obj)
pickupObject = obj
end)
while not pickupObject do
Citizen.Wait(10)
end
end
SetEntityAsMissionEntity(pickupObject, true, false)
PlaceObjectOnGroundProperly(pickupObject)
FreezeEntityPosition(pickupObject, true)
pickups[pickupId] = {
id = pickupId,
obj = pickupObject,
label = label,
inRange = false,
coords = objectCoords
}
end)
RegisterNetEvent('esx:createMissingPickups')
AddEventHandler('esx:createMissingPickups', function(missingPickups)
for pickupId,pickup in pairs(missingPickups) do
local pickupObject = nil
if pickup.type == 'item_weapon' then
ESX.Streaming.RequestWeaponAsset(GetHashKey(pickup.name))
pickupObject = CreateWeaponObject(GetHashKey(pickup.name), 50, pickup.coords.x, pickup.coords.y, pickup.coords.z, true, 1.0, 0)
for k,componentName in ipairs(pickup.components) do
local component = ESX.GetWeaponComponent(pickup.name, componentName)
GiveWeaponComponentToWeaponObject(pickupObject, component.hash)
end
else
ESX.Game.SpawnLocalObject('prop_money_bag_01', pickup.coords, function(obj)
pickupObject = obj
end)
while not pickupObject do
Citizen.Wait(10)
end
end
SetEntityAsMissionEntity(pickupObject, true, false)
PlaceObjectOnGroundProperly(pickupObject)
FreezeEntityPosition(pickupObject, true)
pickups[pickupId] = {
id = pickupId,
obj = pickupObject,
label = pickup.label,
inRange = false,
coords = vector3(pickup.coords.x, pickup.coords.y, pickup.coords.z)
}
end
end)
RegisterNetEvent('esx:removePickup')
AddEventHandler('esx:removePickup', function(id)
ESX.Game.DeleteObject(pickups[id].obj)
pickups[id] = nil
end)
RegisterNetEvent('esx:deleteVehicle')
AddEventHandler('esx:deleteVehicle', function(radius)
local playerPed = PlayerPedId()
if radius and tonumber(radius) then
radius = tonumber(radius) + 0.01
local vehicles = ESX.Game.GetVehiclesInArea(GetEntityCoords(playerPed), radius)
for k,entity in ipairs(vehicles) do
local attempt = 0
while not NetworkHasControlOfEntity(entity) and attempt < 100 and DoesEntityExist(entity) do
Citizen.Wait(100)
NetworkRequestControlOfEntity(entity)
attempt = attempt + 1
end
if DoesEntityExist(entity) and NetworkHasControlOfEntity(entity) then
ESX.Game.DeleteVehicle(entity)
end
end
else
local vehicle, attempt = ESX.Game.GetVehicleInDirection(), 0
if IsPedInAnyVehicle(playerPed, true) then
vehicle = GetVehiclePedIsIn(playerPed, false)
end
while not NetworkHasControlOfEntity(vehicle) and attempt < 100 and DoesEntityExist(vehicle) do
Citizen.Wait(100)
NetworkRequestControlOfEntity(vehicle)
attempt = attempt + 1
end
if DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle) then
ESX.Game.DeleteVehicle(vehicle)
end
end
end)
-- Pause menu disables HUD display
if Config.EnableHud then
Citizen.CreateThread(function()
while true do
Citizen.Wait(300)
if IsPauseMenuActive() and not isPaused then
isPaused = true
TriggerEvent('es:setMoneyDisplay', 0.0)
ESX.UI.HUD.SetDisplay(0.0)
elseif not IsPauseMenuActive() and isPaused then
isPaused = false
TriggerEvent('es:setMoneyDisplay', 1.0)
ESX.UI.HUD.SetDisplay(1.0)
end
end
end)
end
-- Save loadout
Citizen.CreateThread(function()
local lastLoadout = {}
while true do
Citizen.Wait(5000)
local playerPed, loadout, loadoutChanged = PlayerPedId(), {}, false
for k,v in ipairs(Config.Weapons) do
local weaponName = v.name
local weaponHash = GetHashKey(weaponName)
local weaponComponents = {}
if HasPedGotWeapon(playerPed, weaponHash, false) and weaponName ~= 'WEAPON_UNARMED' then
local ammo = GetAmmoInPedWeapon(playerPed, weaponHash)
for k2,v2 in ipairs(v.components) do
if HasPedGotWeaponComponent(playerPed, weaponHash, v2.hash) then
table.insert(weaponComponents, v2.name)
end
end
if not lastLoadout[weaponName] or lastLoadout[weaponName] ~= ammo then
loadoutChanged = true
end
lastLoadout[weaponName] = ammo
table.insert(loadout, {
name = weaponName,
ammo = ammo,
label = v.label,
components = weaponComponents
})
else
if lastLoadout[weaponName] then
loadoutChanged = true
end
lastLoadout[weaponName] = nil
end
end
if loadoutChanged and isLoadoutLoaded then
ESX.PlayerData.loadout = loadout
end
end
end)
-- Menu interactions
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if IsControlJustReleased(0, 289) and IsInputDisabled(0) and not isDead and not ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then
ESX.ShowInventory()
end
end
end)
-- Disable wanted level
if Config.DisableWantedLevel then
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
local playerId = PlayerId()
if GetPlayerWantedLevel(playerId) ~= 0 then
SetPlayerWantedLevel(playerId, 0, false)
SetPlayerWantedLevelNow(playerId, false)
end
end
end)
end
-- Pickups
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
local playerPed = PlayerPedId()
local playerCoords, letSleep = GetEntityCoords(playerPed), true
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer()
for k,v in pairs(pickups) do
local distance = #(playerCoords - v.coords)
if distance < 5 then
local label = v.label
letSleep = false
if distance < 1 then
if IsControlJustReleased(0, 38) then
if IsPedOnFoot(playerPed) and (closestDistance == -1 or closestDistance > 3) and not v.inRange then
v.inRange = true
local dict, anim = 'weapons@first_person@aim_rng@generic@projectile@sticky_bomb@', 'plant_floor'
ESX.Streaming.RequestAnimDict(dict)
TaskPlayAnim(playerPed, dict, anim, 8.0, 1.0, 1000, 16, 0.0, false, false, false)
Citizen.Wait(1000)
TriggerServerEvent('esx:onPickup', v.id)
PlaySoundFrontend(-1, 'PICK_UP', 'HUD_FRONTEND_DEFAULT_SOUNDSET', false)
end
end
label = ('%s~n~%s'):format(label, _U('threw_pickup_prompt'))
end
ESX.Game.Utils.DrawText3D({
x = v.coords.x,
y = v.coords.y,
z = v.coords.z + 0.25
}, label, 1.2, 1)
elseif v.inRange then
v.inRange = false
end
end
if letSleep then
Citizen.Wait(500)
end
end
end)
-- Update current player coords
Citizen.CreateThread(function()
local previousCoords = vector3(0, 0, 0)
-- wait for player to restore coords
while not isLoadoutLoaded do
Citizen.Wait(1000)
end
while true do
Citizen.Wait(Config.CoordsSyncInterval)
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local distance = #(playerCoords - previousCoords)
if distance > 10 then
previousCoords = playerCoords
local playerHeading = ESX.Math.Round(GetEntityHeading(playerPed), 1)
local formattedCoords = {x = ESX.Math.Round(playerCoords.x, 1), y = ESX.Math.Round(playerCoords.y, 1), z = ESX.Math.Round(playerCoords.z, 1), heading = playerHeading}
TriggerServerEvent('esx:updateCoords', formattedCoords)
end
end
end)