save only metadata of nodes that are not empty (provided that can be determined)

master
Sokomine 2015-05-24 15:11:58 +02:00
parent a52149a1e6
commit 01c3df0a08
2 changed files with 76 additions and 29 deletions

View File

@ -570,16 +570,12 @@ build_chest.on_receive_fields = function(pos, formname, fields, player)
tostring( start_pos.x )..':'..tostring( start_pos.y )..':'..tostring( start_pos.z )..'_'..
'0_0';
-- TODO: handle metadata
-- create directory for the schematics (same path as WorldEdit uses)
save_restore.create_directory( '/schems' );
-- store a backup of the original landscape
-- <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 );
handle_schematics.create_schematic_with_meta( start_pos, end_pos, base_filename );
meta:set_string('backup', base_filename );
-- clear metadata so that the new building can be placed
handle_schematics.clear_meta( start_pos, end_pos );
minetest.chat_send_player( pname, 'CREATING backup schematic for this place in \"schems/'..base_filename..'.mts\".');
end
@ -717,12 +713,8 @@ mirror = nil;
-- TODO: forbid overwriting existing files?
local worldpath = minetest.get_worldpath();
local filename_complete = worldpath..'/schems/'..filename..'.mts';
-- 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);
handle_schematics.create_schematic_with_meta( p1, p2, filename );
-- store that we have saved this area
meta:set_string('saved_as_filename', filename);

View File

@ -18,53 +18,86 @@ handle_schematics.sort_pos_get_size = function( p1, p2 )
end
local handle_schematics_get_meta_table = function( pos, all_meta )
local handle_schematics_get_meta_table = function( pos, all_meta, start_pos )
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 = {};
local count_inv = 0;
local inv_is_empty = true;
for name, list in pairs( m.inventory ) do
invlist[ name ] = {};
count_inv = count_inv + 1;
for i, stack in ipairs(list) do
if( not( stack:is_empty())) then
invlist[ name ][ i ] = stack:to_string();
empty_meta = false;
inv_is_empty = false;
end
end
end
-- the fields part at least is unproblematic
local count_fields = 0;
if( empty_meta and m.fields ) then
for k,v in pairs( m.fields ) do
empty_meta = false;
count_fields = count_fields + 1;
end
end
-- only
-- ignore default:sign_wall without text on it
if( count_inv==0
and count_fields<=3 and m.fields.formspec and m.fields.infotext
and m.fields.formspec == "field[text;;${text}]"
and m.fields.infotext == "\"\"") then
-- also consider signs empty if their text has been set once and deleted afterwards
if( not( m.fields.text ) or m.fields.text == "" ) then
print('SKIPPING empty sign AT '..minetest.pos_to_string( pos)..' while saving metadata.');
empty_meta = true;
end
elseif( count_inv > 0 and inv_is_empty
and count_fields>0 and m.fields.formspec ) then
local n = minetest.get_node( pos );
if( n and n.name
and (n.name=='default:chest' or n.name=='default:chest_locked' or n.name=='default:bookshelf'
or n.name=='default:furnace' or n.name=='default:furnace_active'
or n.name=='cottages:shelf' or n.name=='cottages:anvil' or n.name=='cottages:threshing_floor' )) then
print('SKIPPING empty '..tostring(n.name)..' AT '..minetest.pos_to_string( pos )..' while saving metadata.');
empty_meta = true;
end
end
-- only save if there is something to be saved
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};
-- positions are stored as relative positions
all_meta[ #all_meta+1 ] = {
x=pos.x-start_pos.x,
y=pos.y-start_pos.y,
z=pos.z-start_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 )
handle_schematics.save_meta = function( start_pos, end_pos, filename )
local all_meta = {};
local p = handle_schematics.sort_pos_get_size( start_pos, end_pos );
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 );
handle_schematics_get_meta_table( pos, all_meta, p );
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 );
handle_schematics_get_meta_table( {x=x, y=y, z=z}, all_meta, p );
end
end
end
@ -72,10 +105,17 @@ handle_schematics.save_meta = function( start_pos, end_pos, filename, clear_meta
if( #all_meta > 0 ) then
save_restore.save_data( 'schems/'..filename..'.meta', all_meta );
end
end
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} );
-- all metadata values will be deleted when this function is called,
-- making the area ready for new voxelmanip/schematic data
handle_schematics.clear_meta = function( start_pos, end_pos )
local empty_meta = { inventory = {}, fields = {} };
if( minetest.find_nodes_with_meta ) then
for _,pos in ipairs( minetest.find_nodes_with_meta( start_pos, end_pos )) do
local meta = minetest.get_meta( pos );
meta:from_table( empty_meta );
end
end
@ -92,3 +132,18 @@ handle_schematics.restore_meta = function( filename )
meta:from_table( {inventory = pos.inventory, fields = pos.fields });
end
end
-- return true on success; will overwrite existing files
handle_schematics.create_schematic_with_meta = function( p1, p2, base_filename )
-- create directory for the schematics (same path as WorldEdit uses)
save_restore.create_directory( '/schems' );
local complete_filename = minetest.get_worldpath()..'/schems/'..base_filename..'.mts';
-- actually create the schematic
minetest.create_schematic( p1, p2, nil, complete_filename, nil);
-- save metadata; the file will only be created if there is any metadata that is to be saved
handle_schematics.save_meta( p1, p2, base_filename );
return save_restore.file_exists( complete_filename );
end