Added Waypoints & Limits

Limits:
   Players can now be governed by how many total homes they can place
   Default values are:
    Basic = 2
    Advanced = 4
    Super = 8
    Unlimited = inf
   Where Basic is default for singleplayer modes (ie given by default)

  Waypoints:
   Players can now choose what homes become visable via a waypoint.
   THIS FEATURE REQUIRES MINETEST VERSION 5.0 OR HIGHER
   Removing a home that has been "marked" as a waypoint also will remove
the waypoint
   Setting a home to a new location will update the waypoint to the new
location
   The api for waypoints has been reworked to support golang-like
function responses (success, errmsg, value)
   Waypoints currently use (0, 200, 0) RGB values 0x0c800 in HEX

  This mod is ready to prepare for release onto contentdb. (v1.0)
This commit is contained in:
Apollo 2022-05-24 17:22:24 -04:00
parent aaf8a920ef
commit 5106eb4eb1
5 changed files with 363 additions and 19 deletions

View File

@ -1,16 +1,44 @@
# home_point
A /sethome and /home mod for Minetest
A multi homes teleport feature.
## CMDs
## Commands
All commands require `home_point` priviledge
All commands require `home_point` privilege (And `/sh` needs one of the further privileges, See Limiting homes section below)
* `/h (place_name)` Goes to a place called place_name unless not given then your player name is used.
* `/sh (place_name)` Saves a place called place_name unless not given then your player name is used.
* `/rh (place_name)` Removes a place called place_name unless not given then your player name is used.
* `/lh` Lists all your homes, if you don't have any it will tell you how to make one.
* `/wh (place_name)` Places a waypoint at the designated home till you log-out/quit, if place_name not given then your player name is used.
> `/wh` actually toggles a waypoint, and when `/sh` is used with the same home as a waypoint a new waypoint will be place at the new location. (Also when `/rh` is used on a home with a waypoint the waypoint will be removed)
## Notice
This mod uses mod storage... this means if the server crashes the mod will lose a few home points.
This mod uses mod storage... this means if the server crashes the mod could lose a few home points.
## Limiting homes
There are 4 default privileges which are defined in settings.
All these do is limit the number of home_points players can set.
> (For servers) This means you need to add `home_point` and at least `home_point_basic` to your default_privs in minetest.conf,
so new players can at least use home_point. (See [here](https://github.com/minetest/minetest/blob/master/builtin/settingtypes.txt#L1166) for info on default_privs in minetest.conf)
### home_point_basic
Defaults to max of 2 homes (Change with `home_point.home_point_basic` in settings)
### home_point_advanced
Defaults to max of 4 homes (Change with `home_point.home_point_advanced` in settings)
### home_point_super
Defaults to max of 8 homes (Change with `home_point.home_point_super` in settings)
### home_point_unlimited
Allows unlimited number of homes (Not defined in settings, as unlimited is assumed to be unlimited)

174
init.lua
View File

@ -4,9 +4,10 @@ local modpath = minetest.get_modpath("home_point")
home_point = {}
home_point.storage = minetest.get_mod_storage()
home_point.temp = {} -- Used to track who has what waypoints set for what homes
-- Actually it's our api so if someone else wanted to monkey with points they can
dofile(modpath.."/store_base.lua")
dofile(modpath..DIR_DELIM.."store_base.lua")
-- Assistants
function home_point.firstToUpper(str)
@ -24,7 +25,29 @@ function home_point.split(inputstr, sep)
return t
end
minetest.register_privilege("home_point", "Gives access to home point")
dofile(modpath..DIR_DELIM.."settings.lua")
minetest.register_privilege("home_point", {
description = "Gives access to home point commands",
give_to_singleplayer = true -- This should mean in singleplayer you start off with the defaults
})
minetest.register_privilege("home_point_basic", {
description = "Gives access upto "..tostring(home_point.home_point_basic).." homes",
give_to_singleplayer = true -- This should mean in singleplayer you start off with the defaults
})
minetest.register_privilege("home_point_advanced", {
description = "Gives access upto "..tostring(home_point.home_point_advanced).." homes",
give_to_singleplayer = false
})
minetest.register_privilege("home_point_super", {
description = "Gives access upto "..tostring(home_point.home_point_super).." homes",
give_to_singleplayer = false
})
minetest.register_privilege("home_point_unlimited", {
description= "Gives access to unlimited homes",
give_to_singleplayer = false
})
-- Set home
minetest.register_chatcommand("sh", {
@ -37,13 +60,63 @@ minetest.register_chatcommand("sh", {
if name ~= "singleplayer" then
if minetest.get_player_by_name(name) == nil then return false, "You must be online to use this command" end
end
-- Ensure we stop users from placing unlimited homes when they are not allowed to
local homes = home_point.count(name)
if not minetest.check_player_privs(name, {home_point_unlimited=true}) then
if minetest.check_player_privs(name, {home_point_super=true}) then
if homes+1 > home_point.home_point_super then
return false, "You can only have "..tostring(home_point.home_point_super).." homes, currently you have "..tostring(homes).."."
end
elseif minetest.check_player_privs(name, {home_point_advanced=true}) then
if homes+1 > home_point.home_point_basic then
return false, "You can only have "..tostring(home_point.home_point_advanced).." homes, currently you have "..tostring(homes).."."
end
elseif minetest.check_player_privs(name, {home_point_basic=true}) then
if homes+1 > home_point.home_point_basic then
return false, "You can only have "..tostring(home_point.home_point_basic).." homes, currently you have "..tostring(homes).."."
end
else
return false, "You appear to not have access to place any homes, You need home_point and one of these (home_point_basic, home_point_advanced, home_point_super, or home_point_unlimited)."
end
end
-- Setup the place/home
local place = string.match(param, "^([%a%d_-]+)") or ""
if place ~= "" then
minetest.log("action", "[home_point] "..name.." saves a point as '"..place.."'")
return home_point.save(name, place), "Saved as "..place
local rc = home_point.save(name, place)
-- Update a waypoints position if we are showing that home
local is_way = home_point.waypoint_is(name, place)
if is_way.success == true and is_way.value ~= -1 then
local pl = home_point.place_waypoint(name, place)
if pl.success ~= true then
minetest.log("action", "[home_point] Err="..pl.errmsg.." Val="..minetest.serialize(pl.value))
end
pl = home_point.place_waypoint(name, place)
if pl.success ~= true then
minetest.log("action", "[home_point] Err="..pl.errmsg.." Val="..minetest.serialize(pl.value))
end
else
minetest.log("action", "[home_point] Err="..is_way.errmsg.." Val="..minetest.serialize(is_way.value))
end
return rc, "Saved as "..place
else
minetest.log("action", "[home_point] "..name.." saves a point as '"..name.."'")
return home_point.save(name, name), "Saved as "..name
local rc = home_point.save(name, name)
-- Update a waypoints position if we are showing that home
local is_way = home_point.waypoint_is(name, name)
if is_way.success == true and is_way.value ~= -1 then
local pl = home_point.place_waypoint(name, name)
if pl.success ~= true then
minetest.log("action", "[home_point] Err="..pl.errmsg.." Val="..minetest.serialize(pl.value))
end
pl = home_point.place_waypoint(name, name)
if pl.success ~= true then
minetest.log("action", "[home_point] Err="..pl.errmsg.." Val="..minetest.serialize(pl.value))
end
else
minetest.log("action", "[home_point] Err="..is_way.errmsg.." Val="..minetest.serialize(is_way.value))
end
return rc, "Saved as "..name
end
return false, "Uable to determine place_name"
end,
@ -94,15 +167,41 @@ minetest.register_chatcommand("rh", {
if minetest.get_player_by_name(name) == nil then return false, "You must be online to use this command" end
end
local place = string.match(param, "^([%a%d_-]+)") or ""
local target = nil
local resp = ""
if place ~= "" then
home_point.remove(name, place)
minetest.log("action", "[home_point] "..name.." removes home of '"..place.."'")
minetest.chat_send_player(name, ""..place.." removed")
--minetest.chat_send_player(name, ""..place.." removed")
resp = place.." removed"
-- Remove waypoints from deleted homes
local is_way = home_point.waypoint_is(name, place)
if is_way.success and is_way.value ~= -1 then
local place_way = home_point.place_waypoint(name, place)
if place_way.success == true then
minetest.log("action", "[home_point] "..name.." removed waypoint at '"..place.."'")
else
minetest.log("action", "[home_point] Err="..place_way.errmsg.." Val="..minetest.serialize(place_way.value))
end
end
if home_point.remove(name, place) then
minetest.chat_send_player(name, reps)
end
else
home_point.remove(name, name)
minetest.log("action", "[home_point] "..name.." removes home of '"..name.."'")
minetest.chat_send_player(name, ""..name.." removed")
--minetest.chat_send_player(name, ""..name.." removed")
resp = name.." removed"
-- Remove waypoints from deleted homes
local is_way = home_point.waypoint_is(name, name)
if is_way.success and is_way.value ~= -1 then
local place_way = home_point.place_waypoint(name, name)
if place_way.success == true then
minetest.log("action", "[home_point] "..name.." removed waypoint at '"..name.."'")
else
minetest.log("action", "[home_point] Err="..place_way.errmsg.." Val="..minetest.serialize(place_way.value))
end
end
if home_point.remove(name, name) then
minetest.chat_send_player(name, reps)
end
end
end,
})
@ -119,11 +218,20 @@ minetest.register_chatcommand("lh", {
if minetest.get_player_by_name(name) == nil then return false, "You must be online to use this command" end
end
local list = home_point.list(name)
if list ~= nil then
local r = "Homes: " .. tostring(#list+1) .. "\n"
if list ~= nil and home_point.count(name) ~= 0 then
--minetest.log("action", "[home_point] "..type(list).." "..minetest.serialize(list).." "..tostring(#list))
local r = "Homes: " .. tostring(home_point.count(name)) .. "\n"
for k in pairs(list) do
local pos = list[k].split(list[k], " ")
r = r .. " " .. k .. " (" .. pos[1] .. ", " .. pos[2] .. ", " .. pos[3] .. ")\n"
local is_way = home_point.waypoint_is(name, k)
if is_way.success == false then
minetest.log("action", "[home_point] Err="..is_way.errmsg.." Val="..minetest.serialize(is_way.value))
end
if is_way.success == true and is_way.value ~= -1 then
r = r .. " " .. k .. " (" .. pos[1] .. ", " .. pos[2] .. ", " .. pos[3] .. ") *\n"
else
r = r .. " " .. k .. " (" .. pos[1] .. ", " .. pos[2] .. ", " .. pos[3] .. ")\n"
end
end
return true, r
else
@ -132,4 +240,46 @@ minetest.register_chatcommand("lh", {
end,
})
-- Toggle waypoint on home
minetest.register_chatcommand("wh", {
privs = {
home_point = true
},
description = "Toggles a waypoint at a home point",
func = function (name, param)
-- Don't allow offline players
if name ~= "singleplayer" then
if minetest.get_player_by_name(name) == nil then return false, "You must be online to use this command" end
end
local place = string.match(param, "^([%a%d_-]+)") or ""
if home_point.count(name) ~= 0 then
if place ~= "" then
if home_point.get(name, place) ~= "" then
local rc = home_point.place_waypoint(name, place)
if rc.success == true then
minetest.log("action", "[home_point] "..name.." "..rc.errmsg.." at "..place.." '"..home_point.get(name, place).."'")
minetest.chat_send_player(name, rc.errmsg.." at "..place)
else
minetest.log("action", "[home_point] Err="..rc.errmsg.." Val="..minetest.serialize(rc.value))
end
else
minetest.chat_send_player(name, "No such home point "..place)
end
else
if home_point.get(name, name) ~= "" then
local rc = home_point.place_waypoint(name, name)
if rc.success == true then
minetest.log("action", "[home_point] "..name.." "..rc.errmsg.." at "..name.." '"..home_point.get(name, name).."'")
minetest.chat_send_player(name, rc.errmsg.." at "..name)
else
minetest.log("action", "[home_point] Err="..rc.errmsg.." Val="..minetest.serialize(rc.value))
end
end
end
else
minetest.chat_send_player(name, "You don't have any homes yet, use /sh <home_name> to place a home.")
end
end
})
minetest.log("action", "[home_point] Ready")

25
settings.lua Normal file
View File

@ -0,0 +1,25 @@
home_point.home_point_basic = minetest.settings:get("home_point.home_point_basic")
if home_point.home_point_basic == nil then
home_point.home_point_basic = 2
minetest.settings:set("home_point.home_point_basic", 2)
else
home_point.home_point_basic = tonumber(home_point.home_point_basic)
end
home_point.home_point_advanced = minetest.settings:get("home_point.home_point_advanced")
if home_point.home_point_advanced == nil then
home_point.home_point_advanced = 4
minetest.settings:set("home_point.home_point_advanced", 4)
else
home_point.home_point_advanced = tonumber(home_point.home_point_advanced)
end
home_point.home_point_super = minetest.settings:get("home_point.home_point_super")
if home_point.home_point_super == nil then
home_point.home_point_super = 8
minetest.settings:set("home_point.home_point_super", 8)
else
home_point.home_point_super = tonumber(home_point.home_point_super)
end

9
settingtypes.txt Normal file
View File

@ -0,0 +1,9 @@
# Limits how many homes basic users can use
home_point.home_point_basic (Home Point Basic) int 2
# Limits how many homes advanced users can use
home_point.home_point_advanced (Home Point Advanced) int 4
# Limits how many homes super users can use
home_point.home_point_super (Home Point Super) int 8

View File

@ -6,11 +6,11 @@ function home_point.save(pname, place_name)
-- If the player really is a player
if p ~= nil then
-- Get their position and convert it to string
local pos = p:get_pos()
pos = "".. math.floor(pos.x) .." ".. math.floor(pos.y+1) .." ".. math.floor(pos.z)
local pos = vector.round(p:get_pos())
pos = "".. pos.x .." ".. pos.y+1 .." ".. pos.z
-- Obtain the player's homes update/insert then update the mods storage
local tmp = minetest.deserialize(home_point.storage:get_string(pname)) or {}
tmp[place_name] = pos
tmp[place_name] = pos
home_point.storage:set_string(pname, minetest.serialize(tmp))
return true
end
@ -46,14 +46,19 @@ function home_point.remove(pname, place_name)
if tmp ~= nil then
-- Make a new table and add all except selected place
local new = {}
local found = false
for k in pairs(tmp) do
if k ~= place_name then
new[k] = tmp[k]
else
found = true
end
end
home_point.storage:set_string(pname, minetest.serialize(new))
return found
end
end
return false
end
-- Returns list of home and position for a player
@ -62,4 +67,131 @@ function home_point.list(pname)
if p ~= nil then
return minetest.deserialize(home_point.storage:get_string(pname))
end
return {}
end
-- Returns the actual count/number of homes
function home_point.count(pname)
local home_count = 0
local p = minetest.get_player_by_name(pname) or nil
if p ~= nil then
local list = home_point.list(pname)
if list ~= nil then
for k in pairs(list) do
home_count = home_count + 1
end
end
end
return home_count
end
-- Waypoints are temporary, as in when the user quits/logs out I need to clear them from the temp list
-- Do we have a waypoint hud id for the given home point?
function home_point.waypoint_is(pname, home)
if home_point.get(pname, home) ~= "" then
local waypoints = home_point.temp[pname] or {}
--minetest.log("action", minetest.serialize(waypoints))
for _, way in pairs(waypoints) do
local way_name = way[1]
local way_hid = way[2]
--minetest.log("action", "[home_point.waypoint_is] way_name='"..way_name.."' way_hid="..tostring(way_hid))
if way_name == home then
return {success=true, errmsg="", value=way_hid}
end
end
return {success=true, errmsg="Home point '"..home.."' doesn't have a waypoint set.", value=-1}
else
return {success=false, errmsg="No such home point '"..home.."'.", value=nil}
end
end
-- Adds the given hud id to the given home point
function home_point.waypoint_add(pname, home, hud_id)
if home_point.get(pname, home) ~= "" then
local waypoints = home_point.temp[pname] or {}
local tab = {}
table.insert(tab, home)
table.insert(tab, hud_id)
table.insert(waypoints, tab)
home_point.temp[pname] = waypoints
return {success=true, errmsg="", value=tab}
else
return {success=false, errmsg="No such home point '"..home.."'", value=nil}
end
end
function home_point.waypoint_remove(pname, home)
if home_point.get(pname, home) ~= "" then
local waypoints = home_point.temp[pname] or {}
local new_waypoints = {}
for _, way in pairs(waypoints) do
local way_name = way[1]
local way_hid = way[2]
--minetest.log("action", "[home_point.waypoint_remove] way_name='"..way_name.."' way_hid="..tostring(way_hid))
if way_name ~= home then
local tab = {}
table.insert(tab, way_name)
table.insert(tab, way_hid)
table.insert(new_waypoints, tab)
end
end
home_point.temp[pname] = new_waypoints
return {success=true, errmsg="", value=nil}
else
return {success=false, errmsg="No such home point '"..home.."'", value=nil}
end
end
function home_point.place_waypoint(pname, home)
if home_point.get(pname, home) ~= "" then
-- Obtain the actual pos
local raw_pos = home_point.split(home_point.get(pname, home), " ")
local pos = {x=tonumber(raw_pos[1]), y=tonumber(raw_pos[2]), z=tonumber(raw_pos[3])}
local player = minetest.get_player_by_name(pname)
local is_way = home_point.waypoint_is(pname, home)
if is_way.success == true then
if is_way.value ~= -1 then
-- Remove
local rm = home_point.waypoint_remove(pname, home)
if rm.success ~= true then
return {success=false, errmsg="home_point.waypoint_remove returned error", value=rm}
else
player:hud_remove(is_way.value)
return {success=true, errmsg="Removed waypoint", value=nil}
end
else
-- Add
local add = home_point.waypoint_add(pname, home, player:hud_add({
hud_elem_type = "waypoint",
world_pos = vector.subtract(pos, {x=0, y=1, z=0}),
name = home,
number = 0x00c800
}))
if add.success ~= true then
return {success=false, errmsg="home_point.waypoint_add returned error", value=add}
else
return {success=true, errmsg="Created waypoint", value=add.value}
end
end
else
return {success=false, errmsg="home_point.waypoint_is returned error", value=is_way}
end
else
return {success=false, errmsg="No such home point '"..home.."'", value=nil}
end
end
minetest.register_on_leaveplayer(function(player)
local pname = player:get_player_name()
if home_point.temp[pname] ~= nil then
local new = {}
for name, tab in pairs(home_point.temp) do
if name ~= pname then
new[name] = tab
end
end
home_point.temp = new
end
end)