570 lines
19 KiB
Lua
570 lines
19 KiB
Lua
local const_irc, const_discord = bridges.irc, bridges.discord
|
|
local const_bridge = const_irc or const_discord
|
|
|
|
modlib.log.create_channel("adv_chat") -- Create log channel
|
|
local data_dir = minetest.get_worldpath() .. "/data"
|
|
minetest.mkdir(data_dir)
|
|
to_be_sent = modlib.persistence.lua_log_file.new(data_dir .. "/adv_chat.lua", {})
|
|
to_be_sent:init()
|
|
modlib.player.set_property_default("adv_chat.roles",{})
|
|
modlib.player.set_property_default("adv_chat.blocked",{chatters={}, roles={}})
|
|
|
|
registered_on_chat_messages = {}
|
|
|
|
function register_on_chat_message(func)
|
|
table.insert(registered_on_chat_messages, func)
|
|
end
|
|
|
|
register_on_chat_message(function(sendername, content, msg)
|
|
if not msg.targets then
|
|
modlib.log.write("adv_chat", "[MSG] "..sendername..": "..content)
|
|
end
|
|
end)
|
|
|
|
function unregister_on_chat_message(func)
|
|
for index, func_2 in modlib.table.rpairs(func) do
|
|
if func == func_2 then
|
|
table.remove(registered_on_chat_messages, index)
|
|
end
|
|
end
|
|
end
|
|
|
|
function call_registered_on_chat_messages(name, message, msg_info)
|
|
for _, func in ipairs(registered_on_chat_messages) do
|
|
if func(name, message, msg_info) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
registered_on_joinplayers = {}
|
|
|
|
function register_on_joinplayer(func)
|
|
table.insert(registered_on_joinplayers, func)
|
|
end
|
|
|
|
register_on_joinplayer(function(player)
|
|
if get_color(player:get_player_name()) == "#FFFFFF" then
|
|
chatters[player:get_player_name()].color = roles.minetest.color
|
|
end
|
|
end)
|
|
|
|
|
|
function call_registered_on_joinplayers(player)
|
|
for _, func in ipairs(registered_on_joinplayers) do
|
|
if func(player) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
channels={} --channelname -> definition : {hud_pos, mode, autoremove, max_messages, max_lines, wrap_chars, smartwrap}
|
|
roles={} -- Role -> players -> true
|
|
if roles_case_insensitive then
|
|
modlib.table.set_case_insensitive_index(roles)
|
|
end
|
|
chatters={} -- Chatter -> stuff
|
|
|
|
|
|
function is_blocked(target, source)
|
|
if not chatters[target] then return false end
|
|
local blocked=chatters[target].blocked
|
|
if not blocked then return false end
|
|
if blocked.chatters[source] then
|
|
return true
|
|
end
|
|
for role,_ in pairs(blocked.roles) do
|
|
if roles[role].affected[source] then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
function send_to_chatter(sendername, chattername, message)
|
|
if is_blocked(chattername, sendername) then return end
|
|
if chatters[chattername].minetest then
|
|
minetest.chat_send_player(chattername, message)
|
|
else
|
|
if const_discord then
|
|
if chatters[chattername].discord then
|
|
discord_bridge.write("[PMS]"..get_color(chattername).." "..chattername.." "..message)
|
|
end
|
|
end
|
|
if const_irc then
|
|
if chatters[chattername].irc then
|
|
irc_bridge.write("[PMS]"..chattername.." "..message)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function send_to_targets(msg)
|
|
message.mentionpart(msg)
|
|
if modlib.table.is_empty(msg.valid_targets) then
|
|
return
|
|
end
|
|
if message.handle_on_chat_messages(msg) then
|
|
return msg.handled_by_on_chat_messages
|
|
end
|
|
local irc_mentioned, discord_mentioned
|
|
if const_irc then
|
|
irc_mentioned = msg.targets.irc
|
|
end
|
|
if const_discord then
|
|
discord_mentioned = msg.targets.discord
|
|
end
|
|
for target, _ in pairs(msg.targets) do
|
|
if not chatters[target] then
|
|
if roles[target] then
|
|
modlib.table.add_all(msg.targets, roles[target].affected)
|
|
end
|
|
msg.targets[target]=nil
|
|
end
|
|
end
|
|
local discord_chatters={}
|
|
local irc_chatters={}
|
|
for chatter, _ in pairs(msg.targets) do
|
|
if not is_blocked(chatter, msg.chatter.name) then
|
|
if chatters[chatter].minetest then
|
|
minetest.chat_send_player(chatter, message.build(msg, "minetest"))
|
|
else
|
|
if const_discord then
|
|
if chatters[chatter].discord then
|
|
table.insert(discord_chatters, chatter:sub(1, chatter:len()-9))
|
|
end
|
|
end
|
|
if const_irc then
|
|
if chatters[chatter].irc then
|
|
table.insert(irc_chatters, chatter:sub(1, chatter:len()-5))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if const_discord then
|
|
if msg.sent_to ~= "discord" then
|
|
if discord_mentioned then
|
|
discord_bridge.write("[MSG]"..(msg.chatter.color).." "..message.build(msg, "discord"))
|
|
elseif #discord_chatters > 0 then
|
|
discord_bridge.write("[PMS]"..(msg.chatter.color).." "..table.concat(discord_chatters, ",").." "..message.build(msg, "discord"))
|
|
end
|
|
end
|
|
end
|
|
|
|
if const_irc then
|
|
if msg.sent_to ~= "irc" then
|
|
if irc_mentioned then
|
|
irc_bridge.write("[MSG]"..message.build(msg, "irc"))
|
|
elseif #irc_chatters > 0 then
|
|
irc_bridge.write("[PMS]"..table.concat(irc_chatters, ",").." "..message.build(msg, "irc"))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function join(name, def)
|
|
if not def.roles then
|
|
def.roles={}
|
|
end
|
|
if not def.name then
|
|
def.name=name
|
|
end
|
|
def.service = ((def.minetest and "minetest") or (def.irc and "irc")) or "discord"
|
|
chatters[name]=def
|
|
local to_be_received=to_be_sent.root[name]
|
|
if to_be_received then
|
|
local date=os.date("%Y-%m-%d")
|
|
for _, m in ipairs(to_be_received) do
|
|
local sender_color=get_color(m.sender)
|
|
local datepart=""
|
|
if date ~= m.date then
|
|
datepart=m.date.." "
|
|
end
|
|
local message
|
|
if def.minetest then
|
|
message="["..datepart..m.time.."] "..minetest.get_color_escape_sequence(sender_color)..
|
|
m.sender..schemes.minetest.content_prefix..m.message
|
|
else
|
|
message="["..datepart..m.time.."] "..m.sender..schemes.other.content_prefix..m.message
|
|
end
|
|
send_to_chatter(m.sender, name, message)
|
|
end
|
|
end
|
|
to_be_sent:set_root(name, nil)
|
|
end
|
|
|
|
function core.send_join_message(name) end
|
|
|
|
function send_join_message(name)
|
|
minetest.chat_send_all(mt_color(name)..name..minetest.get_color_escape_sequence("#FFFFFF").." joined.")
|
|
end
|
|
|
|
function rename(chattername, new_chattername)
|
|
chatters[new_chattername]=chatters[chattername]
|
|
transfer_roles(chattername, new_chattername)
|
|
chatters[chattername]=nil
|
|
minetest.chat_send_all(mt_color(new_chattername)..chattername..minetest.get_color_escape_sequence("#FFFFFF").." is now known as "..mt_color(new_chattername)..new_chattername)
|
|
end
|
|
|
|
function leave(name)
|
|
remove_roles(name)
|
|
chatters[name]=nil
|
|
end
|
|
|
|
function core.send_leave_message(name, timeout) end
|
|
|
|
function send_leave_message(name, timed_out)
|
|
local message = mt_color(name)..name..minetest.get_color_escape_sequence("#FFFFFF").." left"
|
|
if timed_out then
|
|
message = message .. " (timed out)"
|
|
end
|
|
minetest.chat_send_all(message .. ".")
|
|
end
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
join(player:get_player_name(), {color=modlib.player.get_color(player), roles={}, blocked={chatters={}, roles={}}, minetest=true})
|
|
add_role(player:get_player_name(), "minetest")
|
|
if not call_registered_on_joinplayers(player) then
|
|
send_join_message(player:get_player_name())
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player, timed_out)
|
|
send_leave_message(player:get_player_name(), timed_out)
|
|
leave(player:get_player_name())
|
|
end)
|
|
|
|
function register_role(rolename, roledef)
|
|
roles[rolename]={title=roledef.title, color=roledef.color or "#FFFFFF",affected={}}
|
|
modlib.player.register_forbidden_name(rolename)
|
|
end
|
|
|
|
if const_bridge then
|
|
minetest.original_chat_send_all=minetest.chat_send_all
|
|
minetest.chat_send_all=function(msg)
|
|
local adv_message=message.new(nil, nil, msg)
|
|
adv_message.internal=true
|
|
send_to_all(adv_message)
|
|
end
|
|
minetest.original_chat_send_player=minetest.chat_send_player
|
|
minetest.chat_send_player=function(name, msg)
|
|
local chatter=chatters[name]
|
|
if not chatter then
|
|
return
|
|
end
|
|
if chatter.minetest then
|
|
return minetest.original_chat_send_player(name, msg)
|
|
end
|
|
local adv_message=message.new(nil, nil, msg)
|
|
adv_message.internal=true
|
|
local to_be_sent=message.build(adv_message, chatter.service)
|
|
|
|
if const_irc then
|
|
if chatter.irc then
|
|
irc_bridge.write("[PMS]"..chatter.name.." "..to_be_sent)
|
|
end
|
|
end
|
|
if const_discord then
|
|
if chatter.discord then
|
|
discord_bridge.write("[PMS]#FFFFFF "..chatter.name.." "..to_be_sent)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
register_role("minetest",{color="#66FF66"})
|
|
|
|
function unregister_role(rolename)
|
|
roles[rolename]=nil
|
|
modlib.player.unregister_forbidden_name(rolename)
|
|
end
|
|
|
|
function add_role(player, role, value)
|
|
if not roles[role] or not chatters[player] then return false end
|
|
if not roles[role].affected[player] then
|
|
roles[role].affected[player]=value or true
|
|
end
|
|
if not chatters[player].roles[role] then
|
|
chatters[player].roles[role]=value or true
|
|
end
|
|
return true
|
|
end
|
|
|
|
function remove_role(player, role, expected_value)
|
|
if expected_value and roles[role].affected[player] == expected_value then
|
|
roles[role].affected[player]=nil
|
|
chatters[player].roles[role]=nil
|
|
end
|
|
end
|
|
|
|
function remove_roles(chatter)
|
|
for role, _ in pairs(chatters[chatter].roles) do
|
|
roles[role].affected[chatter] = nil
|
|
chatters[chatter].roles[role] = nil
|
|
end
|
|
end
|
|
|
|
function transfer_roles(chatter, new_chatter)
|
|
for role, _ in pairs(chatters[chatter].roles) do
|
|
roles[role].affected[new_chatter] = roles[role].affected[chatter]
|
|
roles[role].affected[chatter] = nil
|
|
end
|
|
end
|
|
|
|
function get_color(chatter)
|
|
if chatters[chatter] then
|
|
return chatters[chatter].color or "#FFFFFF"
|
|
end
|
|
return "#FFFFFF"
|
|
end
|
|
|
|
function mt_color(chattername)
|
|
return minetest.get_color_escape_sequence(get_color(chattername))
|
|
end
|
|
|
|
function send_to_all(msg)
|
|
if message.handle_on_chat_messages(msg) then
|
|
return msg.handled_by_on_chat_messages
|
|
end
|
|
if const_irc then
|
|
if msg.sent_to ~= "irc" then
|
|
irc_bridge.write("[MSG]"..message.build(msg, "irc"))
|
|
end
|
|
end
|
|
if const_discord then
|
|
if msg.sent_to ~= "discord" then
|
|
discord_bridge.write("[MSG]"..((msg.chatter and msg.chatter.color) or "#FFFFFF").." "..message.build(msg, "discord"))
|
|
end
|
|
end
|
|
if msg.sent_to ~= "minetest" then
|
|
local mt_msg
|
|
for _,player in pairs(minetest.get_connected_players()) do
|
|
local playername=player:get_player_name()
|
|
if not msg.chatter or not is_blocked(playername, msg.chatter) then
|
|
mt_msg=mt_msg or message.build(msg, "minetest")
|
|
minetest.chat_send_player(playername, mt_msg)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function send_to_players(msg, players, origin)
|
|
for playername,_ in pairs(players) do
|
|
local blocked=modlib.player.get_property(playername, "chatroles.blocked")
|
|
if not blocked.players[origin] then
|
|
local send = true
|
|
for role,_ in ipairs(blocked.roles) do
|
|
if roles[role].affected[origin] then
|
|
send = false
|
|
break
|
|
end
|
|
end
|
|
if send then
|
|
minetest.chat_send_player(playername, msg)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function get_affected_by_mentions(mentions)
|
|
local affected={}
|
|
for _, mention in pairs(mentions) do
|
|
if roles[mention] then
|
|
modlib.table.add_all(affected, roles[mention].affected)
|
|
elseif minetest.get_player_by_name(mention) then
|
|
affected[mention]=true
|
|
end
|
|
end
|
|
return affected
|
|
end
|
|
|
|
function parse_message(message)
|
|
return colorize_message(parse_unicode(message))
|
|
end
|
|
|
|
function on_chat_message(sender, msg)
|
|
local mentions={}
|
|
local msg_content=msg
|
|
if msg:sub(1,1)=="@" then
|
|
local delim_space=false
|
|
local last_non_delim_char=false
|
|
for i=1,msg:len() do
|
|
local c=msg:sub(i,i)
|
|
if c == "," then
|
|
last_non_delim_char=false
|
|
elseif c ~=" " then
|
|
if last_non_delim_char and i-last_non_delim_char > 1 then
|
|
delim_space=i-1
|
|
break
|
|
end
|
|
last_non_delim_char=i
|
|
end
|
|
end
|
|
|
|
if not delim_space then
|
|
minetest.chat_send_player(sender, "No message given. Use '@mentions message'.")
|
|
return true
|
|
end
|
|
|
|
msg_content=msg:sub(delim_space+1)
|
|
local msg_header=msg:sub(2, delim_space-1)
|
|
local parts=modlib.text.split_without_limit(msg_header,",")
|
|
for _, part in pairs(parts) do
|
|
table.insert(mentions, modlib.text.trim(part, " "))
|
|
end
|
|
local adv_msg=message.new(chatters[sender], mentions, msg_content)
|
|
message.mentionpart(adv_msg)
|
|
table.insert(mentions, sender)
|
|
send_to_targets(adv_msg)
|
|
if #adv_msg.invalid_mentions == 1 then
|
|
minetest.chat_send_player(sender, "The target "..adv_msg.invalid_mentions[1].." is inexistant.")
|
|
elseif #adv_msg.invalid_mentions > 1 then
|
|
minetest.chat_send_player(sender, "The targets "..table.concat(adv_msg.invalid_mentions, ", ").." are inexistant.")
|
|
end
|
|
else
|
|
local sender_color=get_color(sender)
|
|
players={}
|
|
for _,player in pairs(minetest.get_connected_players()) do
|
|
players[player:get_player_name()]=true
|
|
end
|
|
local adv_msg=message.new(chatters[sender], mentions, msg_content)
|
|
send_to_all(adv_msg)
|
|
end
|
|
return true
|
|
end
|
|
minetest.register_on_chat_message(on_chat_message)
|
|
|
|
local prefix = (cmdlib and "chat ") or "chat_"
|
|
|
|
minetest.register_chatcommand(prefix.."msg",{
|
|
params = "<name> <message>",
|
|
description = "Send a message to a chatter as soon as they join",
|
|
privs={},
|
|
func = function(sendername, param)
|
|
local delim=param:find(" ")
|
|
if not delim or delim==string.len(param) then
|
|
return false, "No message specified"
|
|
else
|
|
local playername=param:sub(1,delim-1)
|
|
if minetest.player_exists(playername) or modlib.text.ends_with(playername, "[irc]") or modlib.text.ends_with(playername, "[discord]") then
|
|
local message=colorize_message(param:sub(delim+1))
|
|
if not to_be_sent.root[playername] then
|
|
to_be_sent:set_root(playername, {})
|
|
end
|
|
local list = to_be_sent.root[playername]
|
|
to_be_sent:set(list, #list+1, {sender=sendername, message=message, date=os.date("%Y-%m-%d"), time=os.date("%H:%M:%S")})
|
|
to_be_sent:flush()
|
|
return true, "Your message '"..message..minetest.get_color_escape_sequence("#FFFFFF").."' will be sent to chatter '"..playername.."' as soon as they join."
|
|
else
|
|
return false, "No chatter called '"..playername.."'"
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
local formspec=[[size[9,0.5,false]
|
|
field[0.2,0.2;7,1;text;;]
|
|
button_exit[7,0;2,0.75;send;Send]
|
|
no_prepend[]
|
|
]]
|
|
|
|
minetest.register_chatcommand(prefix.."say", {
|
|
params="",
|
|
description="Send chat message using entry field.",
|
|
privs={discord_user=false, irc_user=false},
|
|
func=function(sendername)
|
|
minetest.show_formspec(sendername, "chatroles:chatbox", formspec)
|
|
end
|
|
})
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname=="chatroles:chatbox" and fields.text then
|
|
on_chat_message(player:get_player_name(), fields.text)
|
|
end
|
|
end)
|
|
|
|
minetest.register_chatcommand(prefix.."block", {
|
|
params = "<name> | <role>",
|
|
description = "Block messages from chatter or role",
|
|
privs={},
|
|
func = function(sendername, param)
|
|
param=modlib.text.trim(param)
|
|
if param:len() == 0 or (not chatters[param] and not roles[param]) then
|
|
return false, "No valid chatter name or role given."
|
|
end
|
|
if not chatters[sendername] then
|
|
return false, "No valid sender name."
|
|
end
|
|
local blocked=chatters[sendername].blocked.chatters
|
|
if roles[param] then
|
|
blocked=chatters[sendername].blocked.roles
|
|
end
|
|
if blocked[param] then
|
|
return false, type..param.." is already blocked"
|
|
end
|
|
blocked[param]=true
|
|
return true, type..param.." was blocked"
|
|
end
|
|
})
|
|
|
|
minetest.register_chatcommand(prefix.."unblock", {
|
|
params = "<name> | <role>",
|
|
description = "Unblock messages from chatter or role",
|
|
privs={},
|
|
func = function(sendername, param)
|
|
param=modlib.text.trim(param)
|
|
if param:len() == 0 or (not chatters[param] and not roles[param]) then
|
|
return false, "No valid chatter name or role given."
|
|
end
|
|
if not chatters[sendername] then
|
|
return false, "No valid sender name."
|
|
end
|
|
local blocked=chatters[sendername].blocked.chatters
|
|
if roles[param] then
|
|
blocked=chatters[sendername].blocked.roles
|
|
end
|
|
if not blocked[param] then
|
|
return false, type..param.." is not blocked"
|
|
end
|
|
blocked[param]=nil
|
|
return true, type..param.." was unblocked"
|
|
end
|
|
})
|
|
|
|
minetest.register_chatcommand(prefix.."login", {
|
|
params = "<name> <password>",
|
|
description = "Log in as (fake) player to execute chatcommands as them",
|
|
privs = {chatter=true},
|
|
func = function(sendername, param)
|
|
param=modlib.text.trim(param)
|
|
if param:len() == 0 then
|
|
return false, "No arguments given - missing name and password."
|
|
end
|
|
local name, password = unpack(modlib.text.split(param, " ", 2))
|
|
password = password or ""
|
|
local auth = minetest.get_auth_handler().get_auth(name)
|
|
if auth and minetest.check_password_entry(name, auth.password, password) then
|
|
chatters[sendername].login = name
|
|
return true, 'Logged in as "'..name..'"'
|
|
end
|
|
return false, "Wrong playername/password. : "..name..", "..password.."!="..auth.password
|
|
end
|
|
})
|
|
|
|
minetest.register_chatcommand(prefix.."logout", {
|
|
params = "",
|
|
description = "Log out from your (fake) player account",
|
|
privs = {chatter=true},
|
|
func = function(sendername, param)
|
|
if not chatters[sendername].login then
|
|
return false, "Not logged in."
|
|
end
|
|
local login = chatters[sendername].login
|
|
chatters[sendername].login = nil
|
|
return true, 'Logged out from "'..login..'"'
|
|
end
|
|
})
|