metadata is now saved as well

master
Sokomine 2015-05-09 16:47:10 +02:00
parent b68e2a95b5
commit a52149a1e6
4 changed files with 203 additions and 26 deletions

View File

@ -126,6 +126,25 @@ end
build_chest.show_size_data = function( building_name )
if( not( building_name )
or building_name == ''
or not( build_chest.building[ building_name ] )
or not( build_chest.building[ building_name ].size )) then
return "";
end
local size = build_chest.building[ building_name ].size;
-- show which building has been selected
return "label[0.3,9.5;Selected building:]"..
"label[2.3,9.5;"..minetest.formspec_escape(building_name).."]"..
-- size of the building
"label[0.3,9.8;Size ( wide x length x height ):]"..
"label[4.3,9.8;"..tostring( size.x )..' x '..tostring( size.z )..' x '..tostring( size.y ).."]";
end
build_chest.update_formspec = function( pos, page, player, fields )
@ -164,19 +183,8 @@ build_chest.update_formspec = function( pos, page, player, fields )
"label[0.3,0.8;Part of village:]" .."label[3.3,0.8;"..(village_name or "?").."]"
.."label[7.3,0.8;located at "..(minetest.pos_to_string( village_pos ) or '?').."]"..
"label[0.3,1.2;Owned by:]" .."label[3.3,1.2;"..(owner_name or "?").."]"..
"label[3.3,1.6;Click on a menu entry to select it:]";
if( building_name and building_name ~= '' and build_chest.building[ building_name ] and build_chest.building[ building_name ].size) then
local size = build_chest.building[ building_name ].size;
formspec = formspec..
-- show which building has been selected
"label[0.3,9.5;Selected building:]"..
"label[2.3,9.5;"..minetest.formspec_escape(building_name).."]"..
-- size of the building
"label[0.3,9.8;Size ( wide x length x height ):]"..
"label[4.3,9.8;"..tostring( size.x )..' x '..tostring( size.z )..' x '..tostring( size.y ).."]";
end
"label[3.3,1.6;Click on a menu entry to select it:]"..
build_chest.show_size_data( building_name );
local current_path = minetest.deserialize( meta:get_string( 'current_path' ) or 'return {}' );
if( #current_path > 0 ) then
@ -383,7 +391,9 @@ build_chest.update_formspec = function( pos, page, player, fields )
meta:set_string( 'building_name', options[1] );
local start_pos = build_chest.get_start_pos( pos );
if( type(start_pos)=='table' and start_pos and start_pos.x and build_chest.building[ options[1]].size) then
-- TODO: also show size and such
-- size information has just been read; we can now display it
formspec = formspec..build_chest.show_size_data( building_name );
-- do replacements for realtest where necessary (this needs to be done only once)
local replacements = {};
replacements_group['realtest'].replace( replacements );
@ -555,20 +565,23 @@ build_chest.on_receive_fields = function(pos, formname, fields, player)
local end_pos = minetest.deserialize( meta:get_string('end_pos'));
local filename = meta:get_string('backup' );
if( not( filename ) or filename == "" ) then
-- <worldname>/backup_PLAYERNAME_x_y_z_burried_rotation.mts
filename = minetest.get_worldpath()..'/backup_'..
local base_filename = 'backup_'..
meta:get_string('owner')..'_'..
tostring( start_pos.x )..':'..tostring( start_pos.y )..':'..tostring( start_pos.z )..'_'..
'0_0.mts';
'0_0';
-- TODO: handle metadata
-- create directory for the schematics (same path as WorldEdit uses)
os.execute("mkdir \""..minetest.get_worldpath().."/schems".. "\"");
save_restore.create_directory( '/schems' );
-- store a backup of the original landscape
minetest.create_schematic( start_pos, end_pos, nil, filename, nil);
meta:set_string('backup', filename );
-- <worldname>/backup_PLAYERNAME_x_y_z_burried_rotation.mts
filename = minetest.get_worldpath()..'/schems/'..base_filename..'.mts';
minetest.create_schematic( start_pos, end_pos, nil, filename, nil);
-- save metadata and clear it so that the new building can be placed
handle_schematics.save_meta( start_pos, end_pos, base_filename, true );
meta:set_string('backup', base_filename );
minetest.chat_send_player( pname, 'CREATING backup schematic for this place in '..tostring( filename )..'.');
minetest.chat_send_player( pname, 'CREATING backup schematic for this place in \"schems/'..base_filename..'.mts\".');
end
-- TODO: use scaffolding here (exchange some replacements)
@ -590,9 +603,13 @@ mirror = nil;
local start_pos = minetest.deserialize( meta:get_string('start_pos'));
local end_pos = minetest.deserialize( meta:get_string('end_pos'));
local backup_file = meta:get_string( 'backup' );
if( start_pos and end_pos and start_pos.x and end_pos.x and backup_file and backup_file ~= "") then
minetest.place_schematic( start_pos, backup_file, "0", {}, true );
meta:set_string('backup', nil );
if( start_pos and end_pos and start_pos.x and end_pos.x and backup_file and backup_file ~= "" ) then
if( save_restore.file_exists( 'schems/'..backup_file..'.mts' )) then
filename = minetest.get_worldpath()..'/schems/'..backup_file..'.mts';
minetest.place_schematic( start_pos, filename, "0", {}, true );
handle_schematics.restore_meta( backup_file );
meta:set_string('backup', nil );
end
end
@ -700,10 +717,12 @@ mirror = nil;
-- TODO: forbid overwriting existing files?
local worldpath = minetest.get_worldpath();
local filename_complete = worldpath..'/schems/'..filename..'.mts';
-- make sure the directory exists...
os.execute("mkdir \""..minetest.get_worldpath().."/schems".. "\"");
-- create directory for the schematics (same path as WorldEdit uses)
save_restore.create_directory( '/schems' );
-- really save it with probability_list and slice_prob_list both as nil
minetest.create_schematic( p1, p2, nil, filename_complete, nil);
-- save metadata, but do not clear it
handle_schematics.save_meta( start_pos, end_pos, base_filename, false);
-- store that we have saved this area
meta:set_string('saved_as_filename', filename);

View File

@ -0,0 +1,94 @@
handle_schematics.sort_pos_get_size = function( p1, p2 )
local res = {x=p1.x, y=p1.y, z=p1.z,
sizex = math.abs( p1.x - p2.x )+1,
sizey = math.abs( p1.y - p2.y )+1,
sizez = math.abs( p1.z - p2.z )+1};
if( p2.x < p1.x ) then
res.x = p2.x;
end
if( p2.y < p1.y ) then
res.y = p2.y;
end
if( p2.z < p1.z ) then
res.z = p2.z;
end
return res;
end
local handle_schematics_get_meta_table = function( pos, all_meta )
local m = minetest.get_meta( pos ):to_table();
local empty_meta = true;
-- TODO: do not save known nodes if they contain the same values as a default node of that type
--local n = minetest.get_node( pos );
-- the inventory part contains functions and cannot be fed to minetest.serialize directly
local invlist = {};
for name, list in pairs( m.inventory ) do
invlist[ name ] = {};
for i, stack in ipairs(list) do
if( not( stack:is_empty())) then
invlist[ name ][ i ] = stack:to_string();
empty_meta = false;
end
end
end
-- the fields part at least is unproblematic
if( empty_meta and m.fields ) then
for k,v in pairs( m.fields ) do
empty_meta = false;
end
end
-- only
if( not( empty_meta )) then
-- TODO: use relative positions instead of absolute ones
all_meta[ #all_meta+1 ] = { x=pos.x, y=pos.y, z=pos.z, fields = m.fields, inventory = invlist};
end
end
-- reads metadata values from start_pos to end_pos and stores them in a file
-- if clear_meta is set, all metadata values will be deleted after saving,
-- making the area ready for new voxelmanip/schematic data
handle_schematics.save_meta = function( start_pos, end_pos, filename, clear_meta )
local all_meta = {};
if( minetest.find_nodes_with_meta ) then
for _,pos in ipairs( minetest.find_nodes_with_meta( start_pos, end_pos )) do
handle_schematics_get_meta_table( pos, all_meta );
end
else
local p = handle_schematics.sort_pos_get_size( start_pos, end_pos );
for x=p.x, p.x+p.sizex do
for y=p.y, p.y+p.sizey do
for z=p.z, p.z+p.sizez do
handle_schematics_get_meta_table( {x=x, y=y, z=z}, all_meta );
end
end
end
end
if( #all_meta > 0 ) then
save_restore.save_data( 'schems/'..filename..'.meta', all_meta );
local empty_meta = { inventory = {}, fields = {} };
for _, pos in ipairs( all_meta ) do
local meta = minetest.get_meta( {x=pos.x, y=pos.y, z=pos.z} );
meta:from_table( empty_meta );
end
end
end
-- restore metadata from file
-- TODO: use relative instead of absolute positions
handle_schematics.restore_meta = function( filename )
local all_meta = save_restore.restore_data( 'schems/'..filename..'.meta' );
for _,pos in ipairs( all_meta ) do
local meta = minetest.get_meta( {x=pos.x, y=pos.y, z=pos.z} );
meta:from_table( {inventory = pos.inventory, fields = pos.fields });
end
end

View File

@ -17,6 +17,10 @@ dofile(handle_schematics.modpath.."/rotate.lua")
-- count nodes, take param2 into account for rotation etc.
dofile(handle_schematics.modpath.."/handle_schematics_misc.lua")
-- store and restore metadata
dofile(handle_schematics.modpath.."/save_restore.lua");
dofile(handle_schematics.modpath.."/handle_schematics_meta.lua");
-- uses replacements_group.* namespace
-- these functions are responsible for the optional dependencies; they check
-- which nodes are available and may be offered as possible replacements

60
save_restore.lua Normal file
View File

@ -0,0 +1,60 @@
-- reserve the namespace
save_restore = {}
-- TODO: if this gets more versatile, add sanity checks for filename
-- TODO: apart from allowing filenames, schems/<filename> also needs to be allowed
-- TODO: save and restore ought to be library functions and not implemented in each individual mod!
save_restore.save_data = function( filename, data )
local path = minetest.get_worldpath()..'/'..filename;
local file = io.open( path, 'w' );
if( file ) then
file:write( minetest.serialize( data ));
file:close();
else
print("[save_restore] Error: Savefile '"..tostring( path ).."' could not be written.");
end
end
save_restore.restore_data = function( filename )
local path = minetest.get_worldpath()..'/'..filename;
local file = io.open( path, 'r' );
if( file ) then
local data = file:read("*all");
file:close();
return minetest.deserialize( data );
else
print("[save_restore] Error: Savefile '"..tostring( path ).."' not found.");
return {}; -- return empty table
end
end
save_restore.file_exists = function( filename )
local path = minetest.get_worldpath()..'/'..filename;
local file = io.open( path, 'r' );
if( file ) then
file:close();
return true;
end
return;
end
save_restore.create_directory = function( filename )
local path = minetest.get_worldpath()..'/'..filename;
if( not( save_restore.file_exists( filename ))) then
os.execute("mkdir \""..minetest.get_worldpath().."/schems".. "\"");
end
end