diff --git a/resources/[ERS]/night_discordapi/.fxap b/resources/[ERS]/night_discordapi/.fxap index e6ec958fd..55800ac69 100644 Binary files a/resources/[ERS]/night_discordapi/.fxap and b/resources/[ERS]/night_discordapi/.fxap differ diff --git a/resources/[ERS]/night_discordapi/README.md b/resources/[ERS]/night_discordapi/README.md new file mode 100644 index 000000000..60cf8f175 --- /dev/null +++ b/resources/[ERS]/night_discordapi/README.md @@ -0,0 +1,385 @@ +# Night Discord API + +A comprehensive FiveM resource for integrating Discord functionality into your server. This resource provides easy access to Discord user data, guild membership, roles, and more through a simple API. + +## ๐Ÿ“‹ Table of Contents + +- [Features](#features) +- [Installation](#installation) +- [Configuration](#configuration) +- [Exports](#exports) +- [Usage Examples](#usage-examples) +- [Support](#support) + +## โœจ Features + +- **Discord User Management**: Check if users are members of specific Discord servers +- **Role Verification**: Verify user roles across multiple Discord servers +- **User Data Retrieval**: Get Discord user information, avatars, and member details +- **Guild Information**: Retrieve Discord server/guild information +- **Caching System**: Built-in caching for improved performance +- **Rate Limiting**: Automatic Discord API rate limit handling +- **Multi-Guild Support**: Support for multiple Discord servers +- **Custom Role Mapping**: Map Discord role IDs to custom names + +## ๐Ÿš€ Installation + +1. **Download the resource** and place it in your server's resources folder +2. **Configure the resource** by editing `config/config.lua` +3. **Add to your server.cfg somewhere ON TOP as one of the first starting resources**: + ``` + ensure night_discordapi + ``` +4. **Restart your server** + +## โš™๏ธ Configuration + +Edit `config/config.lua` to configure the resource: + +**Note**: This resource requires a Discord bot to function. You can either use the default bot provided by Nights Software (https://discord.com/oauth2/authorize?client_id=956690799385522237&permissions=1024&scope=bot) or set up your own Discord bot following the documentation. + +```lua +Config = { + -- Discord Bot Token (leave empty to use the provided default FiveM DC API bot, or add your own bot token) + Discord_Bot_Token = "", + + -- Discord Guild/Server Configuration + Discord_Guild_Names = { + ["YOUR_GUILD_ID"] = "Your Guild Name", + ["ANOTHER_GUILD_ID"] = "Another Guild Name", + }, + + -- Discord Role Mapping + Discord_Role_Names = { + ["ROLE_ID"] = "Role_Name", + ["ANOTHER_ROLE_ID"] = "Another_Role", + }, + + -- Logging Level (0 = INFO/ERROR/WARN only, 1+ = includes DEBUG) + Discord_API_Log_Level = 1, +} +``` + +### Configuration Details + +- **Discord_Bot_Token**: Your Discord bot token (optional - uses default if empty) +- **Discord_Guild_Names**: Map Discord server IDs to readable names +- **Discord_Role_Names**: Map Discord role IDs to custom role names +- **Discord_API_Log_Level**: Control logging verbosity + +## ๐Ÿ“š Exports + +### Guild Membership Functions + +#### `IsUserPartOfThisGuild(src, force, guildName)` +Check if a player is a member of a specific Discord server. + +**Parameters:** +- `src` (string): Player source ID +- `force` (boolean): Force refresh cache (required) +- `guildName` (string): Name of the Discord server (as defined in config) (required) + +**Returns:** `boolean` - true if user is a member, false if not, nil on error + +**Example:** +```lua +local isMember = exports['night_discordapi']:IsUserPartOfThisGuild(source, false, "Your Guild Name") +if isMember then + print("Player is a member of the Discord server!") +end +``` + +#### `IsUserPartOfAnyOfTheseGuilds(src, force, guildNames)` +Check if a player is a member of any of the specified Discord servers. + +**Parameters:** +- `src` (string): Player source ID +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `boolean` - true if user is a member of any server, false if not, nil on error + +**Example:** +```lua +local guildNames = {"Guild 1", "Guild 2", "Guild 3"} +local isMember = exports['night_discordapi']:IsUserPartOfAnyOfTheseGuilds(source, false, guildNames) +if isMember then + print("Player is a member of at least one Discord server!") +end +``` + +#### `IsUserPartOfAllOfTheseGuilds(src, force, guildNames)` +Check if a player is a member of all specified Discord servers. + +**Parameters:** +- `src` (string): Player source ID +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `boolean` - true if user is a member of all servers, false if not, nil on error + +**Example:** +```lua +local guildNames = {"Guild 1", "Guild 2"} +local isMember = exports['night_discordapi']:IsUserPartOfAllOfTheseGuilds(source, false, guildNames) +if isMember then + print("Player is a member of all Discord servers!") +end +``` + +### User Data Functions + +#### `GetDiscordUser(src, force)` +Get Discord user information for a player. + +**Parameters:** +- `src` (string): Player source ID +- `force` (boolean): Force refresh cache (optional) + +**Returns:** `table` - User data containing id, name, avatar, or nil on error + +**Example:** +```lua +local userData = exports['night_discordapi']:GetDiscordUser(source, false) +if userData then + print("Discord ID: " .. userData.id) + print("Username: " .. userData.name) + print("Avatar: " .. (userData.avatar or "No avatar")) +end +``` + +#### `GetDiscordMember(src, force, guildNames)` +Get Discord member information for a player in specific servers. + +**Parameters:** +- `src` (string): Player source ID +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `table` - Member data containing id, name, nick, avatar, discriminator, roles, or nil on error + +**Example:** +```lua +local memberData = exports['night_discordapi']:GetDiscordMember(source, false, {"Your Guild Name"}) +if memberData then + print("Member ID: " .. memberData.id) + print("Nickname: " .. (memberData.nick or "No nickname")) + print("Roles: " .. table.concat(memberData.roles, ", ")) +end +``` + +### Role Functions + +#### `GetDiscordMemberRoles(src, force, guildNames)` +Get all Discord roles for a player across specified servers. + +**Parameters:** +- `src` (string): Player source ID +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `table` - Array of role names, or nil on error + +**Example:** +```lua +local roles = exports['night_discordapi']:GetDiscordMemberRoles(source, false, {"Guild 1", "Guild 2"}) +if roles then + for _, role in ipairs(roles) do + print("Role: " .. role) + end +end +``` + +#### `IsMemberPartOfThisRole(src, roleName, force, guildNames)` +Check if a player has a specific Discord role. + +**Parameters:** +- `src` (string): Player source ID +- `roleName` (string): Name of the role to check +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `boolean` - true if user has the role, false if not, nil on error + +**Example:** +```lua +local hasRole = exports['night_discordapi']:IsMemberPartOfThisRole(source, "Admin", false, {"Your Guild"}) +if hasRole then + print("Player has Admin role!") +end +``` + +#### `IsMemberPartOfAnyOfTheseRoles(src, roleNames, force, guildNames)` +Check if a player has any of the specified Discord roles. + +**Parameters:** +- `src` (string): Player source ID +- `roleNames` (table): Array of role names to check +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `boolean` - true if user has any of the roles, false if not, nil on error + +**Example:** +```lua +local roleNames = {"Admin", "Moderator", "VIP"} +local hasRole = exports['night_discordapi']:IsMemberPartOfAnyOfTheseRoles(source, roleNames, false, {"Your Guild"}) +if hasRole then + print("Player has at least one of the specified roles!") +end +``` + +#### `IsMemberPartOfAllOfTheseRoles(src, roleNames, force, guildNames)` +Check if a player has all of the specified Discord roles. + +**Parameters:** +- `src` (string): Player source ID +- `roleNames` (table): Array of role names to check +- `force` (boolean): Force refresh cache (optional) +- `guildNames` (table): Array of Discord server names (optional) + +**Returns:** `boolean` - true if user has all roles, false if not, nil on error + +**Example:** +```lua +local roleNames = {"Admin", "Moderator"} +local hasAllRoles = exports['night_discordapi']:IsMemberPartOfAllOfTheseRoles(source, roleNames, false, {"Your Guild"}) +if hasAllRoles then + print("Player has all specified roles!") +end +``` + +### Guild Information Functions + +#### `GetDiscordGuild(guildName, force)` +Get information about a Discord server/guild. + +**Parameters:** +- `guildName` (string): Name of the Discord server (as defined in config) +- `force` (boolean): Force refresh cache (optional) + +**Returns:** `table` - Guild data containing id, name, icon, ownerid, roles, or nil on error + +**Example:** +```lua +local guildData = exports['night_discordapi']:GetDiscordGuild("Your Guild Name", false) +if guildData then + print("Guild ID: " .. guildData.id) + print("Guild Name: " .. guildData.name) + print("Owner ID: " .. guildData.ownerid) +end +``` + +## ๐Ÿ’ก Usage Examples + +### Basic Permission System +```lua +-- Check if player has admin role +local hasAdmin = exports['night_discordapi']:IsMemberPartOfThisRole(source, "Admin", false, {"Your Guild"}) +if hasAdmin then + -- Give admin permissions + TriggerClientEvent('chat:addMessage', source, { + color = {255, 0, 0}, + multiline = true, + args = {"System", "You have admin permissions!"} + }) +end +``` + +### Multi-Server Role Check +```lua +-- Check if player has role in any of multiple servers +local guildNames = {"Main Server", "Staff Server", "VIP Server"} +local roleNames = {"Admin", "Moderator", "VIP"} +local hasPermission = exports['night_discordapi']:IsMemberPartOfAnyOfTheseRoles(source, roleNames, false, guildNames) + +if hasPermission then + -- Example: Grant access to restricted area + TriggerClientEvent('restrictedArea:grantAccess', source) +end +``` + +### User Information Display +```lua +-- Get and display user information +local userData = exports['night_discordapi']:GetDiscordUser(source, false) +if userData then + TriggerClientEvent('chat:addMessage', -1, { + color = {0, 255, 0}, + multiline = true, + args = {"Discord", userData.name .. " joined the server!"} + }) +end +``` + +### Guild Membership Verification +```lua +-- Verify player is member of specific guild +local isMember = exports['night_discordapi']:IsUserPartOfThisGuild(source, false, "Whitelisted Guild") +if not isMember then + DropPlayer(source, "You must be a member of our Discord server to join this server.") +end +``` + +### Advanced Role System +```lua +-- Check multiple roles across multiple servers +local guildNames = {"Police Department", "Fire Department", "EMS"} +local requiredRoles = {"Officer", "Firefighter", "Paramedic"} + +local hasRequiredRole = exports['night_discordapi']:IsMemberPartOfAnyOfTheseRoles(source, requiredRoles, false, guildNames) +if hasRequiredRole then + -- Allow access to emergency services + TriggerClientEvent('emergency:grantAccess', source) +else + TriggerClientEvent('chat:addMessage', source, { + color = {255, 0, 0}, + multiline = true, + args = {"System", "You need to be verified in our Discord server to access emergency services."} + }) +end +``` + +## ๐Ÿ”ง Advanced Configuration + +### Custom Role Mapping +```lua +Discord_Role_Names = { + ["123456789012345678"] = "Admin", + ["987654321098765432"] = "Moderator", + ["555666777888999000"] = "VIP", + -- Add more role mappings as needed +} +``` + +### Multiple Guild Support +```lua +Discord_Guild_Names = { + ["123456789012345678"] = "Main Server", + ["987654321098765432"] = "Staff Server", + ["555666777888999000"] = "VIP Server", + -- Add more guilds as needed +} +``` + +## ๐Ÿ› ๏ธ Troubleshooting + +### Common Issues + +1. **Bot Token Invalid**: Ensure your Discord bot token is correct and the bot has proper permissions +2. **Guild Not Found**: Make sure the bot is invited to all configured Discord servers +3. **Role Not Found**: Verify role IDs are correct and the bot has permission to view roles +4. **Rate Limiting**: The resource handles Discord API rate limits automatically + +### Debug Mode +Enable debug logging by setting `Discord_API_Log_Level = 1` in your config to see detailed API request information. + +## ๐Ÿ“ž Support + +- **Documentation**: https://docs.nights-software.com/resources/discordAPI/ +- **Discord Support**: https://discord.nights-software.com/ +- **Installation Video**: Available on the documentation page + +## ๐Ÿ“„ License + +This resource is developed and maintained by Nights Software. \ No newline at end of file diff --git a/resources/[ERS]/night_discordapi/config.lua b/resources/[ERS]/night_discordapi/config/config.lua similarity index 62% rename from resources/[ERS]/night_discordapi/config.lua rename to resources/[ERS]/night_discordapi/config/config.lua index 1f657cfe7..f84515a76 100644 --- a/resources/[ERS]/night_discordapi/config.lua +++ b/resources/[ERS]/night_discordapi/config/config.lua @@ -5,20 +5,22 @@ ------------------------------------------------------------------------------------ -- Please read the documentation and/or watch the installation video tutorial (available on the documentation page) before asking us for support. + -- Documentation Page: https://docs.nights-software.com/resources/discordAPI/ (<- INSTALLATION GUIDE HERE) -- Support Discord: https://discord.nights-software.com/ Config = { - -- No own bot? Leave it as default and invite ours ยป https://discord.com/oauth2/authorize?client_id=956690799385522237&permissions=1024&scope=bot - -- If you do have a bot: define your BOT token below, inbetween the quotation marks: "bot_token", + -- No own bot? Leave `Discord_Bot_Token = "",` as it is and invite ours ยป https://discord.com/oauth2/authorize?client_id=956690799385522237&permissions=1024&scope=bot + -- If you do have a bot: define your BOT token below, inbetween the quotation marks: "your_bot_token_here", Discord_Bot_Token = "NzUxOTY4NTY3MzA5NzYyNjgw.GzVJ9D.kAxZs0UBN-XxcSJPBRqo6zrp1L_KsjoBHibYYE", - Discord_Guild_Names = { -- Add your Discord Servers/Guilds by their ID here, when fetching something with this resource, we try and get as much information as possible from all your guilds - ["361895986198609920"] = "Elite Groupe", -- Your primary server/guild ID (legacy scripts will get information regarding this guild) + Discord_Guild_Names = { + ["361895986198609920"] = "[Elite Gaming RP]", -- Your primary server/guild ID (legacy scripts will get information regarding this guild) + -- ["1001055923912653544"] = "My Community Discord", -- Add another guild. Make sure to invite the bot into this guild. }, - Discord_Role_Names = { -- Add Discord roles by their role ID here, name them how you want but make sure to use the same name in other configs of our resources. + Discord_Role_Names = { -- Add Discord roles by their role ID here, name them how you want but make sure to MATCH the NAMES in other configs of our resources. -- Example: ["361899298209923075"] = "EG|Owner", - ["789553875152535593"] = "EG | Development Team", + ["671141073728307228"] = "EG | Development Team", ["650653280275267591"] = "EG | Head of Staff", ["556158473981788176"] = "EG | Sr. Admin", ["635155687688634399"] = "EG | Admin", @@ -27,8 +29,6 @@ Config = { ["789551229549281331"] = "EG | Sr. Staff", ["608583076037001225"] = "EG | Staff", ["538822780662054963"] = "EG | Helper", - ["586249238623551528"] = "EG | Staff Team", - ["1231114889234219089"] = "Sheriff", ["807381510026035240"] = "Dispatcher", ["807381507622305852"] = "FiveM First Responder ๐Ÿšจ", ["807381508859887667"] = "CHP", @@ -38,7 +38,5 @@ Config = { ["876585455615889450"] = "Civilian II", ["468677647228363421"] = "Banned", }, - Discord_API_Cooldown = 2, -- Number of seconds between each API request. At least 2 is recommended. - Discord_API_Log_Level = 3, -- 0 = Disabled, 1 = Errors only, 2 = Errors and warnings, 3 = All messages. - Discord_API_Log_SameMessageCooldown = 5 -- Number of seconds between API request errors with the same message. + Discord_API_Log_Level = 0, -- Level 0 - Only shows INFO, ERROR and WARN messages | Any higher level will include DEBUG messages } diff --git a/resources/[ERS]/night_discordapi/fxmanifest.lua b/resources/[ERS]/night_discordapi/fxmanifest.lua index c6e82d62f..fd7abc6f1 100644 --- a/resources/[ERS]/night_discordapi/fxmanifest.lua +++ b/resources/[ERS]/night_discordapi/fxmanifest.lua @@ -4,12 +4,15 @@ games {'gta5'} author 'Nights Software' description 'API to fetch data from Discord' -version '2.0.6' +version '2.1.1' lua54 'yes' server_only 'yes' -server_scripts {'config.lua', 'server.lua'} +server_scripts { + 'config/config.lua', + 'server/*.lua' +} server_exports { 'IsUserPartOfThisGuild', @@ -21,9 +24,9 @@ server_exports { 'IsMemberPartOfThisRole', 'IsMemberPartOfAnyOfTheseRoles', 'IsMemberPartOfAllOfTheseRoles', - 'GetDiscordGuild' + 'GetDiscordGuild', + 'GetCacheStats' } -escrow_ignore {'config.lua'} - +escrow_ignore {'config/config.lua'} dependency '/assetpacks' \ No newline at end of file diff --git a/resources/[ERS]/night_discordapi/server/api.lua b/resources/[ERS]/night_discordapi/server/api.lua new file mode 100644 index 000000000..8eb8dca2c Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/api.lua differ diff --git a/resources/[ERS]/night_discordapi/server/cache.lua b/resources/[ERS]/night_discordapi/server/cache.lua new file mode 100644 index 000000000..5eec18511 Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/cache.lua differ diff --git a/resources/[ERS]/night_discordapi/server/functions.lua b/resources/[ERS]/night_discordapi/server/functions.lua new file mode 100644 index 000000000..d1d2182aa Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/functions.lua differ diff --git a/resources/[ERS]/night_discordapi/server/logs.lua b/resources/[ERS]/night_discordapi/server/logs.lua new file mode 100644 index 000000000..5ca042681 Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/logs.lua differ diff --git a/resources/[ERS]/night_discordapi/server/ratelimits.lua b/resources/[ERS]/night_discordapi/server/ratelimits.lua new file mode 100644 index 000000000..441f73610 Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/ratelimits.lua differ diff --git a/resources/[ERS]/night_discordapi/server/server.lua b/resources/[ERS]/night_discordapi/server/server.lua new file mode 100644 index 000000000..f72b09c3e Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/server.lua differ diff --git a/resources/[ERS]/night_discordapi/server/utils.lua b/resources/[ERS]/night_discordapi/server/utils.lua new file mode 100644 index 000000000..b79707644 Binary files /dev/null and b/resources/[ERS]/night_discordapi/server/utils.lua differ diff --git a/resources/[ERS]/night_ers/config/config.lua b/resources/[ERS]/night_ers/config/config.lua index 91c3a101a..28940bbc0 100644 --- a/resources/[ERS]/night_ers/config/config.lua +++ b/resources/[ERS]/night_ers/config/config.lua @@ -37,7 +37,7 @@ Config = { }, Enable_Night_Subtitles = false, -- Optional PAID (Included with ERS): https://store.nights-software.com/package/6043540 (Enables good looking subtitles instead of FiveM native mission text) Enable_Nearest_Postal = true, -- Optional FREE: https://docs.nights-software.com/resources/nightShifts/#installing-nearest-postal-optional (client/c_functions.lua for GetPostal()) - Enable_Discord_Webhooks = false, -- Set your webhook URL in server/s_functions.lua. + Enable_Discord_Webhooks = true, -- Set your webhook URL in server/s_functions.lua. --====================== DISCORD RICH PRESENCE ======================-- @@ -61,7 +61,7 @@ Config = { ["tow"] = "Tow", }, RichPresenceButton = { -- Your Discord rich presence buttons - up to 2 buttons. - [0] = { enabled = true, label = "Join Server", url = "fivem://connect/YOURSERVERHASH" }, + [0] = { enabled = true, label = "Join Server", url = "https://elite-gaming.gg" }, } }, @@ -73,7 +73,7 @@ Config = { IgnoreUnitRequirement = false, -- true = Any unit can receive callouts for any service. | false = Callouts are offered by service type (Police, fire, ambulance, tow). DisplayUnitWaypoints = true, -- true = Display unit waypoints on screen. | false = Do not display unit waypoints on screen. (enabled is higher resmon) - Enable_Night_DiscordApi_Permissions = false, -- server/s_functions.lua + Enable_Night_DiscordApi_Permissions = true, -- server/s_functions.lua Enable_Ace_Permissions = false, -- server/s_functions.lua Enable_ESX_Permissions = { Check_By_Job = false, -- server/s_functions.lua diff --git a/resources/[ERS]/night_shifts/config/config.lua b/resources/[ERS]/night_shifts/config/config.lua index 086574473..8554eb271 100644 --- a/resources/[ERS]/night_shifts/config/config.lua +++ b/resources/[ERS]/night_shifts/config/config.lua @@ -31,7 +31,7 @@ Config = { Enable_Discord_API = true, -- You need the discord API for this script, otherwise it will not work https://store.nights-software.com/package/5035729 [FREE] Included in the Tebex package. Enable_Nearest_Postal = true, -- Nearest-postal integration, if false it will always return "Unknown" on postals. (CFX Post: https://forum.cfx.re/t/release-nearest-postal-script/293511) Edit getPostal(x,y) in c_functions.lua if you desire to integrate your own postal system. - Enable_MDT_Battery_System = false, -- Set to false to disable the battery system, if disabled it'll always stay 100%. Charging can be done in vehicles and interiors + Enable_MDT_Battery_System = true, -- Set to false to disable the battery system, if disabled it'll always stay 100%. Charging can be done in vehicles and interiors DefaultSoundVolume = 0.15, -- Used for notifications. Higher than 0.5 will set it to 0.25, limited to protect ears Enable_Discord_Webhooks = false, -- Set your webhook URL in s_functions.lua, edit your preferences for these messages in c_functions.lua and s_functions.lua Enable_Blips = true, -- Allow this system to add blips for backup requests, panic buttons, sighting reports, ANPR hits etc.