-
Notifications
You must be signed in to change notification settings - Fork 10
/
handle_schematics_meta.lua
184 lines (160 loc) · 5.76 KB
/
handle_schematics_meta.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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, start_pos )
local m = minetest.get_meta( pos ):to_table();
local empty_meta = true;
-- 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
invlist[ name ][ i ] = stack:to_string();
-- if( not( stack:is_empty())) then
-- empty_meta = false;
-- inv_is_empty = false;
-- end
end
end
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};
if(true) then return; 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
-- 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
-- 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
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, p );
end
else
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-p.x, y=y-p.y, z=z-p.z}, all_meta, p );
end
end
end
end
if( #all_meta > 0 ) then
save_restore.save_data( 'schems/'..filename..'.meta', all_meta );
end
end
-- 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
end
-- restore metadata from file
-- TODO: use relative instead of absolute positions (already done for .we files)
-- TODO: handle mirror
handle_schematics.restore_meta = function( filename, all_meta, start_pos, end_pos, rotate, mirror )
if( not( all_meta ) and filename ) then
local file, err = save_restore.file_access(filename, "rb")
if(file) then
all_meta = file:read("*all");
all_meta = minetest.deserialize(all_meta)
file:close();
end
end
if(not(all_meta)) then
return
end
for _,pos in ipairs( all_meta ) do
local p = {y = math.min(start_pos.y, start_pos.y)+pos.y}
if( rotate == 0 ) then
p.x = math.min(start_pos.x, end_pos.x)+pos.x;
p.z = math.min(start_pos.z, end_pos.z)+pos.z;
elseif( rotate == 1 ) then
p.x = math.min(start_pos.x, end_pos.x)+pos.z;
p.z = math.max(start_pos.z, end_pos.z)-pos.x;
-- rotate by 180 degrees
elseif( rotate == 2 ) then
p.x = math.max(start_pos.x, end_pos.x)-pos.x;
p.z = math.max(start_pos.z, end_pos.z)-pos.z;
elseif( rotate == 3 ) then
p.x = math.max(start_pos.x, end_pos.x)-pos.z;
p.z = math.min(start_pos.z, end_pos.z)+pos.x;
end
local meta = minetest.get_meta( p );
meta:from_table( {inventory = pos.inventory, fields = pos.fields });
-- print("SETTING meta at "..minetest.serialize(p)..": "..minetest.serialize(pos.inventory));
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_schems_directory();
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