2020-07-29 15:03:55 -07:00
local const_irc , const_discord = bridges.irc , bridges.discord
local const_bridge = const_irc or const_discord
2019-07-13 11:03:35 -07:00
2020-02-20 08:27:49 -08:00
modlib.log . create_channel ( " adv_chat " ) -- Create log channel
2021-05-13 06:32:37 -07:00
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 ( )
2020-02-20 08:27:49 -08:00
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
2019-07-13 11:03:35 -07:00
2020-02-24 12:01:57 -08:00
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
2019-07-13 11:03:35 -07:00
channels = { } --channelname -> definition : {hud_pos, mode, autoremove, max_messages, max_lines, wrap_chars, smartwrap}
roles = { } -- Role -> players -> true
2020-04-01 04:07:02 -07:00
if roles_case_insensitive then
2020-04-05 04:15:02 -07:00
modlib.table . set_case_insensitive_index ( roles )
2020-04-01 04:07:02 -07:00
end
2019-07-13 11:03:35 -07:00
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
2021-05-13 06:32:37 -07:00
minetest.chat_send_player ( chattername , message )
2019-07-13 11:03:35 -07:00
else
2020-07-29 15:03:55 -07:00
if const_discord then
if chatters [ chattername ] . discord then
discord_bridge.write ( " [PMS] " .. get_color ( chattername ) .. " " .. chattername .. " " .. message )
end
2019-07-13 11:03:35 -07:00
end
2020-07-29 15:03:55 -07:00
if const_irc then
if chatters [ chattername ] . irc then
irc_bridge.write ( " [PMS] " .. chattername .. " " .. message )
end
2019-07-13 11:03:35 -07:00
end
end
end
2019-10-31 13:54:15 -07:00
function send_to_targets ( msg )
message.mentionpart ( msg )
2020-02-20 08:27:49 -08:00
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
2020-07-29 15:03:55 -07:00
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
2019-10-31 13:54:15 -07:00
for target , _ in pairs ( msg.targets ) do
2019-07-13 11:03:35 -07:00
if not chatters [ target ] then
if roles [ target ] then
2020-02-29 03:55:23 -08:00
modlib.table . add_all ( msg.targets , roles [ target ] . affected )
2019-07-13 11:03:35 -07:00
end
2019-10-31 13:54:15 -07:00
msg.targets [ target ] = nil
2019-07-13 11:03:35 -07:00
end
end
local discord_chatters = { }
local irc_chatters = { }
2019-10-31 13:54:15 -07:00
for chatter , _ in pairs ( msg.targets ) do
2020-07-29 15:03:55 -07:00
if not is_blocked ( chatter , msg.chatter . name ) then
2019-07-13 11:03:35 -07:00
if chatters [ chatter ] . minetest then
2019-10-31 13:54:15 -07:00
minetest.chat_send_player ( chatter , message.build ( msg , " minetest " ) )
2019-07-13 11:03:35 -07:00
else
2020-07-29 15:03:55 -07:00
if const_discord then
if chatters [ chatter ] . discord then
table.insert ( discord_chatters , chatter : sub ( 1 , chatter : len ( ) - 9 ) )
end
2019-07-13 11:03:35 -07:00
end
2020-07-29 15:03:55 -07:00
if const_irc then
if chatters [ chatter ] . irc then
table.insert ( irc_chatters , chatter : sub ( 1 , chatter : len ( ) - 5 ) )
end
2019-07-13 11:03:35 -07:00
end
end
end
end
2020-07-29 15:03:55 -07:00
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
2019-07-13 11:03:35 -07:00
end
end
2020-07-29 15:03:55 -07:00
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
2019-07-13 11:03:35 -07:00
end
end
end
function join ( name , def )
if not def.roles then
def.roles = { }
end
2019-10-31 13:54:15 -07:00
if not def.name then
def.name = name
end
def.service = ( ( def.minetest and " minetest " ) or ( def.irc and " irc " ) ) or " discord "
2019-07-13 11:03:35 -07:00
chatters [ name ] = def
2021-05-13 06:32:37 -07:00
local to_be_received = to_be_sent.root [ name ]
2019-07-13 11:03:35 -07:00
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
2020-04-30 08:14:34 -07:00
message = " [ " .. datepart .. m.time .. " ] " .. minetest.get_color_escape_sequence ( sender_color ) ..
m.sender .. schemes.minetest . content_prefix .. m.message
2019-07-13 11:03:35 -07:00
else
2020-04-30 08:14:34 -07:00
message = " [ " .. datepart .. m.time .. " ] " .. m.sender .. schemes.other . content_prefix .. m.message
2019-07-13 11:03:35 -07:00
end
send_to_chatter ( m.sender , name , message )
end
end
2021-05-13 06:32:37 -07:00
to_be_sent : set_root ( name , nil )
2019-07-13 11:03:35 -07:00
end
2020-02-24 12:01:57 -08:00
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
2019-07-13 11:03:35 -07:00
function leave ( name )
2020-02-24 12:01:57 -08:00
remove_roles ( name )
2019-07-13 11:03:35 -07:00
chatters [ name ] = nil
end
2020-02-24 12:01:57 -08:00
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
2019-07-13 11:03:35 -07:00
minetest.register_on_joinplayer ( function ( player )
2020-02-24 12:01:57 -08:00
join ( player : get_player_name ( ) , { color = modlib.player . get_color ( player ) , roles = { } , blocked = { chatters = { } , roles = { } } , minetest = true } )
2019-07-13 11:03:35 -07:00
add_role ( player : get_player_name ( ) , " minetest " )
2020-02-24 12:01:57 -08:00
if not call_registered_on_joinplayers ( player ) then
send_join_message ( player : get_player_name ( ) )
end
2019-07-13 11:03:35 -07:00
end )
2020-02-24 12:01:57 -08:00
minetest.register_on_leaveplayer ( function ( player , timed_out )
send_leave_message ( player : get_player_name ( ) , timed_out )
leave ( player : get_player_name ( ) )
2019-07-13 11:03:35 -07:00
end )
function register_role ( rolename , roledef )
roles [ rolename ] = { title = roledef.title , color = roledef.color or " #FFFFFF " , affected = { } }
2020-02-29 03:55:23 -08:00
modlib.player . register_forbidden_name ( rolename )
2019-07-13 11:03:35 -07:00
end
2020-07-29 15:03:55 -07:00
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 )
2019-11-23 09:17:10 -08:00
2020-07-29 15:03:55 -07:00
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
2019-10-31 13:54:15 -07:00
end
2019-07-13 11:03:35 -07:00
end
register_role ( " minetest " , { color = " #66FF66 " } )
function unregister_role ( rolename )
roles [ rolename ] = nil
2020-02-29 03:55:23 -08:00
modlib.player . unregister_forbidden_name ( rolename )
2019-07-13 11:03:35 -07:00
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
2020-02-24 12:01:57 -08:00
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
2019-07-13 11:03:35 -07:00
function get_color ( chatter )
if chatters [ chatter ] then
return chatters [ chatter ] . color or " #FFFFFF "
end
return " #FFFFFF "
end
2020-02-24 12:01:57 -08:00
function mt_color ( chattername )
return minetest.get_color_escape_sequence ( get_color ( chattername ) )
end
2019-10-31 13:54:15 -07:00
function send_to_all ( msg )
2020-02-20 08:27:49 -08:00
if message.handle_on_chat_messages ( msg ) then
return msg.handled_by_on_chat_messages
end
2020-07-29 15:03:55 -07:00
if const_irc then
if msg.sent_to ~= " irc " then
irc_bridge.write ( " [MSG] " .. message.build ( msg , " irc " ) )
end
2019-07-13 11:03:35 -07:00
end
2020-07-29 15:03:55 -07:00
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
2019-07-13 11:03:35 -07:00
end
2019-10-31 13:54:15 -07:00
if msg.sent_to ~= " minetest " then
local mt_msg
2019-07-13 11:03:35 -07:00
for _ , player in pairs ( minetest.get_connected_players ( ) ) do
local playername = player : get_player_name ( )
2019-10-31 13:54:15 -07:00
if not msg.chatter or not is_blocked ( playername , msg.chatter ) then
mt_msg = mt_msg or message.build ( msg , " minetest " )
2019-07-13 11:03:35 -07:00
minetest.chat_send_player ( playername , mt_msg )
end
end
end
end
function send_to_players ( msg , players , origin )
for playername , _ in pairs ( players ) do
2020-02-29 03:55:23 -08:00
local blocked = modlib.player . get_property ( playername , " chatroles.blocked " )
2020-03-30 05:16:11 -07:00
if not blocked.players [ origin ] then
local send = true
2019-07-13 11:03:35 -07:00
for role , _ in ipairs ( blocked.roles ) do
if roles [ role ] . affected [ origin ] then
2020-03-30 05:16:11 -07:00
send = false
break
2019-07-13 11:03:35 -07:00
end
end
2020-03-30 05:16:11 -07:00
if send then
minetest.chat_send_player ( playername , msg )
end
2019-07-13 11:03:35 -07:00
end
end
end
function get_affected_by_mentions ( mentions )
local affected = { }
for _ , mention in pairs ( mentions ) do
if roles [ mention ] then
2020-02-29 03:55:23 -08:00
modlib.table . add_all ( affected , roles [ mention ] . affected )
2019-07-13 11:03:35 -07:00
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
2020-04-30 08:14:34 -07:00
function on_chat_message ( sender , msg )
2019-07-13 11:03:35 -07:00
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 )
2020-02-29 03:55:23 -08:00
local parts = modlib.text . split_without_limit ( msg_header , " , " )
2019-07-13 11:03:35 -07:00
for _ , part in pairs ( parts ) do
2020-02-29 03:55:23 -08:00
table.insert ( mentions , modlib.text . trim ( part , " " ) )
2019-07-13 11:03:35 -07:00
end
2019-10-31 13:54:15 -07:00
local adv_msg = message.new ( chatters [ sender ] , mentions , msg_content )
message.mentionpart ( adv_msg )
2019-07-13 11:03:35 -07:00
table.insert ( mentions , sender )
2020-02-20 08:27:49 -08:00
send_to_targets ( adv_msg )
2019-10-31 13:54:15 -07:00
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. " )
2019-07-13 11:03:35 -07:00
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
2019-10-31 13:54:15 -07:00
local adv_msg = message.new ( chatters [ sender ] , mentions , msg_content )
send_to_all ( adv_msg )
2019-07-13 11:03:35 -07:00
end
return true
end
minetest.register_on_chat_message ( on_chat_message )
2020-02-29 03:55:23 -08:00
local prefix = ( cmdlib and " chat " ) or " chat_ "
2019-10-31 13:54:15 -07:00
minetest.register_chatcommand ( prefix .. " msg " , {
2019-07-13 11:03:35 -07:00
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 )
2020-02-29 03:55:23 -08:00
if minetest.player_exists ( playername ) or modlib.text . ends_with ( playername , " [irc] " ) or modlib.text . ends_with ( playername , " [discord] " ) then
2019-07-13 11:03:35 -07:00
local message = colorize_message ( param : sub ( delim + 1 ) )
2021-05-13 06:32:37 -07:00
if not to_be_sent.root [ playername ] then
to_be_sent : set_root ( playername , { } )
2019-07-13 11:03:35 -07:00
end
2021-05-13 06:32:37 -07:00
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 ( )
2019-07-13 11:03:35 -07:00
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 [ ]
] ]
2019-10-31 13:54:15 -07:00
minetest.register_chatcommand ( prefix .. " say " , {
2019-07-13 11:03:35 -07:00
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 )
2019-10-31 13:54:15 -07:00
minetest.register_chatcommand ( prefix .. " block " , {
2019-07-13 11:03:35 -07:00
params = " <name> | <role> " ,
description = " Block messages from chatter or role " ,
privs = { } ,
func = function ( sendername , param )
2020-02-29 03:55:23 -08:00
param = modlib.text . trim ( param )
2019-07-13 11:03:35 -07:00
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
} )
2019-10-31 13:54:15 -07:00
minetest.register_chatcommand ( prefix .. " unblock " , {
2019-07-13 11:03:35 -07:00
params = " <name> | <role> " ,
description = " Unblock messages from chatter or role " ,
privs = { } ,
func = function ( sendername , param )
2020-02-29 03:55:23 -08:00
param = modlib.text . trim ( param )
2019-07-13 11:03:35 -07:00
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
2019-10-31 13:54:15 -07:00
} )
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 )
2020-02-29 03:55:23 -08:00
param = modlib.text . trim ( param )
2019-10-31 13:54:15 -07:00
if param : len ( ) == 0 then
return false , " No arguments given - missing name and password. "
end
2020-02-29 03:55:23 -08:00
local name , password = unpack ( modlib.text . split ( param , " " , 2 ) )
2019-10-31 13:54:15 -07:00
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
2019-11-23 09:17:10 -08:00
} )