Minetest源码分析十三:Mapgen

xiaoxiao2021-02-28  108

Minetest源码分析十三:Mapgen

minetest->margen.h   minetest->mapgen_v6.h

Mapgen:真实生成具体的地图。要生成什么样的地图,具体参数都是是这里设置。通过MapgenParams结构来存储传递参数的。

类的实例初始化:

在类EmergeManager中的initMapgens()中创建实例的,在实例的create函数中传入MapgenParams参数。initMapgens()方法只在server对象的构造函数中调用。程序运行过程中,只在开始时调用一次EmergeManager中的initMapgens,也就是开始给emergeThread创建了这个Mapgen对象。

具体方法如下:

void EmergeManager::initMapgens() { if (!params.sparams) { params.sparams = createMapgenParams(params.mg_name); params.sparams->readParams(g_settings); } // Create the mapgens for (u32 i = 0; i != emergethread.size(); i++) { Mapgen *mg = createMapgen(params.mg_name, i, ¶ms); mapgen.push_back(mg); } }

MapgenParamsMapgen类中使用到的参数,这里是定义的一个结构。地图参数存储在map_meta.txt文件中。

struct MapgenParams { std::string mg_name; s16 chunksize; u64 seed; s16 water_level; u32 flags; NoiseParams np_biome_heat; NoiseParams np_biome_humidity; MapgenSpecificParams *sparams; MapgenParams() : mg_name(DEFAULT_MAPGEN), chunksize(5), seed(0), water_level(1), flags(MG_TREES | MG_CAVES | MG_LIGHT), np_biome_heat(NoiseParams(50, 50, v3f(500.0, 500.0, 500.0), 5349, 3, 0.5, 2.0)), np_biome_humidity(NoiseParams(50, 50, v3f(500.0, 500.0, 500.0), 842, 3, 0.5, 2.0)), sparams(NULL) {} void load(const Settings &settings); void save(Settings &settings) const; };

MapgenParams中使用到的相关宏定义

#define MG_TREES         0x01

#define MG_CAVES         0x02

#define MG_DUNGEONS      0x04

#define MG_FLAT          0x08

#define MG_LIGHT         0x10

Mapgen:

主要方法:

void MapgenV6::makeChunk(BlockMakeData *data)

功能:给Block创建的数据结构设置值、填充值。主要是BlockMakeData结构中MMVManip变量设置值,MMVManip实例变量中主要是设置MapNode *m_data这个成员变量值。也就是说makeChunk主要是设置一系列MapNode的data值。

参数:BlockMakeDatainit Block 时创建的数据结构。

调用:一般与initBlockMakefinishBlockMake一起使用,在这两个方法中间调用。主要是EmergeThreadThread()线程函数的循环体中使用,不断获取需要生成的block 位置,然后根据位置进行生成block的数据结构,之后就需要使用makeChunk来设置好block数据结构中该有的数据。

initBlockMake(&data, p);

mapgen->makeChunk(&data);

finishBlockMake(&data, modified_blocks);

函数主要流程:

1.Generate general ground level to full area

2.Make caves (this code is relatively horrible)

3.Add mud to the central chunk

4.Flow mud away from steep edges

5.Add dungeons

6.Add top and bottom side of water to transforming_liquid queue

7.Add surface nodesgrowGrass();

8.Generate some trees, and add grass, if a jungle

9.Generate the registered decorations

10.Generate the registered ores

11.Calculate lighting

void MapgenV6::makeChunk(BlockMakeData *data) { this->generating = true; this->vm = data->vmanip; this->ndef = data->nodedef; // Hack: use minimum block coords for old code that assumes a single block v3s16 blockpos = data->blockpos_requested; v3s16 blockpos_min = data->blockpos_min; v3s16 blockpos_max = data->blockpos_max; // Area of central chunk node_min = blockpos_min * MAP_BLOCKSIZE; node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1); // Full allocated area full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE; full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1); central_area_size = node_max - node_min + v3s16(1, 1, 1); assert(central_area_size.X == central_area_size.Z); int volume_blocks = (blockpos_max.X - blockpos_min.X + 1) * (blockpos_max.Y - blockpos_min.Y + 1) * (blockpos_max.Z - blockpos_max.Z + 1); volume_nodes = volume_blocks * MAP_BLOCKSIZE * MAP_BLOCKSIZE * MAP_BLOCKSIZE; // Create a block-specific seed blockseed = get_blockseed(data->seed, full_node_min); // Make some noise calculateNoise(); // Maximum height of the stone surface and obstacles. // This is used to guide the cave generation s16 stone_surface_max_y; // Generate general ground level to full area stone_surface_max_y = generateGround(); // // Create initial heightmap to limit caves // updateHeightmap(node_min, node_max); const s16 max_spread_amount = MAP_BLOCKSIZE; // Limit dirt flow area by 1 because mud is flown into neighbors. s16 mudflow_minpos = -max_spread_amount + 1; s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2; // Loop this part, it will make stuff look older and newer nicely const u32 age_loops = 2; for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop // Make caves (this code is relatively horrible) // if (flags & MG_CAVES) // generateCaves(stone_surface_max_y); // Add mud to the central chunk addMud(); // Flow mud away from steep edges if (spflags & MGV6_MUDFLOW) flowMud(mudflow_minpos, mudflow_maxpos); } // // // Update heightmap after mudflow // updateHeightmap(node_min, node_max); // Add dungeons if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) { DungeonParams dp; dp.np_rarity = nparams_dungeon_rarity; dp.np_density = nparams_dungeon_density; dp.np_wetness = nparams_dungeon_wetness; dp.c_water = c_water_source; if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) { dp.c_cobble = c_sandbrick; dp.c_moss = c_sandbrick; // should make this 'cracked sandstone' later dp.c_stair = c_stair_sandstone; dp.diagonal_dirs = true; dp.mossratio = 0.0; dp.holesize = v3s16(2, 3, 2); dp.roomsize = v3s16(2, 5, 2); dp.notifytype = GENNOTIFY_TEMPLE; } else { dp.c_cobble = c_cobble; dp.c_moss = c_mossycobble; dp.c_stair = c_stair_cobble; dp.diagonal_dirs = false; dp.mossratio = 3.0; dp.holesize = v3s16(1, 2, 1); dp.roomsize = v3s16(0, 0, 0); dp.notifytype = GENNOTIFY_DUNGEON; } // DungeonGen dgen(this, &dp); // dgen.generate(blockseed, full_node_min, full_node_max); } // Add top and bottom side of water to transforming_liquid queue updateLiquid(&data->transforming_liquid, full_node_min, full_node_max); // // Add surface nodes // growGrass(); // // Generate some trees, and add grass, if a jungle // if (flags & MG_TREES) // placeTreesAndJungleGrass(); // Generate the registered decorations m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max); // Generate the registered ores m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max); // Calculate lighting if (flags & MG_LIGHT) calcLighting(node_min, node_max); this->generating = false; }

参考资料

http://dev.minetest.net/Mapgen

转载请注明原文地址: https://www.6miu.com/read-58621.html

最新回复(0)