]> git.lizzy.rs Git - dragonfireclient.git/blob - src/voxel.cpp
old water removed, some fixes here and there
[dragonfireclient.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 int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
268 {
269         m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED2;
270
271         if(p.Y > highest_y)
272                 highest_y = p.Y;
273         
274         /*if(recur_count > 1000)
275                 throw ProcessingLimitException
276                                 ("getWaterPressure recur_count limit reached");*/
277         
278         if(recur_count > 10000)
279                 return -1;
280         
281         recur_count++;
282
283         v3s16 dirs[6] = {
284                 v3s16(0,1,0), // top
285                 v3s16(0,0,1), // back
286                 v3s16(0,0,-1), // front
287                 v3s16(1,0,0), // right
288                 v3s16(-1,0,0), // left
289                 v3s16(0,-1,0), // bottom
290         };
291
292         // Load neighboring nodes
293         emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 1);
294
295         s32 i;
296         for(i=0; i<6; i++)
297         {
298                 v3s16 p2 = p + dirs[i];
299                 u8 f = m_flags[m_area.index(p2)];
300                 // Ignore inexistent or checked nodes
301                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED2))
302                         continue;
303                 MapNode &n = m_data[m_area.index(p2)];
304                 // Ignore non-liquid nodes
305                 if(content_liquid(n.d) == false)
306                         continue;
307
308                 int pr;
309
310                 // If at ocean surface
311                 if(n.pressure == 1 && n.d == CONTENT_WATERSOURCE)
312                 //if(n.pressure == 1) // Causes glitches but is fast
313                 {
314                         pr = 1;
315                 }
316                 // Otherwise recurse more
317                 else
318                 {
319                         pr = getWaterPressure(p2, highest_y, recur_count);
320                         if(pr == -1)
321                                 continue;
322                 }
323
324                 // If block is at top, pressure here is one higher
325                 if(i == 0)
326                 {
327                         if(pr < 255)
328                                 pr++;
329                 }
330                 // If block is at bottom, pressure here is one lower
331                 else if(i == 5)
332                 {
333                         if(pr > 1)
334                                 pr--;
335                 }
336                 
337                 // Node is on the pressure route
338                 m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED4;
339
340                 // Got pressure
341                 return pr;
342         }
343         
344         // Nothing useful found
345         return -1;
346 }
347
348 void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
349                 VoxelArea request_area,
350                 core::map<v3s16, u8> &active_nodes,
351                 int recur_count)
352 {
353         //if(recur_count > 10000)
354                 /*throw ProcessingLimitException
355                                 ("spreadWaterPressure recur_count limit reached");*/
356         if(recur_count > 10)
357                 return;
358         recur_count++;
359         
360         /*dstream<<"spreadWaterPressure: p=("
361                         <<p.X<<","<<p.Y<<","<<p.Z<<")"
362                         <<", oldpr="<<(int)m_data[m_area.index(p)].pressure
363                         <<", pr="<<pr
364                         <<", recur_count="<<recur_count
365                         <<", request_area=";
366         request_area.print(dstream);
367         dstream<<std::endl;*/
368
369         m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
370         m_data[m_area.index(p)].pressure = pr;
371
372         v3s16 dirs[6] = {
373                 v3s16(0,1,0), // top
374                 v3s16(-1,0,0), // left
375                 v3s16(1,0,0), // right
376                 v3s16(0,0,-1), // front
377                 v3s16(0,0,1), // back
378                 v3s16(0,-1,0), // bottom
379         };
380
381         // Load neighboring nodes
382         emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 2);
383
384         s32 i;
385         for(i=0; i<6; i++)
386         {
387                 v3s16 p2 = p + dirs[i];
388                 
389                 u8 f = m_flags[m_area.index(p2)];
390
391                 // Ignore inexistent and checked nodes
392                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
393                         continue;
394
395                 MapNode &n = m_data[m_area.index(p2)];
396                 
397                 /*
398                         If material is air:
399                                 add to active_nodes if there is flow-causing pressure.
400                         NOTE: Do not remove anything from there. We cannot know
401                               here if some other neighbor of it causes flow.
402                 */
403                 if(liquid_replaces_content(n.d))
404                 {
405                         bool pressure_causes_flow = false;
406                         // If empty block is at top
407                         if(i == 0)
408                         {
409                                 if(m_disable_water_climb)
410                                         continue;
411                                 
412                                 //if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
413                                 if(pr >= 3)
414                                         pressure_causes_flow = true;
415                         }
416                         // If block is at bottom
417                         else if(i == 5)
418                         {
419                                 pressure_causes_flow = true;
420                         }
421                         // If block is at side
422                         else
423                         {
424                                 //if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
425                                 if(pr >= 2)
426                                         pressure_causes_flow = true;
427                         }
428                         
429                         if(pressure_causes_flow)
430                         {
431                                 active_nodes[p2] = 1;
432                         }
433
434                         continue;
435                 }
436
437                 // Ignore non-liquid nodes
438                 if(content_liquid(n.d) == false)
439                         continue;
440
441                 int pr2 = pr;
442                 // If block is at top, pressure there is lower
443                 if(i == 0)
444                 {
445                         if(pr2 > 0)
446                                 pr2--;
447                 }
448                 // If block is at bottom, pressure there is higher
449                 else if(i == 5)
450                 {
451                         if(pr2 < 255)
452                                 pr2++;
453                 }
454
455                 /*if(m_disable_water_climb)
456                 {
457                         if(pr2 > 3)
458                                 pr2 = 3;
459                 }*/
460                 
461                 // Ignore if correct pressure is already set and is not on
462                 // request_area.
463                 // Thus, request_area can be used for updating as much
464                 // pressure info in some area as possible to possibly
465                 // make some calls to getWaterPressure unnecessary.
466                 if(n.pressure == pr2 && request_area.contains(p2) == false)
467                         continue;
468
469                 spreadWaterPressure(p2, pr2, request_area, active_nodes, recur_count);
470         }
471 }
472
473 void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
474                 core::map<v3s16, u8> &active_nodes,
475                 bool checked3_is_clear)
476 {
477         TimeTaker timer("updateAreaWaterPressure", &updateareawaterpressure_time);
478
479         emerge(a, 3);
480         
481         bool checked2_clear = false;
482         
483         if(checked3_is_clear == false)
484         {
485                 //clearFlag(VOXELFLAG_CHECKED3);
486
487                 clearFlag(VOXELFLAG_CHECKED3 | VOXELFLAG_CHECKED2);
488                 checked2_clear = true;
489         }
490         
491
492         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
493         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
494         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
495         {
496                 v3s16 p(x,y,z);
497
498                 u8 f = m_flags[m_area.index(p)];
499                 // Ignore inexistent or checked nodes
500                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
501                         continue;
502                 MapNode &n = m_data[m_area.index(p)];
503                 // Ignore non-liquid nodes
504                 if(content_liquid(n.d) == false)
505                         continue;
506                 
507                 if(checked2_clear == false)
508                 {
509                         clearFlag(VOXELFLAG_CHECKED2);
510                         checked2_clear = true;
511                 }
512
513                 checked2_clear = false;
514
515                 s16 highest_y = -32768;
516                 int recur_count = 0;
517                 int pr = -1;
518
519                 try
520                 {
521                         // 0-1ms @ recur_count <= 100
522                         //TimeTaker timer("getWaterPressure", g_irrlicht);
523                         pr = getWaterPressure(p, highest_y, recur_count);
524                 }
525                 catch(ProcessingLimitException &e)
526                 {
527                         //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
528                 }
529
530                 if(pr == -1)
531                 {
532                         assert(highest_y != -32768);
533
534                         pr = highest_y - p.Y + 1;
535                         if(pr > 255)
536                                 pr = 255;
537
538                         /*dstream<<"WARNING: Pressure at ("
539                                         <<p.X<<","<<p.Y<<","<<p.Z<<")"
540                                         <<" = "<<pr
541                                         //<<" and highest_y == -32768"
542                                         <<std::endl;
543                         assert(highest_y != -32768);
544                         continue;*/
545                 }
546                 
547                 try
548                 {
549                         // 0ms
550                         //TimeTaker timer("spreadWaterPressure", g_irrlicht);
551                         spreadWaterPressure(p, pr, a, active_nodes, 0);
552                 }
553                 catch(ProcessingLimitException &e)
554                 {
555                         //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
556                 }
557         }
558 }
559
560 bool VoxelManipulator::flowWater(v3s16 removed_pos,
561                 core::map<v3s16, u8> &active_nodes,
562                 int recursion_depth, bool debugprint,
563                 u32 stoptime)
564 {
565         v3s16 dirs[6] = {
566                 v3s16(0,1,0), // top
567                 v3s16(0,0,-1), // front
568                 v3s16(0,0,1), // back
569                 v3s16(-1,0,0), // left
570                 v3s16(1,0,0), // right
571                 v3s16(0,-1,0), // bottom
572         };
573
574         recursion_depth++;
575
576         v3s16 p;
577         bool from_ocean = false;
578         
579         // Randomize horizontal order
580         static s32 cs = 0;
581         if(cs < 3)
582                 cs++;
583         else
584                 cs = 0;
585         s16 s1 = (cs & 1) ? 1 : -1;
586         s16 s2 = (cs & 2) ? 1 : -1;
587         //dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
588
589         {
590         TimeTaker timer1("flowWater pre", &flowwater_pre_time);
591         
592         // Load neighboring nodes
593         emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)), 4);
594         
595         // Ignore incorrect removed_pos
596         {
597                 u8 f = m_flags[m_area.index(removed_pos)];
598                 // Ignore inexistent or checked node
599                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
600                         return false;
601                 MapNode &n = m_data[m_area.index(removed_pos)];
602                 // Ignore nodes to which the water can't go
603                 if(liquid_replaces_content(n.d) == false)
604                         return false;
605         }
606         
607         s32 i;
608         for(i=0; i<6; i++)
609         {
610                 // Don't raise water from bottom
611                 if(m_disable_water_climb && i == 5)
612                         continue;
613
614                 p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
615
616                 u8 f = m_flags[m_area.index(p)];
617                 // Inexistent or checked nodes can't move
618                 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
619                         continue;
620                 MapNode &n = m_data[m_area.index(p)];
621                 // Only liquid nodes can move
622                 if(content_liquid(n.d) == false)
623                         continue;
624                 // If block is at top, select it always
625                 if(i == 0)
626                 {
627                         break;
628                 }
629                 // If block is at bottom, select it if it has enough pressure
630                 if(i == 5)
631                 {
632                         //if(n.pressure >= PRESERVE_WATER_VOLUME ? 3 : 2)
633                         if(n.pressure >= 3)
634                                 break;
635                         continue;
636                 }
637                 // Else block is at some side. Select it if it has enough pressure
638                 //if(n.pressure >= PRESERVE_WATER_VOLUME ? 2 : 1)
639                 if(n.pressure >= 2)
640                 {
641                         break;
642                 }
643         }
644
645         // If there is nothing to move, return
646         if(i==6)
647                 return false;
648
649         /*
650                 Move water and bubble
651         */
652
653         u8 m = m_data[m_area.index(p)].d;
654         u8 f = m_flags[m_area.index(p)];
655
656         if(m == CONTENT_WATERSOURCE)
657                 from_ocean = true;
658
659         // Move air bubble if not taking water from ocean
660         if(from_ocean == false)
661         {
662                 m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
663                 m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
664         }
665         
666         /*
667                 This has to be done to copy the brightness of a light source
668                 correctly. Otherwise unspreadLight will fuck up when water
669                 has replaced a light source.
670         */
671         u8 light = m_data[m_area.index(removed_pos)].getLightBanksWithSource();
672
673         m_data[m_area.index(removed_pos)].d = m;
674         m_flags[m_area.index(removed_pos)] = f;
675
676         m_data[m_area.index(removed_pos)].setLightBanks(light);
677         
678         // Mark removed_pos checked
679         m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
680
681         // If block was dropped from surface, increase pressure
682         if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
683         {
684                 m_data[m_area.index(removed_pos)].pressure = 2;
685         }
686         
687         /*
688         NOTE: This does not work as-is
689         if(m == CONTENT_WATERSOURCE)
690         {
691                 // If block was raised to surface, increase pressure of
692                 // source node
693                 if(i == 5 && m_data[m_area.index(p)].pressure == 1)
694                 {
695                         m_data[m_area.index(p)].pressure = 2;
696                 }
697         }*/
698         
699         /*if(debugprint)
700         {
701                 dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
702                 print(dstream, VOXELPRINT_WATERPRESSURE);
703         }*/
704
705         // Update pressure
706         VoxelArea a;
707         a.addPoint(p - v3s16(1,1,1));
708         a.addPoint(p + v3s16(1,1,1));
709         a.addPoint(removed_pos - v3s16(1,1,1));
710         a.addPoint(removed_pos + v3s16(1,1,1));
711         updateAreaWaterPressure(a, active_nodes);
712         
713         /*if(debugprint)
714         {
715                 dstream<<"VoxelManipulator::flowWater(): Pressure updated:"<<std::endl;
716                 print(dstream, VOXELPRINT_WATERPRESSURE);
717                 //std::cin.get();
718         }*/
719
720         if(debugprint)
721         {
722                 dstream<<"VoxelManipulator::flowWater(): step done:"<<std::endl;
723                 print(dstream, VOXELPRINT_WATERPRESSURE);
724                 //std::cin.get();
725         }
726         
727         }//timer1
728         
729         //if(PRESERVE_WATER_VOLUME)
730         if(from_ocean == false)
731         {
732                 // Flow water to the newly created empty position
733                 /*flowWater(p, active_nodes, recursion_depth,
734                                 debugprint, counter, counterlimit);*/
735                 flowWater(p, active_nodes, recursion_depth,
736                                 debugprint, stoptime);
737         }
738         
739         if(stoptime != 0)
740         {
741                 u32 timenow = getTimeMs();
742                 // Well, it is a bit hard to guess because we don't know the
743                 // start time...
744                 bool overflow = timenow < stoptime - 100000;
745                 if(timenow >= stoptime || overflow)
746                 {
747                         dstream<<"flowWater: stoptime reached"<<std::endl;
748                         throw ProcessingLimitException("flowWater stoptime reached");
749                 }
750         }
751         
752 find_again:
753         
754         // Try flowing water to empty positions around removed_pos.
755         // They are checked in reverse order compared to the previous loop.
756         for(s32 i=5; i>=0; i--)
757         {
758                 // Don't try to flow to top
759                 if(m_disable_water_climb && i == 0)
760                         continue;
761
762                 //v3s16 p = removed_pos + dirs[i];
763                 p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
764
765                 u8 f = m_flags[m_area.index(p)];
766                 // Water can't move to inexistent nodes
767                 if(f & VOXELFLAG_INEXISTENT)
768                         continue;
769                 MapNode &n = m_data[m_area.index(p)];
770                 // Water can only move to air
771                 if(liquid_replaces_content(n.d) == false)
772                         continue;
773                         
774                 // Flow water to node
775                 bool moved =
776                 flowWater(p, active_nodes, recursion_depth,
777                                 debugprint, stoptime);
778                 /*flowWater(p, active_nodes, recursion_depth,
779                                 debugprint, counter, counterlimit);*/
780                 
781                 if(moved)
782                 {
783                         // Search again from all neighbors
784                         goto find_again;
785                 }
786         }
787
788         return true;
789 }
790
791 void VoxelManipulator::flowWater(
792                 core::map<v3s16, u8> &active_nodes,
793                 int recursion_depth, bool debugprint,
794                 u32 timelimit)
795 {
796         addarea_time = 0;
797         emerge_time = 0;
798         emerge_load_time = 0;
799         clearflag_time = 0;
800         updateareawaterpressure_time = 0;
801         flowwater_pre_time = 0;
802
803         if(active_nodes.size() == 0)
804         {
805                 dstream<<"flowWater: no active nodes"<<std::endl;
806                 return;
807         }
808
809         //TimeTaker timer1("flowWater (active_nodes)", g_irrlicht);
810
811         //dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
812
813
814         u32 stoptime = 0;
815         stoptime = getTimeMs() + timelimit;
816
817         // Count of handled active nodes
818         u32 handled_count = 0;
819
820         try
821         {
822
823         /*
824                 Take random one at first
825
826                 This is randomized only at the first time so that all
827                 subsequent nodes will be taken at roughly the same position
828         */
829         s32 k = 0;
830         if(active_nodes.size() != 0)
831                 k = (s32)myrand() % (s32)active_nodes.size();
832
833         // Flow water to active nodes
834         for(;;)
835         //for(s32 h=0; h<1; h++)
836         {
837                 if(active_nodes.size() == 0)
838                         break;
839
840                 handled_count++;
841                 
842                 // Clear check flags
843                 clearFlag(VOXELFLAG_CHECKED);
844                 
845                 //dstream<<"Selecting a new active_node"<<std::endl;
846
847 #if 0
848                 // Take first one
849                 core::map<v3s16, u8>::Node
850                                 *n = active_nodes.getIterator().getNode();
851 #endif
852
853 #if 1
854                 
855                 core::map<v3s16, u8>::Iterator
856                                 i = active_nodes.getIterator().getNode();
857                 for(s32 j=0; j<k; j++)
858                 {
859                         i++;
860                 }
861                 core::map<v3s16, u8>::Node *n = i.getNode();
862
863                 // Decrement index if less than 0.
864                 // This keeps us in existing indices always.
865                 if(k > 0)
866                         k--;
867 #endif
868
869                 v3s16 p = n->getKey();
870                 active_nodes.remove(p);
871                 flowWater(p, active_nodes, recursion_depth,
872                                 debugprint, stoptime);
873         }
874
875         }
876         catch(ProcessingLimitException &e)
877         {
878                 //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
879         }
880         
881         /*v3s16 e = m_area.getExtent();
882         s32 v = m_area.getVolume();
883         dstream<<"flowWater (active): "
884                         <<"area ended up as "
885                         <<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
886                         <<", handled a_node count: "<<handled_count
887                         <<", active_nodes.size() = "<<active_nodes.size()
888                         <<std::endl;
889         dstream<<"addarea_time: "<<addarea_time
890                         <<", emerge_time: "<<emerge_time
891                         <<", emerge_load_time: "<<emerge_load_time
892                         <<", clearflag_time: "<<clearflag_time
893                         <<", flowwater_pre_time: "<<flowwater_pre_time
894                         <<", updateareawaterpressure_time: "<<updateareawaterpressure_time
895                         <<std::endl;*/
896 }
897
898
899 //END