[Release] FiveM To Discord

This bot is a real hard finger, and works perfectly.

Or a possibility for us to create such things.

If you are capable of scripting something yourself, yes.

Otherwise, probably not


Yes if I just have a start. lol :smiley:

You can find some very helpful tutorials at #development:tutorials
Also these links may come in handy:

FiveM Wiki
FiveM Natives reference
FiveM Docs
GTAForums

Also check the resources of other ppl and how they did certain things, that helped me a lot when I started :slight_smile:

2 Likes

There is. Just copy my code and you should be fine. This will send all the special commands to a separate channel.

Note: This is my first try to understand and edit lua. I could have made some mistakes but it works.

Config.lua

DiscordWebhookSystemInfos = 'WEBHOOK_LINK_HERE'
DiscordWebhookKillinglogs = 'WEBHOOK_LINK_HERE'
DiscordWebhookChat = 'WEBHOOK_LINK_HERE'
DiscordWebhookDispatch = 'WEBHOOK_LINK_HERE'

SystemAvatar = 'https://wiki.fivem.net/w/images/d/db/FiveM-Wiki.png'

UserAvatar = 'https://i.imgur.com/KIcqSYs.png'

SystemName = 'SYSTEM'


--[[ Special Commands formatting
		 *YOUR_TEXT*			--> Make Text Italics in Discord
		**YOUR_TEXT**			--> Make Text Bold in Discord
	   ***YOUR_TEXT***			--> Make Text Italics & Bold in Discord
		__YOUR_TEXT__			--> Underline Text in Discord
	   __*YOUR_TEXT*__			--> Underline Text and make it Italics in Discord
	  __**YOUR_TEXT**__			--> Underline Text and make it Bold in Discord
	 __***YOUR_TEXT***__		--> Underline Text and make it Italics & Bold in Discord
		~~YOUR_TEXT~~			--> Strikethrough Text in Discord
]]
-- Use 'USERNAME_NEEDED_HERE' without the quotes if you need a Users Name in a special command
-- Use 'USERID_NEEDED_HERE' without the quotes if you need a Users ID in a special command


-- These Special Commands will be printed differently in Discord, depending on what you set it to
SpecialCommands = {
				   {'/911', '__**[911]**__:  Dispatch to civilian channel!'},
				  }

						
-- These Blacklisted Commands will not be printed in Discord
BlacklistedCommands = {
					   '/fix',
					   '/revive',
					  }


server.lua

-- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA!
-- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA!
-- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA! -- JUST EDIT THE CONFIG.LUA!

-- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE!
-- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE!
-- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE!
-- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE!
-- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE!
-- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE! -- DO NOT EDIT THESE!

