Update beds code from Minetest Game 0.4.15

This commit is contained in:
Wuzzy 2017-02-12 23:43:30 +01:00
parent b886e2bf32
commit 1eb89599bf
7 changed files with 578 additions and 289 deletions

@ -1,26 +1,26 @@
Minetest mod "Beds"
=======================
version: 1.1
License of source code: WTFPL
-----------------------------
author: BlockMen (2013)
original author: PilzAdam
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.
--USING the mod--
------------------
This mods implements Beds like known from Minecraft. You can use them to sleep at night to skip the time or to prevent attacks by evil mobs.
To sleep you have to "rightclick" on your bed. You can only sleep at night and get noticed when it is too early.
After dying the player will respawn at the last bed he has slept.
Minetest Game mod: beds
=======================
See license.txt for license information.
Authors of source code
----------------------
Originally by BlockMen (MIT)
Various Minetest developers and contributors (MIT)
Authors of media (textures)
---------------------------
BlockMen (CC BY-SA 3.0)
This mod adds a bed to Minetest which allows to skip the night.
To sleep, rightclick the bed. If playing in singleplayer mode the night gets skipped
immediately. If playing multiplayer you get shown how many other players are in bed too,
if all players are sleeping the night gets skipped. The night skip can be forced if more
than 50% of the players are lying in bed and use this option.
Another feature is a controlled respawning. If you have slept in bed (not just lying in
it) your respawn point is set to the beds location and you will respawn there after
death.
You can disable the respawn at beds by setting "enable_bed_respawn = false" in
minetest.conf.
You can disable the night skip feature by setting "enable_bed_night_skip = false" in
minetest.conf or by using the /set command in-game.

158
mods/beds/api.lua Normal file

@ -0,0 +1,158 @@
local reverse = true
local function destruct_bed(pos, n)
local node = minetest.get_node(pos)
local other
if n == 2 then
local dir = minetest.facedir_to_dir(node.param2)
other = vector.subtract(pos, dir)
elseif n == 1 then
local dir = minetest.facedir_to_dir(node.param2)
other = vector.add(pos, dir)
end
if reverse then
reverse = not reverse
minetest.remove_node(other)
minetest.check_for_falling(other)
else
reverse = not reverse
end
end
function beds.register_bed(name, def)
minetest.register_node(name .. "_bottom", {
description = def.description,
inventory_image = def.inventory_image,
wield_image = def.wield_image,
drawtype = "nodebox",
tiles = def.tiles.bottom,
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
stack_max = 1,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 1},
sounds = def.sounds or mcl_sounds.node_sound_wood_defaults(),
node_box = {
type = "fixed",
fixed = def.nodebox.bottom,
},
selection_box = {
type = "fixed",
fixed = def.selectionbox,
},
on_place = function(itemstack, placer, pointed_thing)
local under = pointed_thing.under
local pos
if minetest.registered_items[minetest.get_node(under).name].buildable_to then
pos = under
else
pos = pointed_thing.above
end
if minetest.is_protected(pos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(pos, placer:get_player_name())
return itemstack
end
local node_def = minetest.registered_nodes[minetest.get_node(pos).name]
if not node_def or not node_def.buildable_to then
return itemstack
end
local dir = minetest.dir_to_facedir(placer:get_look_dir())
local botpos = vector.add(pos, minetest.facedir_to_dir(dir))
if minetest.is_protected(botpos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(botpos, placer:get_player_name())
return itemstack
end
local botdef = minetest.registered_nodes[minetest.get_node(botpos).name]
if not botdef or not botdef.buildable_to then
return itemstack
end
minetest.set_node(pos, {name = name .. "_bottom", param2 = dir})
minetest.set_node(botpos, {name = name .. "_top", param2 = dir})
if not minetest.setting_getbool("creative_mode") then
itemstack:take_item()
end
return itemstack
end,
on_destruct = function(pos)
destruct_bed(pos, 1)
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
beds.on_rightclick(pos, clicker)
return itemstack
end,
on_rotate = function(pos, node, user, mode, new_param2)
local dir = minetest.facedir_to_dir(node.param2)
local p = vector.add(pos, dir)
local node2 = minetest.get_node_or_nil(p)
if not node2 or not minetest.get_item_group(node2.name, "bed") == 2 or
not node.param2 == node2.param2 then
return false
end
if minetest.is_protected(p, user:get_player_name()) then
minetest.record_protection_violation(p, user:get_player_name())
return false
end
if mode ~= screwdriver.ROTATE_FACE then
return false
end
local newp = vector.add(pos, minetest.facedir_to_dir(new_param2))
local node3 = minetest.get_node_or_nil(newp)
local node_def = node3 and minetest.registered_nodes[node3.name]
if not node_def or not node_def.buildable_to then
return false
end
if minetest.is_protected(newp, user:get_player_name()) then
minetest.record_protection_violation(newp, user:get_player_name())
return false
end
node.param2 = new_param2
-- do not remove_node here - it will trigger destroy_bed()
minetest.set_node(p, {name = "air"})
minetest.set_node(pos, node)
minetest.set_node(newp, {name = name .. "_top", param2 = new_param2})
return true
end,
})
minetest.register_node(name .. "_top", {
drawtype = "nodebox",
tiles = def.tiles.top,
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
pointable = false,
groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2},
sounds = def.sounds or mcl_sounds.node_sound_wood_defaults(),
drop = name .. "_bottom",
node_box = {
type = "fixed",
fixed = def.nodebox.top,
},
on_destruct = function(pos)
destruct_bed(pos, 2)
end,
})
minetest.register_alias(name, name .. "_bottom")
minetest.register_craft({
output = name,
recipe = def.recipe
})
end

