// spawn_tree(pos, treedef) int ModApiEnvMod::l_spawn_tree(lua_State *L) { GET_ENV_PTR; v3s16 p0 = read_v3s16(L, 1); treegen::TreeDef tree_def; std::string trunk,leaves,fruit; INodeDefManager *ndef = env->getGameDef()->ndef(); if(lua_istable(L, 2)) { getstringfield(L, 2, "axiom", tree_def.initial_axiom); getstringfield(L, 2, "rules_a", tree_def.rules_a); getstringfield(L, 2, "rules_b", tree_def.rules_b); getstringfield(L, 2, "rules_c", tree_def.rules_c); getstringfield(L, 2, "rules_d", tree_def.rules_d); getstringfield(L, 2, "trunk", trunk); tree_def.trunknode=ndef->getId(trunk); getstringfield(L, 2, "leaves", leaves); tree_def.leavesnode=ndef->getId(leaves); tree_def.leaves2_chance=0; getstringfield(L, 2, "leaves2", leaves); if (leaves !="") { tree_def.leaves2node=ndef->getId(leaves); getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance); } getintfield(L, 2, "angle", tree_def.angle); getintfield(L, 2, "iterations", tree_def.iterations); if (!getintfield(L, 2, "random_level", tree_def.iterations_random_level)) tree_def.iterations_random_level = 0; getstringfield(L, 2, "trunk_type", tree_def.trunk_type); getboolfield(L, 2, "thin_branches", tree_def.thin_branches); tree_def.fruit_chance=0; getstringfield(L, 2, "fruit", fruit); if (fruit != "") { tree_def.fruitnode=ndef->getId(fruit); getintfield(L, 2, "fruit_chance",tree_def.fruit_chance); } tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed); } else return 0; treegen::error e; if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) { if (e == treegen::UNBALANCED_BRACKETS) { luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); } else { luaL_error(L, "spawn_tree(): unknown error"); } } return 1; }
void Mapgen_features::layers_init(EmergeManager *emerge, const Json::Value & paramsj) { const auto & layersj = paramsj["layers"]; INodeDefManager *ndef = emerge->ndef; auto layer_default_thickness = paramsj.get("layer_default_thickness", 1).asInt(); auto layer_thickness_multiplier = paramsj.get("layer_thickness_multiplier", 1).asInt(); if (!layersj.empty()) for (unsigned int i = 0; i < layersj.size(); ++i) { if (layersj[i].empty()) continue; const auto & layerj = layersj[i]; const auto & name = layerj["name"].asString(); if (name.empty()) continue; auto content = ndef->getId(name); if (content == CONTENT_IGNORE) continue; auto layer = layer_data{ content, MapNode(content, layerj["param1"].asInt(), layerj["param2"].asInt()) }; layer.height_min = layerj.get("y_min", layerj.get("height_min", -MAX_MAP_GENERATION_LIMIT).asInt()).asInt(); layer.height_max = layerj.get("y_max", layerj.get("height_max", +MAX_MAP_GENERATION_LIMIT).asInt()).asInt(); layer.thickness = layerj.get("thickness", layer_default_thickness).asInt() * layer_thickness_multiplier; //layer.name = name; //dev layers.emplace_back(layer); } if (layers.empty()) infostream << "layers empty, using only default:stone mg_params="<<paramsj<<std::endl; else verbosestream << "layers size=" << layers.size() << std::endl; }
// spawn_tree(pos, treedef) int ModApiEnvMod::l_spawn_tree(lua_State *L) { GET_ENV_PTR; v3s16 p0 = read_v3s16(L, 1); treegen::TreeDef tree_def; std::string trunk,leaves,fruit; INodeDefManager *ndef = env->getGameDef()->ndef(); if(lua_istable(L, 2)) { getstringfield(L, 2, "axiom", tree_def.initial_axiom); getstringfield(L, 2, "rules_a", tree_def.rules_a); getstringfield(L, 2, "rules_b", tree_def.rules_b); getstringfield(L, 2, "rules_c", tree_def.rules_c); getstringfield(L, 2, "rules_d", tree_def.rules_d); getstringfield(L, 2, "trunk", trunk); tree_def.trunknode=ndef->getId(trunk); getstringfield(L, 2, "leaves", leaves); tree_def.leavesnode=ndef->getId(leaves); tree_def.leaves2_chance=0; getstringfield(L, 2, "leaves2", leaves); if (leaves !="") { tree_def.leaves2node=ndef->getId(leaves); getintfield(L, 2, "leaves2_chance", tree_def.leaves2_chance); } getintfield(L, 2, "angle", tree_def.angle); getintfield(L, 2, "iterations", tree_def.iterations); getintfield(L, 2, "random_level", tree_def.iterations_random_level); getstringfield(L, 2, "trunk_type", tree_def.trunk_type); getboolfield(L, 2, "thin_branches", tree_def.thin_branches); tree_def.fruit_chance=0; getstringfield(L, 2, "fruit", fruit); if (fruit != "") { tree_def.fruitnode=ndef->getId(fruit); getintfield(L, 2, "fruit_chance",tree_def.fruit_chance); } getintfield(L, 2, "seed", tree_def.seed); } else return 0; treegen::spawn_ltree (env, p0, ndef, tree_def); return 1; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { INodeDefManager *ndef = env->getGameDef()->ndef(); ServerMap *map = &env->getServerMap(); MapNode n_top = map->getNodeNoEx(p+v3s16(0,1,0)); content_t c_snow = ndef->getId("snow"); if(ndef->get(n_top).light_propagates && !ndef->get(n_top).isLiquid() && n_top.getLightBlend(env->getDayNightRatio(), ndef) >= 13) { if(c_snow != CONTENT_IGNORE && n_top.getContent() == c_snow) n.setContent(ndef->getId("dirt_with_snow")); else n.setContent(ndef->getId("mapgen_dirt_with_grass")); map->addNodeWithEvent(p, n); } }
// get_content_id(name) int ModApiItemMod::l_get_content_id(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::string name = luaL_checkstring(L, 1); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); content_t c = ndef->getId(name); lua_pushinteger(L, c); return 1; /* number of results */ }
MapgenSinglenode::MapgenSinglenode(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { flags = params->flags; INodeDefManager *ndef = emerge->ndef; c_node = ndef->getId("mapgen_singlenode"); if (c_node == CONTENT_IGNORE) c_node = CONTENT_AIR; }
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) { this->generating = false; this->id = mapgenid; this->emerge = emerge; this->bmgr = emerge->biomemgr; this->seed = (int)params->seed; this->water_level = params->water_level; this->flags = params->flags; this->gennotify = emerge->gennotify; this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE; //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; this->zstride = csize.X * csize.Y; this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z]; this->ridge_heightmap = new s16[csize.X * csize.Z]; MapgenV7Params *sp = (MapgenV7Params *)params->sparams; this->spflags = sp->spflags; //// Terrain noise noise_terrain_base = new Noise(&sp->np_terrain_base, seed, csize.X, csize.Z); noise_terrain_alt = new Noise(&sp->np_terrain_alt, seed, csize.X, csize.Z); noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z); noise_height_select = new Noise(&sp->np_height_select, seed, csize.X, csize.Z); noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); noise_mount_height = new Noise(&sp->np_mount_height, seed, csize.X, csize.Z); noise_ridge_uwater = new Noise(&sp->np_ridge_uwater, seed, csize.X, csize.Z); //// 3d terrain noise noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y, csize.Z); noise_ridge = new Noise(&sp->np_ridge, seed, csize.X, csize.Y, csize.Z); //// Biome noise noise_heat = new Noise(bmgr->np_heat, seed, csize.X, csize.Z); noise_humidity = new Noise(bmgr->np_humidity, seed, csize.X, csize.Z); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_stone = ndef->getId("mapgen_stone"); c_dirt = ndef->getId("mapgen_dirt"); c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass"); c_sand = ndef->getId("mapgen_sand"); c_water_source = ndef->getId("mapgen_water_source"); c_lava_source = ndef->getId("mapgen_lava_source"); c_ice = ndef->getId("default:ice"); if (c_ice == CONTENT_IGNORE) c_ice = CONTENT_AIR; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) { INodeDefManager *ndef = env->getGameDef()->ndef(); ServerMap *map = &env->getServerMap(); MapNode n_top = map->getNodeNoEx(p+v3s16(0,1,0)); if(!ndef->get(n_top).light_propagates || ndef->get(n_top).isLiquid()) { n.setContent(ndef->getId("dirt")); map->addNodeWithEvent(p, n); } }
// Correct ids in the block to match nodedef based on names. // Unknown ones are added to nodedef. // Will not update itself to match id-name pairs in nodedef. void correctBlockNodeIds(const NameIdMapping *nimap, MapBlock *block, IGameDef *gamedef) { INodeDefManager *nodedef = gamedef->ndef(); // This means the block contains incorrect ids, and we contain // the information to convert those to names. // nodedef contains information to convert our names to globally // correct ids. std::set<content_t> unnamed_contents; std::set<std::string> unallocatable_contents; for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++) for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++) for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++) { v3s16 p(x0,y0,z0); MapNode n = block->getNode(p); content_t local_id = n.getContent(); std::string name; bool found = nimap->getName(local_id, name); if(!found){ unnamed_contents.insert(local_id); continue; } content_t global_id; found = nodedef->getId(name, global_id); if(!found){ global_id = gamedef->allocateUnknownNodeId(name); if(global_id == CONTENT_IGNORE){ unallocatable_contents.insert(name); continue; } } n.setContent(global_id); block->setNode(p, n); } for(std::set<content_t>::const_iterator i = unnamed_contents.begin(); i != unnamed_contents.end(); i++){ errorstream<<"correctBlockNodeIds(): IGNORING ERROR: " <<"Block contains id "<<(*i) <<" with no name mapping"<<std::endl; } for(std::set<std::string>::const_iterator i = unallocatable_contents.begin(); i != unallocatable_contents.end(); i++){ errorstream<<"correctBlockNodeIds(): IGNORING ERROR: " <<"Could not allocate global id for node name \"" <<(*i)<<"\""<<std::endl; } }
MapgenSinglenode::MapgenSinglenode(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { flags = params->flags; INodeDefManager *ndef = emerge->ndef; c_node = ndef->getId("mapgen_singlenode"); if (c_node == CONTENT_IGNORE) c_node = CONTENT_AIR; MapNode n_node(c_node); set_light = (ndef->get(n_node).sunlight_propagates) ? LIGHT_SUN : 0x00; }
static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, IGameDef *gamedef) { INodeDefManager *nodedef = gamedef->ndef(); // This means the block contains incorrect ids, and we contain // the information to convert those to names. // nodedef contains information to convert our names to globally // correct ids. std::set<content_t> unnamed_contents; std::set<std::string> unallocatable_contents; std::lock_guard<std::mutex> lock(correctBlockNodeIds_mutex); for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++) { content_t local_id = nodes[i].getContent(); std::string name; bool found = nimap->getName(local_id, name); if(!found){ unnamed_contents.insert(local_id); continue; } content_t global_id; found = nodedef->getId(name, global_id); if(!found){ global_id = gamedef->allocateUnknownNodeId(name); if(global_id == CONTENT_IGNORE){ unallocatable_contents.insert(name); continue; } } nodes[i].setContent(global_id); } for(std::set<content_t>::const_iterator i = unnamed_contents.begin(); i != unnamed_contents.end(); i++){ errorstream<<"correctBlockNodeIds(): IGNORING ERROR: " <<"Block contains id "<<(*i) <<" with no name mapping"<<std::endl; } for(std::set<std::string>::const_iterator i = unallocatable_contents.begin(); i != unallocatable_contents.end(); i++){ errorstream<<"correctBlockNodeIds(): IGNORING ERROR: " <<"Could not allocate global id for node name \"" <<(*i)<<"\""<<std::endl; } }
// get_node_def(nodename) int ModApiClient::l_get_node_def(lua_State *L) { IGameDef *gdef = getGameDef(L); assert(gdef); INodeDefManager *ndef = gdef->ndef(); assert(ndef); if (!lua_isstring(L, 1)) return 0; const std::string &name = lua_tostring(L, 1); const ContentFeatures &cf = ndef->get(ndef->getId(name)); if (cf.name != name) // Unknown node. | name = <whatever>, cf.name = ignore return 0; push_content_features(L, cf); return 1; }
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider) { if(active_object_count_wider != 0) return; INodeDefManager *ndef = env->getGameDef()->ndef(); ServerMap *map = &env->getServerMap(); v3s16 p1 = p + v3s16(myrand_range(-2, 2), 0, myrand_range(-2, 2)); MapNode n1 = map->getNodeNoEx(p1); MapNode n1b = map->getNodeNoEx(p1+v3s16(0,-1,0)); if(n1b.getContent() == ndef->getId("dirt_with_grass") && n1.getContent() == CONTENT_AIR) { v3f pos = intToFloat(p1, BS); ServerActiveObject *obj = new RatSAO(env, pos); env->addActiveObject(obj); } }
u32 Map::transformLiquidsReal(Server *m_server, unsigned int max_cycle_ms) { INodeDefManager *nodemgr = m_gamedef->ndef(); DSTACK(__FUNCTION_NAME); //TimeTaker timer("transformLiquidsReal()"); u32 loopcount = 0; u32 initial_size = transforming_liquid_size(); s32 regenerated = 0; #if LIQUID_DEBUG bool debug = 1; #endif u8 relax = g_settings->getS16("liquid_relax"); bool fast_flood = g_settings->getS16("liquid_fast_flood"); int water_level = g_settings->getS16("water_level"); s16 liquid_pressure = m_server->m_emerge->params.liquid_pressure; //g_settings->getS16NoEx("liquid_pressure", liquid_pressure); // list of nodes that due to viscosity have not reached their max level height //std::unordered_map<v3POS, bool, v3POSHash, v3POSEqual> must_reflow, must_reflow_second, must_reflow_third; std::list<v3POS> must_reflow, must_reflow_second, must_reflow_third; // List of MapBlocks that will require a lighting update (due to lava) u16 loop_rand = myrand(); u32 end_ms = porting::getTimeMs() + max_cycle_ms; NEXT_LIQUID: ; while (transforming_liquid_size() > 0) { // This should be done here so that it is done when continue is used if (loopcount >= initial_size * 2 || porting::getTimeMs() > end_ms) break; ++loopcount; /* Get a queued transforming liquid node */ v3POS p0; { //JMutexAutoLock lock(m_transforming_liquid_mutex); p0 = transforming_liquid_pop(); } s16 total_level = 0; //u16 level_max = 0; // surrounding flowing liquid nodes NodeNeighbor neighbors[7] = { { } }; // current level of every block s8 liquid_levels[7] = { -1, -1, -1, -1, -1, -1, -1}; // target levels s8 liquid_levels_want[7] = { -1, -1, -1, -1, -1, -1, -1}; s8 can_liquid_same_level = 0; s8 can_liquid = 0; // warning! when MINETEST_PROTO enabled - CONTENT_IGNORE != 0 content_t liquid_kind = CONTENT_IGNORE; content_t liquid_kind_flowing = CONTENT_IGNORE; content_t melt_kind = CONTENT_IGNORE; content_t melt_kind_flowing = CONTENT_IGNORE; //s8 viscosity = 0; /* Collect information about the environment, start from self */ for (u8 e = 0; e < 7; e++) { u8 i = liquid_explore_map[e]; NodeNeighbor & nb = neighbors[i]; nb.pos = p0 + liquid_flow_dirs[i]; nb.node = getNodeNoEx(neighbors[i].pos); nb.content = nb.node.getContent(); NeighborType nt = NEIGHBOR_SAME_LEVEL; switch (i) { case D_TOP: nt = NEIGHBOR_UPPER; break; case D_BOTTOM: nt = NEIGHBOR_LOWER; break; } nb.type = nt; nb.liquid = 0; nb.infinity = 0; nb.weight = 0; nb.drop = 0; if (!nb.node) { //if (i == D_SELF && (loopcount % 2) && initial_size < m_liquid_step_flow * 3) // must_reflow_third[nb.pos] = 1; // must_reflow_third.push_back(nb.pos); continue; } auto f = nodemgr->get(nb.content); switch (f.liquid_type) { case LIQUID_NONE: if (nb.content == CONTENT_AIR) { liquid_levels[i] = 0; nb.liquid = 1; } //TODO: if (nb.content == CONTENT_AIR || nodemgr->get(nb.node).buildable_to && !nodemgr->get(nb.node).walkable) { // need lua drop api for drop torches else if ( melt_kind_flowing != CONTENT_IGNORE && nb.content == melt_kind_flowing && nb.type != NEIGHBOR_UPPER && !(loopcount % 2)) { u8 melt_max_level = nb.node.getMaxLevel(nodemgr); u8 my_max_level = MapNode(liquid_kind_flowing).getMaxLevel(nodemgr); liquid_levels[i] = (float)my_max_level / melt_max_level * nb.node.getLevel(nodemgr); if (liquid_levels[i]) nb.liquid = 1; } else if ( melt_kind != CONTENT_IGNORE && nb.content == melt_kind && nb.type != NEIGHBOR_UPPER && !(loopcount % 8)) { liquid_levels[i] = nodemgr->get(liquid_kind_flowing).getMaxLevel(); if (liquid_levels[i]) nb.liquid = 1; } else { int drop = ((ItemGroupList) f.groups)["drop_by_liquid"]; if (drop && !(loopcount % drop) ) { liquid_levels[i] = 0; nb.liquid = 1; nb.drop = 1; } } // todo: for erosion add something here.. break; case LIQUID_SOURCE: // if this node is not (yet) of a liquid type, // choose the first liquid type we encounter if (liquid_kind_flowing == CONTENT_IGNORE) liquid_kind_flowing = nodemgr->getId( f.liquid_alternative_flowing); if (liquid_kind == CONTENT_IGNORE) liquid_kind = nb.content; if (liquid_kind_flowing == CONTENT_IGNORE) liquid_kind_flowing = liquid_kind; if (melt_kind == CONTENT_IGNORE) melt_kind = nodemgr->getId(f.melt); if (melt_kind_flowing == CONTENT_IGNORE) melt_kind_flowing = nodemgr->getId( nodemgr->get(nodemgr->getId(f.melt) ).liquid_alternative_flowing); if (melt_kind_flowing == CONTENT_IGNORE) melt_kind_flowing = melt_kind; if (nb.content == liquid_kind) { if (nb.node.param2 & LIQUID_STABLE_MASK) continue; liquid_levels[i] = nb.node.getLevel(nodemgr); //LIQUID_LEVEL_SOURCE; nb.liquid = 1; nb.infinity = (nb.node.param2 & LIQUID_INFINITY_MASK); } break; case LIQUID_FLOWING: // if this node is not (yet) of a liquid type, // choose the first liquid type we encounter if (liquid_kind_flowing == CONTENT_IGNORE) liquid_kind_flowing = nb.content; if (liquid_kind == CONTENT_IGNORE) liquid_kind = nodemgr->getId( f.liquid_alternative_source); if (liquid_kind == CONTENT_IGNORE) liquid_kind = liquid_kind_flowing; if (melt_kind_flowing == CONTENT_IGNORE) melt_kind_flowing = nodemgr->getId(f.melt); if (melt_kind == CONTENT_IGNORE) melt_kind = nodemgr->getId(nodemgr->get(nodemgr->getId( f.melt)).liquid_alternative_source); if (melt_kind == CONTENT_IGNORE) melt_kind = melt_kind_flowing; if (nb.content == liquid_kind_flowing) { if (nb.node.param2 & LIQUID_STABLE_MASK) continue; liquid_levels[i] = nb.node.getLevel(nodemgr); nb.liquid = 1; nb.infinity = (nb.node.param2 & LIQUID_INFINITY_MASK); } break; } // only self, top, bottom swap if (f.liquid_type && e <= 2) { try { nb.weight = ((ItemGroupList) f.groups)["weight"]; if (e == 1 && neighbors[D_BOTTOM].weight && neighbors[D_SELF].weight > neighbors[D_BOTTOM].weight) { setNode(neighbors[D_SELF].pos, neighbors[D_BOTTOM].node); setNode(neighbors[D_BOTTOM].pos, neighbors[D_SELF].node); //must_reflow_second[neighbors[D_SELF].pos] = 1; //must_reflow_second[neighbors[D_BOTTOM].pos] = 1; must_reflow_second.push_back(neighbors[D_SELF].pos); must_reflow_second.push_back(neighbors[D_BOTTOM].pos); #if LIQUID_DEBUG infostream << "Liquid swap1" << neighbors[D_SELF].pos << nodemgr->get(neighbors[D_SELF].node).name << neighbors[D_SELF].node << " w=" << neighbors[D_SELF].weight << " VS " << neighbors[D_BOTTOM].pos << nodemgr->get(neighbors[D_BOTTOM].node).name << neighbors[D_BOTTOM].node << " w=" << neighbors[D_BOTTOM].weight << std::endl; #endif goto NEXT_LIQUID; } if (e == 2 && neighbors[D_SELF].weight && neighbors[D_TOP].weight > neighbors[D_SELF].weight) { setNode(neighbors[D_SELF].pos, neighbors[D_TOP].node); setNode(neighbors[D_TOP].pos, neighbors[D_SELF].node); //must_reflow_second[neighbors[D_SELF].pos] = 1; //must_reflow_second[neighbors[D_TOP].pos] = 1; must_reflow_second.push_back(neighbors[D_SELF].pos); must_reflow_second.push_back(neighbors[D_TOP].pos); #if LIQUID_DEBUG infostream << "Liquid swap2" << neighbors[D_TOP].pos << nodemgr->get(neighbors[D_TOP].node).name << neighbors[D_TOP].node << " w=" << neighbors[D_TOP].weight << " VS " << neighbors[D_SELF].pos << nodemgr->get(neighbors[D_SELF].node).name << neighbors[D_SELF].node << " w=" << neighbors[D_SELF].weight << std::endl; #endif goto NEXT_LIQUID; } } catch(InvalidPositionException &e) { verbosestream << "transformLiquidsReal: weight: setNode() failed:" << nb.pos << ":" << e.what() << std::endl; //goto NEXT_LIQUID; } } if (nb.liquid) { liquid_levels_want[i] = 0; ++can_liquid; if(nb.type == NEIGHBOR_SAME_LEVEL) ++can_liquid_same_level; } if (liquid_levels[i] > 0) total_level += liquid_levels[i]; #if LIQUID_DEBUG infostream << "get node i=" << (int)i << " " << PP(nb.pos) << " c=" << nb.content << " p0=" << (int)nb.node.param0 << " p1=" << (int)nb.node.param1 << " p2=" << (int)nb.node.param2 << " lt=" << f.liquid_type //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing << " l=" << nb.liquid << " inf=" << nb.infinity << " nlevel=" << (int)liquid_levels[i] << " totallevel=" << (int)total_level << " cansame=" << (int)can_liquid_same_level << " Lmax=" << (int)nodemgr->get(liquid_kind_flowing).getMaxLevel() << std::endl; #endif } if (liquid_kind == CONTENT_IGNORE || !neighbors[D_SELF].liquid || total_level <= 0) continue; s16 level_max = nodemgr->get(liquid_kind_flowing).getMaxLevel(); s16 level_max_compressed = nodemgr->get(liquid_kind_flowing).getMaxLevel(1); s16 pressure = liquid_pressure ? ((ItemGroupList) nodemgr->get(liquid_kind).groups)["pressure"] : 0; auto liquid_renewable = nodemgr->get(liquid_kind).liquid_renewable; #if LIQUID_DEBUG s16 total_was = total_level; //debug #endif //viscosity = nodemgr->get(liquid_kind).viscosity; s16 level_avg = total_level / can_liquid; if (!pressure && level_avg) { level_avg = level_max; } #if LIQUID_DEBUG if (debug) infostream << " go: " << nodemgr->get(liquid_kind).name << " total_level=" << (int)total_level //<<" total_was="<<(int)total_was << " level_max=" << (int)level_max << " level_max_compressed=" << (int)level_max_compressed << " level_avg=" << (int)level_avg << " pressure=" << (int)pressure << " can_liquid=" << (int)can_liquid << " can_liquid_same_level=" << (int)can_liquid_same_level << std::endl; ; #endif // fill bottom block if (neighbors[D_BOTTOM].liquid) { liquid_levels_want[D_BOTTOM] = level_avg > level_max ? level_avg : total_level > level_max ? level_max : total_level; total_level -= liquid_levels_want[D_BOTTOM]; //if (pressure && total_level && liquid_levels_want[D_BOTTOM] < level_max_compressed) { // ++liquid_levels_want[D_BOTTOM]; // --total_level; //} } //relax up u16 relax_want = level_max * can_liquid_same_level; if ( liquid_renewable && relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && level_max > 1 && liquid_levels[D_TOP] == 0 && liquid_levels[D_BOTTOM] >= level_max && total_level >= relax_want - (can_liquid_same_level - relax) && total_level < relax_want && can_liquid_same_level >= relax + 1) { regenerated += relax_want - total_level; #if LIQUID_DEBUG infostream << " relax_up: " << " total_level=" << (int)total_level << " to=> " << int(relax_want) << std::endl; #endif total_level = relax_want; } // prevent lakes in air above unloaded blocks if ( liquid_levels[D_TOP] == 0 && p0.Y > water_level && level_max > 1 && !neighbors[D_BOTTOM].node && !(loopcount % 3)) { --total_level; #if LIQUID_DEBUG infostream << " above unloaded fix: " << " total_level=" << (int)total_level << std::endl; #endif } // calculate self level 5 blocks u16 want_level = level_avg > level_max ? level_avg : total_level >= level_max * can_liquid_same_level ? level_max : total_level / can_liquid_same_level; total_level -= want_level * can_liquid_same_level; /* if (pressure && total_level > 0 && neighbors[D_BOTTOM].liquid) { // bottom pressure +1 ++liquid_levels_want[D_BOTTOM]; --total_level; #if LIQUID_DEBUG infostream << " bottom1 pressure+1: " << " bottom=" << (int)liquid_levels_want[D_BOTTOM] << " total_level=" << (int)total_level << std::endl; #endif } */ //relax down if ( liquid_renewable && relax && p0.Y >= water_level - 1 && p0.Y <= water_level + 1 && liquid_levels[D_TOP] == 0 && (total_level <= 1 || !(loopcount % 2)) && level_max > 1 && liquid_levels[D_BOTTOM] >= level_max && want_level <= 0 && total_level <= (can_liquid_same_level - relax) && can_liquid_same_level >= relax + 1) { #if LIQUID_DEBUG infostream << " relax_down: " << " total_level WAS=" << (int)total_level << " to => 0" << std::endl; #endif regenerated -= total_level; total_level = 0; } for (u16 ir = D_SELF; ir < D_TOP; ++ir) { // fill only same level u16 ii = liquid_random_map[(loopcount + loop_rand + 1) % 4][ir]; if (!neighbors[ii].liquid) continue; liquid_levels_want[ii] = want_level; //if (viscosity > 1 && (liquid_levels_want[ii]-liquid_levels[ii]>8-viscosity)) // randomly place rest of divide if (liquid_levels_want[ii] < level_max && total_level > 0) { if (level_max > LIQUID_LEVEL_SOURCE || loopcount % 3 || liquid_levels[ii] <= 0) { if (liquid_levels[ii] > liquid_levels_want[ii]) { ++liquid_levels_want[ii]; --total_level; } } else { ++liquid_levels_want[ii]; --total_level; } } } for (u16 ir = D_SELF; ir < D_TOP; ++ir) { if (total_level < 1) break; u16 ii = liquid_random_map[(loopcount + loop_rand + 2) % 4][ir]; if (liquid_levels_want[ii] >= 0 && liquid_levels_want[ii] < level_max) { ++liquid_levels_want[ii]; --total_level; } } // fill top block if can if (neighbors[D_TOP].liquid && total_level > 0) { //infostream<<"compressing to top was="<<liquid_levels_want[D_TOP]<<" add="<<total_level<<std::endl; //liquid_levels_want[D_TOP] = total_level>level_max_compressed?level_max_compressed:total_level; liquid_levels_want[D_TOP] = total_level > level_max ? level_max : total_level; total_level -= liquid_levels_want[D_TOP]; //if (liquid_levels_want[D_TOP] && total_level && pressure) { if (total_level > 0 && pressure) { /* if (total_level > 0 && neighbors[D_BOTTOM].liquid) { // bottom pressure +2 ++liquid_levels_want[D_BOTTOM]; --total_level; } */ //compressing self level while can //for (u16 ir = D_SELF; ir < D_TOP; ++ir) { for (u16 ir = D_BOTTOM; ir <= D_TOP; ++ir) { if (total_level < 1) break; u16 ii = liquid_random_map[(loopcount + loop_rand + 3) % 4][ir]; if (neighbors[ii].liquid && liquid_levels_want[ii] < level_max_compressed) { ++liquid_levels_want[ii]; --total_level; } } /* if (total_level > 0 && neighbors[D_BOTTOM].liquid) { // bottom pressure +2 ++liquid_levels_want[D_BOTTOM]; --total_level; #if LIQUID_DEBUG infostream << " bottom2 pressure+1: " << " bottom=" << (int)liquid_levels_want[D_BOTTOM] << " total_level=" << (int)total_level << std::endl; #endif } */ } } if (pressure) { if (neighbors[D_BOTTOM].liquid && liquid_levels_want[D_BOTTOM] < level_max_compressed && liquid_levels_want[D_TOP] > 0 ) { //if (liquid_levels_want[D_BOTTOM] <= liquid_levels_want[D_TOP]) { --liquid_levels_want[D_TOP]; ++liquid_levels_want[D_BOTTOM]; #if LIQUID_DEBUG infostream << " bottom1 pressure+: " << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl; #endif //} } else if ( neighbors[D_BOTTOM].liquid && liquid_levels_want[D_BOTTOM] < level_max_compressed && liquid_levels_want[D_SELF] > level_max ) { if (liquid_levels_want[D_BOTTOM] <= liquid_levels_want[D_SELF]) { --liquid_levels_want[D_SELF]; ++liquid_levels_want[D_BOTTOM]; #if LIQUID_DEBUG infostream << " bottom2 pressure+: " << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl; #endif } } else if ( neighbors[D_TOP].liquid && liquid_levels_want[D_SELF] < level_max_compressed && liquid_levels_want[D_TOP] > level_max ) { if (liquid_levels_want[D_SELF] <= liquid_levels_want[D_TOP]) { --liquid_levels_want[D_TOP]; ++liquid_levels_want[D_SELF]; #if LIQUID_DEBUG infostream << " bottom3 pressure+: " << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl; #endif } } if (liquid_levels_want[D_TOP] > level_max && relax && total_level <= 0 && level_avg > level_max && liquid_levels_want[D_TOP] < level_avg) { #if LIQUID_DEBUG infostream << " top pressure relax: " << " top=" << (int)liquid_levels_want[D_TOP] << " to=>" << level_avg << std::endl; #endif //regenerated += level_avg - liquid_levels_want[D_TOP]; //liquid_levels_want[D_TOP] = level_avg; regenerated += 1 ; liquid_levels_want[D_TOP] += 1; } } #if LIQUID_DEBUG if (total_level > 0) infostream << " rest 1: " << " wtop=" << (int)liquid_levels_want[D_TOP] << " total_level=" << (int)total_level << std::endl; #endif if (total_level > 0 && neighbors[D_TOP].liquid && liquid_levels_want[D_TOP] < level_max_compressed) { s16 add = (total_level > level_max_compressed - liquid_levels_want[D_TOP]) ? level_max_compressed - liquid_levels_want[D_TOP] : total_level; liquid_levels_want[D_TOP] += add; total_level -= add; } if (total_level > 0 && neighbors[D_SELF].liquid && liquid_levels_want[D_SELF] < level_max_compressed) { // very rare, compressed only s16 add = (total_level > level_max_compressed - liquid_levels_want[D_SELF]) ? level_max_compressed - liquid_levels_want[D_SELF] : total_level; #if LIQUID_DEBUG if (total_level > 0) infostream << " rest 2: " << " wself=" << (int)liquid_levels_want[D_SELF] << " total_level=" << (int)total_level << " add=" << (int)add << std::endl; #endif liquid_levels_want[D_SELF] += add; total_level -= add; } #if LIQUID_DEBUG if (total_level > 0) infostream << " rest 3: " << " total_level=" << (int)total_level << std::endl; #endif for (u16 ii = 0; ii < 7; ii++) { // infinity and cave flood optimization if (neighbors[ii].infinity && liquid_levels_want[ii] < liquid_levels[ii]) { #if LIQUID_DEBUG infostream << " infinity: was=" << (int)ii << " = " << (int)liquid_levels_want[ii] << " to=" << (int)liquid_levels[ii] << std::endl; #endif regenerated += liquid_levels[ii] - liquid_levels_want[ii]; liquid_levels_want[ii] = liquid_levels[ii]; } else if ( liquid_levels_want[ii] >= 0 && liquid_levels_want[ii] < level_max && level_max > 1 && fast_flood && p0.Y < water_level && initial_size >= 1000 && ii != D_TOP && want_level >= level_max / 4 && can_liquid_same_level >= 5 && liquid_levels[D_TOP] >= level_max) { #if LIQUID_DEBUG infostream << " flood_fast: was=" << (int)ii << " = " << (int)liquid_levels_want[ii] << " to=" << (int)level_max << std::endl; #endif regenerated += level_max - liquid_levels_want[ii]; liquid_levels_want[ii] = level_max; } } #if LIQUID_DEBUG if (total_level != 0) //|| flowed != volume) infostream << " AFTER err level=" << (int)total_level //<< " flowed="<<flowed<< " volume=" << volume << " max=" << (int)level_max << " wantsame=" << (int)want_level << " top=" << (int)liquid_levels_want[D_TOP] << " topwas=" << (int)liquid_levels[D_TOP] << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " botwas=" << (int)liquid_levels[D_BOTTOM] << std::endl; s16 flowed = 0; // for debug #endif #if LIQUID_DEBUG if (debug) infostream << " dpress=" << " bot=" << (int)liquid_levels_want[D_BOTTOM] << " slf=" << (int)liquid_levels_want[D_SELF] << " top=" << (int)liquid_levels_want[D_TOP] << std::endl; #endif for (u16 r = 0; r < 7; r++) { u16 i = liquid_random_map[(loopcount + loop_rand + 4) % 4][r]; if (liquid_levels_want[i] < 0 || !neighbors[i].liquid) continue; #if LIQUID_DEBUG if (debug) infostream << " set=" << i << " " << neighbors[i].pos << " want=" << (int)liquid_levels_want[i] << " was=" << (int) liquid_levels[i] << std::endl; #endif /* disabled because brokes constant volume of lava u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity; if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) { // amount to gain, limited by viscosity // must be at least 1 in absolute value s8 level_inc = liquid_levels_want[i] - liquid_levels[i]; if (level_inc < -viscosity || level_inc > viscosity) new_node_level = liquid_levels[i] + level_inc/viscosity; else if (level_inc < 0) new_node_level = liquid_levels[i] - 1; else if (level_inc > 0) new_node_level = liquid_levels[i] + 1; } else { */ // last level must flow down on stairs if (liquid_levels_want[i] != liquid_levels[i] && liquid_levels[D_TOP] <= 0 && (!neighbors[D_BOTTOM].liquid || level_max == 1) && liquid_levels_want[i] >= 1 && liquid_levels_want[i] <= 2) { for (u16 ir = D_SELF + 1; ir < D_TOP; ++ir) { // only same level u16 ii = liquid_random_map[(loopcount + loop_rand + 5) % 4][ir]; if (neighbors[ii].liquid) must_reflow_second.push_back(neighbors[i].pos + liquid_flow_dirs[ii]); //must_reflow_second[neighbors[i].pos + liquid_flow_dirs[ii]] = 1; } } #if LIQUID_DEBUG if (liquid_levels_want[i] > 0) flowed += liquid_levels_want[i]; #endif if (liquid_levels[i] == liquid_levels_want[i]) { continue; } if (neighbors[i].drop) {// && level_max > 1 && total_level >= level_max - 1 m_server->getEnv().getScriptIface()->node_drop(neighbors[i].pos, 2); } neighbors[i].node.setContent(liquid_kind_flowing); neighbors[i].node.setLevel(nodemgr, liquid_levels_want[i], 1); try { setNode(neighbors[i].pos, neighbors[i].node); } catch(InvalidPositionException &e) { verbosestream << "transformLiquidsReal: setNode() failed:" << neighbors[i].pos << ":" << e.what() << std::endl; } // If node emits light, MapBlock requires lighting update // or if node removed v3POS blockpos = getNodeBlockPos(neighbors[i].pos); MapBlock *block = getBlockNoCreateNoEx(blockpos, true); // remove true if light bugs if(block != NULL) { //modified_blocks[blockpos] = block; if(!nodemgr->get(neighbors[i].node).light_propagates || nodemgr->get(neighbors[i].node).light_source) // better to update always lighting_modified_blocks.set_try(block->getPos(), block); } // fmtodo: make here random %2 or.. if (total_level < level_max * can_liquid) must_reflow.push_back(neighbors[i].pos); } #if LIQUID_DEBUG //if (total_was != flowed) { if (total_was > flowed) { infostream << " volume changed! flowed=" << flowed << " total_was=" << total_was << " want_level=" << want_level; for (u16 rr = 0; rr <= 6; rr++) { infostream << " i=" << rr << ",b" << (int)liquid_levels[rr] << ",a" << (int)liquid_levels_want[rr]; } infostream << std::endl; } #endif /* //for better relax only same level if (changed) for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { if (!neighbors[ii].l) continue; must_reflow.push_back(p0 + dirs[ii]); }*/ //g_profiler->graphAdd("liquids", 1); } u32 ret = loopcount >= initial_size ? 0 : transforming_liquid_size(); if (ret || loopcount > m_liquid_step_flow) m_liquid_step_flow += (m_liquid_step_flow > loopcount ? -1 : 1) * (int)loopcount / 10; /* if (loopcount) infostream<<"Map::transformLiquidsReal(): loopcount="<<loopcount<<" initial_size="<<initial_size <<" avgflow="<<m_liquid_step_flow <<" reflow="<<must_reflow.size() <<" reflow_second="<<must_reflow_second.size() <<" reflow_third="<<must_reflow_third.size() <<" queue="<< transforming_liquid_size() <<" per="<< porting::getTimeMs() - (end_ms - max_cycle_ms) <<" ret="<<ret<<std::endl; */ { //TimeTaker timer13("transformLiquidsReal() reflow"); //auto lock = m_transforming_liquid.lock_unique_rec(); std::lock_guard<std::mutex> lock(m_transforming_liquid_mutex); //m_transforming_liquid.insert(must_reflow.begin(), must_reflow.end()); for (const auto & p : must_reflow) m_transforming_liquid.push_back(p); must_reflow.clear(); //m_transforming_liquid.insert(must_reflow_second.begin(), must_reflow_second.end()); for (const auto & p : must_reflow_second) m_transforming_liquid.push_back(p); must_reflow_second.clear(); //m_transforming_liquid.insert(must_reflow_third.begin(), must_reflow_third.end()); for (const auto & p : must_reflow_third) m_transforming_liquid.push_back(p); must_reflow_third.clear(); } g_profiler->add("Server: liquids real processed", loopcount); if (regenerated) g_profiler->add("Server: liquids regenerated", regenerated); if (loopcount < initial_size) g_profiler->add("Server: liquids queue", initial_size); return loopcount; }
MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) , Mapgen_features(mapgenid, params, emerge) { this->m_emerge = emerge; this->bmgr = emerge->biomemgr; // amount of elements to skip for the next index // for noise/height/biome maps (not vmanip) this->ystride = csize.X; this->zstride = csize.X * (csize.Y + 2); this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z]; this->heatmap = NULL; this->humidmap = NULL; MapgenV5Params *sp = (MapgenV5Params *)params->sparams; this->spflags = sp->spflags; // Terrain noise noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); noise_factor = new Noise(&sp->np_factor, seed, csize.X, csize.Z); noise_height = new Noise(&sp->np_height, seed, csize.X, csize.Z); // 3D terrain noise noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z); noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z); // Biome noise noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z); noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z); noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z); noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_stone = ndef->getId("mapgen_stone"); c_water_source = ndef->getId("mapgen_water_source"); c_lava_source = ndef->getId("mapgen_lava_source"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_ice = ndef->getId("mapgen_ice"); c_sandstone = ndef->getId("mapgen_sandstone"); c_cobble = ndef->getId("mapgen_cobble"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_mossycobble = ndef->getId("mapgen_mossycobble"); c_sandstonebrick = ndef->getId("mapgen_sandstonebrick"); c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick"); if (c_ice == CONTENT_IGNORE) c_ice = CONTENT_AIR; if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; //freeminer: y_offset = 1; float_islands = sp->float_islands; noise_float_islands1 = new Noise(&sp->np_float_islands1, seed, csize.X, csize.Y + y_offset * 2, csize.Z); noise_float_islands2 = new Noise(&sp->np_float_islands2, seed, csize.X, csize.Y + y_offset * 2, csize.Z); noise_float_islands3 = new Noise(&sp->np_float_islands3, seed, csize.X, csize.Z); noise_layers = new Noise(&sp->np_layers, seed, csize.X, csize.Y + y_offset * 2, csize.Z); layers_init(emerge, sp->paramsj); //noise_cave_indev = new Noise(&sp->np_cave_indev, seed, csize.X, csize.Y + y_offset * 2, csize.Z); //=== if (c_sandstonebrick == CONTENT_IGNORE) c_sandstonebrick = c_sandstone; if (c_stair_sandstonebrick == CONTENT_IGNORE) c_stair_sandstonebrick = c_sandstone; }
void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; MapNode *tmp_data = new MapNode[nodecount]; // Legacy data changes // This code has to change from post-22 to pre-22 format. INodeDefManager *nodedef = m_gamedef->ndef(); for(u32 i=0; i<nodecount; i++) { const ContentFeatures &f = nodedef->get(tmp_data[i].getContent()); // Mineral if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent()) { tmp_data[i].setContent(nodedef->getId("default:stone")); tmp_data[i].setParam1(1); // MINERAL_COAL } else if(nodedef->getId("default:stone_with_iron") == tmp_data[i].getContent()) { tmp_data[i].setContent(nodedef->getId("default:stone")); tmp_data[i].setParam1(2); // MINERAL_IRON } // facedir_simple if(f.legacy_facedir_simple) { tmp_data[i].setParam1(tmp_data[i].getParam2()); tmp_data[i].setParam2(0); } // wall_mounted if(f.legacy_wallmounted) { u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0}; u8 dir_new_format = tmp_data[i].getParam2() & 7; // lowest 3 bits u8 dir_old_format = wallmounted_new_to_old[dir_new_format]; tmp_data[i].setParam2(dir_old_format); } } // Serialize nodes u32 ser_length = MapNode::serializedLength(version); SharedBuffer<u8> databuf_nodelist(nodecount * ser_length); for(u32 i=0; i<nodecount; i++) { tmp_data[i].serialize(&databuf_nodelist[i*ser_length], version); } delete[] tmp_data; // These have no compression if(version <= 3 || version == 5 || version == 6) { writeU8(os, is_underground); os.write((char*)*databuf_nodelist, databuf_nodelist.getSize()); } else if(version <= 10) { /* With compression. Compress the materials and the params separately. */ // First byte writeU8(os, is_underground); // Get and compress materials SharedBuffer<u8> materialdata(nodecount); for(u32 i=0; i<nodecount; i++) { materialdata[i] = databuf_nodelist[i*ser_length]; } compress(materialdata, os, version); // Get and compress lights SharedBuffer<u8> lightdata(nodecount); for(u32 i=0; i<nodecount; i++) { lightdata[i] = databuf_nodelist[i*ser_length+1]; } compress(lightdata, os, version); if(version >= 10) { // Get and compress param2 SharedBuffer<u8> param2data(nodecount); for(u32 i=0; i<nodecount; i++) { param2data[i] = databuf_nodelist[i*ser_length+2]; } compress(param2data, os, version); } } // All other versions (newest) else { // First byte u8 flags = 0; if(is_underground) flags |= 0x01; if(m_day_night_differs) flags |= 0x02; if(m_lighting_expired) flags |= 0x04; if(version >= 18) { if(m_generated == false) flags |= 0x08; } writeU8(os, flags); /* Get data */ // Create buffer with different parameters sorted SharedBuffer<u8> databuf(nodecount*3); for(u32 i=0; i<nodecount; i++) { databuf[i] = databuf_nodelist[i*ser_length]; databuf[i+nodecount] = databuf_nodelist[i*ser_length+1]; databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2]; } /* Compress data to output stream */ compress(databuf, os, version); /* NodeMetadata */ if(version >= 14) { if(version <= 15) { try{ std::ostringstream oss(std::ios_base::binary); m_node_metadata->serialize(oss); os<<serializeString(oss.str()); } // This will happen if the string is longer than 65535 catch(SerializationError &e) { // Use an empty string os<<serializeString(""); } } else { std::ostringstream oss(std::ios_base::binary); m_node_metadata->serialize(oss); compressZlib(oss.str(), os); //os<<serializeLongString(oss.str()); } } } if(disk) { // Versions up from 9 have block objects. (DEPRECATED) if(version >= 9) { // count=0 writeU16(os, 0); } // Versions up from 15 have static objects. if(version >= 15) { m_static_objects.serialize(os); } // Timestamp if(version >= 17) { writeU32(os, getTimestamp()); } // Scan and write node definition id mapping if(version >= 21) { NameIdMapping nimap; getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef()); nimap.serialize(os); } } }
void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; // Initialize default flags is_underground = false; m_day_night_differs = false; m_lighting_expired = false; m_generated = true; // Make a temporary buffer u32 ser_length = MapNode::serializedLength(version); SharedBuffer<u8> databuf_nodelist(nodecount * ser_length); // These have no compression if(version <= 3 || version == 5 || version == 6) { char tmp; is.read(&tmp, 1); if(is.gcount() != 1) throw SerializationError ("MapBlock::deSerialize: no enough input data"); is_underground = tmp; is.read((char*)*databuf_nodelist, nodecount * ser_length); if(is.gcount() != nodecount * ser_length) throw SerializationError ("MapBlock::deSerialize: no enough input data"); } else if(version <= 10) { u8 t8; is.read((char*)&t8, 1); is_underground = t8; { // Uncompress and set material data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { databuf_nodelist[i*ser_length] = s[i]; } } { // Uncompress and set param data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { databuf_nodelist[i*ser_length + 1] = s[i]; } } if(version >= 10) { // Uncompress and set param2 data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount) throw SerializationError ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i<s.size(); i++) { databuf_nodelist[i*ser_length + 2] = s[i]; } } } // All other versions (newest) else { u8 flags; is.read((char*)&flags, 1); is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false; if(version >= 18) m_generated = (flags & 0x08) ? false : true; // Uncompress data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); if(s.size() != nodecount*3) throw SerializationError ("MapBlock::deSerialize: decompress resulted in size" " other than nodecount*3"); // deserialize nodes from buffer for(u32 i=0; i<nodecount; i++) { databuf_nodelist[i*ser_length] = s[i]; databuf_nodelist[i*ser_length + 1] = s[i+nodecount]; databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2]; } /* NodeMetadata */ if(version >= 14) { // Ignore errors try{ if(version <= 15) { std::string data = deSerializeString(is); std::istringstream iss(data, std::ios_base::binary); m_node_metadata->deSerialize(iss, m_gamedef); } else { //std::string data = deSerializeLongString(is); std::ostringstream oss(std::ios_base::binary); decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); m_node_metadata->deSerialize(iss, m_gamedef); } } catch(SerializationError &e) { errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" <<" while deserializing node metadata"<<std::endl; } } } // Deserialize node data for(u32 i=0; i<nodecount; i++) { data[i].deSerialize(&databuf_nodelist[i*ser_length], version); } if(disk) { /* Versions up from 9 have block objects. (DEPRECATED) */ if(version >= 9){ u16 count = readU16(is); // Not supported and length not known if count is not 0 if(count != 0){ errorstream<<"WARNING: MapBlock::deSerialize_pre22(): " <<"Ignoring stuff coming at and after MBOs"<<std::endl; return; } } /* Versions up from 15 have static objects. */ if(version >= 15) m_static_objects.deSerialize(is); // Timestamp if(version >= 17){ setTimestamp(readU32(is)); m_disk_timestamp = m_timestamp; } else { setTimestamp(BLOCK_TIMESTAMP_UNDEFINED); } // Dynamically re-set ids based on node names NameIdMapping nimap; // If supported, read node definition id mapping if(version >= 21){ nimap.deSerialize(is); // Else set the legacy mapping } else { content_mapnode_get_name_id_mapping(&nimap); } correctBlockNodeIds(&nimap, data, m_gamedef); } // Legacy data changes // This code has to convert from pre-22 to post-22 format. INodeDefManager *nodedef = m_gamedef->ndef(); for(u32 i=0; i<nodecount; i++) { const ContentFeatures &f = nodedef->get(data[i].getContent()); // Mineral if(nodedef->getId("default:stone") == data[i].getContent() && data[i].getParam1() == 1) { data[i].setContent(nodedef->getId("default:stone_with_coal")); data[i].setParam1(0); } else if(nodedef->getId("default:stone") == data[i].getContent() && data[i].getParam1() == 2) { data[i].setContent(nodedef->getId("default:stone_with_iron")); data[i].setParam1(0); } // facedir_simple if(f.legacy_facedir_simple) { data[i].setParam2(data[i].getParam1()); data[i].setParam1(0); } // wall_mounted if(f.legacy_wallmounted) { u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0}; u8 dir_old_format = data[i].getParam2(); u8 dir_new_format = 0; for(u8 j=0; j<8; j++) { if((dir_old_format & wallmounted_new_to_old[j]) != 0) { dir_new_format = j; break; } } data[i].setParam2(dir_new_format); } } }
MapgenV6::MapgenV6(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { this->m_emerge = emerge; this->ystride = csize.X; //////fix this this->heightmap = new s16[csize.X * csize.Z]; MapgenV6Params *sp = (MapgenV6Params *)params->sparams; this->spflags = sp->spflags; this->freq_desert = sp->freq_desert; this->freq_beach = sp->freq_beach; np_cave = &sp->np_cave; np_humidity = &sp->np_humidity; np_trees = &sp->np_trees; np_apple_trees = &sp->np_apple_trees; //// Create noise objects noise_terrain_base = new Noise(&sp->np_terrain_base, seed, csize.X, csize.Y); noise_terrain_higher = new Noise(&sp->np_terrain_higher, seed, csize.X, csize.Y); noise_steepness = new Noise(&sp->np_steepness, seed, csize.X, csize.Y); noise_height_select = new Noise(&sp->np_height_select, seed, csize.X, csize.Y); noise_mud = new Noise(&sp->np_mud, seed, csize.X, csize.Y); noise_beach = new Noise(&sp->np_beach, seed, csize.X, csize.Y); noise_biome = new Noise(&sp->np_biome, seed, csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE); noise_humidity = new Noise(&sp->np_humidity, seed, csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_stone = ndef->getId("mapgen_stone"); c_dirt = ndef->getId("mapgen_dirt"); c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass"); c_sand = ndef->getId("mapgen_sand"); c_water_source = ndef->getId("mapgen_water_source"); c_lava_source = ndef->getId("mapgen_lava_source"); c_gravel = ndef->getId("mapgen_gravel"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_desert_sand = ndef->getId("mapgen_desert_sand"); c_dirt_with_snow = ndef->getId("mapgen_dirt_with_snow"); c_snow = ndef->getId("mapgen_snow"); c_snowblock = ndef->getId("mapgen_snowblock"); c_ice = ndef->getId("mapgen_ice"); c_clay = ndef->getId("default:clay"); c_cobble = ndef->getId("mapgen_cobble"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_mossycobble = ndef->getId("mapgen_mossycobble"); if (c_desert_sand == CONTENT_IGNORE) c_desert_sand = c_sand; if (c_desert_stone == CONTENT_IGNORE) c_desert_stone = c_stone; if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; // freeminer: c_dirt_with_snow = ndef->getId("mapgen_dirt_with_snow"); c_ice = ndef->getId("mapgen_ice"); if (c_dirt_with_snow == CONTENT_IGNORE) c_dirt_with_snow = c_dirt_with_grass; if (c_snow == CONTENT_IGNORE) c_snow = CONTENT_AIR; if (c_snowblock == CONTENT_IGNORE) c_snowblock = c_dirt_with_grass; if (c_ice == CONTENT_IGNORE) c_ice = c_water_source; }
ClientCached* createClientCachedDirect(const std::string &name, IGameDef *gamedef) const { infostream<<"Lazily creating item texture and mesh for \"" <<name<<"\""<<std::endl; // This is not thread-safe sanity_check(get_current_thread_id() == m_main_thread); // Skip if already in cache ClientCached *cc = NULL; m_clientcached.get(name, &cc); if(cc) return cc; ITextureSource *tsrc = gamedef->getTextureSource(); INodeDefManager *nodedef = gamedef->getNodeDefManager(); const ItemDefinition &def = get(name); // Create new ClientCached cc = new ClientCached(); // Create an inventory texture cc->inventory_texture = NULL; if(def.inventory_image != "") cc->inventory_texture = tsrc->getTexture(def.inventory_image); // Additional processing for nodes: // - Create a wield mesh if WieldMeshSceneNode can't render // the node on its own. // - If inventory_texture isn't set yet, create one using // render-to-texture. if (def.type == ITEM_NODE) { // Get node properties content_t id = nodedef->getId(name); const ContentFeatures &f = nodedef->get(id); bool need_rtt_mesh = cc->inventory_texture == NULL; // Keep this in sync with WieldMeshSceneNode::setItem() bool need_wield_mesh = !(f.mesh_ptr[0] || f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES || f.drawtype == NDT_AIRLIKE); scene::IMesh *node_mesh = NULL; if (need_rtt_mesh || need_wield_mesh) { u8 param1 = 0; if (f.param_type == CPT_LIGHT) param1 = 0xee; /* Make a mesh from the node */ MeshMakeData mesh_make_data(gamedef, false); u8 param2 = 0; if (f.param_type_2 == CPT2_WALLMOUNTED) param2 = 1; MapNode mesh_make_node(id, param1, param2); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); node_mesh = mapblock_mesh.getMesh(); node_mesh->grab(); video::SColor c(255, 255, 255, 255); setMeshColor(node_mesh, c); // scale and translate the mesh so it's a // unit cube centered on the origin scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS)); translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0)); } /* Draw node mesh into a render target texture */ if (need_rtt_mesh) { TextureFromMeshParams params; params.mesh = node_mesh; params.dim.set(64, 64); params.rtt_texture_name = "INVENTORY_" + def.name + "_RTT"; params.delete_texture_on_shutdown = true; params.camera_position.set(0, 1.0, -1.5); params.camera_position.rotateXZBy(45); params.camera_lookat.set(0, 0, 0); // Set orthogonal projection params.camera_projection_matrix.buildProjectionMatrixOrthoLH( 1.65, 1.65, 0, 100); params.ambient_light.set(1.0, 0.2, 0.2, 0.2); params.light_position.set(10, 100, -50); params.light_color.set(1.0, 0.5, 0.5, 0.5); params.light_radius = 1000; #ifdef __ANDROID__ params.camera_position.set(0, -1.0, -1.5); params.camera_position.rotateXZBy(45); params.light_position.set(10, -100, -50); #endif cc->inventory_texture = tsrc->generateTextureFromMesh(params); // render-to-target didn't work if (cc->inventory_texture == NULL) { cc->inventory_texture = tsrc->getTexture(f.tiledef[0].name); } } /* Use the node mesh as the wield mesh */ if (need_wield_mesh) { cc->wield_mesh = node_mesh; cc->wield_mesh->grab(); // no way reference count can be smaller than 2 in this place! assert(cc->wield_mesh->getReferenceCount() >= 2); } if (node_mesh) node_mesh->drop(); } // Put in cache m_clientcached.set(name, cc); return cc; }
virtual void updateTexturesAndMeshes(IGameDef *gamedef) { #ifndef SERVER infostream<<"ItemDefManager::updateTexturesAndMeshes(): Updating " <<"textures and meshes in item definitions"<<std::endl; ITextureSource *tsrc = gamedef->getTextureSource(); INodeDefManager *nodedef = gamedef->getNodeDefManager(); IrrlichtDevice *device = tsrc->getDevice(); video::IVideoDriver *driver = device->getVideoDriver(); for(std::map<std::string, ItemDefinition*>::iterator i = m_item_definitions.begin(); i != m_item_definitions.end(); i++) { ItemDefinition *def = i->second; bool need_node_mesh = false; // Create an inventory texture def->inventory_texture = NULL; if(def->inventory_image != "") { def->inventory_texture = tsrc->getTextureRaw(def->inventory_image); } else if(def->type == ITEM_NODE) { need_node_mesh = true; } // Create a wield mesh if(def->wield_mesh != NULL) { def->wield_mesh->drop(); def->wield_mesh = NULL; } if(def->type == ITEM_NODE && def->wield_image == "") { need_node_mesh = true; } else if(def->wield_image != "" || def->inventory_image != "") { // Extrude the wield image into a mesh std::string imagename; if(def->wield_image != "") imagename = def->wield_image; else imagename = def->inventory_image; def->wield_mesh = createExtrudedMesh( tsrc->getTextureRaw(imagename), driver, def->wield_scale * v3f(40.0, 40.0, 4.0)); if(def->wield_mesh == NULL) { infostream<<"ItemDefManager: WARNING: " <<"updateTexturesAndMeshes(): " <<"Unable to create extruded mesh for item " <<def->name<<std::endl; } } if(need_node_mesh) { /* Get node properties */ content_t id = nodedef->getId(def->name); const ContentFeatures &f = nodedef->get(id); u8 param1 = 0; if(f.param_type == CPT_LIGHT) param1 = 0xee; /* Make a mesh from the node */ MeshMakeData mesh_make_data(gamedef); MapNode mesh_make_node(id, param1, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data); scene::IMesh *node_mesh = mapblock_mesh.getMesh(); assert(node_mesh); setMeshColor(node_mesh, video::SColor(255, 255, 255, 255)); /* Scale and translate the mesh so it's a unit cube centered on the origin */ scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS)); translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0)); /* Draw node mesh into a render target texture */ if(def->inventory_texture == NULL) { core::dimension2d<u32> dim(64,64); std::string rtt_texture_name = "INVENTORY_" + def->name + "_RTT"; v3f camera_position(0, 1.0, -1.5); camera_position.rotateXZBy(45); v3f camera_lookat(0, 0, 0); core::CMatrix4<f32> camera_projection_matrix; // Set orthogonal projection camera_projection_matrix.buildProjectionMatrixOrthoLH( 1.65, 1.65, 0, 100); video::SColorf ambient_light(0.2,0.2,0.2); v3f light_position(10, 100, -50); video::SColorf light_color(0.5,0.5,0.5); f32 light_radius = 1000; def->inventory_texture = generateTextureFromMesh( node_mesh, device, dim, rtt_texture_name, camera_position, camera_lookat, camera_projection_matrix, ambient_light, light_position, light_color, light_radius); // render-to-target didn't work if(def->inventory_texture == NULL) { def->inventory_texture = tsrc->getTextureRaw(f.tname_tiles[0]); } } /* Use the node mesh as the wield mesh */ if(def->wield_mesh == NULL) { // Scale to proper wield mesh proportions scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0) * def->wield_scale); def->wield_mesh = node_mesh; def->wield_mesh->grab(); } // falling outside of here deletes node_mesh } } #endif }
void mapblock_mesh_generate_special(MeshMakeData *data, MeshCollector &collector, IGameDef *gamedef) { INodeDefManager *nodedef = gamedef->ndef(); // 0ms //TimeTaker timer("mapblock_mesh_generate_special()"); /* Some settings */ bool new_style_water = g_settings->getBool("new_style_water"); float node_liquid_level = 1.0; if(new_style_water) node_liquid_level = 0.85; v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE; /*// General ground material for special output // Texture is modified just before usage video::SMaterial material_general; material_general.setFlag(video::EMF_LIGHTING, false); material_general.setFlag(video::EMF_BILINEAR_FILTER, false); material_general.setFlag(video::EMF_FOG_ENABLE, true); material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;*/ for(s16 z=0; z<MAP_BLOCKSIZE; z++) for(s16 y=0; y<MAP_BLOCKSIZE; y++) for(s16 x=0; x<MAP_BLOCKSIZE; x++) { v3s16 p(x,y,z); MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p); const ContentFeatures &f = nodedef->get(n); // Only solidness=0 stuff is drawn here if(f.solidness != 0) continue; switch(f.drawtype){ default: infostream<<"Got "<<f.drawtype<<std::endl; assert(0); break; case NDT_AIRLIKE: break; case NDT_LIQUID: { /* Add water sources to mesh if using new style */ assert(nodedef->get(n).special_materials[0]); //assert(nodedef->get(n).special_materials[1]); assert(nodedef->get(n).special_aps[0]); video::SMaterial &liquid_material = *nodedef->get(n).special_materials[0]; /*video::SMaterial &liquid_material_bfculled = *nodedef->get(n).special_materials[1];*/ AtlasPointer &pa_liquid1 = *nodedef->get(n).special_aps[0]; bool top_is_air = false; MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); if(n.getContent() == CONTENT_AIR) top_is_air = true; if(top_is_air == false) continue; u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef)); video::SColor c = MapBlock_LightColor( nodedef->get(n).alpha, l); video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x0(), pa_liquid1.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x1(), pa_liquid1.y1()), video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, pa_liquid1.x1(), pa_liquid1.y0()), video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, pa_liquid1.x0(), pa_liquid1.y0()), }; for(s32 i=0; i<4; i++) { vertices[i].Pos.Y += (-0.5+node_liquid_level)*BS; vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(liquid_material, vertices, 4, indices, 6); break;} case NDT_FLOWINGLIQUID: { /* Add flowing liquid to mesh */ assert(nodedef->get(n).special_materials[0]); assert(nodedef->get(n).special_materials[1]); assert(nodedef->get(n).special_aps[0]); video::SMaterial &liquid_material = *nodedef->get(n).special_materials[0]; video::SMaterial &liquid_material_bfculled = *nodedef->get(n).special_materials[1]; AtlasPointer &pa_liquid1 = *nodedef->get(n).special_aps[0]; bool top_is_same_liquid = false; MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); content_t c_flowing = nodedef->getId(nodedef->get(n).liquid_alternative_flowing); content_t c_source = nodedef->getId(nodedef->get(n).liquid_alternative_source); if(ntop.getContent() == c_flowing || ntop.getContent() == c_source) top_is_same_liquid = true; u8 l = 0; // Use the light of the node on top if possible if(nodedef->get(ntop).param_type == CPT_LIGHT) l = decode_light(ntop.getLightBlend(data->m_daynight_ratio, nodedef)); // Otherwise use the light of this node (the liquid) else l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef)); video::SColor c = MapBlock_LightColor( nodedef->get(n).alpha, l); // Neighbor liquid levels (key = relative position) // Includes current node core::map<v3s16, f32> neighbor_levels; core::map<v3s16, content_t> neighbor_contents; core::map<v3s16, u8> neighbor_flags; const u8 neighborflag_top_is_same_liquid = 0x01; v3s16 neighbor_dirs[9] = { v3s16(0,0,0), v3s16(0,0,1), v3s16(0,0,-1), v3s16(1,0,0), v3s16(-1,0,0), v3s16(1,0,1), v3s16(-1,0,-1), v3s16(1,0,-1), v3s16(-1,0,1), }; for(u32 i=0; i<9; i++) { content_t content = CONTENT_AIR; float level = -0.5 * BS; u8 flags = 0; // Check neighbor v3s16 p2 = p + neighbor_dirs[i]; MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); if(n2.getContent() != CONTENT_IGNORE) { content = n2.getContent(); if(n2.getContent() == c_source) level = (-0.5+node_liquid_level) * BS; else if(n2.getContent() == c_flowing) level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK) + 0.5) / 8.0 * node_liquid_level) * BS; // Check node above neighbor. // NOTE: This doesn't get executed if neighbor // doesn't exist p2.Y += 1; n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); if(n2.getContent() == c_source || n2.getContent() == c_flowing) flags |= neighborflag_top_is_same_liquid; } neighbor_levels.insert(neighbor_dirs[i], level); neighbor_contents.insert(neighbor_dirs[i], content); neighbor_flags.insert(neighbor_dirs[i], flags); } // Corner heights (average between four liquids) f32 corner_levels[4]; v3s16 halfdirs[4] = { v3s16(0,0,0), v3s16(1,0,0), v3s16(1,0,1), v3s16(0,0,1), }; for(u32 i=0; i<4; i++) { v3s16 cornerdir = halfdirs[i]; float cornerlevel = 0; u32 valid_count = 0; u32 air_count = 0; for(u32 j=0; j<4; j++) { v3s16 neighbordir = cornerdir - halfdirs[j]; content_t content = neighbor_contents[neighbordir]; // If top is liquid, draw starting from top of node if(neighbor_flags[neighbordir] & neighborflag_top_is_same_liquid) { cornerlevel = 0.5*BS; valid_count = 1; break; } // Source is always the same height else if(content == c_source) { cornerlevel = (-0.5+node_liquid_level)*BS; valid_count = 1; break; } // Flowing liquid has level information else if(content == c_flowing) { cornerlevel += neighbor_levels[neighbordir]; valid_count++; } else if(content == CONTENT_AIR) { air_count++; } } if(air_count >= 2) cornerlevel = -0.5*BS; else if(valid_count > 0) cornerlevel /= valid_count; corner_levels[i] = cornerlevel; } /* Generate sides */ v3s16 side_dirs[4] = { v3s16(1,0,0), v3s16(-1,0,0), v3s16(0,0,1), v3s16(0,0,-1), }; s16 side_corners[4][2] = { {1, 2}, {3, 0}, {2, 3}, {0, 1}, }; for(u32 i=0; i<4; i++) { v3s16 dir = side_dirs[i]; /* If our topside is liquid and neighbor's topside is liquid, don't draw side face */ if(top_is_same_liquid && neighbor_flags[dir] & neighborflag_top_is_same_liquid) continue; content_t neighbor_content = neighbor_contents[dir]; const ContentFeatures &n_feat = nodedef->get(neighbor_content); // Don't draw face if neighbor is blocking the view if(n_feat.solidness == 2) continue; bool neighbor_is_same_liquid = (neighbor_content == c_source || neighbor_content == c_flowing); // Don't draw any faces if neighbor same is liquid and top is // same liquid if(neighbor_is_same_liquid == true && top_is_same_liquid == false) continue; // Use backface culled material if neighbor doesn't have a // solidness of 0 video::SMaterial *current_material = &liquid_material; if(n_feat.solidness != 0 || n_feat.visual_solidness != 0) current_material = &liquid_material_bfculled; video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x0(), pa_liquid1.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x1(), pa_liquid1.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x1(), pa_liquid1.y0()), video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x0(), pa_liquid1.y0()), }; /* If our topside is liquid, set upper border of face at upper border of node */ if(top_is_same_liquid) { vertices[2].Pos.Y = 0.5*BS; vertices[3].Pos.Y = 0.5*BS; } /* Otherwise upper position of face is corner levels */ else { vertices[2].Pos.Y = corner_levels[side_corners[i][0]]; vertices[3].Pos.Y = corner_levels[side_corners[i][1]]; } /* If neighbor is liquid, lower border of face is corner liquid levels */ if(neighbor_is_same_liquid) { vertices[0].Pos.Y = corner_levels[side_corners[i][1]]; vertices[1].Pos.Y = corner_levels[side_corners[i][0]]; } /* If neighbor is not liquid, lower border of face is lower border of node */ else { vertices[0].Pos.Y = -0.5*BS; vertices[1].Pos.Y = -0.5*BS; } for(s32 j=0; j<4; j++) { if(dir == v3s16(0,0,1)) vertices[j].Pos.rotateXZBy(0); if(dir == v3s16(0,0,-1)) vertices[j].Pos.rotateXZBy(180); if(dir == v3s16(-1,0,0)) vertices[j].Pos.rotateXZBy(90); if(dir == v3s16(1,0,-0)) vertices[j].Pos.rotateXZBy(-90); // Do this to not cause glitches when two liquids are // side-by-side /*if(neighbor_is_same_liquid == false){ vertices[j].Pos.X *= 0.98; vertices[j].Pos.Z *= 0.98; }*/ vertices[j].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(*current_material, vertices, 4, indices, 6); } /* Generate top side, if appropriate */ if(top_is_same_liquid == false) { video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x0(), pa_liquid1.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid1.x1(), pa_liquid1.y1()), video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, pa_liquid1.x1(), pa_liquid1.y0()), video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, pa_liquid1.x0(), pa_liquid1.y0()), }; // This fixes a strange bug s32 corner_resolve[4] = {3,2,1,0}; for(s32 i=0; i<4; i++) { //vertices[i].Pos.Y += liquid_level; //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)]; s32 j = corner_resolve[i]; vertices[i].Pos.Y += corner_levels[j]; vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(liquid_material, vertices, 4, indices, 6); } break;} case NDT_GLASSLIKE: { video::SMaterial material_glass; material_glass.setFlag(video::EMF_LIGHTING, false); material_glass.setFlag(video::EMF_BILINEAR_FILTER, false); material_glass.setFlag(video::EMF_FOG_ENABLE, true); material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; AtlasPointer pa_glass = f.tiles[0].texture; material_glass.setTexture(0, pa_glass.atlas); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); video::SColor c = MapBlock_LightColor(255, l); for(u32 j=0; j<6; j++) { // Check this neighbor v3s16 n2p = blockpos_nodes + p + g_6dirs[j]; MapNode n2 = data->m_vmanip.getNodeNoEx(n2p); // Don't make face if neighbor is of same type if(n2.getContent() == n.getContent()) continue; // The face at Z+ video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, pa_glass.x0(), pa_glass.y1()), video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, pa_glass.x1(), pa_glass.y1()), video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, pa_glass.x1(), pa_glass.y0()), video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, pa_glass.x0(), pa_glass.y0()), }; // Rotations in the g_6dirs format if(j == 0) // Z+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(0); else if(j == 1) // Y+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(-90); else if(j == 2) // X+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-90); else if(j == 3) // Z- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(180); else if(j == 4) // Y- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(90); else if(j == 5) // X- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(90); for(u16 i=0; i<4; i++){ vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(material_glass, vertices, 4, indices, 6); } break;} case NDT_ALLFACES: { video::SMaterial material_leaves1; material_leaves1.setFlag(video::EMF_LIGHTING, false); material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false); material_leaves1.setFlag(video::EMF_FOG_ENABLE, true); material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; AtlasPointer pa_leaves1 = f.tiles[0].texture; material_leaves1.setTexture(0, pa_leaves1.atlas); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); video::SColor c = MapBlock_LightColor(255, l); for(u32 j=0; j<6; j++) { video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, pa_leaves1.x0(), pa_leaves1.y1()), video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, pa_leaves1.x1(), pa_leaves1.y1()), video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, pa_leaves1.x1(), pa_leaves1.y0()), video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, pa_leaves1.x0(), pa_leaves1.y0()), }; // Rotations in the g_6dirs format if(j == 0) // Z+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(0); else if(j == 1) // Y+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(-90); else if(j == 2) // X+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-90); else if(j == 3) // Z- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(180); else if(j == 4) // Y- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(90); else if(j == 5) // X- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(90); for(u16 i=0; i<4; i++){ vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(material_leaves1, vertices, 4, indices, 6); } break;} case NDT_ALLFACES_OPTIONAL: // This is always pre-converted to something else assert(0); break; case NDT_TORCHLIKE: { v3s16 dir = unpackDir(n.param2); AtlasPointer ap(0); if(dir == v3s16(0,-1,0)){ ap = f.tiles[0].texture; // floor } else if(dir == v3s16(0,1,0)){ ap = f.tiles[1].texture; // ceiling // For backwards compatibility } else if(dir == v3s16(0,0,0)){ ap = f.tiles[0].texture; // floor } else { ap = f.tiles[2].texture; // side } // Set material video::SMaterial material; material.setFlag(video::EMF_LIGHTING, false); material.setFlag(video::EMF_BACK_FACE_CULLING, false); material.setFlag(video::EMF_BILINEAR_FILTER, false); material.setFlag(video::EMF_FOG_ENABLE, true); //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; material.setTexture(0, ap.atlas); video::SColor c(255,255,255,255); // Wall at X+ of node video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, ap.x0(), ap.y0()), }; for(s32 i=0; i<4; i++) { if(dir == v3s16(1,0,0)) vertices[i].Pos.rotateXZBy(0); if(dir == v3s16(-1,0,0)) vertices[i].Pos.rotateXZBy(180); if(dir == v3s16(0,0,1)) vertices[i].Pos.rotateXZBy(90); if(dir == v3s16(0,0,-1)) vertices[i].Pos.rotateXZBy(-90); if(dir == v3s16(0,-1,0)) vertices[i].Pos.rotateXZBy(45); if(dir == v3s16(0,1,0)) vertices[i].Pos.rotateXZBy(-45); vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(material, vertices, 4, indices, 6); break;} case NDT_SIGNLIKE: { // Set material video::SMaterial material; material.setFlag(video::EMF_LIGHTING, false); material.setFlag(video::EMF_BACK_FACE_CULLING, false); material.setFlag(video::EMF_BILINEAR_FILTER, false); material.setFlag(video::EMF_FOG_ENABLE, true); material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; AtlasPointer ap = f.tiles[0].texture; material.setTexture(0, ap.atlas); u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef)); video::SColor c = MapBlock_LightColor(255, l); float d = (float)BS/16; // Wall at X+ of node video::S3DVertex vertices[4] = { video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, ap.x0(), ap.y0()), }; v3s16 dir = unpackDir(n.param2); for(s32 i=0; i<4; i++) { if(dir == v3s16(1,0,0)) vertices[i].Pos.rotateXZBy(0); if(dir == v3s16(-1,0,0)) vertices[i].Pos.rotateXZBy(180); if(dir == v3s16(0,0,1)) vertices[i].Pos.rotateXZBy(90); if(dir == v3s16(0,0,-1)) vertices[i].Pos.rotateXZBy(-90); if(dir == v3s16(0,-1,0)) vertices[i].Pos.rotateXYBy(-90); if(dir == v3s16(0,1,0)) vertices[i].Pos.rotateXYBy(90); vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(material, vertices, 4, indices, 6); break;} case NDT_PLANTLIKE: { video::SMaterial material_papyrus; material_papyrus.setFlag(video::EMF_LIGHTING, false); material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false); material_papyrus.setFlag(video::EMF_FOG_ENABLE, true); material_papyrus.MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; AtlasPointer pa_papyrus = f.tiles[0].texture; material_papyrus.setTexture(0, pa_papyrus.atlas); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); video::SColor c = MapBlock_LightColor(255, l); for(u32 j=0; j<4; j++) { video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, pa_papyrus.x0(), pa_papyrus.y1()), video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, pa_papyrus.x1(), pa_papyrus.y1()), video::S3DVertex( BS/2*f.visual_scale, -BS/2 + f.visual_scale*BS,0, 0,0,0, c, pa_papyrus.x1(), pa_papyrus.y0()), video::S3DVertex(-BS/2*f.visual_scale, -BS/2 + f.visual_scale*BS,0, 0,0,0, c, pa_papyrus.x0(), pa_papyrus.y0()), }; if(j == 0) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(45); } else if(j == 1) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-45); } else if(j == 2) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(135); } else if(j == 3) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-135); } for(u16 i=0; i<4; i++) { vertices[i].Pos *= f.visual_scale; vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(material_papyrus, vertices, 4, indices, 6); } break;} case NDT_FENCELIKE: { video::SMaterial material_wood; material_wood.setFlag(video::EMF_LIGHTING, false); material_wood.setFlag(video::EMF_BILINEAR_FILTER, false); material_wood.setFlag(video::EMF_FOG_ENABLE, true); material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; AtlasPointer pa_wood = f.tiles[0].texture; material_wood.setTexture(0, pa_wood.atlas); u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio, nodedef))); video::SColor c = MapBlock_LightColor(255, l); const f32 post_rad=(f32)BS/10; const f32 bar_rad=(f32)BS/20; const f32 bar_len=(f32)(BS/2)-post_rad; // The post - always present v3f pos = intToFloat(p+blockpos_nodes, BS); f32 postuv[24]={ 0.4,0.4,0.6,0.6, 0.35,0,0.65,1, 0.35,0,0.65,1, 0.35,0,0.65,1, 0.35,0,0.65,1, 0.4,0.4,0.6,0.6}; makeCuboid(material_wood, &collector, &pa_wood, c, pos, post_rad,BS/2,post_rad, postuv); // Now a section of fence, +X, if there's a post there v3s16 p2 = p; p2.X++; MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); const ContentFeatures *f2 = &nodedef->get(n2); if(f2->drawtype == NDT_FENCELIKE) { pos = intToFloat(p+blockpos_nodes, BS); pos.X += BS/2; pos.Y += BS/4; f32 xrailuv[24]={ 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6}; makeCuboid(material_wood, &collector, &pa_wood, c, pos, bar_len,bar_rad,bar_rad, xrailuv); pos.Y -= BS/2; makeCuboid(material_wood, &collector, &pa_wood, c, pos, bar_len,bar_rad,bar_rad, xrailuv); } // Now a section of fence, +Z, if there's a post there p2 = p; p2.Z++; n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); f2 = &nodedef->get(n2); if(f2->drawtype == NDT_FENCELIKE) { pos = intToFloat(p+blockpos_nodes, BS); pos.Z += BS/2; pos.Y += BS/4; f32 zrailuv[24]={ 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6}; makeCuboid(material_wood, &collector, &pa_wood, c, pos, bar_rad,bar_rad,bar_len, zrailuv); pos.Y -= BS/2; makeCuboid(material_wood, &collector, &pa_wood, c, pos, bar_rad,bar_rad,bar_len, zrailuv); } break;} case NDT_RAILLIKE: { bool is_rail_x [] = { false, false }; /* x-1, x+1 */ bool is_rail_z [] = { false, false }; /* z-1, z+1 */ MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z)); MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z)); MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1)); MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1)); content_t thiscontent = n.getContent(); if(n_minus_x.getContent() == thiscontent) is_rail_x[0] = true; if(n_plus_x.getContent() == thiscontent) is_rail_x[1] = true; if(n_minus_z.getContent() == thiscontent) is_rail_z[0] = true; if(n_plus_z.getContent() == thiscontent) is_rail_z[1] = true; int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1]; // Assign textures AtlasPointer ap = f.tiles[0].texture; // straight if(adjacencies < 2) ap = f.tiles[0].texture; // straight else if(adjacencies == 2) { if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1])) ap = f.tiles[0].texture; // straight else ap = f.tiles[1].texture; // curved } else if(adjacencies == 3) ap = f.tiles[2].texture; // t-junction else if(adjacencies == 4) ap = f.tiles[3].texture; // crossing video::SMaterial material_rail; material_rail.setFlag(video::EMF_LIGHTING, false); material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false); material_rail.setFlag(video::EMF_BILINEAR_FILTER, false); material_rail.setFlag(video::EMF_FOG_ENABLE, true); material_rail.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; material_rail.setTexture(0, ap.atlas); u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio, nodedef)); video::SColor c = MapBlock_LightColor(255, l); float d = (float)BS/16; video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c, ap.x0(), ap.y0()), }; // Rotate textures int angle = 0; if(adjacencies == 1) { if(is_rail_x[0] || is_rail_x[1]) angle = 90; } else if(adjacencies == 2) { if(is_rail_x[0] && is_rail_x[1]) angle = 90; else if(is_rail_x[0] && is_rail_z[0]) angle = 270; else if(is_rail_x[0] && is_rail_z[1]) angle = 180; else if(is_rail_x[1] && is_rail_z[1]) angle = 90; } else if(adjacencies == 3) { if(!is_rail_x[0]) angle=0; if(!is_rail_x[1]) angle=180; if(!is_rail_z[0]) angle=90; if(!is_rail_z[1]) angle=270; } if(angle != 0) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(angle); } for(s32 i=0; i<4; i++) { vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } u16 indices[] = {0,1,2,2,3,0}; collector.append(material_rail, vertices, 4, indices, 6); break;} } } }
void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef) { ITextureSource *tsrc = gamedef->getTextureSource(); IItemDefManager *idef = gamedef->getItemDefManager(); //IShaderSource *shdrsrc = gamedef->getShaderSource(); INodeDefManager *ndef = gamedef->getNodeDefManager(); const ItemDefinition &def = item.getDefinition(idef); const ContentFeatures &f = ndef->get(def.name); content_t id = ndef->getId(def.name); #if 0 //// TODO(RealBadAngel): Reactivate when shader is added for wield items if (m_enable_shaders) { u32 shader_id = shdrsrc->getShader("nodes_shader", TILE_MATERIAL_BASIC, NDT_NORMAL); m_material_type = shdrsrc->getShaderInfo(shader_id).material; } #endif // If wield_image is defined, it overrides everything else if (def.wield_image != "") { setExtruded(def.wield_image, def.wield_scale, tsrc, 1); return; } // Handle nodes // See also CItemDefManager::createClientCached() else if (def.type == ITEM_NODE) { if (f.mesh_ptr[0]) { // e.g. mesh nodes and nodeboxes changeToMesh(f.mesh_ptr[0]); // mesh_ptr[0] is pre-scaled by BS * f->visual_scale m_meshnode->setScale( def.wield_scale * WIELD_SCALE_FACTOR / (BS * f.visual_scale)); } else if (f.drawtype == NDT_AIRLIKE) { changeToMesh(NULL); } else if (f.drawtype == NDT_PLANTLIKE) { setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count); } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) { setCube(f.tiles, def.wield_scale, tsrc); } else { //// TODO: Change false in the following constructor args to //// appropriate value when shader is added for wield items (if applicable) MeshMakeData mesh_make_data(gamedef, false); MapNode mesh_make_node(id, 255, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); changeToMesh(mapblock_mesh.getMesh()); translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS)); m_meshnode->setScale( def.wield_scale * WIELD_SCALE_FACTOR / (BS * f.visual_scale)); } u32 material_count = m_meshnode->getMaterialCount(); if (material_count > 6) { errorstream << "WieldMeshSceneNode::setItem: Invalid material " "count " << material_count << ", truncating to 6" << std::endl; material_count = 6; } for (u32 i = 0; i < material_count; ++i) { video::SMaterial &material = m_meshnode->getMaterial(i); material.setFlag(video::EMF_BACK_FACE_CULLING, true); material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter); material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter); bool animated = (f.tiles[i].animation_frame_count > 1); if (animated) { FrameSpec animation_frame = f.tiles[i].frames[0]; material.setTexture(0, animation_frame.texture); } else { material.setTexture(0, f.tiles[i].texture); } material.MaterialType = m_material_type; #if 0 //// TODO(RealBadAngel): Reactivate when shader is added for wield items if (m_enable_shaders) { if (f.tiles[i].normal_texture) { if (animated) { FrameSpec animation_frame = f.tiles[i].frames[0]; material.setTexture(1, animation_frame.normal_texture); } else { material.setTexture(1, f.tiles[i].normal_texture); } material.setTexture(2, tsrc->getTexture("enable_img.png")); } else { material.setTexture(2, tsrc->getTexture("disable_img.png")); } } #endif } return; } else if (def.inventory_image != "") { setExtruded(def.inventory_image, def.wield_scale, tsrc, 1); return; } // no wield mesh found changeToMesh(NULL); }
MapgenFractal::MapgenFractal(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { this->m_emerge = emerge; this->bmgr = emerge->biomemgr; //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; this->zstride = csize.X * (csize.Y + 2); this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z]; this->heatmap = NULL; this->humidmap = NULL; MapgenFractalParams *sp = (MapgenFractalParams *)params->sparams; this->spflags = sp->spflags; this->fractal = sp->fractal; this->iterations = sp->iterations; this->scale = sp->scale; this->offset = sp->offset; this->slice_w = sp->slice_w; this->julia_x = sp->julia_x; this->julia_y = sp->julia_y; this->julia_z = sp->julia_z; this->julia_w = sp->julia_w; this->formula = fractal / 2 + fractal % 2; this->julia = fractal % 2 == 0; //// 2D terrain noise noise_seabed = new Noise(&sp->np_seabed, seed, csize.X, csize.Z); noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); //// 3D terrain noise noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z); //// Biome noise noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z); noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z); noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z); noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_stone = ndef->getId("mapgen_stone"); c_water_source = ndef->getId("mapgen_water_source"); c_lava_source = ndef->getId("mapgen_lava_source"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_ice = ndef->getId("mapgen_ice"); c_sandstone = ndef->getId("mapgen_sandstone"); c_cobble = ndef->getId("mapgen_cobble"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_mossycobble = ndef->getId("mapgen_mossycobble"); c_sandstonebrick = ndef->getId("mapgen_sandstonebrick"); c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick"); if (c_ice == CONTENT_IGNORE) c_ice = CONTENT_AIR; if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; if (c_sandstonebrick == CONTENT_IGNORE) c_sandstonebrick = c_sandstone; if (c_stair_sandstonebrick == CONTENT_IGNORE) c_stair_sandstonebrick = c_sandstone; }
void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client) { ITextureSource *tsrc = client->getTextureSource(); IItemDefManager *idef = client->getItemDefManager(); IShaderSource *shdrsrc = client->getShaderSource(); INodeDefManager *ndef = client->getNodeDefManager(); const ItemDefinition &def = item.getDefinition(idef); const ContentFeatures &f = ndef->get(def.name); content_t id = ndef->getId(def.name); if (m_enable_shaders) { u32 shader_id = shdrsrc->getShader("wielded_shader", TILE_MATERIAL_BASIC, NDT_NORMAL); m_material_type = shdrsrc->getShaderInfo(shader_id).material; } m_colors.clear(); // If wield_image is defined, it overrides everything else if (def.wield_image != "") { setExtruded(def.wield_image, def.wield_scale, tsrc, 1); return; } // Handle nodes // See also CItemDefManager::createClientCached() else if (def.type == ITEM_NODE) { if (f.mesh_ptr[0]) { // e.g. mesh nodes and nodeboxes changeToMesh(f.mesh_ptr[0]); // mesh_ptr[0] is pre-scaled by BS * f->visual_scale m_meshnode->setScale( def.wield_scale * WIELD_SCALE_FACTOR / (BS * f.visual_scale)); } else if (f.drawtype == NDT_AIRLIKE) { changeToMesh(NULL); } else if (f.drawtype == NDT_PLANTLIKE) { setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count); } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) { setCube(f.tiles, def.wield_scale, tsrc); } else { MeshMakeData mesh_make_data(client, false); MapNode mesh_make_node(id, 255, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); changeToMesh(mapblock_mesh.getMesh()); translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS)); m_meshnode->setScale( def.wield_scale * WIELD_SCALE_FACTOR / (BS * f.visual_scale)); } u32 material_count = m_meshnode->getMaterialCount(); if (material_count > 6) { errorstream << "WieldMeshSceneNode::setItem: Invalid material " "count " << material_count << ", truncating to 6" << std::endl; material_count = 6; } for (u32 i = 0; i < material_count; ++i) { const TileSpec *tile = &(f.tiles[i]); video::SMaterial &material = m_meshnode->getMaterial(i); material.setFlag(video::EMF_BACK_FACE_CULLING, true); material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter); material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter); bool animated = (tile->animation_frame_count > 1); if (animated) { FrameSpec animation_frame = tile->frames[0]; material.setTexture(0, animation_frame.texture); } else { material.setTexture(0, tile->texture); } m_colors.push_back(tile->color); material.MaterialType = m_material_type; if (m_enable_shaders) { if (tile->normal_texture) { if (animated) { FrameSpec animation_frame = tile->frames[0]; material.setTexture(1, animation_frame.normal_texture); } else { material.setTexture(1, tile->normal_texture); } } material.setTexture(2, tile->flags_texture); } } return; } else if (def.inventory_image != "") { setExtruded(def.inventory_image, def.wield_scale, tsrc, 1); return; } // no wield mesh found changeToMesh(NULL); }
ClientCached* createClientCachedDirect(const std::string &name, IGameDef *gamedef) const { infostream<<"Lazily creating item texture and mesh for \"" <<name<<"\""<<std::endl; // This is not thread-safe assert(get_current_thread_id() == m_main_thread); // Skip if already in cache ClientCached *cc = NULL; m_clientcached.get(name, &cc); if(cc) return cc; ITextureSource *tsrc = gamedef->getTextureSource(); INodeDefManager *nodedef = gamedef->getNodeDefManager(); IrrlichtDevice *device = tsrc->getDevice(); video::IVideoDriver *driver = device->getVideoDriver(); const ItemDefinition *def = &get(name); // Create new ClientCached cc = new ClientCached(); bool need_node_mesh = false; // Create an inventory texture cc->inventory_texture = NULL; if(def->inventory_image != "") { cc->inventory_texture = tsrc->getTextureRaw(def->inventory_image); } else if(def->type == ITEM_NODE) { need_node_mesh = true; } // Create a wield mesh assert(cc->wield_mesh == NULL); if(def->type == ITEM_NODE && def->wield_image == "") { need_node_mesh = true; } else if(def->wield_image != "" || def->inventory_image != "") { // Extrude the wield image into a mesh std::string imagename; if(def->wield_image != "") imagename = def->wield_image; else imagename = def->inventory_image; cc->wield_mesh = createExtrudedMesh( tsrc->getTextureRaw(imagename), driver, def->wield_scale * v3f(40.0, 40.0, 4.0)); if(cc->wield_mesh == NULL) { infostream<<"ItemDefManager: WARNING: " <<"updateTexturesAndMeshes(): " <<"Unable to create extruded mesh for item " <<def->name<<std::endl; } } if(need_node_mesh) { /* Get node properties */ content_t id = nodedef->getId(def->name); const ContentFeatures &f = nodedef->get(id); u8 param1 = 0; if(f.param_type == CPT_LIGHT) param1 = 0xee; /* Make a mesh from the node */ MeshMakeData mesh_make_data(gamedef); MapNode mesh_make_node(id, param1, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data); scene::IMesh *node_mesh = mapblock_mesh.getMesh(); assert(node_mesh); video::SColor c(255, 255, 255, 255); if(g_settings->getS32("enable_shaders") != 0) c = MapBlock_LightColor(255, 0xffff, decode_light(f.light_source)); setMeshColor(node_mesh, c); /* Scale and translate the mesh so it's a unit cube centered on the origin */ scaleMesh(node_mesh, v3f(1.0/BS, 1.0/BS, 1.0/BS)); translateMesh(node_mesh, v3f(-1.0, -1.0, -1.0)); /* Draw node mesh into a render target texture */ if(cc->inventory_texture == NULL) { core::dimension2d<u32> dim(64,64); std::string rtt_texture_name = "INVENTORY_" + def->name + "_RTT"; v3f camera_position(0, 1.0, -1.5); camera_position.rotateXZBy(45); v3f camera_lookat(0, 0, 0); core::CMatrix4<f32> camera_projection_matrix; // Set orthogonal projection camera_projection_matrix.buildProjectionMatrixOrthoLH( 1.65, 1.65, 0, 100); video::SColorf ambient_light(0.2,0.2,0.2); v3f light_position(10, 100, -50); video::SColorf light_color(0.5,0.5,0.5); f32 light_radius = 1000; cc->inventory_texture = generateTextureFromMesh( node_mesh, device, dim, rtt_texture_name, camera_position, camera_lookat, camera_projection_matrix, ambient_light, light_position, light_color, light_radius); // render-to-target didn't work if(cc->inventory_texture == NULL) { cc->inventory_texture = tsrc->getTextureRaw(f.tiledef[0].name); } } else { if (m_driver == 0) m_driver = driver; m_extruded_textures.push_back(cc->inventory_texture); } /* Use the node mesh as the wield mesh */ // Scale to proper wield mesh proportions scaleMesh(node_mesh, v3f(30.0, 30.0, 30.0) * def->wield_scale); cc->wield_mesh = node_mesh; cc->wield_mesh->grab(); //no way reference count can be smaller than 2 in this place! assert(cc->wield_mesh->getReferenceCount() >= 2); } // Put in cache m_clientcached.set(name, cc); return cc; }
scene::IMesh *getItemMesh(Client *client, const ItemStack &item) { ITextureSource *tsrc = client->getTextureSource(); IItemDefManager *idef = client->getItemDefManager(); INodeDefManager *ndef = client->getNodeDefManager(); const ItemDefinition &def = item.getDefinition(idef); const ContentFeatures &f = ndef->get(def.name); content_t id = ndef->getId(def.name); if (!g_extrusion_mesh_cache) { g_extrusion_mesh_cache = new ExtrusionMeshCache(); } else { g_extrusion_mesh_cache->grab(); } scene::IMesh *mesh; // If inventory_image is defined, it overrides everything else if (def.inventory_image != "") { mesh = getExtrudedMesh(tsrc, def.inventory_image); return mesh; } else if (def.type == ITEM_NODE) { if (f.mesh_ptr[0]) { mesh = cloneMesh(f.mesh_ptr[0]); scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); setMeshColor(mesh, video::SColor (255, 255, 255, 255)); } else if (f.drawtype == NDT_PLANTLIKE) { mesh = getExtrudedMesh(tsrc, tsrc->getTextureName(f.tiles[0].texture_id)); } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES || f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) { mesh = cloneMesh(g_extrusion_mesh_cache->createCube()); scaleMesh(mesh, v3f(1.2, 1.2, 1.2)); } else { MeshMakeData mesh_make_data(client, false); MapNode mesh_make_node(id, 255, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); mesh = cloneMesh(mapblock_mesh.getMesh()); translateMesh(mesh, v3f(-BS, -BS, -BS)); scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); u32 mc = mesh->getMeshBufferCount(); for (u32 i = 0; i < mc; ++i) { video::SMaterial &material1 = mesh->getMeshBuffer(i)->getMaterial(); video::SMaterial &material2 = mapblock_mesh.getMesh()->getMeshBuffer(i)->getMaterial(); material1.setTexture(0, material2.getTexture(0)); material1.setTexture(1, material2.getTexture(1)); material1.setTexture(2, material2.getTexture(2)); material1.setTexture(3, material2.getTexture(3)); material1.MaterialType = material2.MaterialType; } } u32 mc = mesh->getMeshBufferCount(); for (u32 i = 0; i < mc; ++i) { const TileSpec *tile = &(f.tiles[i]); scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); colorizeMeshBuffer(buf, &tile->color); video::SMaterial &material = buf->getMaterial(); material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.setFlag(video::EMF_BILINEAR_FILTER, false); material.setFlag(video::EMF_TRILINEAR_FILTER, false); material.setFlag(video::EMF_BACK_FACE_CULLING, true); material.setFlag(video::EMF_LIGHTING, false); if (tile->animation_frame_count > 1) { FrameSpec animation_frame = tile->frames[0]; material.setTexture(0, animation_frame.texture); } else { material.setTexture(0, tile->texture); } } rotateMeshXZby(mesh, -45); rotateMeshYZby(mesh, -30); return mesh; } return NULL; }
MapgenV7::MapgenV7(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { this->m_emerge = emerge; this->bmgr = emerge->biomemgr; //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; this->zstride = csize.X * (csize.Y + 2); this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z]; this->heatmap = NULL; this->humidmap = NULL; this->ridge_heightmap = new s16[csize.X * csize.Z]; MapgenV7Params *sp = (MapgenV7Params *)params->sparams; this->spflags = sp->spflags; //// Terrain noise noise_terrain_base = new Noise(&sp->np_terrain_base, seed, csize.X, csize.Z); noise_terrain_alt = new Noise(&sp->np_terrain_alt, seed, csize.X, csize.Z); noise_terrain_persist = new Noise(&sp->np_terrain_persist, seed, csize.X, csize.Z); noise_height_select = new Noise(&sp->np_height_select, seed, csize.X, csize.Z); noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); noise_mount_height = new Noise(&sp->np_mount_height, seed, csize.X, csize.Z); noise_ridge_uwater = new Noise(&sp->np_ridge_uwater, seed, csize.X, csize.Z); //// 3d terrain noise noise_mountain = new Noise(&sp->np_mountain, seed, csize.X, csize.Y + 2, csize.Z); noise_ridge = new Noise(&sp->np_ridge, seed, csize.X, csize.Y + 2, csize.Z); noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z); //// Biome noise noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z); noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z); noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z); noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_stone = ndef->getId("mapgen_stone"); c_water_source = ndef->getId("mapgen_water_source"); c_lava_source = ndef->getId("mapgen_lava_source"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_ice = ndef->getId("mapgen_ice"); c_sandstone = ndef->getId("mapgen_sandstone"); c_cobble = ndef->getId("mapgen_cobble"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_mossycobble = ndef->getId("mapgen_mossycobble"); c_sandstonebrick = ndef->getId("mapgen_sandstonebrick"); c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick"); if (c_ice == CONTENT_IGNORE) c_ice = CONTENT_AIR; if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; if (c_sandstonebrick == CONTENT_IGNORE) c_sandstonebrick = c_sandstone; if (c_stair_sandstonebrick == CONTENT_IGNORE) c_stair_sandstonebrick = c_sandstone; }
MapgenFlat::MapgenFlat(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { this->m_emerge = emerge; this->bmgr = emerge->biomemgr; //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; this->zstride = csize.X * (csize.Y + 2); this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z]; this->heatmap = NULL; this->humidmap = NULL; MapgenFlatParams *sp = (MapgenFlatParams *)params->sparams; this->spflags = sp->spflags; this->ground_level = sp->ground_level; this->large_cave_depth = sp->large_cave_depth; this->lake_threshold = sp->lake_threshold; this->lake_steepness = sp->lake_steepness; this->hill_threshold = sp->hill_threshold; this->hill_steepness = sp->hill_steepness; //// 2D noise noise_terrain = new Noise(&sp->np_terrain, seed, csize.X, csize.Z); noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); //// 3D noise noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z); //// Biome noise noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z); noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z); noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z); noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_stone = ndef->getId("mapgen_stone"); c_water_source = ndef->getId("mapgen_water_source"); c_lava_source = ndef->getId("mapgen_lava_source"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_ice = ndef->getId("mapgen_ice"); c_sandstone = ndef->getId("mapgen_sandstone"); c_cobble = ndef->getId("mapgen_cobble"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_mossycobble = ndef->getId("mapgen_mossycobble"); c_sandstonebrick = ndef->getId("mapgen_sandstonebrick"); c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick"); if (c_ice == CONTENT_IGNORE) c_ice = CONTENT_AIR; if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; if (c_sandstonebrick == CONTENT_IGNORE) c_sandstonebrick = c_sandstone; if (c_stair_sandstonebrick == CONTENT_IGNORE) c_stair_sandstonebrick = c_sandstone; }
void mapblock_mesh_generate_special(MeshMakeData *data, MeshCollector &collector) { INodeDefManager *nodedef = data->m_gamedef->ndef(); // 0ms //TimeTaker timer("mapblock_mesh_generate_special()"); /* Some settings */ bool new_style_water = g_settings->getBool("new_style_water"); float node_liquid_level = 1.0; if(new_style_water) node_liquid_level = 0.85; v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE; for(s16 z=0; z<MAP_BLOCKSIZE; z++) for(s16 y=0; y<MAP_BLOCKSIZE; y++) for(s16 x=0; x<MAP_BLOCKSIZE; x++) { v3s16 p(x,y,z); MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes+p); const ContentFeatures &f = nodedef->get(n); // Only solidness=0 stuff is drawn here if(f.solidness != 0) continue; switch(f.drawtype){ default: infostream<<"Got "<<f.drawtype<<std::endl; assert(0); break; case NDT_AIRLIKE: break; case NDT_LIQUID: { /* Add water sources to mesh if using new style */ TileSpec tile_liquid = f.special_tiles[0]; AtlasPointer &pa_liquid = tile_liquid.texture; bool top_is_air = false; MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); if(n.getContent() == CONTENT_AIR) top_is_air = true; if(top_is_air == false) continue; u16 l = getInteriorLight(n, 0, data); video::SColor c = MapBlock_LightColor(f.alpha, l); video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid.x0(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid.x1(), pa_liquid.y1()), video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, pa_liquid.x1(), pa_liquid.y0()), video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, pa_liquid.x0(), pa_liquid.y0()), }; v3f offset(p.X, p.Y + (-0.5+node_liquid_level)*BS, p.Z); for(s32 i=0; i<4; i++) { vertices[i].Pos += offset; } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(tile_liquid, vertices, 4, indices, 6); break;} case NDT_FLOWINGLIQUID: { /* Add flowing liquid to mesh */ TileSpec tile_liquid = f.special_tiles[0]; TileSpec tile_liquid_bfculled = f.special_tiles[1]; AtlasPointer &pa_liquid = tile_liquid.texture; bool top_is_same_liquid = false; MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing); content_t c_source = nodedef->getId(f.liquid_alternative_source); if(ntop.getContent() == c_flowing || ntop.getContent() == c_source) top_is_same_liquid = true; u16 l = 0; // If this liquid emits light and doesn't contain light, draw // it at what it emits, for an increased effect u8 light_source = nodedef->get(n).light_source; if(light_source != 0){ //l = decode_light(undiminish_light(light_source)); l = decode_light(light_source); l = l | (l<<8); } // Use the light of the node on top if possible else if(nodedef->get(ntop).param_type == CPT_LIGHT) l = getInteriorLight(ntop, 0, data); // Otherwise use the light of this node (the liquid) else l = getInteriorLight(n, 0, data); video::SColor c = MapBlock_LightColor(f.alpha, l); // Neighbor liquid levels (key = relative position) // Includes current node core::map<v3s16, f32> neighbor_levels; core::map<v3s16, content_t> neighbor_contents; core::map<v3s16, u8> neighbor_flags; const u8 neighborflag_top_is_same_liquid = 0x01; v3s16 neighbor_dirs[9] = { v3s16(0,0,0), v3s16(0,0,1), v3s16(0,0,-1), v3s16(1,0,0), v3s16(-1,0,0), v3s16(1,0,1), v3s16(-1,0,-1), v3s16(1,0,-1), v3s16(-1,0,1), }; for(u32 i=0; i<9; i++) { content_t content = CONTENT_AIR; float level = -0.5 * BS; u8 flags = 0; // Check neighbor v3s16 p2 = p + neighbor_dirs[i]; MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); if(n2.getContent() != CONTENT_IGNORE) { content = n2.getContent(); if(n2.getContent() == c_source) level = (-0.5+node_liquid_level) * BS; else if(n2.getContent() == c_flowing) level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK) + 0.5) / 8.0 * node_liquid_level) * BS; // Check node above neighbor. // NOTE: This doesn't get executed if neighbor // doesn't exist p2.Y += 1; n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); if(n2.getContent() == c_source || n2.getContent() == c_flowing) flags |= neighborflag_top_is_same_liquid; } neighbor_levels.insert(neighbor_dirs[i], level); neighbor_contents.insert(neighbor_dirs[i], content); neighbor_flags.insert(neighbor_dirs[i], flags); } // Corner heights (average between four liquids) f32 corner_levels[4]; v3s16 halfdirs[4] = { v3s16(0,0,0), v3s16(1,0,0), v3s16(1,0,1), v3s16(0,0,1), }; for(u32 i=0; i<4; i++) { v3s16 cornerdir = halfdirs[i]; float cornerlevel = 0; u32 valid_count = 0; u32 air_count = 0; for(u32 j=0; j<4; j++) { v3s16 neighbordir = cornerdir - halfdirs[j]; content_t content = neighbor_contents[neighbordir]; // If top is liquid, draw starting from top of node if(neighbor_flags[neighbordir] & neighborflag_top_is_same_liquid) { cornerlevel = 0.5*BS; valid_count = 1; break; } // Source is always the same height else if(content == c_source) { cornerlevel = (-0.5+node_liquid_level)*BS; valid_count = 1; break; } // Flowing liquid has level information else if(content == c_flowing) { cornerlevel += neighbor_levels[neighbordir]; valid_count++; } else if(content == CONTENT_AIR) { air_count++; } } if(air_count >= 2) cornerlevel = -0.5*BS; else if(valid_count > 0) cornerlevel /= valid_count; corner_levels[i] = cornerlevel; } /* Generate sides */ v3s16 side_dirs[4] = { v3s16(1,0,0), v3s16(-1,0,0), v3s16(0,0,1), v3s16(0,0,-1), }; s16 side_corners[4][2] = { {1, 2}, {3, 0}, {2, 3}, {0, 1}, }; for(u32 i=0; i<4; i++) { v3s16 dir = side_dirs[i]; /* If our topside is liquid and neighbor's topside is liquid, don't draw side face */ if(top_is_same_liquid && neighbor_flags[dir] & neighborflag_top_is_same_liquid) continue; content_t neighbor_content = neighbor_contents[dir]; const ContentFeatures &n_feat = nodedef->get(neighbor_content); // Don't draw face if neighbor is blocking the view if(n_feat.solidness == 2) continue; bool neighbor_is_same_liquid = (neighbor_content == c_source || neighbor_content == c_flowing); // Don't draw any faces if neighbor same is liquid and top is // same liquid if(neighbor_is_same_liquid == true && top_is_same_liquid == false) continue; // Use backface culled material if neighbor doesn't have a // solidness of 0 const TileSpec *current_tile = &tile_liquid; if(n_feat.solidness != 0 || n_feat.visual_solidness != 0) current_tile = &tile_liquid_bfculled; video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid.x0(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid.x1(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid.x1(), pa_liquid.y0()), video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid.x0(), pa_liquid.y0()), }; /* If our topside is liquid, set upper border of face at upper border of node */ if(top_is_same_liquid) { vertices[2].Pos.Y = 0.5*BS; vertices[3].Pos.Y = 0.5*BS; } /* Otherwise upper position of face is corner levels */ else { vertices[2].Pos.Y = corner_levels[side_corners[i][0]]; vertices[3].Pos.Y = corner_levels[side_corners[i][1]]; } /* If neighbor is liquid, lower border of face is corner liquid levels */ if(neighbor_is_same_liquid) { vertices[0].Pos.Y = corner_levels[side_corners[i][1]]; vertices[1].Pos.Y = corner_levels[side_corners[i][0]]; } /* If neighbor is not liquid, lower border of face is lower border of node */ else { vertices[0].Pos.Y = -0.5*BS; vertices[1].Pos.Y = -0.5*BS; } for(s32 j=0; j<4; j++) { if(dir == v3s16(0,0,1)) vertices[j].Pos.rotateXZBy(0); if(dir == v3s16(0,0,-1)) vertices[j].Pos.rotateXZBy(180); if(dir == v3s16(-1,0,0)) vertices[j].Pos.rotateXZBy(90); if(dir == v3s16(1,0,-0)) vertices[j].Pos.rotateXZBy(-90); // Do this to not cause glitches when two liquids are // side-by-side /*if(neighbor_is_same_liquid == false){ vertices[j].Pos.X *= 0.98; vertices[j].Pos.Z *= 0.98; }*/ vertices[j].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(*current_tile, vertices, 4, indices, 6); } /* Generate top side, if appropriate */ if(top_is_same_liquid == false) { video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, pa_liquid.x0(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, pa_liquid.x1(), pa_liquid.y1()), video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, pa_liquid.x1(), pa_liquid.y0()), video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, pa_liquid.x0(), pa_liquid.y0()), }; // To get backface culling right, the vertices need to go // clockwise around the front of the face. And we happened to // calculate corner levels in exact reverse order. s32 corner_resolve[4] = {3,2,1,0}; for(s32 i=0; i<4; i++) { //vertices[i].Pos.Y += liquid_level; //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)]; s32 j = corner_resolve[i]; vertices[i].Pos.Y += corner_levels[j]; vertices[i].Pos += intToFloat(p, BS); } // Default downwards-flowing texture animation goes from // -Z towards +Z, thus the direction is +Z. // Rotate texture to make animation go in flow direction // Positive if liquid moves towards +Z int dz = (corner_levels[side_corners[2][0]] + corner_levels[side_corners[2][1]] < corner_levels[side_corners[3][0]] + corner_levels[side_corners[3][1]]); // Positive if liquid moves towards +X int dx = (corner_levels[side_corners[0][0]] + corner_levels[side_corners[0][1]] < corner_levels[side_corners[1][0]] + corner_levels[side_corners[1][1]]); // -X if(-dx >= abs(dz)) { v2f t = vertices[0].TCoords; vertices[0].TCoords = vertices[1].TCoords; vertices[1].TCoords = vertices[2].TCoords; vertices[2].TCoords = vertices[3].TCoords; vertices[3].TCoords = t; } // +X if(dx >= abs(dz)) { v2f t = vertices[0].TCoords; vertices[0].TCoords = vertices[3].TCoords; vertices[3].TCoords = vertices[2].TCoords; vertices[2].TCoords = vertices[1].TCoords; vertices[1].TCoords = t; } // -Z if(-dz >= abs(dx)) { v2f t = vertices[0].TCoords; vertices[0].TCoords = vertices[3].TCoords; vertices[3].TCoords = vertices[2].TCoords; vertices[2].TCoords = vertices[1].TCoords; vertices[1].TCoords = t; t = vertices[0].TCoords; vertices[0].TCoords = vertices[3].TCoords; vertices[3].TCoords = vertices[2].TCoords; vertices[2].TCoords = vertices[1].TCoords; vertices[1].TCoords = t; } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(tile_liquid, vertices, 4, indices, 6); } break;} case NDT_GLASSLIKE: { TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data); AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); for(u32 j=0; j<6; j++) { // Check this neighbor v3s16 n2p = blockpos_nodes + p + g_6dirs[j]; MapNode n2 = data->m_vmanip.getNodeNoEx(n2p); // Don't make face if neighbor is of same type if(n2.getContent() == n.getContent()) continue; // The face at Z+ video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, ap.x0(), ap.y0()), }; // Rotations in the g_6dirs format if(j == 0) // Z+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(0); else if(j == 1) // Y+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(-90); else if(j == 2) // X+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-90); else if(j == 3) // Z- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(180); else if(j == 4) // Y- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(90); else if(j == 5) // X- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(90); for(u16 i=0; i<4; i++){ vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(tile, vertices, 4, indices, 6); } break;} case NDT_ALLFACES: { TileSpec tile_leaves = getNodeTile(n, p, v3s16(0,0,0), data); AtlasPointer pa_leaves = tile_leaves.texture; u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); v3f pos = intToFloat(p, BS); aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2); box.MinEdge += pos; box.MaxEdge += pos; makeCuboid(&collector, box, &tile_leaves, 1, c, NULL); break;} case NDT_ALLFACES_OPTIONAL: // This is always pre-converted to something else assert(0); break; case NDT_TORCHLIKE: { v3s16 dir = n.getWallMountedDir(nodedef); u8 tileindex = 0; if(dir == v3s16(0,-1,0)){ tileindex = 0; // floor } else if(dir == v3s16(0,1,0)){ tileindex = 1; // ceiling // For backwards compatibility } else if(dir == v3s16(0,0,0)){ tileindex = 0; // floor } else { tileindex = 2; // side } TileSpec tile = getNodeTileN(n, p, tileindex, data); tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; AtlasPointer ap = tile.texture; video::SColor c(255,255,255,255); // Wall at X+ of node video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, ap.x0(), ap.y0()), }; for(s32 i=0; i<4; i++) { if(dir == v3s16(1,0,0)) vertices[i].Pos.rotateXZBy(0); if(dir == v3s16(-1,0,0)) vertices[i].Pos.rotateXZBy(180); if(dir == v3s16(0,0,1)) vertices[i].Pos.rotateXZBy(90); if(dir == v3s16(0,0,-1)) vertices[i].Pos.rotateXZBy(-90); if(dir == v3s16(0,-1,0)) vertices[i].Pos.rotateXZBy(45); if(dir == v3s16(0,1,0)) vertices[i].Pos.rotateXZBy(-45); vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(tile, vertices, 4, indices, 6); break;} case NDT_SIGNLIKE: { TileSpec tile = getNodeTileN(n, p, 0, data); tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 0, data); video::SColor c = MapBlock_LightColor(255, l); float d = (float)BS/16; // Wall at X+ of node video::S3DVertex vertices[4] = { video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, ap.x0(), ap.y0()), video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, ap.x0(), ap.y1()), }; v3s16 dir = n.getWallMountedDir(nodedef); for(s32 i=0; i<4; i++) { if(dir == v3s16(1,0,0)) vertices[i].Pos.rotateXZBy(0); if(dir == v3s16(-1,0,0)) vertices[i].Pos.rotateXZBy(180); if(dir == v3s16(0,0,1)) vertices[i].Pos.rotateXZBy(90); if(dir == v3s16(0,0,-1)) vertices[i].Pos.rotateXZBy(-90); if(dir == v3s16(0,-1,0)) vertices[i].Pos.rotateXYBy(-90); if(dir == v3s16(0,1,0)) vertices[i].Pos.rotateXYBy(90); vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(tile, vertices, 4, indices, 6); break;} case NDT_PLANTLIKE: { TileSpec tile = getNodeTileN(n, p, 0, data); tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); for(u32 j=0; j<4; j++) { video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex( BS/2*f.visual_scale, -BS/2 + f.visual_scale*BS,0, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(-BS/2*f.visual_scale, -BS/2 + f.visual_scale*BS,0, 0,0,0, c, ap.x0(), ap.y0()), }; if(j == 0) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(45); } else if(j == 1) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-45); } else if(j == 2) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(135); } else if(j == 3) { for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-135); } for(u16 i=0; i<4; i++) { vertices[i].Pos *= f.visual_scale; vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector collector.append(tile, vertices, 4, indices, 6); } break;} case NDT_FENCELIKE: { TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data); TileSpec tile_nocrack = tile; tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK; // A hack to put wood the right way around in the posts ITextureSource *tsrc = data->m_gamedef->tsrc(); TileSpec tile_rot = tile; tile_rot.texture = tsrc->getTexture(tsrc->getTextureName( tile.texture.id) + "^[transformR90"); u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); const f32 post_rad=(f32)BS/8; const f32 bar_rad=(f32)BS/16; const f32 bar_len=(f32)(BS/2)-post_rad; v3f pos = intToFloat(p, BS); // The post - always present aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad); post.MinEdge += pos; post.MaxEdge += pos; f32 postuv[24]={ 6/16.,6/16.,10/16.,10/16., 6/16.,6/16.,10/16.,10/16., 0/16.,0,4/16.,1, 4/16.,0,8/16.,1, 8/16.,0,12/16.,1, 12/16.,0,16/16.,1}; makeCuboid(&collector, post, &tile_rot, 1, c, postuv); // Now a section of fence, +X, if there's a post there v3s16 p2 = p; p2.X++; MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); const ContentFeatures *f2 = &nodedef->get(n2); if(f2->drawtype == NDT_FENCELIKE) { aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad, bar_len+BS/2,bar_rad+BS/4,bar_rad); bar.MinEdge += pos; bar.MaxEdge += pos; f32 xrailuv[24]={ 0/16.,2/16.,16/16.,4/16., 0/16.,4/16.,16/16.,6/16., 6/16.,6/16.,8/16.,8/16., 10/16.,10/16.,12/16.,12/16., 0/16.,8/16.,16/16.,10/16., 0/16.,14/16.,16/16.,16/16.}; makeCuboid(&collector, bar, &tile_nocrack, 1, c, xrailuv); bar.MinEdge.Y -= BS/2; bar.MaxEdge.Y -= BS/2; makeCuboid(&collector, bar, &tile_nocrack, 1, c, xrailuv); } // Now a section of fence, +Z, if there's a post there p2 = p; p2.Z++; n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); f2 = &nodedef->get(n2); if(f2->drawtype == NDT_FENCELIKE) { aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2, bar_rad,bar_rad+BS/4,bar_len+BS/2); bar.MinEdge += pos; bar.MaxEdge += pos; f32 zrailuv[24]={ 3/16.,1/16.,5/16.,5/16., // cannot rotate; stretch 4/16.,1/16.,6/16.,5/16., // for wood texture instead 0/16.,9/16.,16/16.,11/16., 0/16.,6/16.,16/16.,8/16., 6/16.,6/16.,8/16.,8/16., 10/16.,10/16.,12/16.,12/16.}; makeCuboid(&collector, bar, &tile_nocrack, 1, c, zrailuv); bar.MinEdge.Y -= BS/2; bar.MaxEdge.Y -= BS/2; makeCuboid(&collector, bar, &tile_nocrack, 1, c, zrailuv); } break;} case NDT_RAILLIKE: { bool is_rail_x [] = { false, false }; /* x-1, x+1 */ bool is_rail_z [] = { false, false }; /* z-1, z+1 */ bool is_rail_z_minus_y [] = { false, false }; /* z-1, z+1; y-1 */ bool is_rail_x_minus_y [] = { false, false }; /* x-1, z+1; y-1 */ bool is_rail_z_plus_y [] = { false, false }; /* z-1, z+1; y+1 */ bool is_rail_x_plus_y [] = { false, false }; /* x-1, x+1; y+1 */ MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z)); MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z)); MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1)); MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1)); MapNode n_plus_x_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1, y+1, z)); MapNode n_plus_x_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1, y-1, z)); MapNode n_minus_x_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1, y+1, z)); MapNode n_minus_x_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1, y-1, z)); MapNode n_plus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z+1)); MapNode n_minus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z-1)); MapNode n_plus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z+1)); MapNode n_minus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z-1)); content_t thiscontent = n.getContent(); if(n_minus_x.getContent() == thiscontent) is_rail_x[0] = true; if (n_minus_x_minus_y.getContent() == thiscontent) is_rail_x_minus_y[0] = true; if(n_minus_x_plus_y.getContent() == thiscontent) is_rail_x_plus_y[0] = true; if(n_plus_x.getContent() == thiscontent) is_rail_x[1] = true; if (n_plus_x_minus_y.getContent() == thiscontent) is_rail_x_minus_y[1] = true; if(n_plus_x_plus_y.getContent() == thiscontent) is_rail_x_plus_y[1] = true; if(n_minus_z.getContent() == thiscontent) is_rail_z[0] = true; if (n_minus_z_minus_y.getContent() == thiscontent) is_rail_z_minus_y[0] = true; if(n_minus_z_plus_y.getContent() == thiscontent) is_rail_z_plus_y[0] = true; if(n_plus_z.getContent() == thiscontent) is_rail_z[1] = true; if (n_plus_z_minus_y.getContent() == thiscontent) is_rail_z_minus_y[1] = true; if(n_plus_z_plus_y.getContent() == thiscontent) is_rail_z_plus_y[1] = true; bool is_rail_x_all[] = {false, false}; bool is_rail_z_all[] = {false, false}; is_rail_x_all[0]=is_rail_x[0] || is_rail_x_minus_y[0] || is_rail_x_plus_y[0]; is_rail_x_all[1]=is_rail_x[1] || is_rail_x_minus_y[1] || is_rail_x_plus_y[1]; is_rail_z_all[0]=is_rail_z[0] || is_rail_z_minus_y[0] || is_rail_z_plus_y[0]; is_rail_z_all[1]=is_rail_z[1] || is_rail_z_minus_y[1] || is_rail_z_plus_y[1]; // reasonable default, flat straight unrotated rail bool is_straight = true; int adjacencies = 0; int angle = 0; u8 tileindex = 0; // check for sloped rail if (is_rail_x_plus_y[0] || is_rail_x_plus_y[1] || is_rail_z_plus_y[0] || is_rail_z_plus_y[1]) { adjacencies = 5; //5 means sloped is_straight = true; // sloped is always straight } else { // is really straight, rails on both sides is_straight = (is_rail_x_all[0] && is_rail_x_all[1]) || (is_rail_z_all[0] && is_rail_z_all[1]); adjacencies = is_rail_x_all[0] + is_rail_x_all[1] + is_rail_z_all[0] + is_rail_z_all[1]; } switch (adjacencies) { case 1: if(is_rail_x_all[0] || is_rail_x_all[1]) angle = 90; break; case 2: if(!is_straight) tileindex = 1; // curved if(is_rail_x_all[0] && is_rail_x_all[1]) angle = 90; if(is_rail_z_all[0] && is_rail_z_all[1]){ if (n_minus_z_plus_y.getContent() == thiscontent) angle = 180; } else if(is_rail_x_all[0] && is_rail_z_all[0]) angle = 270; else if(is_rail_x_all[0] && is_rail_z_all[1]) angle = 180; else if(is_rail_x_all[1] && is_rail_z_all[1]) angle = 90; break; case 3: // here is where the potential to 'switch' a junction is, but not implemented at present tileindex = 2; // t-junction if(!is_rail_x_all[1]) angle=180; if(!is_rail_z_all[0]) angle=90; if(!is_rail_z_all[1]) angle=270; break; case 4: tileindex = 3; // crossing break; case 5: //sloped if(is_rail_z_plus_y[0]) angle = 180; if(is_rail_x_plus_y[0]) angle = 90; if(is_rail_x_plus_y[1]) angle = -90; break; default: break; } TileSpec tile = getNodeTileN(n, p, tileindex, data); tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 0, data); video::SColor c = MapBlock_LightColor(255, l); float d = (float)BS/64; char g=-1; if (is_rail_x_plus_y[0] || is_rail_x_plus_y[1] || is_rail_z_plus_y[0] || is_rail_z_plus_y[1]) g=1; //Object is at a slope video::S3DVertex vertices[4] = { video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, ap.x0(), ap.y1()), video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, ap.x1(), ap.y1()), video::S3DVertex(BS/2,g*BS/2+d,BS/2, 0,0,0, c, ap.x1(), ap.y0()), video::S3DVertex(-BS/2,g*BS/2+d,BS/2, 0,0,0, c, ap.x0(), ap.y0()), }; for(s32 i=0; i<4; i++) { if(angle != 0) vertices[i].Pos.rotateXZBy(angle); vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; collector.append(tile, vertices, 4, indices, 6); break;} case NDT_NODEBOX: { TileSpec tiles[6]; for(int i = 0; i < 6; i++) { tiles[i] = getNodeTileN(n, p, i, data); } u16 l = getInteriorLight(n, 0, data); video::SColor c = MapBlock_LightColor(255, l); v3f pos = intToFloat(p, BS); std::vector<aabb3f> boxes = n.getNodeBoxes(nodedef); for(std::vector<aabb3f>::iterator i = boxes.begin(); i != boxes.end(); i++) { aabb3f box = *i; box.MinEdge += pos; box.MaxEdge += pos; // Compute texture coords f32 tx1 = (i->MinEdge.X/BS)+0.5; f32 ty1 = (i->MinEdge.Y/BS)+0.5; f32 tz1 = (i->MinEdge.Z/BS)+0.5; f32 tx2 = (i->MaxEdge.X/BS)+0.5; f32 ty2 = (i->MaxEdge.Y/BS)+0.5; f32 tz2 = (i->MaxEdge.Z/BS)+0.5; f32 txc[24] = { // up tx1, 1-tz2, tx2, 1-tz1, // down tx1, tz1, tx2, tz2, // right tz1, 1-ty2, tz2, 1-ty1, // left 1-tz2, 1-ty2, 1-tz1, 1-ty1, // back 1-tx2, 1-ty2, 1-tx1, 1-ty1, // front tx1, 1-ty2, tx2, 1-ty1, }; makeCuboid(&collector, box, tiles, 6, c, txc); } break;} } } }
MapgenValleys::MapgenValleys(int mapgenid, MapgenParams *params, EmergeManager *emerge) : Mapgen(mapgenid, params, emerge) { this->m_emerge = emerge; this->bmgr = emerge->biomemgr; //// amount of elements to skip for the next index //// for noise/height/biome maps (not vmanip) this->ystride = csize.X; this->zstride = csize.X * (csize.Y + 2); this->biomemap = new u8[csize.X * csize.Z]; this->heightmap = new s16[csize.X * csize.Z]; this->heatmap = NULL; this->humidmap = NULL; this->map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT, g_settings->getU16("map_generation_limit")); MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams; this->spflags = sp->spflags; this->humid_rivers = (spflags & MG_VALLEYS_HUMID_RIVERS); this->use_altitude_chill = (spflags & MG_VALLEYS_ALT_CHILL); this->altitude_chill = sp->altitude_chill; this->humidity_adjust = params->np_biome_humidity.offset - 50.f; this->large_cave_depth = sp->large_cave_depth; this->lava_features_lim = rangelim(sp->lava_features, 0, 10); this->massive_cave_depth = sp->massive_cave_depth; this->river_depth_bed = sp->river_depth + 1.f; this->river_size_factor = sp->river_size / 100.f; this->water_features_lim = rangelim(sp->water_features, 0, 10); // a small chance of overflows if the settings are very high this->cave_water_max_height = water_level + MYMAX(0, water_features_lim - 6) * 50; this->lava_max_height = water_level + MYMAX(0, lava_features_lim - 6) * 50; tcave_cache = new float[csize.Y + 2]; //// 2D Terrain noise noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z); noise_inter_valley_slope = new Noise(&sp->np_inter_valley_slope, seed, csize.X, csize.Z); noise_rivers = new Noise(&sp->np_rivers, seed, csize.X, csize.Z); noise_terrain_height = new Noise(&sp->np_terrain_height, seed, csize.X, csize.Z); noise_valley_depth = new Noise(&sp->np_valley_depth, seed, csize.X, csize.Z); noise_valley_profile = new Noise(&sp->np_valley_profile, seed, csize.X, csize.Z); //// 3D Terrain noise noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 2, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 2, csize.Z); noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Y + 2, csize.Z); noise_massive_caves = new Noise(&sp->np_massive_caves, seed, csize.X, csize.Y + 2, csize.Z); //// Biome noise noise_heat_blend = new Noise(¶ms->np_biome_heat_blend, seed, csize.X, csize.Z); noise_heat = new Noise(¶ms->np_biome_heat, seed, csize.X, csize.Z); noise_humidity_blend = new Noise(¶ms->np_biome_humidity_blend, seed, csize.X, csize.Z); noise_humidity = new Noise(¶ms->np_biome_humidity, seed, csize.X, csize.Z); //// Resolve nodes to be used INodeDefManager *ndef = emerge->ndef; c_cobble = ndef->getId("mapgen_cobble"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_dirt = ndef->getId("mapgen_dirt"); c_lava_source = ndef->getId("mapgen_lava_source"); c_mossycobble = ndef->getId("mapgen_mossycobble"); c_river_water_source = ndef->getId("mapgen_river_water_source"); c_sand = ndef->getId("mapgen_sand"); c_sandstonebrick = ndef->getId("mapgen_sandstonebrick"); c_sandstone = ndef->getId("mapgen_sandstone"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick"); c_stone = ndef->getId("mapgen_stone"); c_water_source = ndef->getId("mapgen_water_source"); if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_river_water_source == CONTENT_IGNORE) c_river_water_source = c_water_source; if (c_sand == CONTENT_IGNORE) c_sand = c_stone; if (c_sandstonebrick == CONTENT_IGNORE) c_sandstonebrick = c_sandstone; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; if (c_stair_sandstonebrick == CONTENT_IGNORE) c_stair_sandstonebrick = c_sandstone; }