diff options
author | Loic Blot <loic.blot@unix-experience.fr> | 2015-01-12 17:01:41 +0100 |
---|---|---|
committer | Craig Robbins <kde.psych@gmail.com> | 2015-02-10 20:04:08 +1000 |
commit | a704c04f00bfea4b77550169fa08105c2ee0dfd0 (patch) | |
tree | f0f56c7845a14d0e583628f026e59eb1f4cfc7b5 /src/client.cpp | |
parent | 15c037614f6f7193cef4bfd1da45d83ef2fef393 (diff) | |
download | minetest-a704c04f00bfea4b77550169fa08105c2ee0dfd0.tar.gz minetest-a704c04f00bfea4b77550169fa08105c2ee0dfd0.tar.bz2 minetest-a704c04f00bfea4b77550169fa08105c2ee0dfd0.zip |
Network Layer 7 rework (Packet handling)
* Move networkcode to a dedicated directory
* Rename clientserver.h to network/networkprotocol.h (Better name) and sanitize some includes
* Create object NetworkPacket
* It stores command (opcode) and data separated
* It also stores peer_id
* Data reading can be done by using a streaming interface
* Change packet routing analysis
* Remove old conditional analysis
* Now uses function pointed analysis and add connection state ({Client,Server}::handlers)
* Connection state permit to categorize condition to handle before analyze packets
* Create a handler for depreciated messages, instead of duplicating code
Diffstat (limited to 'src/client.cpp')
-rw-r--r-- | src/client.cpp | 1779 |
1 files changed, 923 insertions, 856 deletions
diff --git a/src/client.cpp b/src/client.cpp index 2f70d624c..b13631f95 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/string.h" #include "strfnd.h" #include "client.h" -#include "clientserver.h" +#include "network/clientopcodes.h" #include "main.h" #include "filesys.h" #include "porting.h" @@ -1013,1008 +1013,1076 @@ void Client::Receive() ProcessData(*data, datasize, sender_peer_id); } -/* - sender_peer_id given to this shall be quaranteed to be a valid peer -*/ -void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) +void Client::handleCommand_Deprecated(ToClientPacket* pkt) { - DSTACK(__FUNCTION_NAME); + infostream << "Got deprecated command " + << toClientCommandTable[pkt->getCommand()].name << " from peer " + << pkt->getPeerId() << "!" << std::endl; +} - // Ignore packets that don't even fit a command - if(datasize < 2) - { - m_packetcounter.add(60000); +void Client::handleCommand_Init(ToClientPacket* pkt) +{ + if(pkt->getSize() < 1) return; - } - ToClientCommand command = (ToClientCommand)readU16(&data[0]); + u8 deployed; + *pkt >> deployed; - //infostream<<"Client: received command="<<command<<std::endl; - m_packetcounter.add((u16)command); + infostream << "Client: TOCLIENT_INIT received with " + "deployed=" << ((int)deployed & 0xff) << std::endl; - /* - 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; + if(!ser_ver_supported(deployed)) { + infostream << "Client: TOCLIENT_INIT: Server sent " + << "unsupported ser_fmt_ver"<< std::endl; return; } - u8 ser_version = m_server_ser_ver; + m_server_ser_ver = deployed; - if(command == TOCLIENT_INIT) - { - if(datasize < 3) - return; + // Get player position + v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0); + if(pkt->getSize() >= 1 + 6) { + *pkt >> playerpos_s16; + } + v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0); - u8 deployed = data[2]; - infostream<<"Client: TOCLIENT_INIT received with " - "deployed="<<((int)deployed&0xff)<<std::endl; + // Set player position + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + player->setPosition(playerpos_f); - if(!ser_ver_supported(deployed)) - { - infostream<<"Client: TOCLIENT_INIT: Server sent " - <<"unsupported ser_fmt_ver"<<std::endl; - return; - } + if(pkt->getSize() >= 1 + 6 + 8) { + // Get map seed + *pkt >> m_map_seed; + infostream << "Client: received map seed: " << m_map_seed << std::endl; + } - m_server_ser_ver = deployed; + if(pkt->getSize() >= 1 + 6 + 8 + 4) { + *pkt >> m_recommended_send_interval; + infostream << "Client: received recommended send interval " + << m_recommended_send_interval<<std::endl; + } - // Get player position - v3s16 playerpos_s16(0, BS*2+BS*20, 0); - if(datasize >= 2+1+6) - playerpos_s16 = readV3S16(&data[2+1]); - v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS/2, 0); + // Reply to server + u32 replysize = 2; + SharedBuffer<u8> reply(replysize); + writeU16(&reply[0], TOSERVER_INIT2); + // Send as reliable + m_con.Send(PEER_ID_SERVER, 1, reply, true); + m_state = LC_Init; +} - // Set player position - Player *player = m_env.getLocalPlayer(); - assert(player != NULL); - player->setPosition(playerpos_f); +void Client::handleCommand_AccessDenied(ToClientPacket* pkt) +{ + // 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; + m_access_denied_reason = L"Unknown"; + if(pkt->getSize() >= 2) { + *pkt >> m_access_denied_reason; + } +} - if(datasize >= 2+1+6+8) - { - // Get map seed - m_map_seed = readU64(&data[2+1+6]); - infostream<<"Client: received map seed: "<<m_map_seed<<std::endl; - } +void Client::handleCommand_RemoveNode(ToClientPacket* pkt) +{ + if(pkt->getSize() < 6) + return; - if(datasize >= 2+1+6+8+4) - { - // Get map seed - m_recommended_send_interval = readF1000(&data[2+1+6+8]); - infostream<<"Client: received recommended send interval " - <<m_recommended_send_interval<<std::endl; - } + v3s16 p; + *pkt >> p.X; + *pkt >> p.Y; + *pkt >> p.Z; + removeNode(p); +} - // Reply to server - u32 replysize = 2; - SharedBuffer<u8> reply(replysize); - writeU16(&reply[0], TOSERVER_INIT2); - // Send as reliable - m_con.Send(PEER_ID_SERVER, 1, reply, true); +void Client::handleCommand_AddNode(ToClientPacket* pkt) +{ + if(pkt->getSize() < 6 + MapNode::serializedLength(m_server_ser_ver)) + return; - m_state = LC_Init; + v3s16 p; + *pkt >> p.X; + *pkt >> p.Y; + *pkt >> p.Z; - return; + MapNode n; + n.deSerialize(pkt->getU8Ptr(6), m_server_ser_ver); + + bool remove_metadata = true; + u32 index = 6 + MapNode::serializedLength(m_server_ser_ver); + if ((pkt->getSize() >= index + 1) && pkt->getU8(index)) { + remove_metadata = false; } - if(command == TOCLIENT_ACCESS_DENIED) - { - // 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; - m_access_denied_reason = L"Unknown"; - if(datasize >= 4) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - m_access_denied_reason = deSerializeWideString(is); - } + addNode(p, n, remove_metadata); +} +void Client::handleCommand_BlockData(ToClientPacket* pkt) +{ + // Ignore too small packet + if(pkt->getSize() < 6) return; + + v3s16 p; + *pkt >> p.X; + *pkt >> p.Y; + *pkt >> p.Z; + + std::string datastring(pkt->getString(6), pkt->getSize() - 6); + std::istringstream istr(datastring, std::ios_base::binary); + + MapSector *sector; + MapBlock *block; + + v2s16 p2d(p.X, p.Z); + sector = m_env.getMap().emergeSector(p2d); + + assert(sector->getPos() == p2d); + + block = sector->getBlockNoCreateNoEx(p.Y); + if(block) { + /* + Update an existing block + */ + block->deSerialize(istr, m_server_ser_ver, false); + block->deSerializeNetworkSpecific(istr); + } + else { + /* + Create a new block + */ + block = new MapBlock(&m_env.getMap(), p, this); + block->deSerialize(istr, m_server_ser_ver, false); + block->deSerializeNetworkSpecific(istr); + sector->insertBlock(block); } - if(ser_version == SER_FMT_VER_INVALID) - { - infostream<<"Client: Server serialization" - " format invalid or not initialized." - " Skipping incoming command="<<command<<std::endl; - return; + if (localdb != NULL) { + ((ServerMap&) localserver->getMap()).saveBlock(block, localdb); } /* - Handle runtime commands + Add it to mesh update queue and set it to be acknowledged after update. */ - // there's no sane reason why we shouldn't have a player and - // almost everyone needs a player reference - Player *player = m_env.getLocalPlayer(); - assert(player != NULL); + addUpdateMeshTaskWithEdge(p, true); +} - if(command == TOCLIENT_REMOVENODE) - { - if(datasize < 8) - return; - v3s16 p; - p.X = readS16(&data[2]); - p.Y = readS16(&data[4]); - p.Z = readS16(&data[6]); - removeNode(p); - } - else if(command == TOCLIENT_ADDNODE) - { - if(datasize < 8 + MapNode::serializedLength(ser_version)) - return; +void Client::handleCommand_Inventory(ToClientPacket* pkt) +{ + if(pkt->getSize() < 1) + return; - v3s16 p; - p.X = readS16(&data[2]); - p.Y = readS16(&data[4]); - p.Z = readS16(&data[6]); + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); - MapNode n; - n.deSerialize(&data[8], ser_version); + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); - bool remove_metadata = true; - u32 index = 8 + MapNode::serializedLength(ser_version); - if ((datasize >= index+1) && data[index]){ - remove_metadata = false; - } + player->inventory.deSerialize(is); - addNode(p, n, remove_metadata); - } - else if(command == TOCLIENT_BLOCKDATA) - { - // Ignore too small packet - if(datasize < 8) - return; + m_inventory_updated = true; - v3s16 p; - p.X = readS16(&data[2]); - p.Y = readS16(&data[4]); - p.Z = readS16(&data[6]); + delete m_inventory_from_server; + m_inventory_from_server = new Inventory(player->inventory); + m_inventory_from_server_age = 0.0; +} + +void Client::handleCommand_TimeOfDay(ToClientPacket* pkt) +{ + if(pkt->getSize() < 2) + return; - std::string datastring((char*)&data[8], datasize-8); - std::istringstream istr(datastring, std::ios_base::binary); + u16 time_of_day; - MapSector *sector; - MapBlock *block; + *pkt >> time_of_day; - v2s16 p2d(p.X, p.Z); - sector = m_env.getMap().emergeSector(p2d); + time_of_day = time_of_day % 24000; + float time_speed = 0; - assert(sector->getPos() == p2d); + if(pkt->getSize() >= 2 + 4) { + *pkt >> time_speed; + } + else { + // Old message; try to approximate speed of time by ourselves + float time_of_day_f = (float)time_of_day / 24000.0; + float tod_diff_f = 0; - block = sector->getBlockNoCreateNoEx(p.Y); - if(block) - { - /* - Update an existing block - */ - block->deSerialize(istr, ser_version, false); - block->deSerializeNetworkSpecific(istr); - } + if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8) + tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0; else - { - /* - Create a new block - */ - block = new MapBlock(&m_env.getMap(), p, this); - block->deSerialize(istr, ser_version, false); - block->deSerializeNetworkSpecific(istr); - sector->insertBlock(block); - } + tod_diff_f = time_of_day_f - m_last_time_of_day_f; - if (localdb != NULL) { - ((ServerMap&) localserver->getMap()).saveBlock(block, localdb); - } + m_last_time_of_day_f = time_of_day_f; + float time_diff = m_time_of_day_update_timer; + m_time_of_day_update_timer = 0; - /* - Add it to mesh update queue and set it to be acknowledged after update. - */ - addUpdateMeshTaskWithEdge(p, true); + if(m_time_of_day_set){ + time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff; + infostream << "Client: Measured time_of_day speed (old format): " + << time_speed << " tod_diff_f=" << tod_diff_f + << " time_diff=" << time_diff << std::endl; + } } - else if(command == TOCLIENT_INVENTORY) - { - if(datasize < 3) - return; - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); + // Update environment + m_env.setTimeOfDay(time_of_day); + m_env.setTimeOfDaySpeed(time_speed); + m_time_of_day_set = true; - player->inventory.deSerialize(is); + u32 dr = m_env.getDayNightRatio(); + infostream << "Client: time_of_day=" << time_of_day + << " time_speed=" << time_speed + << " dr=" << dr << std::endl; +} - m_inventory_updated = true; +void Client::handleCommand_ChatMessage(ToClientPacket* pkt) +{ + /* + u16 command + u16 length + wstring message + */ + u16 len, read_wchar; - delete m_inventory_from_server; - m_inventory_from_server = new Inventory(player->inventory); - m_inventory_from_server_age = 0.0; + *pkt >> len; + std::wstring message; + for(unsigned int i=0; i<len; i++) { + *pkt >> read_wchar; + message += (wchar_t)read_wchar; } - else if(command == TOCLIENT_TIME_OF_DAY) - { - if(datasize < 4) - return; - u16 time_of_day = readU16(&data[2]); - time_of_day = time_of_day % 24000; - float time_speed = 0; + m_chat_queue.push_back(message); +} - if(datasize >= 2 + 2 + 4) - { - time_speed = readF1000(&data[4]); +void Client::handleCommand_ActiveObjectRemoveAdd(ToClientPacket* pkt) +{ + /* + u16 command + u16 count of removed objects + for all removed objects { + u16 id } - else { - // Old message; try to approximate speed of time by ourselves - float time_of_day_f = (float)time_of_day / 24000.0; - float tod_diff_f = 0; - - if(time_of_day_f < 0.2 && m_last_time_of_day_f > 0.8) - tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0; - else - tod_diff_f = time_of_day_f - m_last_time_of_day_f; - - m_last_time_of_day_f = time_of_day_f; - float time_diff = m_time_of_day_update_timer; - m_time_of_day_update_timer = 0; - - if(m_time_of_day_set){ - time_speed = (3600.0*24.0) * tod_diff_f / time_diff; - infostream<<"Client: Measured time_of_day speed (old format): " - <<time_speed<<" tod_diff_f="<<tod_diff_f - <<" time_diff="<<time_diff<<std::endl; - } + u16 count of added objects + for all added objects { + u16 id + u8 type + u32 initialization data length + string initialization data } + */ - // Update environment - m_env.setTimeOfDay(time_of_day); - m_env.setTimeOfDaySpeed(time_speed); - m_time_of_day_set = true; + // Read removed objects + u8 type; + u16 removed_count, added_count, id; - u32 dr = m_env.getDayNightRatio(); - infostream<<"Client: time_of_day="<<time_of_day - <<" time_speed="<<time_speed - <<" dr="<<dr<<std::endl; - } - else if(command == TOCLIENT_CHAT_MESSAGE) - { - /* - u16 command - u16 length - wstring message - */ - u8 buf[6]; - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); + *pkt >> removed_count; - // Read stuff - is.read((char*) buf, 2); - u16 len = readU16(buf); + for(u16 i=0; i<removed_count; i++) { + *pkt >> id; + m_env.removeActiveObject(id); + } - std::wstring message; - for(unsigned int i=0; i<len; i++) - { - is.read((char*)buf, 2); - message += (wchar_t)readU16(buf); - } + // Read added objects + *pkt >> added_count; - m_chat_queue.push_back(message); + for(u16 i=0; i<added_count; i++) { + *pkt >> id >> type; + m_env.addActiveObject(id, type, pkt->readLongString()); } - else if(command == TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD) - { - /* - u16 command - u16 count of removed objects - for all removed objects { - u16 id - } - u16 count of added objects - for all added objects { - u16 id - u8 type - u32 initialization data length - string initialization data - } - */ - - char buf[6]; - // Get all data except the command number - std::string datastring((char*)&data[2], datasize-2); - // Throw them in an istringstream - std::istringstream is(datastring, std::ios_base::binary); +} - // Read removed objects - is.read(buf, 2); - u16 removed_count = readU16((u8*)buf); - for(unsigned int i=0; i<removed_count; i++) +void Client::handleCommand_ActiveObjectMessages(ToClientPacket* pkt) +{ + /* + u16 command + for all objects { - is.read(buf, 2); - u16 id = readU16((u8*)buf); - m_env.removeActiveObject(id); + u16 id + u16 message length + string message } + */ + char buf[6]; + // Get all data except the command number + std::string datastring(pkt->getString(0), pkt->getSize()); + // Throw them in an istringstream + std::istringstream is(datastring, std::ios_base::binary); - // Read added objects + while(is.eof() == false) { + is.read(buf, 2); + u16 id = readU16((u8*)buf); + if(is.eof()) + break; is.read(buf, 2); - u16 added_count = readU16((u8*)buf); - for(unsigned int i=0; i<added_count; i++) + size_t message_size = readU16((u8*)buf); + std::string message; + message.reserve(message_size); + for(unsigned int i=0; i<message_size; i++) { - is.read(buf, 2); - u16 id = readU16((u8*)buf); is.read(buf, 1); - u8 type = readU8((u8*)buf); - std::string data = deSerializeLongString(is); - // Add it - m_env.addActiveObject(id, type, data); + message.append(buf, 1); } + // Pass on to the environment + m_env.processActiveObjectMessage(id, message); } - else if(command == TOCLIENT_ACTIVE_OBJECT_MESSAGES) - { - /* - u16 command - for all objects - { - u16 id - u16 message length - string message - } - */ - char buf[6]; - // Get all data except the command number - std::string datastring((char*)&data[2], datasize-2); - // Throw them in an istringstream - std::istringstream is(datastring, std::ios_base::binary); +} - while(is.eof() == false) - { - is.read(buf, 2); - u16 id = readU16((u8*)buf); - if(is.eof()) - break; - is.read(buf, 2); - size_t message_size = readU16((u8*)buf); - std::string message; - message.reserve(message_size); - for(unsigned int i=0; i<message_size; i++) - { - is.read(buf, 1); - message.append(buf, 1); - } - // Pass on to the environment - m_env.processActiveObjectMessage(id, message); - } - } - else if(command == TOCLIENT_MOVEMENT) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - player->movement_acceleration_default = readF1000(is) * BS; - player->movement_acceleration_air = readF1000(is) * BS; - player->movement_acceleration_fast = readF1000(is) * BS; - player->movement_speed_walk = readF1000(is) * BS; - player->movement_speed_crouch = readF1000(is) * BS; - player->movement_speed_fast = readF1000(is) * BS; - player->movement_speed_climb = readF1000(is) * BS; - player->movement_speed_jump = readF1000(is) * BS; - player->movement_liquid_fluidity = readF1000(is) * BS; - player->movement_liquid_fluidity_smooth = readF1000(is) * BS; - player->movement_liquid_sink = readF1000(is) * BS; - player->movement_gravity = readF1000(is) * BS; - } - else if(command == TOCLIENT_HP) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); +void Client::handleCommand_Movement(ToClientPacket* pkt) +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); - u8 oldhp = player->hp; - u8 hp = readU8(is); - player->hp = hp; + float mad, maa, maf, msw, mscr, msf, mscl, msj, lf, lfs, ls, g; - 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_back(event); - } - } - else if(command == TOCLIENT_BREATH) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); + *pkt >> mad >> maa >> maf >> msw >> mscr >> msf >> mscl >> msj + >> lf >> lfs >> ls >> g; - player->setBreath(readU16(is)); - } - else if(command == TOCLIENT_MOVE_PLAYER) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - v3f pos = readV3F1000(is); - f32 pitch = readF1000(is); - f32 yaw = readF1000(is); - player->setPosition(pos); - - infostream<<"Client got TOCLIENT_MOVE_PLAYER" - <<" pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")" - <<" pitch="<<pitch - <<" yaw="<<yaw - <<std::endl; + player->movement_acceleration_default = mad * BS; + player->movement_acceleration_air = maa * BS; + player->movement_acceleration_fast = maf * BS; + player->movement_speed_walk = msw * BS; + player->movement_speed_crouch = mscr * BS; + player->movement_speed_fast = msf * BS; + player->movement_speed_climb = mscl * BS; + player->movement_speed_jump = msj * BS; + player->movement_liquid_fluidity = lf * BS; + player->movement_liquid_fluidity_smooth = lfs * BS; + player->movement_liquid_sink = ls * BS; + player->movement_gravity = g * BS; +} - /* - 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_back(event); +void Client::handleCommand_HP(ToClientPacket* pkt) +{ - // 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_PLAYERITEM) - { - infostream<<"Client: WARNING: Ignoring TOCLIENT_PLAYERITEM"<<std::endl; - } - else if(command == TOCLIENT_DEATHSCREEN) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + + u8 oldhp = player->hp; - bool set_camera_point_target = readU8(is); - v3f camera_point_target = readV3F1000(is); + u8 hp; + *pkt >> hp; + player->hp = hp; + + if(hp < oldhp) { + // Add to ClientEvent queue 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; + event.type = CE_PLAYER_DAMAGE; + event.player_damage.amount = oldhp - hp; m_client_event_queue.push_back(event); } - else if(command == TOCLIENT_ANNOUNCE_MEDIA) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - int num_files = readU16(is); - - infostream<<"Client: Received media announcement: packet size: " - <<datasize<<std::endl; - - 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<<"! " - <<" files="<<num_files - <<" size="<<datasize<<std::endl; - return; - } +} - // Mesh update thread must be stopped while - // updating content definitions - assert(!m_mesh_update_thread.IsRunning()); +void Client::handleCommand_Breath(ToClientPacket* pkt) +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); - for(int i=0; i<num_files; i++) - { - std::string name = deSerializeString(is); - std::string sha1_base64 = deSerializeString(is); - std::string sha1_raw = base64_decode(sha1_base64); - m_media_downloader->addFile(name, sha1_raw); - } + u16 breath; - std::vector<std::string> remote_media; - try { - Strfnd sf(deSerializeString(is)); - while(!sf.atend()) { - std::string baseurl = trim(sf.next(",")); - if(baseurl != "") - m_media_downloader->addRemoteServer(baseurl); - } - } - catch(SerializationError& e) { - // not supported by server or turned off - } + *pkt >> breath; - m_media_downloader->step(this); + player->setBreath(breath); +} + +void Client::handleCommand_MovePlayer(ToClientPacket* pkt) +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + + v3f pos; + f32 pitch, yaw; + + *pkt >> pos >> pitch >> yaw; + + 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_back(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; +} + +void Client::handleCommand_PlayerItem(ToClientPacket* pkt) +{ + infostream << "Client: WARNING: Ignoring TOCLIENT_PLAYERITEM" << std::endl; +} + +void Client::handleCommand_DeathScreen(ToClientPacket* pkt) +{ + bool set_camera_point_target; + v3f camera_point_target; + + *pkt >> set_camera_point_target; + *pkt >> camera_point_target; + + 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_back(event); +} + +void Client::handleCommand_AnnounceMedia(ToClientPacket* pkt) +{ + u16 num_files; + + *pkt >> num_files; + + infostream << "Client: Received media announcement: packet size: " + << pkt->getSize() << std::endl; + + 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 << "! " + << " files=" << num_files + << " size=" << pkt->getSize() << std::endl; + return; } - else if(command == TOCLIENT_MEDIA) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - /* - u16 command - u16 total number of file bunches - u16 index of this bunch - u32 number of files in this bunch - for each file { - u16 length of name - string name - u32 length of data - data - } - */ - int num_bunches = readU16(is); - int bunch_i = readU16(is); - u32 num_files = readU32(is); - infostream<<"Client: Received files: bunch "<<bunch_i<<"/" - <<num_bunches<<" files="<<num_files - <<" size="<<datasize<<std::endl; - - if (num_files == 0) - return; + // Mesh update thread must be stopped while + // updating content definitions + assert(!m_mesh_update_thread.IsRunning()); - if (m_media_downloader == NULL || - !m_media_downloader->isStarted()) { - const char *problem = m_media_downloader ? - "media has not been requested" : - "all media has been received already"; - errorstream<<"Client: Received media but " - <<problem<<"! " - <<" bunch "<<bunch_i<<"/"<<num_bunches - <<" files="<<num_files - <<" size="<<datasize<<std::endl; - return; - } + for(int i=0; i<num_files; i++) { + std::string name, sha1_base64; - // Mesh update thread must be stopped while - // updating content definitions - assert(!m_mesh_update_thread.IsRunning()); + *pkt >> name >> sha1_base64; + + std::string sha1_raw = base64_decode(sha1_base64); + m_media_downloader->addFile(name, sha1_raw); + } - for(unsigned int i=0; i<num_files; i++){ - std::string name = deSerializeString(is); - std::string data = deSerializeLongString(is); - m_media_downloader->conventionalTransferDone( - name, data, this); + std::vector<std::string> remote_media; + try { + std::string str; + + *pkt >> str; + + Strfnd sf(str); + while(!sf.atend()) { + std::string baseurl = trim(sf.next(",")); + if(baseurl != "") + m_media_downloader->addRemoteServer(baseurl); } } - else if(command == TOCLIENT_TOOLDEF) - { - infostream<<"Client: WARNING: Ignoring TOCLIENT_TOOLDEF"<<std::endl; + catch(SerializationError& e) { + // not supported by server or turned off } - 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()); - - // Decompress node definitions - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); - std::ostringstream tmp_os; - decompressZlib(tmp_is, tmp_os); - - // Deserialize node definitions - std::istringstream tmp_is2(tmp_os.str()); - m_nodedef->deSerialize(tmp_is2); - m_nodedef_received = true; - } - else if(command == TOCLIENT_CRAFTITEMDEF) - { - infostream<<"Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF"<<std::endl; + + m_media_downloader->step(this); +} + +void Client::handleCommand_Media(ToClientPacket* pkt) +{ + /* + u16 command + u16 total number of file bunches + u16 index of this bunch + u32 number of files in this bunch + for each file { + u16 length of name + string name + u32 length of data + data + } + */ + u16 num_bunches; + u16 bunch_i; + u32 num_files; + + *pkt >> num_bunches >> bunch_i >> num_files; + + infostream << "Client: Received files: bunch " << bunch_i << "/" + << num_bunches << " files=" << num_files + << " size=" << pkt->getSize() << std::endl; + + if (num_files == 0) + return; + + if (m_media_downloader == NULL || + !m_media_downloader->isStarted()) { + const char *problem = m_media_downloader ? + "media has not been requested" : + "all media has been received already"; + errorstream << "Client: Received media but " + << problem << "! " + << " bunch " << bunch_i << "/" << num_bunches + << " files=" << num_files + << " size=" << pkt->getSize() << std::endl; + return; } - 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()); - - // Decompress item definitions - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); - std::ostringstream tmp_os; - decompressZlib(tmp_is, tmp_os); - - // Deserialize node definitions - std::istringstream tmp_is2(tmp_os.str()); - m_itemdef->deSerialize(tmp_is2); - m_itemdef_received = true; - } - else if(command == TOCLIENT_PLAY_SOUND) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - s32 server_id = readS32(is); - std::string name = deSerializeString(is); - float gain = readF1000(is); - int type = readU8(is); // 0=local, 1=positional, 2=object - v3f pos = readV3F1000(is); - u16 object_id = readU16(is); - bool loop = readU8(is); - // Start playing - int client_id = -1; - switch(type){ + + // Mesh update thread must be stopped while + // updating content definitions + assert(!m_mesh_update_thread.IsRunning()); + + for(unsigned int i=0; i<num_files; i++) { + std::string name; + + *pkt >> name; + + std::string data = pkt->readLongString(); + + m_media_downloader->conventionalTransferDone( + name, data, this); + } +} + +void Client::handleCommand_ToolDef(ToClientPacket* pkt) +{ + infostream << "Client: WARNING: Ignoring TOCLIENT_TOOLDEF" << std::endl; +} + +void Client::handleCommand_NodeDef(ToClientPacket* pkt) +{ + infostream << "Client: Received node definitions: packet size: " + << pkt->getSize() << std::endl; + + // Mesh update thread must be stopped while + // updating content definitions + assert(!m_mesh_update_thread.IsRunning()); + + // Decompress node definitions + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); + std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); + std::ostringstream tmp_os; + decompressZlib(tmp_is, tmp_os); + + // Deserialize node definitions + std::istringstream tmp_is2(tmp_os.str()); + m_nodedef->deSerialize(tmp_is2); + m_nodedef_received = true; +} + +void Client::handleCommand_CraftItemDef(ToClientPacket* pkt) +{ + infostream << "Client: WARNING: Ignoring TOCLIENT_CRAFTITEMDEF" << std::endl; +} + +void Client::handleCommand_ItemDef(ToClientPacket* pkt) +{ + infostream << "Client: Received item definitions: packet size: " + << pkt->getSize() << std::endl; + + // Mesh update thread must be stopped while + // updating content definitions + assert(!m_mesh_update_thread.IsRunning()); + + // Decompress item definitions + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); + std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary); + std::ostringstream tmp_os; + decompressZlib(tmp_is, tmp_os); + + // Deserialize node definitions + std::istringstream tmp_is2(tmp_os.str()); + m_itemdef->deSerialize(tmp_is2); + m_itemdef_received = true; +} + +void Client::handleCommand_PlaySound(ToClientPacket* pkt) +{ + s32 server_id; + std::string name; + float gain; + u8 type; // 0=local, 1=positional, 2=object + v3f pos; + u16 object_id; + bool loop; + + *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop; + + // 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 + 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; - } + default: + break; } - else if(command == TOCLIENT_STOP_SOUND) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - s32 server_id = readS32(is); - 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) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - m_privileges.clear(); - infostream<<"Client: Privileges updated: "; - u16 num_privileges = readU16(is); - for(unsigned int i=0; i<num_privileges; i++){ - std::string priv = deSerializeString(is); - m_privileges.insert(priv); - infostream<<priv<<" "; - } - infostream<<std::endl; + 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_INVENTORY_FORMSPEC) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); +} - // Store formspec in LocalPlayer - player->inventory_formspec = deSerializeLongString(is); - } - else if(command == TOCLIENT_DETACHED_INVENTORY) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); +void Client::handleCommand_StopSound(ToClientPacket* pkt) +{ + s32 server_id; - std::string name = deSerializeString(is); + *pkt >> server_id; - infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl; + std::map<s32, int>::iterator i = + m_sounds_server_to_client.find(server_id); - 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); + if(i != m_sounds_server_to_client.end()) { + int client_id = i->second; + m_sound->stopSound(client_id); } - else if(command == TOCLIENT_SHOW_FORMSPEC) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); +} - std::string formspec = deSerializeLongString(is); - std::string formname = deSerializeString(is); +void Client::handleCommand_Privileges(ToClientPacket* pkt) +{ + m_privileges.clear(); + infostream << "Client: Privileges updated: "; + u16 num_privileges; - 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_back(event); - } - else if(command == TOCLIENT_SPAWN_PARTICLE) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - v3f pos = readV3F1000(is); - v3f vel = readV3F1000(is); - v3f acc = readV3F1000(is); - float expirationtime = readF1000(is); - float size = readF1000(is); - bool collisiondetection = readU8(is); - std::string texture = deSerializeLongString(is); - bool vertical = false; - try { - vertical = readU8(is); - } catch (...) {} + *pkt >> num_privileges; - 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); + for(unsigned int i=0; i<num_privileges; i++) { + std::string priv; - m_client_event_queue.push_back(event); + *pkt >> priv; + + m_privileges.insert(priv); + infostream << priv << " "; } - else if(command == TOCLIENT_ADD_PARTICLESPAWNER) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); - - u16 amount = readU16(is); - float spawntime = readF1000(is); - v3f minpos = readV3F1000(is); - v3f maxpos = readV3F1000(is); - v3f minvel = readV3F1000(is); - v3f maxvel = readV3F1000(is); - v3f minacc = readV3F1000(is); - v3f maxacc = readV3F1000(is); - float minexptime = readF1000(is); - float maxexptime = readF1000(is); - float minsize = readF1000(is); - float maxsize = readF1000(is); - bool collisiondetection = readU8(is); - std::string texture = deSerializeLongString(is); - u32 id = readU32(is); - bool vertical = false; - try { - vertical = readU8(is); - } catch (...) {} + infostream << std::endl; +} - 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; +void Client::handleCommand_InventoryFormSpec(ToClientPacket* pkt) +{ + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); - m_client_event_queue.push_back(event); - } - else if(command == TOCLIENT_DELETE_PARTICLESPAWNER) - { - std::string datastring((char*)&data[2], datasize-2); - std::istringstream is(datastring, std::ios_base::binary); + // Store formspec in LocalPlayer + player->inventory_formspec = pkt->readLongString(); +} - u32 id = readU16(is); +void Client::handleCommand_DetachedInventory(ToClientPacket* pkt) +{ + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); - ClientEvent event; - event.type = CE_DELETE_PARTICLESPAWNER; - event.delete_particlespawner.id = id; + std::string name = deSerializeString(is); + + 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); +} + +void Client::handleCommand_ShowFormSpec(ToClientPacket* pkt) +{ + std::string formspec = pkt->readLongString(); + std::string formname; - m_client_event_queue.push_back(event); - } - else if(command == TOCLIENT_HUDADD) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); - - u32 id = readU32(is); - u8 type = readU8(is); - v2f pos = readV2F1000(is); - std::string name = deSerializeString(is); - v2f scale = readV2F1000(is); - std::string text = deSerializeString(is); - u32 number = readU32(is); - u32 item = readU32(is); - u32 dir = readU32(is); - v2f align = readV2F1000(is); - v2f offset = readV2F1000(is); - v3f world_pos; - v2s32 size; - try{ - world_pos = readV3F1000(is); - }catch(SerializationError &e) {}; - try{ - size = readV2S32(is); - } catch(SerializationError &e) {}; + *pkt >> formname; - 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_back(event); - } - else if(command == TOCLIENT_HUDRM) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); + 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_back(event); +} - u32 id = readU32(is); +void Client::handleCommand_SpawnParticle(ToClientPacket* pkt) +{ + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); - ClientEvent event; - event.type = CE_HUDRM; - event.hudrm.id = id; - m_client_event_queue.push_back(event); - } - else if(command == TOCLIENT_HUDCHANGE) - { - std::string sdata; - v2f v2fdata; - v3f v3fdata; - u32 intdata = 0; - v2s32 v2s32data; - - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); - - u32 id = readU32(is); - u8 stat = (HudElementStat)readU8(is); - - if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || - stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) - v2fdata = readV2F1000(is); - else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT) - sdata = deSerializeString(is); - else if (stat == HUD_STAT_WORLD_POS) - v3fdata = readV3F1000(is); - else if (stat == HUD_STAT_SIZE ) - v2s32data = readV2S32(is); - else - intdata = readU32(is); + v3f pos = readV3F1000(is); + v3f vel = readV3F1000(is); + v3f acc = readV3F1000(is); + float expirationtime = readF1000(is); + float size = readF1000(is); + bool collisiondetection = readU8(is); + std::string texture = deSerializeLongString(is); + bool vertical = false; + try { + vertical = readU8(is); + } catch (...) {} - 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_back(event); - } - else if(command == TOCLIENT_HUD_SET_FLAGS) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); + 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); - u32 flags = readU32(is); - u32 mask = readU32(is); + m_client_event_queue.push_back(event); +} - player->hud_flags &= ~mask; - player->hud_flags |= flags; - } - else if(command == TOCLIENT_HUD_SET_PARAM) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); +void Client::handleCommand_AddParticleSpawner(ToClientPacket* pkt) +{ + u16 amount; + float spawntime; + v3f minpos; + v3f maxpos; + v3f minvel; + v3f maxvel; + v3f minacc; + v3f maxacc; + float minexptime; + float maxexptime; + float minsize; + float maxsize; + bool collisiondetection; + u32 id; - u16 param = readU16(is); - std::string value = deSerializeString(is); + *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel + >> minacc >> maxacc >> minexptime >> maxexptime >> minsize + >> maxsize >> collisiondetection; - 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_SET_SKY) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); + std::string texture = pkt->readLongString(); - video::SColor *bgcolor = new video::SColor(readARGB8(is)); - std::string *type = new std::string(deSerializeString(is)); - u16 count = readU16(is); - std::vector<std::string> *params = new std::vector<std::string>; + *pkt >> id; - for(size_t i=0; i<count; i++) - params->push_back(deSerializeString(is)); + bool vertical = false; + try { + *pkt >> vertical; + } catch (...) {} - 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_back(event); + 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_back(event); +} + +void Client::handleCommand_DeleteParticleSpawner(ToClientPacket* pkt) +{ + u16 id; + + *pkt >> id; + + ClientEvent event; + event.type = CE_DELETE_PARTICLESPAWNER; + event.delete_particlespawner.id = id; + + m_client_event_queue.push_back(event); +} + +void Client::handleCommand_HudAdd(ToClientPacket* pkt) +{ + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); + + u32 id; + u8 type; + v2f pos; + std::string name; + v2f scale; + std::string text; + u32 number; + u32 item; + u32 dir; + v2f align; + v2f offset; + v3f world_pos; + v2s32 size; + + *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item + >> dir >> align >> offset; + try { + *pkt >> world_pos; + } + catch(SerializationError &e) {}; + + try { + *pkt >> size; + } catch(SerializationError &e) {}; + + 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_back(event); +} + +void Client::handleCommand_HudRemove(ToClientPacket* pkt) +{ + u32 id; + + *pkt >> id; + + ClientEvent event; + event.type = CE_HUDRM; + event.hudrm.id = id; + m_client_event_queue.push_back(event); +} + +void Client::handleCommand_HudChange(ToClientPacket* pkt) +{ + std::string sdata; + v2f v2fdata; + v3f v3fdata; + u32 intdata = 0; + v2s32 v2s32data; + u32 id; + u8 stat; + + *pkt >> id >> stat; + + if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || + stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) + *pkt >> v2fdata; + else if (stat == HUD_STAT_NAME || stat == HUD_STAT_TEXT) + *pkt >> sdata; + else if (stat == HUD_STAT_WORLD_POS) + *pkt >> v3fdata; + else if (stat == HUD_STAT_SIZE ) + *pkt >> v2s32data; + else + *pkt >> 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_back(event); +} + +void Client::handleCommand_HudSetFlags(ToClientPacket* pkt) +{ + u32 flags, mask; + + *pkt >> flags >> mask; + + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + + player->hud_flags &= ~mask; + player->hud_flags |= flags; +} + +void Client::handleCommand_HudSetParam(ToClientPacket* pkt) +{ + u16 param; std::string value; + + *pkt >> param >> value; + + Player *player = m_env.getLocalPlayer(); + assert(player != NULL); + + 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(command == TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); + 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; + } +} - bool do_override = readU8(is); - float day_night_ratio_f = (float)readU16(is) / 65536; +void Client::handleCommand_HudSetSky(ToClientPacket* pkt) +{ + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); - 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_back(event); + video::SColor *bgcolor = new video::SColor(readARGB8(is)); + std::string *type = new std::string(deSerializeString(is)); + u16 count = readU16(is); + std::vector<std::string> *params = new std::vector<std::string>; + + for(size_t i=0; i<count; i++) + params->push_back(deSerializeString(is)); + + 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_back(event); +} + +void Client::handleCommand_OverrideDayNightRatio(ToClientPacket* pkt) +{ + bool do_override; + u16 day_night_ratio_u; + + *pkt >> do_override >> day_night_ratio_u; + + float day_night_ratio_f = (float)day_night_ratio_u / 65536; + + 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_back(event); +} + +void Client::handleCommand_LocalPlayerAnimations(ToClientPacket* pkt) +{ + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player != NULL); + + *pkt >> player->local_animations[0]; + *pkt >> player->local_animations[1]; + *pkt >> player->local_animations[2]; + *pkt >> player->local_animations[3]; + *pkt >> player->local_animation_speed; +} + +void Client::handleCommand_EyeOffset(ToClientPacket* pkt) +{ + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player != NULL); + + *pkt >> player->eye_offset_first >> player->eye_offset_third; +} + +inline void Client::handleCommand(ToClientPacket* pkt) +{ + const ToClientCommandHandler& opHandle = toClientCommandTable[pkt->getCommand()]; + (this->*opHandle.handler)(pkt); +} + +/* + sender_peer_id given to this shall be quaranteed to be a valid peer +*/ +void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) +{ + DSTACK(__FUNCTION_NAME); + + // Ignore packets that don't even fit a command + if(datasize < 2) { + m_packetcounter.add(60000); + return; } - else if(command == TOCLIENT_LOCAL_PLAYER_ANIMATIONS) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); - LocalPlayer *player = m_env.getLocalPlayer(); - assert(player != NULL); + ToClientPacket* pkt = new ToClientPacket(data, datasize, sender_peer_id); + + ToClientCommand command = pkt->getCommand(); - player->local_animations[0] = readV2S32(is); - player->local_animations[1] = readV2S32(is); - player->local_animations[2] = readV2S32(is); - player->local_animations[3] = readV2S32(is); - player->local_animation_speed = readF1000(is); + //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; + delete pkt; + return; } - else if(command == TOCLIENT_EYE_OFFSET) - { - std::string datastring((char *)&data[2], datasize - 2); - std::istringstream is(datastring, std::ios_base::binary); - LocalPlayer *player = m_env.getLocalPlayer(); - assert(player != NULL); + // Command must be handled into ToClientCommandHandler + if (command >= TOCLIENT_NUM_MSG_TYPES) { + infostream << "Client: Ignoring unknown command " + << command << std::endl; + } - player->eye_offset_first = readV3F1000(is); - player->eye_offset_third = readV3F1000(is); + /* + * Those packets are handled before m_server_ser_ver is set, it's normal + * But we must use the new ToClientConnectionState in the future, + * as a byte mask + */ + if(toClientCommandTable[command].state == TOCLIENT_STATE_NOT_CONNECTED) { + handleCommand(pkt); + delete pkt; + return; } - else - { - infostream<<"Client: Ignoring unknown command " - <<command<<std::endl; + + if(m_server_ser_ver == SER_FMT_VER_INVALID) { + infostream << "Client: Server serialization" + " format invalid or not initialized." + " Skipping incoming command=" << command << std::endl; + delete pkt; + return; } + + /* + Handle runtime commands + */ + + handleCommand(pkt); + delete pkt; } void Client::Send(u16 channelnum, SharedBuffer<u8> data, bool reliable) @@ -2900,4 +2968,3 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename) smgr->getMeshCache()->removeMesh(mesh); return mesh; } - |