From fea7973687c0dc4fabef5bf043360d8f413d3233 Mon Sep 17 00:00:00 2001 From: Andrew Ward Date: Fri, 2 Feb 2018 17:07:41 +0000 Subject: [PATCH] Add kick above certain number of violations (#2) Keep track of muted players, prevents players without shout being shown wrong message Add kick after 3 mutes in 5 minutes (ish) Split chat message callback in to functions, this would allow other mods to use the functions to check for spam and write their own violation mechanisms (although I'd like to add a callback) Add word count to chat command Add support for words.txt file in mod, to avoid having to manually enter loads of items. In future support for reading from world files using /filter import words.txt could be added. Make filter case insensitive Add gitignore --- .gitignore | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++ init.lua | 110 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 197 insertions(+), 26 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bfb8d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +words*.txt + + +# Created by https://www.gitignore.io/api/lua,linux,macos,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Lua ### +# Compiled Lua sources +luac.out + +# luarocks build files +*.src.rock +*.zip +*.tar.gz + +# Object files +*.o +*.os +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo +*.def +*.exp + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/lua,linux,macos,windows diff --git a/init.lua b/init.lua index 8e90504..1d02a24 100644 --- a/init.lua +++ b/init.lua @@ -24,43 +24,99 @@ ]]-- +filter = {} +local words = {} +local muted = {} +local violations = {} local s = minetest.get_mod_storage() -assert(s, "minetest version too old") -local words -local sw = s:get_string("words") +function filter.init() + local sw = s:get_string("words") + if sw and sw ~= "" then + words = minetest.parse_json(sw) + end -if sw and sw ~= "" then - words = minetest.parse_json(sw) -else - words = {} + if #words == 0 then + filter.import_file(minetest.get_modpath("filter") .. "/words.txt") + end end -minetest.register_on_chat_message(function(name, message) +function filter.import_file(filepath) + local file = io.open(filepath, "r") + if file then + for line in file:lines() do + line = line:trim() + if line ~= "" then + words[#words + 1] = line:trim() + end + end + return true + else + return false + end +end + +function filter.check_message(name, message) + for _, w in ipairs(words) do + if string.find(message:lower(), "%f[%a]" .. w .. "%f[%A]") then + return false + end + end + + return true +end + +function filter.on_violation(name, message) + violations[name] = (violations[name] or 0) + 1 + + local resolution + + if violations[name] >= 3 then + resolution = "kicked" + minetest.kick_player(name, "Please mind your language!") + else + resolution = "muted" + local privs = minetest.get_player_privs(name) + privs.shout = nil + minetest.set_player_privs(name, privs) + minetest.chat_send_player(name, "Watch your language! You have been temporarily muted") + + muted[name] = true + + minetest.after(60, function() + muted[name] = nil + minetest.chat_send_player(name, "Chat privilege reinstated. Please do not abuse chat.") + privs.shout = true + minetest.set_player_privs(name, privs) + end) + end + + minetest.log("action", "VIOLATION (" .. resolution .. "): <" .. name .. "> ".. message) +end + +table.insert(minetest.registered_on_chat_messages, 1, function(name, message) local privs = minetest.get_player_privs(name) - if not privs.shout then + if not privs.shout and muted[name] then minetest.chat_send_player(name, "You are temporarily muted.") return true end - for _, w in ipairs(words) do - if string.find(message, "%f[%a]" .. w .. "%f[%A]") then - privs.shout = nil - minetest.set_player_privs(name, privs) - minetest.chat_send_player(name, "Chat temporarily disabled due to language.") + if not filter.check_message(name, message) then + filter.on_violation(name, message) + return true + end +end) - minetest.after(60, function() - minetest.chat_send_player(name, "Chat privilege reinstated. Please do not abuse chat.") - privs.shout = true - minetest.set_player_privs(name, privs) - end) - - return true +local function step() + for name, v in pairs(violations) do + violations[name] = math.floor(v * 0.5) + if violations[name] < 1 then + violations[name] = nil end end - - return false -end) + minetest.after(2*60, step) +end +minetest.after(2*60, step) minetest.register_chatcommand("filter", { params = "filter server", @@ -69,7 +125,7 @@ minetest.register_chatcommand("filter", { func = function(name, param) local cmd, val = param:match("(%w+) (.+)") if param == "list" then - return true, table.concat(words, ", ") + return true, #words .. " words: " .. table.concat(words, ", ") elseif cmd == "add" then table.insert(words, val) s:set_string("words", minetest.write_json(words)) @@ -84,7 +140,9 @@ minetest.register_chatcommand("filter", { end return true, "\"" .. val .. "\" not found in list." else - return true, "Usage: /filter []" + return true, "I know " .. #words .. " words.\nUsage: /filter []" end end, }) + +filter.init()