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