void MapgenV6::placeTreesAndJungleGrass() { //TimeTaker t("placeTrees"); PseudoRandom grassrandom(blockseed + 53); content_t c_sand = ndef->getId("mapgen_sand"); content_t c_junglegrass = ndef->getId("mapgen_junglegrass"); // if we don't have junglegrass, don't place cignore... that's bad if (c_junglegrass == CONTENT_IGNORE) c_junglegrass = CONTENT_AIR; MapNode n_junglegrass(c_junglegrass); v3s16 em = vm->m_area.getExtent(); // Divide area into parts s16 div = 8; s16 sidelen = central_area_size.X / div; double area = sidelen * sidelen; // N.B. We must add jungle grass first, since tree leaves will // obstruct the ground, giving us a false ground level for (s16 z0 = 0; z0 < div; z0++) for (s16 x0 = 0; x0 < div; x0++) { // Center position of part of division v2s16 p2d_center( node_min.X + sidelen / 2 + sidelen * x0, node_min.Z + sidelen / 2 + sidelen * z0 ); // Minimum edge of part of division v2s16 p2d_min( node_min.X + sidelen * x0, node_min.Z + sidelen * z0 ); // Maximum edge of part of division v2s16 p2d_max( node_min.X + sidelen + sidelen * x0 - 1, node_min.Z + sidelen + sidelen * z0 - 1 ); // Get biome at center position of part of division BiomeV6Type bt = getBiome(v3POS(p2d_center.X, node_min.Y, p2d_center.Y)); // Amount of trees float humidity = getHumidity(v3POS(p2d_center.X, node_max.Y, p2d_center.Y)); s32 tree_count; if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) { tree_count = area * getTreeAmount(p2d_center) * ((humidity + 1)/2.0); if (bt == BT_JUNGLE) tree_count *= 4; } else { tree_count = 0; } if (node_max.Y < water_level) tree_count /= 2; // Add jungle grass if (bt == BT_JUNGLE) { u32 grass_count = 5 * humidity * tree_count; for (u32 i = 0; i < grass_count; i++) { s16 x = grassrandom.range(p2d_min.X, p2d_max.X); s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y); /* wtf int mapindex = central_area_size.X * (z - node_min.Z) + (x - node_min.X); s16 y = heightmap[mapindex]; */ s16 y = findGroundLevelFull(v2s16(x, z)); if (y < water_level) continue; u32 vi = vm->m_area.index(x, y, z); // place on dirt_with_grass, since we know it is exposed to sunlight if (vm->m_data[vi].getContent() == c_dirt_with_grass) { vm->m_area.add_y(em, vi, 1); vm->m_data[vi] = n_junglegrass; } } } // Put trees in random places on part of division for (s32 i = 0; i < tree_count; i++) { s16 x = myrand_range(p2d_min.X, p2d_max.X); s16 z = myrand_range(p2d_min.Y, p2d_max.Y); /* wtf int mapindex = central_area_size.X * (z - node_min.Z) + (x - node_min.X); s16 y = heightmap[mapindex]; */ s16 y = findGroundLevelFull(v2s16(x, z)); // Don't make a tree under water level // Don't make a tree so high that it doesn't fit if (y > node_max.Y - 6) continue; v3s16 p(x, y, z); // Trees grow only on mud and grass and snowblock { u32 i = vm->m_area.index(p); content_t c = vm->m_data[i].getContent(); if (c != c_dirt && c != c_dirt_with_grass && c != c_dirt_with_snow && c != c_snowblock && (y >= water_level || c != c_sand)) continue; } p.Y++; // Make a tree if (y < water_level) { if (y < water_level - 20) // do not spawn trees in lakes treegen::make_cavetree(*vm, p, bt == BT_JUNGLE, ndef, myrand()); } else if (bt == BT_JUNGLE) { treegen::make_jungletree(*vm, p, ndef, myrand()); } else if (bt == BT_TAIGA) { treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand()); } else if (bt == BT_NORMAL) { bool is_apple_tree = (myrand_range(0, 3) == 0) && getHaveAppleTree(v2s16(x, z)); treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand()); } } } //printf("placeTreesAndJungleGrass: %dms\n", t.stop()); }
size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { PseudoRandom ps(blockseed + 53); int carea_size = nmax.X - nmin.X + 1; // Divide area into parts if (carea_size % sidelen) { errorstream << "Decoration::placeDeco: chunk size is not divisible by " "sidelen; setting sidelen to " << carea_size << std::endl; sidelen = carea_size; } s16 divlen = carea_size / sidelen; int area = sidelen * sidelen; for (s16 z0 = 0; z0 < divlen; z0++) for (s16 x0 = 0; x0 < divlen; x0++) { v2s16 p2d_center( // Center position of part of division nmin.X + sidelen / 2 + sidelen * x0, nmin.Z + sidelen / 2 + sidelen * z0 ); v2s16 p2d_min( // Minimum edge of part of division nmin.X + sidelen * x0, nmin.Z + sidelen * z0 ); v2s16 p2d_max( // Maximum edge of part of division nmin.X + sidelen + sidelen * x0 - 1, nmin.Z + sidelen + sidelen * z0 - 1 ); // Amount of decorations float nval = (flags & DECO_USE_NOISE) ? NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) : fill_ratio; u32 deco_count = area * MYMAX(nval, 0.f); for (u32 i = 0; i < deco_count; i++) { s16 x = ps.range(p2d_min.X, p2d_max.X); s16 z = ps.range(p2d_min.Y, p2d_max.Y); int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X); s16 y = mg->heightmap ? mg->heightmap[mapindex] : mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); if (y < nmin.Y || y > nmax.Y || y < y_min || y > y_max) continue; if (y + getHeight() >= mg->vm->m_area.MaxEdge.Y) { continue; #if 0 printf("Decoration at (%d %d %d) cut off\n", x, y, z); //add to queue JMutexAutoLock cutofflock(cutoff_mutex); cutoffs.push_back(CutoffData(x, y, z, height)); #endif } if (mg->biomemap) { std::set<u8>::iterator iter; if (!biomes.empty()) { iter = biomes.find(mg->biomemap[mapindex]); if (iter == biomes.end()) continue; } } v3s16 pos(x, y, z); if (generate(mg->vm, &ps, pos)) mg->gennotify.addEvent(GENNOTIFY_DECORATION, pos, index); } } return 0; }
void MapgenV6::placeTreesAndJungleGrass() { //TimeTaker t("placeTrees"); PseudoRandom grassrandom(blockseed + 53); content_t c_sand = ndef->getId("mapgen_sand"); content_t c_junglegrass = ndef->getId("mapgen_junglegrass"); // if we don't have junglegrass, don't place cignore... that's bad if (c_junglegrass == CONTENT_IGNORE) c_junglegrass = CONTENT_AIR; MapNode n_junglegrass(c_junglegrass); v3s16 em = vm->m_area.getExtent(); // Divide area into parts s16 div = 8; s16 sidelen = central_area_size.X / div; double area = sidelen * sidelen; // N.B. We must add jungle grass first, since tree leaves will // obstruct the ground, giving us a false ground level for (s16 z0 = 0; z0 < div; z0++) for (s16 x0 = 0; x0 < div; x0++) { // Center position of part of division v2s16 p2d_center( node_min.X + sidelen / 2 + sidelen * x0, node_min.Z + sidelen / 2 + sidelen * z0 ); // Minimum edge of part of division v2s16 p2d_min( node_min.X + sidelen * x0, node_min.Z + sidelen * z0 ); // Maximum edge of part of division v2s16 p2d_max( node_min.X + sidelen + sidelen * x0 - 1, node_min.Z + sidelen + sidelen * z0 - 1 ); // Amount of trees, jungle area u32 tree_count = area * getTreeAmount(p2d_center); float humidity = 0; bool is_jungle = false; if (flags & MGV6_JUNGLES) { humidity = getHumidity(p2d_center); if (humidity > 0.75) { is_jungle = true; tree_count *= 4; } } if (node_max.Y < water_level) tree_count /= 2; // Add jungle grass if (is_jungle) { u32 grass_count = 5 * humidity * tree_count; for (u32 i = 0; i < grass_count; i++) { s16 x = grassrandom.range(p2d_min.X, p2d_max.X); s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y); s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////optimize this! if (y < water_level || y < node_min.Y || y > node_max.Y) continue; u32 vi = vm->m_area.index(x, y, z); // place on dirt_with_grass, since we know it is exposed to sunlight if (vm->m_data[vi].getContent() == c_dirt_with_grass) { vm->m_area.add_y(em, vi, 1); vm->m_data[vi] = n_junglegrass; } } } // Put trees in random places on part of division for (u32 i = 0; i < tree_count; i++) { s16 x = myrand_range(p2d_min.X, p2d_max.X); s16 z = myrand_range(p2d_min.Y, p2d_max.Y); s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////////optimize this! // Don't make a tree under water level // Don't make a tree so high that it doesn't fit if(y > node_max.Y - 6) continue; v3s16 p(x,y,z); // Trees grow only on mud and grass { u32 i = vm->m_area.index(p); MapNode *n = &vm->m_data[i]; if (n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && (y >= water_level || n->getContent() != c_sand)) continue; } p.Y++; // Make a tree if (y < water_level) { if (y < water_level - 20) // do not spawn trees in lakes treegen::make_cavetree(*vm, p, is_jungle, ndef, myrand()); } else if (is_jungle) { treegen::make_jungletree(*vm, p, ndef, myrand()); } else { bool is_apple_tree = (myrand_range(0, 3) == 0) && getHaveAppleTree(v2s16(x, z)); treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand()); } } } //printf("placeTreesAndJungleGrass: %dms\n", t.stop()); }
void Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { PseudoRandom ps(blockseed + 53); int carea_size = nmax.X - nmin.X + 1; // Divide area into parts if (carea_size % sidelen) { errorstream << "Decoration::placeDeco: chunk size is not divisible by " "sidelen; setting sidelen to " << carea_size << std::endl; sidelen = carea_size; } s16 divlen = carea_size / sidelen; int area = sidelen * sidelen; for (s16 z0 = 0; z0 < divlen; z0++) for (s16 x0 = 0; x0 < divlen; x0++) { v2s16 p2d_center( // Center position of part of division nmin.X + sidelen / 2 + sidelen * x0, nmin.Z + sidelen / 2 + sidelen * z0 ); v2s16 p2d_min( // Minimum edge of part of division nmin.X + sidelen * x0, nmin.Z + sidelen * z0 ); v2s16 p2d_max( // Maximum edge of part of division nmin.X + sidelen + sidelen * x0 - 1, nmin.Z + sidelen + sidelen * z0 - 1 ); // Amount of decorations float nval = np ? NoisePerlin2D(np, p2d_center.X, p2d_center.Y, mapseed) : fill_ratio; u32 deco_count = area * MYMAX(nval, 0.f); for (u32 i = 0; i < deco_count; i++) { s16 x = ps.range(p2d_min.X, p2d_max.X); s16 z = ps.range(p2d_min.Y, p2d_max.Y); int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X); s16 y = mg->heightmap ? mg->heightmap[mapindex] : mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); if (y < nmin.Y || y > nmax.Y) continue; int height = getHeight(); int max_y = nmax.Y;// + MAP_BLOCKSIZE - 1; if (y + 1 + height > max_y) { continue; #if 0 printf("Decoration at (%d %d %d) cut off\n", x, y, z); //add to queue JMutexAutoLock cutofflock(cutoff_mutex); cutoffs.push_back(CutoffData(x, y, z, height)); #endif } if (mg->biomemap) { std::set<u8>::iterator iter; if (biomes.size()) { iter = biomes.find(mg->biomemap[mapindex]); if (iter == biomes.end()) continue; } } generate(mg, &ps, max_y, v3s16(x, y, z)); } } }
size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { PcgRandom ps(blockseed + 53); int carea_size = nmax.X - nmin.X + 1; // Divide area into parts // If chunksize is changed it may no longer be divisable by sidelen if (carea_size % sidelen) sidelen = carea_size; s16 divlen = carea_size / sidelen; int area = sidelen * sidelen; for (s16 z0 = 0; z0 < divlen; z0++) for (s16 x0 = 0; x0 < divlen; x0++) { v2s16 p2d_center( // Center position of part of division nmin.X + sidelen / 2 + sidelen * x0, nmin.Z + sidelen / 2 + sidelen * z0 ); v2s16 p2d_min( // Minimum edge of part of division nmin.X + sidelen * x0, nmin.Z + sidelen * z0 ); v2s16 p2d_max( // Maximum edge of part of division nmin.X + sidelen + sidelen * x0 - 1, nmin.Z + sidelen + sidelen * z0 - 1 ); // Amount of decorations float nval = (flags & DECO_USE_NOISE) ? NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) : fill_ratio; u32 deco_count = 0; float deco_count_f = (float)area * nval; if (deco_count_f >= 1.f) { deco_count = deco_count_f; } else if (deco_count_f > 0.f) { // For low density decorations calculate a chance for 1 decoration if (ps.range(1000) <= deco_count_f * 1000.f) deco_count = 1; } for (u32 i = 0; i < deco_count; i++) { s16 x = ps.range(p2d_min.X, p2d_max.X); s16 z = ps.range(p2d_min.Y, p2d_max.Y); int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X); s16 y = -MAX_MAP_GENERATION_LIMIT; if (flags & DECO_LIQUID_SURFACE) y = mg->findLiquidSurface(v2s16(x, z), nmin.Y, nmax.Y); else if (mg->heightmap) y = mg->heightmap[mapindex]; else y = mg->findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); if (y < nmin.Y || y > nmax.Y || y < y_min || y > y_max) continue; if (y + getHeight() >= mg->vm->m_area.MaxEdge.Y) { continue; #if 0 printf("Decoration at (%d %d %d) cut off\n", x, y, z); //add to queue MutexAutoLock cutofflock(cutoff_mutex); cutoffs.push_back(CutoffData(x, y, z, height)); #endif } if (mg->biomemap) { std::set<u8>::iterator iter; if (!biomes.empty()) { iter = biomes.find(mg->biomemap[mapindex]); if (iter == biomes.end()) continue; } } v3s16 pos(x, y, z); if (generate(mg->vm, &ps, pos)) mg->gennotify.addEvent(GENNOTIFY_DECORATION, pos, index); } } return 0; }