diff --git a/init.lua b/init.lua index cb71ee4..fb60c61 100644 --- a/init.lua +++ b/init.lua @@ -145,13 +145,6 @@ function rspawn:set_player_spawn(name, newpos) return true end -local function register_original_spawn(playername, pos) - if not rspawn.playerspawns["original spawns"] then - rspawn.playerspawns["original spawns"] = {} - end - rspawn.playerspawns["original spawns"][playername] = pos -end - function rspawn:set_newplayer_spawn(player) -- only use for new players / players who have never had a randomized spawn if not player then return end @@ -164,7 +157,6 @@ function rspawn:set_newplayer_spawn(player) local newpos = rspawn:get_next_spawn() if newpos then - register_original_spawn(playername, newpos) rspawn:set_player_spawn(playername, newpos) else diff --git a/lua/commands.lua b/lua/commands.lua index dbaee43..bd0fd85 100644 --- a/lua/commands.lua +++ b/lua/commands.lua @@ -4,46 +4,13 @@ local cooldown_time = tonumber(minetest.settings:get("rspawn.cooldown_time")) or -- Command privileges -minetest.register_privilege("spawn", "Can teleport to spawn position.") -minetest.register_privilege("setspawn", "Can manually set a spawn point") +minetest.register_privilege("spawn", "Can teleport to a spawn position and manage shared spawns.") +minetest.register_privilege("setspawn", "Can manually set a spawn point.") minetest.register_privilege("newspawn", "Can get a new randomized spawn position.") minetest.register_privilege("spawnadmin", "Can clean up timers and set new spawns for players.") -- Support functions -local function splitstring(sdata, sep) - local idx - local tdata = {} - - while sdata ~= "" do - idx = sdata:find(sep) - - if idx then - tdata[#tdata+1] = sdata:sub(1,idx-1) - sdata = sdata:sub(idx+1, sdata:len() ) - - else -- last element - tdata[#tdata+1] = sdata - break - end - end - - return tdata -end - -local function set_original_spawn(tname) - local tpos = rspawn.playerspawns["original spawns"][tname] - - if not tpos then - minetest.chat_send_player(tname, "Could not find your original spawn!") - - elseif rspawn:consume_levvy(minetest.get_player_by_name(tname)) then - rspawn:set_player_spawn(tname, tpos) - else - minetest.chat_send_player(tname, "You do not have enough to pay the levvy. Aborting.") - end -end - local function request_new_spawn(username, targetname) local timername = username if targetname ~= username then @@ -67,12 +34,12 @@ end -- Commands minetest.register_chatcommand("spawn", { - description = "Teleport to spawn position, or manage invitations. See you current invitation with '/spawn invite'. If you are a guest at a spawn, return to your orgiinal spawn with '/spawn original'", - params = "[ invite [] | accept | decline | original ]", + description = "Teleport to your spawn, or manage guests in your spawn.", + params = "[ add | visit | kick | guests | hosts ]", privs = "spawn", - func = function(name, args) + func = function(playername, args) local target = rspawn.playerspawns[name] - local args = splitstring(args, " ") + local args = args:split(" ") if #args == 0 then if target then @@ -83,29 +50,24 @@ minetest.register_chatcommand("spawn", { minetest.chat_send_player(name, "You have no spawn position!") return end + elseif #args < 3 then + for command,action in pairs({ + ["guests"] = function() rspawn.invites:listguests(playername) end, + ["hosts"] = function() rspawn.invites:listhosts(playername) end, + ["add"] = function(commandername,targetname) rspawn.invites:addplayer(commandername,targetname) end, + ["visit"] = function(commandername,targetname) rspawn.invites:visitplayer(targetname, commandername) end, + ["kick"] = function(commandername,targetname) rspawn.invites:exileplayer(commandername, targetname) end, + }) do - elseif args[1] == "accept" then - rspawn.invites:accept(name) - return - - elseif args[1] == "decline" then - rspawn.invites:decline(name) - return - - elseif args[1] == "original" then - set_original_spawn(name) - return - - elseif args[1] == "invite" then - if #args == 2 then - rspawn.invites:invite_player_fromto(name, args[2]) - return - - elseif #args == 1 then - rspawn.invites:show_invite_for(name) - return + if args[1] == command then + if #args == 2 then + action(playername, args[2]) + else + action() + end + return + end end - end minetest.chat_send_player(name, "Please check '/help spawn'") @@ -133,32 +95,18 @@ minetest.register_chatcommand("newspawn", { }) minetest.register_chatcommand("playerspawn", { - description = "Randomly select a new spawn position for a player, or use specified position, 'original' for their original spawn.", - params = " { new | | original | setoriginal | go }", + description = "Randomly select a new spawn position for a player, or use specified position, or go to their spawn.", + params = " { new | | go }", privs = "spawnadmin", func = function(name, args) if args ~= "" then - args = splitstring(args, " ") + args = args:splitstring(" ") if #args == 2 then local tname = args[1] local tpos - if args[2] == "original" then - tpos = rspawn.playerspawns["original spawns"][tname] - if not tpos then - minetest.chat_send_player( name, "Could not find original spawn for "..tname) - minetest.chat_send_player(tname, "Could not find original spawn for "..tname) - return - end - elseif args[2] == "setoriginal" then - rspawn.playerspawns["original spawns"][tname] = rspawn.playerspawns[tname] - minetest.chat_send_player(name, "Saved "..tname.. - "'s spawn "..minetest.pos_to_string(rspawn.playerspawns[tname]).. - " as original.") - return - - elseif args[2] == "go" then + if args[2] == "go" then local user = minetest.get_player_by_name(name) local dest = rspawn.playerspawns[args[1]] if dest then @@ -168,18 +116,20 @@ minetest.register_chatcommand("playerspawn", { minetest.chat_send_player(name, "No rspawn coords for "..args[1]) end return + elseif args[2] == "new" then request_new_spawn(name, args[1]) return + else tpos = minetest.string_to_pos(args[2]) - end - if tpos then - if not rspawn:set_player_spawn(tname, tpos) then - minetest.chat_send_player(name, name.."'s spawn could not be reset") + if tpos then + if not rspawn:set_player_spawn(tname, tpos) then + minetest.chat_send_player(name, name.."'s spawn could not be reset") + end + return end - return end end end diff --git a/lua/data.lua b/lua/data.lua index 7404a2c..532c3bf 100644 --- a/lua/data.lua +++ b/lua/data.lua @@ -1,5 +1,13 @@ local spawnsfile = minetest.get_worldpath().."/dynamicspawns.lua.ser" +--[[ Reconcile functions + +reconcile_original_spawns : convert from base implementation to invites with original spawns + +reconcile_guestlist_spawns : convert from "original spawns" implementation to "guest lists" + +--]] + -- Comatibility with old behaviour - players whose original spawns had not been registered receive the one they are now using local function reconcile_original_spawns() if not rspawn.playerspawns["original spawns"] then @@ -17,6 +25,36 @@ local function reconcile_original_spawns() rspawn:spawnsave() end +local function reconcile_guest(guestname, guestspawn) + for hostname,hostspawn in pairs(rspawn.playerspawns) do + if hostspawn == guestspawn then + local hostlist = rspawn.playerspawns["guest lists"][hostname] or {} + hostlist[guestname] = 1 + rspawn.playerspawns["guest lists"][hostname] = hostlist + + rspawn.playerspawns["original spawns"][guestname] = nil + end + end +end + +local function reconcile_guestlist_spawns() + local original_spawns = rspawn.playerspawns["original spawns"] + if not original_spawns then return + + for guestname,spawnpos in pairs(original_spawns) do + reconcile_guest(guestname, spawnpos) + rspawn.playerspawns[guestname] = spawnpos + end + + if #rspawn.playerspawns["original spawns"] == 0 then + rspawn.playerspawns["original spawns"] = nil + else + minetest.log("error", "Failed to reconcile all spawns") + end + + rspawn:spawnsave() +end + function rspawn:spawnsave() local serdata = minetest.serialize(rspawn.playerspawns) if not serdata then @@ -48,6 +86,7 @@ function rspawn:spawnload() rspawn.playerspawns["pre gen"] = pregens reconcile_original_spawns() + reconcile_guestlist_spawns() minetest.debug("Loaded rspawn data with "..tostring(#pregens).." pregen nodes") end diff --git a/lua/invites.lua b/lua/invites.lua index ed5fbb2..b9fc464 100644 --- a/lua/invites.lua +++ b/lua/invites.lua @@ -19,52 +19,9 @@ minetest.after(0,function() end end) -local function get_players(p1name, p2name) - -- Check both players are online. - -- It is easier to implement agains online players than to manage offline interactions - local err, p1, p2 - local errmsg_generic = " is not online." - - if not p1name then - minetest.log("error", "Missing p1name") - return nil,nil,"Internal error." - - elseif not p2name then - minetest.log("error", "Missing p2name") - return nil,nil,"Internal error." - end - - p1 = minetest.get_player_by_name(p1name) - p2 = minetest.get_player_by_name(p2name) - - if not p1 then err = p1name..errmsg_generic end - if not p2 then err = p2name..errmsg_generic end - - return p1,p2,err -end - -function rspawn.invites:invite_player_fromto(hostname, guestname) - local host,guest = get_players(hostname, guestname) - - if not (host and guest) then - minetest.chat_send_player(hostname, err or "player not online") - return - end - - if not rspawn.invitations[guestname] then - rspawn.invitations[guestname] = hostname - else - minetest.chat_send_player(hostname, guestname.." already has a pending invitation, and cannot be invited.") - return - end - - local hostspawn_s = minetest.pos_to_string(rspawn.playerspawns[hostname]) - - minetest.chat_send_player(guestname, hostname.." invited you to join their spawn point.\nIf you accept, your spawn point will be set to "..hostspawn_s.." and you will be taken there IMMEDIATELY.\nRun '/spawn accept' to accept, '/spawn decline' to decline and clear the invite.") - - minetest.chat_send_player(hostname, - "You have invited "..guestname.." to join your spawn.\nIf they accept, you will be charged \n\n "..levvy_qtty.." "..levvy_nicename.." \n\nwhich will be taken from your inventory." - ) +local function canvisit(hostname, guestname) + local glist = rspawn.playerspawns["guest lists"][hostname] or {} + return glist[guestname] == 1 end local function find_levvy(player) @@ -102,7 +59,7 @@ local function find_levvy(player) end end - minetest.chat_send_player(pname, "You do not have enough "..levvy_nicename.." to pay the spawn levvy for your invitaiton.") + minetest.chat_send_player(pname, "You do not have enough "..levvy_nicename.." to pay the spawn levvy for your invitation.") return false end @@ -145,45 +102,35 @@ function rspawn:consume_levvy(player) end function rspawn.invites:addplayer(hostname, guestname) - local guestlist = rspawn.guestlists[hostname] or {} - - if guestlist[guestname] ~= nil then - minetest.chat_send_player(hostname, guestname.." is already in your guest list.") - - elseif rspawn:consume_levvy(minetest.get_player_by_name(hostname) ) then -- Automatically notifies host if they don't have enough - guestlist[guestname] = 1 - rspawn.questlists[hostname] = guestlist - - minetest.chat_send_player(guestname, hostname.." added you to their spawn! You can now visit them with /spawn visit "..hostname) - end -end - -function rspawn.invites:exileplayer(hostname, guestname) - local guestlist = rspawn.guestlists[hostname] or {} - - if guestlist[guestname] == 1 then - guestlist[guestname] = 0 - rspawn.questlists[hostname] = guestlist - - minetest.chat_send_player(guestname, hostname.." has exiled you!") - else - minetest.chat_send_player(hostname, guestname.." is not in your accepted guests list.") - end -end - -function rspawn.invites:liftexileplayer(hostname, guestname) - local guestlist = rspawn.guestlists[hostname] or {} + local guestlist = rspawn.playerspawns["guest lists"][hostname] or {} if guestlist[guestname] == 0 then guestlist[guestname] = 1 - rspawn.questlists[hostname] = guestlist + minetest.chat_send_player(guestname, hostname.." let you back into their spawn.") - rspawn.invites:kick(hostname, guestname) - - minetest.chat_send_player(guestname, hostname.." has exiled you!") - else - minetest.chat_send_player(hostname, guestname.." is not in your exiled guests list.") + elseif rspawn:consume_levvy(minetest.get_player_by_name(hostname) ) then -- Automatically notifies host if they don't have enough + guestlist[guestname] = 1 + minetest.chat_send_player(guestname, hostname.." added you to their spawn! You can now visit them with /spawn visit "..hostname) end + + minetest.chat_send_player(hostname, guestname.." is allowed to visit your spawn.") + rspawn.playerspawns["guest lists"][hostname] = guestlist +end + +function rspawn.invites:exileplayer(hostname, guestname) + local guestlist = rspawn.playerspawns["guest lists"][hostname] or {} + + if guestlist[guestname] == 1 then + guestlist[guestname] = 0 + rspawn.playerspawns["guest lists"][hostname] = guestlist + + else + minetest.chat_send_player(hostname, guestname.." is not in your accepted guests list.") + return + end + + minetest.chat_send_player(guestname, hostname.." banishes you!") + rspawn.invites:kick(hostname, guestname) end function rspawn.invites:kick(hostname, guestname) @@ -199,7 +146,7 @@ end function rspawn.invites:listguests(hostname) local guests = "" - local guestlist = rspawn.guestlists[hostname] or {} + local guestlist = rspawn.playerspawns["guest lists"][hostname] or {} for guestname,status in pairs(guestlist) do if status == 1 then status = "" else status = " (exiled)" @@ -213,8 +160,8 @@ end function rspawn.invites:listhosts(guestname) local hosts = "" - for _,hostname in ipairs(rspawn.guestlists) do - for gname,status in pairs(rspawn.guestlists[hostname]) do + for _,hostname in ipairs(rspawn.playerspawns["guest lists"]) do + for gname,status in pairs(rspawn.playerspawns["guest lists"][hostname]) do if guestname == gname then if status == 1 then status = "" else status = " (exiled)" @@ -226,55 +173,14 @@ function rspawn.invites:listhosts(guestname) minetest.chat_send_player(guestname, hosts) end -function rspawn.invites:accept(guestname) - local hostname = rspawn.invitations[guestname] +function rspawn.invites:visitplayer(hostname, guestname) + local guest = minetest.get_player_by_name(guestname) + local hostpos = rspawn.playerspawns[hostname] - if not hostname then - minetest.chat_send_player(guestname, "No invitation to accept.") - return - end - - local host,guest = get_players(hostname, guestname) - - if not (host and guest) then - minetest.chat_send_player(guestname, err or "player not online") - return - end - - if rspawn:consume_levvy(minetest.get_player_by_name(hostname) ) then -- Systematically notifies host if they don't have enough - local hostspawn = rspawn.playerspawns[hostname] - rspawn:set_player_spawn(guestname, hostspawn) -- sets new spawn position, saves, teleports player - local success_message = " has accepted the spawn invitation from " - minetest.chat_send_player(guestname, guestname..success_message..hostname) - minetest.chat_send_player(hostname, guestname..success_message..hostname) - - minetest.chat_send_player(guestname, "You can return to your original spawn using '/spawn original' for \n\n "..levvy_qtty.." "..levvy_nicename.." \n\nwhich will be taken from your inventory.") - - else -- Host was notified, now notify guest - minetest.chat_send_player(guestname, hostname.." was unable to pay the levvy. Invitation could not be accepted.") - end -end - - -function rspawn.invites:decline(guestname) - local hostname = rspawn.invitations[guestname] - - if hostname then - rspawn.invitations[guestname] = nil - -- Player not online, message simply ignored. - minetest.chat_send_player(guestname, "Declined invitation to join "..hostname.."'s spawn for now.") - minetest.chat_send_player(hostname, guestname.." declined to join your spawn point for now.") + if guest and hostpos and canvisit(hostname, guestname) then + guest:setpos(hostpos) else - minetest.chat_send_player(guestname, "No invitation to decline.") - end -end - -function rspawn.invites:show_invite_for(guestname) - local hostname = rspawn.invitations[guestname] - - if hostname then - minetest.chat_send_player(guestname, "You have been invited to join "..hostname.." at "..minetest.pos_to_string(rspawn.playerspawns[hostname])) - else - minetest.chat_send_player(guestname, "No pending invitation.") + minetest.log("error", "[rspawn] Missing spawn position data for "..hostname) + minetest.chat_send_player(guestname, "Could not find spawn position for "..hostname) end end