]> git.lizzy.rs Git - worldedit.git/blob - functions.lua
Re-add support for the old WorldEdit save format on a load-only basis. Implemented...
[worldedit.git] / functions.lua
1 --modifies positions `pos1` and `pos2` so that each component of `pos1` is less than or equal to its corresponding conent of `pos2`, returning two new positions\r
2 worldedit.sort_pos = function(pos1, pos2)\r
3         pos1 = {x=pos1.x, y=pos1.y, z=pos1.z}\r
4         pos2 = {x=pos2.x, y=pos2.y, z=pos2.z}\r
5         if pos1.x > pos2.x then\r
6                 pos2.x, pos1.x = pos1.x, pos2.x\r
7         end\r
8         if pos1.y > pos2.y then\r
9                 pos2.y, pos1.y = pos1.y, pos2.y\r
10         end\r
11         if pos1.z > pos2.z then\r
12                 pos2.z, pos1.z = pos1.z, pos2.z\r
13         end\r
14         return pos1, pos2\r
15 end\r
16 \r
17 --determines the volume of the region defined by positions `pos1` and `pos2`, returning the volume\r
18 worldedit.volume = function(pos1, pos2)\r
19         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
20         return (pos2.x - pos1.x + 1) * (pos2.y - pos1.y + 1) * (pos2.z - pos1.z + 1)\r
21 end\r
22 \r
23 --sets a region defined by positions `pos1` and `pos2` to `nodename`, returning the number of nodes filled\r
24 worldedit.set = function(pos1, pos2, nodename)\r
25         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
26         local env = minetest.env\r
27 \r
28         local node = {name=nodename}\r
29         local pos = {x=pos1.x, y=0, z=0}\r
30         while pos.x <= pos2.x do\r
31                 pos.y = pos1.y\r
32                 while pos.y <= pos2.y do\r
33                         pos.z = pos1.z\r
34                         while pos.z <= pos2.z do\r
35                                 env:add_node(pos, node)\r
36                                 pos.z = pos.z + 1\r
37                         end\r
38                         pos.y = pos.y + 1\r
39                 end\r
40                 pos.x = pos.x + 1\r
41         end\r
42         return worldedit.volume(pos1, pos2)\r
43 end\r
44 \r
45 --replaces all instances of `searchnode` with `replacenode` in a region defined by positions `pos1` and `pos2`, returning the number of nodes replaced\r
46 worldedit.replace = function(pos1, pos2, searchnode, replacenode)\r
47         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
48         local env = minetest.env\r
49 \r
50         if searchnode:find(":") == nil then\r
51                 searchnode = "default:" .. searchnode\r
52         end\r
53 \r
54         local pos = {x=pos1.x, y=0, z=0}\r
55         local node = {name=replacenode}\r
56         local count = 0\r
57         while pos.x <= pos2.x do\r
58                 pos.y = pos1.y\r
59                 while pos.y <= pos2.y do\r
60                         pos.z = pos1.z\r
61                         while pos.z <= pos2.z do\r
62                                 if env:get_node(pos).name == searchnode then\r
63                                         env:add_node(pos, node)\r
64                                         count = count + 1\r
65                                 end\r
66                                 pos.z = pos.z + 1\r
67                         end\r
68                         pos.y = pos.y + 1\r
69                 end\r
70                 pos.x = pos.x + 1\r
71         end\r
72         return count\r
73 end\r
74 \r
75 --copies the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes copied\r
76 worldedit.copy = function(pos1, pos2, axis, amount)\r
77         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
78         local env = minetest.env\r
79 \r
80         if amount < 0 then\r
81                 local pos = {x=pos1.x, y=0, z=0}\r
82                 while pos.x <= pos2.x do\r
83                         pos.y = pos1.y\r
84                         while pos.y <= pos2.y do\r
85                                 pos.z = pos1.z\r
86                                 while pos.z <= pos2.z do\r
87                                         local node = env:get_node(pos, node)\r
88                                         local value = pos[axis]\r
89                                         pos[axis] = value - amount\r
90                                         env:add_node(pos, node)\r
91                                         pos[axis] = value\r
92                                         pos.z = pos.z + 1\r
93                                 end\r
94                                 pos.y = pos.y + 1\r
95                         end\r
96                         pos.x = pos.x + 1\r
97                 end\r
98         else\r
99                 local pos = {x=pos2.x, y=0, z=0}\r
100                 while pos.x >= pos1.x do\r
101                         pos.y = pos2.y\r
102                         while pos.y >= pos1.y do\r
103                                 pos.z = pos2.z\r
104                                 while pos.z >= pos1.z do\r
105                                         local node = minetest.env:get_node(pos, node)\r
106                                         local value = pos[axis]\r
107                                         pos[axis] = value + amount\r
108                                         minetest.env:add_node(pos, node)\r
109                                         pos[axis] = value\r
110                                         pos.z = pos.z - 1\r
111                                 end\r
112                                 pos.y = pos.y - 1\r
113                         end\r
114                         pos.x = pos.x - 1\r
115                 end\r
116         end\r
117         return worldedit.volume(pos1, pos2)\r
118 end\r
119 \r
120 --moves the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") by `amount` nodes, returning the number of nodes moved\r
121 worldedit.move = function(pos1, pos2, axis, amount)\r
122         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
123         local env = minetest.env\r
124 \r
125         if amount < 0 then\r
126                 local pos = {x=pos1.x, y=0, z=0}\r
127                 while pos.x <= pos2.x do\r
128                         pos.y = pos1.y\r
129                         while pos.y <= pos2.y do\r
130                                 pos.z = pos1.z\r
131                                 while pos.z <= pos2.z do\r
132                                         local node = env:get_node(pos, node)\r
133                                         env:remove_node(pos)\r
134                                         local value = pos[axis]\r
135                                         pos[axis] = value - amount\r
136                                         env:add_node(pos, node)\r
137                                         pos[axis] = value\r
138                                         pos.z = pos.z + 1\r
139                                 end\r
140                                 pos.y = pos.y + 1\r
141                         end\r
142                         pos.x = pos.x + 1\r
143                 end\r
144         else\r
145                 local pos = {x=pos2.x, y=0, z=0}\r
146                 while pos.x >= pos1.x do\r
147                         pos.y = pos2.y\r
148                         while pos.y >= pos1.y do\r
149                                 pos.z = pos2.z\r
150                                 while pos.z >= pos1.z do\r
151                                         local node = minetest.env:get_node(pos, node)\r
152                                         env:remove_node(pos)\r
153                                         local value = pos[axis]\r
154                                         pos[axis] = value + amount\r
155                                         minetest.env:add_node(pos, node)\r
156                                         pos[axis] = value\r
157                                         pos.z = pos.z - 1\r
158                                 end\r
159                                 pos.y = pos.y - 1\r
160                         end\r
161                         pos.x = pos.x - 1\r
162                 end\r
163         end\r
164         return worldedit.volume(pos1, pos2)\r
165 end\r
166 \r
167 --duplicates the region defined by positions `pos1` and `pos2` along the `axis` axis ("x" or "y" or "z") `count` times, returning the number of nodes stacked\r
168 worldedit.stack = function(pos1, pos2, axis, count)\r
169         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
170         local length = pos2[axis] - pos1[axis] + 1\r
171         local amount = 0\r
172         local copy = worldedit.copy\r
173         if count < 0 then\r
174                 count = -count\r
175                 length = -length\r
176         end\r
177         for i = 1, count do\r
178                 amount = amount + length\r
179                 copy(pos1, pos2, axis, amount)\r
180         end\r
181         return worldedit.volume(pos1, pos2)\r
182 end\r
183 \r
184 --digs a region defined by positions `pos1` and `pos2`, returning the number of nodes dug\r
185 worldedit.dig = function(pos1, pos2)\r
186         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
187         local env = minetest.env\r
188 \r
189         local pos = {x=pos1.x, y=0, z=0}\r
190         while pos.x <= pos2.x do\r
191                 pos.y = pos1.y\r
192                 while pos.y <= pos2.y do\r
193                         pos.z = pos1.z\r
194                         while pos.z <= pos2.z do\r
195                                 env:dig_node(pos)\r
196                                 pos.z = pos.z + 1\r
197                         end\r
198                         pos.y = pos.y + 1\r
199                 end\r
200                 pos.x = pos.x + 1\r
201         end\r
202         return worldedit.volume(pos1, pos2)\r
203 end\r
204 \r
205 --converts the region defined by positions `pos1` and `pos2` into a single string, returning the serialized data and the number of nodes serialized\r
206 worldedit.serialize = function(pos1, pos2)\r
207         local pos1, pos2 = worldedit.sort_pos(pos1, pos2)\r
208         local pos = {x=pos1.x, y=0, z=0}\r
209         local count = 0\r
210         local result = {}\r
211         local env = minetest.env\r
212         while pos.x <= pos2.x do\r
213                 pos.y = pos1.y\r
214                 while pos.y <= pos2.y do\r
215                         pos.z = pos1.z\r
216                         while pos.z <= pos2.z do\r
217                                 local node = env:get_node(pos)\r
218                                 if node.name ~= "air" and node.name ~= "ignore" then\r
219                                         count = count + 1\r
220                                         result[count] = pos.x - pos1.x .. " " .. pos.y - pos1.y .. " " .. pos.z - pos1.z .. " " .. node.name .. " " .. node.param1 .. " " .. node.param2\r
221                                 end\r
222                                 pos.z = pos.z + 1\r
223                         end\r
224                         pos.y = pos.y + 1\r
225                 end\r
226                 pos.x = pos.x + 1\r
227         end\r
228         result = table.concat(result, "\n")\r
229         return result, count\r
230 end\r
231 \r
232 --loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
233 worldedit.deserialize = function(originpos, value)\r
234         local pos = {x=0, y=0, z=0}\r
235         local node = {name="", param1=0, param2=0}\r
236         local count = 0\r
237         local env = minetest.env\r
238         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\r
239                 pos.x = originpos.x + tonumber(x)\r
240                 pos.y = originpos.y + tonumber(y)\r
241                 pos.z = originpos.z + tonumber(z)\r
242                 node.name = name\r
243                 node.param1 = param1\r
244                 node.param2 = param2\r
245                 env:add_node(pos, node)\r
246                 count = count + 1\r
247         end\r
248         return count\r
249 end\r
250 \r
251 --loads the nodes represented by string `value` at position `originpos`, returning the number of nodes deserialized\r
252 --based on [table.save/table.load](http://lua-users.org/wiki/SaveTableToFile) by ChillCode, available under the MIT license (GPL compatible)\r
253 worldedit.deserialize_old = function(originpos, value)\r
254         --obtain the node table\r
255         local count = 0\r
256         local get_tables = loadstring(value)\r
257         if get_tables == nil then --error loading value\r
258                 return count\r
259         end\r
260         local tables = get_tables()\r
261 \r
262         --transform the node table into an array of nodes\r
263         for i = 1, #tables do\r
264                 for j, v in pairs(tables[i]) do\r
265                         if type(v) == "table" then\r
266                                 tables[i][j] = tables[v[1]]\r
267                         end\r
268                 end\r
269         end\r
270 \r
271         --load the node array\r
272         local env = minetest.env\r
273         for i, v in ipairs(tables[1]) do\r
274                 local pos = v[1]\r
275                 pos.x, pos.y, pos.z = originpos.x + pos.x, originpos.y + pos.y, originpos.z + pos.z\r
276                 env:add_node(pos, v[2])\r
277                 count = count + 1\r
278         end\r
279         return count\r
280 end