Merge branch 'guestlists'

master
Tai Kedzierski 2019-01-24 00:12:44 +00:00
commit 7370847ebf
8 changed files with 283 additions and 300 deletions

View File

@ -36,11 +36,11 @@ rspawn.max_x = tonumber(minetest.settings:get("rspawn.max_x") or 31000)
rspawn.min_z = tonumber(minetest.settings:get("rspawn.min_z") or -31000)
rspawn.max_z = tonumber(minetest.settings:get("rspawn.max_z") or 31000)
dofile(mpath.."/src/data.lua")
dofile(mpath.."/src/invites.lua")
dofile(mpath.."/src/commands.lua")
dofile(mpath.."/src/forceload.lua")
dofile(mpath.."/src/debugging.lua")
dofile(mpath.."/lua/data.lua")
dofile(mpath.."/lua/invites.lua")
dofile(mpath.."/lua/commands.lua")
dofile(mpath.."/lua/forceload.lua")
dofile(mpath.."/lua/debugging.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
@ -233,4 +225,4 @@ minetest.register_on_respawnplayer(function(player)
end
end)
dofile(mpath.."/src/pregeneration.lua")
dofile(mpath.."/lua/pregeneration.lua")

View File

@ -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,48 +34,43 @@ 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 [<player>] | accept | decline | original ]",
description = "Teleport to your spawn, or manage guests in your spawn.",
params = "[ add <player> | visit <player> | kick <player> | guests | hosts ]",
privs = "spawn",
func = function(name, args)
local target = rspawn.playerspawns[name]
local args = splitstring(args, " ")
func = function(playername, args)
local target = rspawn.playerspawns[playername]
local args = args:split(" ")
if #args == 0 then
if target then
minetest.get_player_by_name(name):setpos(target)
minetest.get_player_by_name(playername):setpos(target)
return
else
minetest.chat_send_player(name, "You have no spawn position!")
minetest.chat_send_player(playername, "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'")
minetest.chat_send_player(playername, "Please check '/help spawn'")
end
})
@ -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 = "<playername> { new | <pos> | original | setoriginal | go }",
description = "Randomly select a new spawn position for a player, or use specified position, or go to their spawn.",
params = "<playername> { new | <pos> | 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

View File

@ -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,39 @@ local function reconcile_original_spawns()
rspawn:spawnsave()
end
local function reconcile_guest(guestname, guestspawn)
for hostname,hostspawn in pairs(rspawn.playerspawns) do
if hostname ~= "guest lists" and hostname ~= guestname and hostspawn == guestspawn then
local hostlist = rspawn.playerspawns["guest lists"][hostname] or {}
hostlist[guestname] = 1
rspawn.playerspawns["guest lists"][hostname] = hostlist
end
end
end
local function reconcile_guestlist_spawns()
if not rspawn.playerspawns["guest lists"] then rspawn.playerspawns["guest lists"] = {} end
for guestname,spawnpos in pairs(rspawn.playerspawns) do
reconcile_guest(guestname, spawnpos)
if rspawn.playerspawns["original spawns"][guestname] then
rspawn.playerspawns[guestname] = rspawn.playerspawns["original spawns"][guestname]
rspawn.playerspawns["original spawns"][guestname] = nil
else
minetest.debug("Could not return "..guestname)
end
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 +89,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

198
lua/invites.lua Normal file
View File

