Add bed.is_valid_bed; make bed API public for real

This commit is contained in:
Wuzzy 2024-03-23 11:12:39 +01:00
parent eef9bbc5d5
commit 1cdd1e2081
3 changed files with 76 additions and 43 deletions

View File

@ -48,7 +48,7 @@ Mods with documented APIs:
* `rp_armor`: Armor information * `rp_armor`: Armor information
* `rp_achievements`: Add and trigger achievements * `rp_achievements`: Add and trigger achievements
* `rp_bed`: Get, set and unset (re)spawn position * `rp_bed`: Get, set and unset (re)spawn position; query bed info
* `rp_crafting`: Add crafting recipes * `rp_crafting`: Add crafting recipes
* `rp_default`: Sapling helpers, biome information * `rp_default`: Sapling helpers, biome information
* `rp_door`: Add doors * `rp_door`: Add doors

View File

@ -1,6 +1,7 @@
# API documentation for `rp_bed` # API documentation for `rp_bed`
This simple API allows setting some stuff related to (re)spawning. This simple API allows setting some stuff related to (re)spawning
and also query info about the bed itself.
## Function reference ## Function reference
@ -21,3 +22,15 @@ it's already used by the player.
Clears the bed (re)spawn position of `player`. The player will respawn Clears the bed (re)spawn position of `player`. The player will respawn
according to the default Minetest rules. according to the default Minetest rules.
### `bed.is_valid_bed(pos)`
Returns true if the node at `pos` is part of a valid bed.
A bed is valid if:
* It consists of 2 nodes, a 'head' and a 'foot'
* Both nodes 'connect' to each other to form a complete bed
* Both nodes have the same `param2`
Single 'bed' nodes (without a matching other piece) count as invalid.

View File

