junk_removal/init.lua

280 lines
9.4 KiB
Lua

-- JUNK REMOVAL by SaKeL
-- Player blocks/items what are not found in the World directory /players will be removed/replaced with leaves and apples. Free up blocked and protected space on the map from players what are not playing anymore or were deleted.
-- private core variables - for speed
local worldpath = minetest.get_worldpath()
local junk_removal = {}
-- list of players i.e. { [1] = "SaKeL", [2] = "ADMIN", ...}
-- read only on the server start - read only!
junk_removal.playersfilelist = {}
-- table of players i.e. { ["SaKeL"] = true, ["ADMIN"] = true, ...}
-- this will give us much more faster table lookup than iterating through the table (playersfilelist)
-- read / write
junk_removal.playerstable = {}
-- new players connected for the 1st time - didn't had their player file yet - adepts for removal
-- when player satisfy requirements, he will be removed from this list
-- read / write
junk_removal.newplayers = {}
-- new players for definite removal - these came out from newplayers and did not satisfy the requirements
-- for auth.txt only
-- read / write
junk_removal.unsatisfied = {}
-- removed usatisfied players + players not found in playerstable
-- used just to print out the names of removed players
-- read only
junk_removal.removed_from_auth = {}
-- what a newplayers have to have in the inventory before leaving the game in order to qualify for non-removal
junk_removal.requirements = { "default:stick 1", "default:steel_ingot 1" }
-- list of node names for i.e. LBM
junk_removal.nodenames = {
-- protector
"protector:protect",
"protector:protect2",
"protector:chest",
-- chests
"default:chest_locked",
"default:chest_locked_open",
-- doors
"doors:door_steel_a",
"doors:door_steel_b",
"doors:trapdoor_steel",
"doors:trapdoor_steel_open",
-- basic machines
"basic_machines:autocrafter",
"basic_machines:ball_spawner",
"basic_machines:constructor",
"basic_machines:grinder",
"basic_machines:mover",
"basic_machines:keypad",
"basic_machines:detector",
"basic_machines:clockgen",
"basic_machines:distributor",
"basic_machines:battery_0",
"basic_machines:battery_1",
"basic_machines:battery_2",
"basic_machines:recycler",
"basic_machines:generator",
-- xdecor
"xdecor:enchantment_table",
-- easyvend
"easyvend:vendor",
"easyvend:vendor_on",
"easyvend:depositor",
"easyvend:depositor_on",
-- city block
"city_block:cityblock",
"xdecor:itemframe",
"xdecor:mailbox"
}
function junk_removal:load()
junk_removal.playersfilelist = minetest.get_dir_list(worldpath.."/players", false)
-- index table by player name so searching in it is faster
for i = 1, #junk_removal.playersfilelist do
junk_removal.playerstable[junk_removal.playersfilelist[i]] = true
end
-- print("junk_removal.playersfilelist: ", minetest.serialize(junk_removal.playersfilelist))
-- print("junk_removal.playerstable: ", minetest.serialize(junk_removal.playerstable))
end
minetest.register_on_joinplayer(function(player)
local pname = player:get_player_name()
if not pname then return end
local inv = player:get_inventory()
local is_newplayer = inv:get_stack("newplayer", 1):get_count()
if not junk_removal.playerstable[pname] or is_newplayer > 0 then
-- set player inventory data
inv:set_size("newplayer", 1)
inv:set_stack("newplayer", 1, ItemStack("newplayer"))
-- print("adding player: "..pname.." to playerstable")
-- print("adding player: "..pname.." to newplayers")
junk_removal.playerstable[pname] = true
junk_removal.newplayers[pname] = true
local form = "size[8,8]"..
default.gui_bg..
default.gui_bg_img..
"textarea[0.8,0.5;7,7;welcome;Welcome "..pname.." to Survival X server;\n*** IMPORTANT ***\n\nHi "..pname..", please have at least 1 STICK and 1 STEEL INGOT in your inventory when leaving the game to register as serious player.\n\nIf not, your player data will be deleted!\n\nThis is needed only for 1 time, after that you don't need to do that and you will not see this window any more.\n\nHave fun!\n\nADMIN;default]"..
"button_exit[3,7;2,1.5;play;PLAY]"
minetest.show_formspec(pname, "junk_removal:welcome", form)
end
end)
minetest.register_on_leaveplayer(function(player, timed_out)
local pname = player:get_player_name()
local pinv = player:get_inventory()
if not pname or not pinv then return end
local inv = player:get_inventory()
-- new player - adept for removal
if junk_removal.newplayers[pname] then
local pfilename = worldpath.."/players/"..pname
local req_satisfied = true
for k, item in ipairs(junk_removal.requirements) do
if not pinv:contains_item("main", item) then
req_satisfied = false
junk_removal.unsatisfied[pname] = true -- for auth.txt
break
else
junk_removal.unsatisfied[pname] = nil -- for auth.txt
end
end
-- remove player files
if not req_satisfied then
-- print("removing player: "..pname.." from playerstable")
junk_removal.playerstable[pname] = nil
-- @author rnd
-- PROBLEM: deleting doesnt always work? seems minetest itself is saving stuff, so we wait a little and then we delete
minetest.after(1, function()
minetest.log("action", "[junk_removal] Removing player filename: "..pfilename)
local err, msg = os.remove(pfilename)
if err == nil then
minetest.log("warning", "[junk_removal] Error while removing player data "..pfilename..", error message: "..msg)
end
end)
else
-- print("removing player: "..pname.." from newplayers")
-- this player satisfied requirements for the 1st time, removing from newplayers list and player will no be checked anymore (old player)
junk_removal.newplayers[pname] = nil
inv:set_stack("newplayer", 1, ItemStack(""))
end
end
end)
-- remove players with unsatisfied requirements from auth.txt
-- The auth.txt file is written periodically and at shutdown, so we should edit it only when the server is not running
function junk_removal:remove_players_from_auth()
-- read file
local file = io.open(worldpath.."/auth.txt", "r")
if not file then return end
local lines = {}
local count = 0
local removed = 0
while true do
local line = file:read("*l")
if line == nil then break end
-- print("pname: "..line:split(":")[1])
-- print("hashed_password: "..line:split(":")[2])
-- print("privs: "..line:split(":")[3])
-- print("last_login: "..line:split(":")[4])
local pname = line:split(":")[1]
if not junk_removal.unsatisfied[pname] and junk_removal.playerstable[pname] then
count = count + 1
table.insert(lines, line)
else
table.insert(junk_removal.removed_from_auth, pname)
removed = removed + 1
end
end
file:close()
-- write all the lines
-- file = io.open(worldpath.."/auth_2.txt", "w")
file = io.open(worldpath.."/auth.txt", "w")
if not file then return end
for i, l in ipairs(lines) do
file:write(l, "\n")
end
file:close()
minetest.log("action", "===========================[junk_removal]===========================")
minetest.log("action", " written players to auth.txt: "..count)
minetest.log("action", " removed players from auth.txt: "..removed)
minetest.log("action", " removed players names: "..minetest.serialize(junk_removal.removed_from_auth))
minetest.log("action", "==========================[/junk_removal]===========================")
end
minetest.register_on_shutdown(function()
-- we canno't rely on local methods any more since removing the player files in not working from here, we will setup an 'newplayer' inventory flag instead
-- for k, v in pairs(junk_removal.newplayers) do
-- print("k: "..k)
-- local filename = worldpath.."/players/"..k
-- local file, msg = io.open(filename, "r")
-- if not file then
-- minetest.log("warning", "[junk_removal] Error while opening player data "..filename.." error message: "..msg)
-- return
-- end
-- local content = file:read("*all")
-- file:close()
-- for _, item in ipairs(junk_removal.requirements) do
-- print("Item "..item:split(" ")[1])
-- if not string.find(content, "Item "..item:split(" ")[1]) then
-- -- os.execute("sleep "..1)
-- local isOK, msg = os.remove(filename)
-- if not isOK then
-- minetest.log("warning", "[junk_removal] Error while removing player data "..filename.." error message: "..msg)
-- else
-- print(os.date("%X")..": [junk_removal] Removing player filename: "..filename)
-- end
-- junk_removal.unsatisfied[k] = true -- for auth.txt
-- break
-- else
-- junk_removal.unsatisfied[k] = nil -- for auth.txt
-- end
-- end
-- end
junk_removal:remove_players_from_auth()
end)
minetest.register_lbm({
label = "Junk Removal",
name = "junk_removal:remove_junk",
nodenames = junk_removal.nodenames,
run_at_every_load = true,
action = function(pos, node)
local nname = node.name or ""
local meta = minetest.get_meta(pos)
local owner = meta:get_string("owner")
local replace_nodename = "default:apple"
if math.random(2) == 1 then
replace_nodename = "default:leaves"
end
-- remove nodes from mods what were removed from the game (unknown blocks)
if nname == "city_block:cityblock" then
minetest.log("action", "removed unknown node ("..nname.."): at "..minetest.pos_to_string(pos))
minetest.set_node(pos, {name = replace_nodename})
end
if not owner or owner == "" then
return
end
if not junk_removal.playerstable[owner] then
minetest.log("action", "removing player junk ("..nname.."): "..owner.." at "..minetest.pos_to_string(pos))
minetest.set_node(pos, {name = replace_nodename})
end
end
})
junk_removal:load()
print ("[Mod] Junk Removal Loaded.")