@ -0,0 +1,198 @@
rspawn.invites = {}
-- invitations[guest] = host
rspawn.invitations = {}
local invite_charge = {}
levvy_name = minetest.settings:get("rspawn.levvy_name") or "default:cobble"
levvy_qtty = tonumber(minetest.settings:get("rspawn.levvy_qtty")) or 10
levvy_nicename = "cobblestone"
minetest.after(0,function()
if minetest.registered_items[levvy_name] then
levvy_nicename = minetest.registered_nodes[levvy_name].description
else
minetest.debug("No such item "..levvy_name.." -- reverting to defaults.")
levvy_name = "default:cobble"
levvy_qtty = 99
end
end)
local function canvisit(hostname, guestname)
minetest.debug(dump(rspawn.playerspawns["guest lists"]))
local glist = rspawn.playerspawns["guest lists"][hostname] or {}
return glist[guestname] == 1
end
local function find_levvy(player)
-- return itemstack index, and stack itself, with qtty removed
-- or none if not found/not enough found
local i
if not player then
minetest.log("action", "Tried to access undefined player")
return false
end
local pname = player:get_player_name()
local player_inv = minetest.get_inventory({type='player', name = pname})
local total_count = 0
if not player_inv then
minetest.log("action", "Could not access inventory for "..pname)
return false
end
for i = 1,32 do
local itemstack = player_inv:get_stack('main', i)
local itemname = itemstack:get_name()
if itemname == levvy_name then
if itemstack:get_count() >= levvy_qtty then
return true
else
total_count = total_count + itemstack:get_count()
if total_count >= (levvy_qtty) then
return true
end
end
end
end
minetest.chat_send_player(pname, "You do not have enough "..levvy_nicename.." to pay the spawn levvy for your invitation.")
return false
end
function rspawn:consume_levvy(player)
if not player then
minetest.log("action", "Tried to access undefined player")
return false
end
local i
local pname = player:get_player_name()
local player_inv = minetest.get_inventory({type='player', name = pname})
local total_count = 0
-- TODO combine find_levvy and consume_levvy so that we're
-- not scouring the inventory twice...
if find_levvy(player) then
for i = 1,32 do
local itemstack = player_inv:get_stack('main', i)
local itemname = itemstack:get_name()
if itemname == levvy_name then
if itemstack:get_count() >= levvy_qtty then
itemstack:take_item(levvy_qtty)
player_inv:set_stack('main', i, itemstack)
return true
else
total_count = total_count + itemstack:get_count()
itemstack:clear()
player_inv:set_stack('main', i, itemstack)
if total_count >= (levvy_qtty) then
return true
end
end
end
end
end
return false
end
function rspawn.invites:addplayer(hostname, guestname)
local guestlist = rspawn.playerspawns["guest lists"][hostname] or {}
if guestlist[guestname] ~= nil then
if guestlist[guestname] == 0 then
minetest.chat_send_player(guestname, hostname.." let you back into their spawn.")
end
guestlist[guestname] = 1
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)
else
return
end
minetest.chat_send_player(hostname, guestname.." is allowed to visit your spawn.")
rspawn.playerspawns["guest lists"][hostname] = guestlist
rspawn:spawnsave()
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)
rspawn:spawnsave()
end
function rspawn.invites:kick(hostname, guestname)
local guest = minetest.get_player_by_name(guestname)
local guestpos = guest:getpos()
local hostspawnpos = rspawn.playerspawns[hostname]
local guestspawnpos = rspawn.playerspawns[guestname]
if vector.distance(guestpos, hostspawnpos) < 32 then
guest:setpos(guestspawnpos)
end
end
function rspawn.invites:listguests(hostname)
local guests = ""
local guestlist = rspawn.playerspawns["guest lists"][hostname] or {}
for guestname,status in pairs(guestlist) do
if status == 1 then status = "" else status = " (exiled)" end
guests = guests..", "..guestname..status
end
minetest.chat_send_player(hostname, guests:sub(3))
end
function rspawn.invites:listhosts(guestname)
local hosts = ""
for hostname,hostguestlist in pairs(rspawn.playerspawns["guest lists"]) do
for gname,status in pairs(hostguestlist) do
if guestname == gname then
if status == 1 then status = "" else status = " (exiled)" end
hosts = hosts..", "..hostname..status
end
end
end
minetest.chat_send_player(guestname, hosts:sub(3))
end
function rspawn.invites:visitplayer(hostname, guestname)
local guest = minetest.get_player_by_name(guestname)
local hostpos = rspawn.playerspawns[hostname]
if not hostpos then
minetest.log("error", "[rspawn] Missing spawn position data for "..hostname)
minetest.chat_send_player(guestname, "Could not find spawn position for "..hostname)
end
if guest and canvisit(hostname, guestname) then
guest:setpos(hostpos)
else
minetest.chat_send_player(guestname, "Could not visit "..hostname)
end
end

View File

@ -1,199 +0,0 @@
rspawn.invites = {}
-- invitations[guest] = host
rspawn.invitations = {}
local invite_charge = {}
levvy_name = minetest.settings:get("rspawn.levvy_name") or "default:cobble"
levvy_qtty = tonumber(minetest.settings:get("rspawn.levvy_qtty")) or 10
levvy_nicename = "cobblestone"
minetest.after(0,function()
if minetest.registered_items[levvy_name] then
levvy_nicename = minetest.registered_nodes[levvy_name].description
else
minetest.debug("No such item "..levvy_name.." -- reverting to defaults.")
levvy_name = "default:cobble"
levvy_qtty = 99
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."
)
end
local function find_levvy(player)
-- return itemstack index, and stack itself, with qtty removed
-- or none if not found/not enough found
local i
if not player then
minetest.log("action", "Tried to access undefined player")
return false
end
local pname = player:get_player_name()
local player_inv = minetest.get_inventory({type='player', name = pname})
local total_count = 0
if not player_inv then
minetest.log("action", "Could not access inventory for "..pname)
return false
end
for i = 1,32 do
local itemstack = player_inv:get_stack('main', i)
local itemname = itemstack:get_name()
if itemname == levvy_name then
if itemstack:get_count() >= levvy_qtty then
return true
else
total_count = total_count + itemstack:get_count()
if total_count >= (levvy_qtty) then
return true
end
end
end
end
minetest.chat_send_player(pname, "You do not have enough "..levvy_nicename.." to pay the spawn levvy for your invitaiton.")
return false
end
function rspawn:consume_levvy(player)
if not player then
minetest.log("action", "Tried to access undefined player")
return false
end
local i
local pname = player:get_player_name()
local player_inv = minetest.get_inventory({type='player', name = pname})
local total_count = 0
-- TODO combine find_levvy and consume_levvy so that we're
-- not scouring the inventory twice...
if find_levvy(player) then
for i = 1,32 do
local itemstack = player_inv:get_stack('main', i)
local itemname = itemstack:get_name()
if itemname == levvy_name then
if itemstack:get_count() >= levvy_qtty then
itemstack:take_item(levvy_qtty)
player_inv:set_stack('main', i, itemstack)
return true
else
total_count = total_count + itemstack:get_count()
itemstack:clear()
player_inv:set_stack('main', i, itemstack)
if total_count >= (levvy_qtty) then
return true
end
end
end
end
end
return false
end
function rspawn.invites:accept(guestname)
local hostname = rspawn.invitations[guestname]
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.")
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.")
end
end