void Client::handleCommand_InitLegacy(NetworkPacket* pkt) { if (pkt->getSize() < 1) return; u8 server_ser_ver; *pkt >> server_ser_ver; infostream << "Client: TOCLIENT_INIT_LEGACY received with " "server_ser_ver=" << ((int)server_ser_ver & 0xff) << std::endl; if (!ser_ver_supported(server_ser_ver)) { infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent " << "unsupported ser_fmt_ver"<< std::endl; return; } m_server_ser_ver = server_ser_ver; // We can be totally wrong with this guess // but we only need some value < 25. m_proto_ver = 24; // Get player position v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0); if (pkt->getSize() >= 1 + 6) { *pkt >> playerpos_s16; }
ServerMapSector* ServerMapSector::deSerialize( std::istream &is, Map *parent, v2s16 p2d, std::map<v2s16, MapSector*> & sectors, IGameDef *gamedef ) { /* [0] u8 serialization version + heightmap data */ /* Read stuff */ // Read version u8 version = SER_FMT_VER_INVALID; is.read((char*)&version, 1); if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapSector format not supported"); /* Add necessary reading stuff here */ /* Get or create sector */ ServerMapSector *sector = NULL; std::map<v2s16, MapSector*>::iterator n = sectors.find(p2d); if(n != sectors.end()) { dstream<<"WARNING: deSerializing existent sectors not supported " "at the moment, because code hasn't been tested." <<std::endl; MapSector *sector = n->second; assert(sector->getId() == MAPSECTOR_SERVER); return (ServerMapSector*)sector; } else { sector = new ServerMapSector(parent, p2d, gamedef); sectors[p2d] = sector; } /* Set stuff in sector */ // Nothing here return sector; }
void MapNode::serialize(u8 *dest, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); u8 actual_d = d; // Convert from new version to old if(version <= 18) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 if(d == CONTENT_IGNORE) d = 255; else if(d == CONTENT_AIR) d = 254; } if(version == 0) { dest[0] = actual_d; } else if(version <= 9) { dest[0] = actual_d; dest[1] = param; } else { dest[0] = actual_d; dest[1] = param; dest[2] = param2; } }
void Client::handleCommand_Hello(NetworkPacket* pkt) { if (pkt->getSize() < 1) return; u8 serialization_ver; u16 proto_ver; u16 compression_mode; u32 auth_mechs; std::string username_legacy; // for case insensitivity *pkt >> serialization_ver >> compression_mode >> proto_ver >> auth_mechs >> username_legacy; // Chose an auth method we support AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs); infostream << "Client: TOCLIENT_HELLO received with " << "serialization_ver=" << (u32)serialization_ver << ", auth_mechs=" << auth_mechs << ", proto_ver=" << proto_ver << ", compression_mode=" << compression_mode << ". Doing auth with mech " << chosen_auth_mechanism << std::endl; if (!ser_ver_supported(serialization_ver)) { infostream << "Client: TOCLIENT_HELLO: Server sent " << "unsupported ser_fmt_ver"<< std::endl; return; } m_server_ser_ver = serialization_ver; m_proto_ver = proto_ver; //TODO verify that username_legacy matches sent username, only // differs in casing (make both uppercase and compare) // This is only neccessary though when we actually want to add casing support if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) { // we recieved a TOCLIENT_HELLO while auth was already going on errorstream << "Client: TOCLIENT_HELLO while auth was already going on" << "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl; if ((m_chosen_auth_mech == AUTH_MECHANISM_SRP) || (m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD)) { srp_user_delete((SRPUser *) m_auth_data); m_auth_data = 0; } } // Authenticate using that method, or abort if there wasn't any method found if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) { startAuth(chosen_auth_mechanism); } else { m_chosen_auth_mech = AUTH_MECHANISM_NONE; m_access_denied = true; m_access_denied_reason = "Unknown"; m_con.Disconnect(); } }
u32 MapNode::serializedLength(u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); if(version == 0) return 1; else if(version <= 9) return 2; else return 3; }
void MapNode::deSerialize(u8 *source, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); if(version == 0) { param0 = source[0]; } else if(version == 1) { param0 = source[0]; // This version doesn't support saved lighting if(light_propagates() || light_source() > 0) param1 = 0; else param1 = source[1]; } else if(version <= 9) { param0 = source[0]; param1 = source[1]; } else { param0 = source[0]; param1 = source[1]; param2 = source[2]; } // Convert special values from old version to new if(version <= 18) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 if(param0 == 255) param0 = CONTENT_IGNORE; else if(param0 == 254) param0 = CONTENT_AIR; } // version 19 is f****d up with sometimes the old values and sometimes not if(version == 19) { if(param0 == 255) param0 = CONTENT_IGNORE; else if(param0 == 254) param0 = CONTENT_AIR; } // Translate to our known version *this = mapnode_translate_to_internal(*this, version); }
void MapNode::deSerialize(u8 *source, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); if(version == 0) { d = source[0]; } else if(version == 1) { d = source[0]; // This version doesn't support saved lighting if(light_propagates() || light_source() > 0) param = 0; else param = source[1]; } else if(version <= 9) { d = source[0]; param = source[1]; } else { d = source[0]; param = source[1]; param2 = source[2]; // Convert from old version to new if(version <= 18) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 if(d == 255) d = CONTENT_IGNORE; else if(d == 254) d = CONTENT_AIR; } } }
void Client::handleCommand_Hello(NetworkPacket* pkt) { if (pkt->getSize() < 1) return; u8 deployed; *pkt >> deployed; infostream << "Client: TOCLIENT_HELLO received with " "deployed=" << ((int)deployed & 0xff) << std::endl; if (!ser_ver_supported(deployed)) { infostream << "Client: TOCLIENT_HELLO: Server sent " << "unsupported ser_fmt_ver"<< std::endl; return; } m_server_ser_ver = deployed; // @ TODO auth to server }
void MapSector::serialize(std::ostream &os, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapSector format not supported"); /* [0] u8 serialization version + heightmap data */ // Server has both of these, no need to support not having them. //assert(m_objects != NULL); // Write version os.write((char*)&version, 1); /* Add stuff here, if needed */ }
void MapSector::deSerialize(std::istream &is) { /* [0] u8 serialization version + heightmap data */ /* Read stuff */ // Read version u8 version = SER_FMT_VER_INVALID; is.read((char*)&version, 1); if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapSector format not supported"); /* Add necessary reading stuff here */ }
void MapNode::serialize(u8 *dest, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); // Translate to wanted version MapNode n_foreign = mapnode_translate_from_internal(*this, version); u8 actual_param0 = n_foreign.param0; // Convert special values from new version to old if(version <= 18) { // In these versions, CONTENT_IGNORE and CONTENT_AIR // are 255 and 254 if(actual_param0 == CONTENT_IGNORE) actual_param0 = 255; else if(actual_param0 == CONTENT_AIR) actual_param0 = 254; } if(version == 0) { dest[0] = actual_param0; } else if(version <= 9) { dest[0] = actual_param0; dest[1] = n_foreign.param1; } else { dest[0] = actual_param0; dest[1] = n_foreign.param1; dest[2] = n_foreign.param2; } }
void Client::handleCommand_InitLegacy(NetworkPacket* pkt) { if (pkt->getSize() < 1) return; u8 deployed; *pkt >> deployed; infostream << "Client: TOCLIENT_INIT_LEGACY received with " "deployed=" << ((int)deployed & 0xff) << std::endl; if (!ser_ver_supported(deployed)) { infostream << "Client: TOCLIENT_INIT_LEGACY: Server sent " << "unsupported ser_fmt_ver"<< std::endl; return; } m_server_ser_ver = deployed; // Get player position v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0); if (pkt->getSize() >= 1 + 6) { *pkt >> playerpos_s16; }
void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())<<std::endl); m_day_night_differs_expired = false; if(version <= 21) { deSerialize_pre22(is, version, disk); return; } u8 flags = readU8(is); is_underground = (flags & 0x01) ? true : false; m_day_night_differs = (flags & 0x02) ? true : false; m_lighting_expired = (flags & 0x04) ? true : false; m_generated = (flags & 0x08) ? false : true; /* Bulk node data */ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Bulk node data"<<std::endl); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u8 content_width = readU8(is); u8 params_width = readU8(is); if(content_width != 1 && content_width != 2) throw SerializationError("MapBlock::deSerialize(): invalid content_width"); if(params_width != 2) throw SerializationError("MapBlock::deSerialize(): invalid params_width"); MapNode::deSerializeBulk(is, version, data, nodecount, content_width, params_width, true); /* NodeMetadata */ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Node metadata"<<std::endl); // Ignore errors try{ std::ostringstream oss(std::ios_base::binary); decompressZlib(is, oss); std::istringstream iss(oss.str(), std::ios_base::binary); if(version >= 23) m_node_metadata.deSerialize(iss, m_gamedef); else content_nodemeta_deserialize_legacy(iss, &m_node_metadata, &m_node_timers, m_gamedef); } catch(SerializationError &e) { errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" <<" while deserializing node metadata at (" <<PP(getPos())<<": "<<e.what()<<std::endl; } /* Data that is only on disk */ if(disk) { // Node timers if(version == 23){ // Read unused zero readU8(is); } else if(version >= 24){ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Node timers"<<std::endl); m_node_timers.deSerialize(is); } // Static objects TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Static objects"<<std::endl); m_static_objects.deSerialize(is); // Timestamp TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Timestamp"<<std::endl); setTimestamp(readU32(is)); m_disk_timestamp = m_timestamp; // Dynamically re-set ids based on node names TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": NameIdMapping"<<std::endl); NameIdMapping nimap; nimap.deSerialize(is); correctBlockNodeIds(&nimap, data, m_gamedef); }
void MapBlock::serialize(std::ostream &os, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); if(data == NULL) { throw SerializationError("ERROR: Not writing dummy block."); } // Can't do this anymore; we have 16-bit dynamically allocated node IDs // in memory; conversion just won't work in this direction. if(version < 24) throw SerializationError("MapBlock::serialize: serialization to " "version < 24 not possible"); // 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; 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) { // Node timers m_node_timers.serialize(os); // Static objects m_static_objects.serialize(os); // Timestamp writeU32(os, getTimestamp()); // Write block-specific node definition id mapping nimap.serialize(os); } }
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 MapBlock::serialize(std::ostream &os, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); if(data == NULL) { throw SerializationError("ERROR: Not writing dummy block."); } if(version <= 21) { serialize_pre22(os, version, disk); return; } // First byte u8 flags = 0; if(is_underground) flags |= 0x01; if(m_day_night_differs) flags |= 0x02; if(m_lighting_expired) flags |= 0x04; if(m_generated == false) flags |= 0x08; 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 = 1; /*u8 content_width = (nimap.size() <= 255) ? 1 : 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 = 1; /*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) { // Static objects m_static_objects.serialize(os); // Timestamp writeU32(os, getTimestamp()); // Write block-specific node definition id mapping nimap.serialize(os); } }
void MapBlock::deSerialize(std::istream &is, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); // These have no lighting info if(version <= 1) { setLightingExpired(true); } // These have no "generated" field if(version < 18) { m_generated = true; } // These have no compression if(version <= 3 || version == 5 || version == 6) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; char tmp; is.read(&tmp, 1); if(is.gcount() != 1) throw SerializationError ("MapBlock::deSerialize: no enough input data"); is_underground = tmp; for(u32 i=0; i<nodecount; i++) { s32 len = MapNode::serializedLength(version); SharedBuffer<u8> d(len); is.read((char*)*d, len); if(is.gcount() != len) throw SerializationError ("MapBlock::deSerialize: no enough input data"); data[i].deSerialize(*d, version); } } else if(version <= 10) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; 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++) { data[i].param0 = 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++) { data[i].param1 = 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++) { data[i].param2 = s[i]; } } } // All other versions (newest) else { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; 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++) { u8 buf[3]; buf[0] = s[i]; buf[1] = s[i+nodecount]; buf[2] = s[i+nodecount*2]; data[i].deSerialize(buf, version); } /* 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; } } } }
void MapBlock::serialize(std::ostream &os, u8 version) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); if(data == NULL) { throw SerializationError("ERROR: Not writing dummy block."); } // These have no compression if(version <= 3 || version == 5 || version == 6) { u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; u32 buflen = 1 + nodecount * MapNode::serializedLength(version); SharedBuffer<u8> dest(buflen); dest[0] = is_underground; for(u32 i=0; i<nodecount; i++) { u32 s = 1 + i * MapNode::serializedLength(version); data[i].serialize(&dest[s], version); } os.write((char*)*dest, dest.getSize()); } else if(version <= 10) { /* With compression. Compress the materials and the params separately. */ // First byte os.write((char*)&is_underground, 1); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; // Get and compress materials SharedBuffer<u8> materialdata(nodecount); for(u32 i=0; i<nodecount; i++) { materialdata[i] = data[i].param0; } compress(materialdata, os, version); // Get and compress lights SharedBuffer<u8> lightdata(nodecount); for(u32 i=0; i<nodecount; i++) { lightdata[i] = data[i].param1; } compress(lightdata, os, version); if(version >= 10) { // Get and compress param2 SharedBuffer<u8> param2data(nodecount); for(u32 i=0; i<nodecount; i++) { param2data[i] = data[i].param2; } compress(param2data, os, version); } } // All other versions (newest) else { // First byte u8 flags = 0; if(is_underground) flags |= 0x01; if(m_day_night_differs) flags |= 0x02; if(m_lighting_expired) flags |= 0x04; if(version >= 18) { if(m_generated == false) flags |= 0x08; } os.write((char*)&flags, 1); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; /* Get data */ // Serialize nodes SharedBuffer<u8> databuf_nodelist(nodecount*3); for(u32 i=0; i<nodecount; i++) { data[i].serialize(&databuf_nodelist[i*3], version); } // Create buffer with different parameters sorted SharedBuffer<u8> databuf(nodecount*3); for(u32 i=0; i<nodecount; i++) { databuf[i] = databuf_nodelist[i*3]; databuf[i+nodecount] = databuf_nodelist[i*3+1]; databuf[i+nodecount*2] = databuf_nodelist[i*3+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()); } } } }
/* sender_peer_id given to this shall be quaranteed to be a valid peer */ void Client::ProcessData(NetworkPacket *pkt) { DSTACK(__FUNCTION_NAME); ScopeProfiler sp(g_profiler, "Client::ProcessData"); auto datasize = pkt->getSize(); auto sender_peer_id = pkt->getPeerId(); int command; MsgpackPacket packet; msgpack::unpacked msg; if (!con::parse_msgpack_packet(pkt->getString(0), datasize, &packet, &command, &msg)) { // invalid packet return; } //infostream<<"Client: received command="<<command<<std::endl; m_packetcounter.add((u16)command); /* If this check is removed, be sure to change the queue system to know the ids */ if(sender_peer_id != PEER_ID_SERVER) { infostream<<"Client::ProcessData(): Discarding data not " "coming from server: peer_id="<<sender_peer_id <<std::endl; return; } u8 ser_version = m_server_ser_ver; //infostream<<"Client received command="<<(int)command<<std::endl; if(command == TOCLIENT_INIT) { u8 deployed; packet[TOCLIENT_INIT_DEPLOYED].convert(&deployed); infostream<<"Client: TOCLIENT_INIT received with " "deployed="<<((int)deployed&0xff)<<std::endl; if(!ser_ver_supported(deployed)) { infostream<<"Client: TOCLIENT_INIT: Server sent " <<"unsupported ser_fmt_ver"<<std::endl; return; } m_server_ser_ver = deployed; // Set player position Player *player = m_env.getLocalPlayer(); if(!player) return; packet[TOCLIENT_INIT_SEED].convert(&m_map_seed); infostream<<"Client: received map seed: "<<m_map_seed<<std::endl; packet[TOCLIENT_INIT_STEP].convert(&m_recommended_send_interval); infostream<<"Client: received recommended send interval " <<m_recommended_send_interval<<std::endl; // TOCLIENT_INIT_POS if (m_localserver) { Settings settings; packet[TOCLIENT_INIT_MAP_PARAMS].convert(&settings); m_localserver->getEmergeManager()->params.load(settings); } // Reply to server MSGPACK_PACKET_INIT(TOSERVER_INIT2, 0); m_con.Send(PEER_ID_SERVER, 1, buffer, true); m_state = LC_Init; return; } if(command == TOCLIENT_ACCESS_DENIED_LEGACY) { // The server didn't like our password. Note, this needs // to be processed even if the serialisation format has // not been agreed yet, the same as TOCLIENT_INIT. m_access_denied = true; packet[TOCLIENT_ACCESS_DENIED_CUSTOM_STRING].convert(&m_access_denied_reason); return; } if(ser_version == SER_FMT_VER_INVALID) { infostream<<"Client: Server serialization" " format invalid or not initialized." " Skipping incoming command="<<command<<std::endl; return; } /* Handle runtime commands */ // there's no sane reason why we shouldn't have a player and // almost everyone needs a player reference Player *player = m_env.getLocalPlayer(); if(!player) return; if(command == TOCLIENT_REMOVENODE) { v3s16 p = packet[TOCLIENT_REMOVENODE_POS].as<v3s16>(); removeNode(p, 2); //use light from top node } else if(command == TOCLIENT_ADDNODE) { v3s16 p = packet[TOCLIENT_ADDNODE_POS].as<v3s16>(); MapNode n = packet[TOCLIENT_ADDNODE_NODE].as<MapNode>(); bool remove_metadata = packet[TOCLIENT_ADDNODE_REMOVE_METADATA].as<bool>(); addNode(p, n, remove_metadata, 2); //fast add } else if(command == TOCLIENT_BLOCKDATA) { v3s16 p = packet[TOCLIENT_BLOCKDATA_POS].as<v3s16>(); s8 step = 1; packet[TOCLIENT_BLOCKDATA_STEP].convert(&step); if (step == 1) { std::istringstream istr(packet[TOCLIENT_BLOCKDATA_DATA].as<std::string>(), std::ios_base::binary); MapBlock *block; block = m_env.getMap().getBlockNoCreateNoEx(p); bool new_block = !block; if (new_block) block = new MapBlock(&m_env.getMap(), p, this); block->deSerialize(istr, ser_version, false); s32 h; // for convert to atomic packet[TOCLIENT_BLOCKDATA_HEAT].convert(&h); block->heat = h; packet[TOCLIENT_BLOCKDATA_HUMIDITY].convert(&h); block->humidity = h; if (packet.count(TOCLIENT_BLOCKDATA_CONTENT_ONLY)) block->content_only = packet[TOCLIENT_BLOCKDATA_CONTENT_ONLY].as<content_t>(); if (m_localserver != NULL) { m_localserver->getMap().saveBlock(block); } if (new_block) if (!m_env.getMap().insertBlock(block)) delete block; /* //Add it to mesh update queue and set it to be acknowledged after update. */ //infostream<<"Adding mesh update task for received block "<<p<<std::endl; updateMeshTimestampWithEdge(p); if (block->content_only != CONTENT_IGNORE && block->content_only != CONTENT_AIR) { if (getNodeBlockPos(floatToInt(m_env.getLocalPlayer()->getPosition(), BS)).getDistanceFrom(p) <= 1) addUpdateMeshTaskWithEdge(p); } /* #if !defined(NDEBUG) if (m_env.getClientMap().m_block_boundary.size() > 150) m_env.getClientMap().m_block_boundary.clear(); m_env.getClientMap().m_block_boundary[p] = block; #endif */ }//step } else if(command == TOCLIENT_INVENTORY) { std::string datastring = packet[TOCLIENT_INVENTORY_DATA].as<std::string>(); std::istringstream is(datastring, std::ios_base::binary); Player *player = m_env.getLocalPlayer(); if(!player) return; player->inventory.deSerialize(is); m_inventory_updated = true; delete m_inventory_from_server; m_inventory_from_server = new Inventory(player->inventory); m_inventory_from_server_age = 0.0; } else if(command == TOCLIENT_TIME_OF_DAY) { u16 time_of_day = packet[TOCLIENT_TIME_OF_DAY_TIME].as<u16>(); time_of_day = time_of_day % 24000; f32 time_speed = packet[TOCLIENT_TIME_OF_DAY_TIME_SPEED].as<f32>(); // Update environment m_env.setTimeOfDay(time_of_day); m_env.setTimeOfDaySpeed(time_speed); m_time_of_day_set = true; u32 dr = m_env.getDayNightRatio(); verbosestream<<"Client: time_of_day="<<time_of_day <<" time_speed="<<time_speed <<" dr="<<dr<<std::endl; } else if(command == TOCLIENT_CHAT_MESSAGE) { std::string message = packet[TOCLIENT_CHAT_MESSAGE_DATA].as<std::string>(); m_chat_queue.push(message); } else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD) { std::vector<u16> removed_objects; packet[TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_REMOVE].convert(&removed_objects); for (size_t i = 0; i < removed_objects.size(); ++i) m_env.removeActiveObject(removed_objects[i]); std::vector<ActiveObjectAddData> added_objects; packet[TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD_ADD].convert(&added_objects); for (size_t i = 0; i < added_objects.size(); ++i) m_env.addActiveObject(added_objects[i].id, added_objects[i].type, added_objects[i].data); } else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES) { ActiveObjectMessages messages; packet[TOCLIENT_ACTIVE_OBJECT_MESSAGES_MESSAGES].convert(&messages); for (size_t i = 0; i < messages.size(); ++i) m_env.processActiveObjectMessage(messages[i].first, messages[i].second); } else if(command == TOCLIENT_MOVEMENT) { Player *player = m_env.getLocalPlayer(); packet[TOCLIENT_MOVEMENT_ACCELERATION_DEFAULT].convert(&player->movement_acceleration_default); packet[TOCLIENT_MOVEMENT_ACCELERATION_AIR].convert(&player->movement_acceleration_air); packet[TOCLIENT_MOVEMENT_ACCELERATION_FAST].convert(&player->movement_acceleration_fast); packet[TOCLIENT_MOVEMENT_SPEED_WALK].convert(&player->movement_speed_walk); packet[TOCLIENT_MOVEMENT_SPEED_CROUCH].convert(&player->movement_speed_crouch); packet[TOCLIENT_MOVEMENT_SPEED_FAST].convert(&player->movement_speed_fast); packet[TOCLIENT_MOVEMENT_SPEED_CLIMB].convert(&player->movement_speed_climb); packet[TOCLIENT_MOVEMENT_SPEED_JUMP].convert(&player->movement_speed_jump); packet[TOCLIENT_MOVEMENT_LIQUID_FLUIDITY].convert(&player->movement_liquid_fluidity); packet[TOCLIENT_MOVEMENT_LIQUID_FLUIDITY_SMOOTH].convert(&player->movement_liquid_fluidity_smooth); packet[TOCLIENT_MOVEMENT_LIQUID_SINK].convert(&player->movement_liquid_sink); packet[TOCLIENT_MOVEMENT_GRAVITY].convert(&player->movement_gravity); } else if(command == TOCLIENT_HP) { Player *player = m_env.getLocalPlayer(); if(!player) return; u8 oldhp = player->hp; u8 hp = packet[TOCLIENT_HP_HP].as<u8>(); player->hp = hp; if(hp < oldhp) { // Add to ClientEvent queue ClientEvent event; event.type = CE_PLAYER_DAMAGE; event.player_damage.amount = oldhp - hp; m_client_event_queue.push(event); } } else if(command == TOCLIENT_BREATH) { Player *player = m_env.getLocalPlayer(); player->setBreath(packet[TOCLIENT_BREATH_BREATH].as<u16>()) ; } else if(command == TOCLIENT_MOVE_PLAYER) { Player *player = m_env.getLocalPlayer(); if(!player) return; v3f pos = packet[TOCLIENT_MOVE_PLAYER_POS].as<v3f>(); f32 pitch = packet[TOCLIENT_MOVE_PLAYER_PITCH].as<f32>(); f32 yaw = packet[TOCLIENT_MOVE_PLAYER_YAW].as<f32>(); player->setPosition(pos); infostream<<"Client got TOCLIENT_MOVE_PLAYER" <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")" <<" pitch="<<pitch <<" yaw="<<yaw <<std::endl; /* Add to ClientEvent queue. This has to be sent to the main program because otherwise it would just force the pitch and yaw values to whatever the camera points to. */ ClientEvent event; event.type = CE_PLAYER_FORCE_MOVE; event.player_force_move.pitch = pitch; event.player_force_move.yaw = yaw; m_client_event_queue.push(event); // Ignore damage for a few seconds, so that the player doesn't // get damage from falling on ground m_ignore_damage_timer = 3.0; } else if(command == TOCLIENT_DEATHSCREEN) { bool set_camera_point_target = packet[TOCLIENT_DEATHSCREEN_SET_CAMERA].as<bool>(); v3f camera_point_target = packet[TOCLIENT_DEATHSCREEN_CAMERA_POINT].as<v3f>(); ClientEvent event; event.type = CE_DEATHSCREEN; event.deathscreen.set_camera_point_target = set_camera_point_target; event.deathscreen.camera_point_target_x = camera_point_target.X; event.deathscreen.camera_point_target_y = camera_point_target.Y; event.deathscreen.camera_point_target_z = camera_point_target.Z; m_client_event_queue.push(event); } else if(command == TOCLIENT_ANNOUNCE_MEDIA) { if (m_media_downloader == NULL || m_media_downloader->isStarted()) { const char *problem = m_media_downloader ? "we already saw another announcement" : "all media has been received already"; errorstream<<"Client: Received media announcement but " <<problem<<"!" <<std::endl; return; } // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); MediaAnnounceList announce_list; packet[TOCLIENT_ANNOUNCE_MEDIA_LIST].convert(&announce_list); for (size_t i = 0; i < announce_list.size(); ++i) m_media_downloader->addFile(announce_list[i].first, base64_decode(announce_list[i].second)); std::vector<std::string> remote_media; std::string remote_media_string = packet[TOCLIENT_ANNOUNCE_MEDIA_REMOTE_SERVER].as<std::string>(); Strfnd sf(remote_media_string); while(!sf.atend()) { std::string baseurl = trim(sf.next(",")); if(baseurl != "") m_media_downloader->addRemoteServer(baseurl); } m_media_downloader->step(this); } else if(command == TOCLIENT_MEDIA) { MediaData media_data; packet[TOCLIENT_MEDIA_MEDIA].convert(&media_data); // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); for(size_t i = 0; i < media_data.size(); ++i) m_media_downloader->conventionalTransferDone( media_data[i].first, media_data[i].second, this); } else if(command == TOCLIENT_NODEDEF) { infostream<<"Client: Received node definitions: packet size: " <<datasize<<std::endl; // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); packet[TOCLIENT_NODEDEF_DEFINITIONS].convert(m_nodedef); m_nodedef_received = true; } else if(command == TOCLIENT_ITEMDEF) { infostream<<"Client: Received item definitions: packet size: " <<datasize<<std::endl; // Mesh update thread must be stopped while // updating content definitions //assert(!m_mesh_update_thread.IsRunning()); packet[TOCLIENT_ITEMDEF_DEFINITIONS].convert(m_itemdef); m_itemdef_received = true; } else if(command == TOCLIENT_PLAY_SOUND) { s32 server_id = packet[TOCLIENT_PLAY_SOUND_ID].as<s32>(); std::string name = packet[TOCLIENT_PLAY_SOUND_NAME].as<std::string>(); float gain = packet[TOCLIENT_PLAY_SOUND_GAIN].as<f32>(); int type = packet[TOCLIENT_PLAY_SOUND_TYPE].as<u8>(); // 0=local, 1=positional, 2=object v3f pos = packet[TOCLIENT_PLAY_SOUND_POS].as<v3f>(); u16 object_id = packet[TOCLIENT_PLAY_SOUND_OBJECT_ID].as<u16>(); bool loop = packet[TOCLIENT_PLAY_SOUND_LOOP].as<bool>(); // Start playing int client_id = -1; switch(type){ case 0: // local client_id = m_sound->playSound(name, loop, gain); break; case 1: // positional client_id = m_sound->playSoundAt(name, loop, gain, pos); break; case 2: { // object ClientActiveObject *cao = m_env.getActiveObject(object_id); if(cao) pos = cao->getPosition(); client_id = m_sound->playSoundAt(name, loop, gain, pos); // TODO: Set up sound to move with object break; } default: break; } if(client_id != -1){ m_sounds_server_to_client[server_id] = client_id; m_sounds_client_to_server[client_id] = server_id; if(object_id != 0) m_sounds_to_objects[client_id] = object_id; } } else if(command == TOCLIENT_STOP_SOUND) { s32 server_id = packet[TOCLIENT_STOP_SOUND_ID].as<s32>(); std::map<s32, int>::iterator i = m_sounds_server_to_client.find(server_id); if(i != m_sounds_server_to_client.end()){ int client_id = i->second; m_sound->stopSound(client_id); } } else if(command == TOCLIENT_PRIVILEGES) { packet[TOCLIENT_PRIVILEGES_PRIVILEGES].convert(&m_privileges); } else if(command == TOCLIENT_INVENTORY_FORMSPEC) { // Store formspec in LocalPlayer player->inventory_formspec = packet[TOCLIENT_INVENTORY_FORMSPEC_DATA].as<std::string>(); } else if(command == TOCLIENT_DETACHED_INVENTORY) { std::string name = packet[TOCLIENT_DETACHED_INVENTORY_NAME].as<std::string>(); std::string datastring = packet[TOCLIENT_DETACHED_INVENTORY_DATA].as<std::string>(); std::istringstream is(datastring, std::ios_base::binary); infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl; Inventory *inv = NULL; if(m_detached_inventories.count(name) > 0) inv = m_detached_inventories[name]; else{ inv = new Inventory(m_itemdef); m_detached_inventories[name] = inv; } inv->deSerialize(is); } else if(command == TOCLIENT_SHOW_FORMSPEC) { std::string formspec = packet[TOCLIENT_SHOW_FORMSPEC_DATA].as<std::string>(); std::string formname = packet[TOCLIENT_SHOW_FORMSPEC_NAME].as<std::string>(); ClientEvent event; event.type = CE_SHOW_FORMSPEC; // pointer is required as event is a struct only! // adding a std:string to a struct isn't possible event.show_formspec.formspec = new std::string(formspec); event.show_formspec.formname = new std::string(formname); m_client_event_queue.push(event); } else if(command == TOCLIENT_SPAWN_PARTICLE) { v3f pos = packet[TOCLIENT_SPAWN_PARTICLE_POS].as<v3f>(); v3f vel = packet[TOCLIENT_SPAWN_PARTICLE_VELOCITY].as<v3f>(); v3f acc = packet[TOCLIENT_SPAWN_PARTICLE_ACCELERATION].as<v3f>(); float expirationtime = packet[TOCLIENT_SPAWN_PARTICLE_EXPIRATIONTIME].as<float>(); float size = packet[TOCLIENT_SPAWN_PARTICLE_SIZE].as<float>(); bool collisiondetection = packet[TOCLIENT_SPAWN_PARTICLE_COLLISIONDETECTION].as<bool>(); std::string texture = packet[TOCLIENT_SPAWN_PARTICLE_TEXTURE].as<std::string>(); bool vertical = packet[TOCLIENT_SPAWN_PARTICLE_VERTICAL].as<bool>(); ClientEvent event; event.type = CE_SPAWN_PARTICLE; event.spawn_particle.pos = new v3f (pos); event.spawn_particle.vel = new v3f (vel); event.spawn_particle.acc = new v3f (acc); event.spawn_particle.expirationtime = expirationtime; event.spawn_particle.size = size; event.spawn_particle.collisiondetection = collisiondetection; event.spawn_particle.vertical = vertical; event.spawn_particle.texture = new std::string(texture); m_client_event_queue.push(event); } else if(command == TOCLIENT_ADD_PARTICLESPAWNER) { u16 amount; float spawntime, minexptime, maxexptime, minsize, maxsize; v3f minpos, maxpos, minvel, maxvel, minacc, maxacc; bool collisiondetection, vertical; u32 id; std::string texture; packet[TOCLIENT_ADD_PARTICLESPAWNER_AMOUNT].convert(&amount); packet[TOCLIENT_ADD_PARTICLESPAWNER_SPAWNTIME].convert(&spawntime); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINPOS].convert(&minpos); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXPOS].convert(&maxpos); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINVEL].convert(&minvel); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXVEL].convert(&maxvel); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINACC].convert(&minacc); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXACC].convert(&maxacc); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINEXPTIME].convert(&minexptime); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXEXPTIME].convert(&maxexptime); packet[TOCLIENT_ADD_PARTICLESPAWNER_MINSIZE].convert(&minsize); packet[TOCLIENT_ADD_PARTICLESPAWNER_MAXSIZE].convert(&maxsize); packet[TOCLIENT_ADD_PARTICLESPAWNER_COLLISIONDETECTION].convert(&collisiondetection); packet[TOCLIENT_ADD_PARTICLESPAWNER_TEXTURE].convert(&texture); packet[TOCLIENT_ADD_PARTICLESPAWNER_VERTICAL].convert(&vertical); packet[TOCLIENT_ADD_PARTICLESPAWNER_ID].convert(&id); ClientEvent event; event.type = CE_ADD_PARTICLESPAWNER; event.add_particlespawner.amount = amount; event.add_particlespawner.spawntime = spawntime; event.add_particlespawner.minpos = new v3f (minpos); event.add_particlespawner.maxpos = new v3f (maxpos); event.add_particlespawner.minvel = new v3f (minvel); event.add_particlespawner.maxvel = new v3f (maxvel); event.add_particlespawner.minacc = new v3f (minacc); event.add_particlespawner.maxacc = new v3f (maxacc); event.add_particlespawner.minexptime = minexptime; event.add_particlespawner.maxexptime = maxexptime; event.add_particlespawner.minsize = minsize; event.add_particlespawner.maxsize = maxsize; event.add_particlespawner.collisiondetection = collisiondetection; event.add_particlespawner.vertical = vertical; event.add_particlespawner.texture = new std::string(texture); event.add_particlespawner.id = id; m_client_event_queue.push(event); } else if(command == TOCLIENT_DELETE_PARTICLESPAWNER) { u32 id = packet[TOCLIENT_DELETE_PARTICLESPAWNER_ID].as<u32>(); ClientEvent event; event.type = CE_DELETE_PARTICLESPAWNER; event.delete_particlespawner.id = id; m_client_event_queue.push(event); } else if(command == TOCLIENT_HUDADD) { //std::string datastring((char *)&data[2], datasize - 2); //std::istringstream is(datastring, std::ios_base::binary); u32 id, number, item, dir; u8 type; v2f pos, scale, align, offset; std::string name, text; v3f world_pos; v2s32 size; packet[TOCLIENT_HUDADD_ID].convert(&id); packet[TOCLIENT_HUDADD_TYPE].convert(&type); packet[TOCLIENT_HUDADD_POS].convert(&pos); packet[TOCLIENT_HUDADD_NAME].convert(&name); packet[TOCLIENT_HUDADD_SCALE].convert(&scale); packet[TOCLIENT_HUDADD_TEXT].convert(&text); packet[TOCLIENT_HUDADD_NUMBER].convert(&number); packet[TOCLIENT_HUDADD_ITEM].convert(&item); packet[TOCLIENT_HUDADD_DIR].convert(&dir); packet[TOCLIENT_HUDADD_ALIGN].convert(&align); packet[TOCLIENT_HUDADD_OFFSET].convert(&offset); packet[TOCLIENT_HUDADD_WORLD_POS].convert(&world_pos); packet[TOCLIENT_HUDADD_SIZE].convert(&size); ClientEvent event; event.type = CE_HUDADD; event.hudadd.id = id; event.hudadd.type = type; event.hudadd.pos = new v2f(pos); event.hudadd.name = new std::string(name); event.hudadd.scale = new v2f(scale); event.hudadd.text = new std::string(text); event.hudadd.number = number; event.hudadd.item = item; event.hudadd.dir = dir; event.hudadd.align = new v2f(align); event.hudadd.offset = new v2f(offset); event.hudadd.world_pos = new v3f(world_pos); event.hudadd.size = new v2s32(size); m_client_event_queue.push(event); } else if(command == TOCLIENT_HUDRM) { u32 id = packet[TOCLIENT_HUDRM_ID].as<u32>(); ClientEvent event; event.type = CE_HUDRM; event.hudrm.id = id; m_client_event_queue.push(event); } else if(command == TOCLIENT_HUDCHANGE) { std::string sdata; v2f v2fdata; v3f v3fdata; v2s32 v2s32data; u32 intdata = 0; u32 id = packet[TOCLIENT_HUDCHANGE_ID].as<u32>(); u8 stat = packet[TOCLIENT_HUDCHANGE_STAT].as<int>(); if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) packet[TOCLIENT_HUDCHANGE_V2F].convert(&v2fdata); else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT) packet[TOCLIENT_HUDCHANGE_STRING].convert(&sdata); else if (stat == HUD_STAT_WORLD_POS) packet[TOCLIENT_HUDCHANGE_V3F].convert(&v3fdata); else if (stat == HUD_STAT_SIZE) packet[TOCLIENT_HUDCHANGE_V2S32].convert(&v2s32data); else packet[TOCLIENT_HUDCHANGE_U32].convert(&intdata); ClientEvent event; event.type = CE_HUDCHANGE; event.hudchange.id = id; event.hudchange.stat = (HudElementStat)stat; event.hudchange.v2fdata = new v2f(v2fdata); event.hudchange.v3fdata = new v3f(v3fdata); event.hudchange.sdata = new std::string(sdata); event.hudchange.data = intdata; event.hudchange.v2s32data = new v2s32(v2s32data); m_client_event_queue.push(event); } else if(command == TOCLIENT_HUD_SET_FLAGS) { Player *player = m_env.getLocalPlayer(); if(!player) return; u32 flags = packet[TOCLIENT_HUD_SET_FLAGS_FLAGS].as<u32>(); u32 mask = packet[TOCLIENT_HUD_SET_FLAGS_MASK].as<u32>(); player->hud_flags &= ~mask; player->hud_flags |= flags; } else if(command == TOCLIENT_HUD_SET_PARAM) { u16 param = packet[TOCLIENT_HUD_SET_PARAM_ID].as<u16>(); std::string value = packet[TOCLIENT_HUD_SET_PARAM_VALUE].as<std::string>(); if(param == HUD_PARAM_HOTBAR_ITEMCOUNT && value.size() == 4){ s32 hotbar_itemcount = readS32((u8*) value.c_str()); if(hotbar_itemcount > 0 && hotbar_itemcount <= HUD_HOTBAR_ITEMCOUNT_MAX) player->hud_hotbar_itemcount = hotbar_itemcount; } else if (param == HUD_PARAM_HOTBAR_IMAGE) { ((LocalPlayer *) player)->hotbar_image = value; } else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) { ((LocalPlayer *) player)->hotbar_selected_image = value; } } /* else if(command == TOCLIENT_ANIMATIONS) { LocalPlayer *player = m_env.getLocalPlayer(); packet[TOCLIENT_ANIMATIONS_DEFAULT_START].convert(&player->animation_default_start); packet[TOCLIENT_ANIMATIONS_DEFAULT_STOP].convert(&player->animation_default_stop); packet[TOCLIENT_ANIMATIONS_WALK_START].convert(&player->animation_walk_start); packet[TOCLIENT_ANIMATIONS_WALK_STOP].convert(&player->animation_walk_stop); packet[TOCLIENT_ANIMATIONS_DIG_START].convert(&player->animation_dig_start); packet[TOCLIENT_ANIMATIONS_DIG_STOP].convert(&player->animation_dig_stop); packet[TOCLIENT_ANIMATIONS_WD_START].convert(&player->animation_wd_start); packet[TOCLIENT_ANIMATIONS_WD_STOP].convert(&player->animation_wd_stop); } */ else if(command == TOCLIENT_SET_SKY) { video::SColor *bgcolor = new video::SColor(packet[TOCLIENT_SET_SKY_COLOR].as<video::SColor>()); std::string *type = new std::string(packet[TOCLIENT_SET_SKY_TYPE].as<std::string>()); std::vector<std::string> *params = new std::vector<std::string>; packet[TOCLIENT_SET_SKY_PARAMS].convert(params); ClientEvent event; event.type = CE_SET_SKY; event.set_sky.bgcolor = bgcolor; event.set_sky.type = type; event.set_sky.params = params; m_client_event_queue.push(event); } else if(command == TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO) { bool do_override; float day_night_ratio_f; packet[TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_DO].convert(&do_override); packet[TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO_VALUE].convert(&day_night_ratio_f); ClientEvent event; event.type = CE_OVERRIDE_DAY_NIGHT_RATIO; event.override_day_night_ratio.do_override = do_override; event.override_day_night_ratio.ratio_f = day_night_ratio_f; m_client_event_queue.push(event); } else if(command == TOCLIENT_LOCAL_PLAYER_ANIMATIONS) { LocalPlayer *player = m_env.getLocalPlayer(); if(!player) return; packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_IDLE].convert(&player->local_animations[0]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_WALK].convert(&player->local_animations[1]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_DIG].convert(&player->local_animations[2]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_WALKDIG].convert(&player->local_animations[3]); packet[TOCLIENT_LOCAL_PLAYER_ANIMATIONS_FRAME_SPEED].convert(&player->local_animation_speed); } else if(command == TOCLIENT_EYE_OFFSET) { LocalPlayer *player = m_env.getLocalPlayer(); if(!player) return; packet[TOCLIENT_EYE_OFFSET_FIRST].convert(&player->eye_offset_first); packet[TOCLIENT_EYE_OFFSET_THIRD].convert(&player->eye_offset_third); } else { infostream<<"Client: Ignoring unknown command " <<command<<std::endl; } }