minetest-gamehub/gamehub/extender.lua

219 lines
5.6 KiB
Lua

--[[
gamehub mod (C) shivajiva101@hotmail.com 2019
This file is part of gamehub.
gamehub is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
gamehub is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with gamehub. If not, see <https://www.gnu.org/licenses/>.
Some parts of the code in this file are modified or copied
from worldedit by Uberi https://github.com/Uberi/Minetest-WorldEdit
]]
local HEADER = 5 .. ":"
-- Serialise any meta nodes within a volume
-- @param pos1: first vector
-- @param pos2: second vector
-- @return serialised string, node count
function gamehub.serialise_meta(pos1, pos2)
pos1, pos2 = worldedit.sort_pos(pos1, pos2)
worldedit.keep_loaded(pos1, pos2)
local pos = {x=pos1.x, y=0, z=0}
local count = 0
local result = {}
local get_node, get_meta = minetest.get_node, minetest.get_meta
while pos.x <= pos2.x do
pos.y = pos1.y
while pos.y <= pos2.y do
pos.z = pos1.z
while pos.z <= pos2.z do
local node = get_node(pos)
if node.name ~= "air" and node.name ~= "ignore" then
local meta = get_meta(pos):to_table()
local meta_content
-- Convert metadata item stacks to item strings
for name, inventory in pairs(meta.inventory) do
for index, stack in ipairs(inventory) do
meta_content = true
inventory[index] = stack.to_string and stack:to_string() or stack
end
end
for name, field in pairs(meta.fields) do
meta_content = true
end
for k in pairs(meta) do
if k ~= "inventory" and k ~= "fields" then
meta_content = true
break
end
end
if meta_content then
count = count + 1
result[count] = {
x = pos.x - pos1.x,
y = pos.y - pos1.y,
z = pos.z - pos1.z,
name = node.name,
param1 = node.param1 ~= 0 and node.param1 or nil,
param2 = node.param2 ~= 0 and node.param2 or nil,
meta = meta_content and meta or nil,
}
end
end
pos.z = pos.z + 1
end
pos.y = pos.y + 1
end
pos.x = pos.x + 1
end
-- Serialise entries
return HEADER .. minetest.serialize(result), count
end
-- Adds a hollow cube of playerclip double lined with kill
-- designed for games created in the air
-- @param pos: base vector of cube (x=,y=,z=)
-- @param vol: volume (x=,y=,z=)
-- @param clear: replace shield with air (bool)
-- @return number of nodes added
local function wrapper(pos, vol, remove)
local function sort_pos(pos1, pos2)
if pos1.x > pos2.x then
pos2.x, pos1.x = pos1.x, pos2.x
end
if pos1.y > pos2.y then
pos2.y, pos1.y = pos1.y, pos2.y
end
if pos1.z > pos2.z then
pos2.z, pos1.z = pos1.z, pos2.z
end
return pos1, pos2
end
local function volume(pos1, pos2)
local p1, p2 = sort_pos(pos1, pos2)
return (p2.x - p1.x + 1) *
(p2.y - p1.y + 1) *
(p2.z - p1.z + 1)
end
local function get_empty_data(area)
local data = {}
local c_ignore = minetest.get_content_id("ignore")
for i = 1, volume(area.MinEdge, area.MaxEdge) do
data[i] = c_ignore
end
return data
end
local function init(pos1, pos2)
local manip = minetest.get_voxel_manip()
local emerged_pos1, emerged_pos2 = manip:read_from_map(pos1, pos2)
local area = VoxelArea:new({MinEdge=emerged_pos1, MaxEdge=emerged_pos2})
return manip, area
end
local manip, area = init(pos, vector.add(pos, vol))
local data = get_empty_data(area)
local node_1, node_2, msg
if remove == true then
node_1 = minetest.get_content_id("air")
node_2 = node_1
msg = "Shield replaced with air on area id: "
else
node_1 = minetest.get_content_id("maptools:playerclip")
node_2 = minetest.get_content_id("maptools:kill")
msg = "Shield added to area id: "
end
local stride = {x=1, y=area.ystride, z=area.zstride}
local offset = vector.subtract(pos, area.MinEdge)
local count = 0
-- add the nodes
for z = 0, vol.z-1 do
local index_z = (offset.z + z) * stride.z + 1
for y = 0, vol.y-1 do
local index_y = index_z + (offset.y + y) * stride.y
for x = 0, vol.x-1 do
local is_clip = z == 0 or z == vol.z-1
or y == 0 or y == vol.y-1
or x == 0 or x == vol.x-1
local is_kill = z == 1 or z == vol.z-2 or z == vol.z-3
or y == 1 or y == 2 or y == vol.y-2 or y == vol.y-3
or x == 1 or x == 2 or x == vol.x-2 or x == vol.x-3
if is_clip then
local i = index_y + (offset.x + x)
data[i] = node_1
count = count + 1
elseif is_kill then
local i = index_y + (offset.x + x)
data[i] = node_2
count = count + 1
end
end
end
end
manip:set_data(data)
manip:write_to_map()
manip:update_map()
return count, msg
end
-- Adds a protective shield to an area id
-- @param id: area id to shield (int)
-- @param remover: replace shield with air (bool)
-- @return number of nodes added
gamehub.protect = function(id, remove)
local p1, p2, dims
local areas = areas.areas
-- using area vectors
p1 = areas[id].pos1
p2 = areas[id].pos2
-- sort if reqd
if p1.y > p2.y then
p2, p1 = p1, p2
end
-- volume vect
dims = {
x = p2.x - p1.x,
y = p2.y - p1.y,
z = p2.z - p1.z
}
-- unsign if reqd
for k,v in pairs(dims) do
if v < 0 then
dims[k] = (v*v)^0.5
end
end
-- execute, returning node count
return wrapper(p1, dims, remove)
end