34
mods/beds/beds.lua Normal file

@ -0,0 +1,34 @@
-- Simple shaped bed
beds.register_bed("beds:bed", {
description = "Bed",
inventory_image = "beds_bed.png",
wield_image = "beds_bed.png",
tiles = {
bottom = {
"beds_bed_top_bottom.png^[transformR90",
"default_wood.png",
"beds_bed_side_bottom_r.png",
"beds_bed_side_bottom_r.png^[transformfx",
"blank.png",
"beds_bed_side_bottom.png"
},
top = {
"beds_bed_top_top.png^[transformR90",
"default_wood.png",
"beds_bed_side_top_r.png",
"beds_bed_side_top_r.png^[transformfx",
"beds_bed_side_top.png",
"blank.png",
}
},
nodebox = {
bottom = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5},
top = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5},
},
selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.06, 1.5},
recipe = {
{"group:wool", "group:wool", "group:wool"},
{"group:wood", "group:wood", "group:wood"}
},
})

220
mods/beds/functions.lua Normal file

@ -0,0 +1,220 @@
local pi = math.pi
local player_in_bed = 0
local is_sp = minetest.is_singleplayer()
local enable_respawn = minetest.setting_getbool("enable_bed_respawn")
if enable_respawn == nil then
enable_respawn = true
end
-- Helper functions
local function get_look_yaw(pos)
local n = minetest.get_node(pos)
if n.param2 == 1 then
return pi / 2, n.param2
elseif n.param2 == 3 then
return -pi / 2, n.param2
elseif n.param2 == 0 then
return pi, n.param2
else
return 0, n.param2
end
end
local function is_night_skip_enabled()
local enable_night_skip = minetest.setting_getbool("enable_bed_night_skip")
if enable_night_skip == nil then
enable_night_skip = true
end
return enable_night_skip
end
local function check_in_beds(players)
local in_bed = beds.player
if not players then
players = minetest.get_connected_players()
end
for n, player in ipairs(players) do
local name = player:get_player_name()
if not in_bed[name] then
return false
end
end
return #players > 0
end
local function lay_down(player, pos, bed_pos, state, skip)
local name = player:get_player_name()
local hud_flags = player:hud_get_flags()
if not player or not name then
return
end
-- stand up
if state ~= nil and not state then
local p = beds.pos[name] or nil
if beds.player[name] ~= nil then
beds.player[name] = nil
player_in_bed = player_in_bed - 1
end
-- skip here to prevent sending player specific changes (used for leaving players)
if skip then
return
end
if p then
player:setpos(p)
end
-- physics, eye_offset, etc
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
player:set_look_horizontal(math.random(1, 180) / 100)
mcl_player.player_attached[name] = false
player:set_physics_override(1, 1, 1)
hud_flags.wielditem = true
mcl_player.player_set_animation(player, "stand" , 30)
-- lay down
else
beds.player[name] = 1
beds.pos[name] = pos
player_in_bed = player_in_bed + 1
-- physics, eye_offset, etc
player:set_eye_offset({x = 0, y = -13, z = 0}, {x = 0, y = 0, z = 0})
local yaw, param2 = get_look_yaw(bed_pos)
player:set_look_horizontal(yaw)
local dir = minetest.facedir_to_dir(param2)
local p = {x = bed_pos.x + dir.x / 2, y = bed_pos.y, z = bed_pos.z + dir.z / 2}
player:set_physics_override(0, 0, 0)
player:setpos(p)
mcl_player.player_attached[name] = true
hud_flags.wielditem = false
mcl_player.player_set_animation(player, "lay" , 0)
end
player:hud_set_flags(hud_flags)
end
local function update_formspecs(finished)
local ges = #minetest.get_connected_players()
local form_n
local is_majority = (ges / 2) < player_in_bed
if finished then
form_n = beds.formspec .. "label[2.7,11; Good morning.]"
else
form_n = beds.formspec .. "label[2.2,11;" .. tostring(player_in_bed) ..
" of " .. tostring(ges) .. " players are in bed]"
if is_majority and is_night_skip_enabled() then
form_n = form_n .. "button_exit[2,8;4,0.75;force;Force night skip]"
end
end
for name,_ in pairs(beds.player) do
minetest.show_formspec(name, "beds_form", form_n)
end
end
-- Public functions
function beds.kick_players()
for name, _ in pairs(beds.player) do
local player = minetest.get_player_by_name(name)
lay_down(player, nil, nil, false)
end
end
function beds.skip_night()
minetest.set_timeofday(0.23)
end
function beds.on_rightclick(pos, player)
local name = player:get_player_name()
local ppos = player:getpos()
local tod = minetest.get_timeofday()
if tod > 0.2 and tod < 0.805 then
if beds.player[name] then
lay_down(player, nil, nil, false)
end
minetest.chat_send_player(name, "You can only sleep at night.")
return
end
-- move to bed
if not beds.player[name] then
lay_down(player, ppos, pos)
beds.set_spawns() -- save respawn positions when entering bed
else
lay_down(player, nil, nil, false)
end
if not is_sp then
update_formspecs(false)
end
-- skip the night and let all players stand up
if check_in_beds() then
minetest.after(2, function()
if not is_sp then
update_formspecs(is_night_skip_enabled())
end
if is_night_skip_enabled() then
beds.skip_night()
beds.kick_players()
end
end)
end
end
-- Callbacks
-- Only register respawn callback if respawn enabled
if enable_respawn then
-- respawn player at bed if enabled and valid position is found
minetest.register_on_respawnplayer(function(player)
local name = player:get_player_name()
local pos = beds.spawn[name]
if pos then
player:setpos(pos)
return true
end
end)
end
minetest.register_on_leaveplayer(function(player)
local name = player:get_player_name()
lay_down(player, nil, nil, false, true)
beds.player[name] = nil
if check_in_beds() then
minetest.after(2, function()
update_formspecs(is_night_skip_enabled())
if is_night_skip_enabled() then
beds.skip_night()
beds.kick_players()
end
end)
end
end)
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "beds_form" then
return
end
if fields.quit or fields.leave then
lay_down(player, nil, nil, false)
update_formspecs(false)
end
if fields.force then
update_formspecs(is_night_skip_enabled())
if is_night_skip_enabled() then
beds.skip_night()
beds.kick_players()
end
end
end)

