280 lines
9.4 KiB
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.")
|