bool Map::propagateSunlight(v3POS pos, std::set<v3POS> & light_sources, bool remove_light) { MapBlock *block = getBlockNoCreateNoEx(pos); INodeDefManager *nodemgr = m_gamedef->ndef(); // Whether the sunlight at the top of the bottom block is valid bool block_below_is_valid = true; v3POS pos_relative = block->getPosRelative(); for(s16 x = 0; x < MAP_BLOCKSIZE; ++x) { for(s16 z = 0; z < MAP_BLOCKSIZE; ++z) { bool no_sunlight = false; // Check if node above block has sunlight MapNode n = getNode(pos_relative + v3POS(x, MAP_BLOCKSIZE, z)); if (n) { if(n.getLight(LIGHTBANK_DAY, m_gamedef->ndef()) != LIGHT_SUN) { no_sunlight = true; } } else { // NOTE: This makes over-ground roofed places sunlighted // Assume sunlight, unless is_underground==true if(block->getIsUnderground()) { no_sunlight = true; } else { MapNode n = block->getNode(v3POS(x, MAP_BLOCKSIZE - 1, z)); if(n && m_gamedef->ndef()->get(n).sunlight_propagates == false) no_sunlight = true; } // NOTE: As of now, this just would make everything dark. // No sunlight here //no_sunlight = true; } s16 y = MAP_BLOCKSIZE - 1; // This makes difference to diminishing in water. //bool stopped_to_solid_object = false; u8 current_light = no_sunlight ? 0 : LIGHT_SUN; for(; y >= 0; --y) { v3POS pos(x, y, z); MapNode n = block->getNode(pos); if(current_light == 0) { // Do nothing } else if(current_light == LIGHT_SUN && nodemgr->get(n).sunlight_propagates) { // Do nothing: Sunlight is continued } else if(nodemgr->get(n).light_propagates == false) { // A solid object is on the way. //stopped_to_solid_object = true; // Light stops. current_light = 0; } else { // Diminish light current_light = diminish_light(current_light); } u8 old_light = n.getLight(LIGHTBANK_DAY, nodemgr); if(current_light > old_light || remove_light) { n.setLight(LIGHTBANK_DAY, current_light, nodemgr); block->setNode(pos, n); } if(diminish_light(current_light) != 0) { light_sources.insert(pos_relative + pos); } } // Whether or not the block below should see LIGHT_SUN bool sunlight_should_go_down = (current_light == LIGHT_SUN); /* If the block below hasn't already been marked invalid: Check if the node below the block has proper sunlight at top. If not, the block below is invalid. Ignore non-transparent nodes as they always have no light */ if(block_below_is_valid) { MapNode n = getNode(pos_relative + v3POS(x, -1, z)); if (n) { if(nodemgr->get(n).light_propagates) { if(n.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN && sunlight_should_go_down == false) block_below_is_valid = false; else if(n.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN && sunlight_should_go_down == true) block_below_is_valid = false; } } else { // Just no block below, no need to panic. } } } } return block_below_is_valid; }
/* Calculate smooth lighting at the XYZ- corner of p. Single light bank. */ static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data) { static v3s16 dirs8[8] = { v3s16(0,0,0), v3s16(0,0,1), v3s16(0,1,0), v3s16(0,1,1), v3s16(1,0,0), v3s16(1,1,0), v3s16(1,0,1), v3s16(1,1,1), }; INodeDefManager *ndef = data->m_gamedef->ndef(); u16 ambient_occlusion = 0; u16 light = 0; u16 light_count = 0; u8 light_source_max = 0; for(u32 i=0; i<8; i++) { MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]); // if it's CONTENT_IGNORE we can't do any light calculations if (n.getContent() == CONTENT_IGNORE) { continue; } const ContentFeatures &f = ndef->get(n); if(f.light_source > light_source_max) light_source_max = f.light_source; // Check f.solidness because fast-style leaves look // better this way if(f.param_type == CPT_LIGHT && f.solidness != 2) { light += decode_light(n.getLight(bank, ndef)); light_count++; } else { ambient_occlusion++; } } if(light_count == 0) return 255; light /= light_count; // Boost brightness around light sources if(decode_light(light_source_max) >= light) //return decode_light(undiminish_light(light_source_max)); return decode_light(light_source_max); if(ambient_occlusion > 4) { //ambient_occlusion -= 4; //light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0); float light_amount = (8 - ambient_occlusion) / 4.0; float light_f = (float)light / 255.0; light_f = pow(light_f, 2.2f); // gamma -> linear space light_f = light_f * light_amount; light_f = pow(light_f, 1.0f/2.2f); // linear -> gamma space if(light_f > 1.0) light_f = 1.0; light = 255.0 * light_f + 0.5; } return light; }
MapgenV5::MapgenV5(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; 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; if (c_sandstonebrick == CONTENT_IGNORE) c_sandstonebrick = c_sandstone; if (c_stair_sandstonebrick == CONTENT_IGNORE) c_stair_sandstonebrick = c_sandstone; }
// register_ore({lots of stuff}) int ModApiMapgen::l_register_ore(lua_State *L) { NO_MAP_LOCK_REQUIRED; int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); BiomeManager *bmgr = getServer(L)->getEmergeManager()->biomemgr; OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); Ore *ore = oremgr->create(oretype); if (!ore) { errorstream << "register_ore: ore_type " << oretype << " not implemented\n"; return 0; } ore->name = getstringfield_default(L, index, "name", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->noise = NULL; ore->flags = 0; //// Get noise_threshold warn_if_field_exists(L, index, "noise_threshhold", "Deprecated: new name is \"noise_threshold\"."); float nthresh; if (!getfloatfield(L, index, "noise_threshold", nthresh) && !getfloatfield(L, index, "noise_threshhold", nthresh)) nthresh = 0; ore->nthresh = nthresh; //// Get y_min/y_max warn_if_field_exists(L, index, "height_min", "Deprecated: new name is \"y_min\"."); warn_if_field_exists(L, index, "height_max", "Deprecated: new name is \"y_max\"."); int ymin, ymax; if (!getintfield(L, index, "y_min", ymin) && !getintfield(L, index, "height_min", ymin)) ymin = -31000; if (!getintfield(L, index, "y_max", ymax) && !getintfield(L, index, "height_max", ymax)) ymax = 31000; ore->y_min = ymin; ore->y_max = ymax; if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; delete ore; return 0; } //// Get flags getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); //// Get biomes associated with this decoration (if any) lua_getfield(L, index, "biomes"); if (get_biome_list(L, -1, bmgr, &ore->biomes)) errorstream << "register_ore: couldn't get all biomes " << std::endl; lua_pop(L, 1); //// Get noise parameters if needed lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &ore->np)) { ore->flags |= OREFLAG_USE_NOISE; } else if (ore->NEEDS_NOISE) { errorstream << "register_ore: specified ore type requires valid " "noise parameters" << std::endl; delete ore; return 0; } lua_pop(L, 1); //// Get type-specific parameters switch (oretype) { case ORE_SHEET: { OreSheet *oresheet = (OreSheet *)ore; oresheet->column_height_min = getintfield_default(L, index, "column_height_min", 1); oresheet->column_height_max = getintfield_default(L, index, "column_height_max", ore->clust_size); oresheet->column_midpoint_factor = getfloatfield_default(L, index, "column_midpoint_factor", 0.5f); break; } case ORE_PUFF: { OrePuff *orepuff = (OrePuff *)ore; lua_getfield(L, index, "np_puff_top"); read_noiseparams(L, -1, &orepuff->np_puff_top); lua_pop(L, 1); lua_getfield(L, index, "np_puff_bottom"); read_noiseparams(L, -1, &orepuff->np_puff_bottom); lua_pop(L, 1); break; } case ORE_VEIN: { OreVein *orevein = (OreVein *)ore; orevein->random_factor = getfloatfield_default(L, index, "random_factor", 1.f); break; } default: break; } ObjDefHandle handle = oremgr->add(ore); if (handle == OBJDEF_INVALID_HANDLE) { delete ore; return 0; } ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", "")); size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames); ore->m_nnlistsizes.push_back(nnames); ndef->pendNodeResolve(ore); lua_pushinteger(L, handle); return 1; }
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->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); //// 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"); c_cobble = ndef->getId("mapgen_cobble"); c_desert_stone = ndef->getId("mapgen_desert_stone"); c_mossycobble = ndef->getId("mapgen_mossycobble"); c_sandbrick = ndef->getId("mapgen_sandstonebrick"); c_stair_cobble = ndef->getId("mapgen_stair_cobble"); c_stair_sandstone = ndef->getId("mapgen_stair_sandstone"); if (c_ice == CONTENT_IGNORE) c_ice = CONTENT_AIR; if (c_mossycobble == CONTENT_IGNORE) c_mossycobble = c_cobble; if (c_sandbrick == CONTENT_IGNORE) c_sandbrick = c_desert_stone; if (c_stair_cobble == CONTENT_IGNORE) c_stair_cobble = c_cobble; if (c_stair_sandstone == CONTENT_IGNORE) c_stair_sandstone = c_sandbrick; }
// register_ore({lots of stuff}) int ModApiMapgen::l_register_ore(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); OreManager *oremgr = getServer(L)->getEmergeManager()->oremgr; enum OreType oretype = (OreType)getenumfield(L, index, "ore_type", es_OreType, ORE_SCATTER); Ore *ore = oremgr->create(oretype); if (!ore) { errorstream << "register_ore: ore_type " << oretype << " not implemented"; return 0; } ore->name = getstringfield_default(L, index, "name", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); ore->nthresh = getfloatfield_default(L, index, "noise_threshhold", 0); ore->noise = NULL; ore->flags = 0; warn_if_field_exists(L, index, "height_min", "Deprecated: new name is \"y_min\"."); warn_if_field_exists(L, index, "height_max", "Deprecated: new name is \"y_max\"."); int ymin, ymax; if (!getintfield(L, index, "y_min", ymin) && !getintfield(L, index, "height_min", ymin)) ymin = -31000; if (!getintfield(L, index, "y_max", ymax) && !getintfield(L, index, "height_max", ymax)) ymax = 31000; ore->y_min = ymin; ore->y_max = ymax; if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; delete ore; return 0; } getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &ore->np)) { ore->flags |= OREFLAG_USE_NOISE; } else if (ore->NEEDS_NOISE) { errorstream << "register_ore: specified ore type requires valid " "noise parameters" << std::endl; delete ore; return 0; } lua_pop(L, 1); if (oretype == ORE_VEIN) { OreVein *orevein = (OreVein *)ore; orevein->random_factor = getfloatfield_default(L, index, "random_factor", 1.f); } ObjDefHandle handle = oremgr->add(ore); if (handle == OBJDEF_INVALID_HANDLE) { delete ore; return 0; } ore->m_nodenames.push_back(getstringfield_default(L, index, "ore", "")); size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames); ore->m_nnlistsizes.push_back(nnames); ndef->pendNodeResolve(ore, NODE_RESOLVE_DEFERRED); lua_pushinteger(L, handle); return 1; }
PointedThing ClientEnvironment::getPointedThing( core::line3d<f32> shootline, bool liquids_pointable, bool look_for_object) { PointedThing result; INodeDefManager *nodedef = m_map->getNodeDefManager(); core::aabbox3d<s16> maximal_exceed = nodedef->getSelectionBoxIntUnion(); // The code needs to search these nodes core::aabbox3d<s16> search_range(-maximal_exceed.MaxEdge, -maximal_exceed.MinEdge); // If a node is found, there might be a larger node behind. // To find it, we have to go further. s16 maximal_overcheck = std::max(abs(search_range.MinEdge.X), abs(search_range.MaxEdge.X)) + std::max(abs(search_range.MinEdge.Y), abs(search_range.MaxEdge.Y)) + std::max(abs(search_range.MinEdge.Z), abs(search_range.MaxEdge.Z)); const v3f original_vector = shootline.getVector(); const f32 original_length = original_vector.getLength(); f32 min_distance = original_length; // First try to find an active object if (look_for_object) { ClientActiveObject *selected_object = getSelectedActiveObject( shootline, &result.intersection_point, &result.intersection_normal); if (selected_object != NULL) { min_distance = (result.intersection_point - shootline.start).getLength(); result.type = POINTEDTHING_OBJECT; result.object_id = selected_object->getId(); } } // Reduce shootline if (original_length > 0) { shootline.end = shootline.start + shootline.getVector() / original_length * min_distance; } // Try to find a node that is closer than the selected active // object (if it exists). voxalgo::VoxelLineIterator iterator(shootline.start / BS, shootline.getVector() / BS); v3s16 oldnode = iterator.m_current_node_pos; // Indicates that a node was found. bool is_node_found = false; // If a node is found, it is possible that there's a node // behind it with a large nodebox, so continue the search. u16 node_foundcounter = 0; // If a node is found, this is the center of the // first nodebox the shootline meets. v3f found_boxcenter(0, 0, 0); // The untested nodes are in this range. core::aabbox3d<s16> new_nodes; while (true) { // Test the nodes around the current node in search_range. new_nodes = search_range; new_nodes.MinEdge += iterator.m_current_node_pos; new_nodes.MaxEdge += iterator.m_current_node_pos; // Only check new nodes v3s16 delta = iterator.m_current_node_pos - oldnode; if (delta.X > 0) new_nodes.MinEdge.X = new_nodes.MaxEdge.X; else if (delta.X < 0) new_nodes.MaxEdge.X = new_nodes.MinEdge.X; else if (delta.Y > 0) new_nodes.MinEdge.Y = new_nodes.MaxEdge.Y; else if (delta.Y < 0) new_nodes.MaxEdge.Y = new_nodes.MinEdge.Y; else if (delta.Z > 0) new_nodes.MinEdge.Z = new_nodes.MaxEdge.Z; else if (delta.Z < 0) new_nodes.MaxEdge.Z = new_nodes.MinEdge.Z; // For each untested node for (s16 x = new_nodes.MinEdge.X; x <= new_nodes.MaxEdge.X; x++) { for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) { for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) { MapNode n; v3s16 np(x, y, z); bool is_valid_position; n = m_map->getNodeNoEx(np, &is_valid_position); if (!(is_valid_position && isPointableNode(n, nodedef, liquids_pointable))) { continue; } std::vector<aabb3f> boxes; n.getSelectionBoxes(nodedef, &boxes, n.getNeighbors(np, m_map)); v3f npf = intToFloat(np, BS); for (std::vector<aabb3f>::const_iterator i = boxes.begin(); i != boxes.end(); ++i) { aabb3f box = *i; box.MinEdge += npf; box.MaxEdge += npf; v3f intersection_point; v3s16 intersection_normal; if (!boxLineCollision(box, shootline.start, shootline.getVector(), &intersection_point, &intersection_normal)) { continue; } f32 distance = (intersection_point - shootline.start).getLength(); if (distance >= min_distance) { continue; } result.type = POINTEDTHING_NODE; result.node_undersurface = np; result.intersection_point = intersection_point; result.intersection_normal = intersection_normal; found_boxcenter = box.getCenter(); min_distance = distance; is_node_found = true; } } } } if (is_node_found) { node_foundcounter++; if (node_foundcounter > maximal_overcheck) { break; } } // Next node if (iterator.hasNext()) { oldnode = iterator.m_current_node_pos; iterator.next(); } else { break; } } if (is_node_found) { // Set undersurface and abovesurface nodes f32 d = 0.002 * BS; v3f fake_intersection = result.intersection_point; // Move intersection towards its source block. if (fake_intersection.X < found_boxcenter.X) fake_intersection.X += d; else fake_intersection.X -= d; if (fake_intersection.Y < found_boxcenter.Y) fake_intersection.Y += d; else fake_intersection.Y -= d; if (fake_intersection.Z < found_boxcenter.Z) fake_intersection.Z += d; else fake_intersection.Z -= d; result.node_real_undersurface = floatToInt(fake_intersection, BS); result.node_abovesurface = result.node_real_undersurface + result.intersection_normal; } return result; }
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; // 1-down overgeneration this->zstride_1d = csize.X * (csize.Y + 1); 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 // 1-down overgeneraion noise_cave1 = new Noise(&sp->np_cave1, seed, csize.X, csize.Y + 1, csize.Z); noise_cave2 = new Noise(&sp->np_cave2, seed, csize.X, csize.Y + 1, 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::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(getDayNightDiff()) 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); } } }
// Temporary option for old move code void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, std::vector<CollisionInfo> *collision_info) { Map *map = &env->getMap(); INodeDefManager *nodemgr = m_client->ndef(); v3f position = getPosition(); // Copy parent position if local player is attached if (isAttached) { setPosition(overridePosition); m_sneak_node_exists = false; return; } // Skip collision detection if noclip mode is used bool fly_allowed = m_client->checkLocalPrivilege("fly"); bool noclip = m_client->checkLocalPrivilege("noclip") && g_settings->getBool("noclip"); bool free_move = noclip && fly_allowed && g_settings->getBool("free_move"); if (free_move) { position += m_speed * dtime; setPosition(position); m_sneak_node_exists = false; return; } /* Collision detection */ bool is_valid_position; MapNode node; v3s16 pp; /* Check if player is in liquid (the oscillating value) */ if (in_liquid) { // If in liquid, the threshold of coming out is at higher y pp = floatToInt(position + v3f(0, BS * 0.1, 0), BS); node = map->getNodeNoEx(pp, &is_valid_position); if (is_valid_position) { in_liquid = nodemgr->get(node.getContent()).isLiquid(); liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; } else { in_liquid = false; } } else { // If not in liquid, the threshold of going in is at lower y pp = floatToInt(position + v3f(0, BS * 0.5, 0), BS); node = map->getNodeNoEx(pp, &is_valid_position); if (is_valid_position) { in_liquid = nodemgr->get(node.getContent()).isLiquid(); liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; } else { in_liquid = false; } } /* Check if player is in liquid (the stable value) */ pp = floatToInt(position + v3f(0, 0, 0), BS); node = map->getNodeNoEx(pp, &is_valid_position); if (is_valid_position) in_liquid_stable = nodemgr->get(node.getContent()).isLiquid(); else in_liquid_stable = false; /* Check if player is climbing */ pp = floatToInt(position + v3f(0, 0.5 * BS, 0), BS); v3s16 pp2 = floatToInt(position + v3f(0, -0.2 * BS, 0), BS); node = map->getNodeNoEx(pp, &is_valid_position); bool is_valid_position2; MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2); if (!(is_valid_position && is_valid_position2)) is_climbing = false; else is_climbing = (nodemgr->get(node.getContent()).climbable || nodemgr->get(node2.getContent()).climbable) && !free_move; /* Collision uncertainty radius Make it a bit larger than the maximum distance of movement */ //f32 d = pos_max_d * 1.1; // A fairly large value in here makes moving smoother f32 d = 0.15 * BS; // This should always apply, otherwise there are glitches sanity_check(d > pos_max_d); // Maximum distance over border for sneaking f32 sneak_max = BS * 0.4; /* If sneaking, keep in range from the last walked node and don't fall off from it */ if (control.sneak && m_sneak_node_exists && !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid && physics_override_sneak) { f32 maxd = 0.5 * BS + sneak_max; v3f lwn_f = intToFloat(m_sneak_node, BS); position.X = rangelim(position.X, lwn_f.X - maxd, lwn_f.X + maxd); position.Z = rangelim(position.Z, lwn_f.Z - maxd, lwn_f.Z + maxd); if (!is_climbing) { // Move up if necessary f32 new_y = (lwn_f.Y - 0.5 * BS) + m_sneak_node_bb_ymax; if (position.Y < new_y) position.Y = new_y; /* Collision seems broken, since player is sinking when sneaking over the edges of current sneaking_node. TODO (when fixed): Set Y-speed only to 0 when position.Y < new_y. */ if (m_speed.Y < 0) m_speed.Y = 0; } } // this shouldn't be hardcoded but transmitted from server float player_stepheight = touching_ground ? (BS * 0.6) : (BS * 0.2); #ifdef __ANDROID__ player_stepheight += (0.6 * BS); #endif v3f accel_f = v3f(0, 0, 0); collisionMoveResult result = collisionMoveSimple(env, m_client, pos_max_d, m_collisionbox, player_stepheight, dtime, &position, &m_speed, accel_f); /* If the player's feet touch the topside of any node, this is set to true. Player is allowed to jump when this is true. */ bool touching_ground_was = touching_ground; touching_ground = result.touching_ground; //bool standing_on_unloaded = result.standing_on_unloaded; /* Check the nodes under the player to see from which node the player is sneaking from, if any. If the node from under the player has been removed, the player falls. */ f32 position_y_mod = 0.05 * BS; if (m_sneak_node_bb_ymax > 0) position_y_mod = m_sneak_node_bb_ymax - position_y_mod; v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS); if (m_sneak_node_exists && nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" && m_old_node_below_type != "air") { // Old node appears to have been removed; that is, // it wasn't air before but now it is m_need_to_get_new_sneak_node = false; m_sneak_node_exists = false; } else if (nodemgr->get(map->getNodeNoEx(current_node)).name != "air") { // We are on something, so make sure to recalculate the sneak // node. m_need_to_get_new_sneak_node = true; } if (m_need_to_get_new_sneak_node && physics_override_sneak) { m_sneak_node_bb_ymax = 0; v3s16 pos_i_bottom = floatToInt(position - v3f(0, position_y_mod, 0), BS); v2f player_p2df(position.X, position.Z); f32 min_distance_f = 100000.0 * BS; // If already seeking from some node, compare to it. v3s16 new_sneak_node = m_sneak_node; for (s16 x= -1; x <= 1; x++) for (s16 z= -1; z <= 1; z++) { v3s16 p = pos_i_bottom + v3s16(x, 0, z); v3f pf = intToFloat(p, BS); v2f node_p2df(pf.X, pf.Z); f32 distance_f = player_p2df.getDistanceFrom(node_p2df); f32 max_axis_distance_f = MYMAX( fabs(player_p2df.X - node_p2df.X), fabs(player_p2df.Y - node_p2df.Y)); if (distance_f > min_distance_f || max_axis_distance_f > 0.5 * BS + sneak_max + 0.1 * BS) continue; // The node to be sneaked on has to be walkable node = map->getNodeNoEx(p, &is_valid_position); if (!is_valid_position || !nodemgr->get(node).walkable) continue; // And the node above it has to be nonwalkable node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position); if (!is_valid_position || nodemgr->get(node).walkable) continue; // If not 'sneak_glitch' the node 2 nodes above it has to be nonwalkable if (!physics_override_sneak_glitch) { node =map->getNodeNoEx(p + v3s16(0, 2, 0), &is_valid_position); if (!is_valid_position || nodemgr->get(node).walkable) continue; } min_distance_f = distance_f; new_sneak_node = p; } bool sneak_node_found = (min_distance_f < 100000.0 * BS * 0.9); m_sneak_node = new_sneak_node; m_sneak_node_exists = sneak_node_found; if (sneak_node_found) { f32 cb_max = 0; MapNode n = map->getNodeNoEx(m_sneak_node); std::vector<aabb3f> nodeboxes; n.getCollisionBoxes(nodemgr, &nodeboxes); for (const auto &box : nodeboxes) { if (box.MaxEdge.Y > cb_max) cb_max = box.MaxEdge.Y; } m_sneak_node_bb_ymax = cb_max; } /* If sneaking, the player's collision box can be in air, so this has to be set explicitly */ if (sneak_node_found && control.sneak) touching_ground = true; } /* Set new position but keep sneak node set */ bool sneak_node_exists = m_sneak_node_exists; setPosition(position); m_sneak_node_exists = sneak_node_exists; /* Report collisions */ // Dont report if flying if (collision_info && !(g_settings->getBool("free_move") && fly_allowed)) { for (const auto &info : result.collisions) { collision_info->push_back(info); } } if (!result.standing_on_object && !touching_ground_was && touching_ground) { MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround"); m_client->event()->put(e); // Set camera impact value to be used for view bobbing camera_impact = getSpeed().Y * -1; } { camera_barely_in_ceiling = false; v3s16 camera_np = floatToInt(getEyePosition(), BS); MapNode n = map->getNodeNoEx(camera_np); if (n.getContent() != CONTENT_IGNORE) { if (nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2) camera_barely_in_ceiling = true; } } /* Update the node last under the player */ m_old_node_below = floatToInt(position - v3f(0, BS / 2, 0), BS); m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name; /* Check properties of the node on which the player is standing */ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos())); // Determine if jumping is possible m_can_jump = touching_ground && !in_liquid; if (itemgroup_get(f.groups, "disable_jump")) m_can_jump = false; // Jump key pressed while jumping off from a bouncy block if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") && m_speed.Y >= -0.5 * BS) { float jumpspeed = movement_speed_jump * physics_override_jump; if (m_speed.Y > 1) { // Reduce boost when speed already is high m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 )); } else { m_speed.Y += jumpspeed; } setSpeed(m_speed); m_can_jump = false; } }
bool LocalPlayer::updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max) { static const v3s16 dir9_center[9] = { v3s16( 0, 0, 0), v3s16( 1, 0, 0), v3s16(-1, 0, 0), v3s16( 0, 0, 1), v3s16( 0, 0, -1), v3s16( 1, 0, 1), v3s16(-1, 0, 1), v3s16( 1, 0, -1), v3s16(-1, 0, -1) }; INodeDefManager *nodemgr = m_client->ndef(); MapNode node; bool is_valid_position; bool new_sneak_node_exists = m_sneak_node_exists; // We want the top of the sneak node to be below the players feet f32 position_y_mod = 0.05 * BS; if (m_sneak_node_exists) position_y_mod = m_sneak_node_bb_top.MaxEdge.Y - position_y_mod; // Get position of current standing node const v3s16 current_node = floatToInt(position - v3f(0, position_y_mod, 0), BS); if (current_node != m_sneak_node) { new_sneak_node_exists = false; } else { node = map->getNodeNoEx(current_node, &is_valid_position); if (!is_valid_position || !nodemgr->get(node).walkable) new_sneak_node_exists = false; } // Keep old sneak node if (new_sneak_node_exists) return true; // Get new sneak node m_sneak_ladder_detected = false; f32 min_distance_f = 100000.0 * BS; for (const auto &d : dir9_center) { const v3s16 p = current_node + d; const v3f pf = intToFloat(p, BS); const v2f diff(position.X - pf.X, position.Z - pf.Z); f32 distance_f = diff.getLength(); if (distance_f > min_distance_f || fabs(diff.X) > (.5 + .1) * BS + sneak_max.X || fabs(diff.Y) > (.5 + .1) * BS + sneak_max.Z) continue; // The node to be sneaked on has to be walkable node = map->getNodeNoEx(p, &is_valid_position); if (!is_valid_position || !nodemgr->get(node).walkable) continue; // And the node(s) above have to be nonwalkable bool ok = true; if (!physics_override_sneak_glitch) { u16 height = ceilf( (m_collisionbox.MaxEdge.Y - m_collisionbox.MinEdge.Y) / BS ); for (u16 y = 1; y <= height; y++) { node = map->getNodeNoEx(p + v3s16(0, y, 0), &is_valid_position); if (!is_valid_position || nodemgr->get(node).walkable) { ok = false; break; } } } else { // legacy behaviour: check just one node node = map->getNodeNoEx(p + v3s16(0, 1, 0), &is_valid_position); ok = is_valid_position && !nodemgr->get(node).walkable; } if (!ok) continue; min_distance_f = distance_f; m_sneak_node = p; new_sneak_node_exists = true; } if (!new_sneak_node_exists) return false; // Update saved top bounding box of sneak node node = map->getNodeNoEx(m_sneak_node); std::vector<aabb3f> nodeboxes; node.getCollisionBoxes(nodemgr, &nodeboxes); m_sneak_node_bb_top = getNodeBoundingBox(nodeboxes); if (physics_override_sneak_glitch) { // Detect sneak ladder: // Node two meters above sneak node must be solid node = map->getNodeNoEx(m_sneak_node + v3s16(0, 2, 0), &is_valid_position); if (is_valid_position && nodemgr->get(node).walkable) { // Node three meters above: must be non-solid node = map->getNodeNoEx(m_sneak_node + v3s16(0, 3, 0), &is_valid_position); m_sneak_ladder_detected = is_valid_position && !nodemgr->get(node).walkable; } } return true; }
void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, std::vector<CollisionInfo> *collision_info) { if (!collision_info || collision_info->empty()) { // Node below the feet, update each ClientEnvironment::step() m_standing_node = floatToInt(m_position, BS) - v3s16(0, 1, 0); } // Temporary option for old move code if (!physics_override_new_move) { old_move(dtime, env, pos_max_d, collision_info); return; } Map *map = &env->getMap(); INodeDefManager *nodemgr = m_client->ndef(); v3f position = getPosition(); // Copy parent position if local player is attached if (isAttached) { setPosition(overridePosition); return; } // Skip collision detection if noclip mode is used bool fly_allowed = m_client->checkLocalPrivilege("fly"); bool noclip = m_client->checkLocalPrivilege("noclip") && g_settings->getBool("noclip"); bool free_move = g_settings->getBool("free_move") && fly_allowed; if (noclip && free_move) { position += m_speed * dtime; setPosition(position); return; } /* Collision detection */ bool is_valid_position; MapNode node; v3s16 pp; /* Check if player is in liquid (the oscillating value) */ // If in liquid, the threshold of coming out is at higher y if (in_liquid) { pp = floatToInt(position + v3f(0,BS*0.1,0), BS); node = map->getNodeNoEx(pp, &is_valid_position); if (is_valid_position) { in_liquid = nodemgr->get(node.getContent()).isLiquid(); liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; } else { in_liquid = false; } } // If not in liquid, the threshold of going in is at lower y else { pp = floatToInt(position + v3f(0,BS*0.5,0), BS); node = map->getNodeNoEx(pp, &is_valid_position); if (is_valid_position) { in_liquid = nodemgr->get(node.getContent()).isLiquid(); liquid_viscosity = nodemgr->get(node.getContent()).liquid_viscosity; } else { in_liquid = false; } } /* Check if player is in liquid (the stable value) */ pp = floatToInt(position + v3f(0,0,0), BS); node = map->getNodeNoEx(pp, &is_valid_position); if (is_valid_position) { in_liquid_stable = nodemgr->get(node.getContent()).isLiquid(); } else { in_liquid_stable = false; } /* Check if player is climbing */ pp = floatToInt(position + v3f(0,0.5*BS,0), BS); v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS); node = map->getNodeNoEx(pp, &is_valid_position); bool is_valid_position2; MapNode node2 = map->getNodeNoEx(pp2, &is_valid_position2); if (!(is_valid_position && is_valid_position2)) { is_climbing = false; } else { is_climbing = (nodemgr->get(node.getContent()).climbable || nodemgr->get(node2.getContent()).climbable) && !free_move; } /* Collision uncertainty radius Make it a bit larger than the maximum distance of movement */ //f32 d = pos_max_d * 1.1; // A fairly large value in here makes moving smoother f32 d = 0.15*BS; // This should always apply, otherwise there are glitches sanity_check(d > pos_max_d); // Player object property step height is multiplied by BS in // /src/script/common/c_content.cpp and /src/content_sao.cpp float player_stepheight = (m_cao == nullptr) ? 0.0f : (touching_ground ? m_cao->getStepHeight() : (0.2f * BS)); // TODO this is a problematic hack. // Use a better implementation for autojump, or apply a custom stepheight // to all players, as this currently creates unintended special movement // abilities and advantages for Android players on a server. #ifdef __ANDROID__ if (touching_ground) player_stepheight += (0.6f * BS); #endif v3f accel_f = v3f(0,0,0); collisionMoveResult result = collisionMoveSimple(env, m_client, pos_max_d, m_collisionbox, player_stepheight, dtime, &position, &m_speed, accel_f); bool could_sneak = control.sneak && !free_move && !in_liquid && !is_climbing && physics_override_sneak; // Add new collisions to the vector if (collision_info && !free_move) { v3f diff = intToFloat(m_standing_node, BS) - position; f32 distance = diff.getLength(); // Force update each ClientEnvironment::step() bool is_first = collision_info->empty(); for (const auto &colinfo : result.collisions) { collision_info->push_back(colinfo); if (colinfo.type != COLLISION_NODE || colinfo.new_speed.Y != 0 || (could_sneak && m_sneak_node_exists)) continue; diff = intToFloat(colinfo.node_p, BS) - position; // Find nearest colliding node f32 len = diff.getLength(); if (is_first || len < distance) { m_standing_node = colinfo.node_p; distance = len; } } } /* If the player's feet touch the topside of any node, this is set to true. Player is allowed to jump when this is true. */ bool touching_ground_was = touching_ground; touching_ground = result.touching_ground; bool sneak_can_jump = false; // Max. distance (X, Z) over border for sneaking determined by collision box // * 0.49 to keep the center just barely on the node v3f sneak_max = m_collisionbox.getExtent() * 0.49; if (m_sneak_ladder_detected) { // restore legacy behaviour (this makes the m_speed.Y hack necessary) sneak_max = v3f(0.4 * BS, 0, 0.4 * BS); } /* If sneaking, keep on top of last walked node and don't fall off */ if (could_sneak && m_sneak_node_exists) { const v3f sn_f = intToFloat(m_sneak_node, BS); const v3f bmin = sn_f + m_sneak_node_bb_top.MinEdge; const v3f bmax = sn_f + m_sneak_node_bb_top.MaxEdge; const v3f old_pos = position; const v3f old_speed = m_speed; f32 y_diff = bmax.Y - position.Y; m_standing_node = m_sneak_node; // (BS * 0.6f) is the basic stepheight while standing on ground if (y_diff < BS * 0.6f) { // Only center player when they're on the node position.X = rangelim(position.X, bmin.X - sneak_max.X, bmax.X + sneak_max.X); position.Z = rangelim(position.Z, bmin.Z - sneak_max.Z, bmax.Z + sneak_max.Z); if (position.X != old_pos.X) m_speed.X = 0; if (position.Z != old_pos.Z) m_speed.Z = 0; } if (y_diff > 0 && m_speed.Y < 0 && (physics_override_sneak_glitch || y_diff < BS * 0.6f)) { // Move player to the maximal height when falling or when // the ledge is climbed on the next step. position.Y = bmax.Y; m_speed.Y = 0; } // Allow jumping on node edges while sneaking if (m_speed.Y == 0 || m_sneak_ladder_detected) sneak_can_jump = true; if (collision_info && m_speed.Y - old_speed.Y > BS) { // Collide with sneak node, report fall damage CollisionInfo sn_info; sn_info.node_p = m_sneak_node; sn_info.old_speed = old_speed; sn_info.new_speed = m_speed; collision_info->push_back(sn_info); } } /* Find the next sneak node if necessary */ bool new_sneak_node_exists = false; if (could_sneak) new_sneak_node_exists = updateSneakNode(map, position, sneak_max); /* Set new position but keep sneak node set */ setPosition(position); m_sneak_node_exists = new_sneak_node_exists; /* Report collisions */ if(!result.standing_on_object && !touching_ground_was && touching_ground) { MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround"); m_client->event()->put(e); // Set camera impact value to be used for view bobbing camera_impact = getSpeed().Y * -1; } { camera_barely_in_ceiling = false; v3s16 camera_np = floatToInt(getEyePosition(), BS); MapNode n = map->getNodeNoEx(camera_np); if(n.getContent() != CONTENT_IGNORE){ if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){ camera_barely_in_ceiling = true; } } } /* Check properties of the node on which the player is standing */ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(m_standing_node)); // Determine if jumping is possible m_can_jump = (touching_ground && !in_liquid && !is_climbing) || sneak_can_jump; if (itemgroup_get(f.groups, "disable_jump")) m_can_jump = false; // Jump key pressed while jumping off from a bouncy block if (m_can_jump && control.jump && itemgroup_get(f.groups, "bouncy") && m_speed.Y >= -0.5 * BS) { float jumpspeed = movement_speed_jump * physics_override_jump; if (m_speed.Y > 1) { // Reduce boost when speed already is high m_speed.Y += jumpspeed / (1 + (m_speed.Y / 16 )); } else { m_speed.Y += jumpspeed; } setSpeed(m_speed); m_can_jump = false; } }
static void getTileInfo( // Input: MeshMakeData *data, v3s16 p, v3s16 face_dir, // Output: bool &makes_face, v3s16 &p_corrected, v3s16 &face_dir_corrected, u16 *lights, TileSpec &tile, u8 &light_source ) { VoxelManipulator &vmanip = data->m_vmanip; INodeDefManager *ndef = data->m_gamedef->ndef(); v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE; MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p); // Don't even try to get n1 if n0 is already CONTENT_IGNORE if (n0.getContent() == CONTENT_IGNORE ) { makes_face = false; return; } MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir); // This is hackish bool equivalent = false; u8 mf = face_contents(n0.getContent(), n1.getContent(), &equivalent, ndef); if(mf == 0) { makes_face = false; return; } makes_face = true; if(mf == 1) { tile = getNodeTile(n0, p, face_dir, data); p_corrected = p; face_dir_corrected = face_dir; light_source = ndef->get(n0).light_source; } else { tile = getNodeTile(n1, p + face_dir, -face_dir, data); p_corrected = p + face_dir; face_dir_corrected = -face_dir; light_source = ndef->get(n1).light_source; } // eg. water and glass if(equivalent) tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; if(data->m_smooth_lighting == false) { lights[0] = lights[1] = lights[2] = lights[3] = getFaceLight(n0, n1, face_dir, ndef); } else { v3s16 vertex_dirs[4]; getNodeVertexDirs(face_dir_corrected, vertex_dirs); for(u16 i=0; i<4; i++) { lights[i] = getSmoothLight( blockpos_nodes + p_corrected, vertex_dirs[i], data); } } return; }
void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_reload_ratio, ClientEnvironment &c_env) { // Get player position // Smooth the movement when walking up stairs v3f old_player_position = m_playernode->getPosition(); v3f player_position = player->getPosition(); if (player->isAttached && player->parent) player_position = player->parent->getPosition(); //if(player->touching_ground && player_position.Y > old_player_position.Y) if(player->touching_ground && player_position.Y > old_player_position.Y) { f32 oldy = old_player_position.Y; f32 newy = player_position.Y; f32 t = exp(-23*frametime); player_position.Y = oldy * t + newy * (1-t); } // Set player node transformation m_playernode->setPosition(player_position); m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0)); m_playernode->updateAbsolutePosition(); // Get camera tilt timer (hurt animation) float cameratilt = fabs(fabs(player->hurt_tilt_timer-0.75)-0.75); // Fall bobbing animation float fall_bobbing = 0; if(player->camera_impact >= 1 && m_camera_mode < CAMERA_MODE_THIRD) { if(m_view_bobbing_fall == -1) // Effect took place and has finished player->camera_impact = m_view_bobbing_fall = 0; else if(m_view_bobbing_fall == 0) // Initialize effect m_view_bobbing_fall = 1; // Convert 0 -> 1 to 0 -> 1 -> 0 fall_bobbing = m_view_bobbing_fall < 0.5 ? m_view_bobbing_fall * 2 : -(m_view_bobbing_fall - 0.5) * 2 + 1; // Smoothen and invert the above fall_bobbing = sin(fall_bobbing * 0.5 * M_PI) * -1; // Amplify according to the intensity of the impact fall_bobbing *= (1 - rangelim(50 / player->camera_impact, 0, 1)) * 5; fall_bobbing *= m_cache_fall_bobbing_amount; } // Calculate players eye offset for different camera modes v3f PlayerEyeOffset = player->getEyeOffset(); if (m_camera_mode == CAMERA_MODE_FIRST) PlayerEyeOffset += player->eye_offset_first; else PlayerEyeOffset += player->eye_offset_third; // Set head node transformation m_headnode->setPosition(PlayerEyeOffset+v3f(0,cameratilt*-player->hurt_tilt_strength+fall_bobbing,0)); m_headnode->setRotation(v3f(player->getPitch(), 0, cameratilt*player->hurt_tilt_strength)); m_headnode->updateAbsolutePosition(); // Compute relative camera position and target v3f rel_cam_pos = v3f(0,0,0); v3f rel_cam_target = v3f(0,0,1); v3f rel_cam_up = v3f(0,1,0); if (m_view_bobbing_anim != 0 && m_camera_mode < CAMERA_MODE_THIRD) { f32 bobfrac = my_modf(m_view_bobbing_anim * 2); f32 bobdir = (m_view_bobbing_anim < 0.5) ? 1.0 : -1.0; #if 1 f32 bobknob = 1.2; f32 bobtmp = sin(pow(bobfrac, bobknob) * M_PI); //f32 bobtmp2 = cos(pow(bobfrac, bobknob) * M_PI); v3f bobvec = v3f( 0.3 * bobdir * sin(bobfrac * M_PI), -0.28 * bobtmp * bobtmp, 0.); //rel_cam_pos += 0.2 * bobvec; //rel_cam_target += 0.03 * bobvec; //rel_cam_up.rotateXYBy(0.02 * bobdir * bobtmp * M_PI); float f = 1.0; f *= m_cache_view_bobbing_amount; rel_cam_pos += bobvec * f; //rel_cam_target += 0.995 * bobvec * f; rel_cam_target += bobvec * f; rel_cam_target.Z -= 0.005 * bobvec.Z * f; //rel_cam_target.X -= 0.005 * bobvec.X * f; //rel_cam_target.Y -= 0.005 * bobvec.Y * f; rel_cam_up.rotateXYBy(-0.03 * bobdir * bobtmp * M_PI * f); #else f32 angle_deg = 1 * bobdir * sin(bobfrac * M_PI); f32 angle_rad = angle_deg * M_PI / 180; f32 r = 0.05; v3f off = v3f( r * sin(angle_rad), r * (cos(angle_rad) - 1), 0); rel_cam_pos += off; //rel_cam_target += off; rel_cam_up.rotateXYBy(angle_deg); #endif } // Compute absolute camera position and target m_headnode->getAbsoluteTransformation().transformVect(m_camera_position, rel_cam_pos); m_headnode->getAbsoluteTransformation().rotateVect(m_camera_direction, rel_cam_target - rel_cam_pos); v3f abs_cam_up; m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up); // Seperate camera position for calculation v3f my_cp = m_camera_position; // Reposition the camera for third person view if (m_camera_mode > CAMERA_MODE_FIRST) { if (m_camera_mode == CAMERA_MODE_THIRD_FRONT) m_camera_direction *= -1; my_cp.Y += 2; // Calculate new position bool abort = false; for (int i = BS; i <= BS*2.75; i++) { my_cp.X = m_camera_position.X + m_camera_direction.X*-i; my_cp.Z = m_camera_position.Z + m_camera_direction.Z*-i; if (i > 12) my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i); // Prevent camera positioned inside nodes INodeDefManager *nodemgr = m_gamedef->ndef(); MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS)); const ContentFeatures& features = nodemgr->get(n); if(features.walkable) { my_cp.X += m_camera_direction.X*-1*-BS/2; my_cp.Z += m_camera_direction.Z*-1*-BS/2; my_cp.Y += m_camera_direction.Y*-1*-BS/2; abort = true; break; } } // If node blocks camera position don't move y to heigh if (abort && my_cp.Y > player_position.Y+BS*2) my_cp.Y = player_position.Y+BS*2; } // Update offset if too far away from the center of the map m_camera_offset.X += CAMERA_OFFSET_STEP* (((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP); m_camera_offset.Y += CAMERA_OFFSET_STEP* (((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP); m_camera_offset.Z += CAMERA_OFFSET_STEP* (((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP); // Set camera node transformation m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS)); m_cameranode->setUpVector(abs_cam_up); // *100.0 helps in large map coordinates m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction); // update the camera position in front-view mode to render blocks behind player if (m_camera_mode == CAMERA_MODE_THIRD_FRONT) m_camera_position = my_cp; // Get FOV setting f32 fov_degrees = m_cache_fov; fov_degrees = MYMAX(fov_degrees, 10.0); fov_degrees = MYMIN(fov_degrees, 170.0); // FOV and aspect ratio m_aspect = (f32) porting::getWindowSize().X / (f32) porting::getWindowSize().Y; m_fov_y = fov_degrees * M_PI / 180.0; // Increase vertical FOV on lower aspect ratios (<16:10) m_fov_y *= MYMAX(1.0, MYMIN(1.4, sqrt(16./10. / m_aspect))); m_fov_x = 2 * atan(m_aspect * tan(0.5 * m_fov_y)); m_cameranode->setAspectRatio(m_aspect); m_cameranode->setFOV(m_fov_y); // Position the wielded item //v3f wield_position = v3f(45, -35, 65); v3f wield_position = v3f(55, -35, 65); //v3f wield_rotation = v3f(-100, 120, -100); v3f wield_rotation = v3f(-100, 120, -100); wield_position.Y += fabs(m_wield_change_timer)*320 - 40; if(m_digging_anim < 0.05 || m_digging_anim > 0.5) { f32 frac = 1.0; if(m_digging_anim > 0.5) frac = 2.0 * (m_digging_anim - 0.5); // This value starts from 1 and settles to 0 f32 ratiothing = pow((1.0f - tool_reload_ratio), 0.5f); //f32 ratiothing2 = pow(ratiothing, 0.5f); f32 ratiothing2 = (easeCurve(ratiothing*0.5))*2.0; wield_position.Y -= frac * 25.0 * pow(ratiothing2, 1.7f); //wield_position.Z += frac * 5.0 * ratiothing2; wield_position.X -= frac * 35.0 * pow(ratiothing2, 1.1f); wield_rotation.Y += frac * 70.0 * pow(ratiothing2, 1.4f); //wield_rotation.X -= frac * 15.0 * pow(ratiothing2, 1.4f); //wield_rotation.Z += frac * 15.0 * pow(ratiothing2, 1.0f); } if (m_digging_button != -1) { f32 digfrac = m_digging_anim; wield_position.X -= 50 * sin(pow(digfrac, 0.8f) * M_PI); wield_position.Y += 24 * sin(digfrac * 1.8 * M_PI); wield_position.Z += 25 * 0.5; // Euler angles are PURE EVIL, so why not use quaternions? core::quaternion quat_begin(wield_rotation * core::DEGTORAD); core::quaternion quat_end(v3f(80, 30, 100) * core::DEGTORAD); core::quaternion quat_slerp; quat_slerp.slerp(quat_begin, quat_end, sin(digfrac * M_PI)); quat_slerp.toEuler(wield_rotation); wield_rotation *= core::RADTODEG; } else { f32 bobfrac = my_modf(m_view_bobbing_anim); wield_position.X -= sin(bobfrac*M_PI*2.0) * 3.0; wield_position.Y += sin(my_modf(bobfrac*2.0)*M_PI) * 3.0; } m_wieldnode->setPosition(wield_position); m_wieldnode->setRotation(wield_rotation); m_wieldnode->setColor(player->light_color); // Render distance feedback loop updateViewingRange(frametime, busytime); // If the player is walking, swimming, or climbing, // view bobbing is enabled and free_move is off, // start (or continue) the view bobbing animation. v3f speed = player->getSpeed(); const bool movement_XZ = hypot(speed.X, speed.Z) > BS; const bool movement_Y = fabs(speed.Y) > BS; const bool walking = movement_XZ && player->touching_ground; const bool swimming = (movement_XZ || player->swimming_vertical) && player->in_liquid; const bool climbing = movement_Y && player->is_climbing; if ((walking || swimming || climbing) && m_cache_view_bobbing && (!g_settings->getBool("free_move") || !m_gamedef->checkLocalPrivilege("fly"))) { // Start animation m_view_bobbing_state = 1; m_view_bobbing_speed = MYMIN(speed.getLength(), 40); } else if (m_view_bobbing_state == 1) { // Stop animation m_view_bobbing_state = 2; m_view_bobbing_speed = 60; } }
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_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; 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; }
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 }
/* Propagates sunlight down through the block. Doesn't modify nodes that are not affected by sunlight. Returns false if sunlight at bottom block is invalid. Returns true if sunlight at bottom block is valid. Returns true if bottom block doesn't exist. If there is a block above, continues from it. If there is no block above, assumes there is sunlight, unless is_underground is set or highest node is water. All sunlighted nodes are added to light_sources. if remove_light==true, sets non-sunlighted nodes black. if black_air_left!=NULL, it is set to true if non-sunlighted air is left in block. */ bool MapBlock::propagateSunlight(std::set<v3s16> & light_sources, bool remove_light, bool *black_air_left) { INodeDefManager *nodemgr = m_gamedef->ndef(); // Whether the sunlight at the top of the bottom block is valid bool block_below_is_valid = true; v3s16 pos_relative = getPosRelative(); for(s16 x=0; x<MAP_BLOCKSIZE; x++) { for(s16 z=0; z<MAP_BLOCKSIZE; z++) { #if 1 bool no_sunlight = false; bool no_top_block = false; // Check if node above block has sunlight try{ MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); if(n.getContent() == CONTENT_IGNORE) { // Trust heuristics no_sunlight = is_underground; } else if(n.getLight(LIGHTBANK_DAY, m_gamedef->ndef()) != LIGHT_SUN) { no_sunlight = true; } } catch(InvalidPositionException &e) { no_top_block = true; // NOTE: This makes over-ground roofed places sunlighted // Assume sunlight, unless is_underground==true if(is_underground) { no_sunlight = true; } else { MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z)); if(m_gamedef->ndef()->get(n).sunlight_propagates == false) { no_sunlight = true; } } // NOTE: As of now, this just would make everything dark. // No sunlight here //no_sunlight = true; } #endif #if 0 // Doesn't work; nothing gets light. bool no_sunlight = true; bool no_top_block = false; // Check if node above block has sunlight try{ MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN) { no_sunlight = false; } } catch(InvalidPositionException &e) { no_top_block = true; } #endif /*std::cout<<"("<<x<<","<<z<<"): " <<"no_top_block="<<no_top_block <<", is_underground="<<is_underground <<", no_sunlight="<<no_sunlight <<std::endl;*/ s16 y = MAP_BLOCKSIZE-1; // This makes difference to diminishing in water. bool stopped_to_solid_object = false; u8 current_light = no_sunlight ? 0 : LIGHT_SUN; for(; y >= 0; y--) { v3s16 pos(x, y, z); MapNode &n = getNodeRef(pos); if(current_light == 0) { // Do nothing } else if(current_light == LIGHT_SUN && nodemgr->get(n).sunlight_propagates) { // Do nothing: Sunlight is continued } else if(nodemgr->get(n).light_propagates == false) { // A solid object is on the way. stopped_to_solid_object = true; // Light stops. current_light = 0; } else { // Diminish light current_light = diminish_light(current_light); } u8 old_light = n.getLight(LIGHTBANK_DAY, nodemgr); if(current_light > old_light || remove_light) { n.setLight(LIGHTBANK_DAY, current_light, nodemgr); } if(diminish_light(current_light) != 0) { light_sources.insert(pos_relative + pos); } if(current_light == 0 && stopped_to_solid_object) { if(black_air_left) { *black_air_left = true; } } } // Whether or not the block below should see LIGHT_SUN bool sunlight_should_go_down = (current_light == LIGHT_SUN); /* If the block below hasn't already been marked invalid: Check if the node below the block has proper sunlight at top. If not, the block below is invalid. Ignore non-transparent nodes as they always have no light */ try { if(block_below_is_valid) { MapNode n = getNodeParent(v3s16(x, -1, z)); if(nodemgr->get(n).light_propagates) { if(n.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN && sunlight_should_go_down == false) block_below_is_valid = false; else if(n.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN && sunlight_should_go_down == true) block_below_is_valid = false; } }//if }//try catch(InvalidPositionException &e) { /*std::cout<<"InvalidBlockException for bottom block node" <<std::endl;*/ // Just no block below, no need to panic. } } } return block_below_is_valid; }
void LocalPlayer::move(f32 dtime, ClientEnvironment *env, f32 pos_max_d, std::list<CollisionInfo> *collision_info) { Map *map = &env->getMap(); INodeDefManager *nodemgr = m_gamedef->ndef(); v3f position = getPosition(); v3f old_speed = m_speed; // Copy parent position if local player is attached if(isAttached) { setPosition(overridePosition); return; } // Skip collision detection if noclip mode is used bool fly_allowed = m_gamedef->checkLocalPrivilege("fly"); bool noclip = m_gamedef->checkLocalPrivilege("noclip") && g_settings->getBool("noclip"); bool free_move = noclip && fly_allowed && g_settings->getBool("free_move"); if(free_move) { position += m_speed * dtime; setPosition(position); return; } /* Collision detection */ /* Check if player is in liquid (the oscillating value) */ try{ // If in liquid, the threshold of coming out is at higher y if(in_liquid) { v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS); in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity; } // If not in liquid, the threshold of going in is at lower y else { v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS); in_liquid = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); liquid_viscosity = nodemgr->get(map->getNode(pp).getContent()).liquid_viscosity; } } catch(InvalidPositionException &e) { in_liquid = false; } /* Check if player is in liquid (the stable value) */ try{ v3s16 pp = floatToInt(position + v3f(0,0,0), BS); in_liquid_stable = nodemgr->get(map->getNode(pp).getContent()).isLiquid(); } catch(InvalidPositionException &e) { in_liquid_stable = false; } /* Check if player is climbing */ try { v3s16 pp = floatToInt(position + v3f(0,0.5*BS,0), BS); v3s16 pp2 = floatToInt(position + v3f(0,-0.2*BS,0), BS); is_climbing = ((nodemgr->get(map->getNode(pp).getContent()).climbable || nodemgr->get(map->getNode(pp2).getContent()).climbable) && !free_move); } catch(InvalidPositionException &e) { is_climbing = false; } /* Collision uncertainty radius Make it a bit larger than the maximum distance of movement */ //f32 d = pos_max_d * 1.1; // A fairly large value in here makes moving smoother f32 d = 0.15*BS; // This should always apply, otherwise there are glitches assert(d > pos_max_d); float player_radius = BS*0.30; float player_height = BS*1.55; // Maximum distance over border for sneaking f32 sneak_max = BS*0.4; /* If sneaking, keep in range from the last walked node and don't fall off from it */ if(control.sneak && m_sneak_node_exists && !(fly_allowed && g_settings->getBool("free_move")) && !in_liquid) { f32 maxd = 0.5*BS + sneak_max; v3f lwn_f = intToFloat(m_sneak_node, BS); position.X = rangelim(position.X, lwn_f.X-maxd, lwn_f.X+maxd); position.Z = rangelim(position.Z, lwn_f.Z-maxd, lwn_f.Z+maxd); if(!is_climbing) { f32 min_y = lwn_f.Y + 0.5*BS; if(position.Y < min_y) { position.Y = min_y; if(m_speed.Y < 0) m_speed.Y = 0; } } } /* Calculate player collision box (new and old) */ core::aabbox3d<f32> playerbox( -player_radius, 0.0, -player_radius, player_radius, player_height, player_radius ); float player_stepheight = touching_ground ? (BS*0.6) : (BS*0.2); v3f accel_f = v3f(0,0,0); collisionMoveResult result = collisionMoveSimple(env, m_gamedef, pos_max_d, playerbox, player_stepheight, dtime, position, m_speed, accel_f); /* If the player's feet touch the topside of any node, this is set to true. Player is allowed to jump when this is true. */ bool touching_ground_was = touching_ground; touching_ground = result.touching_ground; //bool standing_on_unloaded = result.standing_on_unloaded; /* Check the nodes under the player to see from which node the player is sneaking from, if any. If the node from under the player has been removed, the player falls. */ v3s16 current_node = floatToInt(position - v3f(0,BS/2,0), BS); if(m_sneak_node_exists && nodemgr->get(map->getNodeNoEx(m_old_node_below)).name == "air" && m_old_node_below_type != "air") { // Old node appears to have been removed; that is, // it wasn't air before but now it is m_need_to_get_new_sneak_node = false; m_sneak_node_exists = false; } else if(nodemgr->get(map->getNodeNoEx(current_node)).name != "air") { // We are on something, so make sure to recalculate the sneak // node. m_need_to_get_new_sneak_node = true; } if(m_need_to_get_new_sneak_node) { v3s16 pos_i_bottom = floatToInt(position - v3f(0,BS/2,0), BS); v2f player_p2df(position.X, position.Z); f32 min_distance_f = 100000.0*BS; // If already seeking from some node, compare to it. /*if(m_sneak_node_exists) { v3f sneaknode_pf = intToFloat(m_sneak_node, BS); v2f sneaknode_p2df(sneaknode_pf.X, sneaknode_pf.Z); f32 d_horiz_f = player_p2df.getDistanceFrom(sneaknode_p2df); f32 d_vert_f = fabs(sneaknode_pf.Y + BS*0.5 - position.Y); // Ignore if player is not on the same level (likely dropped) if(d_vert_f < 0.15*BS) min_distance_f = d_horiz_f; }*/ v3s16 new_sneak_node = m_sneak_node; for(s16 x=-1; x<=1; x++) for(s16 z=-1; z<=1; z++) { v3s16 p = pos_i_bottom + v3s16(x,0,z); v3f pf = intToFloat(p, BS); v2f node_p2df(pf.X, pf.Z); f32 distance_f = player_p2df.getDistanceFrom(node_p2df); f32 max_axis_distance_f = MYMAX( fabs(player_p2df.X-node_p2df.X), fabs(player_p2df.Y-node_p2df.Y)); if(distance_f > min_distance_f || max_axis_distance_f > 0.5*BS + sneak_max + 0.1*BS) continue; try{ // The node to be sneaked on has to be walkable if(nodemgr->get(map->getNode(p)).walkable == false) continue; // And the node above it has to be nonwalkable if(nodemgr->get(map->getNode(p+v3s16(0,1,0))).walkable == true) continue; } catch(InvalidPositionException &e) { continue; } min_distance_f = distance_f; new_sneak_node = p; } bool sneak_node_found = (min_distance_f < 100000.0*BS*0.9); m_sneak_node = new_sneak_node; m_sneak_node_exists = sneak_node_found; /* If sneaking, the player's collision box can be in air, so this has to be set explicitly */ if(sneak_node_found && control.sneak) touching_ground = true; } /* Set new position */ setPosition(position); /* Report collisions */ bool bouncy_jump = false; // Dont report if flying if(collision_info && !(g_settings->getBool("free_move") && fly_allowed)) { for(size_t i=0; i<result.collisions.size(); i++){ const CollisionInfo &info = result.collisions[i]; collision_info->push_back(info); if(info.new_speed.Y - info.old_speed.Y > 0.1*BS && info.bouncy) bouncy_jump = true; } } if(bouncy_jump && control.jump){ m_speed.Y += movement_speed_jump*BS; touching_ground = false; MtEvent *e = new SimpleTriggerEvent("PlayerJump"); m_gamedef->event()->put(e); } if(!touching_ground_was && touching_ground){ MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround"); m_gamedef->event()->put(e); } { camera_barely_in_ceiling = false; v3s16 camera_np = floatToInt(getEyePosition(), BS); MapNode n = map->getNodeNoEx(camera_np); if(n.getContent() != CONTENT_IGNORE){ if(nodemgr->get(n).walkable && nodemgr->get(n).solidness == 2){ camera_barely_in_ceiling = true; } } } /* Update the node last under the player */ m_old_node_below = floatToInt(position - v3f(0,BS/2,0), BS); m_old_node_below_type = nodemgr->get(map->getNodeNoEx(m_old_node_below)).name; /* Check properties of the node on which the player is standing */ const ContentFeatures &f = nodemgr->get(map->getNodeNoEx(getStandingNodePos())); // Determine if jumping is possible m_can_jump = touching_ground && !in_liquid; if(itemgroup_get(f.groups, "disable_jump")) m_can_jump = false; }
// register_decoration({lots of stuff}) int ModApiMapgen::l_register_decoration(lua_State *L) { int index = 1; luaL_checktype(L, index, LUA_TTABLE); INodeDefManager *ndef = getServer(L)->getNodeDefManager(); DecorationManager *decomgr = getServer(L)->getEmergeManager()->decomgr; BiomeManager *biomemgr = getServer(L)->getEmergeManager()->biomemgr; SchematicManager *schemmgr = getServer(L)->getEmergeManager()->schemmgr; enum DecorationType decotype = (DecorationType)getenumfield(L, index, "deco_type", es_DecorationType, -1); Decoration *deco = decomgr->create(decotype); if (!deco) { errorstream << "register_decoration: decoration placement type " << decotype << " not implemented" << std::endl; return 0; } deco->name = getstringfield_default(L, index, "name", ""); deco->fill_ratio = getfloatfield_default(L, index, "fill_ratio", 0.02); deco->y_min = getintfield_default(L, index, "y_min", -31000); deco->y_max = getintfield_default(L, index, "y_max", 31000); deco->sidelen = getintfield_default(L, index, "sidelen", 8); if (deco->sidelen <= 0) { errorstream << "register_decoration: sidelen must be " "greater than 0" << std::endl; delete deco; return 0; } //// Get node name(s) to place decoration on size_t nread = getstringlistfield(L, index, "place_on", &deco->m_nodenames); deco->m_nnlistsizes.push_back(nread); //// Get decoration flags getflagsfield(L, index, "flags", flagdesc_deco, &deco->flags, NULL); //// Get NoiseParams to define how decoration is placed lua_getfield(L, index, "noise_params"); if (read_noiseparams(L, -1, &deco->np)) deco->flags |= DECO_USE_NOISE; lua_pop(L, 1); //// Get biomes associated with this decoration (if any) lua_getfield(L, index, "biomes"); if (get_biome_list(L, -1, biomemgr, &deco->biomes)) errorstream << "register_decoration: couldn't get all biomes " << std::endl; lua_pop(L, 1); //// Handle decoration type-specific parameters bool success = false; switch (decotype) { case DECO_SIMPLE: success = read_deco_simple(L, (DecoSimple *)deco); break; case DECO_SCHEMATIC: success = read_deco_schematic(L, schemmgr, (DecoSchematic *)deco); break; case DECO_LSYSTEM: break; } if (!success) { delete deco; return 0; } ndef->pendNodeResolve(deco, NODE_RESOLVE_DEFERRED); ObjDefHandle handle = decomgr->add(deco); if (handle == OBJDEF_INVALID_HANDLE) { delete deco; return 0; } lua_pushinteger(L, handle); return 1; }
/* Calculate smooth lighting at the XYZ- corner of p. Both light banks */ static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data) { static const v3s16 dirs8[8] = { v3s16(0,0,0), v3s16(0,0,1), v3s16(0,1,0), v3s16(0,1,1), v3s16(1,0,0), v3s16(1,1,0), v3s16(1,0,1), v3s16(1,1,1), }; INodeDefManager *ndef = data->m_gamedef->ndef(); u16 ambient_occlusion = 0; u16 light_count = 0; u8 light_source_max = 0; u16 light_day = 0; u16 light_night = 0; for (u32 i = 0; i < 8; i++) { const MapNode &n = data->m_vmanip.getNodeRefUnsafeCheckFlags(p - dirs8[i]); // if it's CONTENT_IGNORE we can't do any light calculations if (n.getContent() == CONTENT_IGNORE) { continue; } const ContentFeatures &f = ndef->get(n); if (f.light_source > light_source_max) light_source_max = f.light_source; // Check f.solidness because fast-style leaves look better this way if (f.param_type == CPT_LIGHT && f.solidness != 2) { light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f)); light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f)); light_count++; } else { ambient_occlusion++; } } if(light_count == 0) return 0xffff; light_day /= light_count; light_night /= light_count; // Boost brightness around light sources bool skip_ambient_occlusion_day = false; if(decode_light(light_source_max) >= light_day) { light_day = decode_light(light_source_max); skip_ambient_occlusion_day = true; } bool skip_ambient_occlusion_night = false; if(decode_light(light_source_max) >= light_night) { light_night = decode_light(light_source_max); skip_ambient_occlusion_night = true; } if (ambient_occlusion > 4) { static const float ao_gamma = rangelim( g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0); // Table of gamma space multiply factors. static const float light_amount[3] = { powf(0.75, 1.0 / ao_gamma), powf(0.5, 1.0 / ao_gamma), powf(0.25, 1.0 / ao_gamma) }; //calculate table index for gamma space multiplier ambient_occlusion -= 5; if (!skip_ambient_occlusion_day) light_day = rangelim(core::round32(light_day*light_amount[ambient_occlusion]), 0, 255); if (!skip_ambient_occlusion_night) light_night = rangelim(core::round32(light_night*light_amount[ambient_occlusion]), 0, 255); } return light_day | (light_night << 8); }
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; MapgenValleysParams *sp = (MapgenValleysParams *)params->sparams; this->spflags = sp->spflags; this->cliff_terrain = (spflags & MG_VALLEYS_CLIFFS); this->fast_terrain = (spflags & MG_VALLEYS_FAST); this->humid_rivers = (spflags & MG_VALLEYS_HUMID_RIVERS); this->rugged_terrain = (spflags & MG_VALLEYS_RUGGED); this->use_altitude_chill = (spflags & MG_VALLEYS_ALT_CHILL); this->altitude_chill = sp->altitude_chill; this->cave_water_max_height = sp->cave_water_max_height; this->humidity_adjust = sp->humidity - 50.f; this->humidity_break_point = sp->humidity_break_point; this->lava_max_height = sp->lava_max_height; this->river_depth = sp->river_depth + 1.f; this->river_size = sp->river_size / 100.f; this->temperature_adjust = sp->temperature - 50.f; this->water_features = MYMAX(1, MYMIN(11, 11 - sp->water_features)); //// 2D Terrain noise noise_cliffs = new Noise(&sp->np_cliffs, seed, csize.X, csize.Z); noise_corr = new Noise(&sp->np_corr, seed, csize.X, csize.Z); 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); if (this->fast_terrain) noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, seed, csize.X, csize.Z); //// 3D Terrain noise noise_simple_caves_1 = new Noise(&sp->np_simple_caves_1, seed, csize.X, csize.Y + 2, csize.Z); noise_simple_caves_2 = new Noise(&sp->np_simple_caves_2, seed, csize.X, csize.Y + 2, csize.Z); if (!this->fast_terrain) noise_inter_valley_fill = new Noise(&sp->np_inter_valley_fill, 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; }
u32 Map::updateLighting(concurrent_map<v3POS, MapBlock*> & a_blocks, std::map<v3POS, MapBlock*> & modified_blocks, unsigned int max_cycle_ms) { INodeDefManager *nodemgr = m_gamedef->ndef(); int ret = 0; int loopcount = 0; TimeTaker timer("updateLighting"); // For debugging //bool debug=true; //u32 count_was = modified_blocks.size(); //std::unordered_set<v3POS, v3POSHash, v3POSEqual> light_sources; //std::unordered_map<v3POS, u8, v3POSHash, v3POSEqual> unlight_from_day, unlight_from_night; std::set<v3POS> light_sources; std::map<v3POS, u8> unlight_from_day, unlight_from_night; unordered_map_v3POS<int> processed; int num_bottom_invalid = 0; //MutexAutoLock lock2(m_update_lighting_mutex); #if !ENABLE_THREADS auto lock = m_nothread_locker.lock_unique_rec(); #endif { //TimeTaker t("updateLighting: first stuff"); u32 end_ms = porting::getTimeMs() + max_cycle_ms; for(auto i = a_blocks.begin(); i != a_blocks.end(); ++i) { auto block = getBlockNoCreateNoEx(i->first); for(;;) { // Don't bother with dummy blocks. if(!block || block->isDummy()) break; auto lock = block->try_lock_unique_rec(); if (!lock->owns_lock()) break; // may cause dark areas v3POS pos = block->getPos(); if (processed.count(pos) && processed[pos] <= i->first.Y ) { break; } ++loopcount; processed[pos] = i->first.Y; v3POS posnodes = block->getPosRelative(); //modified_blocks[pos] = block; block->setLightingExpired(true); block->lighting_broken = true; /* Clear all light from block */ for(s16 z = 0; z < MAP_BLOCKSIZE; z++) for(s16 x = 0; x < MAP_BLOCKSIZE; x++) for(s16 y = 0; y < MAP_BLOCKSIZE; y++) { v3POS p(x, y, z); bool is_valid_position; MapNode n = block->getNode(p, &is_valid_position); if (!is_valid_position) { /* This would happen when dealing with a dummy block. */ infostream << "updateLighting(): InvalidPositionException" << std::endl; continue; } u8 oldlight_day = n.getLight(LIGHTBANK_DAY, nodemgr); u8 oldlight_night = n.getLight(LIGHTBANK_NIGHT, nodemgr); n.setLight(LIGHTBANK_DAY, 0, nodemgr); n.setLight(LIGHTBANK_NIGHT, 0, nodemgr); block->setNode(p, n); // If node sources light, add to list //u8 source = nodemgr->get(n).light_source; if(nodemgr->get(n).light_source) light_sources.insert(p + posnodes); v3POS p_map = p + posnodes; // Collect borders for unlighting if(x == 0 || x == MAP_BLOCKSIZE - 1 || y == 0 || y == MAP_BLOCKSIZE - 1 || z == 0 || z == MAP_BLOCKSIZE - 1) { if(oldlight_day) unlight_from_day[p_map] = oldlight_day; if(oldlight_night) unlight_from_night[p_map] = oldlight_night; } } lock->unlock(); bool bottom_valid = propagateSunlight(pos, light_sources); if(!bottom_valid) num_bottom_invalid++; pos.Y--; block = getBlockNoCreateNoEx(pos); } if (porting::getTimeMs() > end_ms) { ++ret; break; } } } { //TimeTaker timer("updateLighting: unspreadLight"); unspreadLight(LIGHTBANK_DAY, unlight_from_day, light_sources, modified_blocks); unspreadLight(LIGHTBANK_NIGHT, unlight_from_night, light_sources, modified_blocks); } { //TimeTaker timer("updateLighting: spreadLight"); spreadLight(LIGHTBANK_DAY, light_sources, modified_blocks, porting::getTimeMs() + max_cycle_ms * 10); spreadLight(LIGHTBANK_NIGHT, light_sources, modified_blocks, porting::getTimeMs() + max_cycle_ms * 10); } for (auto & i : processed) { a_blocks.erase(i.first); MapBlock *block = getBlockNoCreateNoEx(i.first); if(!block) continue; block->setLightingExpired(false); block->lighting_broken = false; } g_profiler->add("Server: light blocks", loopcount); return ret; }
void FallingSAO::step(float dtime, bool send_recommended) { // Object pending removal, skip if (m_removed || !m_env) { return; } // If no texture, remove it if (m_prop.textures.empty()) { m_removed = true; return; } LuaEntitySAO::step(dtime, send_recommended); INodeDefManager* ndef = m_env->getGameDef()->getNodeDefManager(); m_acceleration = v3f(0,-10*BS,0); // Under node, center v3f p_under(m_base_position.X, m_base_position.Y - 7, m_base_position.Z); v3s16 p = floatToInt(m_base_position, BS); /* bool cur_exists = false, under_exists = false; */ MapNode n = m_env->getMap().getNode(p), n_under = m_env->getMap().getNode(floatToInt(p_under, BS)); const ContentFeatures &f = ndef->get(n), &f_under = ndef->get(n_under); bool cur_exists = n, under_exists = n_under; // Mapblock current or under is not loaded, stop there if (!n || !cur_exists || !under_exists) { return; } if ((f_under.walkable || (itemgroup_get(f_under.groups, "float") && f_under.liquid_type == LIQUID_NONE))) { if (f_under.leveled && f_under.name.compare(f.name) == 0) { u8 addLevel = n.getLevel(ndef); if (addLevel == 0) { addLevel = n_under.getLevel(ndef); } if (n_under.addLevel(ndef, addLevel)) { m_removed = true; return; } } else if (f_under.buildable_to && (itemgroup_get(f.groups,"float") == 0 || f_under.liquid_type == LIQUID_NONE)) { m_env->removeNode(floatToInt(p_under, BS), fast); return; } if (n.getContent() != CONTENT_AIR && (f.liquid_type == LIQUID_NONE)) { m_env->removeNode(p); if (!f.buildable_to) { ItemStack stack; std::string n_name = ndef->get(m_node).name; stack.deSerialize(n_name); m_env->spawnItemActiveObject(n_name, m_base_position, stack); } } m_env->setNode(p, m_node, fast); m_removed = true; m_env->nodeUpdate(p, 2, fast); return; } }
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); 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); } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) { setCube(f.tiles, def.wield_scale, tsrc); } else { Map map(gamedef); MapDrawControl map_draw_control; MeshMakeData mesh_make_data(gamedef, map, map_draw_control); 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)); } for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) { assert(i < 6); 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); return; } // no wield mesh found changeToMesh(NULL); }