@ -1,263 +1,17 @@
local player_in_bed = 0
local guy
local hand
local old_yaw = 0
local function get_dir(pos)
local btop = "beds:bed_top"
if minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z}).name == btop then
return 7.9
elseif minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z}).name == btop then
return 4.75
elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1}).name == btop then
return 3.15
elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1}).name == btop then
return 6.28
end
end
local function plock(start, max, tick, player, yaw)
if start+tick < max then
player:set_look_pitch(-1.2)
player:set_look_yaw(yaw)
minetest.after(tick, plock, start+tick, max, tick, player, yaw)
else
player:set_look_pitch(0)
if old_yaw ~= 0 then minetest.after(0.1+tick, function() player:set_look_yaw(old_yaw) end) end
end
end
local function exit(pos)
local npos = minetest.find_node_near(pos, 1, "beds:bed_bottom")
if npos ~= nil then pos = npos end
if minetest.get_node({x=pos.x+1,y=pos.y,z=pos.z}).name == "air" then
return {x=pos.x+1,y=pos.y,z=pos.z}
elseif minetest.get_node({x=pos.x-1,y=pos.y,z=pos.z}).name == "air" then
return {x=pos.x-1,y=pos.y,z=pos.z}
elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z+1}).name == "air" then
return {x=pos.x,y=pos.y,z=pos.z+1}
elseif minetest.get_node({x=pos.x,y=pos.y,z=pos.z-1}).name == "air" then
return {x=pos.x,y=pos.y,z=pos.z-1}
else
return {x=pos.x,y=pos.y,z=pos.z}
end
end
minetest.register_node("beds:bed_bottom", {
description = "Bed",
inventory_image = "beds_bed.png",
wield_image = "beds_bed.png",
wield_scale = {x=1.5,y=1.5,z=1.5},
drawtype = "nodebox",
is_ground_content = false,
tiles = {"beds_bed_top_bottom.png^[transformR90", "default_wood.png", "beds_bed_side_bottom_r.png", "beds_bed_side_bottom_r.png^[transformfx", "beds_bed_leer.png", "beds_bed_side_bottom.png"},
paramtype = "light",
paramtype2 = "facedir",
stack_max = 1,
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3,bed=1,deco_block=1},
sounds = mcl_sounds.node_sound_wood_defaults(),
node_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5},
},
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0.06, 1.5},
},
after_place_node = function(pos, placer, itemstack)
local node = minetest.get_node(pos)
local param2 = node.param2
local npos = {x=pos.x, y=pos.y, z=pos.z}
if param2 == 0 then
npos.z = npos.z+1
elseif param2 == 1 then
npos.x = npos.x+1
elseif param2 == 2 then
npos.z = npos.z-1
elseif param2 == 3 then
npos.x = npos.x-1
end
if minetest.registered_nodes[minetest.get_node(npos).name].buildable_to == true and minetest.get_node({x=npos.x, y=npos.y-1, z=npos.z}).name ~= "air" then
minetest.set_node(npos, {name="beds:bed_top", param2 = param2})
else
minetest.dig_node(pos)
return true
end
end,
on_destruct = function(pos)
pos = minetest.find_node_near(pos, 1, "beds:bed_top")
if pos ~= nil then minetest.remove_node(pos) end
end,
on_rightclick = function(pos, node, clicker, itemstack)
if not clicker:is_player() then
return
end
if minetest.get_timeofday() > 0.2 and minetest.get_timeofday() < 0.805 then
minetest.chat_send_all("You can only sleep at night")
return
else
clicker:set_physics_override(0,0,0)
old_yaw = clicker:get_look_yaw()
guy = clicker
clicker:set_look_yaw(get_dir(pos))
minetest.chat_send_all("Good night")
plock(0,2,0.1,clicker, get_dir(pos))
end
if not clicker:get_player_control().sneak then
local meta = minetest.get_meta(pos)
local param2 = node.param2
if param2 == 0 then
pos.z = pos.z+1
elseif param2 == 1 then
pos.x = pos.x+1
elseif param2 == 2 then
pos.z = pos.z-1
elseif param2 == 3 then
pos.x = pos.x-1
end
if clicker:get_player_name() == meta:get_string("player") then
if param2 == 0 then
pos.x = pos.x-1
elseif param2 == 1 then
pos.z = pos.z+1
elseif param2 == 2 then
pos.x = pos.x+1
elseif param2 == 3 then
pos.z = pos.z-1
end
pos.y = pos.y-0.5
clicker:setpos(pos)
meta:set_string("player", "")
player_in_bed = player_in_bed-1
elseif meta:get_string("player") == "" then
pos.y = pos.y-0.5
clicker:setpos(pos)
meta:set_string("player", clicker:get_player_name())
player_in_bed = player_in_bed+1
end
end
end
})
minetest.register_node("beds:bed_top", {
drawtype = "nodebox",
tiles = {"beds_bed_top_top.png^[transformR90", "beds_bed_leer.png", "beds_bed_side_top_r.png", "beds_bed_side_top_r.png^[transformfx", "beds_bed_side_top.png", "beds_bed_leer.png"},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
groups = {snappy=1,choppy=2,oddly_breakable_by_hand=2,flammable=3,not_in_creative_inventory=1},
sounds = mcl_sounds.node_sound_wood_defaults(),
node_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0.06, 0.5},
},
selection_box = {
type = "fixed",
fixed = {0, 0, 0, 0, 0, 0},
},
})
minetest.register_alias("beds:bed", "beds:bed_bottom")
minetest.register_craft({
output = "beds:bed",
recipe = {
{"group:wool", "group:wool", "group:wool", },
{"group:wood", "group:wood", "group:wood", }
}
})
local beds_player_spawns = {}
local file = io.open(minetest.get_worldpath().."/beds_player_spawns", "r")
if file then
beds_player_spawns = minetest.deserialize(file:read("*all"))
file:close()
end
local timer = 0
local wait = false
minetest.register_globalstep(function(dtime)
if timer<2 then
timer = timer+dtime
return
end
timer = 0
local players = #minetest.get_connected_players()
if players == player_in_bed and players ~= 0 then
if minetest.get_timeofday() < 0.2 or minetest.get_timeofday() > 0.805 then
if not wait then
minetest.after(2, function()
minetest.set_timeofday(0.23)
wait = false
guy:set_physics_override(1,1,1)
guy:setpos(exit(guy:getpos()))
end)
wait = true
for _,player in ipairs(minetest.get_connected_players()) do
beds_player_spawns[player:get_player_name()] = player:getpos()
end
local file = io.open(minetest.get_worldpath().."/beds_player_spawns", "w")
if file then
file:write(minetest.serialize(beds_player_spawns))
file:close()
end
end
end
end
end)
minetest.register_on_respawnplayer(function(player)
local name = player:get_player_name()
if beds_player_spawns[name] then
player:setpos(beds_player_spawns[name])
return true
end
end)
minetest.register_abm({
nodenames = {"beds:bed_bottom"},
interval = 1,
chance = 1,
action = function(pos, node)
local meta = minetest.get_meta(pos)
if meta:get_string("player") ~= "" then
local param2 = node.param2
if param2 == 0 then
pos.z = pos.z+1
elseif param2 == 1 then
pos.x = pos.x+1
elseif param2 == 2 then
pos.z = pos.z-1
elseif param2 == 3 then
pos.x = pos.x-1
end
local player = minetest.get_player_by_name(meta:get_string("player"))
if player == nil then
meta:set_string("player", "")
player_in_bed = player_in_bed-1
return
end
local player_pos = player:getpos()
player_pos.x = math.floor(0.5+player_pos.x)
player_pos.y = math.floor(0.5+player_pos.y)
player_pos.z = math.floor(0.5+player_pos.z)
if pos.x ~= player_pos.x or pos.y ~= player_pos.y or pos.z ~= player_pos.z then
meta:set_string("player", "")
player_in_bed = player_in_bed-1
return
end
end
end
})
if minetest.setting_get("log_mods") then
minetest.log("action", "beds loaded")
end
beds = {}
beds.player = {}
beds.pos = {}
beds.spawn = {}
beds.formspec = "size[8,15;true]" ..
"bgcolor[#080808BB; true]" ..
"button_exit[2,12;4,0.75;leave;Leave Bed]"
local modpath = minetest.get_modpath("beds")
-- Load files
dofile(modpath .. "/functions.lua")
dofile(modpath .. "/api.lua")
dofile(modpath .. "/beds.lua")
dofile(modpath .. "/spawns.lua")

