3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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;
40 VoxelManipulator::VoxelManipulator():
44 m_disable_water_climb = false;
47 VoxelManipulator::~VoxelManipulator()
56 void VoxelManipulator::clear()
58 // Reset area to volume=0
68 void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
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;
75 for(s32 y=m_area.MaxEdge.Y; y>=m_area.MinEdge.Y; y--)
77 if(em.X >= 3 && em.Y >= 3)
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-> ";
85 for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
87 for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
89 u8 f = m_flags[m_area.index(x,y,z)];
91 if(f & VOXELFLAG_NOT_LOADED)
93 else if(f & VOXELFLAG_INEXISTENT)
98 u8 m = m_data[m_area.index(x,y,z)].d;
99 u8 pr = m_data[m_area.index(x,y,z)].param2;
100 if(mode == VOXELPRINT_MATERIAL)
105 else if(mode == VOXELPRINT_WATERPRESSURE)
107 if(m == CONTENT_WATER)
113 else if(liquid_replaces_content(m))
131 void VoxelManipulator::addArea(VoxelArea area)
133 // Cancel if requested area has zero volume
134 if(area.getExtent() == v3s16(0,0,0))
137 // Cancel if m_area already contains the requested area
138 if(m_area.contains(area))
141 TimeTaker timer("addArea", &addarea_time);
143 // Calculate new area
145 // New area is the requested area if m_area has zero volume
146 if(m_area.getExtent() == v3s16(0,0,0))
150 // Else add requested area to m_area
154 new_area.addArea(area);
157 s32 new_size = new_area.getVolume();
159 /*dstream<<"adding area ";
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;*/
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++)
173 new_flags[i] = VOXELFLAG_NOT_LOADED;
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++)
182 // If loaded, copy data and flags
183 if((m_flags[m_area.index(x,y,z)] & VOXELFLAG_NOT_LOADED) == false)
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)];
190 // Replace area, data and flags
194 MapNode *old_data = m_data;
195 u8 *old_flags = m_flags;
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;*/
208 //dstream<<"addArea done"<<std::endl;
211 void VoxelManipulator::copyFrom(MapNode *src, VoxelArea src_area,
212 v3s16 from_pos, v3s16 to_pos, v3s16 size)
214 for(s16 z=0; z<size.Z; z++)
215 for(s16 y=0; y<size.Y; y++)
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);
225 void VoxelManipulator::clearFlag(u8 flags)
227 // 0-1ms on moderate area
228 TimeTaker timer("clearFlag", &clearflag_time);
230 v3s16 s = m_area.getExtent();
232 /*dstream<<"clearFlag clearing area of size "
233 <<""<<s.X<<"x"<<s.Y<<"x"<<s.Z<<""
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++)
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)
248 s32 volume = m_area.getVolume();
249 for(s32 i=0; i<volume; i++)
251 m_flags[i] &= ~flags;
254 /*s32 volume = m_area.getVolume();
255 for(s32 i=0; i<volume; i++)
258 m_flags[i] &= ~flags;
263 dstream<<"clearFlag changed "<<count<<" flags out of "
264 <<volume<<" nodes"<<std::endl;*/
267 void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
268 core::map<v3s16, bool> & light_sources)
271 v3s16(0,0,1), // back
273 v3s16(1,0,0), // right
274 v3s16(0,0,-1), // front
275 v3s16(0,-1,0), // bottom
276 v3s16(-1,0,0), // left
279 emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
281 // Loop through 6 neighbors
282 for(u16 i=0; i<6; i++)
284 // Get the position of the neighbor node
285 v3s16 n2pos = p + dirs[i];
287 u32 n2i = m_area.index(n2pos);
289 if(m_flags[n2i] & VOXELFLAG_INEXISTENT)
292 MapNode &n2 = m_data[n2i];
295 If the neighbor is dimmer than what was specified
296 as oldlight (the light of the previous node)
298 if(n2.getLight(bank) < oldlight)
301 And the neighbor is transparent and it has some light
303 if(n2.light_propagates() && n2.getLight(bank) != 0)
306 Set light to 0 and add to queue
309 u8 current_light = n2.getLight(bank);
310 n2.setLight(bank, 0);
312 unspreadLight(bank, n2pos, current_light, light_sources);
315 Remove from light_sources if it is there
316 NOTE: This doesn't happen nearly at all
318 /*if(light_sources.find(n2pos))
320 std::cout<<"Removed from light_sources"<<std::endl;
321 light_sources.remove(n2pos);
326 light_sources.insert(n2pos, true);
333 Goes recursively through the neighbours of the node.
335 Alters only transparent nodes.
337 If the lighting of the neighbour is lower than the lighting of
338 the node was (before changing it to 0 at the step before), the
339 lighting of the neighbour is set to 0 and then the same stuff
340 repeats for the neighbour.
342 The ending nodes of the routine are stored in light_sources.
343 This is useful when a light is removed. In such case, this
344 routine can be called for the light node and then again for
345 light_sources to re-light the area without the removed light.
347 values of from_nodes are lighting values.
349 void VoxelManipulator::unspreadLight(enum LightBank bank,
350 core::map<v3s16, u8> & from_nodes,
351 core::map<v3s16, bool> & light_sources)
353 if(from_nodes.size() == 0)
356 core::map<v3s16, u8>::Iterator j;
357 j = from_nodes.getIterator();
359 for(; j.atEnd() == false; j++)
361 v3s16 pos = j.getNode()->getKey();
363 //MapNode &n = m_data[m_area.index(pos)];
365 u8 oldlight = j.getNode()->getValue();
367 unspreadLight(bank, pos, oldlight, light_sources);
374 Goes recursively through the neighbours of the node.
376 Alters only transparent nodes.
378 If the lighting of the neighbour is lower than the lighting of
379 the node was (before changing it to 0 at the step before), the
380 lighting of the neighbour is set to 0 and then the same stuff
381 repeats for the neighbour.
383 The ending nodes of the routine are stored in light_sources.
384 This is useful when a light is removed. In such case, this
385 routine can be called for the light node and then again for
386 light_sources to re-light the area without the removed light.
388 values of from_nodes are lighting values.
390 void VoxelManipulator::unspreadLight(enum LightBank bank,
391 core::map<v3s16, u8> & from_nodes,
392 core::map<v3s16, bool> & light_sources)
395 v3s16(0,0,1), // back
397 v3s16(1,0,0), // right
398 v3s16(0,0,-1), // front
399 v3s16(0,-1,0), // bottom
400 v3s16(-1,0,0), // left
403 if(from_nodes.size() == 0)
406 core::map<v3s16, u8> unlighted_nodes;
407 core::map<v3s16, u8>::Iterator j;
408 j = from_nodes.getIterator();
410 for(; j.atEnd() == false; j++)
412 v3s16 pos = j.getNode()->getKey();
414 emerge(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1)));
416 //MapNode &n = m_data[m_area.index(pos)];
418 u8 oldlight = j.getNode()->getValue();
420 // Loop through 6 neighbors
421 for(u16 i=0; i<6; i++)
423 // Get the position of the neighbor node
424 v3s16 n2pos = pos + dirs[i];
426 u32 n2i = m_area.index(n2pos);
428 if(m_flags[n2i] & VOXELFLAG_INEXISTENT)
431 MapNode &n2 = m_data[n2i];
434 If the neighbor is dimmer than what was specified
435 as oldlight (the light of the previous node)
437 if(n2.getLight(bank) < oldlight)
440 And the neighbor is transparent and it has some light
442 if(n2.light_propagates() && n2.getLight(bank) != 0)
445 Set light to 0 and add to queue
448 u8 current_light = n2.getLight(bank);
449 n2.setLight(bank, 0);
451 unlighted_nodes.insert(n2pos, current_light);
454 Remove from light_sources if it is there
455 NOTE: This doesn't happen nearly at all
457 /*if(light_sources.find(n2pos))
459 std::cout<<"Removed from light_sources"<<std::endl;
460 light_sources.remove(n2pos);
465 light_sources.insert(n2pos, true);
470 /*dstream<<"unspreadLight(): Changed block "
471 <<blockchangecount<<" times"
472 <<" for "<<from_nodes.size()<<" nodes"
475 if(unlighted_nodes.size() > 0)
476 unspreadLight(bank, unlighted_nodes, light_sources);
480 void VoxelManipulator::spreadLight(enum LightBank bank, v3s16 p)
482 const v3s16 dirs[6] = {
483 v3s16(0,0,1), // back
485 v3s16(1,0,0), // right
486 v3s16(0,0,-1), // front
487 v3s16(0,-1,0), // bottom
488 v3s16(-1,0,0), // left
491 emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)));
493 u32 i = m_area.index(p);
495 if(m_flags[i] & VOXELFLAG_INEXISTENT)
498 MapNode &n = m_data[i];
500 u8 oldlight = n.getLight(bank);
501 u8 newlight = diminish_light(oldlight);
503 // Loop through 6 neighbors
504 for(u16 i=0; i<6; i++)
506 // Get the position of the neighbor node
507 v3s16 n2pos = p + dirs[i];
509 u32 n2i = m_area.index(n2pos);
511 if(m_flags[n2i] & VOXELFLAG_INEXISTENT)
514 MapNode &n2 = m_data[n2i];
517 If the neighbor is brighter than the current node,
518 add to list (it will light up this node on its turn)
520 if(n2.getLight(bank) > undiminish_light(oldlight))
522 spreadLight(bank, n2pos);
525 If the neighbor is dimmer than how much light this node
526 would spread on it, add to list
528 if(n2.getLight(bank) < newlight)
530 if(n2.light_propagates())
532 n2.setLight(bank, newlight);
533 spreadLight(bank, n2pos);
541 Lights neighbors of from_nodes, collects all them and then
544 void VoxelManipulator::spreadLight(enum LightBank bank,
545 core::map<v3s16, bool> & from_nodes)
547 if(from_nodes.size() == 0)
550 core::map<v3s16, bool> lighted_nodes;
551 core::map<v3s16, bool>::Iterator j;
552 j = from_nodes.getIterator();
554 for(; j.atEnd() == false; j++)
556 v3s16 pos = j.getNode()->getKey();
558 spreadLight(bank, pos);
565 Lights neighbors of from_nodes, collects all them and then
568 void VoxelManipulator::spreadLight(enum LightBank bank,
569 core::map<v3s16, bool> & from_nodes)
571 const v3s16 dirs[6] = {
572 v3s16(0,0,1), // back
574 v3s16(1,0,0), // right
575 v3s16(0,0,-1), // front
576 v3s16(0,-1,0), // bottom
577 v3s16(-1,0,0), // left
580 if(from_nodes.size() == 0)
583 core::map<v3s16, bool> lighted_nodes;
584 core::map<v3s16, bool>::Iterator j;
585 j = from_nodes.getIterator();
587 for(; j.atEnd() == false; j++)
589 v3s16 pos = j.getNode()->getKey();
591 emerge(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1)));
593 u32 i = m_area.index(pos);
595 if(m_flags[i] & VOXELFLAG_INEXISTENT)
598 MapNode &n = m_data[i];
600 u8 oldlight = n.getLight(bank);
601 u8 newlight = diminish_light(oldlight);
603 // Loop through 6 neighbors
604 for(u16 i=0; i<6; i++)
606 // Get the position of the neighbor node
607 v3s16 n2pos = pos + dirs[i];
611 u32 n2i = m_area.index(n2pos);
613 if(m_flags[n2i] & VOXELFLAG_INEXISTENT)
616 MapNode &n2 = m_data[n2i];
619 If the neighbor is brighter than the current node,
620 add to list (it will light up this node on its turn)
622 if(n2.getLight(bank) > undiminish_light(oldlight))
624 lighted_nodes.insert(n2pos, true);
627 If the neighbor is dimmer than how much light this node
628 would spread on it, add to list
630 if(n2.getLight(bank) < newlight)
632 if(n2.light_propagates())
634 n2.setLight(bank, newlight);
635 lighted_nodes.insert(n2pos, true);
639 catch(InvalidPositionException &e)
646 /*dstream<<"spreadLight(): Changed block "
647 <<blockchangecount<<" times"
648 <<" for "<<from_nodes.size()<<" nodes"
651 if(lighted_nodes.size() > 0)
652 spreadLight(bank, lighted_nodes);
657 int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count)
659 m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED2;
664 /*if(recur_count > 1000)
665 throw ProcessingLimitException
666 ("getWaterPressure recur_count limit reached");*/
668 if(recur_count > 10000)
675 v3s16(0,0,1), // back
676 v3s16(0,0,-1), // front
677 v3s16(1,0,0), // right
678 v3s16(-1,0,0), // left
679 v3s16(0,-1,0), // bottom
682 // Load neighboring nodes
683 emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 1);
688 v3s16 p2 = p + dirs[i];
689 u8 f = m_flags[m_area.index(p2)];
690 // Ignore inexistent or checked nodes
691 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED2))
693 MapNode &n = m_data[m_area.index(p2)];
694 // Ignore non-liquid nodes
695 if(content_liquid(n.d) == false)
700 // If at ocean surface
701 if(n.pressure == 1 && n.d == CONTENT_WATERSOURCE)
702 //if(n.pressure == 1) // Causes glitches but is fast
706 // Otherwise recurse more
709 pr = getWaterPressure(p2, highest_y, recur_count);
714 // If block is at top, pressure here is one higher
720 // If block is at bottom, pressure here is one lower
727 // Node is on the pressure route
728 m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED4;
734 // Nothing useful found
738 void VoxelManipulator::spreadWaterPressure(v3s16 p, int pr,
739 VoxelArea request_area,
740 core::map<v3s16, u8> &active_nodes,
743 //if(recur_count > 10000)
744 /*throw ProcessingLimitException
745 ("spreadWaterPressure recur_count limit reached");*/
750 /*dstream<<"spreadWaterPressure: p=("
751 <<p.X<<","<<p.Y<<","<<p.Z<<")"
752 <<", oldpr="<<(int)m_data[m_area.index(p)].pressure
754 <<", recur_count="<<recur_count
756 request_area.print(dstream);
757 dstream<<std::endl;*/
759 m_flags[m_area.index(p)] |= VOXELFLAG_CHECKED3;
760 m_data[m_area.index(p)].pressure = pr;
764 v3s16(-1,0,0), // left
765 v3s16(1,0,0), // right
766 v3s16(0,0,-1), // front
767 v3s16(0,0,1), // back
768 v3s16(0,-1,0), // bottom
771 // Load neighboring nodes
772 emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1)), 2);
777 v3s16 p2 = p + dirs[i];
779 u8 f = m_flags[m_area.index(p2)];
781 // Ignore inexistent and checked nodes
782 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
785 MapNode &n = m_data[m_area.index(p2)];
789 add to active_nodes if there is flow-causing pressure.
790 NOTE: Do not remove anything from there. We cannot know
791 here if some other neighbor of it causes flow.
793 if(liquid_replaces_content(n.d))
795 bool pressure_causes_flow = false;
796 // If empty block is at top
799 if(m_disable_water_climb)
802 //if(pr >= PRESERVE_WATER_VOLUME ? 3 : 2)
804 pressure_causes_flow = true;
806 // If block is at bottom
809 pressure_causes_flow = true;
811 // If block is at side
814 //if(pr >= PRESERVE_WATER_VOLUME ? 2 : 1)
816 pressure_causes_flow = true;
819 if(pressure_causes_flow)
821 active_nodes[p2] = 1;
827 // Ignore non-liquid nodes
828 if(content_liquid(n.d) == false)
832 // If block is at top, pressure there is lower
838 // If block is at bottom, pressure there is higher
845 /*if(m_disable_water_climb)
851 // Ignore if correct pressure is already set and is not on
853 // Thus, request_area can be used for updating as much
854 // pressure info in some area as possible to possibly
855 // make some calls to getWaterPressure unnecessary.
856 if(n.pressure == pr2 && request_area.contains(p2) == false)
859 spreadWaterPressure(p2, pr2, request_area, active_nodes, recur_count);
863 void VoxelManipulator::updateAreaWaterPressure(VoxelArea a,
864 core::map<v3s16, u8> &active_nodes,
865 bool checked3_is_clear)
867 TimeTaker timer("updateAreaWaterPressure", &updateareawaterpressure_time);
871 bool checked2_clear = false;
873 if(checked3_is_clear == false)
875 //clearFlag(VOXELFLAG_CHECKED3);
877 clearFlag(VOXELFLAG_CHECKED3 | VOXELFLAG_CHECKED2);
878 checked2_clear = true;
882 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
883 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
884 for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
888 u8 f = m_flags[m_area.index(p)];
889 // Ignore inexistent or checked nodes
890 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED3))
892 MapNode &n = m_data[m_area.index(p)];
893 // Ignore non-liquid nodes
894 if(content_liquid(n.d) == false)
897 if(checked2_clear == false)
899 clearFlag(VOXELFLAG_CHECKED2);
900 checked2_clear = true;
903 checked2_clear = false;
905 s16 highest_y = -32768;
911 // 0-1ms @ recur_count <= 100
912 //TimeTaker timer("getWaterPressure", g_irrlicht);
913 pr = getWaterPressure(p, highest_y, recur_count);
915 catch(ProcessingLimitException &e)
917 //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
922 assert(highest_y != -32768);
924 pr = highest_y - p.Y + 1;
928 /*dstream<<"WARNING: Pressure at ("
929 <<p.X<<","<<p.Y<<","<<p.Z<<")"
931 //<<" and highest_y == -32768"
933 assert(highest_y != -32768);
940 //TimeTaker timer("spreadWaterPressure", g_irrlicht);
941 spreadWaterPressure(p, pr, a, active_nodes, 0);
943 catch(ProcessingLimitException &e)
945 //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
950 bool VoxelManipulator::flowWater(v3s16 removed_pos,
951 core::map<v3s16, u8> &active_nodes,
952 int recursion_depth, bool debugprint,
957 v3s16(0,0,-1), // front
958 v3s16(0,0,1), // back
959 v3s16(-1,0,0), // left
960 v3s16(1,0,0), // right
961 v3s16(0,-1,0), // bottom
967 bool from_ocean = false;
969 // Randomize horizontal order
975 s16 s1 = (cs & 1) ? 1 : -1;
976 s16 s2 = (cs & 2) ? 1 : -1;
977 //dstream<<"s1="<<s1<<", s2="<<s2<<std::endl;
980 TimeTaker timer1("flowWater pre", &flowwater_pre_time);
982 // Load neighboring nodes
983 emerge(VoxelArea(removed_pos - v3s16(1,1,1), removed_pos + v3s16(1,1,1)), 4);
985 // Ignore incorrect removed_pos
987 u8 f = m_flags[m_area.index(removed_pos)];
988 // Ignore inexistent or checked node
989 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
991 MapNode &n = m_data[m_area.index(removed_pos)];
992 // Ignore nodes to which the water can't go
993 if(liquid_replaces_content(n.d) == false)
1000 // Don't raise water from bottom
1001 if(m_disable_water_climb && i == 5)
1004 p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
1006 u8 f = m_flags[m_area.index(p)];
1007 // Inexistent or checked nodes can't move
1008 if(f & (VOXELFLAG_INEXISTENT | VOXELFLAG_CHECKED))
1010 MapNode &n = m_data[m_area.index(p)];
1011 // Only liquid nodes can move
1012 if(content_liquid(n.d) == false)
1014 // If block is at top, select it always
1019 // If block is at bottom, select it if it has enough pressure
1022 //if(n.pressure >= PRESERVE_WATER_VOLUME ? 3 : 2)
1027 // Else block is at some side. Select it if it has enough pressure
1028 //if(n.pressure >= PRESERVE_WATER_VOLUME ? 2 : 1)
1035 // If there is nothing to move, return
1040 Move water and bubble
1043 u8 m = m_data[m_area.index(p)].d;
1044 u8 f = m_flags[m_area.index(p)];
1046 if(m == CONTENT_WATERSOURCE)
1049 // Move air bubble if not taking water from ocean
1050 if(from_ocean == false)
1052 m_data[m_area.index(p)].d = m_data[m_area.index(removed_pos)].d;
1053 m_flags[m_area.index(p)] = m_flags[m_area.index(removed_pos)];
1057 This has to be done to copy the brightness of a light source
1058 correctly. Otherwise unspreadLight will fuck up when water
1059 has replaced a light source.
1061 u8 light = m_data[m_area.index(removed_pos)].getLightBanksWithSource();
1063 m_data[m_area.index(removed_pos)].d = m;
1064 m_flags[m_area.index(removed_pos)] = f;
1066 m_data[m_area.index(removed_pos)].setLightBanks(light);
1068 // Mark removed_pos checked
1069 m_flags[m_area.index(removed_pos)] |= VOXELFLAG_CHECKED;
1071 // If block was dropped from surface, increase pressure
1072 if(i == 0 && m_data[m_area.index(removed_pos)].pressure == 1)
1074 m_data[m_area.index(removed_pos)].pressure = 2;
1078 NOTE: This does not work as-is
1079 if(m == CONTENT_WATERSOURCE)
1081 // If block was raised to surface, increase pressure of
1083 if(i == 5 && m_data[m_area.index(p)].pressure == 1)
1085 m_data[m_area.index(p)].pressure = 2;
1091 dstream<<"VoxelManipulator::flowWater(): Moved bubble:"<<std::endl;
1092 print(dstream, VOXELPRINT_WATERPRESSURE);
1097 a.addPoint(p - v3s16(1,1,1));
1098 a.addPoint(p + v3s16(1,1,1));
1099 a.addPoint(removed_pos - v3s16(1,1,1));
1100 a.addPoint(removed_pos + v3s16(1,1,1));
1101 updateAreaWaterPressure(a, active_nodes);
1105 dstream<<"VoxelManipulator::flowWater(): Pressure updated:"<<std::endl;
1106 print(dstream, VOXELPRINT_WATERPRESSURE);
1112 dstream<<"VoxelManipulator::flowWater(): step done:"<<std::endl;
1113 print(dstream, VOXELPRINT_WATERPRESSURE);
1119 //if(PRESERVE_WATER_VOLUME)
1120 if(from_ocean == false)
1122 // Flow water to the newly created empty position
1123 /*flowWater(p, active_nodes, recursion_depth,
1124 debugprint, counter, counterlimit);*/
1125 flowWater(p, active_nodes, recursion_depth,
1126 debugprint, stoptime);
1131 u32 timenow = getTimeMs();
1132 // Well, it is a bit hard to guess because we don't know the
1134 bool overflow = timenow < stoptime - 100000;
1135 if(timenow >= stoptime || overflow)
1137 dstream<<"flowWater: stoptime reached"<<std::endl;
1138 throw ProcessingLimitException("flowWater stoptime reached");
1144 // Try flowing water to empty positions around removed_pos.
1145 // They are checked in reverse order compared to the previous loop.
1146 for(s32 i=5; i>=0; i--)
1148 // Don't try to flow to top
1149 if(m_disable_water_climb && i == 0)
1152 //v3s16 p = removed_pos + dirs[i];
1153 p = removed_pos + v3s16(s1*dirs[i].X, dirs[i].Y, s2*dirs[i].Z);
1155 u8 f = m_flags[m_area.index(p)];
1156 // Water can't move to inexistent nodes
1157 if(f & VOXELFLAG_INEXISTENT)
1159 MapNode &n = m_data[m_area.index(p)];
1160 // Water can only move to air
1161 if(liquid_replaces_content(n.d) == false)
1164 // Flow water to node
1166 flowWater(p, active_nodes, recursion_depth,
1167 debugprint, stoptime);
1168 /*flowWater(p, active_nodes, recursion_depth,
1169 debugprint, counter, counterlimit);*/
1173 // Search again from all neighbors
1181 void VoxelManipulator::flowWater(
1182 core::map<v3s16, u8> &active_nodes,
1183 int recursion_depth, bool debugprint,
1188 emerge_load_time = 0;
1190 updateareawaterpressure_time = 0;
1191 flowwater_pre_time = 0;
1193 if(active_nodes.size() == 0)
1195 dstream<<"flowWater: no active nodes"<<std::endl;
1199 //TimeTaker timer1("flowWater (active_nodes)", g_irrlicht);
1201 //dstream<<"active_nodes.size() = "<<active_nodes.size()<<std::endl;
1205 stoptime = getTimeMs() + timelimit;
1207 // Count of handled active nodes
1208 u32 handled_count = 0;
1214 Take random one at first
1216 This is randomized only at the first time so that all
1217 subsequent nodes will be taken at roughly the same position
1220 if(active_nodes.size() != 0)
1221 k = (s32)myrand() % (s32)active_nodes.size();
1223 // Flow water to active nodes
1225 //for(s32 h=0; h<1; h++)
1227 if(active_nodes.size() == 0)
1232 // Clear check flags
1233 clearFlag(VOXELFLAG_CHECKED);
1235 //dstream<<"Selecting a new active_node"<<std::endl;
1239 core::map<v3s16, u8>::Node
1240 *n = active_nodes.getIterator().getNode();
1245 core::map<v3s16, u8>::Iterator
1246 i = active_nodes.getIterator().getNode();
1247 for(s32 j=0; j<k; j++)
1251 core::map<v3s16, u8>::Node *n = i.getNode();
1253 // Decrement index if less than 0.
1254 // This keeps us in existing indices always.
1259 v3s16 p = n->getKey();
1260 active_nodes.remove(p);
1261 flowWater(p, active_nodes, recursion_depth,
1262 debugprint, stoptime);
1266 catch(ProcessingLimitException &e)
1268 //dstream<<"getWaterPressure ProcessingLimitException"<<std::endl;
1271 /*v3s16 e = m_area.getExtent();
1272 s32 v = m_area.getVolume();
1273 dstream<<"flowWater (active): "
1274 <<"area ended up as "
1275 <<e.X<<"x"<<e.Y<<"x"<<e.Z<<" = "<<v
1276 <<", handled a_node count: "<<handled_count
1277 <<", active_nodes.size() = "<<active_nodes.size()
1279 dstream<<"addarea_time: "<<addarea_time
1280 <<", emerge_time: "<<emerge_time
1281 <<", emerge_load_time: "<<emerge_load_time
1282 <<", clearflag_time: "<<clearflag_time
1283 <<", flowwater_pre_time: "<<flowwater_pre_time
1284 <<", updateareawaterpressure_time: "<<updateareawaterpressure_time