s16 MapBlock::getGroundLevel(v2s16 p2d) { auto lock = lock_shared_rec(); if(isDummy()) return -3; try { s16 y = MAP_BLOCKSIZE-1; for(; y>=0; y--) { MapNode n = getNodeRef(p2d.X, y, p2d.Y); if(m_gamedef->ndef()->get(n).walkable) { if(y == MAP_BLOCKSIZE-1) return -2; else return y; } } return -1; } catch(InvalidPositionException &e) { return -3; } }
void MapBlock::copyTo(VoxelManipulator &dst) { auto lock = lock_shared_rec(); v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE); VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1)); // Copy from data to VoxelManipulator dst.copyFrom(data, data_area, v3s16(0,0,0), getPosRelative(), data_size); }
void MapBlock::actuallyUpdateDayNightDiff() { INodeDefManager *nodemgr = m_gamedef->ndef(); // Running this function un-expires m_day_night_differs m_day_night_differs_expired = false; if (data == NULL) { m_day_night_differs = false; return; } bool differs; /* Check if any lighting value differs */ auto lock = lock_shared_rec(); for (u32 i = 0; i < MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++) { MapNode &n = data[i]; differs = !n.isLightDayNightEq(nodemgr); if (differs) break; } /* If some lighting values differ, check if the whole thing is just air. If it is just air, differs = false */ if (differs) { bool only_air = true; for (u32 i = 0; i < MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++) { MapNode &n = data[i]; if (n.getContent() != CONTENT_AIR) { only_air = false; break; } } if (only_air) differs = false; } // Set member variable m_day_night_differs = differs; }
void MapBlock::serialize(std::ostream &os, u8 version, bool disk) { auto lock = lock_shared_rec(); if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); if(data == NULL) { throw SerializationError("ERROR: Not writing dummy block."); } FATAL_ERROR_IF(version < SER_FMT_CLIENT_VER_LOWEST, "Serialize version error"); // First byte u8 flags = 0; if(is_underground) flags |= 0x01; if(getDayNightDiff()) flags |= 0x02; if(m_lighting_expired) flags |= 0x04; if(m_generated == false) { flags |= 0x08; infostream<<" serialize not generated block"<<std::endl; } writeU8(os, flags); /* Bulk node data */ NameIdMapping nimap; u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; if(disk) { MapNode *tmp_nodes = new MapNode[nodecount]; for(u32 i=0; i<nodecount; i++) tmp_nodes[i] = data[i]; getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef()); u8 content_width = 2; u8 params_width = 2; writeU8(os, content_width); writeU8(os, params_width); MapNode::serializeBulk(os, version, tmp_nodes, nodecount, content_width, params_width, true); delete[] tmp_nodes; } else { u8 content_width = 2; u8 params_width = 2; writeU8(os, content_width); writeU8(os, params_width); MapNode::serializeBulk(os, version, data, nodecount, content_width, params_width, true); } /* Node metadata */ std::ostringstream oss(std::ios_base::binary); m_node_metadata.serialize(oss); compressZlib(oss.str(), os); /* Data that goes to disk, but not the network */ if(disk) { if(version <= 24){ // Node timers m_node_timers.serialize(os, version); } // Static objects m_static_objects.serialize(os); // Timestamp writeU32(os, getTimestamp()); // Write block-specific node definition id mapping nimap.serialize(os); if(version >= 25){ // Node timers m_node_timers.serialize(os, version); } } }
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) { DSTACK(__FUNCTION_NAME); bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT; std::string prefix; if(pass == scene::ESNRP_SOLID) prefix = "CM: solid: "; else prefix = "CM: transparent: "; //ScopeProfiler sp(g_profiler, "CM::renderMap() " + prefix, SPT_AVG); /* Get time for measuring timeout. Measuring time is very useful for long delays when the machine is swapping a lot. */ //int time1 = time(0); /* Get animation parameters */ float animation_time = m_client->getAnimationTime(); int crack = m_client->getCrackLevel(); u32 daynight_ratio = m_client->getEnv().getDayNightRatio(); m_camera_mutex.Lock(); v3f camera_position = m_camera_position; f32 camera_fov = m_camera_fov * 1.1; m_camera_mutex.Unlock(); /* Get all blocks and draw all visible ones */ v3s16 cam_pos_nodes = floatToInt(camera_position, BS); u32 vertex_count = 0; u32 meshbuffer_count = 0; // For limiting number of mesh animations per frame u32 mesh_animate_count = 0; u32 mesh_animate_count_far = 0; // Blocks that were drawn and had a mesh u32 blocks_drawn = 0; // Blocks which had a corresponding meshbuffer for this pass u32 blocks_had_pass_meshbuf = 0; // Blocks from which stuff was actually drawn u32 blocks_without_stuff = 0; /* Draw the selected MapBlocks */ { //ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG); MeshBufListList drawbufs; std::vector<MapBlock::mesh_type> used_meshes; //keep shared_ptr auto drawlist = m_drawlist.load(); auto lock = drawlist->lock_shared_rec(); used_meshes.reserve(drawlist->size()); //g_profiler->add("CM::renderMap()cnt"+ prefix, drawlist->size()); for(auto & ir : *drawlist) { auto block = ir.second; int mesh_step = getFarmeshStep(m_control, getNodeBlockPos(cam_pos_nodes), block->getPos()); // If the mesh of the block happened to get deleted, ignore it auto mapBlockMesh = block->getMesh(mesh_step); if (!mapBlockMesh) continue; float d = 0.0; if(isBlockInSight(block->getPos(), camera_position, m_camera_direction, camera_fov, 100000*BS, &d) == false) { continue; } used_meshes.emplace_back(mapBlockMesh); // Mesh animation { //JMutexAutoLock lock(block->mesh_mutex); mapBlockMesh->updateCameraOffset(m_camera_offset); // Pretty random but this should work somewhat nicely bool faraway = d >= BS*50; //bool faraway = d >= m_control.wanted_range * BS; if(mapBlockMesh->isAnimationForced() || !faraway || mesh_animate_count_far < (m_control.range_all ? 200 : 50)) { bool animated = mapBlockMesh->animate( faraway, animation_time, crack, daynight_ratio); if(animated) mesh_animate_count++; if(animated && faraway) mesh_animate_count_far++; } else { mapBlockMesh->decreaseAnimationForceTimer(); } } /* Get the meshbuffers of the block */ { //JMutexAutoLock lock(block->mesh_mutex); auto *mesh = mapBlockMesh->getMesh(); if (!mesh) continue; u32 c = mesh->getMeshBufferCount(); for(u32 i=0; i<c; i++) { scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, m_cache_trilinear_filter); buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, m_cache_bilinear_filter); buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, m_cache_anistropic_filter); const video::SMaterial& material = buf->getMaterial(); video::IMaterialRenderer* rnd = driver->getMaterialRenderer(material.MaterialType); bool transparent = (rnd && rnd->isTransparent()); if(transparent == is_transparent_pass) { if(buf->getVertexCount() == 0) errorstream<<"Block ["<<analyze_block(block) <<"] contains an empty meshbuf"<<std::endl; drawbufs.add(buf); } } } } std::vector<MeshBufList> &lists = drawbufs.lists; //int timecheck_counter = 0; for(std::vector<MeshBufList>::iterator i = lists.begin(); i != lists.end(); ++i) { #if 0 timecheck_counter++; if(timecheck_counter > 50) { timecheck_counter = 0; int time2 = time(0); if(time2 > time1 + 4) { infostream << "ClientMap::renderMap(): " "Rendering takes ages, returning." << std::endl; return; } } #endif MeshBufList &list = *i; driver->setMaterial(list.m); for(std::vector<scene::IMeshBuffer*>::iterator j = list.bufs.begin(); j != list.bufs.end(); ++j) { scene::IMeshBuffer *buf = *j; driver->drawMeshBuffer(buf); vertex_count += buf->getVertexCount(); meshbuffer_count++; } } } // ScopeProfiler // Log only on solid pass because values are the same if(pass == scene::ESNRP_SOLID) { g_profiler->avg("CM: animated meshes", mesh_animate_count); g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far); } g_profiler->avg(prefix+"vertices drawn", vertex_count); if(blocks_had_pass_meshbuf != 0) g_profiler->avg(prefix+"meshbuffers per block", (float)meshbuffer_count / (float)blocks_had_pass_meshbuf); if(blocks_drawn != 0) g_profiler->avg(prefix+"empty blocks (frac)", (float)blocks_without_stuff / blocks_drawn); g_profiler->avg("CM: PrimitiveDrawn", driver->getPrimitiveCountDrawn()); /*infostream<<"renderMap(): is_transparent_pass="******", rendered "<<vertex_count<<" vertices."<<std::endl;*/ }
std::string PlayerSAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); if (!m_player) return ""; if(protocol_version >= 15) { writeU8(os, 1); // version os<<serializeString(m_player->getName()); // name writeU8(os, 1); // is_player writeS16(os, getId()); //id writeV3F1000(os, m_base_position + v3f(0,BS*1,0)); writeF1000(os, m_yaw); writeS16(os, getHP()); auto lock = lock_shared_rec(); std::ostringstream msg_os(std::ios::binary); msg_os << serializeLongString(getPropertyPacket()); // message 1 msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 msg_os << serializeLongString(gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3 for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4 msg_os << serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak, m_physics_override_sneak_glitch)); // 5 // (GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) : Deprecated, for backwards compatibility only. msg_os << serializeLongString(gob_cmd_update_nametag_attributes(m_prop.nametag_color)); // 6 int message_count = 6 + m_bone_position.size(); for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin(); ii != m_attachment_child_ids.end(); ++ii) { if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { message_count++; msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), obj->getClientInitializationData(protocol_version))); } } writeU8(os, message_count); os.write(msg_os.str().c_str(), msg_os.str().size()); } else { writeU8(os, 0); // version os<<serializeString(m_player->getName()); // name writeU8(os, 1); // is_player writeV3F1000(os, m_base_position + v3f(0,BS*1,0)); writeF1000(os, m_yaw); writeS16(os, getHP()); writeU8(os, 2); // number of messages stuffed in here os<<serializeLongString(getPropertyPacket()); // message 1 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 } // return result return os.str(); }
std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); auto lock = lock_shared_rec(); try { if(protocol_version >= 14) { writeU8(os, 1); // version os<<serializeString(""); // name writeU8(os, 0); // is_player writeS16(os, getId()); //id writeV3F1000(os, getBasePosition()); writeF1000(os, m_yaw); writeS16(os, m_hp); std::ostringstream msg_os(std::ios::binary); msg_os << serializeLongString(getPropertyPacket()); // message 1 msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 msg_os << serializeLongString(gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3 for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4 int message_count = 4 + m_bone_position.size(); for (UNORDERED_SET<int>::const_iterator ii = m_attachment_child_ids.begin(); (ii != m_attachment_child_ids.end()); ++ii) { if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { message_count++; msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), obj->getClientInitializationData(protocol_version))); } } writeU8(os, message_count); os.write(msg_os.str().c_str(), msg_os.str().size()); } else { writeU8(os, 0); // version os<<serializeString(""); // name writeU8(os, 0); // is_player writeV3F1000(os, getBasePosition()); writeF1000(os, m_yaw); writeS16(os, m_hp); writeU8(os, 2); // number of messages stuffed in here os<<serializeLongString(getPropertyPacket()); // message 1 os<<serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 } } catch (std::exception &e){ errorstream << "Catn serialize object id="<<getId()<< " pos="<< getBasePosition() << std::endl; return ""; } // return result return os.str(); }