123 lines
3.9 KiB
Lua
123 lines
3.9 KiB
Lua
local shown = {}
|
|
|
|
local settings = minetest.settings
|
|
local MSG_BUBBLE_LIFETIME = tonumber(settings:get("message_bubbles_lifetime")) or 10
|
|
local MAX_CHARS_PER_LINE = tonumber(settings:get("message_bubbles_char_limit")) or 40
|
|
local MAX_NUM_LINES = tonumber(settings:get("message_bubbles_max_num_lines")) or 1
|
|
local MSG_BUBBLE_PREFIX = settings:get("message_bubbles_prefix") or "Says: "
|
|
|
|
local cumulativeTime = 0
|
|
|
|
-- gsub requires escaping of custom characters otherwise the replacement can break
|
|
local function literal(str)
|
|
return str:gsub("[%(%)%.%%%+%-%*%?%[%^%$%]]", "%%%1")
|
|
end
|
|
|
|
local function removeEscape(str)
|
|
return str:gsub("%%", "")
|
|
end
|
|
|
|
local function trim(msg)
|
|
if not msg or not type(msg) == "string" then return "" end
|
|
if string.len(msg) <= MAX_CHARS_PER_LINE then return msg end
|
|
if MAX_NUM_LINES <= 1 then return string.sub(msg, 1, MAX_CHARS_PER_LINE)..".." end
|
|
|
|
-- else: we have multilines to split
|
|
local words = string.split(msg, " ", false)
|
|
local ret = ""
|
|
local currLine = 1
|
|
local wordIndex = 1
|
|
local line = ""
|
|
while currLine <= MAX_NUM_LINES do
|
|
local adjMaxChPerLine = MAX_CHARS_PER_LINE
|
|
if currLine == 1 then adjMaxChPerLine = MAX_CHARS_PER_LINE - string.len(MSG_BUBBLE_PREFIX) end
|
|
local space = ""
|
|
if string.len(line) > 0 then space = " " end
|
|
local tmp = line..space
|
|
if words[wordIndex] then
|
|
tmp = line..space..words[wordIndex]
|
|
else -- we used all the words, return early
|
|
return ret..line
|
|
end
|
|
|
|
if string.len(tmp) <= adjMaxChPerLine then
|
|
-- adding this word didn't overflow the line length
|
|
line = tmp
|
|
wordIndex = wordIndex + 1
|
|
else -- the word pushed the line length over the limit
|
|
if currLine == MAX_NUM_LINES then
|
|
-- last line, just cut last word and return early
|
|
line = string.sub(tmp, 1, adjMaxChPerLine)
|
|
return ret..line..".."
|
|
else
|
|
-- don't add the word, leave it to the next line (don't increment wordIndex)
|
|
ret = ret..line.."\n"
|
|
end
|
|
line = ""
|
|
currLine = currLine + 1
|
|
end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
minetest.register_on_chat_message(function(name, origMessage)
|
|
if minetest.get_player_privs(name).shout then
|
|
local player = minetest.get_player_by_name(name)
|
|
if not player then return end
|
|
local msg = "\n"..MSG_BUBBLE_PREFIX..trim(origMessage)
|
|
msg = removeEscape(msg)
|
|
local nametag = player:get_nametag_attributes()
|
|
local nametagText = nametag.text
|
|
local hadToAddName = false
|
|
if shown[name] then
|
|
local currText = shown[name].text
|
|
if shown[name].wasEmpty then
|
|
shown[name].text = name..msg
|
|
shown[name].addedMsg = msg
|
|
else
|
|
shown[name].text = string.gsub(nametagText, literal(shown[name].addedMsg), msg)
|
|
shown[name].addedMsg = msg
|
|
end
|
|
shown[name].time = minetest.get_gametime()
|
|
else
|
|
local addedMsg = msg
|
|
if not nametagText or nametagText == "" then
|
|
msg = name..msg
|
|
hadToAddName = true
|
|
else
|
|
msg = nametagText..msg
|
|
end
|
|
shown[name] = {
|
|
text = msg,
|
|
addedMsg = addedMsg,
|
|
time = minetest.get_gametime(),
|
|
wasEmpty = hadToAddName,
|
|
}
|
|
end
|
|
nametag.text = shown[name].text
|
|
player:set_nametag_attributes(nametag)
|
|
end
|
|
end)
|
|
|
|
minetest.register_globalstep(function(dtime)
|
|
cumulativeTime = cumulativeTime + dtime
|
|
if cumulativeTime > 1 then
|
|
cumulativeTime = 0
|
|
local currTime = minetest.get_gametime()
|
|
for playerName, info in pairs(shown) do
|
|
if currTime - info.time > MSG_BUBBLE_LIFETIME then
|
|
local player = minetest.get_player_by_name(playerName)
|
|
if player then
|
|
local nametag = player:get_nametag_attributes()
|
|
if info.wasEmpty then
|
|
nametag.text = ""
|
|
else
|
|
nametag.text = string.gsub(nametag.text, literal(info.addedMsg), "")
|
|
end
|
|
player:set_nametag_attributes(nametag)
|
|
end
|
|
shown[playerName] = nil
|
|
end
|
|
end
|
|
end
|
|
end) |