60
mods/beds/license.txt Normal file

@ -0,0 +1,60 @@
License of source code
----------------------
The MIT License (MIT)
Copyright (C) 2014-2016 BlockMen
Copyright (C) 2014-2016 Various Minetest developers and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
For more details:
https://opensource.org/licenses/MIT
Licenses of media (textures)
----------------------------
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
Copyright (C) 2014-2016 BlockMen
You are free to:
Share — copy and redistribute the material in any medium or format.
Adapt — remix, transform, and build upon the material for any purpose, even commercially.
The licensor cannot revoke these freedoms as long as you follow the license terms.
Under the following terms:
Attribution — You must give appropriate credit, provide a link to the license, and
indicate if changes were made. You may do so in any reasonable manner, but not in any way
that suggests the licensor endorses you or your use.
ShareAlike — If you remix, transform, or build upon the material, you must distribute
your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that
legally restrict others from doing anything the license permits.
Notices:
You do not have to comply with the license for elements of the material in the public
domain or where your use is permitted by an applicable exception or limitation.
No warranties are given. The license may not give you all of the permissions necessary
for your intended use. For example, other rights such as publicity, privacy, or moral
rights may limit how you use the material.
For more details:
http://creativecommons.org/licenses/by-sa/3.0/

63
mods/beds/spawns.lua Normal file

