Fix player potentially respawning in solid node
This commit is contained in:
parent
80f627ad8a
commit
61d853040f
@ -101,7 +101,7 @@ This is the list of all groups used for nodes. Note: If no number/rating is spec
|
|||||||
* `door_wood`: Wooden door
|
* `door_wood`: Wooden door
|
||||||
* `fence`: Fence
|
* `fence`: Fence
|
||||||
* `sign`: Sign
|
* `sign`: Sign
|
||||||
* `bed`: Bed
|
* `bed`: Bed segment
|
||||||
* `torch`: Torch
|
* `torch`: Torch
|
||||||
|
|
||||||
### Node material groups (used for full nodes only):
|
### Node material groups (used for full nodes only):
|
||||||
|
@ -18,6 +18,35 @@ bed.userdata.temp = {}
|
|||||||
-- List of occupied beds, indexed by node position hash
|
-- List of occupied beds, indexed by node position hash
|
||||||
bed.occupied_beds = {}
|
bed.occupied_beds = {}
|
||||||
|
|
||||||
|
-- Returns <spawn position>, <spawn yaw> of `player` or
|
||||||
|
-- nil if if there is no spawn active
|
||||||
|
bed.get_spawn = function(player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
local spawn, yaw
|
||||||
|
if bed.userdata.saved[name].spawn_pos then
|
||||||
|
spawn = bed.userdata.saved[name].spawn_pos
|
||||||
|
end
|
||||||
|
if bed.userdata.saved[name].spawn_yaw then
|
||||||
|
yaw = bed.userdata.saved[name].spawn_yaw
|
||||||
|
end
|
||||||
|
return spawn, yaw
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Sets the bed spawn position for `player`
|
||||||
|
bed.set_spawn = function(player, spawn_pos, yaw)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
bed.userdata.saved[name].spawn_pos = table.copy(spawn_pos)
|
||||||
|
bed.userdata.saved[name].spawn_yaw = yaw or 0
|
||||||
|
minetest.log("action", "[rp_bed] Respawn position of "..name.." set to "..minetest.pos_to_string(spawn_pos, 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Unsets the bed spawn position of `player`
|
||||||
|
bed.unset_spawn = function(player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
bed.userdata.saved[name].spawn_pos = nil
|
||||||
|
bed.userdata.saved[name].spawn_yaw = nil
|
||||||
|
end
|
||||||
|
|
||||||
-- Savefile
|
-- Savefile
|
||||||
|
|
||||||
local bed_file = minetest.get_worldpath() .. "/bed.dat"
|
local bed_file = minetest.get_worldpath() .. "/bed.dat"
|
||||||
@ -68,8 +97,9 @@ local function put_player_in_bed(player)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
player:set_look_horizontal(bed.userdata.saved[name].spawn_yaw)
|
local _, spawn_yaw = bed.get_spawn(player)
|
||||||
player:set_pos(bed.userdata.saved[name].spawn_pos)
|
player:set_look_horizontal(spawn_yaw)
|
||||||
|
player:set_pos(bed.userdata.temp[name].sleep_pos)
|
||||||
|
|
||||||
player_effects.apply_effect(player, "inbed")
|
player_effects.apply_effect(player, "inbed")
|
||||||
|
|
||||||
@ -99,8 +129,12 @@ local function take_player_from_bed(player)
|
|||||||
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
|
||||||
if bed.userdata.saved[name].spawn_pos then
|
local spawn_pos, spawn_yaw = bed.get_spawn(player)
|
||||||
player:set_pos(bed.userdata.saved[name].spawn_pos)
|
if spawn_pos then
|
||||||
|
player:set_pos(spawn_pos)
|
||||||
|
if spawn_yaw then
|
||||||
|
player:set_look_horizontal(spawn_yaw)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
bed.userdata.temp[name].in_bed = false
|
bed.userdata.temp[name].in_bed = false
|
||||||
@ -181,6 +215,7 @@ local function on_joinplayer(player)
|
|||||||
bed.userdata.temp[name] = {
|
bed.userdata.temp[name] = {
|
||||||
in_bed = false,
|
in_bed = false,
|
||||||
node_pos = nil,
|
node_pos = nil,
|
||||||
|
sleep_pos = nil,
|
||||||
}
|
}
|
||||||
delayed_save()
|
delayed_save()
|
||||||
end
|
end
|
||||||
@ -198,18 +233,98 @@ local function on_leaveplayer(player)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Respawning player
|
-- Returns true if players can spawn into the given node safely.
|
||||||
|
local function node_is_spawnable_in(node, is_upper)
|
||||||
local function on_respawnplayer(player)
|
-- All non-walkable, non-damaging, non-drowning nodes are safe.
|
||||||
local name = player:get_player_name()
|
-- Also the bed as a special case for the lower check.
|
||||||
|
if not node then
|
||||||
if bed.userdata.temp[name] then
|
return false
|
||||||
take_player_from_bed(player)
|
end
|
||||||
|
if not is_upper and minetest.get_item_group(node.name, "bed") ~= 0 then
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
local def = minetest.registered_nodes[node.name]
|
||||||
|
if not def.walkable and def.drowning <= 0 and def.damage_per_second <= 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns true if players can spawn on given node safely (without falling).
|
||||||
|
local function node_is_spawnable_on(node)
|
||||||
|
-- All walkable full cube nodes that don't disable jump are accepted
|
||||||
|
if not node then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local def = minetest.registered_nodes[node.name]
|
||||||
|
if def.walkable and
|
||||||
|
((def.collision_box == nil and def.node_box == nil) or
|
||||||
|
(not def.collision_box and def.node_box and def.node_box.type == "regular") or
|
||||||
|
(not def.node_box and def.collision_box and def.collision_box.type == "regular")) and
|
||||||
|
(minetest.get_item_group(node.name, "disable_jump") == 0) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local respawn_check_posses = {
|
||||||
|
vector.new(0, 0, 0 ),
|
||||||
|
vector.new(0, 0, -1 ),
|
||||||
|
vector.new(0, 0, 1 ),
|
||||||
|
vector.new(-1,0, 0 ),
|
||||||
|
vector.new(1, 0, 0 ),
|
||||||
|
vector.new(-1,0, -1 ),
|
||||||
|
vector.new(-1,0, 1 ),
|
||||||
|
vector.new(1, 0, -1 ),
|
||||||
|
vector.new(1, 0, 1 ),
|
||||||
|
}
|
||||||
|
|
||||||
|
local attempt_bed_respawn = function(player)
|
||||||
|
-- Place player on respawn position if set
|
||||||
|
local name = player:get_player_name()
|
||||||
|
local pos, yaw = bed.get_spawn(player)
|
||||||
|
if pos then
|
||||||
|
-- Check if position is safe, if not, try to spawn to one of the
|
||||||
|
-- neighbor blocks
|
||||||
|
for n=1, #respawn_check_posses do
|
||||||
|
local cpos = vector.add(pos, respawn_check_posses[n])
|
||||||
|
local node = minetest.get_node(cpos)
|
||||||
|
if node_is_spawnable_in(node, false) then
|
||||||
|
local is_bed = minetest.get_item_group(node.name, "bed") ~= 0
|
||||||
|
-- Check posses above (must be free)
|
||||||
|
-- and below (must be walkable)
|
||||||
|
-- If bed, 2 posses must be free above
|
||||||
|
local acpos = { x=cpos.x, y=cpos.y+1, z=cpos.z }
|
||||||
|
local aacpos = { x=cpos.x, y=cpos.y+2, z=cpos.z }
|
||||||
|
local abpos = { x=cpos.x, y=cpos.y-1, z=cpos.z }
|
||||||
|
local anode = minetest.get_node(acpos)
|
||||||
|
local aanode = minetest.get_node(aacpos)
|
||||||
|
local bnode = minetest.get_node(abpos)
|
||||||
|
if node_is_spawnable_in(anode, true) and
|
||||||
|
((n == 1 and is_bed) or node_is_spawnable_on(bnode)) and
|
||||||
|
(not is_bed or node_is_spawnable_in(aanode, false)) then
|
||||||
|
local spos = cpos
|
||||||
|
if not is_bed then
|
||||||
|
spos.y = spos.y - 0.5
|
||||||
|
end
|
||||||
|
player:set_pos(spos)
|
||||||
|
if yaw then
|
||||||
|
player:set_look_horizontal(yaw)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
bed.unset_spawn(player)
|
||||||
|
minetest.chat_send_player(name, minetest.colorize("#FFFF00", S("Your respawn position was blocked or dangerous. You've lost your old respawn position.")))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local on_respawnplayer = attempt_bed_respawn
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
@ -403,7 +518,6 @@ minetest.register_node(
|
|||||||
end
|
end
|
||||||
|
|
||||||
local clicker_name = clicker:get_player_name()
|
local clicker_name = clicker:get_player_name()
|
||||||
local put_pos = vector.add(pos, vector.divide(minetest.facedir_to_dir(node.param2), 2))
|
|
||||||
|
|
||||||
local sleeper_name = get_player_in_bed(pos)
|
local sleeper_name = get_player_in_bed(pos)
|
||||||
|
|
||||||
@ -439,7 +553,7 @@ minetest.register_node(
|
|||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
put_pos.y = put_pos.y + 0.6
|
local put_pos = table.copy(pos)
|
||||||
|
|
||||||
local yaw = 0
|
local yaw = 0
|
||||||
|
|
||||||
@ -449,12 +563,11 @@ minetest.register_node(
|
|||||||
|
|
||||||
bed.userdata.temp[clicker_name].in_bed = true
|
bed.userdata.temp[clicker_name].in_bed = true
|
||||||
|
|
||||||
bed.userdata.saved[clicker_name].spawn_yaw = yaw
|
bed.set_spawn(clicker, put_pos, yaw)
|
||||||
bed.userdata.saved[clicker_name].spawn_pos = put_pos
|
|
||||||
|
|
||||||
minetest.log("action", "[rp_bed] Respawn position of "..clicker_name.." set to "..minetest.pos_to_string(put_pos, 1))
|
|
||||||
|
|
||||||
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.facedir_to_dir(node.param2), 2))
|
||||||
|
bed.userdata.temp[clicker_name].sleep_pos = sleep_pos
|
||||||
|
|
||||||
set_bed_occupier(pos, clicker_name)
|
set_bed_occupier(pos, clicker_name)
|
||||||
|
|
||||||
@ -480,7 +593,7 @@ minetest.register_node(
|
|||||||
diggable = false,
|
diggable = false,
|
||||||
tiles = {"bed_head.png", "default_wood.png", "bed_side.png"},
|
tiles = {"bed_head.png", "default_wood.png", "bed_side.png"},
|
||||||
use_texture_alpha = "clip",
|
use_texture_alpha = "clip",
|
||||||
groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3},
|
groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 1},
|
||||||
sounds = rp_sounds.node_sound_wood_defaults(),
|
sounds = rp_sounds.node_sound_wood_defaults(),
|
||||||
node_box = {
|
node_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user