2017-05-21 16:52:55 +02:00
|
|
|
RegisterServerEvent('chat:init')
|
|
|
|
RegisterServerEvent('chat:addTemplate')
|
|
|
|
RegisterServerEvent('chat:addMessage')
|
|
|
|
RegisterServerEvent('chat:addSuggestion')
|
|
|
|
RegisterServerEvent('chat:removeSuggestion')
|
|
|
|
RegisterServerEvent('_chat:messageEntered')
|
|
|
|
RegisterServerEvent('chat:clear')
|
2017-07-09 16:21:45 +02:00
|
|
|
RegisterServerEvent('__cfx_internal:commandFallback')
|
2017-05-17 19:22:20 +02:00
|
|
|
|
2020-04-13 07:45:09 +02:00
|
|
|
-- this is a built-in event, but somehow needs to be registered
|
|
|
|
RegisterNetEvent('playerJoining')
|
|
|
|
|
2020-04-12 15:16:02 +02:00
|
|
|
exports('addMessage', function(target, message)
|
|
|
|
if not message then
|
|
|
|
message = target
|
|
|
|
target = -1
|
|
|
|
end
|
|
|
|
|
|
|
|
if not target or not message then return end
|
|
|
|
|
|
|
|
TriggerClientEvent('chat:addMessage', target, message)
|
|
|
|
end)
|
|
|
|
|
|
|
|
local hooks = {}
|
|
|
|
local hookIdx = 1
|
|
|
|
|
|
|
|
exports('registerMessageHook', function(hook)
|
|
|
|
local resource = GetInvokingResource()
|
|
|
|
hooks[hookIdx + 1] = {
|
|
|
|
fn = hook,
|
|
|
|
resource = resource
|
|
|
|
}
|
|
|
|
|
|
|
|
hookIdx = hookIdx + 1
|
|
|
|
end)
|
|
|
|
|
|
|
|
local modes = {}
|
|
|
|
|
2020-04-12 22:17:33 +02:00
|
|
|
local function getMatchingPlayers(seObject)
|
|
|
|
local players = GetPlayers()
|
|
|
|
local retval = {}
|
|
|
|
|
|
|
|
for _, v in ipairs(players) do
|
|
|
|
if IsPlayerAceAllowed(v, seObject) then
|
|
|
|
retval[#retval + 1] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return retval
|
|
|
|
end
|
|
|
|
|
2020-04-12 15:16:02 +02:00
|
|
|
exports('registerMode', function(modeData)
|
|
|
|
if not modeData.name or not modeData.displayName or not modeData.cb then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
local resource = GetInvokingResource()
|
|
|
|
|
|
|
|
modes[modeData.name] = modeData
|
|
|
|
modes[modeData.name].resource = resource
|
|
|
|
|
2020-04-12 22:17:33 +02:00
|
|
|
local clObj = {
|
2020-04-12 15:16:02 +02:00
|
|
|
name = modeData.name,
|
|
|
|
displayName = modeData.displayName,
|
2020-11-01 12:48:44 +01:00
|
|
|
color = modeData.color or '#fff',
|
|
|
|
isChannel = modeData.isChannel,
|
|
|
|
isGlobal = modeData.isGlobal,
|
2020-04-12 22:17:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if not modeData.seObject then
|
|
|
|
TriggerClientEvent('chat:addMode', -1, clObj)
|
|
|
|
else
|
|
|
|
for _, v in ipairs(getMatchingPlayers(modeData.seObject)) do
|
|
|
|
TriggerClientEvent('chat:addMode', v, clObj)
|
|
|
|
end
|
|
|
|
end
|
2020-04-12 15:16:02 +02:00
|
|
|
|
|
|
|
return true
|
|
|
|
end)
|
|
|
|
|
|
|
|
local function unregisterHooks(resource)
|
|
|
|
local toRemove = {}
|
|
|
|
|
|
|
|
for k, v in pairs(hooks) do
|
|
|
|
if v.resource == resource then
|
|
|
|
table.insert(toRemove, k)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, v in ipairs(toRemove) do
|
|
|
|
hooks[v] = nil
|
|
|
|
end
|
|
|
|
|
|
|
|
toRemove = {}
|
|
|
|
|
|
|
|
for k, v in pairs(modes) do
|
|
|
|
if v.resource == resource then
|
|
|
|
table.insert(toRemove, k)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, v in ipairs(toRemove) do
|
|
|
|
TriggerClientEvent('chat:removeMode', -1, {
|
|
|
|
name = v
|
|
|
|
})
|
|
|
|
|
|
|
|
modes[v] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-27 11:30:50 +02:00
|
|
|
local function routeMessage(source, author, message, mode, fromConsole)
|
|
|
|
if source >= 1 then
|
|
|
|
author = GetPlayerName(source)
|
2017-05-17 19:22:20 +02:00
|
|
|
end
|
|
|
|
|
2020-04-12 15:16:02 +02:00
|
|
|
local outMessage = {
|
|
|
|
color = { 255, 255, 255 },
|
|
|
|
multiline = true,
|
2020-04-27 11:30:50 +02:00
|
|
|
args = { message },
|
|
|
|
mode = mode
|
2020-04-12 15:16:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if author ~= "" then
|
|
|
|
outMessage.args = { author, message }
|
|
|
|
end
|
|
|
|
|
2020-04-12 22:17:33 +02:00
|
|
|
if mode and modes[mode] then
|
|
|
|
local modeData = modes[mode]
|
|
|
|
|
|
|
|
if modeData.seObject and not IsPlayerAceAllowed(source, modeData.seObject) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-12 15:16:02 +02:00
|
|
|
local messageCanceled = false
|
|
|
|
local routingTarget = -1
|
|
|
|
|
|
|
|
local hookRef = {
|
|
|
|
updateMessage = function(t)
|
|
|
|
-- shallow merge
|
|
|
|
for k, v in pairs(t) do
|
|
|
|
if k == 'template' then
|
|
|
|
outMessage['template'] = v:gsub('%{%}', outMessage['template'] or '@default')
|
|
|
|
elseif k == 'params' then
|
|
|
|
if not outMessage.params then
|
|
|
|
outMessage.params = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
for pk, pv in pairs(v) do
|
|
|
|
outMessage.params[pk] = pv
|
|
|
|
end
|
|
|
|
else
|
|
|
|
outMessage[k] = v
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
cancel = function()
|
|
|
|
messageCanceled = true
|
|
|
|
end,
|
|
|
|
|
2020-04-12 22:17:33 +02:00
|
|
|
setSeObject = function(object)
|
|
|
|
routingTarget = getMatchingPlayers(object)
|
|
|
|
end,
|
|
|
|
|
2020-04-12 15:16:02 +02:00
|
|
|
setRouting = function(target)
|
|
|
|
routingTarget = target
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2020-04-27 11:30:50 +02:00
|
|
|
for _, hook in pairs(hooks) do
|
|
|
|
if hook.fn then
|
|
|
|
hook.fn(source, outMessage, hookRef)
|
2020-04-12 15:16:02 +02:00
|
|
|
end
|
2020-04-27 11:30:50 +02:00
|
|
|
end
|
2020-04-12 15:16:02 +02:00
|
|
|
|
2020-04-27 11:30:50 +02:00
|
|
|
if modes[mode] then
|
|
|
|
local m = modes[mode]
|
2020-04-12 15:16:02 +02:00
|
|
|
|
2020-04-27 11:30:50 +02:00
|
|
|
m.cb(source, outMessage, hookRef)
|
2020-04-12 15:16:02 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if messageCanceled then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
TriggerEvent('chatMessage', source, #outMessage.args > 1 and outMessage.args[1] or '', outMessage.args[#outMessage.args])
|
2017-05-17 19:22:20 +02:00
|
|
|
|
|
|
|
if not WasEventCanceled() then
|
2020-04-12 15:16:02 +02:00
|
|
|
if type(routingTarget) ~= 'table' then
|
|
|
|
TriggerClientEvent('chat:addMessage', routingTarget, outMessage)
|
|
|
|
else
|
|
|
|
for _, id in ipairs(routingTarget) do
|
|
|
|
TriggerClientEvent('chat:addMessage', id, outMessage)
|
|
|
|
end
|
|
|
|
end
|
2017-05-17 19:22:20 +02:00
|
|
|
end
|
|
|
|
|
2020-04-27 11:30:50 +02:00
|
|
|
if not fromConsole then
|
|
|
|
print(author .. '^7' .. (modes[mode] and (' (' .. modes[mode].displayName .. ')') or '') .. ': ' .. message .. '^7')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
AddEventHandler('_chat:messageEntered', function(author, color, message, mode)
|
|
|
|
if not message or not author then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local source = source
|
|
|
|
|
|
|
|
routeMessage(source, author, message, mode)
|
2017-05-17 19:22:20 +02:00
|
|
|
end)
|
|
|
|
|
2017-07-09 16:21:45 +02:00
|
|
|
AddEventHandler('__cfx_internal:commandFallback', function(command)
|
|
|
|
local name = GetPlayerName(source)
|
|
|
|
|
2020-04-27 11:30:50 +02:00
|
|
|
-- route the message as if it were a /command
|
|
|
|
routeMessage(source, name, '/' .. command, nil, true)
|
2017-07-09 16:21:45 +02:00
|
|
|
|
|
|
|
CancelEvent()
|
|
|
|
end)
|
|
|
|
|
2017-05-17 19:22:20 +02:00
|
|
|
-- player join messages
|
2020-04-12 15:16:02 +02:00
|
|
|
AddEventHandler('playerJoining', function()
|
|
|
|
if GetConvarInt('chat_showJoins', 1) == 0 then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2017-05-21 16:52:55 +02:00
|
|
|
TriggerClientEvent('chatMessage', -1, '', { 255, 255, 255 }, '^2* ' .. GetPlayerName(source) .. ' joined.')
|
2017-05-17 19:22:20 +02:00
|
|
|
end)
|
|
|
|
|
|
|
|
AddEventHandler('playerDropped', function(reason)
|
2020-04-12 15:16:02 +02:00
|
|
|
if GetConvarInt('chat_showQuits', 1) == 0 then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2017-05-21 16:52:55 +02:00
|
|
|
TriggerClientEvent('chatMessage', -1, '', { 255, 255, 255 }, '^2* ' .. GetPlayerName(source) ..' left (' .. reason .. ')')
|
2017-05-17 19:22:20 +02:00
|
|
|
end)
|
2017-07-09 16:21:45 +02:00
|
|
|
|
|
|
|
RegisterCommand('say', function(source, args, rawCommand)
|
2020-04-27 11:30:50 +02:00
|
|
|
routeMessage(source, (source == 0) and 'console' or GetPlayerName(source), rawCommand:sub(5), nil, true)
|
2018-02-20 12:01:29 +01:00
|
|
|
end)
|
|
|
|
|
|
|
|
-- command suggestions for clients
|
|
|
|
local function refreshCommands(player)
|
|
|
|
if GetRegisteredCommands then
|
|
|
|
local registeredCommands = GetRegisteredCommands()
|
|
|
|
|
|
|
|
local suggestions = {}
|
|
|
|
|
|
|
|
for _, command in ipairs(registeredCommands) do
|
|
|
|
if IsPlayerAceAllowed(player, ('command.%s'):format(command.name)) then
|
|
|
|
table.insert(suggestions, {
|
|
|
|
name = '/' .. command.name,
|
|
|
|
help = ''
|
|
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
TriggerClientEvent('chat:addSuggestions', player, suggestions)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
AddEventHandler('chat:init', function()
|
2020-04-12 22:17:33 +02:00
|
|
|
local source = source
|
2018-02-20 12:01:29 +01:00
|
|
|
refreshCommands(source)
|
2020-04-12 22:17:33 +02:00
|
|
|
|
|
|
|
for _, modeData in pairs(modes) do
|
|
|
|
local clObj = {
|
|
|
|
name = modeData.name,
|
|
|
|
displayName = modeData.displayName,
|
2020-11-01 12:48:44 +01:00
|
|
|
color = modeData.color or '#fff',
|
|
|
|
isChannel = modeData.isChannel,
|
|
|
|
isGlobal = modeData.isGlobal,
|
2020-04-12 22:17:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if not modeData.seObject or IsPlayerAceAllowed(source, modeData.seObject) then
|
|
|
|
TriggerClientEvent('chat:addMode', source, clObj)
|
|
|
|
end
|
|
|
|
end
|
2018-02-20 12:01:29 +01:00
|
|
|
end)
|
|
|
|
|
|
|
|
AddEventHandler('onServerResourceStart', function(resName)
|
|
|
|
Wait(500)
|
|
|
|
|
|
|
|
for _, player in ipairs(GetPlayers()) do
|
|
|
|
refreshCommands(player)
|
|
|
|
end
|
2018-09-26 18:06:30 +02:00
|
|
|
end)
|
2020-04-12 15:16:02 +02:00
|
|
|
|
|
|
|
AddEventHandler('onResourceStop', function(resName)
|
|
|
|
unregisterHooks(resName)
|
|
|
|
end)
|