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