From 509847b4d19eab5cf791c6483c1e6374cc449a8b Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 20:40:59 +0100 Subject: [PATCH 1/9] Update init.lua Add chat shortcuts for loadalign (load with player alignment) and some helper commands --- worldedit_shortcommands/init.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/worldedit_shortcommands/init.lua b/worldedit_shortcommands/init.lua index a3cbb67..1eb73aa 100644 --- a/worldedit_shortcommands/init.lua +++ b/worldedit_shortcommands/init.lua @@ -47,4 +47,8 @@ worldedit.alias_chatcommand("/hlt", "/highlight") worldedit.alias_chatcommand("/rsr", "/restore") worldedit.alias_chatcommand("/l", "/lua") worldedit.alias_chatcommand("/lt", "/luatransform") -worldedit.alias_chatcommand("/clro", "/clearobjects") \ No newline at end of file +worldedit.alias_chatcommand("/clro", "/clearobjects") +worldedit.alias_chatcommand("/la", "/loadalign") +worldedit.alias_chatcommand("/lao", "/loadalignoffset") +worldedit.alias_chatcommand("/co", "/correctorigin") +worldedit.alias_chatcommand("/oc", "/correctorigin") From c1aadd078d23f68b85ae5ed40d53d950ed4b7911 Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 20:48:42 +0100 Subject: [PATCH 2/9] Update serialization.lua a worldedit.deserializeAligned - new function to enable loading a region with orientation based on player orientation - (and 2 helper functions for it) --- worldedit/serialization.lua | 272 +++++++++++++++++++++++++++++++++++- 1 file changed, 271 insertions(+), 1 deletion(-) diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua index bbedca5..9da3651 100644 --- a/worldedit/serialization.lua +++ b/worldedit/serialization.lua @@ -163,7 +163,10 @@ worldedit.allocate = function(originpos, value) --local nodes = minetest.deserialize(value) --wip: this is broken for larger tables in the current version of LuaJIT + -- The following loop sets up pos1 and pos2 to encompass the boundary of the region, + -- and checks all nodes reference mods present in the current world. If they are not present, they are returned for processing if required. count = #nodes + local missingMods = "" for index = 1, count do local entry = nodes[index] x, y, z = originx + entry.x, originy + entry.y, originz + entry.z @@ -173,11 +176,24 @@ worldedit.allocate = function(originpos, value) if x > pos2x then pos2x = x end if y > pos2y then pos2y = y end if z > pos2z then pos2z = z end + local colonLoc = string.find(entry.name, ":") + if colonLoc ~= nil then + local curMod = entry.name:sub(0,colonLoc-1) + if not string.find(missingMods, (curMod.. ";")) then + if not minetest.get_modpath(curMod) then + missingMods = missingMods.. curMod.. "; " + end + end + end + end + if string.len(missingMods) ~= 0 then + print("Worldedit file dependencies include the following missing mods:") + print(missingMods) end end local pos1 = {x=pos1x, y=pos1y, z=pos1z} local pos2 = {x=pos2x, y=pos2y, z=pos2z} - return pos1, pos2, count + return pos1, pos2, count, missingMods end --loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized @@ -271,3 +287,257 @@ worldedit.deserialize = function(originpos, value) end return count end + + +-- create a copy of a node added by worldedit.deserializeAligned, then rotate it and replace the original with the correctly aligned copy +-- hopefully this function is not required, but is included as it may aid/improve backward compatibility if worldedit.getNewRotation doesn't work properly +worldedit.screwdriver_handler = function(pos, axisChange) + -- This function is hopefully not needed, but is included just in case (for old file formats) + -- the basis of this is the minetest screwdriver function + -- it would probably + if axisChange == "Z" then return end + + -- create a copy of the node + local nodeRot = minetest.get_node({x=pos.x, y=pos.y, z=pos.z}) + + -- Get ready to set the param2 + local n = nodeRot.param2 + + -- screwdriver uses axis direction. not sure why, but leave it there just in case... + local axisdir = math.floor(n / 4) + local rotation = n - axisdir * 4 + -- screwdriver uses a separate function rather than modulus. Not sure why, but this seems to work + if axisChange == "X" then + n = axisdir * 4 + ((rotation + 1) % 4) + elseif axisChange == "z" then + n = axisdir * 4 + ((rotation + 2) % 4) + elseif axisChange == "x" then + n = axisdir * 4 + ((rotation + 3) % 4) + else + n = axisdir * 4 + end + + -- now replace the node with the copied one + nodeRot.param2 = n + minetest.swap_node({x=pos.x, y=pos.y, z=pos.z}, nodeRot) + +end + +-- return the correct orientation for a node within a region being loaded by worldedit.deserializeAligned +worldedit.getNewRotation = function(param2, axisChange) + -- the basis of this is the minetest screwdriver function + if axisChange == "Z" then return param2 end + + -- screwdriver uses axisdir. not sure why, but leave it there just in case... + local axisdir = math.floor(param2 / 4) + local rotation = param2 - axisdir * 4 + -- screwdriver uses a separate function rather than modulus. Not sure why, but modulus seems to work without the extra call + if axisChange == "X" then + param2 = axisdir * 4 + ((rotation + 1) % 4) + elseif axisChange == "z" then + param2 = axisdir * 4 + ((rotation + 2) % 4) + elseif axisChange == "x" then + param2 = axisdir * 4 + ((rotation + 3) % 4) + end + + -- now return the new param2 + return param2 +end + +--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, axis) + --make area stay loaded + local pos1, pos2 = worldedit.allocate(originpos, value) + local manip = minetest.get_voxel_manip() + manip:read_from_map(pos1, pos2) + + local huge = math.huge + local originx, originy, originz = originpos.x, originpos.y, originpos.z + local count = 0 + local pos1x, pos1y, pos1z = huge, huge, huge + local pos2x, pos2y, pos2z = -huge, -huge, -huge + local add_node, get_meta = minetest.add_node, minetest.get_meta + local version = worldedit.valueversion(value) +-- print ("Debug info deserializeAligned: version: ".. version) +-- minetest.chat_send_all("Debug info deserializeAligned: version: ".. version) + + 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 + print ("WorldEdit deserializeAligned: attempting to rotate untested file format version: 1") + for index = 1, count do + local entry = nodes[index] + local pos = entry[1] + if axis == "x" then + pos.x, pos.y, pos.z = originx + pos.z, originy - pos.y, originz - pos.x + elseif axis == "X" then + pos.x, pos.y, pos.z = originx - pos.z, originy - pos.y, originz + pos.x + elseif axis == "z" then + pos.x, pos.y, pos.z = originx + pos.x, originy - pos.y, originz + pos.z + elseif axis == "Z" then + 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 + if pos.x < pos1x then pos1x = pos.x end + if pos.y < pos1y then pos1y = pos.y end + if pos.z < pos1z then pos1z = pos.z end + if pos.x > pos2x then pos2x = pos.x end + if pos.y > pos2y then pos2y = pos.y end + if pos.z > pos2z then pos2z = pos.z end + entry[2].param2 = worldedit.getNewRotation(entry[2].param2,axis) -- adjust param2 (rotation of the node) to match the overall rotation of the load + -- this has only been tested to work with version == 4 + -- I'm not sure of the format, so if it wouldn't work then disable and + -- enable the worldedit.screwdriver_handler after the node has been added + add_node(pos, entry[2]) + -- worldedit.screwdriver_handler({x=pos.x, y=pos.y, z=pos.z}, axis) -- this would rotate the node after it's been placed (just in case needed for old format) + end + else --previous meta flat table format + print ("WorldEdit deserializeAligned: attempting to rotate untested file format version: 2") + for index = 1, #nodes do + local entry = nodes[index] + if axis == "x" then + entry.x, entry.y, entry.z = originx - entry.z, originy + entry.y, originz + entry.x + elseif axis == "X" then + entry.x, entry.y, entry.z = originx + entry.z, originy + entry.y, originz - entry.x + elseif axis == "z" then + entry.x, entry.y, entry.z = originx - entry.x, originy + entry.y, originz - entry.z + elseif axis == "Z" then + 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 + + + if entry.x < pos1x then pos1x = entry.x end + if entry.y < pos1y then pos1y = entry.y end + if entry.z < pos1z then pos1z = entry.z end + if entry.x > pos2x then pos2x = entry.x end + if entry.y > pos2y then pos2y = entry.y end + if entry.z > pos2z then pos2z = entry.z end + + entry.param2 = worldedit.getNewRotation(entry.param2,axis) -- adjust param2 (rotation of the node) to match the overall rotation of the load + -- this has only been tested to work with version == 4 + -- I'm not sure of the format, so if it wouldn't work then disable and + -- enable the worldedit.screwdriver_handler after the node has been added + add_node(entry, entry) --entry acts both as position and as node + -- worldedit.screwdriver_handler({x=entry.x, y=entry.y, z=entry.z}, axis) -- this would rotate the node after it's been placed (just in case needed for old format) + + get_meta(entry):from_table(entry.meta) + end + end + elseif version == 3 then --previous list format + print ("WorldEdit deserializeAligned: attempting to rotate untested file format version: 3") + 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 axis == "x" then + pos.x, pos.y, pos.z = originx - tonumber(z), originy + tonumber(y), originz + tonumber(x) + elseif axis == "X" then + pos.x, pos.y, pos.z = originx + tonumber(z), originy + tonumber(y), originz - tonumber(x) + elseif axis == "z" then + pos.x, pos.y, pos.z = originx - tonumber(x), originy + tonumber(y), originz - tonumber(z) + elseif axis == "z" then + 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 + + if pos.x < pos1x then pos1x = pos.x end + if pos.y < pos1y then pos1y = pos.y end + if pos.z < pos1z then pos1z = pos.z end + if pos.x > pos2x then pos2x = pos.x end + if pos.y > pos2y then pos2y = pos.y end + if pos.z > pos2z then pos2z = pos.z end + + node.param2 = worldedit.getNewRotation(node.param2,axis) -- adjust param2 (rotation of the node) to match the overall rotation of the load + -- this has only been tested to work with version == 4 + -- I'm not sure of the format, so if it wouldn't work then disable and + -- enable the worldedit.screwdriver_handler after the node has been added + add_node(pos, node) + -- worldedit.screwdriver_handler({x=pos.x, y=pos.y, z=pos.z}, axis) -- this would rotate the node after it's been placed (just in case needed for old format) + 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 = {} + -- loop through the loaded file, and save each piece of node information to the node table + 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] + print("Node: name: ".. entry.name) + + if axis == "x" then + entry.x, entry.y, entry.z = originx - entry.z, originy + entry.y, originz + entry.x + elseif axis == "X" then + entry.x, entry.y, entry.z = originx + entry.z, originy + entry.y, originz - entry.x + elseif axis == "z" then + entry.x, entry.y, entry.z = originx - entry.x, originy + entry.y, originz - entry.z + elseif axis == "Z" then + 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 + + if entry.x < pos1x then pos1x = entry.x end + if entry.y < pos1y then pos1y = entry.y end + if entry.z < pos1z then pos1z = entry.z end + if entry.x > pos2x then pos2x = entry.x end + if entry.y > pos2y then pos2y = entry.y end + if entry.z > pos2z then pos2z = entry.z end + + entry.param2 = worldedit.getNewRotation(entry.param2,axis) -- adjust param2 (rotation of the node) to match the overall rotation of the load + 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 + + -- Correct pos1 and pos2 location so markers appear as they would have without rotation (ie when saved with corrected origin) + if axis == "x" then + pos1x, pos2x = pos2x, pos1x + elseif axis == "X" then + pos1z, pos2z = pos2z, pos1z + elseif axis == "z" then + pos1x, pos2x = pos2x, pos1x + pos1z, pos2z = pos2z, pos1z + end + return count, {x=pos1x, y=pos1y, z=pos1z}, {x=pos2x, y=pos2y, z=pos2z} +end From daa7234c69d583f4f21a164c369bed80c38528ad Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 20:55:19 +0100 Subject: [PATCH 3/9] Update init.lua add /loadalign command - command to allow loading of a schem file which is aligned to player forward direction (and some helper commands) --- worldedit_commands/init.lua | 173 +++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 1 deletion(-) diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index 2bbfeed..63371d2 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -854,6 +854,7 @@ minetest.register_chatcommand("/allocate", { privs = {worldedit=true}, func = function(name, param) local pos = get_position(name) + local missingMods = "" if pos == nil then return end if param == "" then @@ -878,7 +879,7 @@ minetest.register_chatcommand("/allocate", { worldedit.player_notify(name, "invalid file: file is invalid or created with newer version of WorldEdit") return end - local nodepos1, nodepos2, count = worldedit.allocate(pos, value) + local nodepos1, nodepos2, count, missingMods = worldedit.allocate(pos, value) worldedit.pos1[name] = nodepos1 worldedit.mark_pos1(name) @@ -886,6 +887,9 @@ minetest.register_chatcommand("/allocate", { worldedit.mark_pos2(name) worldedit.player_notify(name, count .. " nodes allocated") + if missingMods ~= "" then + worldedit.player_notify(name, "Warning: schem file contains references to the following missing mods: ".. missingMods) + end end, }) @@ -937,6 +941,173 @@ minetest.register_chatcommand("/load", { end, }) +-- Chat command to move pos1 and pos2 to correct origin (ie pos1 located with minimum x,y,z, pos2 with maximum x,y,z) +-- this is ideally used before /save to decrease confusion with placement for /load and /loadalign +-- This command has a helper function of worldedit.correctOrigin (located below) +-- Shortcut of /co and /oc (to ease confusion) is set in worldedit_shortcommands/init.lua +minetest.register_chatcommand("/correctorigin", { + params = "", + description = "Moves pos1 and pos2 so region is marked with pos1 at the origin (ie minimum x,y,z)", + privs = {worldedit=true}, + func = function(name) + worldedit.correctOrigin(name) + end, +}) + +--Corrects pos1 and pos2 so pos1 is located at the region origin - (ie pos1 located with minimum x,y,z, pos2 with maximum z,y,z) +-- not sure where best located, so left with the chat command. +worldedit.correctOrigin = function(name) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + + if pos1 == nil or pos2 == nil then + worldedit.player_notify(name, "no region selected") + return nil + end + + pos1, pos2 = worldedit.sort_pos(pos1, pos2) + + worldedit.pos1[name] = pos1 + worldedit.mark_pos1(name) + worldedit.pos2[name] = pos2 + worldedit.mark_pos2(name) +end + +-- Chat command to enable a global variable which enables an offset to the player (or pos1) location for /loadalign +-- This can be useful it a particular location is not easily accessible (eg if you want a file y-origin to be below ground level, or x- or z- inside a cliff) +-- the offset is cleared by using the command without params (=arguments) +-- Shortcut of /lao is set in worldedit_shortcommands/init.lua +minetest.register_chatcommand("/loadalignoffset", { + params = "x y z", + description = "Set an offset for the worldedit command /loadaligned (x y z)", + privs = {worldedit=true}, + func = function(name, param) + local found, _, x, y, z = param:find("^([+-]?%d+)%s+([+-]?%d+)%s+([+-]?%d+)$") + if x == nil or y == nil or z == nil then + worldedit.player_notify(name, "LoadAlign Offset set to 0 for all axes (to set provide: 'x y z')") + laPosOffset = {x=tonumber(0), y=tonumber(0), z=tonumber(0)} + else + laPosOffset = {x=tonumber(x), y=tonumber(y), z=tonumber(z)} + end + end, +}) + + +-- Chat command to allow loading of a schem file which is aligned to player forward direction. The loaded schem will be in a region to the front, right and above the players location. +-- If the location is not easily accessible (eg if you want a file y-origin to be below ground level, or x- or z- inside a cliff), you can set an offset with /loadalignoffset +-- The player is moved backwards one space to moved them out of the load zone (or more if there is and offset). This may mean the player ends up inside a node (if it suddenly gets dark). You may be able to step out. If not you'll have to teleport to an unblocked location. +-- The /save command saves the file with the origin at the xmin,ymin,zmin, irrespective of where pos1 and pos2 are. To reduce confusion it is suggested that you use the /correctorigin command before saving +-- to move the markers to reflect this, but if you are copying a section one node wide, there are two possible orientations. +-- You need to be facing in the positive z direction to correctly orient yourself to the orientation when it is reloaded. +-- If you are using a schem regularly, and markers are not in your prefered orientation, it is best to do an initial /loadalign to get the correct orientation, then resave it +-- The loaded region is marked with pos1/pos2 with pos1 where the origin would have been when the schem was saved. +-- The function has only been tested with the current (version 4) schem files, so consider use with older schem files to be at your own risk. +-- The most likely bugs with untested versions are: either the entire region is incorrectly rotated or individual nodes are incorrectly oriented (so faces point in the incorrect direction) +-- The functions is a modifications of the original register //load to support alignment relative to player, so code from the screwdriver mod was used as a starter for node orientation. +-- The main functions are in the WorldEdit/worldedit/serialization.lua (worldedit.deserializeAligned which also uses worldedit.getNewRotation, and might need worldedit.screwdriver_handler +-- depending on compatibility with old files) +-- Shortcut of /la is set in worldedit_shortcommands/init.lua +minetest.register_chatcommand("/loadalign", { + params = "", + -- usePlayer (p) forces using player location rather than position markers prior to load. markImport (m) places pos1/pos2 around the new region" + description = "Load nodes from \"(world folder)/schems/[.we[m]]\" with position 1 (or player location) of the current WorldEdit region as the origin. xyz offset from the player/pos1 position (eg for foundations), can be set with /loadalignoffset.", + privs = {worldedit=true}, + func = function(name, param) + local posOffx, posOffy, posOffz + local player = minetest.get_player_by_name(name) + local plPos = player:getpos() + local pos + + + -- There's probably a snazzy way of using patterns to enable multiple optional parameters including a filename, but I don't know how... + -- ideally I would like to be able to supply as params: filename, pos, usePlayer, markImport + fileName = param + -- if this function ever gets merged with load, it's probably easier to be able to determine if player should be used as the origin + -- also anything but 'p' will use pos1 as the origin (if it's set), and just use the player for alignment + usePlayer = "p" + markImport = "m" -- mark the dimensions of the loaded section (anything but 'm' will not mark + + + -- if set use the global posOffset (as this enables offset to be set once and reused) + if posOffset == nil then + posOffx, posOffy, posOffz = 0, 0, 0 + else + posOffx, posOffy, posOffz = laPosOffset.x, laPosOffset.y, laPosOffset.z + end + + if usePlayer ~= "p" then pos = get_position(name) end + if pos == nil then + usePlayer = "p" + pos = plPos + end + pos = {x=math.floor(pos.x+posOffx+0.51),y=math.floor(pos.y+posOffy+0.51),z=math.floor(pos.z+posOffz+0.51)} + + + if fileName == "" then + worldedit.player_notify(name, "invalid usage: " .. param) + return + end + if not string.find(fileName, "^[%w \t.,+-_=!@#$%%^&*()%[%]{};'\"]+$") then + worldedit.player_notify(name, "invalid file name: " .. param) + return + end + + --find the file in the world path, check it exists + local testpaths = { + minetest.get_worldpath() .. "/schems/" .. fileName, + minetest.get_worldpath() .. "/schems/" .. fileName .. ".we", + minetest.get_worldpath() .. "/schems/" .. fileName .. ".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() + + -- check the schem version is recognised + 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 + + -- identify the direction the player is facing, and move them player out of the load region + local dir = player:get_look_dir() + local axx, axy, axz = math.abs(dir.x), math.abs(dir.y), math.abs(dir.z) + if axx > axz and dir.x >= 0 then + axis = "X" + if usePlayer == "p" then player:setpos({x=(plPos.x-1+posOffx), y=plPos.y, z=plPos.z}) end + elseif axx > axz and dir.x < 0 then + axis = "x" + if usePlayer == "p" then player:setpos({x=(plPos.x+1-posOffx), y=plPos.y, z=plPos.z}) end + elseif axx < axz and dir.z >= 0 then + axis = "Z" + if usePlayer == "p" then player:setpos({x=plPos.x, y=plPos.y, z=(plPos.z-1+posOffz)}) end + elseif axx < axz and dir.z < 0 then + axis = "z" + if usePlayer == "p" then player:setpos({x=plPos.x, y=plPos.y, z=(plPos.z+1-posOffz)}) end + end + + local count, pos1, pos2 = worldedit.deserializeAligned(pos, value, axis) + + -- placer pos1 and pos2 markers around the loaded region + if markImport == "m" then + worldedit.pos1[name] = pos1 + worldedit.mark_pos1(name) + worldedit.pos2[name] = pos2 + worldedit.mark_pos2(name) + end + + worldedit.player_notify(name, (count .. " nodes loaded. PlayerFacing: ".. axis.. " Location: x=".. pos.x.. " y=".. pos.y.. " z=".. pos.z.. " Offset: x=".. posOffx.. " y=".. posOffy.. " z=".. posOffz )) --.. x ", y=".. y, "z=".. z) + end, +}) + minetest.register_chatcommand("/lua", { params = "", description = "Executes as a Lua chunk in the global namespace", From 0720ec2b7754055ec0b0824d9552c2dc55d50335 Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 21:11:35 +0100 Subject: [PATCH 4/9] Update init.lua add /loadalign command - command to allow loading of a schem file which is aligned to player forward direction (and some helper commands) --- worldedit_commands/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index 63371d2..6a672b6 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -1028,7 +1028,7 @@ minetest.register_chatcommand("/loadalign", { -- if set use the global posOffset (as this enables offset to be set once and reused) - if posOffset == nil then + if laPosOffset == nil then posOffx, posOffy, posOffz = 0, 0, 0 else posOffx, posOffy, posOffz = laPosOffset.x, laPosOffset.y, laPosOffset.z From a02ed6c522f9aa7c0fcc0fc465694efa7ea402b6 Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 21:20:21 +0100 Subject: [PATCH 5/9] Update serialization.lua add worldedit.deserializeAligned - new function to enable loading a region with orientation based on player orientation - (and 2 helper functions for it) update worldedit.load to return list of missing mods --- worldedit/serialization.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua index 9da3651..07f9db3 100644 --- a/worldedit/serialization.lua +++ b/worldedit/serialization.lua @@ -200,7 +200,7 @@ end --contains code based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible) worldedit.deserialize = function(originpos, value) --make area stay loaded - local pos1, pos2 = worldedit.allocate(originpos, value) + local pos1, pos2, count, missingMods = worldedit.allocate(originpos, value) local manip = minetest.get_voxel_manip() manip:read_from_map(pos1, pos2) @@ -285,7 +285,7 @@ worldedit.deserialize = function(originpos, value) get_meta(entry):from_table(entry.meta) end end - return count + return count, missingMods end @@ -348,7 +348,7 @@ end --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, axis) --make area stay loaded - local pos1, pos2 = worldedit.allocate(originpos, value) + local pos1, pos2, count, missingMods = worldedit.allocate(originpos, value) local manip = minetest.get_voxel_manip() manip:read_from_map(pos1, pos2) @@ -539,5 +539,5 @@ worldedit.deserializeAligned = function(originpos, value, axis) pos1x, pos2x = pos2x, pos1x pos1z, pos2z = pos2z, pos1z end - return count, {x=pos1x, y=pos1y, z=pos1z}, {x=pos2x, y=pos2y, z=pos2z} + return count, {x=pos1x, y=pos1y, z=pos1z}, {x=pos2x, y=pos2y, z=pos2z}, missingMods end From e11b0b336676a20f7322b41ac67fb1159bf4ad21 Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 21:26:23 +0100 Subject: [PATCH 6/9] Update init.lua add /loadalign command - command to allow loading of a schem file which is aligned to player forward direction (and some helper commands). Also update /allocate and /load to report missing mods --- worldedit_commands/init.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/worldedit_commands/init.lua b/worldedit_commands/init.lua index 6a672b6..3db9bbe 100644 --- a/worldedit_commands/init.lua +++ b/worldedit_commands/init.lua @@ -900,6 +900,7 @@ minetest.register_chatcommand("/load", { func = function(name, param) local pos = get_position(name) if pos == nil then return end + local missingMods = "" if param == "" then worldedit.player_notify(name, "invalid usage: " .. param) @@ -935,9 +936,12 @@ minetest.register_chatcommand("/load", { return end - local count = worldedit.deserialize(pos, value) + local count, missingMods = worldedit.deserialize(pos, value) worldedit.player_notify(name, count .. " nodes loaded") + if missingMods ~= "" then + worldedit.player_notify(name, "Warning: schem file contains references to the following missing mods: ".. missingMods) + end end, }) @@ -1016,6 +1020,7 @@ minetest.register_chatcommand("/loadalign", { local player = minetest.get_player_by_name(name) local plPos = player:getpos() local pos + local missingMods = "" -- There's probably a snazzy way of using patterns to enable multiple optional parameters including a filename, but I don't know how... @@ -1094,7 +1099,7 @@ minetest.register_chatcommand("/loadalign", { if usePlayer == "p" then player:setpos({x=plPos.x, y=plPos.y, z=(plPos.z+1-posOffz)}) end end - local count, pos1, pos2 = worldedit.deserializeAligned(pos, value, axis) + local count, pos1, pos2, missingMods = worldedit.deserializeAligned(pos, value, axis) -- placer pos1 and pos2 markers around the loaded region if markImport == "m" then @@ -1105,6 +1110,9 @@ minetest.register_chatcommand("/loadalign", { end worldedit.player_notify(name, (count .. " nodes loaded. PlayerFacing: ".. axis.. " Location: x=".. pos.x.. " y=".. pos.y.. " z=".. pos.z.. " Offset: x=".. posOffx.. " y=".. posOffy.. " z=".. posOffz )) --.. x ", y=".. y, "z=".. z) + if missingMods ~= "" then + worldedit.player_notify(name, "Warning: schem file contains references to the following missing mods: ".. missingMods) + end end, }) From d3b43e1d60e3e21a6e35126b31a98fdb819f6279 Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 22:06:10 +0100 Subject: [PATCH 7/9] oops, missed pasting the correction of allocate return function --- worldedit/serialization.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldedit/serialization.lua b/worldedit/serialization.lua index 07f9db3..b917ec8 100644 --- a/worldedit/serialization.lua +++ b/worldedit/serialization.lua @@ -89,11 +89,12 @@ worldedit.allocate = function(originpos, value) local originx, originy, originz = originpos.x, originpos.y, originpos.z local count = 0 local version = worldedit.valueversion(value) + local missingMods = "" if version == 1 or version == 2 then --flat table format --obtain the node table local get_tables = loadstring(value) if get_tables then --error loading value - return originpos, originpos, count + return originpos, originpos, count, missingMods end local tables = get_tables() @@ -166,7 +167,6 @@ worldedit.allocate = function(originpos, value) -- The following loop sets up pos1 and pos2 to encompass the boundary of the region, -- and checks all nodes reference mods present in the current world. If they are not present, they are returned for processing if required. count = #nodes - local missingMods = "" for index = 1, count do local entry = nodes[index] x, y, z = originx + entry.x, originy + entry.y, originz + entry.z From 37b93a063d4665ed97ec1e22385dc613ba9ad10a Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 22:44:50 +0100 Subject: [PATCH 8/9] Update Chat Commands.md added help for /loadalign, /loadalignoffset, /correctorigin --- Chat Commands.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Chat Commands.md b/Chat Commands.md index c3d5250..210dd13 100644 --- a/Chat Commands.md +++ b/Chat Commands.md @@ -22,6 +22,10 @@ Many commands also have shorter names that can be typed faster. For example, if | `//hdo` | `//hollowdome` | | `//do` | `//dome` | | `//hcyl` | `//hollowcylinder` | +| `//co` | `//correctorigin` | +| `//oc` | `//correctorigin` | +| `//la` | `//loadalign` | +| `//lao` | `//loadalignoffset`| ### `//about` @@ -318,6 +322,44 @@ Load nodes from "(world folder)/schems/``.we" with position 1 of the curre //load some random filename //load huge_base +### `//correctorigin` + +Moves pos1 and pos2 so pos1 is at the origin of the region (ie pos1 located with minimum x,y,z, pos2 with maximum x,y,z) +This is ideally used before /save to decrease confusion with placement for /load and /loadalign +Shortcut of /co and /oc (to ease confusion) is set in worldedit_shortcommands/init.lua + + //correctorigin + +### `//loadalignoffset [x y z]` + +Set a global variable to enable an offset to the player location for /loadalign +-- This can be useful it a particular location is not easily accessible (eg if you want a file y-origin to be below ground level, or x- or z- inside a cliff) +-- the offset is cleared by using the command without params (=arguments) +-- Shortcut of /lao is set in worldedit_shortcommands/init.lua + + //load + //load x y z + +### `//loadalign ` + +Load nodes from "(world folder)/schems/``.we" with player location as the origin. The loaded schem will be in a region to the front, right and above the players location. +If the location is not easily accessible (eg if you want a file y-origin to be below ground level, or x- or z- inside a cliff), you can set an offset with /loadalignoffset +The player is moved backwards one space to moved them out of the load zone (or more if there is and offset). This may mean the player ends up inside a node (if it suddenly gets dark). You may be able to step out. If not you'll have to teleport to an unblocked location. +The /save command saves the file with the origin at the xmin,ymin,zmin, irrespective of where pos1 and pos2 are. To reduce confusion it is suggested that you use the /correctorigin command before saving + to move the markers to reflect this, but if you are copying a section one node wide, there are two possible orientations. + You need to be facing in the positive z direction to correctly orient yourself to the orientation when it is reloaded. + If you are using a schem regularly, and markers are not in your prefered orientation, it is best to do an initial /loadalign to get the correct orientation, then resave it +The loaded region is marked with pos1/pos2 with pos1 where the origin would have been when the schem was saved. +The function has only been tested with the current (version 4) schem files, so consider use with older schem files to be at your own risk. + The most likely bugs with untested versions are: either the entire region is incorrectly rotated or individual nodes are incorrectly oriented (so faces point in the incorrect direction) +The functions is a modifications of the original register //load to support alignment relative to player, so code from the screwdriver mod was used as a starter for node orientation. + The main functions are in the WorldEdit/worldedit/serialization.lua (worldedit.deserializeAligned which also uses worldedit.getNewRotation, and might need worldedit.screwdriver_handler + depending on compatibility with old files) +Shortcut of /la is set in worldedit_shortcommands/init.lua + + //loadalign some random filename + //loadalign huge_base + ### `//lua ` Executes `` as a Lua chunk in the global namespace. From 5993de0d5c2c44932392a4b581b65f368b781390 Mon Sep 17 00:00:00 2001 From: dgm3333 Date: Mon, 26 May 2014 22:52:07 +0100 Subject: [PATCH 9/9] Update Chat Commands.md added message about /allocate mod checking --- Chat Commands.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Chat Commands.md b/Chat Commands.md index 210dd13..8a0a7cd 100644 --- a/Chat Commands.md +++ b/Chat Commands.md @@ -311,6 +311,7 @@ Save the current WorldEdit region to "(world folder)/schems/``.we". ### `//allocate ` Set the region defined by nodes from "(world folder)/schems/``.we" as the current WorldEdit region. +Also display any mods which are not currently enabled in the world, but are referenced in the schem file. //allocate some random filename //allocate huge_base @@ -318,6 +319,7 @@ Set the region defined by nodes from "(world folder)/schems/``.we" as the ### `//load ` Load nodes from "(world folder)/schems/``.we" with position 1 of the current WorldEdit region as the origin. +NB is it suggested you do a dummy-run with //allocate to list referenced mods not currently enabled (which will cause errors) //load some random filename //load huge_base @@ -343,6 +345,8 @@ Set a global variable to enable an offset to the player location for /loadalign ### `//loadalign ` Load nodes from "(world folder)/schems/``.we" with player location as the origin. The loaded schem will be in a region to the front, right and above the players location. +NB is it suggested you do a dummy-run with //allocate to list referenced mods not currently enabled (which will cause errors) + If the location is not easily accessible (eg if you want a file y-origin to be below ground level, or x- or z- inside a cliff), you can set an offset with /loadalignoffset The player is moved backwards one space to moved them out of the load zone (or more if there is and offset). This may mean the player ends up inside a node (if it suddenly gets dark). You may be able to step out. If not you'll have to teleport to an unblocked location. The /save command saves the file with the origin at the xmin,ymin,zmin, irrespective of where pos1 and pos2 are. To reduce confusion it is suggested that you use the /correctorigin command before saving