@ -5,26 +5,26 @@
local S = minetest.get_translator("rp_bed") local S = minetest.get_translator("rp_bed")
local bed = {} bed = {}
local DEFAULT_BED_COLOR = rp_paint.COLOR_AZURE_BLUE local DEFAULT_BED_COLOR = rp_paint.COLOR_AZURE_BLUE
-- Per-user data table -- Per-user data table
bed.userdata = {} local bed_userdata = {}
bed.userdata.saved = {} bed_userdata.saved = {}
bed.userdata.temp = {} bed_userdata.temp = {}
-- List of occupied beds, indexed by node position hash -- List of occupied beds, indexed by node position hash
bed.occupied_beds = {} local occupied_beds = {}
-- Returns <spawn position> of `player` or -- Returns <spawn position> of `player` or
-- nil if if there is no spawn active -- nil if if there is no spawn active
bed.get_spawn = function(player) bed.get_spawn = function(player)
local name = player:get_player_name() local name = player:get_player_name()
local spawn local spawn
if bed.userdata.saved[name].spawn_pos then if bed_userdata.saved[name].spawn_pos then
spawn = bed.userdata.saved[name].spawn_pos spawn = bed_userdata.saved[name].spawn_pos
end end
return spawn return spawn
end end
@ -35,11 +35,11 @@ end
-- it's already used by the player. -- it's already used by the player.
bed.set_spawn = function(player, spawn_pos) bed.set_spawn = function(player, spawn_pos)
local name = player:get_player_name() local name = player:get_player_name()
local old_spawn_pos = bed.userdata.saved[name].spawn_pos local old_spawn_pos = bed_userdata.saved[name].spawn_pos
if old_spawn_pos and vector.equals(spawn_pos, old_spawn_pos) then if old_spawn_pos and vector.equals(spawn_pos, old_spawn_pos) then
return false return false
end end
bed.userdata.saved[name].spawn_pos = table.copy(spawn_pos) bed_userdata.saved[name].spawn_pos = table.copy(spawn_pos)
minetest.log("action", "[rp_bed] Respawn position of "..name.." set to "..minetest.pos_to_string(spawn_pos, 1)) minetest.log("action", "[rp_bed] Respawn position of "..name.." set to "..minetest.pos_to_string(spawn_pos, 1))
return true return true
end end
@ -47,7 +47,27 @@ end
-- Unsets the bed spawn position of `player` -- Unsets the bed spawn position of `player`
bed.unset_spawn = function(player) bed.unset_spawn = function(player)
local name = player:get_player_name() local name = player:get_player_name()
bed.userdata.saved[name].spawn_pos = nil bed_userdata.saved[name].spawn_pos = nil
end
-- Returns true if pos has a valid bed
bed.is_valid_bed = function(pos)
local node = minetest.get_node(pos)
local dir = minetest.fourdir_to_dir(node.param2)
if node.name == "rp_bed:bed_head" then
local neighbor = vector.subtract(pos, dir)
local nnode = minetest.get_node(neighbor)
if nnode.name == "rp_bed:bed_foot" and nnode.param2 == node.param2 then
return true
end
elseif node.name == "rp_bed:bed_foot" then
local neighbor = vector.add(pos, dir)
local nnode = minetest.get_node(neighbor)
if nnode.name == "rp_bed:bed_head" and nnode.param2 == node.param2 then
return true
end
end
return false
end end
-- Savefile -- Savefile
@ -79,14 +99,14 @@ end
-- Returns name of player in bed at pos or nil if not occupied -- Returns name of player in bed at pos or nil if not occupied
local function get_player_in_bed(pos) local function get_player_in_bed(pos)
local hash = minetest.hash_node_position(pos) local hash = minetest.hash_node_position(pos)
local playername = bed.occupied_beds[hash] local playername = occupied_beds[hash]
return playername return playername
end end
-- Assign a player to the bed at pos. -- Assign a player to the bed at pos.
-- If playername==nil, bed will be unassigned. -- If playername==nil, bed will be unassigned.
local function set_bed_occupier(pos, playername) local function set_bed_occupier(pos, playername)
local hash = minetest.hash_node_position(pos) local hash = minetest.hash_node_position(pos)
bed.occupied_beds[hash] = playername occupied_beds[hash] = playername
end end
local function put_player_in_bed(player) local function put_player_in_bed(player)
@ -96,11 +116,11 @@ local function put_player_in_bed(player)
local name = player:get_player_name() local name = player:get_player_name()
if not is_bed_node(bed.userdata.temp[name].node_pos) then if not is_bed_node(bed_userdata.temp[name].node_pos) then
return return
end end
player:set_pos(bed.userdata.temp[name].sleep_pos) player:set_pos(bed_userdata.temp[name].sleep_pos)
player_effects.apply_effect(player, "inbed") player_effects.apply_effect(player, "inbed")
@ -125,11 +145,11 @@ local function clear_bed_status(player)
end end
local name = player:get_player_name() local name = player:get_player_name()
bed.userdata.temp[name].in_bed = false bed_userdata.temp[name].in_bed = false
if bed.userdata.temp[name].node_pos then if bed_userdata.temp[name].node_pos then
set_bed_occupier(bed.userdata.temp[name].node_pos, nil) set_bed_occupier(bed_userdata.temp[name].node_pos, nil)
end end
bed.userdata.temp[name].node_pos = nil bed_userdata.temp[name].node_pos = nil
player_effects.remove_effect(player, "inbed") player_effects.remove_effect(player, "inbed")
@ -152,7 +172,7 @@ local function take_player_from_bed(player)
end end
local name = player:get_player_name() local name = player:get_player_name()
local was_in_bed = bed.userdata.temp[name].in_bed == true local was_in_bed = bed_userdata.temp[name].in_bed == true
if was_in_bed then if was_in_bed then
minetest.log("action", "[rp_bed] "..name.." was taken from bed") minetest.log("action", "[rp_bed] "..name.." was taken from bed")
end end
@ -167,7 +187,7 @@ end
local function save_bed() local function save_bed()
local f = io.open(bed_file, "w") local f = io.open(bed_file, "w")
f:write(minetest.serialize(bed.userdata.saved)) f:write(minetest.serialize(bed_userdata.saved))
io.close(f) io.close(f)
@ -186,7 +206,7 @@ local function load_bed()
local f = io.open(bed_file, "r") local f = io.open(bed_file, "r")
if f then if f then
bed.userdata.saved = minetest.deserialize(f:read("*all")) bed_userdata.saved = minetest.deserialize(f:read("*all"))
io.close(f) io.close(f)
else else
@ -211,12 +231,12 @@ end
local function on_joinplayer(player) local function on_joinplayer(player)
local name = player:get_player_name() local name = player:get_player_name()
if not bed.userdata.saved[name] then if not bed_userdata.saved[name] then
bed.userdata.saved[name] = { bed_userdata.saved[name] = {
spawn_pos = nil, spawn_pos = nil,
} }
end end
bed.userdata.temp[name] = { bed_userdata.temp[name] = {
in_bed = false, in_bed = false,
node_pos = nil, node_pos = nil,
sleep_pos = nil, sleep_pos = nil,
@ -228,12 +248,12 @@ end
local function on_leaveplayer(player) local function on_leaveplayer(player)
local name = player:get_player_name() local name = player:get_player_name()
if bed.userdata.temp[name] then if bed_userdata.temp[name] then
bed.userdata.temp[name].in_bed = false bed_userdata.temp[name].in_bed = false
if bed.userdata.temp[name].node_pos then if bed_userdata.temp[name].node_pos then
set_bed_occupier(bed.userdata.temp[name].node_pos, nil) set_bed_occupier(bed_userdata.temp[name].node_pos, nil)
end end
bed.userdata.temp[name].node_pos = nil bed_userdata.temp[name].node_pos = nil
end end
end end
@ -347,12 +367,12 @@ end
local function on_dieplayer(player) local function on_dieplayer(player)
local name = player:get_player_name() local name = player:get_player_name()
if bed.userdata.temp[name] then if bed_userdata.temp[name] then
bed.userdata.temp[name].in_bed = false bed_userdata.temp[name].in_bed = false
if bed.userdata.temp[name].node_pos then if bed_userdata.temp[name].node_pos then
set_bed_occupier(bed.userdata.temp[name].node_pos, nil) set_bed_occupier(bed_userdata.temp[name].node_pos, nil)
end end
bed.userdata.temp[name].node_pos = nil bed_userdata.temp[name].node_pos = nil
end end
end end
@ -370,7 +390,7 @@ local function on_globalstep(dtime)
local sleeping_players = 0 local sleeping_players = 0
local in_bed = {} local in_bed = {}
for name, data in pairs(bed.userdata.temp) do for name, data in pairs(bed_userdata.temp) do
if data.in_bed then if data.in_bed then
local player = minetest.get_player_by_name(name) local player = minetest.get_player_by_name(name)
if player then if player then
@ -417,7 +437,7 @@ local function on_punchplayer(player)
return return
end end
local name = player:get_player_name() local name = player:get_player_name()
if bed.userdata.temp[name].in_bed then if bed_userdata.temp[name].in_bed then
take_player_from_bed(player) take_player_from_bed(player)
end end
end end
@ -428,7 +448,7 @@ local function on_player_hpchange(player, hp_change)
return return
end end
local name = player:get_player_name() local name = player:get_player_name()
if bed.userdata.temp[name].in_bed then if bed_userdata.temp[name].in_bed then
take_player_from_bed(player) take_player_from_bed(player)
end end
end end
@ -597,7 +617,7 @@ minetest.register_node(
if clicker_name == sleeper_name then if clicker_name == sleeper_name then
take_player_from_bed(clicker) take_player_from_bed(clicker)
elseif sleeper_name == nil and not rp_player.player_attached[clicker_name] elseif sleeper_name == nil and not rp_player.player_attached[clicker_name]
and bed.userdata.temp[clicker_name].in_bed == false then and bed_userdata.temp[clicker_name].in_bed == false then
if not minetest.settings:get_bool("bed_enable", true) then if not minetest.settings:get_bool("bed_enable", true) then
minetest.chat_send_player(clicker_name, minetest.colorize("#FFFF00", S("Sleeping is disabled."))) minetest.chat_send_player(clicker_name, minetest.colorize("#FFFF00", S("Sleeping is disabled.")))
return itemstack return itemstack
@ -640,16 +660,16 @@ minetest.register_node(
local yaw = (-(node.param2 / 2.0) * math.pi) + math.pi local yaw = (-(node.param2 / 2.0) * math.pi) + math.pi
bed.userdata.temp[clicker_name].in_bed = true bed_userdata.temp[clicker_name].in_bed = true
local changed = bed.set_spawn(clicker, put_pos) local changed = bed.set_spawn(clicker, put_pos)
if changed then if changed then
minetest.chat_send_player(clicker_name, minetest.colorize("#00FFFF", S("Respawn position set!"))) minetest.chat_send_player(clicker_name, minetest.colorize("#00FFFF", S("Respawn position set!")))
end end
bed.userdata.temp[clicker_name].node_pos = pos bed_userdata.temp[clicker_name].node_pos = pos
local sleep_pos = vector.add(pos, vector.divide(minetest.fourdir_to_dir(node.param2), 2)) local sleep_pos = vector.add(pos, vector.divide(minetest.fourdir_to_dir(node.param2), 2))
bed.userdata.temp[clicker_name].sleep_pos = sleep_pos bed_userdata.temp[clicker_name].sleep_pos = sleep_pos
set_bed_occupier(pos, clicker_name) set_bed_occupier(pos, clicker_name)