X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fnetwork%2Fclientpackethandler.cpp;h=d19dc38183975844144de93b4d9602b4576fb04e;hb=de73f989eb1397b1103236031fd91309b294583c;hp=1d5a2827723556a2a3a7cf9e83aa2d21b08899af;hpb=88b436e6a9c98af7215bd115e1b7a3f1a1db99d3;p=minetest.git diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 1d5a28277..d19dc3818 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -17,24 +17,30 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "client.h" +#include "client/client.h" #include "util/base64.h" #include "chatmessage.h" -#include "clientmedia.h" +#include "client/clientmedia.h" #include "log.h" #include "map.h" #include "mapsector.h" -#include "minimap.h" +#include "client/minimap.h" +#include "modchannels.h" #include "nodedef.h" #include "serialization.h" #include "server.h" #include "util/strfnd.h" +#include "client/clientevent.h" +#include "client/sound.h" #include "network/clientopcodes.h" +#include "network/connection.h" #include "script/scripting_client.h" #include "util/serialize.h" #include "util/srp.h" #include "tileanimation.h" +#include "gettext.h" +#include "skyparams.h" void Client::handleCommand_Deprecated(NetworkPacket* pkt) { @@ -83,8 +89,8 @@ void Client::handleCommand_Hello(NetworkPacket* pkt) // 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)) { + 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; } @@ -92,12 +98,19 @@ void Client::handleCommand_Hello(NetworkPacket* pkt) // Authenticate using that method, or abort if there wasn't any method found if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) { - startAuth(chosen_auth_mechanism); + if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP && + !m_simple_singleplayer_mode && + !getServerAddress().isLocalhost() && + g_settings->getBool("enable_register_confirmation")) { + promptConfirmRegistration(chosen_auth_mechanism); + } else { + startAuth(chosen_auth_mechanism); + } } else { m_chosen_auth_mech = AUTH_MECHANISM_NONE; m_access_denied = true; m_access_denied_reason = "Unknown"; - m_con.Disconnect(); + m_con->Disconnect(); } } @@ -122,7 +135,15 @@ void Client::handleCommand_AuthAccept(NetworkPacket* pkt) << m_recommended_send_interval<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; - } - v3f playerpos_f = intToFloat(playerpos_s16, BS) - v3f(0, BS / 2, 0); - - - // Set player position - LocalPlayer *player = m_env.getLocalPlayer(); - assert(player != NULL); - player->setPosition(playerpos_f); - - if (pkt->getSize() >= 1 + 6 + 8) { - // Get map seed - *pkt >> m_map_seed; - infostream << "Client: received map seed: " << m_map_seed << std::endl; - } - - if (pkt->getSize() >= 1 + 6 + 8 + 4) { - *pkt >> m_recommended_send_interval; - infostream << "Client: received recommended send interval " - << m_recommended_send_interval<getCommand() == TOCLIENT_ACCESS_DENIED) { - if (pkt->getSize() < 1) - return; - - u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA; - *pkt >> denyCode; - if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN || - denyCode == SERVER_ACCESSDENIED_CRASH) { - *pkt >> m_access_denied_reason; - if (m_access_denied_reason.empty()) { - m_access_denied_reason = accessDeniedStrings[denyCode]; - } - u8 reconnect; - *pkt >> reconnect; - m_access_denied_reconnect = reconnect & 1; - } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) { - *pkt >> m_access_denied_reason; - } else if (denyCode < SERVER_ACCESSDENIED_MAX) { - m_access_denied_reason = accessDeniedStrings[denyCode]; - } else { - // Allow us to add new error messages to the - // protocol without raising the protocol version, if we want to. - // Until then (which may be never), this is outside - // of the defined protocol. - *pkt >> m_access_denied_reason; - if (m_access_denied_reason.empty()) { - m_access_denied_reason = "Unknown"; - } - } - } - // 13/03/15 Legacy code from 0.4.12 and lesser. must stay 1 year - // for compat with old clients - else { + if (pkt->getCommand() != TOCLIENT_ACCESS_DENIED) { + // 13/03/15 Legacy code from 0.4.12 and lesser but is still used + // in some places of the server code if (pkt->getSize() >= 2) { std::wstring wide_reason; *pkt >> wide_reason; m_access_denied_reason = wide_to_utf8(wide_reason); } + return; + } + + if (pkt->getSize() < 1) + return; + + u8 denyCode = SERVER_ACCESSDENIED_UNEXPECTED_DATA; + *pkt >> denyCode; + if (denyCode == SERVER_ACCESSDENIED_SHUTDOWN || + denyCode == SERVER_ACCESSDENIED_CRASH) { + *pkt >> m_access_denied_reason; + if (m_access_denied_reason.empty()) { + m_access_denied_reason = accessDeniedStrings[denyCode]; + } + u8 reconnect; + *pkt >> reconnect; + m_access_denied_reconnect = reconnect & 1; + } else if (denyCode == SERVER_ACCESSDENIED_CUSTOM_STRING) { + *pkt >> m_access_denied_reason; + } else if (denyCode < SERVER_ACCESSDENIED_MAX) { + m_access_denied_reason = accessDeniedStrings[denyCode]; + } else { + // Allow us to add new error messages to the + // protocol without raising the protocol version, if we want to. + // Until then (which may be never), this is outside + // of the defined protocol. + *pkt >> m_access_denied_reason; + if (m_access_denied_reason.empty()) { + m_access_denied_reason = "Unknown"; + } } } @@ -282,6 +249,33 @@ void Client::handleCommand_AddNode(NetworkPacket* pkt) addNode(p, n, remove_metadata); } + +void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt) +{ + if (pkt->getSize() < 1) + return; + + std::istringstream is(pkt->readLongString(), std::ios::binary); + std::stringstream sstr; + decompressZlib(is, sstr); + + NodeMetadataList meta_updates_list(false); + meta_updates_list.deSerialize(sstr, m_itemdef, true); + + Map &map = m_env.getMap(); + for (NodeMetadataMap::const_iterator i = meta_updates_list.begin(); + i != meta_updates_list.end(); ++i) { + v3s16 pos = i->first; + + if (map.isValidPosition(pos) && + map.setNodeMetadata(pos, i->second)) + continue; // Prevent from deleting metadata + + // Meta couldn't be set, unused metadata + delete i->second; + } +} + void Client::handleCommand_BlockData(NetworkPacket* pkt) { // Ignore too small packet @@ -343,7 +337,7 @@ void Client::handleCommand_Inventory(NetworkPacket* pkt) player->inventory.deSerialize(is); - m_inventory_updated = true; + m_update_wielded_item = true; delete m_inventory_from_server; m_inventory_from_server = new Inventory(player->inventory); @@ -367,11 +361,11 @@ void Client::handleCommand_TimeOfDay(NetworkPacket* pkt) } else { // Old message; try to approximate speed of time by ourselves - float time_of_day_f = (float)time_of_day / 24000.0; + float time_of_day_f = (float)time_of_day / 24000.0f; 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; + tod_diff_f = time_of_day_f - m_last_time_of_day_f + 1.0f; else tod_diff_f = time_of_day_f - m_last_time_of_day_f; @@ -380,7 +374,7 @@ void Client::handleCommand_TimeOfDay(NetworkPacket* pkt) m_time_of_day_update_timer = 0; if (m_time_of_day_set) { - time_speed = (3600.0 * 24.0) * tod_diff_f / time_diff; + time_speed = (3600.0f * 24.0f) * 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; @@ -392,34 +386,10 @@ void Client::handleCommand_TimeOfDay(NetworkPacket* pkt) m_env.setTimeOfDaySpeed(time_speed); m_time_of_day_set = true; - u32 dr = m_env.getDayNightRatio(); - infostream << "Client: time_of_day=" << time_of_day - << " time_speed=" << time_speed - << " dr=" << dr << std::endl; -} - -void Client::handleCommand_ChatMessageOld(NetworkPacket *pkt) -{ - /* - u16 command - u16 length - wstring message - */ - u16 len, read_wchar; - - *pkt >> len; - - std::wstring message; - for (u32 i = 0; i < len; i++) { - *pkt >> read_wchar; - message += (wchar_t)read_wchar; - } - - // If chat message not consummed by client lua API - // @TODO send this to CSM using ChatMessage object - if (!moddingEnabled() || !m_script->on_receiving_message(wide_to_utf8(message))) { - pushToChatQueue(new ChatMessage(message)); - } + //u32 dr = m_env.getDayNightRatio(); + //infostream << "Client: time_of_day=" << time_of_day + // << " time_speed=" << time_speed + // << " dr=" << dr << std::endl; } void Client::handleCommand_ChatMessage(NetworkPacket *pkt) @@ -442,17 +412,19 @@ void Client::handleCommand_ChatMessage(NetworkPacket *pkt) return; } - *pkt >> chatMessage->sender >> chatMessage->message >> chatMessage->timestamp; + u64 timestamp; + *pkt >> chatMessage->sender >> chatMessage->message >> timestamp; + chatMessage->timestamp = static_cast(timestamp); chatMessage->type = (ChatMessageType) message_type; // @TODO send this to CSM using ChatMessage object - if (!moddingEnabled() || !m_script->on_receiving_message( + if (modsLoaded() && m_script->on_receiving_message( wide_to_utf8(chatMessage->message))) { - pushToChatQueue(chatMessage); - } else { - // Message was consumed by CSM and should not handled by client, destroying + // Message was consumed by CSM and should not be handled by client delete chatMessage; + } else { + pushToChatQueue(chatMessage); } } @@ -495,6 +467,10 @@ void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt) infostream << "handleCommand_ActiveObjectRemoveAdd: " << e.what() << ". The packet is unreliable, ignoring" << std::endl; } + + // m_activeobjects_received is false before the first + // TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD packet is received + m_activeobjects_received = true; } void Client::handleCommand_ActiveObjectMessages(NetworkPacket* pkt) @@ -551,28 +527,36 @@ void Client::handleCommand_Movement(NetworkPacket* pkt) player->movement_gravity = g * BS; } -void Client::handleCommand_HP(NetworkPacket* pkt) +void Client::handleCommand_Fov(NetworkPacket *pkt) { + f32 fov; + bool is_multiplier; + *pkt >> fov >> is_multiplier; + + LocalPlayer *player = m_env.getLocalPlayer(); + player->setFov({ fov, is_multiplier }); +} +void Client::handleCommand_HP(NetworkPacket *pkt) +{ LocalPlayer *player = m_env.getLocalPlayer(); assert(player != NULL); - u8 oldhp = player->hp; + u16 oldhp = player->hp; - u8 hp; + u16 hp; *pkt >> hp; player->hp = hp; - if (moddingEnabled()) { + if (modsLoaded()) m_script->on_hp_modification(hp); - } if (hp < oldhp) { // Add to ClientEvent queue - ClientEvent event; - event.type = CE_PLAYER_DAMAGE; - event.player_damage.amount = oldhp - hp; + ClientEvent *event = new ClientEvent(); + event->type = CE_PLAYER_DAMAGE; + event->player_damage.amount = oldhp - hp; m_client_event_queue.push(event); } } @@ -613,15 +597,11 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt) 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; + ClientEvent *event = new ClientEvent(); + 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; } void Client::handleCommand_DeathScreen(NetworkPacket* pkt) @@ -632,12 +612,12 @@ void Client::handleCommand_DeathScreen(NetworkPacket* pkt) *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; + ClientEvent *event = new ClientEvent(); + 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); } @@ -802,6 +782,7 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt) [25 + len] bool loop [26 + len] f32 fade [30 + len] f32 pitch + [34 + len] bool ephemeral */ s32 server_id; @@ -814,12 +795,14 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt) bool loop; float fade = 0.0f; float pitch = 1.0f; + bool ephemeral = false; *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop; try { *pkt >> fade; *pkt >> pitch; + *pkt >> ephemeral; } catch (PacketError &e) {}; // Start playing @@ -837,7 +820,6 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt) if (cao) pos = cao->getPosition(); client_id = m_sound->playSoundAt(name, loop, gain, pos, pitch); - // TODO: Set up sound to move with object break; } default: @@ -845,8 +827,11 @@ void Client::handleCommand_PlaySound(NetworkPacket* pkt) } if (client_id != -1) { - m_sounds_server_to_client[server_id] = client_id; - m_sounds_client_to_server[client_id] = server_id; + // for ephemeral sounds, server_id is not meaningful + if (!ephemeral) { + 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; } @@ -910,21 +895,34 @@ void Client::handleCommand_InventoryFormSpec(NetworkPacket* pkt) void Client::handleCommand_DetachedInventory(NetworkPacket* pkt) { - std::string datastring(pkt->getString(0), pkt->getSize()); - std::istringstream is(datastring, std::ios_base::binary); - - std::string name = deSerializeString(is); + std::string name; + bool keep_inv = true; + *pkt >> name >> keep_inv; infostream << "Client: Detached inventory update: \"" << name - << "\"" << std::endl; + << "\", mode=" << (keep_inv ? "update" : "remove") << std::endl; - Inventory *inv = NULL; - if (m_detached_inventories.count(name) > 0) - inv = m_detached_inventories[name]; - else { + const auto &inv_it = m_detached_inventories.find(name); + if (!keep_inv) { + if (inv_it != m_detached_inventories.end()) { + delete inv_it->second; + m_detached_inventories.erase(inv_it); + } + return; + } + Inventory *inv = nullptr; + if (inv_it == m_detached_inventories.end()) { inv = new Inventory(m_itemdef); m_detached_inventories[name] = inv; + } else { + inv = inv_it->second; } + + u16 ignore; + *pkt >> ignore; // this used to be the length of the following string, ignore it + + std::string contents(pkt->getRemainingString(), pkt->getRemainingBytes()); + std::istringstream is(contents, std::ios::binary); inv->deSerialize(is); } @@ -935,12 +933,12 @@ void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt) *pkt >> formname; - ClientEvent event; - event.type = CE_SHOW_FORMSPEC; + ClientEvent *event = new ClientEvent(); + 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); + event->show_formspec.formspec = new std::string(formspec); + event->show_formspec.formname = new std::string(formname); m_client_event_queue.push(event); } @@ -949,38 +947,42 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) std::string datastring(pkt->getString(0), pkt->getSize()); 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); + v3f pos = readV3F32(is); + v3f vel = readV3F32(is); + v3f acc = readV3F32(is); + float expirationtime = readF32(is); + float size = readF32(is); bool collisiondetection = readU8(is); std::string texture = deSerializeLongString(is); - bool vertical = false; - bool collision_removal = false; - struct TileAnimationParams animation; - animation.type = TAT_NONE; - u8 glow = 0; + + bool vertical = false; + bool collision_removal = false; + TileAnimationParams animation; + animation.type = TAT_NONE; + u8 glow = 0; + bool object_collision = false; try { vertical = readU8(is); collision_removal = readU8(is); animation.deSerialize(is, m_proto_ver); glow = readU8(is); + object_collision = readU8(is); } catch (...) {} - 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.collision_removal = collision_removal; - event.spawn_particle.vertical = vertical; - event.spawn_particle.texture = new std::string(texture); - event.spawn_particle.animation = animation; - event.spawn_particle.glow = glow; + ClientEvent *event = new ClientEvent(); + 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.collision_removal = collision_removal; + event->spawn_particle.object_collision = object_collision; + event->spawn_particle.vertical = vertical; + event->spawn_particle.texture = new std::string(texture); + event->spawn_particle.animation = animation; + event->spawn_particle.glow = glow; m_client_event_queue.push(event); } @@ -1000,7 +1002,7 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) float minsize; float maxsize; bool collisiondetection; - u32 id; + u32 server_id; *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel >> minacc >> maxacc >> minexptime >> maxexptime >> minsize @@ -1008,14 +1010,15 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) std::string texture = pkt->readLongString(); - *pkt >> id; + *pkt >> server_id; - bool vertical = false; + bool vertical = false; bool collision_removal = false; - struct TileAnimationParams animation; - animation.type = TAT_NONE; - u8 glow = 0; - u16 attached_id = 0; + u16 attached_id = 0; + TileAnimationParams animation; + animation.type = TAT_NONE; + u8 glow = 0; + bool object_collision = false; try { *pkt >> vertical; *pkt >> collision_removal; @@ -1026,30 +1029,32 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) std::istringstream is(datastring, std::ios_base::binary); animation.deSerialize(is, m_proto_ver); glow = readU8(is); + object_collision = readU8(is); } catch (...) {} - 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.collision_removal = collision_removal; - event.add_particlespawner.attached_id = attached_id; - event.add_particlespawner.vertical = vertical; - event.add_particlespawner.texture = new std::string(texture); - event.add_particlespawner.id = id; - event.add_particlespawner.animation = animation; - event.add_particlespawner.glow = glow; + auto event = new ClientEvent(); + 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.collision_removal = collision_removal; + event->add_particlespawner.object_collision = object_collision; + event->add_particlespawner.attached_id = attached_id; + event->add_particlespawner.vertical = vertical; + event->add_particlespawner.texture = new std::string(texture); + event->add_particlespawner.id = server_id; + event->add_particlespawner.animation = animation; + event->add_particlespawner.glow = glow; m_client_event_queue.push(event); } @@ -1057,22 +1062,12 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt) { - u16 legacy_id; - u32 id; - - // Modification set 13/03/15, 1 year of compat for protocol v24 - if (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY) { - *pkt >> legacy_id; - } - else { - *pkt >> id; - } - + u32 server_id; + *pkt >> server_id; - ClientEvent event; - event.type = CE_DELETE_PARTICLESPAWNER; - event.delete_particlespawner.id = - (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id); + ClientEvent *event = new ClientEvent(); + event->type = CE_DELETE_PARTICLESPAWNER; + event->delete_particlespawner.id = server_id; m_client_event_queue.push(event); } @@ -1082,7 +1077,7 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) std::string datastring(pkt->getString(0), pkt->getSize()); std::istringstream is(datastring, std::ios_base::binary); - u32 id; + u32 server_id; u8 type; v2f pos; std::string name; @@ -1095,8 +1090,9 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) v2f offset; v3f world_pos; v2s32 size; + s16 z_index = 0; - *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item + *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item >> dir >> align >> offset; try { *pkt >> world_pos; @@ -1107,34 +1103,46 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) *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); + try { + *pkt >> z_index; + } + catch(PacketError &e) {} + + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDADD; + event->hudadd.server_id = server_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); + event->hudadd.z_index = z_index; m_client_event_queue.push(event); } void Client::handleCommand_HudRemove(NetworkPacket* pkt) { - u32 id; + u32 server_id; - *pkt >> id; + *pkt >> server_id; - ClientEvent event; - event.type = CE_HUDRM; - event.hudrm.id = id; - m_client_event_queue.push(event); + auto i = m_hud_server_to_client.find(server_id); + if (i != m_hud_server_to_client.end()) { + int client_id = i->second; + m_hud_server_to_client.erase(i); + + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDRM; + event->hudrm.id = client_id; + m_client_event_queue.push(event); + } } void Client::handleCommand_HudChange(NetworkPacket* pkt) @@ -1144,10 +1152,10 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) v3f v3fdata; u32 intdata = 0; v2s32 v2s32data; - u32 id; + u32 server_id; u8 stat; - *pkt >> id >> stat; + *pkt >> server_id >> stat; if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) @@ -1161,16 +1169,19 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) 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(event); + std::unordered_map::const_iterator i = m_hud_server_to_client.find(server_id); + if (i != m_hud_server_to_client.end()) { + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDCHANGE; + event->hudchange.id = i->second; + 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); + } } void Client::handleCommand_HudSetFlags(NetworkPacket* pkt) @@ -1183,18 +1194,23 @@ void Client::handleCommand_HudSetFlags(NetworkPacket* pkt) assert(player != NULL); bool was_minimap_visible = player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE; + bool was_minimap_radar_visible = player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE; player->hud_flags &= ~mask; player->hud_flags |= flags; m_minimap_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_VISIBLE); + bool m_minimap_radar_disabled_by_server = !(player->hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE); // Hide minimap if it has been disabled by the server - if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible) { + if (m_minimap && m_minimap_disabled_by_server && was_minimap_visible) // defers a minimap update, therefore only call it if really // needed, by checking that minimap was visible before m_minimap->setMinimapMode(MINIMAP_MODE_OFF); - } + + // Switch to surface mode if radar disabled by server + if (m_minimap && m_minimap_radar_disabled_by_server && was_minimap_radar_visible) + m_minimap->setMinimapMode(MINIMAP_MODE_SURFACEx1); } void Client::handleCommand_HudSetParam(NetworkPacket* pkt) @@ -1212,49 +1228,140 @@ void Client::handleCommand_HudSetParam(NetworkPacket* pkt) player->hud_hotbar_itemcount = hotbar_itemcount; } else if (param == HUD_PARAM_HOTBAR_IMAGE) { - // If value not empty verify image exists in texture source - if (!value.empty() && !getTextureSource()->isKnownSourceImage(value)) { - errorstream << "Server sent wrong Hud hotbar image (sent value: '" - << value << "')" << std::endl; - return; - } player->hotbar_image = value; } else if (param == HUD_PARAM_HOTBAR_SELECTED_IMAGE) { - // If value not empty verify image exists in texture source - if (!value.empty() && !getTextureSource()->isKnownSourceImage(value)) { - errorstream << "Server sent wrong Hud hotbar selected image (sent value: '" - << value << "')" << std::endl; - return; - } player->hotbar_selected_image = value; } } void Client::handleCommand_HudSetSky(NetworkPacket* pkt) { - std::string datastring(pkt->getString(0), pkt->getSize()); - std::istringstream is(datastring, std::ios_base::binary); + if (m_proto_ver < 39) { + // Handle Protocol 38 and below servers with old set_sky, + // ensuring the classic look is kept. + std::string datastring(pkt->getString(0), pkt->getSize()); + std::istringstream is(datastring, std::ios_base::binary); - video::SColor *bgcolor = new video::SColor(readARGB8(is)); - std::string *type = new std::string(deSerializeString(is)); - u16 count = readU16(is); - std::vector *params = new std::vector; + SkyboxParams skybox; + skybox.bgcolor = video::SColor(readARGB8(is)); + skybox.type = std::string(deSerializeString(is)); + u16 count = readU16(is); + + for (size_t i = 0; i < count; i++) + skybox.textures.emplace_back(deSerializeString(is)); + + skybox.clouds = true; + try { + skybox.clouds = readU8(is); + } catch (...) {} + + // Use default skybox settings: + SkyboxDefaults sky_defaults; + SunParams sun = sky_defaults.getSunDefaults(); + MoonParams moon = sky_defaults.getMoonDefaults(); + StarParams stars = sky_defaults.getStarDefaults(); + + // Fix for "regular" skies, as color isn't kept: + if (skybox.type == "regular") { + skybox.sky_color = sky_defaults.getSkyColorDefaults(); + skybox.tint_type = "default"; + skybox.moon_tint = video::SColor(255, 255, 255, 255); + skybox.sun_tint = video::SColor(255, 255, 255, 255); + } + else { + sun.visible = false; + sun.sunrise_visible = false; + moon.visible = false; + stars.visible = false; + } - for (size_t i = 0; i < count; i++) - params->push_back(deSerializeString(is)); + // Skybox, sun, moon and stars ClientEvents: + ClientEvent *sky_event = new ClientEvent(); + sky_event->type = CE_SET_SKY; + sky_event->set_sky = new SkyboxParams(skybox); + m_client_event_queue.push(sky_event); + + ClientEvent *sun_event = new ClientEvent(); + sun_event->type = CE_SET_SUN; + sun_event->sun_params = new SunParams(sun); + m_client_event_queue.push(sun_event); + + ClientEvent *moon_event = new ClientEvent(); + moon_event->type = CE_SET_MOON; + moon_event->moon_params = new MoonParams(moon); + m_client_event_queue.push(moon_event); + + ClientEvent *star_event = new ClientEvent(); + star_event->type = CE_SET_STARS; + star_event->star_params = new StarParams(stars); + m_client_event_queue.push(star_event); + } else { + SkyboxParams skybox; + u16 texture_count; + std::string texture; + + *pkt >> skybox.bgcolor >> skybox.type >> skybox.clouds >> + skybox.sun_tint >> skybox.moon_tint >> skybox.tint_type; + + if (skybox.type == "skybox") { + *pkt >> texture_count; + for (int i = 0; i < texture_count; i++) { + *pkt >> texture; + skybox.textures.emplace_back(texture); + } + } + else if (skybox.type == "regular") { + *pkt >> skybox.sky_color.day_sky >> skybox.sky_color.day_horizon + >> skybox.sky_color.dawn_sky >> skybox.sky_color.dawn_horizon + >> skybox.sky_color.night_sky >> skybox.sky_color.night_horizon + >> skybox.sky_color.indoors; + } - bool clouds = true; - try { - clouds = readU8(is); - } catch (...) {} + ClientEvent *event = new ClientEvent(); + event->type = CE_SET_SKY; + event->set_sky = new SkyboxParams(skybox); + m_client_event_queue.push(event); + } +} + +void Client::handleCommand_HudSetSun(NetworkPacket *pkt) +{ + SunParams sun; + + *pkt >> sun.visible >> sun.texture>> sun.tonemap + >> sun.sunrise >> sun.sunrise_visible >> sun.scale; + + ClientEvent *event = new ClientEvent(); + event->type = CE_SET_SUN; + event->sun_params = new SunParams(sun); + m_client_event_queue.push(event); +} + +void Client::handleCommand_HudSetMoon(NetworkPacket *pkt) +{ + MoonParams moon; + + *pkt >> moon.visible >> moon.texture + >> moon.tonemap >> moon.scale; + + ClientEvent *event = new ClientEvent(); + event->type = CE_SET_MOON; + event->moon_params = new MoonParams(moon); + m_client_event_queue.push(event); +} + +void Client::handleCommand_HudSetStars(NetworkPacket *pkt) +{ + StarParams stars; + + *pkt >> stars.visible >> stars.count + >> stars.starcolor >> stars.scale; + + ClientEvent *event = new ClientEvent(); + event->type = CE_SET_STARS; + event->star_params = new StarParams(stars); - ClientEvent event; - event.type = CE_SET_SKY; - event.set_sky.bgcolor = bgcolor; - event.set_sky.type = type; - event.set_sky.params = params; - event.set_sky.clouds = clouds; m_client_event_queue.push(event); } @@ -1270,19 +1377,19 @@ void Client::handleCommand_CloudParams(NetworkPacket* pkt) *pkt >> density >> color_bright >> color_ambient >> height >> thickness >> speed; - ClientEvent event; - event.type = CE_CLOUD_PARAMS; - event.cloud_params.density = density; + ClientEvent *event = new ClientEvent(); + event->type = CE_CLOUD_PARAMS; + event->cloud_params.density = density; // use the underlying u32 representation, because we can't // use struct members with constructors here, and this way // we avoid using new() and delete() for no good reason - event.cloud_params.color_bright = color_bright.color; - event.cloud_params.color_ambient = color_ambient.color; - event.cloud_params.height = height; - event.cloud_params.thickness = thickness; + event->cloud_params.color_bright = color_bright.color; + event->cloud_params.color_ambient = color_ambient.color; + event->cloud_params.height = height; + event->cloud_params.thickness = thickness; // same here: deconstruct to skip constructor - event.cloud_params.speed_x = speed.X; - event.cloud_params.speed_y = speed.Y; + event->cloud_params.speed_x = speed.X; + event->cloud_params.speed_y = speed.Y; m_client_event_queue.push(event); } @@ -1295,10 +1402,10 @@ void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt) 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; + ClientEvent *event = new ClientEvent(); + 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); } @@ -1346,9 +1453,9 @@ void Client::handleCommand_UpdatePlayerList(NetworkPacket* pkt) void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt) { - if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD) - && (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) { - errorstream << "Client: Recieved SRP S_B login message," + if (m_chosen_auth_mech != AUTH_MECHANISM_SRP && + m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD) { + errorstream << "Client: Received SRP S_B login message," << " but wasn't supposed to (chosen_mech=" << m_chosen_auth_mech << ")." << std::endl; return; @@ -1361,7 +1468,7 @@ void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt) std::string B; *pkt >> s >> B; - infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl; + infostream << "Client: Received TOCLIENT_SRP_BYTES_S_B." << std::endl; srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(), (const unsigned char *) B.c_str(), B.size(), @@ -1377,7 +1484,123 @@ void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt) Send(&resp_pkt); } -void Client::handleCommand_CSMFlavourLimits(NetworkPacket *pkt) +void Client::handleCommand_FormspecPrepend(NetworkPacket *pkt) +{ + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player != NULL); + + // Store formspec in LocalPlayer + *pkt >> player->formspec_prepend; +} + +void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt) +{ + *pkt >> m_csm_restriction_flags >> m_csm_restriction_noderange; + + // Restrictions were received -> load mods if it's enabled + // Note: this should be moved after mods receptions from server instead + loadMods(); +} + +void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt) +{ + v3f added_vel; + + *pkt >> added_vel; + + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player != NULL); + player->addVelocity(added_vel); +} + +/* + * Mod channels + */ + +void Client::handleCommand_ModChannelMsg(NetworkPacket *pkt) +{ + std::string channel_name, sender, channel_msg; + *pkt >> channel_name >> sender >> channel_msg; + + verbosestream << "Mod channel message received from server " << pkt->getPeerId() + << " on channel " << channel_name << ". sender: `" << sender << "`, message: " + << channel_msg << std::endl; + + if (!m_modchannel_mgr->channelRegistered(channel_name)) { + verbosestream << "Server sent us messages on unregistered channel " + << channel_name << ", ignoring." << std::endl; + return; + } + + m_script->on_modchannel_message(channel_name, sender, channel_msg); +} + +void Client::handleCommand_ModChannelSignal(NetworkPacket *pkt) { - *pkt >> m_csm_flavour_limits >> m_csm_noderange_limit; + u8 signal_tmp; + ModChannelSignal signal; + std::string channel; + + *pkt >> signal_tmp >> channel; + + signal = (ModChannelSignal)signal_tmp; + + bool valid_signal = true; + // @TODO: send Signal to Lua API + switch (signal) { + case MODCHANNEL_SIGNAL_JOIN_OK: + m_modchannel_mgr->setChannelState(channel, MODCHANNEL_STATE_READ_WRITE); + infostream << "Server ack our mod channel join on channel `" << channel + << "`, joining." << std::endl; + break; + case MODCHANNEL_SIGNAL_JOIN_FAILURE: + // Unable to join, remove channel + m_modchannel_mgr->leaveChannel(channel, 0); + infostream << "Server refused our mod channel join on channel `" << channel + << "`" << std::endl; + break; + case MODCHANNEL_SIGNAL_LEAVE_OK: +#ifndef NDEBUG + infostream << "Server ack our mod channel leave on channel " << channel + << "`, leaving." << std::endl; +#endif + break; + case MODCHANNEL_SIGNAL_LEAVE_FAILURE: + infostream << "Server refused our mod channel leave on channel `" << channel + << "`" << std::endl; + break; + case MODCHANNEL_SIGNAL_CHANNEL_NOT_REGISTERED: +#ifndef NDEBUG + // Generally unused, but ensure we don't do an implementation error + infostream << "Server tells us we sent a message on channel `" << channel + << "` but we are not registered. Message was dropped." << std::endl; +#endif + break; + case MODCHANNEL_SIGNAL_SET_STATE: { + u8 state; + *pkt >> state; + + if (state == MODCHANNEL_STATE_INIT || state >= MODCHANNEL_STATE_MAX) { + infostream << "Received wrong channel state " << state + << ", ignoring." << std::endl; + return; + } + + m_modchannel_mgr->setChannelState(channel, (ModChannelState) state); + infostream << "Server sets mod channel `" << channel + << "` in read-only mode." << std::endl; + break; + } + default: +#ifndef NDEBUG + warningstream << "Received unhandled mod channel signal ID " + << signal << ", ignoring." << std::endl; +#endif + valid_signal = false; + break; + } + + // If signal is valid, forward it to client side mods + if (valid_signal) + m_script->on_modchannel_signal(channel, signal); }