Framework Integration

This section guides you through the steps to integrate the HUD script with your framework, utilizing built-in functions for seamless integration.

You can find all the functions here.

You can write whatever you want inside the functions/ folder, which contains server.lua and client.lua for both server-side and client-side configurations. The server.lua file is optional because not everyone will need it. By default, everything is set up for the ESX framework and uses legacyfuel for the vehicle fuel system. As mentioned, you can customize this setup as needed to fit your server.

PlayerData

At the top of the client.lua file, you need to define a global PlayerData object. This object is intended for storing variables about the player. It must include a seatbelt variable; otherwise, the vehicle HUD will break. You can add other variables to the object as needed.

In my case I'm also storing player's ID in it.

PlayerData = {
  seatbelt = false,
  id = 0,
}

STEP 1: Init

You need to decide when to initialize the HUD using InitHud(). In most cases, the HUD should be initialized when the player loads, but your framework might not have a playerLoaded event. If that's the case, you can initialize the HUD a few seconds after the script loads.

RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(player)
  InitHud()
end)

STEP 2: Fuel

You need to implement a function to retrieve fuel from your chosen fuel system. This function must be named exactly as specified. If you're not using a fuel system, simply add return 0 to the function to prevent breaking the vehicle HUD.

GetVehicleFuelLevel = function(vehicle)
  return exports['LegacyFuel']:GetFuel(vehicle)
end

STEP 3: Status

To ensure the status indicators work correctly, you must update them using UpdateStatus(). You have the option to listen to your status system's status update ticker or create an infinite thread to fetch player statuses at intervals of your choice (e.g., every 1, 2, 3, or 4 seconds). The frequency of updates can be tailored to your specific needs.

Each status inside the update object must be sent in the format:['status_name_you_defined_in_config'] = status_percentage

{
    ['thirst'] = 45,
    ['hunger'] = 88,
    ... And so on
}
local handleStatusTick = function(data)
  local playerPed = PlayerPedId()
  local status = {}
  for i = 1, #data, 1 do
    status[data[i].name] = data[i].percent
  end

  local maxHealth = GetEntityMaxHealth(playerPed)
  local currHealth = GetEntityHealth(playerPed)

  status['health'] = (currHealth * 100) / maxHealth
  status['armor'] = GetPedArmour(playerPed)

  UpdateStatus(status)
end
AddEventHandler('esx_status:onTick', handleStatusTick)

STEP 4: Info

This section is optional and only necessary if you have dynamic data in your info HUD (data that changes). If you're using the info HUD and have set the data with default fields that don't need to be updated, you can skip this step. The info HUD uses the UpdateInfo() to update its values. You can use this function in a thread or update it as needed. In the example case, we have a player ID, which is a static variable that doesn't need updating and should be set when the player loads. Another variable is the server player count, which changes over time, so we use a thread to keep track of the current number of players.

Each info inside the update object must be sent in the format:

['info_name_you_defined_in_config'] = "info_value"

{
    ['players'] = "82/128",
    ... And so on
}

functions/client.lua

Update thread:

InfoUpdateThread = function()
  Citizen.CreateThread(function()
    while true do
      -- If you're not using ESX, use your framework callbacks service.
      ESX.TriggerServerCallback('sx-hud:getServerData', function(serverData)
        UpdateInfo({
          ['players'] = ('%s/128'):format(serverData.players),
        })
      end)
      -- Update every 30sec so we don't spam the server that often.
      Citizen.Wait(30000)
    end
  end)
end

Starting info update thread and setting player ID:

RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(player)
  PlayerData['id'] = player.source
  InitHud()

  -- In the example case player source shouldn't change at any time after player loads
  -- So we update the player id once and we're done;
  UpdateInfo({
    ['id'] = player.source
  })
  -- Start the info update thread
  InfoUpdateThread()
end)

functions/server.lua

Create callback function to get server players count.

-- If you're not using ESX, use your framework callbacks service.
ESX.RegisterServerCallback('sx-hud:getServerData', function(source, cb)
  cb({
    players = GetNumPlayerIndices(),
  })
end)

STEP 5: Seatbelt

To make the vehicle HUD seatbelt indicator work, you need to inform the HUD when the seatbelt is on or off. This is a straightforward task: simply update the PlayerData.seatbelt variable to reflect the current seatbelt state. In my example, an event is sent from the seatbelt script whenever the seatbelt state changes. Your seatbelt system might already have this event, but under different name, or you may need to create it yourself.

local handleSeatbelt = function(state)
  PlayerData['seatbelt'] = state
end
RegisterNetEvent('sx-seatbelt:stateChanged')
AddEventHandler('sx-seatbelt:stateChanged', handleSeatbelt)

If you need to create the event to send these changes, simply locate the function or variable setter in your seatbelt script and send the event listed below with the current seatbelt state.

TriggerEvent('sx-seatbelt:stateChanged', newSeatbeltState)

DONE

Final version of the configuration should look something like this:

functions/client.lua

PlayerData = {
  seatbelt = false,
  id = 0,
}

-- STEP 1
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(player)
  PlayerData['id'] = player.source
  InitHud()

  -- In the example case player source shouldn't change at any time after he loads
  -- So we update the player id once and we're done;
  UpdateInfo({
    ['id'] = player.source
  })
  -- Start the info update thread
  InfoUpdateThread()
end)

-- STEP 2
GetVehicleFuelLevel = function(vehicle)
  return exports['LegacyFuel']:GetFuel(vehicle)
end

-- STEP 3
local handleStatusTick = function(data)
  local playerPed = PlayerPedId()
  local status = {}
  for i = 1, #data, 1 do
    status[data[i].name] = data[i].percent
  end

  local maxHealth = GetEntityMaxHealth(playerPed)
  local currHealth = GetEntityHealth(playerPed)

  status['health'] = (currHealth * 100) / maxHealth
  status['armor'] = GetPedArmour(playerPed)

  UpdateStatus(status)
end
AddEventHandler('esx_status:onTick', handleStatusTick)

-- STEP 4
InfoUpdateThread = function()
  Citizen.CreateThread(function()
    while true do
      ESX.TriggerServerCallback('sx-hud:getServerData', function(serverData)
        UpdateInfo({
          ['players'] = ('%s/128'):format(serverData.players),
        })
      end)
      Citizen.Wait(30000)
    end
  end)
end

-- STEP 5
local handleSeatbelt = function(state)
  PlayerData['seatbelt'] = state
end
RegisterNetEvent('sx-seatbelt:stateChanged')
AddEventHandler('sx-seatbelt:stateChanged', handleSeatbelt)

functions/server.lua

ESX.RegisterServerCallback('sx-hud:getServerData', function(source, cb)
  cb({
    players = GetNumPlayerIndices(),
  })
end)

Last updated