The following code adds schem loads aligned to player forward direction. The functions are minor modifications of the original register //load and function load with added support for alignment relative to player:-
The chat command is "//loadalign filename"
NB //allocate will fail to correctly mark the load zone with this command unless you are facing north!
PS: only pos1 (the origin) is required to be set (this is actually also the case for the //load function)
[If I get a chance - next week, I'll add in using the players location to set pos1 if not already set, and possibly also automatically setting pos1/2 to the load-zone for further transformation].
The zone is loaded forward and to the right of the player. origin of the file is set at *save* time - I need to check, but I think as minx,miny,minz, (ie not necessarily at the location of either pos1 or pos2).
The code has only been tested on schem version4, so I'm not 100% sure it works with files saved with an earlier worldedit version.
Paste this at the end of WorldEdit/worldedit_commands/init.lua
Code: Select all
minetest.register_chatcommand("/loadalign", {
params = "<file>",
description = "Load nodes from \"(world folder)/schems/<file>[.we[m]]\" with position 1 of the current WorldEdit region as the origin",
privs = {worldedit=true},
func = function(name, param)
local pos = get_position(name)
if pos == nil then return end
if param == "" then
worldedit.player_notify(name, "invalid usage: " .. param)
return
end
if not string.find(param, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then
worldedit.player_notify(name, "invalid file name: " .. param)
return
end
--find the file in the world path
local testpaths = {
minetest.get_worldpath() .. "/schems/" .. param,
minetest.get_worldpath() .. "/schems/" .. param .. ".we",
minetest.get_worldpath() .. "/schems/" .. param .. ".wem",
}
local file, err
for index, path in ipairs(testpaths) do
file, err = io.open(path, "rb")
if not err then
break
end
end
if err then
worldedit.player_notify(name, "could not open file \"" .. param .. "\"")
return
end
local value = file:read("*a")
file:close()
if worldedit.valueversion(value) == 0 then --unknown version
worldedit.player_notify(name, "invalid file: file is invalid or created with newer version of WorldEdit")
return
end
local yaw = minetest.get_player_by_name(name):get_look_yaw()
if yaw ~= nil then
-- Find angle player facing to enable rotation of position arrow based on yaw.
yaw = math.deg(yaw)
yaw = math.fmod (yaw, 360)
if yaw<0 then yaw = 360 + yaw end
if yaw>360 then yaw = yaw - 360 end
if yaw>315 or yaw<=45 then
rotation="e"
elseif yaw>45 and yaw<=135 then
rotation="n"
elseif yaw>135 and yaw<=225 then
rotation="w"
elseif yaw>225 and yaw<=315 then
rotation="s"
end
end
print (yaw)
print (rotation)
local count = worldedit.deserializeAligned(pos, value, rotation)
worldedit.player_notify(name, count .. " nodes loaded")
end,
})
Paste this at the end of WorldEdit/worldedit/serialization.lua
Code: Select all
--loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized
--contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)
worldedit.deserializeAligned = function(originpos, value, rotation)
--make area stay loaded
local pos1, pos2 = worldedit.allocate(originpos, value)
local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos2)
local originx, originy, originz = originpos.x, originpos.y, originpos.z
local count = 0
local add_node, get_meta = minetest.add_node, minetest.get_meta
local version = worldedit.valueversion(value)
if version == 1 or version == 2 then --original flat table format
--obtain the node table
local get_tables = loadstring(value)
if not get_tables then --error loading value
return count
end
local tables = get_tables()
--transform the node table into an array of nodes
for i = 1, #tables do
for j, v in pairs(tables[i]) do
if type(v) == "table" then
tables[i][j] = tables[v[1]]
end
end
end
local nodes = tables[1]
--load the node array
count = #nodes
if version == 1 then --original flat table format
for index = 1, count do
local entry = nodes[index]
local pos = entry[1]
if rotation == "w" then
pos.x, pos.y, pos.z = originx + pos.z, originy - pos.y, originz - pos.x
elseif rotation == "e" then
pos.x, pos.y, pos.z = originx - pos.z, originy - pos.y, originz + pos.x
elseif rotation == "s" then
pos.x, pos.y, pos.z = originx + pos.x, originy - pos.y, originz + pos.z
else
pos.x, pos.y, pos.z = originx - pos.x, originy - pos.y, originz - pos.z
end
-- pos.x, pos.y, pos.z = originx - pos.x, originy - pos.y, originz - pos.z
add_node(pos, entry[2])
end
else --previous meta flat table format
for index = 1, #nodes do
local entry = nodes[index]
if rotation == "w" then
entry.x, entry.y, entry.z = originx - entry.z, originy + entry.y, originz + entry.x
elseif rotation == "e" then
entry.x, entry.y, entry.z = originx + entry.z, originy + entry.y, originz - entry.x
elseif rotation == "s" then
entry.x, entry.y, entry.z = originx - entry.x, originy + entry.y, originz - entry.z
else
entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
end
-- entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
add_node(entry, entry) --entry acts both as position and as node
get_meta(entry):from_table(entry.meta)
end
end
elseif version == 3 then --previous list format
local pos = {x=0, y=0, z=0}
local node = {name="", param1=0, param2=0}
for x, y, z, name, param1, param2 in value:gmatch("([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)%s+([^%s]+)%s+(%d+)%s+(%d+)[^\r\n]*[\r\n]*") do --match node entries
if rotation == "w" then
pos.x, pos.y, pos.z = originx - tonumber(z), originy + tonumber(y), originz + tonumber(x)
elseif rotation == "e" then
pos.x, pos.y, pos.z = originx + tonumber(z), originy + tonumber(y), originz - tonumber(x)
elseif rotation == "s" then
pos.x, pos.y, pos.z = originx - tonumber(x), originy + tonumber(y), originz - tonumber(z)
else
pos.x, pos.y, pos.z = originx + tonumber(x), originy + tonumber(y), originz + tonumber(z)
end
-- pos.x, pos.y, pos.z = originx + tonumber(x), originy + tonumber(y), originz + tonumber(z)
node.name, node.param1, node.param2 = name, param1, param2
add_node(pos, node)
count = count + 1
end
elseif version == 4 then --current nested table format
--wip: this is a filthy hack that works surprisingly well
value = value:gsub("return%s*{", "", 1):gsub("}%s*$", "", 1)
local escaped = value:gsub("\\\\", "@@"):gsub("\\\"", "@@"):gsub("(\"[^\"]*\")", function(s) return string.rep("@", #s) end)
local startpos, startpos1, endpos = 1, 1
local nodes = {}
while true do
startpos, endpos = escaped:find("},%s*{", startpos)
if not startpos then
break
end
local current = value:sub(startpos1, startpos)
table.insert(nodes, minetest.deserialize("return " .. current))
startpos, startpos1 = endpos, endpos
end
table.insert(nodes, minetest.deserialize("return " .. value:sub(startpos1)))
--local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT
--load the nodes
count = #nodes
for index = 1, count do
local entry = nodes[index]
if rotation == "w" then
entry.x, entry.y, entry.z = originx - entry.z, originy + entry.y, originz + entry.x
elseif rotation == "e" then
entry.x, entry.y, entry.z = originx + entry.z, originy + entry.y, originz - entry.x
elseif rotation == "s" then
entry.x, entry.y, entry.z = originx - entry.x, originy + entry.y, originz - entry.z
else
entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
end
-- entry.x, entry.y, entry.z = originx + entry.x, originy + entry.y, originz + entry.z
add_node(entry, entry) --entry acts both as position and as node
end
--load the metadata
for index = 1, count do
local entry = nodes[index]
get_meta(entry):from_table(entry.meta)
end
end
return count
end