b85ba866642e5dd6747b771c621ed2e9460fcf4b
[oweals/minetest.git] / src / voxel.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "voxel.h"
21 #include "map.h"
22
23 // For TimeTaker
24 #include "main.h"
25 #include "utility.h"
26
27 /*
28         Debug stuff
29 */
30 u32 addarea_time = 0;
31 u32 emerge_time = 0;
32 u32 emerge_load_time = 0;
33 u32 clearflag_time = 0;
34 //u32 getwaterpressure_time = 0;
35 //u32 spreadwaterpressure_time = 0;
36 u32 updateareawaterpressure_time = 0;
37 u32 flowwater_pre_time = 0;
38
39
40 VoxelManipulator::VoxelManipulator():
41         m_data(NULL),
42         m_flags(NULL)
43 {
44 }
45
46 VoxelManipulator::~VoxelManipulator()
47 {
48         clear();
49         if(m_data)
50                 delete[] m_data;
51         if(m_flags)
52                 delete[] m_flags;
53 }
54
55 void VoxelManipulator::clear()
56 {
57         // Reset area to volume=0
58         m_area = VoxelArea();
59         if(m_data)
60                 delete[] m_data;
61         m_data = NULL;
62         if(m_flags)
63                 delete[] m_flags;
64         m_flags = NULL;
65 }
66
67 void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
68 {
69         v3s16 em = m_area.getExtent();
70         v3s16 of = m_area.MinEdge;
71         o<<"size: "<<em.X<<"x"<<em.Y<<"x"<<em.Z
72          <<" offset: ("<<of.X<<","<<of.Y<<","<<of.Z<<")"<<std::endl;
73         
74         for(s32 y=m_area.MaxEdge.Y; y>=m_area.MinEdge.Y; y--)
75         {
76                 if(em.X >= 3 && em.Y >= 3)
77                 {
78                         if     (y==m_area.MinEdge.Y+2) o<<"^     ";
79                         else if(y==m_area.MinEdge.Y+1) o<<"|     ";
80                         else if(y==m_area.MinEdge.Y+0) o<<"y x-> ";
81                         else                           o<<"      ";
82                 }
83
84                 for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
85                 {
86                         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
87                         {
88                                 u8 f = m_flags[m_area.index(x,y,z)];
89                                 char c;
90                                 if(f & VOXELFLAG_NOT_LOADED)
91                                         c = 'N';
92                                 else if(f & VOXELFLAG_INEXISTENT)
93                                         c = 'I';
94                                 else
95                                 {
96                                         c = 'X';
97                                         u8 m = m_data[m_area.index(x,y,z)].d;
98                                         u8 pr = m_data[m_area.index(x,y,z)].pressure;
99                                         if(mode == VOXELPRINT_MATERIAL)
100                                         {
101                                                 if(m <= 9)
102                                                         c = m + '0';
103                                         }
104                                         else if(mode == VOXELPRINT_WATERPRESSURE)
105                                         {
106                                                 if(m == MATERIAL_WATER)
107                                                 {
108                                                         c = 'w';
109                                                         if(pr <= 9)
110                                                                 c = pr + '0';
111                                                 }
112                                                 else if(m == MATERIAL_AIR)
113                                                 {
114                                                         c = ' ';
115                                                 }
116                                                 else
117                                                 {
118                                                         c = '#';
119                                                 }
120                                         }
121                                 }
122                                 o<<c;
123                         }
124                         o<<' ';
125                 }
126                 o<<std::endl;
127         }
128 }
129
130 void VoxelManipulator::addArea(VoxelArea area)
131 {
132         // Cancel if requested area has zero volume
133         if(area.getExtent() == v3s16(0,0,0))
134                 return;
135         
136         // Cancel if m_area already contains the requested area
137         if(m_area.contains(area))
138                 return;
139         
140         TimeTaker timer("addArea", g_device, &addarea_time);
141
142         // Calculate new area
143         VoxelArea new_area;
144         // New area is the requested area if m_area has zero volume
145         if(m_area.getExtent() == v3s16(0,0,0))
146         {
147                 new_area = area;
148         }
149         // Else add requested area to m_area
150         else
151         {
152                 new_area = m_area;
153                 new_area.addArea(area);
154         }
155
156         s32 new_size = new_area.getVolume();
157
158         /*dstream<<"adding area ";
159         area.print(dstream);
160         dstream<<", old area ";
161         m_area.print(dstream);
162         dstream<<", new area ";
163         new_area.print(dstream);
164         dstream<<", new_size="<<new_size;
165         dstream<<std::endl;*/
166
167         // Allocate and clear new data
168         MapNode *new_data = new MapNode[new_size];
169         u8 *new_flags = new u8[new_size];
170         for(s32 i=0; i<new_size; i++)
171         {
172                 new_flags[i] = VOXELFLAG_NOT_LOADED;
173         }
174         
175         // Copy old data
176         
177         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
178         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
179         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
180         {
181                 // If loaded, copy data and flags
182                 if((m_flags[m_area.index(x,y,z)] & VOXELFLAG_NOT_LOADED) == false)
183                 {
184                         new_data[new_area.index(x,y,z)] = m_data[m_area.index(x,y,z)];
185                         new_flags[new_area.index(x,y,z)] = m_flags[m_area.index(x,y,z)];
186                 }
187         }
188
189         // Replace area, data and flags
190         
191         m_area = new_area;
192         
193         MapNode *old_data = m_data;
194         u8 *old_flags = m_flags;
195
196         /*dstream<<"old_data="<<(int)old_data<<", new_data="<<(int)new_data
197         <<", old_flags="<<(int)m_flags<<", new_flags="<<(int)new_flags<<std::endl;*/
198
199         m_data = new_data;
200         m_flags = new_flags;
201         
202         if(old_data)
203                 delete[] old_data;
204         if(old_flags)
205                 delete[] old_flags;
206
207         //dstream<<"addArea done"<<std::endl;
208 }
209
210 void VoxelManipulator::copyFrom(MapNode *src, VoxelArea src_area,
211                 v3s16 from_pos, v3s16 to_pos, v3s16 size)
212 {
213         for(s16 z=0; z<size.Z; z++)
214         for(s16 y=0; y<size.Y; y++)
215         {
216                 s32 i_src = src_area.index(from_pos.X, from_pos.Y+y, from_pos.Z+z);
217                 s32 i_local = m_area.index(to_pos.X, to_pos.Y+y, to_pos.Z+z);
218                 memcpy(&m_data[i_local], &src[i_src], size.X*sizeof(MapNode));
219                 memset(&m_flags[i_local], 0, size.X);
220         }
221 }
222
223 void VoxelManipulator::interpolate(VoxelArea area)
224 {
225         VoxelArea emerge_area = area;
226         emerge_area.MinEdge -= v3s16(1,1,1);
227         emerge_area.MaxEdge += v3s16(1,1,1);
228         emerge(emerge_area);
229
230         SharedBuffer<u8> buf(area.getVolume());
231
232         for(s32 z=area.MinEdge.Z; z<=area.MaxEdge.Z; z++)
233         for(s32 y=area.MinEdge.Y; y<=area.MaxEdge.Y; y++)
234         for(s32 x=area.MinEdge.X; x<=area.MaxEdge.X; x++)
235         {
236                 v3s16 p(x,y,z);
237
238                 v3s16 dirs[] = {
239                         v3s16(1,1,0),
240                         v3s16(1,0,1),
241                         v3s16(1,-1,0),
242                         v3s16(1,0,-1),
243                         v3s16(-1,1,0),
244                         v3s16(-1,0,1),
245                         v3s16(-1,-1,0),
246                         v3s16(-1,0,-1),
247                 };
248                 //const v3s16 *dirs = g_26dirs;
249                 
250                 s16 total = 0;
251                 s16 airness = 0;
252                 u8 m = MATERIAL_IGNORE;
253
254                 for(s16 i=0; i<8; i++)
255                 //for(s16 i=0; i<26; i++)
256                 {
257                         v3s16 p2 = p + dirs[i];
258
259                         u8 f = m_flags[m_area.index(p2)];
260                         assert(!(f & VOXELFLAG_NOT_LOADED));
261                         if(f & VOXELFLAG_INEXISTENT)
262                                 continue;
263
264                         MapNode &n = m_data[m_area.index(p2)];
265
266                         airness += (n.d == MATERIAL_AIR) ? 1 : -1;
267                         total++;
268
269                         if(m == MATERIAL_IGNORE && n.d != MATERIAL_AIR)
270                                 m = n.d;
271                 }
272
273                 // 1 if air, 0 if not
274                 buf[area.index(p)] = airness > -total/2 ? MATERIAL_AIR : m;
275                 //buf[area.index(p)] = airness > -total ? MATERIAL_AIR : m;
276                 //buf[area.index(p)] = airness >= -7 ? MATERIAL_AIR : m;
277         }
278
279         for(s32 z=area.MinEdge.Z; z<=area.MaxEdge.Z; z++)
280         for(s32 y=area.MinEdge.Y; y<=area.MaxEdge.Y; y++)
281         for(s32 x=area.MinEdge.X; x<=area.MaxEdge.X; x++)
282         {
283                 v3s16 p(x,y,z);
284                 m_data[m_area.index(p)].d = buf[area.index(p)];
285         }
286 }
287
288
289 void VoxelManipulator::clearFlag(u8 flags)
290 {
291         // 0-1ms on moderate area
292         TimeTaker timer("clearFlag", g_device, &clearflag_time);
293
294         v3s16 s = m_area.getExtent();
295
296         /*dstream<<"clearFlag clearing area of size "
297                         <<""<<s.X<<"x"<<s.Y<<"x"<<s.Z<<""
298                         <<std::endl;*/
299
300         //s32 count = 0;
301
302         /*for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
303         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
304         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
305         {
306                 u8 f = m_flags[m_area.index(x,y,z)];
307                 m_flags[m_area.index(x,y,z)] &= ~flags;
308                 if(m_flags[m_area.index(x,y,z)] != f)
309                         count++;
310         }*/
311
312         s32 volume = m_area.getVolume();
313         for(s32 i=0; i<volume; i++)
314         {
315                 m_flags[i] &= ~flags;
316         }
317
318         /*s32 volume = m_area.getVolume();
319         for(s32 i=0; i<volume; i++)
320         {
321                 u8 f = m_flags[i];
322                 m_flags[i] &= ~flags;
323                 if(m_flags[i] != f)
324                         count++;
325         }
326
327         dstream<<"clearFlag changed "<<count<<" flags out of "
328                         <<volume<<" nodes"<<std::endl;*/
329 }
330
331 int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
332 {
333         m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED2;
334
335         if(p.Y > highest_y)
336                 highest_y = p.Y;
337         
338         recur_count++;
339         if(recur_count > 30)
340                 throw ProcessingLimitException
341                                 ("getWaterPressure recur_count limit reached");
342
343         v3s16 dirs[6] = {
344                 v3s16(0,1,0), // top
345                 v3s16(-1,0,0), // left
346                 v3s16(1,0,0), // right
347                 v3s16(0,0,-1), // front
348                 v3s16(0,0,1), // back
349                 v3s16(0,-1,0), // bottom
350         };
351
352         // Load neighboring nodes
353         // TODO: A bigger area would be better
354         emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
355
356         s32 i;
357         for(i=0; i<6; i++)
358         {
359                 v3s16 p2 = p + dirs[i];
360                 u8 f = m_flags[m_area.index(p2)];
361                 // Ignore inexistent or checked nodes
362                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED2))
363                         continue;
364                 MapNode &n = m_data[m_area.index(p2)];
365                 // Ignore non-liquid nodes
366                 if(material_liquid(n.d) == false)
367                         continue;
368
369                 int pr;
370                 
371                 // If at surface
372                 /*if(n.pressure == 1)
373                 {
374                         pr = 1;
375                 }
376                 // Otherwise recurse more
377                 else*/
378                 {
379                         pr = getWaterPressure(p2, highest_y, recur_count);
380                         if(pr == -1)
381                                 continue;
382                 }
383
384                 // If block is at top, pressure here is one higher
385                 if(i == 0)
386                 {
387                         if(pr < 255)
388                                 pr++;
389                 }
390                 // If block is at bottom, pressure here is one lower
391                 else if(i == 5)
392                 {
393                         if(pr > 1)
394                                 pr--;
395                 }
396                 
397                 // Node is on the pressure route
398                 m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED4;
399
400                 // Got pressure
401                 return pr;
402         }
403         
404         // Nothing useful found
405         return -1;
406 }
407
408 void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
409                 VoxelArea request_area,
410                 core::map<v3s16, u8> &active_nodes,
411                 int recur_count)
412 {
413         recur_count++;
414         if(recur_count > 10000)
415                 throw ProcessingLimitException
416                                 ("spreadWaterPressure recur_count limit reached");
417
418         m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
419         m_data[m_area.index(p)].pressure = pr;
420
421         v3s16 dirs[6] = {
422                 v3s16(0,1,0), // top
423                 v3s16(-1,0,0), // left
424                 v3s16(1,0,0), // right
425                 v3s16(0,0,-1), // front
426                 v3s16(0,0,1), // back
427                 v3s16(0,-1,0), // bottom
428         };
429
430         // Load neighboring nodes
431         emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
432
433         s32 i;
434         for(i=0; i<6; i++)
435         {
436                 v3s16 p2 = p + dirs[i];
437                 
438                 u8 f = m_flags[m_area.index(p2)];
439
440                 // Ignore inexistent and checked nodes
441                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
442                         continue;
443
444                 MapNode &n = m_data[m_area.index(p2)];
445                 
446                 /*
447                         If material is air:
448                                 add to active_nodes if there is flow-causing pressure.
449                         NOTE: Do not remove anything from there. We cannot know
450                               here if some other neighbor of it causes flow.
451                 */
452                 if(n.d == MATERIAL_AIR)
453                 {
454                         bool pressure_causes_flow = false;
455                         // If block is at top
456                         if(i == 0)
457                         {
458                                 if(pr >= 3)
459                                         pressure_causes_flow = true;
460                         }
461                         // If block is at bottom
462                         else if(i == 5)
463                         {
464                                 pressure_causes_flow = true;
465                         }
466                         // If block is at side
467                         else
468                         {
469                                 if(pr >= 2)
470                                         pressure_causes_flow = true;
471                         }
472                         
473                         if(pressure_causes_flow)
474                         {
475                                 active_nodes[p2] = 1;
476                         }
477
478                         continue;
479                 }
480
481                 // Ignore non-liquid nodes
482                 if(material_liquid(n.d) == false)
483                         continue;
484
485                 int pr2 = pr;
486                 // If block is at top, pressure there is lower
487                 if(i == 0)
488                 {
489                         if(pr2 > 0)
490                                 pr2--;
491                 }
492                 // If block is at bottom, pressure there is higher
493                 else if(i == 5)
494                 {
495                         if(pr2 < 255)
496                                 pr2++;
497                 }
498                 
499                 // Ignore if correct pressure is already set and is not on
500                 // request_area
501                 if(n.pressure == pr2 && request_area.contains(p2) == false)
502                         continue;
503
504                 spreadWaterPressure(p2, pr2, request_area, active_nodes, recur_count);
505         }
506 }
507
508 void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
509                 core::map<v3s16, u8> &active_nodes,
510                 bool checked3_is_clear)
511 {
512         TimeTaker timer("updateAreaWaterPressure", g_device,
513                         &updateareawaterpressure_time);
514
515         emerge(a);
516         
517         bool checked2_clear = false;
518         
519         if(checked3_is_clear == false)
520         {
521                 //clearFlag(VOXELFLAG_CHECKED3);
522
523                 clearFlag(VOXELFLAG_CHECKED3 | VOXELFLAG_CHECKED2);
524                 checked2_clear = true;
525         }
526         
527
528         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
529         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
530         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
531         {
532                 v3s16 p(x,y,z);
533
534                 u8 f = m_flags[m_area.index(p)];
535                 // Ignore inexistent or checked nodes
536                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
537                         continue;
538                 MapNode &n = m_data[m_area.index(p)];
539                 // Ignore non-liquid nodes
540                 if(material_liquid(n.d) == false)
541                         continue;
542                 
543                 if(checked2_clear == false)
544                 {
545                         clearFlag(VOXELFLAG_CHECKED2);
546                         checked2_clear = true;
547                 }
548
549                 checked2_clear = false;
550
551                 s16 highest_y = -32768;
552                 int recur_count = 0;
553                 int pr = -1;
554
555                 try
556                 {
557                         // 0-1ms @ recur_count <= 100
558                         //TimeTaker timer("getWaterPressure", g_device);
559                         pr = getWaterPressure(p, highest_y, recur_count);
560                 }
561                 catch(ProcessingLimitException &e)
562                 {
563                         //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
564                 }
565
566                 if(pr == -1)
567                 {
568                         assert(highest_y != -32768);
569
570                         pr = highest_y - p.Y + 1;
571                         if(pr > 255)
572                                 pr = 255;
573
574                         /*dstream<<"WARNING: Pressure at ("
575                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"
576                                         <<" = "<<pr
577                                         //<<" and highest_y == -32768"
578                                         <<std::endl;
579                         assert(highest_y != -32768);
580                         continue;*/
581                 }
582                 
583                 try
584                 {
585                         // 0ms
586                         //TimeTaker timer("spreadWaterPressure", g_device);
587                         spreadWaterPressure(p, pr, a, active_nodes, 0);
588                 }
589                 catch(ProcessingLimitException &e)
590                 {
591                         //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
592                 }
593         }
594 }
595
596 bool VoxelManipulator::flowWater(v3s16 removed_pos,
597                 core::map<v3s16, u8> &active_nodes,
598                 int recursion_depth, bool debugprint,
599                 int *counter, int counterlimit)
600 {
601         v3s16 dirs[6] = {
602                 v3s16(0,1,0), // top
603                 v3s16(-1,0,0), // left
604                 v3s16(1,0,0), // right
605                 v3s16(0,0,-1), // front
606                 v3s16(0,0,1), // back
607                 v3s16(0,-1,0), // bottom
608         };
609
610         recursion_depth++;
611
612         v3s16 p;
613         
614         // Randomize horizontal order
615         static s32 cs = 0;
616         if(cs < 3)
617                 cs++;
618         else
619                 cs = 0;
620         s16 s1 = (cs & 1) ? 1 : -1;
621         s16 s2 = (cs & 2) ? 1 : -1;
622         //dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
623
624         {
625         TimeTaker timer1("flowWater pre", g_device, &flowwater_pre_time);
626         
627         // Load neighboring nodes
628         emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)));
629         
630         // Ignore incorrect removed_pos
631         {
632                 u8 f = m_flags[m_area.index(removed_pos)];
633                 // Ignore inexistent or checked node
634                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
635                         return false;
636                 MapNode &n = m_data[m_area.index(removed_pos)];
637                 // Water can move only to air
638                 if(n.d != MATERIAL_AIR)
639                         return false;
640         }
641         
642         s32 i;
643         for(i=0; i<6; i++)
644         {
645                 p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
646
647                 u8 f = m_flags[m_area.index(p)];
648                 // Inexistent or checked nodes can't move
649                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
650                         continue;
651                 MapNode &n = m_data[m_area.index(p)];
652                 // Only liquid nodes can move
653                 if(material_liquid(n.d) == false)
654                         continue;
655                 // If block is at top, select it always
656                 if(i == 0)
657                 {
658                         break;
659                 }
660                 // If block is at bottom, select it if it has enough pressure
661                 if(i == 5)
662                 {
663                         if(n.pressure >= 3)
664                                 break;
665                         continue;
666                 }
667                 // Else block is at some side. Select it if it has enough pressure
668                 if(n.pressure >= 2)
669                 {
670                         break;
671                 }
672         }
673
674         // If there is nothing to move, return
675         if(i==6)
676                 return false;
677
678         // Switch nodes at p and removed_pos
679         u8 m = m_data[m_area.index(p)].d;
680         u8 f = m_flags[m_area.index(p)];
681         m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
682         m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
683         m_data[m_area.index(removed_pos)].d = m;
684         m_flags[m_area.index(removed_pos)] = f;
685
686         // Mark removed_pos checked
687         m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
688         // If block was dropped from surface, increase pressure
689         if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
690         {
691                 m_data[m_area.index(removed_pos)].pressure = 2;
692         }
693         
694         /*if(debugprint)
695         {
696                 dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
697                 print(dstream, VOXELPRINT_WATERPRESSURE);
698         }*/
699
700         // Update pressure
701         VoxelArea a;
702         a.addPoint(p - v3s16(1,1,1));
703         a.addPoint(p + v3s16(1,1,1));
704         a.addPoint(removed_pos - v3s16(1,1,1));
705         a.addPoint(removed_pos + v3s16(1,1,1));
706         updateAreaWaterPressure(a, active_nodes);
707         
708         /*if(debugprint)
709         {
710                 dstream<<"VoxelManipulator::flowWater(): Pressure updated:"<<std::endl;
711                 print(dstream, VOXELPRINT_WATERPRESSURE);
712                 //std::cin.get();
713         }*/
714
715         if(debugprint)
716         {
717                 dstream<<"VoxelManipulator::flowWater(): step done:"<<std::endl;
718                 print(dstream, VOXELPRINT_WATERPRESSURE);
719                 //std::cin.get();
720         }
721         
722         }//timer1
723
724         // Flow water to the newly created empty position
725         flowWater(p, active_nodes, recursion_depth,
726                         debugprint, counter, counterlimit);
727         
728 find_again:
729         // Try flowing water to empty positions around removed_pos.
730         // They are checked in reverse order compared to the previous loop.
731         for(s32 i=5; i>=0; i--)
732         {
733                 //v3s16 p = removed_pos + dirs[i];
734                 p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
735
736                 u8 f = m_flags[m_area.index(p)];
737                 // Water can't move to inexistent nodes
738                 if(f & VOXELFLAG_INEXISTENT)
739                         continue;
740                 MapNode &n = m_data[m_area.index(p)];
741                 // Water can only move to air
742                 if(n.d != MATERIAL_AIR)
743                         continue;
744                         
745                 // Flow water to node
746                 bool moved =
747                 flowWater(p, active_nodes, recursion_depth,
748                                 debugprint, counter, counterlimit);
749                 
750                 if(moved)
751                 {
752                         // Search again from all neighbors
753                         goto find_again;
754                 }
755         }
756
757         if(counter != NULL)
758         {
759                 (*counter)++;
760                 if((*counter) % 10 == 0)
761                         dstream<<"flowWater(): moved "<<(*counter)<<" nodes"
762                                         <<std::endl;
763
764                 if(counterlimit != -1 && (*counter) > counterlimit)
765                 {
766                         dstream<<"Counter limit reached; returning"<<std::endl;
767                         throw ProcessingLimitException("flowWater counterlimit reached");
768                 }
769         }
770         
771         return true;
772 }
773
774 void VoxelManipulator::flowWater(
775                 core::map<v3s16, u8> &active_nodes,
776                 int recursion_depth, bool debugprint,
777                 int counterlimit)
778 {
779         addarea_time = 0;
780         emerge_time = 0;
781         emerge_load_time = 0;
782         clearflag_time = 0;
783         updateareawaterpressure_time = 0;
784         flowwater_pre_time = 0;
785
786         TimeTaker timer1("flowWater (active_nodes)", g_device);
787
788         dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
789
790         int counter = 0;
791
792         try
793         {
794
795         // Flow water to active nodes
796         for(;;)
797         {
798                 // Clear check flags
799                 clearFlag(VOXELFLAG_CHECKED);
800                 
801                 if(active_nodes.size() == 0)
802                         break;
803
804                 dstream<<"Selecting a new active_node"<<std::endl;
805
806 #if 0
807                 // Take first one
808                 core::map<v3s16, u8>::Node
809                                 *n = active_nodes.getIterator().getNode();
810 #endif
811
812 #if 1
813                 // Take random one
814                 s32 k = (s32)rand() % (s32)active_nodes.size();
815                 //s32 k = 0;
816                 core::map<v3s16, u8>::Iterator
817                                 i = active_nodes.getIterator().getNode();
818                 for(s32 j=0; j<k; j++)
819                 {
820                         i++;
821                 }
822                 core::map<v3s16, u8>::Node *n = i.getNode();
823 #endif
824
825                 v3s16 p = n->getKey();
826                 active_nodes.remove(p);
827                 flowWater(p, active_nodes, recursion_depth,
828                                 debugprint, &counter, counterlimit);
829         }
830
831         }
832         catch(ProcessingLimitException &e)
833         {
834                 //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
835         }
836         
837         v3s16 e = m_area.getExtent();
838         s32 v = m_area.getVolume();
839         dstream<<"flowWater (active): moved "<<counter<<" nodes, "
840                         <<"area ended up as "
841                         <<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
842                         <<std::endl;
843         
844         dstream<<"addarea_time: "<<addarea_time
845                         <<", emerge_time: "<<emerge_time
846                         <<", emerge_load_time: "<<emerge_load_time
847                         <<", clearflag_time: "<<clearflag_time
848                         <<", flowwater_pre_time: "<<flowwater_pre_time
849                         <<", updateareawaterpressure_time: "<<updateareawaterpressure_time
850                         <<std::endl;
851 }
852
853
854 //END