3 Copyright (C) 2010-2011 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.
25 //#include "serverobject.h"
26 #include "content_sao.h"
28 #include "content_mapnode.h" // For content_mapnode_get_new_name
29 #include "voxelalgorithms.h"
31 #include "main.h" // For g_profiler
37 Some helper functions for the map generator
41 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
43 v3s16 em = vmanip.m_area.getExtent();
44 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
45 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
46 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
48 for(y=y_nodes_max; y>=y_nodes_min; y--)
50 MapNode &n = vmanip.m_data[i];
51 if(content_walkable(n.d))
54 vmanip.m_area.add_y(em, i, -1);
62 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
64 v3s16 em = vmanip.m_area.getExtent();
65 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
66 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
67 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
69 for(y=y_nodes_max; y>=y_nodes_min; y--)
71 MapNode &n = vmanip.m_data[i];
72 if(content_walkable(n.d)
73 && n.getContent() != LEGN(ndef, "CONTENT_TREE")
74 && n.getContent() != LEGN(ndef, "CONTENT_LEAVES"))
77 vmanip.m_area.add_y(em, i, -1);
86 void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0,
87 bool is_apple_tree, INodeDefManager *ndef)
89 MapNode treenode(LEGN(ndef, "CONTENT_TREE"));
90 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
91 MapNode applenode(LEGN(ndef, "CONTENT_APPLE"));
93 s16 trunk_h = myrand_range(4, 5);
95 for(s16 ii=0; ii<trunk_h; ii++)
97 if(vmanip.m_area.contains(p1))
98 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
102 // p1 is now the last piece of the trunk
105 VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
106 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
107 Buffer<u8> leaves_d(leaves_a.getVolume());
108 for(s32 i=0; i<leaves_a.getVolume(); i++)
111 // Force leaves at near the end of the trunk
114 for(s16 z=-d; z<=d; z++)
115 for(s16 y=-d; y<=d; y++)
116 for(s16 x=-d; x<=d; x++)
118 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
122 // Add leaves randomly
123 for(u32 iii=0; iii<7; iii++)
128 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
129 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
130 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
133 for(s16 z=0; z<=d; z++)
134 for(s16 y=0; y<=d; y++)
135 for(s16 x=0; x<=d; x++)
137 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
141 // Blit leaves to vmanip
142 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
143 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
144 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
148 if(vmanip.m_area.contains(p) == false)
150 u32 vi = vmanip.m_area.index(p);
151 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
152 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
154 u32 i = leaves_a.index(x,y,z);
155 if(leaves_d[i] == 1) {
156 bool is_apple = myrand_range(0,99) < 10;
157 if(is_apple_tree && is_apple) {
158 vmanip.m_data[vi] = applenode;
160 vmanip.m_data[vi] = leavesnode;
166 static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0,
167 INodeDefManager *ndef)
169 MapNode treenode(LEGN(ndef, "CONTENT_JUNGLETREE"));
170 MapNode leavesnode(LEGN(ndef, "CONTENT_LEAVES"));
172 for(s16 x=-1; x<=1; x++)
173 for(s16 z=-1; z<=1; z++)
175 if(myrand_range(0, 2) == 0)
177 v3s16 p1 = p0 + v3s16(x,0,z);
178 v3s16 p2 = p0 + v3s16(x,-1,z);
179 if(vmanip.m_area.contains(p2)
180 && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
181 vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
182 else if(vmanip.m_area.contains(p1))
183 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
186 s16 trunk_h = myrand_range(8, 12);
188 for(s16 ii=0; ii<trunk_h; ii++)
190 if(vmanip.m_area.contains(p1))
191 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
195 // p1 is now the last piece of the trunk
198 VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
199 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
200 Buffer<u8> leaves_d(leaves_a.getVolume());
201 for(s32 i=0; i<leaves_a.getVolume(); i++)
204 // Force leaves at near the end of the trunk
207 for(s16 z=-d; z<=d; z++)
208 for(s16 y=-d; y<=d; y++)
209 for(s16 x=-d; x<=d; x++)
211 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
215 // Add leaves randomly
216 for(u32 iii=0; iii<30; iii++)
221 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
222 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
223 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
226 for(s16 z=0; z<=d; z++)
227 for(s16 y=0; y<=d; y++)
228 for(s16 x=0; x<=d; x++)
230 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
234 // Blit leaves to vmanip
235 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
236 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
237 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
241 if(vmanip.m_area.contains(p) == false)
243 u32 vi = vmanip.m_area.index(p);
244 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
245 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
247 u32 i = leaves_a.index(x,y,z);
249 vmanip.m_data[vi] = leavesnode;
253 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
254 INodeDefManager *ndef)
256 MapNode papyrusnode(LEGN(ndef, "CONTENT_PAPYRUS"));
258 s16 trunk_h = myrand_range(2, 3);
260 for(s16 ii=0; ii<trunk_h; ii++)
262 if(vmanip.m_area.contains(p1))
263 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
268 void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
269 INodeDefManager *ndef)
271 MapNode cactusnode(LEGN(ndef, "CONTENT_CACTUS"));
275 for(s16 ii=0; ii<trunk_h; ii++)
277 if(vmanip.m_area.contains(p1))
278 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
284 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
286 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
288 s16 size = myrand_range(3, 6);
290 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
291 Buffer<u8> stone_d(stone_a.getVolume());
292 for(s32 i=0; i<stone_a.getVolume(); i++)
295 // Force stone at bottom to make it usually touch the ground
297 for(s16 z=0; z<=0; z++)
298 for(s16 y=0; y<=0; y++)
299 for(s16 x=0; x<=0; x++)
301 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
305 // Generate from perlin noise
306 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
307 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
308 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
310 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
311 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
312 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
314 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
316 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
320 u32 vi = stone_a.index(v3s16(x,y,z));
325 /*// Add stone randomly
326 for(u32 iii=0; iii<7; iii++)
331 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
332 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
333 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
336 for(s16 z=0; z<=d; z++)
337 for(s16 y=0; y<=d; y++)
338 for(s16 x=0; x<=d; x++)
340 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
344 // Blit stone to vmanip
345 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
346 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
347 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
351 if(vmanip.m_area.contains(p) == false)
353 u32 vi = vmanip.m_area.index(p);
354 if(vmanip.m_data[vi].getContent() != CONTENT_AIR
355 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
357 u32 i = stone_a.index(x,y,z);
359 vmanip.m_data[vi] = stonenode;
365 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
367 MapNode stonenode(LEGN(ndef, "CONTENT_STONE"));
369 s16 size = myrand_range(8, 16);
371 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
372 Buffer<u8> stone_d(stone_a.getVolume());
373 for(s32 i=0; i<stone_a.getVolume(); i++)
376 // Force stone at bottom to make it usually touch the ground
378 for(s16 z=0; z<=0; z++)
379 for(s16 y=0; y<=0; y++)
380 for(s16 x=0; x<=0; x++)
382 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
386 // Generate from perlin noise
387 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
388 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
389 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
392 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
393 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
394 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
395 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
396 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
397 double dz = (double)z-mid_z;
398 double dx = (double)x-mid_x;
399 double dy = MYMAX(0, (double)y-mid_y);
400 double r = sqrt(dz*dz+dx*dx+dy*dy);
401 d /= (2*r/size)*2 + 0.01;
404 u32 vi = stone_a.index(v3s16(x,y,z));
409 /*// Add stone randomly
410 for(u32 iii=0; iii<7; iii++)
415 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
416 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
417 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
420 for(s16 z=0; z<=d; z++)
421 for(s16 y=0; y<=d; y++)
422 for(s16 x=0; x<=d; x++)
424 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
428 // Blit stone to vmanip
429 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
430 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
431 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
435 if(vmanip.m_area.contains(p) == false)
437 u32 vi = vmanip.m_area.index(p);
438 /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
439 && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
441 u32 i = stone_a.index(x,y,z);
443 vmanip.m_data[vi] = stonenode;
449 Dungeon making routines
452 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
453 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
454 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
455 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
457 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
458 INodeDefManager *ndef)
461 for(s16 z=0; z<roomsize.Z; z++)
462 for(s16 y=0; y<roomsize.Y; y++)
465 v3s16 p = roomplace + v3s16(0,y,z);
466 if(vmanip.m_area.contains(p) == false)
468 u32 vi = vmanip.m_area.index(p);
469 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
471 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
474 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
475 if(vmanip.m_area.contains(p) == false)
477 u32 vi = vmanip.m_area.index(p);
478 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
480 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
485 for(s16 x=0; x<roomsize.X; x++)
486 for(s16 y=0; y<roomsize.Y; y++)
489 v3s16 p = roomplace + v3s16(x,y,0);
490 if(vmanip.m_area.contains(p) == false)
492 u32 vi = vmanip.m_area.index(p);
493 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
495 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
498 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
499 if(vmanip.m_area.contains(p) == false)
501 u32 vi = vmanip.m_area.index(p);
502 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
504 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
508 // Make +-Y walls (floor and ceiling)
509 for(s16 z=0; z<roomsize.Z; z++)
510 for(s16 x=0; x<roomsize.X; x++)
513 v3s16 p = roomplace + v3s16(x,0,z);
514 if(vmanip.m_area.contains(p) == false)
516 u32 vi = vmanip.m_area.index(p);
517 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
519 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
522 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
523 if(vmanip.m_area.contains(p) == false)
525 u32 vi = vmanip.m_area.index(p);
526 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
528 vmanip.m_data[vi] = MapNode(LEGN(ndef, "CONTENT_COBBLE"));
533 for(s16 z=1; z<roomsize.Z-1; z++)
534 for(s16 y=1; y<roomsize.Y-1; y++)
535 for(s16 x=1; x<roomsize.X-1; x++)
537 v3s16 p = roomplace + v3s16(x,y,z);
538 if(vmanip.m_area.contains(p) == false)
540 u32 vi = vmanip.m_area.index(p);
541 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
542 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
546 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
547 u8 avoid_flags, MapNode n, u8 or_flags)
549 for(s16 z=0; z<size.Z; z++)
550 for(s16 y=0; y<size.Y; y++)
551 for(s16 x=0; x<size.X; x++)
553 v3s16 p = place + v3s16(x,y,z);
554 if(vmanip.m_area.contains(p) == false)
556 u32 vi = vmanip.m_area.index(p);
557 if(vmanip.m_flags[vi] & avoid_flags)
559 vmanip.m_flags[vi] |= or_flags;
560 vmanip.m_data[vi] = n;
564 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
565 INodeDefManager *ndef)
567 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
568 VMANIP_FLAG_DUNGEON_INSIDE);
571 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
572 INodeDefManager *ndef)
574 make_hole1(vmanip, doorplace, ndef);
575 // Place torch (for testing)
576 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
579 static v3s16 rand_ortho_dir(PseudoRandom &random)
581 if(random.next()%2==0)
582 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
584 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
587 static v3s16 turn_xz(v3s16 olddir, int t)
607 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
609 int turn = random.range(0,2);
618 dir = turn_xz(olddir, 0);
621 dir = turn_xz(olddir, 1);
625 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
626 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
627 PseudoRandom &random, INodeDefManager *ndef)
629 make_hole1(vmanip, doorplace, ndef);
630 v3s16 p0 = doorplace;
634 length = random.range(1,13);
636 length = random.range(1,6);
637 length = random.range(1,13);
638 u32 partlength = random.range(1,13);
641 if(random.next()%2 == 0 && partlength >= 3)
642 make_stairs = random.next()%2 ? 1 : -1;
643 for(u32 i=0; i<length; i++)
649 /*// If already empty
650 if(vmanip.getNodeNoExNoEmerge(p).getContent()
652 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
657 if(vmanip.m_area.contains(p) == true
658 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
662 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
663 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
664 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
665 VMANIP_FLAG_DUNGEON_INSIDE);
666 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
667 VMANIP_FLAG_DUNGEON_INSIDE);
671 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
672 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(LEGN(ndef, "CONTENT_COBBLE")), 0);
673 make_hole1(vmanip, p, ndef);
674 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
675 VMANIP_FLAG_DUNGEON_INSIDE);*/
682 // Can't go here, turn away
683 dir = turn_xz(dir, random.range(0,1));
684 make_stairs = -make_stairs;
686 partlength = random.range(1,length);
691 if(partcount >= partlength)
695 dir = random_turn(random, dir);
697 partlength = random.range(1,length);
700 if(random.next()%2 == 0 && partlength >= 3)
701 make_stairs = random.next()%2 ? 1 : -1;
712 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
713 INodeDefManager *ndef):
724 m_dir = rand_ortho_dir(m_random);
727 void setPos(v3s16 pos)
732 void setDir(v3s16 dir)
737 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
739 for(u32 i=0; i<100; i++)
741 v3s16 p = m_pos + m_dir;
742 v3s16 p1 = p + v3s16(0,1,0);
743 if(vmanip.m_area.contains(p) == false
744 || vmanip.m_area.contains(p1) == false
750 if(vmanip.getNodeNoExNoEmerge(p).getContent()
751 == LEGN(m_ndef, "CONTENT_COBBLE")
752 && vmanip.getNodeNoExNoEmerge(p1).getContent()
753 == LEGN(m_ndef, "CONTENT_COBBLE"))
755 // Found wall, this is a good place!
758 // Randomize next direction
763 Determine where to move next
765 // Jump one up if the actual space is there
766 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
767 == LEGN(m_ndef, "CONTENT_COBBLE")
768 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
769 == LEGN(m_ndef, "CONTENT_AIR")
770 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
771 == LEGN(m_ndef, "CONTENT_AIR"))
773 // Jump one down if the actual space is there
774 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
775 == LEGN(m_ndef, "CONTENT_COBBLE")
776 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
777 == LEGN(m_ndef, "CONTENT_AIR")
778 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
779 == LEGN(m_ndef, "CONTENT_AIR"))
781 // Check if walking is now possible
782 if(vmanip.getNodeNoExNoEmerge(p).getContent()
783 != LEGN(m_ndef, "CONTENT_AIR")
784 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
785 != LEGN(m_ndef, "CONTENT_AIR"))
787 // Cannot continue walking here
797 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
798 v3s16 &result_doordir, v3s16 &result_roomplace)
800 for(s16 trycount=0; trycount<30; trycount++)
804 bool r = findPlaceForDoor(doorplace, doordir);
808 // X east, Z north, Y up
810 if(doordir == v3s16(1,0,0)) // X+
811 roomplace = doorplace +
812 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
813 if(doordir == v3s16(-1,0,0)) // X-
814 roomplace = doorplace +
815 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
816 if(doordir == v3s16(0,0,1)) // Z+
817 roomplace = doorplace +
818 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
819 if(doordir == v3s16(0,0,-1)) // Z-
820 roomplace = doorplace +
821 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
824 if(doordir == v3s16(1,0,0)) // X+
825 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
826 if(doordir == v3s16(-1,0,0)) // X-
827 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
828 if(doordir == v3s16(0,0,1)) // Z+
829 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
830 if(doordir == v3s16(0,0,-1)) // Z-
831 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
836 for(s16 z=1; z<roomsize.Z-1; z++)
837 for(s16 y=1; y<roomsize.Y-1; y++)
838 for(s16 x=1; x<roomsize.X-1; x++)
840 v3s16 p = roomplace + v3s16(x,y,z);
841 if(vmanip.m_area.contains(p) == false)
846 if(vmanip.m_flags[vmanip.m_area.index(p)]
847 & VMANIP_FLAG_DUNGEON_INSIDE)
858 result_doorplace = doorplace;
859 result_doordir = doordir;
860 result_roomplace = roomplace;
867 VoxelManipulator &vmanip;
870 PseudoRandom &m_random;
871 INodeDefManager *m_ndef;
874 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
875 INodeDefManager *ndef)
877 v3s16 areasize = vmanip.m_area.getExtent();
882 Find place for first room
885 for(u32 i=0; i<100; i++)
887 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
888 roomplace = vmanip.m_area.MinEdge + v3s16(
889 random.range(0,areasize.X-roomsize.X-1),
890 random.range(0,areasize.Y-roomsize.Y-1),
891 random.range(0,areasize.Z-roomsize.Z-1));
893 Check that we're not putting the room to an unknown place,
894 otherwise it might end up floating in the air
897 for(s16 z=1; z<roomsize.Z-1; z++)
898 for(s16 y=1; y<roomsize.Y-1; y++)
899 for(s16 x=1; x<roomsize.X-1; x++)
901 v3s16 p = roomplace + v3s16(x,y,z);
902 u32 vi = vmanip.m_area.index(p);
903 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
908 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
922 Stores the center position of the last room made, so that
923 a new corridor can be started from the last room instead of
924 the new room, if chosen so.
926 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
928 u32 room_count = random.range(2,7);
929 for(u32 i=0; i<room_count; i++)
931 // Make a room to the determined place
932 make_room1(vmanip, roomsize, roomplace, ndef);
934 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
936 // Place torch at room center (for testing)
937 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(LEGN(ndef, "CONTENT_TORCH"));
940 if(i == room_count-1)
943 // Determine walker start position
945 bool start_in_last_room = (random.range(0,2)!=0);
946 //bool start_in_last_room = true;
948 v3s16 walker_start_place;
950 if(start_in_last_room)
952 walker_start_place = last_room_center;
956 walker_start_place = room_center;
957 // Store center of current room as the last one
958 last_room_center = room_center;
961 // Create walker and find a place for a door
962 RoomWalker walker(vmanip, walker_start_place, random, ndef);
965 bool r = walker.findPlaceForDoor(doorplace, doordir);
969 if(random.range(0,1)==0)
971 make_door1(vmanip, doorplace, doordir, ndef);
973 // Don't actually make a door
974 doorplace -= doordir;
976 // Make a random corridor starting from the door
978 v3s16 corridor_end_dir;
979 make_corridor(vmanip, doorplace, doordir, corridor_end,
980 corridor_end_dir, random, ndef);
982 // Find a place for a random sized room
983 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
984 walker.setPos(corridor_end);
985 walker.setDir(corridor_end_dir);
986 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
990 if(random.range(0,1)==0)
992 make_door1(vmanip, doorplace, doordir, ndef);
994 // Don't actually make a door
995 roomplace -= doordir;
1000 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
1001 INodeDefManager *ndef)
1005 s32 r = random.range(0, 3);
1007 dir = v3s16( 1, 0, 0);
1011 dir = v3s16(-1, 0, 0);
1015 dir = v3s16( 0, 0, 1);
1019 dir = v3s16( 0, 0,-1);
1022 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1023 16+random.range(0,15),
1024 16+random.range(0,15),
1025 16+random.range(0,15));
1026 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC"), facedir_i);
1027 u32 length = random.range(3,15);
1028 for(u32 j=0; j<length; j++)
1031 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(LEGN(ndef, "CONTENT_NC_RB"));
1036 Noise functions. Make sure seed is mangled differently in each one.
1040 Scaling the output of the noise function affects the overdrive of the
1041 contour function, which affects the shape of the output considerably.
1043 #define CAVE_NOISE_SCALE 12.0
1044 //#define CAVE_NOISE_SCALE 10.0
1045 //#define CAVE_NOISE_SCALE 7.5
1046 //#define CAVE_NOISE_SCALE 5.0
1047 //#define CAVE_NOISE_SCALE 1.0
1049 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1050 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1052 NoiseParams get_cave_noise1_params(u64 seed)
1054 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1055 200, CAVE_NOISE_SCALE);*/
1056 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1057 100, CAVE_NOISE_SCALE);*/
1058 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1059 100, CAVE_NOISE_SCALE);*/
1060 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1061 100, CAVE_NOISE_SCALE);*/
1062 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1063 50, CAVE_NOISE_SCALE);
1064 //return NoiseParams(NOISE_CONSTANT_ONE);
1067 NoiseParams get_cave_noise2_params(u64 seed)
1069 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1070 200, CAVE_NOISE_SCALE);*/
1071 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1072 100, CAVE_NOISE_SCALE);*/
1073 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1074 100, CAVE_NOISE_SCALE);*/
1075 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1076 50, CAVE_NOISE_SCALE);
1077 //return NoiseParams(NOISE_CONSTANT_ONE);
1080 NoiseParams get_ground_noise1_params(u64 seed)
1082 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1086 NoiseParams get_ground_crumbleness_params(u64 seed)
1088 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1092 NoiseParams get_ground_wetness_params(u64 seed)
1094 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1098 bool is_cave(u64 seed, v3s16 p)
1100 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1101 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1102 return d1*d2 > CAVE_NOISE_THRESHOLD;
1106 Ground density noise shall be interpreted by using this.
1108 TODO: No perlin noises here, they should be outsourced
1110 NOTE: The speed of these actually isn't terrible
1112 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1114 //return ((double)p.Y < ground_noise1_val);
1116 double f = 0.55 + noise2d_perlin(
1117 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1118 seed+920381, 3, 0.45);
1123 double h = WATER_LEVEL + 10 * noise2d_perlin(
1124 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1125 seed+84174, 4, 0.5);
1128 return ((double)p.Y - h < ground_noise1_val * f);
1132 Queries whether a position is ground or not.
1134 bool is_ground(u64 seed, v3s16 p)
1136 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1137 return val_is_ground(val1, p, seed);
1140 // Amount of trees per area in nodes
1141 double tree_amount_2d(u64 seed, v2s16 p)
1143 /*double noise = noise2d_perlin(
1144 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1146 double noise = noise2d_perlin(
1147 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1149 double zeroval = -0.39;
1153 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1156 double surface_humidity_2d(u64 seed, v2s16 p)
1158 double noise = noise2d_perlin(
1159 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1160 seed+72384, 4, 0.66);
1161 noise = (noise + 1.0)/2.0;
1170 double randomstone_amount_2d(u64 seed, v2s16 p)
1172 double noise = noise2d_perlin(
1173 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1174 seed+3829434, 5, 0.66);
1175 double zeroval = 0.1;
1179 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1183 double largestone_amount_2d(u64 seed, v2s16 p)
1185 double noise = noise2d_perlin(
1186 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1187 seed+14143242, 5, 0.66);
1188 double zeroval = 0.3;
1192 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1196 Incrementally find ground level from 3d noise
1198 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1200 // Start a bit fuzzy to make averaging lower precision values
1202 s16 level = myrand_range(-precision/2, precision/2);
1203 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1205 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1207 // First find non-ground by going upwards
1208 // Don't stop in caves.
1210 s16 max = level+dec[i-1]*2;
1211 v3s16 p(p2d.X, level, p2d.Y);
1212 for(; p.Y < max; p.Y += dec[i])
1214 if(!is_ground(seed, p))
1221 // Then find ground by going downwards from there.
1222 // Go in caves, too, when precision is 1.
1224 s16 min = level-dec[i-1]*2;
1225 v3s16 p(p2d.X, level, p2d.Y);
1226 for(; p.Y>min; p.Y-=dec[i])
1228 bool ground = is_ground(seed, p);
1229 /*if(dec[i] == 1 && is_cave(seed, p))
1240 // This is more like the actual ground level
1241 level += dec[i-1]/2;
1246 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1248 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1250 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1251 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1253 a += find_ground_level_from_noise(seed,
1254 v2s16(node_min.X, node_min.Y), p);
1255 a += find_ground_level_from_noise(seed,
1256 v2s16(node_min.X, node_max.Y), p);
1257 a += find_ground_level_from_noise(seed,
1258 v2s16(node_max.X, node_max.Y), p);
1259 a += find_ground_level_from_noise(seed,
1260 v2s16(node_max.X, node_min.Y), p);
1261 a += find_ground_level_from_noise(seed,
1262 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1267 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1269 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1271 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1272 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1275 a = MYMAX(a, find_ground_level_from_noise(seed,
1276 v2s16(node_min.X, node_min.Y), p));
1277 a = MYMAX(a, find_ground_level_from_noise(seed,
1278 v2s16(node_min.X, node_max.Y), p));
1279 a = MYMAX(a, find_ground_level_from_noise(seed,
1280 v2s16(node_max.X, node_max.Y), p));
1281 a = MYMAX(a, find_ground_level_from_noise(seed,
1282 v2s16(node_min.X, node_min.Y), p));
1284 a = MYMAX(a, find_ground_level_from_noise(seed,
1285 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1286 // Side middle points
1287 a = MYMAX(a, find_ground_level_from_noise(seed,
1288 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1289 a = MYMAX(a, find_ground_level_from_noise(seed,
1290 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1291 a = MYMAX(a, find_ground_level_from_noise(seed,
1292 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1293 a = MYMAX(a, find_ground_level_from_noise(seed,
1294 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1298 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1300 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1302 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1303 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1306 a = MYMIN(a, find_ground_level_from_noise(seed,
1307 v2s16(node_min.X, node_min.Y), p));
1308 a = MYMIN(a, find_ground_level_from_noise(seed,
1309 v2s16(node_min.X, node_max.Y), p));
1310 a = MYMIN(a, find_ground_level_from_noise(seed,
1311 v2s16(node_max.X, node_max.Y), p));
1312 a = MYMIN(a, find_ground_level_from_noise(seed,
1313 v2s16(node_min.X, node_min.Y), p));
1315 a = MYMIN(a, find_ground_level_from_noise(seed,
1316 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1317 // Side middle points
1318 a = MYMIN(a, find_ground_level_from_noise(seed,
1319 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1320 a = MYMIN(a, find_ground_level_from_noise(seed,
1321 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1322 a = MYMIN(a, find_ground_level_from_noise(seed,
1323 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1324 a = MYMIN(a, find_ground_level_from_noise(seed,
1325 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1329 bool block_is_underground(u64 seed, v3s16 blockpos)
1331 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1332 seed, v2s16(blockpos.X, blockpos.Z));
1334 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1341 #define AVERAGE_MUD_AMOUNT 4
1343 double base_rock_level_2d(u64 seed, v2s16 p)
1345 // The base ground level
1346 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1347 + 20. * noise2d_perlin(
1348 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1349 (seed>>32)+654879876, 6, 0.6);
1351 /*// A bit hillier one
1352 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1353 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1354 (seed>>27)+90340, 6, 0.69);
1358 // Higher ground level
1359 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1360 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1361 seed+85039, 5, 0.69);
1362 //higher = 30; // For debugging
1364 // Limit higher to at least base
1368 // Steepness factor of cliffs
1369 double b = 1.0 + 1.0 * noise2d_perlin(
1370 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1372 b = rangelim(b, 0.0, 1000.0);
1375 b = rangelim(b, 3.0, 1000.0);
1376 //dstream<<"b="<<b<<std::endl;
1379 // Offset to more low
1380 double a_off = -0.2;
1381 // High/low selector
1382 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1383 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1384 seed-359, 6, 0.7));*/
1385 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1386 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1387 seed-359, 5, 0.60));
1389 a = rangelim(a, 0.0, 1.0);
1391 //dstream<<"a="<<a<<std::endl;
1393 double h = base*(1.0-a) + higher*a;
1400 double get_mud_add_amount(u64 seed, v2s16 p)
1402 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1403 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1404 seed+91013, 3, 0.55));
1408 bool get_have_sand(u64 seed, v2s16 p2d)
1410 // Determine whether to have sand here
1411 double sandnoise = noise2d_perlin(
1412 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1413 seed+59420, 3, 0.50);
1415 return (sandnoise > -0.15);
1418 void make_block(BlockMakeData *data)
1422 //dstream<<"makeBlock: no-op"<<std::endl;
1426 assert(data->vmanip);
1427 assert(data->nodedef);
1428 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1429 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1430 data->blockpos_requested.Z >= data->blockpos_min.Z);
1431 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1432 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1433 data->blockpos_requested.Z <= data->blockpos_max.Z);
1435 INodeDefManager *ndef = data->nodedef;
1437 // Hack: use minimum block coordinates for old code that assumes
1439 v3s16 blockpos = data->blockpos_requested;
1441 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1442 <<blockpos.Z<<")"<<std::endl;*/
1444 v3s16 blockpos_min = data->blockpos_min;
1445 v3s16 blockpos_max = data->blockpos_max;
1446 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1447 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1449 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1450 // Area of center block
1451 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1452 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1453 // Full allocated area
1454 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1455 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1457 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1459 int rel_volume = (blockpos_max.X - blockpos_min.X + 1)
1460 * (blockpos_max.Y - blockpos_min.Y + 1)
1461 * (blockpos_max.Z - blockpos_max.Z + 1);
1463 // Area of the block we are generating
1464 double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1467 Get average ground level from noise
1468 TODO: These are currently crap because they assume we are
1469 dealing with a single MapBlock only. Fix them.
1472 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1473 data->seed, v2s16(blockpos.X, blockpos.Z));
1474 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1476 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1478 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1479 data->seed, v2s16(blockpos.X, blockpos.Z));
1480 // Minimum amount of ground above the top of the central block
1481 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1483 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1484 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1485 // Maximum amount of ground above the bottom of the central block
1486 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1488 // Horribly wrong heuristic, but better than nothing
1489 bool block_is_underground = (minimum_ground_depth >
1490 MAP_BLOCKSIZE * (data->blockpos_max.X
1491 - data->blockpos_min.X + 1) / 2);
1494 If block is deep underground, this is set to true and ground
1495 density noise is not generated, for speed optimization.
1497 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1500 Create a block-specific seed
1502 u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
1503 + full_node_min.Y*42123 + full_node_min.X*23;
1509 //NoiseBuffer noisebuf1;
1510 //NoiseBuffer noisebuf2;
1511 NoiseBuffer noisebuf_cave;
1512 NoiseBuffer noisebuf_ground;
1513 NoiseBuffer noisebuf_ground_crumbleness;
1514 NoiseBuffer noisebuf_ground_wetness;
1516 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1517 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1519 //TimeTaker timer("noisebuf.create");
1525 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1526 minpos_f.X, minpos_f.Y, minpos_f.Z,
1527 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1529 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1537 v3f sl = v3f(4.0, 4.0, 4.0);
1542 if(all_is_ground_except_caves == false)
1543 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1544 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1545 minpos_f.X, minpos_f.Y, minpos_f.Z,
1546 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1550 Ground property noise
1552 sl = v3f(2.5, 2.5, 2.5);
1553 noisebuf_ground_crumbleness.create(
1554 get_ground_crumbleness_params(data->seed),
1555 minpos_f.X, minpos_f.Y, minpos_f.Z,
1556 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1558 noisebuf_ground_wetness.create(
1559 get_ground_wetness_params(data->seed),
1560 minpos_f.X, minpos_f.Y, minpos_f.Z,
1561 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1566 Cache some ground type values for speed
1569 // Creates variables c_name=id and n_name=node
1570 #define CONTENT_VARIABLE(ndef, name)\
1571 content_t c_##name = ndef->getId(#name);\
1572 MapNode n_##name(c_##name);
1574 CONTENT_VARIABLE(ndef, stone);
1575 CONTENT_VARIABLE(ndef, air);
1576 CONTENT_VARIABLE(ndef, water_source);
1577 CONTENT_VARIABLE(ndef, dirt);
1578 CONTENT_VARIABLE(ndef, sand);
1579 CONTENT_VARIABLE(ndef, gravel);
1580 CONTENT_VARIABLE(ndef, clay);
1581 CONTENT_VARIABLE(ndef, lava_source);
1582 CONTENT_VARIABLE(ndef, cobble);
1583 CONTENT_VARIABLE(ndef, mossycobble);
1584 CONTENT_VARIABLE(ndef, dirt_with_grass);
1585 CONTENT_VARIABLE(ndef, junglegrass);
1586 CONTENT_VARIABLE(ndef, stone_with_coal);
1587 CONTENT_VARIABLE(ndef, stone_with_iron);
1588 CONTENT_VARIABLE(ndef, mese);
1591 Make base ground level
1594 for(s16 x=node_min.X; x<=node_max.X; x++)
1595 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1600 // Use fast index incrementing
1601 v3s16 em = vmanip.m_area.getExtent();
1602 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1603 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1605 // Only modify places that have no content
1606 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1608 // First priority: make air and water.
1609 // This avoids caves inside water.
1610 if(all_is_ground_except_caves == false
1611 && val_is_ground(noisebuf_ground.get(x,y,z),
1612 v3s16(x,y,z), data->seed) == false)
1614 if(y <= WATER_LEVEL)
1615 vmanip.m_data[i] = n_water_source;
1617 vmanip.m_data[i] = n_air;
1619 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1620 vmanip.m_data[i] = n_air;
1622 vmanip.m_data[i] = n_stone;
1625 data->vmanip->m_area.add_y(em, i, 1);
1631 Add mud and sand and others underground (in place of stone)
1634 for(s16 x=node_min.X; x<=node_max.X; x++)
1635 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1640 // Use fast index incrementing
1641 v3s16 em = vmanip.m_area.getExtent();
1642 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1643 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1645 if(vmanip.m_data[i].getContent() == c_stone)
1647 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1649 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1650 vmanip.m_data[i] = n_dirt;
1652 vmanip.m_data[i] = n_sand;
1654 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1656 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1657 vmanip.m_data[i] = n_gravel;
1659 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1660 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1662 vmanip.m_data[i] = n_lava_source;
1663 for(s16 x1=-1; x1<=1; x1++)
1664 for(s16 y1=-1; y1<=1; y1++)
1665 for(s16 z1=-1; z1<=1; z1++)
1666 data->transforming_liquid.push_back(
1667 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1671 data->vmanip->m_area.add_y(em, i, -1);
1680 //if(node_min.Y < approx_groundlevel)
1681 //if(myrand() % 3 == 0)
1682 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1683 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1684 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1685 float dungeon_rarity = 0.02;
1686 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1688 && node_min.Y < approx_groundlevel)
1690 // Dungeon generator doesn't modify places which have this set
1691 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1692 | VMANIP_FLAG_DUNGEON_PRESERVE);
1694 // Set all air and water to be untouchable to make dungeons open
1695 // to caves and open air
1696 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1697 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1702 // Use fast index incrementing
1703 v3s16 em = vmanip.m_area.getExtent();
1704 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1705 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1707 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1708 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1709 else if(vmanip.m_data[i].getContent() == c_water_source)
1710 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1711 data->vmanip->m_area.add_y(em, i, -1);
1716 PseudoRandom random(blockseed+2);
1719 make_dungeon1(vmanip, random, ndef);
1721 // Convert some cobble to mossy cobble
1722 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1723 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1728 // Use fast index incrementing
1729 v3s16 em = vmanip.m_area.getExtent();
1730 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1731 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1733 // (noisebuf not used because it doesn't contain the
1735 double wetness = noise3d_param(
1736 get_ground_wetness_params(data->seed), x,y,z);
1737 double d = noise3d_perlin((float)x/2.5,
1738 (float)y/2.5,(float)z/2.5,
1740 if(vmanip.m_data[i].getContent() == c_cobble)
1744 vmanip.m_data[i].setContent(c_mossycobble);
1747 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1750 vmanip.m_data[i].setContent(c_dirt);
1752 data->vmanip->m_area.add_y(em, i, -1);
1762 PseudoRandom ncrandom(blockseed+9324342);
1763 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1765 make_nc(vmanip, ncrandom, ndef);
1770 Add top and bottom side of water to transforming_liquid queue
1773 for(s16 x=node_min.X; x<=node_max.X; x++)
1774 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1779 bool water_found = false;
1780 // Use fast index incrementing
1781 v3s16 em = vmanip.m_area.getExtent();
1782 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1783 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1785 if(water_found == false)
1787 if(vmanip.m_data[i].getContent() == c_water_source)
1789 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1790 data->transforming_liquid.push_back(p);
1796 // This can be done because water_found can only
1797 // turn to true and end up here after going through
1799 if(vmanip.m_data[i+1].getContent() != c_water_source)
1801 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1802 data->transforming_liquid.push_back(p);
1803 water_found = false;
1807 data->vmanip->m_area.add_y(em, i, -1);
1813 If close to ground level
1816 //if(abs(approx_ground_depth) < 30)
1817 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1823 for(s16 x=node_min.X; x<=node_max.X; x++)
1824 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1829 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1830 bool have_sand = false;
1831 u32 current_depth = 0;
1832 bool air_detected = false;
1833 bool water_detected = false;
1834 bool have_clay = false;
1836 // Use fast index incrementing
1837 s16 start_y = node_max.Y+2;
1838 v3s16 em = vmanip.m_area.getExtent();
1839 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1840 for(s16 y=start_y; y>=node_min.Y-3; y--)
1842 if(vmanip.m_data[i].getContent() == c_water_source)
1843 water_detected = true;
1844 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1845 air_detected = true;
1847 if((vmanip.m_data[i].getContent() == c_stone
1848 || vmanip.m_data[i].getContent() == c_dirt_with_grass
1849 || vmanip.m_data[i].getContent() == c_dirt
1850 || vmanip.m_data[i].getContent() == c_sand
1851 || vmanip.m_data[i].getContent() == c_gravel
1852 ) && (air_detected || water_detected))
1854 if(current_depth == 0 && y <= WATER_LEVEL+2
1855 && possibly_have_sand)
1858 if(current_depth < 4)
1862 // Determine whether to have clay in the sand here
1863 double claynoise = noise2d_perlin(
1864 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1865 data->seed+4321, 6, 0.95) + 0.5;
1867 have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
1868 ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
1869 ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
1872 vmanip.m_data[i] = MapNode(c_clay);
1874 vmanip.m_data[i] = MapNode(c_sand);
1877 else if(current_depth==0 && !water_detected
1878 && y >= WATER_LEVEL && air_detected)
1879 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
1882 vmanip.m_data[i] = MapNode(c_dirt);
1886 if(vmanip.m_data[i].getContent() == c_dirt
1887 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
1888 vmanip.m_data[i] = MapNode(c_stone);
1893 if(current_depth >= 8)
1896 else if(current_depth != 0)
1899 data->vmanip->m_area.add_y(em, i, -1);
1905 Calculate some stuff
1908 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
1909 bool is_jungle = surface_humidity > 0.75;
1911 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
1918 PseudoRandom treerandom(blockseed);
1919 // Put trees in random places on part of division
1920 for(u32 i=0; i<tree_count; i++)
1922 s16 x = treerandom.range(node_min.X, node_max.X);
1923 s16 z = treerandom.range(node_min.Z, node_max.Z);
1924 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
1925 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
1926 // Don't make a tree under water level
1929 // Make sure tree fits (only trees whose starting point is
1930 // at this block are added)
1931 if(y < node_min.Y || y > node_max.Y)
1934 Find exact ground level
1938 for(; p.Y >= y-6; p.Y--)
1940 u32 i = data->vmanip->m_area.index(p);
1941 MapNode *n = &data->vmanip->m_data[i];
1942 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
1948 // If not found, handle next one
1953 u32 i = data->vmanip->m_area.index(p);
1954 MapNode *n = &data->vmanip->m_data[i];
1956 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
1959 // Papyrus grows only on mud and in water
1960 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
1963 make_papyrus(vmanip, p, ndef);
1965 // Trees grow only on mud and grass, on land
1966 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
1969 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
1970 if(is_jungle == false)
1973 if(myrand_range(0,4) != 0)
1974 is_apple_tree = false;
1976 is_apple_tree = noise2d_perlin(
1977 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
1978 data->seed+342902, 3, 0.45) > 0.2;
1979 make_tree(vmanip, p, is_apple_tree, ndef);
1982 make_jungletree(vmanip, p, ndef);
1984 // Cactii grow only on sand, on land
1985 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
1988 make_cactus(vmanip, p, ndef);
1998 PseudoRandom grassrandom(blockseed);
1999 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2001 s16 x = grassrandom.range(node_min.X, node_max.X);
2002 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2003 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2006 if(y < node_min.Y || y > node_max.Y)
2009 Find exact ground level
2013 for(; p.Y >= y-6; p.Y--)
2015 u32 i = data->vmanip->m_area.index(p);
2016 MapNode *n = &data->vmanip->m_data[i];
2017 if(data->nodedef->get(*n).is_ground_content)
2023 // If not found, handle next one
2027 if(vmanip.m_area.contains(p) == false)
2029 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2032 if(vmanip.m_area.contains(p))
2033 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2035 if(vmanip.m_area.contains(p))
2036 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2042 Add some kind of random stones
2045 u32 random_stone_count = gen_area_nodes *
2046 randomstone_amount_2d(data->seed, p2d_center);
2047 // Put in random places on part of division
2048 for(u32 i=0; i<random_stone_count; i++)
2050 s16 x = myrand_range(node_min.X, node_max.X);
2051 s16 z = myrand_range(node_min.Z, node_max.Z);
2052 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2053 // Don't add under water level
2054 /*if(y < WATER_LEVEL)
2056 // Don't add if doesn't belong to this block
2057 if(y < node_min.Y || y > node_max.Y)
2062 u32 i = data->vmanip->m_area.index(v3s16(p));
2063 MapNode *n = &data->vmanip->m_data[i];
2064 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2067 // Will be placed one higher
2070 make_randomstone(data->vmanip, p);
2079 u32 large_stone_count = gen_area_nodes *
2080 largestone_amount_2d(data->seed, p2d_center);
2081 //u32 large_stone_count = 1;
2082 // Put in random places on part of division
2083 for(u32 i=0; i<large_stone_count; i++)
2085 s16 x = myrand_range(node_min.X, node_max.X);
2086 s16 z = myrand_range(node_min.Z, node_max.Z);
2087 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2088 // Don't add under water level
2089 /*if(y < WATER_LEVEL)
2091 // Don't add if doesn't belong to this block
2092 if(y < node_min.Y || y > node_max.Y)
2097 u32 i = data->vmanip->m_area.index(v3s16(p));
2098 MapNode *n = &data->vmanip->m_data[i];
2099 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2102 // Will be placed one lower
2105 make_largestone(data->vmanip, p);
2115 PseudoRandom mineralrandom(blockseed);
2120 for(s16 i=0; i<approx_ground_depth/4; i++)
2122 if(mineralrandom.next()%50 == 0)
2124 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2125 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2126 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2127 for(u16 i=0; i<27; i++)
2129 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2130 u32 vi = vmanip.m_area.index(p);
2131 if(vmanip.m_data[vi].getContent() == c_stone)
2132 if(mineralrandom.next()%8 == 0)
2133 vmanip.m_data[vi] = MapNode(c_mese);
2142 u16 a = mineralrandom.range(0,15);
2144 u16 amount = 20 * a/1000;
2145 for(s16 i=0; i<amount; i++)
2147 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2148 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2149 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2151 u8 base_content = c_stone;
2152 MapNode new_content(CONTENT_IGNORE);
2155 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2157 new_content = MapNode(c_stone_with_coal);
2161 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2162 new_content = MapNode(c_stone_with_iron);
2163 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2164 vmanip.m_data[i] = MapNode(c_dirt);
2166 vmanip.m_data[i] = MapNode(c_sand);*/
2168 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2172 if(new_content.getContent() != CONTENT_IGNORE)
2174 for(u16 i=0; i<27; i++)
2176 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2177 u32 vi = vmanip.m_area.index(p);
2178 if(vmanip.m_data[vi].getContent() == base_content)
2180 if(mineralrandom.next()%sparseness == 0)
2181 vmanip.m_data[vi] = new_content;
2190 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2191 //for(s16 i=0; i<50; i++)
2192 u16 coal_amount = 30;
2193 u16 coal_rareness = 60 / coal_amount;
2194 if(coal_rareness == 0)
2196 if(mineralrandom.next()%coal_rareness == 0)
2198 u16 a = mineralrandom.next() % 16;
2199 u16 amount = coal_amount * a*a*a / 1000;
2200 for(s16 i=0; i<amount; i++)
2202 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2203 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2204 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2205 for(u16 i=0; i<27; i++)
2207 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2208 u32 vi = vmanip.m_area.index(p);
2209 if(vmanip.m_data[vi].getContent() == c_stone)
2210 if(mineralrandom.next()%8 == 0)
2211 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2218 u16 iron_amount = 8;
2219 u16 iron_rareness = 60 / iron_amount;
2220 if(iron_rareness == 0)
2222 if(mineralrandom.next()%iron_rareness == 0)
2224 u16 a = mineralrandom.next() % 16;
2225 u16 amount = iron_amount * a*a*a / 1000;
2226 for(s16 i=0; i<amount; i++)
2228 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2229 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2230 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2231 for(u16 i=0; i<27; i++)
2233 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2234 u32 vi = vmanip.m_area.index(p);
2235 if(vmanip.m_data[vi].getContent() == c_stone)
2236 if(mineralrandom.next()%8 == 0)
2237 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2247 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2249 VoxelArea a(node_min, node_max);
2250 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2251 for(int i=0; i<2; i++)
2253 enum LightBank bank = banks[i];
2255 core::map<v3s16, bool> light_sources;
2256 core::map<v3s16, u8> unlight_from;
2258 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2259 light_sources, unlight_from);
2261 bool inexistent_top_provides_sunlight = !block_is_underground;
2262 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2263 vmanip, a, inexistent_top_provides_sunlight,
2264 light_sources, ndef);
2265 // TODO: Do stuff according to bottom_sunlight_valid
2267 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2269 vmanip.spreadLight(bank, light_sources, ndef);
2274 BlockMakeData::BlockMakeData():
2281 BlockMakeData::~BlockMakeData()
2286 }; // namespace mapgen