aboutsummaryrefslogtreecommitdiff
path: root/src/network/clientpackethandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/clientpackethandler.cpp')
-rw-r--r--src/network/clientpackethandler.cpp250
1 files changed, 147 insertions, 103 deletions
diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp
index 44bd81dac..48ad60ac6 100644
--- a/src/network/clientpackethandler.cpp
+++ b/src/network/clientpackethandler.cpp
@@ -43,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tileanimation.h"
#include "gettext.h"
#include "skyparams.h"
+#include <memory>
void Client::handleCommand_Deprecated(NetworkPacket* pkt)
{
@@ -88,7 +89,7 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
// This is only neccessary though when we actually want to add casing support
if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
- // we recieved a TOCLIENT_HELLO while auth was already going on
+ // we received 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 ||
@@ -156,7 +157,7 @@ void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
m_password = m_new_password;
- verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
+ verbosestream << "Client: Received TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
// send packet to actually set the password
startAuth(AUTH_MECHANISM_FIRST_SRP);
@@ -261,7 +262,7 @@ void Client::handleCommand_NodemetaChanged(NetworkPacket *pkt)
return;
std::istringstream is(pkt->readLongString(), std::ios::binary);
- std::stringstream sstr;
+ std::stringstream sstr(std::ios::binary | std::ios::in | std::ios::out);
decompressZlib(is, sstr);
NodeMetadataList meta_updates_list(false);
@@ -670,21 +671,19 @@ void Client::handleCommand_AnnounceMedia(NetworkPacket* pkt)
m_media_downloader->addFile(name, sha1_raw);
}
- try {
+ {
std::string str;
-
*pkt >> str;
Strfnd sf(str);
- while(!sf.at_end()) {
+ while (!sf.at_end()) {
std::string baseurl = trim(sf.next(","));
- if (!baseurl.empty())
+ if (!baseurl.empty()) {
+ m_remote_media_servers.emplace_back(baseurl);
m_media_downloader->addRemoteServer(baseurl);
+ }
}
}
- catch(SerializationError& e) {
- // not supported by server or turned off
- }
m_media_downloader->step(this);
}
@@ -716,31 +715,38 @@ void Client::handleCommand_Media(NetworkPacket* pkt)
if (num_files == 0)
return;
- if (!m_media_downloader || !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;
- }
+ bool init_phase = m_media_downloader && m_media_downloader->isStarted();
- // Mesh update thread must be stopped while
- // updating content definitions
- sanity_check(!m_mesh_update_thread.isRunning());
+ if (init_phase) {
+ // Mesh update thread must be stopped while
+ // updating content definitions
+ sanity_check(!m_mesh_update_thread.isRunning());
+ }
- for (u32 i=0; i < num_files; i++) {
- std::string name;
+ for (u32 i = 0; i < num_files; i++) {
+ std::string name, data;
*pkt >> name;
+ data = pkt->readLongString();
- std::string data = pkt->readLongString();
-
- m_media_downloader->conventionalTransferDone(
- name, data, this);
+ bool ok = false;
+ if (init_phase) {
+ ok = m_media_downloader->conventionalTransferDone(name, data, this);
+ } else {
+ // Check pending dynamic transfers, one of them must be it
+ for (const auto &it : m_pending_media_downloads) {
+ if (it.second->conventionalTransferDone(name, data, this)) {
+ ok = true;
+ break;
+ }
+ }
+ }
+ if (!ok) {
+ errorstream << "Client: Received media \"" << name
+ << "\" but no downloads pending. " << num_bunches << " bunches, "
+ << num_files << " in this one. (init_phase=" << init_phase
+ << ")" << std::endl;
+ }
}
}
@@ -755,12 +761,11 @@ void Client::handleCommand_NodeDef(NetworkPacket* pkt)
// Decompress node definitions
std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
- std::ostringstream tmp_os;
+ std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
decompressZlib(tmp_is, tmp_os);
// Deserialize node definitions
- std::istringstream tmp_is2(tmp_os.str());
- m_nodedef->deSerialize(tmp_is2);
+ m_nodedef->deSerialize(tmp_os);
m_nodedef_received = true;
}
@@ -775,12 +780,11 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt)
// Decompress item definitions
std::istringstream tmp_is(pkt->readLongString(), std::ios::binary);
- std::ostringstream tmp_os;
+ std::stringstream tmp_os(std::ios::binary | std::ios::in | std::ios::out);
decompressZlib(tmp_is, tmp_os);
// Deserialize node definitions
- std::istringstream tmp_is2(tmp_os.str());
- m_itemdef->deSerialize(tmp_is2);
+ m_itemdef->deSerialize(tmp_os);
m_itemdef_received = true;
}
@@ -1041,9 +1045,6 @@ void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt)
void Client::handleCommand_HudAdd(NetworkPacket* pkt)
{
- std::string datastring(pkt->getString(0), pkt->getSize());
- std::istringstream is(datastring, std::ios_base::binary);
-
u32 server_id;
u8 type;
v2f pos;
@@ -1059,6 +1060,7 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt)
v2s32 size;
s16 z_index = 0;
std::string text2;
+ u32 style = 0;
*pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item
>> dir >> align >> offset;
@@ -1067,25 +1069,28 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt)
*pkt >> size;
*pkt >> z_index;
*pkt >> text2;
+ *pkt >> style;
} 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;
- event->hudadd.text2 = new std::string(text2);
+ event->type = CE_HUDADD;
+ event->hudadd = new ClientEventHudAdd();
+ event->hudadd->server_id = server_id;
+ event->hudadd->type = type;
+ event->hudadd->pos = pos;
+ event->hudadd->name = name;
+ event->hudadd->scale = scale;
+ event->hudadd->text = text;
+ event->hudadd->number = number;
+ event->hudadd->item = item;
+ event->hudadd->dir = dir;
+ event->hudadd->align = align;
+ event->hudadd->offset = offset;
+ event->hudadd->world_pos = world_pos;
+ event->hudadd->size = size;
+ event->hudadd->z_index = z_index;
+ event->hudadd->text2 = text2;
+ event->hudadd->style = style;
m_client_event_queue.push(event);
}
@@ -1113,27 +1118,40 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt)
*pkt >> server_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 || stat == HUD_STAT_TEXT2)
- *pkt >> sdata;
- else if (stat == HUD_STAT_WORLD_POS)
- *pkt >> v3fdata;
- else if (stat == HUD_STAT_SIZE )
- *pkt >> v2s32data;
- else
- *pkt >> intdata;
+ // Keep in sync with:server.cpp -> SendHUDChange
+ switch ((HudElementStat)stat) {
+ case HUD_STAT_POS:
+ case HUD_STAT_SCALE:
+ case HUD_STAT_ALIGN:
+ case HUD_STAT_OFFSET:
+ *pkt >> v2fdata;
+ break;
+ case HUD_STAT_NAME:
+ case HUD_STAT_TEXT:
+ case HUD_STAT_TEXT2:
+ *pkt >> sdata;
+ break;
+ case HUD_STAT_WORLD_POS:
+ *pkt >> v3fdata;
+ break;
+ case HUD_STAT_SIZE:
+ *pkt >> v2s32data;
+ break;
+ default:
+ *pkt >> intdata;
+ break;
+ }
ClientEvent *event = new ClientEvent();
- event->type = CE_HUDCHANGE;
- event->hudchange.id = server_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);
+ event->type = CE_HUDCHANGE;
+ event->hudchange = new ClientEventHudChange();
+ event->hudchange->id = server_id;
+ event->hudchange->stat = static_cast<HudElementStat>(stat);
+ event->hudchange->v2fdata = v2fdata;
+ event->hudchange->v3fdata = v3fdata;
+ event->hudchange->sdata = sdata;
+ event->hudchange->data = intdata;
+ event->hudchange->v2s32data = v2s32data;
m_client_event_queue.push(event);
}
@@ -1219,19 +1237,17 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt)
} catch (...) {}
// Use default skybox settings:
- SkyboxDefaults sky_defaults;
- SunParams sun = sky_defaults.getSunDefaults();
- MoonParams moon = sky_defaults.getMoonDefaults();
- StarParams stars = sky_defaults.getStarDefaults();
+ SunParams sun = SkyboxDefaults::getSunDefaults();
+ MoonParams moon = SkyboxDefaults::getMoonDefaults();
+ StarParams stars = SkyboxDefaults::getStarDefaults();
// Fix for "regular" skies, as color isn't kept:
if (skybox.type == "regular") {
- skybox.sky_color = sky_defaults.getSkyColorDefaults();
+ skybox.sky_color = SkyboxDefaults::getSkyColorDefaults();
skybox.fog_tint_type = "default";
skybox.fog_moon_tint = video::SColor(255, 255, 255, 255);
skybox.fog_sun_tint = video::SColor(255, 255, 255, 255);
- }
- else {
+ } else {
sun.visible = false;
sun.sunrise_visible = false;
moon.visible = false;
@@ -1381,6 +1397,8 @@ void Client::handleCommand_LocalPlayerAnimations(NetworkPacket* pkt)
*pkt >> player->local_animations[2];
*pkt >> player->local_animations[3];
*pkt >> player->local_animation_speed;
+
+ player->last_animation = -1;
}
void Client::handleCommand_EyeOffset(NetworkPacket* pkt)
@@ -1478,46 +1496,72 @@ void Client::handleCommand_PlayerSpeed(NetworkPacket *pkt)
void Client::handleCommand_MediaPush(NetworkPacket *pkt)
{
std::string raw_hash, filename, filedata;
+ u32 token;
bool cached;
*pkt >> raw_hash >> filename >> cached;
- filedata = pkt->readLongString();
+ if (m_proto_ver >= 40)
+ *pkt >> token;
+ else
+ filedata = pkt->readLongString();
- if (raw_hash.size() != 20 || filedata.empty() || filename.empty() ||
+ if (raw_hash.size() != 20 || filename.empty() ||
+ (m_proto_ver < 40 && filedata.empty()) ||
!string_allowed(filename, TEXTURENAME_ALLOWED_CHARS)) {
throw PacketError("Illegal filename, data or hash");
}
- verbosestream << "Server pushes media file \"" << filename << "\" with "
- << filedata.size() << " bytes of data (cached=" << cached
- << ")" << std::endl;
+ verbosestream << "Server pushes media file \"" << filename << "\" ";
+ if (filedata.empty())
+ verbosestream << "to be fetched ";
+ else
+ verbosestream << "with " << filedata.size() << " bytes ";
+ verbosestream << "(cached=" << cached << ")" << std::endl;
if (m_media_pushed_files.count(filename) != 0) {
- // Silently ignore for synchronization purposes
+ // Ignore (but acknowledge). Previously this was for sync purposes,
+ // but even in new versions media cannot be replaced at runtime.
+ if (m_proto_ver >= 40)
+ sendHaveMedia({ token });
return;
}
- // Compute and check checksum of data
- std::string computed_hash;
- {
- SHA1 ctx;
- ctx.addBytes(filedata.c_str(), filedata.size());
- unsigned char *buf = ctx.getDigest();
- computed_hash.assign((char*) buf, 20);
- free(buf);
- }
- if (raw_hash != computed_hash) {
- verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
+ if (!filedata.empty()) {
+ // LEGACY CODEPATH
+ // Compute and check checksum of data
+ std::string computed_hash;
+ {
+ SHA1 ctx;
+ ctx.addBytes(filedata.c_str(), filedata.size());
+ unsigned char *buf = ctx.getDigest();
+ computed_hash.assign((char*) buf, 20);
+ free(buf);
+ }
+ if (raw_hash != computed_hash) {
+ verbosestream << "Hash of file data mismatches, ignoring." << std::endl;
+ return;
+ }
+
+ // Actually load media
+ loadMedia(filedata, filename, true);
+ m_media_pushed_files.insert(filename);
+
+ // Cache file for the next time when this client joins the same server
+ if (cached)
+ clientMediaUpdateCache(raw_hash, filedata);
return;
}
- // Actually load media
- loadMedia(filedata, filename, true);
m_media_pushed_files.insert(filename);
- // Cache file for the next time when this client joins the same server
- if (cached)
- clientMediaUpdateCache(raw_hash, filedata);
+ // create a downloader for this file
+ auto downloader(std::make_shared<SingleMediaDownloader>(cached));
+ m_pending_media_downloads.emplace_back(token, downloader);
+ downloader->addFile(filename, raw_hash);
+ for (const auto &baseurl : m_remote_media_servers)
+ downloader->addRemoteServer(baseurl);
+
+ downloader->step(this);
}
/*