From f84b7031bd5de8afa74912cf04a9eba47e93564b Mon Sep 17 00:00:00 2001 From: Kasey FItton Date: Fri, 8 Nov 2024 05:50:29 +0000 Subject: [PATCH] feat(es_extended): Discord Rich Presence Support --- .../client/modules/adjustments.lua | 71 +++++++++++++++++++ [core]/es_extended/fxmanifest.lua | 1 + [core]/es_extended/server/main.lua | 6 ++ .../es_extended/shared/config/adjustments.lua | 24 +++++++ 4 files changed, 102 insertions(+) diff --git a/[core]/es_extended/client/modules/adjustments.lua b/[core]/es_extended/client/modules/adjustments.lua index 29c8adf7..da32add5 100644 --- a/[core]/es_extended/client/modules/adjustments.lua +++ b/[core]/es_extended/client/modules/adjustments.lua @@ -138,6 +138,76 @@ function Adjustments:LicensePlates() SetDefaultVehicleNumberPlateTextPattern(-1, Config.CustomAIPlates) end +local placeHolders = { + server_name = function() + return GetConvar("sv_projectName", "ESX-Framework") + end, + server_endpoint = function() + return GetCurrentServerEndpoint() or "localhost:30120" + end, + server_players = function() + return GlobalState.PlayerCount + end, + server_maxplayers = function() + return GetConvarInt("sv_maxClients", 48) + end, + player_name = function() + return GetPlayerName(ESX.playerId) + end, + player_rp_name = function() + return ESX.PlayerData.name or "John Doe" + end, + player_id = function() + return ESX.serverId + end, + player_street = function() + if not ESX.PlayerData.ped then return "Unknown" end + + local playerCoords = GetEntityCoords(ESX.PlayerData.ped) + local streetHash = GetStreetNameAtCoord(playerCoords.x, playerCoords.y, playerCoords.z) + + return GetStreetNameFromHashKey(streetHash) or "Unknown" + end, +} + +function Adjustments:PresencePlaceholders() + local presence = Config.DiscordActivity.presence + + for placeholder, cb in pairs(placeHolders) do + local success, result = pcall(cb) + + if not success then + error(("Failed to execute presence placeholder: ^5%s^7"):format(placeholder)) + error(result) + return "Unknown" + end + + presence = presence:gsub(("{%s}"):format(placeholder), result) + end + + return presence +end + +function Adjustments:DiscordPresence() + if Config.DiscordActivity.appId ~= 0 then + CreateThread(function() + while true do + SetDiscordAppId(Config.DiscordActivity.appId) + SetDiscordRichPresenceAsset(Config.DiscordActivity.assetName) + SetDiscordRichPresenceAssetText(Config.DiscordActivity.assetText) + + for i = 1, #Config.DiscordActivity.buttons do + local button = Config.DiscordActivity.buttons[i] + SetDiscordRichPresenceAction(i - 1, button.label, button.url) + end + + SetRichPresence(self:PresencePlaceholders()) + Wait(Config.DiscordActivity.refresh) + end + end) + end +end + function Adjustments:Load() self:RemoveHudComponents() self:DisableAimAssist() @@ -149,4 +219,5 @@ function Adjustments:Load() self:DispatchServices() self:NPCScenarios() self:LicensePlates() + self:DiscordPresence() end diff --git a/[core]/es_extended/fxmanifest.lua b/[core]/es_extended/fxmanifest.lua index f3e2af0a..40cdf646 100644 --- a/[core]/es_extended/fxmanifest.lua +++ b/[core]/es_extended/fxmanifest.lua @@ -44,6 +44,7 @@ client_scripts { 'client/functions.lua', 'client/wrapper.lua', 'client/modules/callback.lua', + 'client/modules/adjustments.lua', 'client/main.lua', diff --git a/[core]/es_extended/server/main.lua b/[core]/es_extended/server/main.lua index 2be61a05..5d349e1e 100644 --- a/[core]/es_extended/server/main.lua +++ b/[core]/es_extended/server/main.lua @@ -257,6 +257,8 @@ function loadESXPlayer(identifier, playerId, isNew) -- xPlayer Creation local xPlayer = CreateExtendedPlayer(playerId, identifier, 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 @@ -319,9 +321,12 @@ AddEventHandler("playerDropped", function(reason) local job = xPlayer.getJob().name local currentJob = ESX.JobsPlayerCount[job] ESX.JobsPlayerCount[job] = ((currentJob and currentJob > 0) and currentJob or 1) - 1 + GlobalState[("%s:count"):format(job)] = ESX.JobsPlayerCount[job] Core.playersByIdentifier[xPlayer.identifier] = nil + Core.SavePlayer(xPlayer, function() + GlobalState["playerCount"] = GlobalState["playerCount"] - 1 ESX.Players[playerId] = nil end) end @@ -354,6 +359,7 @@ AddEventHandler("esx:playerLogout", function(playerId, cb) Core.playersByIdentifier[xPlayer.identifier] = nil Core.SavePlayer(xPlayer, function() + GlobalState["playerCount"] = GlobalState["playerCount"] - 1 ESX.Players[playerId] = nil if cb then cb() diff --git a/[core]/es_extended/shared/config/adjustments.lua b/[core]/es_extended/shared/config/adjustments.lua index cf5b8584..5cb45fea 100644 --- a/[core]/es_extended/shared/config/adjustments.lua +++ b/[core]/es_extended/shared/config/adjustments.lua @@ -43,3 +43,27 @@ Config.RemoveHudComponents = { -- A string shorter than 8 characters will be padded on the right. Config.CustomAIPlates = "........" -- Custom plates for AI vehicles +--[[ + PlaceHolders: + {server_name} - Server Display Name + {server_endpoint} - Server IP:Server Port + {server_players} - Current Player Count + {server_maxplayers} - Max Player Count + + {player_name} - Player Name + {player_rp_name} - Player RP Name + {player_id} - Player ID + {player_street} - Player Street Name +]] + +Config.DiscordActivity = { + appId = 0, -- Discord Application ID, + assetName = "LargeIcon", --image name for the "large" icon. + assetText = "{server_name}", -- Text to display on the asset + buttons = { + { label = "Join Server", url = "fivem://connect/{server_endpoint}" }, + { label = "Discord", url = "https://discord.esx-framework.org" }, + }, + presence = "{player_name} [{player_id}] | {server_players}/{server_maxplayers}", + refresh = 1 * 60 * 1000, -- 1 minute +}