-- Error Check
if DiscordWebhookSystemInfos == nil and DiscordWebhookKillinglogs == nil and DiscordWebhookChat == nil and DiscordWebhookDisp[atch == nil then
	local Content = LoadResourceFile(GetCurrentResourceName(), 'config.lua')
	Content = load(Content)
	Content()
end
if DiscordWebhookSystemInfos == 'WEBHOOK_LINK_HERE' then
	print('\n\nERROR\n' .. GetCurrentResourceName() .. ': Please add your "System Infos" Webhook\n\n')
else
	PerformHttpRequest(DiscordWebhookSystemInfos, function(Error, Content, Head)
		if Content == '{"code": 50027, "message": "Invalid Webhook Token"}' then
			print('\n\nERROR\n' .. GetCurrentResourceName() .. ': "System Infos" Webhook non-existing!\n\n')
		end
	end)
end
if DiscordWebhookKillinglogs == 'WEBHOOK_LINK_HERE' then
	print('\n\nERROR\n' .. GetCurrentResourceName() .. ': Please add your "Killing Log" Webhook\n\n')
else
	PerformHttpRequest(DiscordWebhookKillinglogs, function(Error, Content, Head)
		if Content == '{"code": 50027, "message": "Invalid Webhook Token"}' then
			print('\n\nERROR\n' .. GetCurrentResourceName() .. ': "Killing Log" Webhook non-existing!\n\n')
		end
	end)
end
if DiscordWebhookChat == 'WEBHOOK_LINK_HERE' then
	print('\n\nERROR\n' .. GetCurrentResourceName() .. ': Please add your "Chat" Webhook\n\n')
else
	PerformHttpRequest(DiscordWebhookChat, function(Error, Content, Head)
		if Content == '{"code": 50027, "message": "Invalid Webhook Token"}' then
			print('\n\nERROR\n' .. GetCurrentResourceName() .. ': "Chat" Webhook non-existing!\n\n')
		end
	end)
end
if DiscordWebhookDispatch == 'WEBHOOK_LINK_HERE' then
	print('\n\nERROR\n' .. GetCurrentResourceName() .. ': Please add your "Dispatch" Webhook\n\n')
else
	PerformHttpRequest(DiscordWebhookChat, function(Error, Content, Head)
		if Content == '{"code": 50027, "message": "Invalid Webhook Token"}' then
			print('\n\nERROR\n' .. GetCurrentResourceName() .. ': "Dispatch" Webhook non-existing!\n\n')
		end
	end)
end
	
-- System Infos
PerformHttpRequest(DiscordWebhookSystemInfos, function(Error, Content, Head) end, 'POST', json.encode({username = SystemName, content = '**FiveM Server Webhook Started**'}), { ['Content-Type'] = 'application/json' })

AddEventHandler('playerConnecting', function()
	ToDiscord(DiscordWebhookSystemInfos, SystemName, '```css\n' .. GetPlayerName(source) .. ' connecting\n```', SystemAvatar)
end)

AddEventHandler('playerDropped', function(Reason)
	ToDiscord(DiscordWebhookSystemInfos, SystemName, '```fix\n' .. GetPlayerName(source) .. ' left (' .. Reason .. ')\n```', SystemAvatar)
end)


-- Killing Log
RegisterServerEvent('PlayerDied')
AddEventHandler('PlayerDied', function(Message, Weapon)
	local date = os.date('*t')
	
	if date.day < 10 then date.day = '0' .. tostring(date.day) end
	if date.month < 10 then date.month = '0' .. tostring(date.month) end
	if date.hour < 10 then date.hour = '0' .. tostring(date.hour) end
	if date.min < 10 then date.min = '0' .. tostring(date.min) end
	if date.sec < 10 then date.sec = '0' .. tostring(date.sec) end
	if Weapon then
		Message = Message .. ' [' .. Weapon .. ']'
	end
	ToDiscord(DiscordWebhookKillinglogs, SystemName, Message .. ' `' .. date.day .. '.' .. date.month .. '.' .. date.year .. ' - ' .. date.hour .. ':' .. date.min .. ':' .. date.sec .. '`', SystemAvatar)
end)


-- Chat
AddEventHandler('chatMessage', function(Source, Name, Message)
	--Removing Color Codes (^0, ^1, ^2 etc.) from the name and the message
	for i = 0, 9 do
		Message = Message:gsub('%^' .. i, '')
		Name = Name:gsub('%^' .. i, '')
	end
	
	--Checking if the message contains a special command
	if IsCommand(Message, 'Special') then
		Message = ReplaceSpecialCommand(Message, Source)
		
		--Getting the steam avatar
		local AvatarURL = UserAvatar
		if GetIDFromSource('steam', Source) then
			print('Using Steam')
			local SteamIDHex = GetIDFromSource('steam', Source)
			local SteamIDInt = tonumber(SteamIDHex, 16)
			PerformHttpRequest('http://steamcommunity.com/profiles/' .. SteamIDInt .. '/?xml=1', function(Error, Content, Head)
				local SteamProfileSplitted = stringsplit(Content, '\n')
				for i, Line in ipairs(SteamProfileSplitted) do
					if Line:find('<avatarFull>') then
						local AvatarURL = Line:gsub('	<avatarFull><!%[CDATA%[', ''):gsub(']]></avatarFull>', '')
						ToDiscord(DiscordWebhookDispatch, Name .. ' [ID: ' .. Source .. ']', Message, AvatarURL) --Sending the message to discord
						break
					end
				end
			end)
		else
			ToDiscord(DiscordWebhookDispatch, Name .. ' [ID: ' .. Source .. ']', Message, AvatarURL) --Sending the message to discord
		end
		return false
	end
	
	-- Shortens the Name, if needed
	if Name:len() > 23 then
		Name = Name:sub(1, 23)
	end

	--Checking if the message contains a blacklisted command
	if not IsCommand(Message, 'Blacklisted') then
	
		--Getting the steam avatar
		local AvatarURL = UserAvatar
		if GetIDFromSource('steam', Source) then
			print('Using Steam')
			local SteamIDHex = GetIDFromSource('steam', Source)
			local SteamIDInt = tonumber(SteamIDHex, 16)
			PerformHttpRequest('http://steamcommunity.com/profiles/' .. SteamIDInt .. '/?xml=1', function(Error, Content, Head)
				local SteamProfileSplitted = stringsplit(Content, '\n')
				for i, Line in ipairs(SteamProfileSplitted) do
					if Line:find('<avatarFull>') then
						local AvatarURL = Line:gsub('	<avatarFull><!%[CDATA%[', ''):gsub(']]></avatarFull>', '')
						ToDiscord(DiscordWebhookChat, Name .. ' [ID: ' .. Source .. ']', Message, AvatarURL) --Sending the message to discord
						break
					end
				end
			end)
		else
			ToDiscord(DiscordWebhookChat, Name .. ' [ID: ' .. Source .. ']', Message, AvatarURL) --Sending the message to discord
		end
	end
end)

-- Functions

function ToDiscord(WebHook, Name, Message, Image)
	if Message == nil or Message == '' then
		return false
	end
	
	PerformHttpRequest(WebHook, function(Error, Content, Head) end, 'POST', json.encode({username = Name, content = Message, avatar_url = Image}), { ['Content-Type'] = 'application/json' })
end

function IsCommand(String, Type)
	local StringSplitted = stringsplit(String, ' ')
	if Type == 'Blacklisted' then
		for i, BlacklistedCommand in ipairs(BlacklistedCommands) do
			if StringSplitted[1]:lower() == BlacklistedCommand:lower() then
				return true
			end
		end
	elseif Type == 'Special' then
		for i, SpecialCommand in ipairs(SpecialCommands) do
			if StringSplitted[1]:lower() == SpecialCommand[1]:lower() then
				return true
			end
		end
	end
	return false
end

function ReplaceSpecialCommand(String, Source)
	local StringSplitted = stringsplit(String, ' ')
	for i, SpecialCommand in ipairs(SpecialCommands) do
		if StringSplitted[1]:lower() == SpecialCommand[1]:lower() then
			StringSplitted[1] = SpecialCommand[2]
			local newString = ''
			for k, StringPart in ipairs(StringSplitted) do
				if newString == '' then
					newString = StringPart
				else
					newString = newString .. ' ' .. StringPart
				end
			end
			newString = newString:gsub('USERNAME_NEEDED_HERE', GetPlayerName(Source))
			newString = newString:gsub('USERID_NEEDED_HERE', Source)
			return newString
		end
	end
end

function stringsplit(input, seperator)
	if seperator == nil then
		seperator = '%s'
	end
	
	local t={} ; i=1
	
	for str in string.gmatch(input, '([^'..seperator..']+)') do
		t[i] = str
		i = i + 1
	end
	
	return t
end

function GetIDFromSource(Type, ID) --(Thanks To WolfKnight [forum.FiveM.net])
    local IDs = GetPlayerIdentifiers(ID)
    for k, CurrentID in pairs(IDs) do
        local ID = stringsplit(CurrentID, ':')
        if (ID[1]:lower() == string.lower(Type)) then
            return ID[2]:lower()
        end
    end
    return nil
end

-- Version Checking down here, better don't touch this
local CurrentVersion = '1.4.4'
local UpdateAvailable = false
local GithubResourceName = 'DiscordBot'

PerformHttpRequest('https://raw.githubusercontent.com/Flatracer/' .. GithubResourceName .. '_Resources/master/VERSION', function(Error, NewestVersion, Header)
	PerformHttpRequest('https://raw.githubusercontent.com/Flatracer/' .. GithubResourceName .. '_Resources/master/CHANGES', function(Error, Changes, Header)
		PerformHttpRequest('https://raw.githubusercontent.com/Flatracer/' .. GithubResourceName .. '_Resources/master/PREVIOUSVERSION', function(Error, PreviousVersion, Header)
			print('\n')
			print('##############')
			print('## ' .. GithubResourceName)
			print('##')
			print('## Current Version: ' .. CurrentVersion)
			print('## Newest Version: ' .. NewestVersion)
			print('##')
			if CurrentVersion ~= NewestVersion then
				if CurrentVersion == PreviousVersion then
					UpdateAvailable = true
				end
				print('## Outdated')
				print('## Check the Topic')
				if UpdateAvailable then
					print('## Or type "update ' .. GetCurrentResourceName() .. '"')
				end
				print('## For the newest Version!')
				print('##############')
				print('CHANGES: ' .. Changes)
			else
				UpdateAvailable = false
				print('## Up to date!')
				print('##############')
			end
			print('\n')
		end)
	end)
end)

-- Instant Update down here, better don't touch this as well
AddEventHandler('rconCommand', function(CMDName, Arguments)
    if CMDName:lower() == 'update' then
		if #Arguments == 1 then
			if Arguments[1]:lower() == GetCurrentResourceName():lower() then
				TriggerEvent(GetCurrentResourceName() .. ':StartUpdate')
			end
		else
			print('Argument count mismatch (Passed: ' .. #Arguments .. ', Wanted: 1)')
		end
		CancelEvent()
	end
end)

RegisterServerEvent(GetCurrentResourceName() .. ':StartUpdate')
AddEventHandler(GetCurrentResourceName() .. ':StartUpdate', function()
	if UpdateAvailable then
		PerformHttpRequest('https://raw.githubusercontent.com/Flatracer/' .. GithubResourceName .. '_Resources/master/CHANGEDFILES', function(Error, Content, Header)
			ContentSplitted = stringsplit(Content, '\n')
			for k, Line in ipairs(ContentSplitted) do
				local PreviousContent = ''
				if Line:find('-add') then
					Line = Line:gsub('-add')
					PreviousContent = LoadResourceFile(GetCurrentResourceName(), Line) .. '\n'
				end
				PerformHttpRequest('https://raw.githubusercontent.com/Flatracer/' .. GithubResourceName .. '/master/' .. Line, function(Error, NewContent, Header)
					SaveResourceFile(GetCurrentResourceName(), Line, PreviousContent .. NewContent, -1)
				end)
			end
		end)
		print('Update finished! Enter "restart ' .. GetCurrentResourceName() .. '" now!')
	else
		print('This is already the newest version! [' .. CurrentVersion .. ']')
	end
end)


1 Like

Do you know a way to do this with a button?

For example:

We are using action menu to give us our weapons. Now I would like to make a submenu called “Radio”.
Is this submenu I would like to have some buttons. Maybe that I’m code 4 or something.

How would I do this? I’ve tried it for like 6 hours now but can’t get it to work. Can you please help me? :smiley:

Sweet. I’ll throw this on and test it. If everything works, you rock!

Dude, you rock.

It had a error on Line 13 of the server.lua. Just a [ where there shouldn’t have been. Fixed it and it works perfectly! Thank you.

FIX:

if DiscordWebhookSystemInfos == nil and DiscordWebhookKillinglogs == nil and DiscordWebhookChat == nil and DiscordWebhookDispatch == nil then

Updated to v1.5.0



  • Added the option to specify commands which have their own webhook link
  • Changed the ‘ToDiscord’ function to an event (Can be called from other resources now)


Download in the First Post!

1 Like

Is there a way to update the resource by typing a command via RCON?

This is not available for this update, with a reason. It would overwrite the config.lua and remove your configuration. So please update it yourself.

This update broke for me? Not sure if this is on your end or what but the only thing that now gets streamed is players connecting and deaths but any message sent by players in game is not streamed.
IGNORE THIS

Huh, is it working or not?

Was working for me before I uploaded it,I’d be weird if it doesn’t work for you.

No it works I just restarted it and it was only streaming connecting players and players who died but I forgot to add the config to it.

Could you help me with trying to get it working with a button? I would really appreciate it!
I have tried it myself but I can’t get it working at all. xD

Do you understand the way Action Menu works?
I haven’t checked it out, so I can’t help right now

If you understand it, then just call this event with the buttons you added:

If you want to use one of the three default channel, you can use this:

-- The channel can be one of these: 'chat' or 'system' or 'kill'
TriggerEvent('DiscordBot:ToDiscord', 'WHICH_CHANNEL', 'NAME', 'MESSAGE', 'IMAGE_URL', true)

Otherwise, if you want to use a different webhook link, use this:

TriggerEvent('DiscordBot:ToDiscord', 'YOUR_WEBHOOK_HERE', 'NAME', 'MESSAGE', 'IMAGE_URL', false)

Yhea I was playing with this to. But still nothing. This is what I’m using. I’m doing this in a client loaded script.

	if ( data == "Code 10" ) then 
		RemoveAllPedWeapons(GetPlayerPed(-1),true)
		chatPrint( "OC: Code 10 gemeld! Fijne dag gewenst!")
		TriggerEvent('DiscordBot:ToDiscord', 'myhookthingy',  'MyMom', '__**[OC]**__:** Ik meld me code 10.**', 'https://i.imgur.com/dX7bext.png', true)

I even tried to replace the whole event and replace it with a net event but still not any sign of it.

--Event to actually send Messages to Discord
RegisterNetEvent('DiscordBot:ToDiscord')
AddEventHandler('DiscordBot:ToDiscord', function(WebHook, Name, Message, Image, External)
	if Message == nil or Message == '' then
		return nil
	end
	if External then
		Image = SystemAvatar
		if WebHook:lower() == 'chat' then
			WebHook = DiscordWebhookChat
		elseif WebHook:lower() == 'system' then
			WebHook = DiscordWebhookSystemInfos
		elseif WebHook:lower() == 'kill' then
			WebHook = DiscordWebhookKillinglogs
		else
			return nil
		end
	end
	PerformHttpRequest(WebHook, function(Error, Content, Head) end, 'POST', json.encode({username = Name, content = Message, avatar_url = Image}), { ['Content-Type'] = 'application/json' })
end)

I also renamed the netevent to something else. Not that any of it worked :stuck_out_tongue:

Three things


  1. You just posted your webhook link, someone could abuse it

  2. Change the true at the end of the TriggerEvent to false.
  3. If you want to call if from a client sided script, use TriggerServerEvent, instead of TriggerEvent

BlockquoteError running system event handling function for resource DiscordBot: citizen:/scripting/lua/scheduler.lua:41: Failed to execute thread: server/server.lua:157: bad argument #1 to ‘for iterator’ (table expected, got nil)
stack traceback:
[C]: in for iterator ‘for iterator’
server/server.lua:157: in function ‘IsCommand’
server/server.lua:83: in upvalue ‘handler’
citizen:/scripting/lua/scheduler.lua:175: in function citizen:/scripting/lua/scheduler.lua:174
stack traceback:
[C]: in function ‘error’
citizen:/scripting/lua/scheduler.lua:41: in field ‘CreateThreadNow’
citizen:/scripting/lua/scheduler.lua:174: in function citizen:/scripting/lua/scheduler.lua:138
â‰ĄÆ’Ă¶â•‘cTm | www.fiverp.ro: t
hitch warning: frame time of 159 milliseconds
Sending heartbeat to live-internal.fivem.net:30110
Sending heartbeat to live-internal.fivem.net:30110
1
1
1
Sending heartbeat to live-internal.fivem.net:30110
Sending heartbeat to live-internal.fivem.net:30110
Sending heartbeat to live-internal.fivem.net:30110
Error running system event handling function for resource DiscordBot: citizen:/scripting/lua/scheduler.lua:41: Failed to execute thread: server/server.lua:157: bad argument #1 to ‘for iterator’ (table expected, got nil)
stack traceback:
[C]: in for iterator ‘for iterator’
server/server.lua:157: in function ‘IsCommand’
server/server.lua:83: in upvalue ‘handler’
citizen:/scripting/lua/scheduler.lua:175: in function citizen:/scripting/lua/scheduler.lua:174
stack traceback:
[C]: in function ‘error’
citizen:/scripting/lua/scheduler.lua:41: in field ‘CreateThreadNow’
citizen:/scripting/lua/scheduler.lua:174: in function citizen:/scripting/lua/scheduler.lua:138