804 lines
20 KiB
Lua
804 lines
20 KiB
Lua
boxes = {}
|
|
|
|
local function bytes_to_string(bytes)
|
|
local s = {}
|
|
for i = 1, #bytes do
|
|
s[i] = string.char(bytes[i])
|
|
end
|
|
return table.concat(s)
|
|
end
|
|
|
|
local function string_to_bytes(str)
|
|
local s = {}
|
|
for i = 1, string.len(str) do
|
|
s[i] = string.byte(str, i)
|
|
end
|
|
return s
|
|
end
|
|
|
|
|
|
function boxes.save(minp, maxp)
|
|
--[[ TODO: save the box in incremental steps to avoid stalling the server. The
|
|
problem is that we have to iterate over all positions since there is no way
|
|
to get the metadata of all nodes in an area, although the engine can.
|
|
However, we still use a voxelmanip to load node bulk data.
|
|
]]
|
|
local vm = minetest.get_voxel_manip(minp, maxp)
|
|
local emin, emax = vm:get_emerged_area()
|
|
local data = vm:get_data()
|
|
local param2 = vm:get_param2_data()
|
|
local flat_data = {}
|
|
local flat_index = 1
|
|
local function add_u8(x)
|
|
flat_data[flat_index] = x
|
|
flat_index = flat_index + 1
|
|
end
|
|
local function add_u16(x)
|
|
add_u8(math.floor(x / 256))
|
|
add_u8(x % 256)
|
|
end
|
|
local function add_position(p)
|
|
add_u16(p.x - minp.x)
|
|
add_u16(p.y - minp.y)
|
|
add_u16(p.z - minp.z)
|
|
end
|
|
local function add_string(s)
|
|
add_u16(string.len(s))
|
|
for i = 1, string.len(s) do
|
|
add_u8(string.byte(s, i))
|
|
end
|
|
end
|
|
|
|
-- Version
|
|
add_u8(1)
|
|
|
|
local sx = maxp.x - minp.x + 1
|
|
local sy = maxp.y - minp.y + 1
|
|
local sz = maxp.z - minp.z + 1
|
|
-- Size
|
|
add_u16(sx)
|
|
add_u16(sy)
|
|
add_u16(sz)
|
|
|
|
local cid_mapping = {}
|
|
local cid_index = 0
|
|
local cid_rmapping = {}
|
|
local schem_size = sx * sy * sz
|
|
local va = VoxelArea:new{MinEdge=emin,MaxEdge=emax}
|
|
|
|
for z = minp.z, maxp.z do
|
|
for y = minp.y, maxp.y do
|
|
local index = va:index(minp.x, y, z)
|
|
for x = minp.x, maxp.x do
|
|
local cid = data[index]
|
|
if cid_rmapping[cid] == nil then
|
|
cid_rmapping[cid] = cid_index
|
|
cid_mapping[cid_index] = minetest.get_name_from_content_id(cid)
|
|
cid_index = cid_index + 1
|
|
end
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Write cid mapping
|
|
add_u16(cid_index)
|
|
for i = 0, cid_index - 1 do
|
|
add_string(cid_mapping[i])
|
|
end
|
|
|
|
-- Write bulk node data
|
|
for z = minp.z, maxp.z do
|
|
for y = minp.y, maxp.y do
|
|
local index = va:index(minp.x, y, z)
|
|
for x = minp.x, maxp.x do
|
|
add_u16(cid_rmapping[data[index]])
|
|
add_u8(param2[index])
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
local meta_to_save = {}
|
|
local meta_save_index = 1
|
|
for z = minp.z, maxp.z do
|
|
for y = minp.y, maxp.y do
|
|
for x = minp.x, maxp.x do
|
|
local meta = minetest.get_meta({x = x, y = y, z = z})
|
|
local meta_table = meta:to_table()
|
|
if next(meta_table.fields) ~= nil or next(meta_table.inventory) ~= nil then
|
|
local inv = {}
|
|
for inv_name, inv_list in pairs(meta_table.inventory) do
|
|
local inv_list_2 = {}
|
|
for i, stack in ipairs(inv_list) do
|
|
inv_list_2[i] = stack:to_string()
|
|
end
|
|
inv[inv_name] = inv_list_2
|
|
end
|
|
meta_to_save[meta_save_index] =
|
|
{ x = x - minp.x, y = y - minp.y, z = z - minp.z,
|
|
fields = meta_table.fields,
|
|
inventory = inv
|
|
}
|
|
meta_save_index = meta_save_index + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
add_u16(meta_save_index - 1)
|
|
for i = 1, meta_save_index - 1 do
|
|
local m = meta_to_save[i]
|
|
add_u16(m.x)
|
|
add_u16(m.y)
|
|
add_u16(m.z)
|
|
add_string(minetest.serialize(m.fields))
|
|
add_string(minetest.serialize(m.inventory))
|
|
end
|
|
|
|
--print(dump(flat_data))
|
|
--print(dump(bytes_to_string(flat_data)))
|
|
local raw_data = bytes_to_string(flat_data)
|
|
return minetest.compress(raw_data, "deflate")
|
|
end
|
|
|
|
function boxes.load(minp, compressed)
|
|
local raw_data = minetest.decompress(compressed, "deflate")
|
|
local raw_data_index = 1
|
|
local function read_u8()
|
|
local c = string.byte(raw_data, raw_data_index)
|
|
raw_data_index = raw_data_index + 1
|
|
return c
|
|
end
|
|
local function read_u16()
|
|
local a = read_u8()
|
|
local b = read_u8()
|
|
return 256 * a + b
|
|
end
|
|
local function read_string()
|
|
local len = read_u16()
|
|
local r = string.sub(raw_data, raw_data_index, raw_data_index + len - 1)
|
|
raw_data_index = raw_data_index + len
|
|
return r
|
|
end
|
|
|
|
local version = read_u8()
|
|
assert (version == 1)
|
|
|
|
local sx = read_u16()
|
|
local sy = read_u16()
|
|
local sz = read_u16()
|
|
|
|
-- Read cid mapping
|
|
local cid_mapping = {}
|
|
local cid_index = read_u16()
|
|
for i = 0, cid_index - 1 do
|
|
cid_mapping[i] = minetest.get_content_id(read_string())
|
|
end
|
|
|
|
local maxp = {x = minp.x + sx - 1, y = minp.y + sy - 1, z = minp.z + sz - 1}
|
|
local vm = minetest.get_voxel_manip(minp, maxp)
|
|
local emin, emax = vm:get_emerged_area()
|
|
local va = VoxelArea:new{MinEdge=emin,MaxEdge=emax}
|
|
local vmdata = vm:get_data()
|
|
local param2 = vm:get_param2_data()
|
|
|
|
-- Read bulk node data
|
|
for z = minp.z, maxp.z do
|
|
for y = minp.y, maxp.y do
|
|
local index = va:index(minp.x, y, z)
|
|
for x = minp.x, maxp.x do
|
|
vmdata[index] = cid_mapping[read_u16()]
|
|
param2[index] = read_u8()
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
vm:set_data(vmdata)
|
|
vm:set_param2_data(param2)
|
|
vm:update_liquids()
|
|
vm:write_to_map()
|
|
vm:update_map()
|
|
|
|
-- Finally, read metadata
|
|
local nmeta = read_u16()
|
|
for i = 1, nmeta do
|
|
local x = read_u16()
|
|
local y = read_u16()
|
|
local z = read_u16()
|
|
local p = {x = minp.x + x, y = minp.y + y, z = minp.z + z}
|
|
local meta = minetest.get_meta(p)
|
|
local fields = minetest.deserialize(read_string())
|
|
local inv = minetest.deserialize(read_string())
|
|
for inv_name, inv_list in pairs(inv) do
|
|
for i, stack in ipairs(inv_list) do
|
|
inv_list[i] = ItemStack(inv_list[i])
|
|
end
|
|
end
|
|
meta:from_table({fields = fields, inventory = inv})
|
|
end
|
|
|
|
end
|
|
|
|
function boxes.extent(compressed)
|
|
local raw_data = minetest.decompress(compressed, "deflate")
|
|
local raw_data_index = 1
|
|
local function read_u8()
|
|
local c = string.byte(raw_data, raw_data_index)
|
|
raw_data_index = raw_data_index + 1
|
|
return c
|
|
end
|
|
local function read_u16()
|
|
local a = read_u8()
|
|
local b = read_u8()
|
|
return 256 * a + b
|
|
end
|
|
|
|
local version = read_u8()
|
|
assert (version == 1)
|
|
|
|
local sx = read_u16()
|
|
local sy = read_u16()
|
|
local sz = read_u16()
|
|
|
|
return {x = sx, y = sy, z = sz}
|
|
end
|
|
|
|
-- Set the region from minp to maxp to air
|
|
function boxes.cleanup(minp, maxp)
|
|
local vm = minetest.get_voxel_manip(minp, maxp)
|
|
local emin, emax = vm:get_emerged_area()
|
|
local va = VoxelArea:new{MinEdge=emin,MaxEdge=emax}
|
|
local vmdata = vm:get_data()
|
|
local param2 = vm:get_param2_data()
|
|
local cid = minetest.get_content_id("air")
|
|
|
|
for z = minp.z, maxp.z do
|
|
for y = minp.y, maxp.y do
|
|
local index = va:index(minp.x, y, z)
|
|
for x = minp.x, maxp.x do
|
|
vmdata[index] = cid
|
|
param2[index] = 0
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
vm:set_data(vmdata)
|
|
vm:set_param2_data(param2)
|
|
vm:update_liquids()
|
|
vm:write_to_map()
|
|
vm:update_map()
|
|
|
|
end
|
|
|
|
--[[
|
|
Now for box allocation.
|
|
|
|
To keep things simple, we will always allocate boxes with same width and
|
|
depth, and with a sizee that is a multiple of boxes_resolution. Height is
|
|
assumed to be unlimited above box_alloc_miny.
|
|
In order to do that, we keep a quadtree of allocatable positions; an allocated
|
|
box will always be a leaf of that tree. We also keep for each subtree the max
|
|
size that can be allocated in it.
|
|
|
|
Thus, this is https://en.wikipedia.org/wiki/Buddy_memory_allocation in 2D.
|
|
]]
|
|
|
|
local boxes_resolution = 64
|
|
local box_alloc_miny = 50
|
|
local boxes_tree = {
|
|
minp = {x = -16384, z = -16384},
|
|
edge_size = 32768,
|
|
max_alloc_size = 32768,
|
|
}
|
|
|
|
local function split_leaf(node)
|
|
assert (node.edge_size >= 2 * boxes_resolution)
|
|
assert (node.children == nil)
|
|
local new_size = node.edge_size / 2
|
|
local x = node.minp.x
|
|
local z = node.minp.z
|
|
node.children = {
|
|
{
|
|
minp = {x = x, z = z},
|
|
edge_size = new_size,
|
|
max_alloc_size = new_size,
|
|
parent = node
|
|
},
|
|
{
|
|
minp = {x = x + new_size, z = z},
|
|
edge_size = new_size,
|
|
max_alloc_size = new_size,
|
|
parent = node,
|
|
},
|
|
{
|
|
minp = {x = x, z = z + new_size},
|
|
edge_size = new_size,
|
|
max_alloc_size = new_size,
|
|
parent = node,
|
|
},
|
|
{
|
|
minp = {x = x + new_size, z = z + new_size},
|
|
edge_size = new_size,
|
|
max_alloc_size = new_size,
|
|
parent = node,
|
|
},
|
|
}
|
|
end
|
|
|
|
-- Update `max_alloc_size` for node and all its parents.
|
|
-- Also, merge subtrees if possible.
|
|
local function update_alloc_sizes(node)
|
|
while node ~= nil do
|
|
local max_size = 0
|
|
local el = node.edge_size / 2
|
|
local can_merge = true
|
|
for _, child in ipairs(node.children) do
|
|
max_size = math.max(max_size, child.max_alloc_size)
|
|
if child.max_alloc_size < el then
|
|
can_merge = false
|
|
end
|
|
end
|
|
if can_merge then
|
|
node.children = nil
|
|
node.max_alloc_size = node.edge_size
|
|
else
|
|
node.max_alloc_size = max_size
|
|
end
|
|
node = node.parent
|
|
end
|
|
end
|
|
|
|
-- Function to know how close to zero a node is.
|
|
-- Used to keep allocations close to (0, box_alloc_miny, 0).
|
|
local function zero_close(node)
|
|
local x = node.minp.x
|
|
local z = node.minp.z
|
|
local size = node.edge_size
|
|
if x < 0 then x = x + size end
|
|
if z < 0 then z = z + size end
|
|
return math.abs(x) + math.abs(z)
|
|
end
|
|
|
|
-- Allocated a box of size `size` horizontally, and unbounded vertically
|
|
-- Returns box minimum position. The minimum position must be given to
|
|
-- boxes.vfree to free the corresponding area.
|
|
function boxes.valloc(size)
|
|
assert (size > 0)
|
|
if boxes_tree.max_alloc_size < size then
|
|
return nil
|
|
end
|
|
|
|
-- Find leaf with enough room, splitting it if big enough
|
|
local node = boxes_tree
|
|
while node.edge_size / 2 >= size and node.edge_size / 2 >= boxes_resolution do
|
|
if node.children == nil then
|
|
split_leaf(node)
|
|
end
|
|
|
|
local best = nil
|
|
local best_distance = 1e10 -- infinity
|
|
for _, child in ipairs(node.children) do
|
|
if child.max_alloc_size >= size and zero_close(child) < best_distance then
|
|
best_distance = zero_close(child)
|
|
best = child
|
|
end
|
|
end
|
|
assert (best ~= nil)
|
|
node = best
|
|
end
|
|
|
|
local result = {x = node.minp.x, y = box_alloc_miny, z = node.minp.z}
|
|
node.max_alloc_size = 0
|
|
update_alloc_sizes(node.parent)
|
|
return result
|
|
end
|
|
|
|
function boxes.vfree(minp)
|
|
assert (minp.y == box_alloc_miny)
|
|
assert (boxes_tree.minp.x <= minp.x)
|
|
assert (minp.x < boxes_tree.minp.x + boxes_tree.edge_size)
|
|
assert (boxes_tree.minp.z <= minp.z)
|
|
assert (minp.z < boxes_tree.minp.z + boxes_tree.edge_size)
|
|
|
|
-- Find leaf containing minp
|
|
local node = boxes_tree
|
|
while node.children ~= nil do
|
|
local cld = nil
|
|
local el = node.edge_size / 2
|
|
for _, child in ipairs(node.children) do
|
|
if child.minp.x <= minp.x and minp.x < child.minp.x + el
|
|
and child.minp.z <= minp.z and minp.z < child.minp.z + el then
|
|
cld = child
|
|
break
|
|
end
|
|
end
|
|
assert (cld ~= nil)
|
|
node = cld
|
|
end
|
|
|
|
assert (node.max_alloc_size == 0)
|
|
node.max_alloc_size = node.edge_size
|
|
update_alloc_sizes(node.parent)
|
|
end
|
|
|
|
function boxes.read_box(box_data)
|
|
local data_index = 1
|
|
local function read_u8()
|
|
local c = string.byte(box_data, data_index)
|
|
data_index = data_index + 1
|
|
return c
|
|
end
|
|
local function read_u16()
|
|
local a = read_u8()
|
|
local b = read_u8()
|
|
return 256 * a + b
|
|
end
|
|
local function read_pos()
|
|
local x = read_u16()
|
|
local y = read_u16()
|
|
local z = read_u16()
|
|
return {x = x, y = y, z = z}
|
|
end
|
|
local size = read_pos()
|
|
local entry = read_pos()
|
|
local exit = read_pos()
|
|
return {
|
|
size = size,
|
|
entry = entry,
|
|
exit = exit,
|
|
data = string.sub(box_data, data_index)
|
|
}
|
|
end
|
|
|
|
function boxes.write_box(box)
|
|
local data_index = 1
|
|
local data = {}
|
|
local function write_u8(x)
|
|
data[data_index] = x
|
|
data_index = data_index + 1
|
|
end
|
|
local function write_u16(x)
|
|
write_u8(math.floor(x / 256))
|
|
write_u8(x % 256)
|
|
end
|
|
local function write_pos(p)
|
|
write_u16(p.x)
|
|
write_u16(p.y)
|
|
write_u16(p.z)
|
|
end
|
|
write_pos(box.size)
|
|
write_pos(box.entry)
|
|
write_pos(box.exit)
|
|
return bytes_to_string(data) .. box.data
|
|
end
|
|
|
|
function vector.min(a, b)
|
|
return {
|
|
x = math.min(a.x, b.x),
|
|
y = math.min(a.y, b.y),
|
|
z = math.min(a.z, b.z),
|
|
}
|
|
end
|
|
|
|
function vector.max(a, b)
|
|
return {
|
|
x = math.max(a.x, b.x),
|
|
y = math.max(a.y, b.y),
|
|
z = math.max(a.z, b.z),
|
|
}
|
|
end
|
|
|
|
local players_in_boxes = {}
|
|
|
|
local function read_file(filename)
|
|
local file = io.open(filename, "r")
|
|
if file ~= nil then
|
|
local file_content = file:read("*all")
|
|
io.close(file)
|
|
return file_content
|
|
end
|
|
return ""
|
|
end
|
|
|
|
local function write_file(filename, data)
|
|
local file, err = io.open(filename, "w")
|
|
if file then
|
|
file:write(data)
|
|
io.close(file)
|
|
else
|
|
error(err)
|
|
end
|
|
end
|
|
|
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
|
local worldpath = minetest.get_worldpath()
|
|
|
|
local entry_lobby_data = read_file(worldpath .. "/entry.box")
|
|
if entry_lobby_data == "" then
|
|
entry_lobby_data = read_file(modpath .. "/entry.box")
|
|
write_file(worldpath .. "/entry.box", entry_lobby_data)
|
|
end
|
|
|
|
local exit_lobby_data = read_file(worldpath .. "/exit.box")
|
|
if exit_lobby_data == "" then
|
|
exit_lobby_data = read_file(modpath .. "/exit.box")
|
|
write_file(worldpath .. "/exit.box", exit_lobby_data)
|
|
end
|
|
|
|
if db.box_get_data(0) == "" then
|
|
local box_data = read_file(modpath .. "/box.box")
|
|
db.box_set_data(0, box_data)
|
|
end
|
|
|
|
local function pop_node(pos)
|
|
local node = minetest.get_node(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
local r = {pos = pos, node = node, meta = meta:to_table()}
|
|
minetest.remove_node(pos)
|
|
return r
|
|
end
|
|
|
|
local function unpop_node(data)
|
|
minetest.set_node(data.pos, data.node)
|
|
local meta = minetest.get_meta(data.pos)
|
|
meta:from_table(data.meta)
|
|
end
|
|
|
|
local function open_door(player, minp, maxp)
|
|
local nds = {}
|
|
local i = 1
|
|
for x = minp.x, maxp.x do
|
|
for y = minp.y, maxp.y do
|
|
for z = minp.z, maxp.z do
|
|
nds[i] = pop_node({x = x, y = y, z = z})
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
local od = players_in_boxes[player:get_player_name()].open_doors
|
|
od[#od + 1] = {minx = maxp.x + 0.5, nodes = nds}
|
|
end
|
|
|
|
function boxes.open_exit(player)
|
|
local name = player:get_player_name()
|
|
local ex = players_in_boxes[name].exit_door
|
|
open_door(player, vector.add(ex, {x = -1, y = 0, z = 0}), vector.add(ex, {x = 0, y = 1, z = 0}))
|
|
end
|
|
|
|
-- Close doors behind players
|
|
minetest.register_globalstep(function(dtime)
|
|
for playername, info in pairs(players_in_boxes) do
|
|
local i = 1
|
|
local player = minetest.get_player_by_name(playername)
|
|
local pos = player:get_pos()
|
|
local doors = info.open_doors
|
|
local n = #doors
|
|
while doors[i] do
|
|
if pos.x >= doors[i].minx then
|
|
for _, data in ipairs(doors[i].nodes) do
|
|
unpop_node(data)
|
|
end
|
|
doors[i] = doors[n]
|
|
doors[n] = nil
|
|
n = n - 1
|
|
else
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
|
|
function boxes.start_box(player, box_data)
|
|
local name = player:get_player_name()
|
|
if players_in_boxes[name] ~= nil then
|
|
return
|
|
end
|
|
|
|
local box = boxes.read_box(box_data)
|
|
local lobby_spawn = boxes.read_box(entry_lobby_data)
|
|
local lobby_exit = boxes.read_box(exit_lobby_data)
|
|
local lobby_spawn_offset = vector.subtract(box.entry, lobby_spawn.exit)
|
|
local lobby_exit_offset = vector.subtract(box.exit, lobby_exit.entry)
|
|
local pmin = vector.min({x = 0, y = 0, z = 0}, vector.min(lobby_spawn_offset,
|
|
lobby_exit_offset))
|
|
local box_offset = {x = -pmin.x, y = -pmin.y, z = -pmin.z}
|
|
local spawn_offset = vector.add(box_offset, lobby_spawn_offset)
|
|
local exit_offset = vector.add(box_offset, lobby_exit_offset)
|
|
local pmax = vector.max(vector.add(box_offset, box.size),
|
|
vector.max(vector.add(spawn_offset, lobby_spawn.size),
|
|
vector.add(exit_offset, lobby_exit.size)))
|
|
local request_size = math.max(pmax.x, pmax.z)
|
|
local minp = boxes.valloc(request_size)
|
|
boxes.load(vector.add(minp, box_offset), box.data)
|
|
boxes.load(vector.add(minp, spawn_offset), lobby_spawn.data)
|
|
boxes.load(vector.add(minp, exit_offset), lobby_exit.data)
|
|
|
|
player:set_pos(vector.add(minp, vector.add(spawn_offset, lobby_spawn.entry)))
|
|
players_in_boxes[name] = {
|
|
minp = minp,
|
|
maxp = vector.add(minp, vector.subtract(pmax, 1)),
|
|
exit_door = vector.add(minp, vector.add(box_offset, box.exit)),
|
|
open_doors = {},
|
|
}
|
|
local entry_door = vector.add(minp, vector.add(box_offset, box.entry))
|
|
open_door(player, vector.add(entry_door, {x = -1, y = 0, z = 0}),
|
|
vector.add(entry_door, {x = 0, y = 1, z = 0}))
|
|
|
|
boxes.open_exit(player)
|
|
end
|
|
|
|
function boxes.end_box(player)
|
|
local name = player:get_player_name()
|
|
if players_in_boxes[name] == nil then
|
|
return
|
|
end
|
|
|
|
local bx = players_in_boxes[name]
|
|
boxes.cleanup(bx.minp, bx.maxp)
|
|
boxes.vfree(bx.minp)
|
|
players_in_boxes[name] = nil
|
|
end
|
|
|
|
minetest.register_on_leaveplayer(function(player)
|
|
boxes.end_box(player)
|
|
end)
|
|
|
|
minetest.register_chatcommand("enter", {
|
|
params = "<boxid>",
|
|
description = "Enter box with this id",
|
|
privs = {server = true},
|
|
func = function(name, param)
|
|
local player = minetest.get_player_by_name(name)
|
|
local id = tonumber(param)
|
|
if not id then
|
|
return
|
|
end
|
|
local data = db.box_get_data(id)
|
|
if not data then
|
|
return
|
|
end
|
|
boxes.start_box(player, data)
|
|
end,
|
|
})
|
|
|
|
minetest.register_chatcommand("leave", {
|
|
params = "",
|
|
description = "Leave the current box",
|
|
privs = {server = true},
|
|
func = function(name, param)
|
|
local player = minetest.get_player_by_name(name)
|
|
boxes.end_box(player)
|
|
end,
|
|
})
|
|
|
|
local lobby_updates = {}
|
|
minetest.register_chatcommand("update_lobby", {
|
|
params = "entry|exit",
|
|
description = "Set corresponding lobby. Use without parameter to start updating a lobby",
|
|
privs = {server = true},
|
|
func = function(name, param)
|
|
if param ~= "entry" and param ~= "exit" and param ~= "" then
|
|
return
|
|
end
|
|
|
|
if param == "" then
|
|
lobby_updates[name] = {}
|
|
else
|
|
local pos1 = lobby_updates[name].pos1
|
|
local pos2 = lobby_updates[name].pos2
|
|
local pos3 = lobby_updates[name].pos3
|
|
if not pos1 or not pos2 or not pos3 then
|
|
minetest.chat_send_player(name, "Not all positions have been set.")
|
|
return
|
|
end
|
|
local minp = vector.min(pos1, pos2)
|
|
local maxp = vector.max(pos1, pos2)
|
|
local data = boxes.save(minp, maxp)
|
|
local p3 = vector.subtract(pos3, minp)
|
|
if param == "exit" then
|
|
if p3.x < 0 or p3.y < 0 or p3.z < 0 then
|
|
minetest.chat_send_player(name, "The entry is not inside the lobby.")
|
|
return
|
|
end
|
|
exit_lobby_data = boxes.write_box({
|
|
size = boxes.extent(data),
|
|
entry = p3,
|
|
exit = p3,
|
|
data = data,
|
|
})
|
|
write_file(worldpath .. "/exit.box", exit_lobby_data)
|
|
else
|
|
local player = minetest.get_player_by_name(name)
|
|
local entry = vector.subtract(vector.round(player:get_pos()), minp)
|
|
p3.x = p3.x + 1
|
|
if entry.x < 0 or entry.y < 0 or entry.z < 0 then
|
|
minetest.chat_send_player(name, "You're not standing inside the lobby.")
|
|
return
|
|
end
|
|
if p3.x < 0 or p3.y < 0 or p3.z < 0 then
|
|
minetest.chat_send_player(name, "The exit is not inside the lobby.")
|
|
return
|
|
end
|
|
entry_lobby_data = boxes.write_box({
|
|
size = boxes.extent(data),
|
|
entry = entry,
|
|
exit = p3,
|
|
data = data,
|
|
})
|
|
write_file(worldpath .. "/entry.box", entry_lobby_data)
|
|
end
|
|
minetest.chat_send_player(name, "Updated.")
|
|
lobby_updates[name] = nil
|
|
end
|
|
end,
|
|
})
|
|
|
|
minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
|
|
if not puncher then return end
|
|
local name = puncher:get_player_name()
|
|
if not lobby_updates[name] then return end
|
|
if not lobby_updates[name].pos1 then
|
|
lobby_updates[name].pos1 = pos
|
|
minetest.chat_send_player(name, "Position 1 set to " .. dump(pos) .. ".")
|
|
elseif not lobby_updates[name].pos2 then
|
|
lobby_updates[name].pos2 = pos
|
|
minetest.chat_send_player(name, "Position 2 set to " .. dump(pos) .. ".")
|
|
elseif not lobby_updates[name].pos3 then
|
|
lobby_updates[name].pos3 = pos
|
|
minetest.chat_send_player(name, "Position 3 set to " .. dump(pos) .. ".")
|
|
end
|
|
end)
|
|
|
|
-- old test code
|
|
--[[
|
|
minetest.after(5, function()
|
|
local data = boxes.save({x = -1, y = -4, z = -1},
|
|
{x = 1, y = -2, z = 1})
|
|
print(string.len(data))
|
|
boxes.load({x = -10, y = 0, z = 5}, data)
|
|
|
|
print(dump(boxes_tree))
|
|
local minp = boxes.valloc(237)
|
|
print(dump(minp))
|
|
print(dump(boxes_tree))
|
|
boxes.vfree(minp)
|
|
print(dump(boxes_tree))
|
|
|
|
local data_spawn = boxes.save({x = -35, y = -32, z = 56},
|
|
{x = -33, y = -29, z = 64})
|
|
local data_exit = boxes.save({x = -10, y = -32, z = 53},
|
|
{x = -8, y = -29, z = 61})
|
|
local sp = {
|
|
size = boxes.extent(data_spawn),
|
|
entry = {x = 0, y = 2, z = 4},
|
|
exit = {x = 3, y = 1, z = 4},
|
|
data = data_spawn,
|
|
}
|
|
local ex = {
|
|
size = boxes.extent(data_exit),
|
|
entry = {x = 0, y = 1, z = 4},
|
|
exit = {x = 3, y = 1, z = 4},
|
|
data = data_exit,
|
|
}
|
|
|
|
local data_box = boxes.save({x = -32, y = -32, z = 48},
|
|
{x = -11, y = -27, z = 69})
|
|
local bx = {
|
|
size = boxes.extent(data_box),
|
|
entry = {x = 0, y = 1, z = 10},
|
|
exit = {x = 22, y = 1, z = 10},
|
|
data = data_box,
|
|
}
|
|
|
|
local path = minetest.get_worldpath()
|
|
write_file(path .. "/entry.box", boxes.write_box(sp))
|
|
write_file(path .. "/exit.box", boxes.write_box(ex))
|
|
write_file(path .. "/box.box", boxes.write_box(bx))
|
|
|
|
local player = minetest.get_player_by_name("singleplayer")
|
|
boxes.start_box(player, db.box_get_data(0))
|
|
end)
|
|
]]
|