diff --git a/README.md b/README.md index 6a9d928..d726438 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,20 @@ Load nodes from "(world folder)/schems/.we" with position 1 of the current //load some random filename //load huge_base +### //metasave + +Save the current WorldEdit region including metadata to "(world folder)/schems/.wem". + + //metasave some random filename + //metasave huge_base + +### //metaload + +Load nodes and metadata from "(world folder)/schems/.wem" with position 1 of the current WorldEdit region as the origin. + + //metaload some random filename + //metaload huge_base + WorldEdit API ------------- WorldEdit exposes all significant functionality in a simple interface. Adding WorldEdit to the file "depends.txt" in your mod gives you access to all of the `worldedit` functions. These are useful if you're looking for high-performance node manipulation without all the hassle of writing tons of code. @@ -294,6 +308,18 @@ This function is deprecated, and should not be used unless there is a need to su Returns the number of nodes deserialized. +### worldedit.metasave(pos1, pos2, file) + +Saves the nodes and meta defined by positions `pos1` and `pos2` into a file + +Returns the number of nodes saved + +### worldedit.metaload(pos1, file) + +Loads the nodes and meta from `file` to position `pos1` + +Returns the number of nodes loaded + License ------- Copyright 2012 sfan5 and Anthony Zhang (Temperest) diff --git a/functions.lua b/functions.lua index fbdfb54..2d16daf 100644 --- a/functions.lua +++ b/functions.lua @@ -566,3 +566,67 @@ worldedit.deserialize_old = function(originpos, value) end return count end + +--saves the nodes and meta defined by positions `pos1` and `pos2` into a file, returning the number of nodes saved +worldedit.metasave = function(pos1, pos2, file) + local path = minetest.get_worldpath() .. "/schems" + local filename = path .. "/" .. file .. ".wem" + os.execute("mkdir \"" .. path .. "\"") --create directory if it does not already exist + local rows = {} + local pos1, pos2 = worldedit.sort_pos(pos1, pos2) + local pos = {x=pos1.x, y=0, z=0} + local count = 0 + local result = {} + local env = minetest.env + 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 = env:get_node(pos) + if node.name ~= "air" and node.name ~= "ignore" then + count = count + 1 + local row = { + x = pos.x-pos1.x, + y = pos.y-pos1.y, + z = pos.z-pos1.z, + name = node.name, + param1 = node.param1, + param2 = node.param2, + meta = env:get_meta(pos):to_table(), + } + table.insert(rows, row) + end + pos.z = pos.z + 1 + end + pos.y = pos.y + 1 + end + pos.x = pos.x + 1 + end + local err = table.save(rows,filename) + if err then return _,err end + return count +end + +--loads the nodes and meta from `file` to position `pos1`, returning the number of nodes loaded +worldedit.metaload = function(pos1, file) + local filename = minetest.get_worldpath() .. "/schems/" .. file .. ".wem" + local rows, err = table.load(filename) + if err then return _,err end + local pos = {x=0, y=0, z=0} + local node = {name="", param1=0, param2=0} + local count = 0 + local env = minetest.env + for i,row in pairs(rows) do + pos.x = pos1.x + tonumber(row.x) + pos.y = pos1.y + tonumber(row.y) + pos.z = pos1.z + tonumber(row.z) + node.name = row.name + node.param1 = row.param1 + node.param2 = row.param2 + env:add_node(pos, node) + env:get_meta(pos):from_table(row.meta) + count = count + 1 + end + return count +end \ No newline at end of file diff --git a/init.lua b/init.lua index 32bf8e2..1e9b0ef 100644 --- a/init.lua +++ b/init.lua @@ -529,3 +529,49 @@ minetest.register_chatcommand("/load", { minetest.chat_send_player(name, count .. " nodes loaded") end, }) + +minetest.register_chatcommand("/metasave", { + params = "", + description = "Save the current WorldEdit region to \"(world folder)/schems/.wem\"", + privs = {worldedit=true}, + func = function(name, param) + local pos1, pos2 = worldedit.pos1[name], worldedit.pos2[name] + if pos1 == nil or pos2 == nil then + minetest.chat_send_player(name, "No WorldEdit region selected") + return + end + if param == "" then + minetest.chat_send_player(name, "Invalid usage: " .. param) + return + end + local count, err = worldedit.metasave(pos1, pos2, param) + if err then + minetest.chat_send_player(name, "error loading file: " .. err) + else + minetest.chat_send_player(name, count .. " nodes saved") + end + end, +}) + +minetest.register_chatcommand("/metaload", { + params = "", + description = "Load nodes from \"(world folder)/schems/.wem\" with position 1 of the current WorldEdit region as the origin", + privs = {worldedit=true}, + func = function(name, param) + local pos1 = worldedit.pos1[name] + if pos1 == nil then + minetest.chat_send_player(name, "No WorldEdit region selected") + return + end + if param == "" then + minetest.chat_send_player(name, "Invalid usage: " .. param) + return + end + local count, err = worldedit.metaload(pos1, param) + if err then + minetest.chat_send_player(name, "error loading file: " .. err) + else + minetest.chat_send_player(name, count .. " nodes loaded") + end + end, +}) diff --git a/table_save.lua b/table_save.lua new file mode 100644 index 0000000..cbc18ae --- /dev/null +++ b/table_save.lua @@ -0,0 +1,133 @@ +--[[ + Save Table to File + Load Table from File + v 1.0 + + Lua 5.2 compatible + + Only Saves Tables, Numbers and Strings + Insides Table References are saved + Does not save Userdata, Metatables, Functions and indices of these + ---------------------------------------------------- + table.save( table , filename ) + + on failure: returns an error msg + + ---------------------------------------------------- + table.load( filename or stringtable ) + + Loads a table that has been saved via the table.save function + + on success: returns a previously saved table + on failure: returns as second argument an error msg + ---------------------------------------------------- + + Licensed under the same terms as Lua itself. +]]-- +do + -- declare local variables + --// exportstring( string ) + --// returns a "Lua" portable version of the string + local function exportstring( s ) + return string.format("%q", s) + end + + --// The Save Function + function table.save( tbl,filename ) + local charS,charE = " ","\n" + local file,err = io.open( filename, "wb" ) + if err then return err end + + -- initiate variables for save procedure + local tables,lookup = { tbl },{ [tbl] = 1 } + file:write( "return {"..charE ) + + for idx,t in ipairs( tables ) do + file:write( "-- Table: {"..idx.."}"..charE ) + file:write( "{"..charE ) + local thandled = {} + + for i,v in ipairs( t ) do + thandled[i] = true + local stype = type( v ) + -- only handle value + if stype == "table" then + if not lookup[v] then + table.insert( tables, v ) + lookup[v] = #tables + end + file:write( charS.."{"..lookup[v].."},"..charE ) + elseif stype == "string" then + file:write( charS..exportstring( v )..","..charE ) + elseif stype == "number" then + file:write( charS..tostring( v )..","..charE ) + end + end + + for i,v in pairs( t ) do + -- escape handled values + if (not thandled[i]) then + + local str = "" + local stype = type( i ) + -- handle index + if stype == "table" then + if not lookup[i] then + table.insert( tables,i ) + lookup[i] = #tables + end + str = charS.."[{"..lookup[i].."}]=" + elseif stype == "string" then + str = charS.."["..exportstring( i ).."]=" + elseif stype == "number" then + str = charS.."["..tostring( i ).."]=" + end + + if str ~= "" then + stype = type( v ) + -- handle value + if stype == "table" then + if not lookup[v] then + table.insert( tables,v ) + lookup[v] = #tables + end + file:write( str.."{"..lookup[v].."},"..charE ) + elseif stype == "string" then + file:write( str..exportstring( v )..","..charE ) + elseif stype == "number" then + file:write( str..tostring( v )..","..charE ) + end + end + end + end + file:write( "},"..charE ) + end + file:write( "}" ) + file:close() + end + + --// The Load Function + function table.load( sfile ) + local ftables,err = loadfile( sfile ) + if err then return _,err end + local tables = ftables() + for idx = 1,#tables do + local tolinki = {} + for i,v in pairs( tables[idx] ) do + if type( v ) == "table" then + tables[idx][i] = tables[v[1]] + end + if type( i ) == "table" and tables[i[1]] then + table.insert( tolinki,{ i,tables[i[1]] } ) + end + end + -- link indices + for _,v in ipairs( tolinki ) do + tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil + end + end + return tables[1] + end +-- close do +end +-- ChillCode \ No newline at end of file