@ -0,0 +1,63 @@
local world_path = minetest.get_worldpath()
local org_file = world_path .. "/beds_spawns"
local file = world_path .. "/beds_spawns"
local bkwd = false
-- check for PA's beds mod spawns
local cf = io.open(world_path .. "/beds_player_spawns", "r")
if cf ~= nil then
io.close(cf)
file = world_path .. "/beds_player_spawns"
bkwd = true
end
function beds.save_spawns()
if not beds.spawn then
return
end
local data = {}
local output = io.open(org_file, "w")
for k, v in pairs(beds.spawn) do
table.insert(data, string.format("%.1f %.1f %.1f %s\n", v.x, v.y, v.z, k))
end
output:write(table.concat(data))
io.close(output)
end
function beds.read_spawns()
local spawns = beds.spawn
local input = io.open(file, "r")
if input and not bkwd then
repeat
local x = input:read("*n")
if x == nil then
break
end
local y = input:read("*n")
local z = input:read("*n")
local name = input:read("*l")
spawns[name:sub(2)] = {x = x, y = y, z = z}
until input:read(0) == nil
io.close(input)
elseif input and bkwd then
beds.spawn = minetest.deserialize(input:read("*all"))
input:close()
beds.save_spawns()
os.rename(file, file .. ".backup")
file = org_file
end
end
beds.read_spawns()
function beds.set_spawns()
for name,_ in pairs(beds.player) do
local player = minetest.get_player_by_name(name)
local p = player:getpos()
-- but don't change spawn location if borrowing a bed
if not minetest.is_protected(p, name) then
beds.spawn[name] = p
end
end
beds.save_spawns()
end