Show additional info (estimated remaining time, etc.) when loading map

This commit is contained in:
yvt 2019-05-19 17:08:09 +09:00
parent bb51d1fe20
commit 720be50ff4
No known key found for this signature in database
GPG Key ID: 48F2768FA8D07C92
2 changed files with 84 additions and 1 deletions

View File

@ -530,6 +530,7 @@ namespace spades {
SPLog("Map size advertised by the server: %lu", (unsigned long)mapSize);
mapLoader.reset(new GameMapLoader());
mapLoadMonitor.reset(new MapDownloadMonitor(*mapLoader));
status = NetClientStatusReceivingMap;
statusString = _Tr("NetClient", "Loading snapshot");
@ -544,6 +545,8 @@ namespace spades {
std::vector<char> dt = reader.GetData();
mapLoader->AddRawChunk(dt.data() + 1, dt.size() - 1);
mapLoadMonitor->AccumulateBytes(
static_cast<unsigned int>(dt.size() - 1));
} else {
reader.DumpDebug();
@ -1282,6 +1285,7 @@ namespace spades {
SPLog("Map size advertised by the server: %lu", (unsigned long)mapSize);
mapLoader.reset(new GameMapLoader());
mapLoadMonitor.reset(new MapDownloadMonitor(*mapLoader));
status = NetClientStatusReceivingMap;
statusString = _Tr("NetClient", "Loading snapshot");
@ -1764,6 +1768,7 @@ namespace spades {
// Move `mapLoader` to a local variable so that the associated resources
// are released as soon as possible when no longer needed
std::unique_ptr<GameMapLoader> mapLoader = std::move(this->mapLoader);
mapLoadMonitor.reset();
SPLog("Waiting for the game map decoding to complete...");
mapLoader->MarkEOF();
@ -1807,6 +1812,17 @@ namespace spades {
return mapLoader->GetProgress();
}
std::string NetClient::GetStatusString() {
if (status == NetClientStatusReceivingMap) {
// Display extra information
auto text = mapLoadMonitor->GetDisplayedText();
if (!text.empty()) {
return Format("{0} ({1})", statusString, text);
}
}
return statusString;
}
NetClient::BandwidthMonitor::BandwidthMonitor(ENetHost *host)
: host(host), lastDown(0.0), lastUp(0.0) {
sw.Reset();
@ -1821,5 +1837,57 @@ namespace spades {
sw.Reset();
}
}
NetClient::MapDownloadMonitor::MapDownloadMonitor(GameMapLoader &mapLoader)
: numBytesDownloaded{0}, mapLoader{mapLoader}, receivedFirstByte{false} {}
void NetClient::MapDownloadMonitor::AccumulateBytes(unsigned int numBytes) {
// It might take a while before receiving the first byte. Take this into account to
// get a more accurate estimate of download time.
if (!receivedFirstByte) {
sw.Reset();
receivedFirstByte = true;
}
numBytesDownloaded += numBytes;
}
std::string NetClient::MapDownloadMonitor::GetDisplayedText() {
if (!receivedFirstByte) {
return {};
}
float secondsElapsed = static_cast<float>(sw.GetTime());
if (secondsElapsed <= 0.0) {
return {};
}
float progress = mapLoader.GetProgress();
float bytesPerSec = static_cast<float>(numBytesDownloaded) / secondsElapsed;
float progressPerSec = progress / secondsElapsed;
std::string text = Format("{0} KB, {1} KB/s", (numBytesDownloaded + 500) / 1000,
((int)bytesPerSec + 500) / 1000);
// Estimate the remaining time
float secondsRemaining = (1.0 - progress) / progressPerSec;
if (secondsRemaining < 86400.0) {
int seconds = (int)secondsRemaining + 1;
text += ", ";
if (seconds < 120) {
text +=
_TrN("NetClient", "{0} second remaining", "{0} seconds remaining", seconds);
} else {
text += _TrN("NetClient", "{0} minute remaining", "{0} minutes remaining",
seconds / 60);
}
}
return text;
}
}
}

View File

@ -67,8 +67,23 @@ namespace spades {
ENetPeer *peer;
std::string statusString;
class MapDownloadMonitor {
Stopwatch sw;
unsigned int numBytesDownloaded;
GameMapLoader &mapLoader;
bool receivedFirstByte;
public:
MapDownloadMonitor(GameMapLoader &);
void AccumulateBytes(unsigned int);
std::string GetDisplayedText();
};
/** Only valid in the `NetClientStatusReceivingMap` state */
std::unique_ptr<GameMapLoader> mapLoader;
/** Only valid in the `NetClientStatusReceivingMap` state */
std::unique_ptr<MapDownloadMonitor> mapLoadMonitor;
std::shared_ptr<GameProperties> properties;
@ -135,7 +150,7 @@ namespace spades {
NetClientStatus GetStatus() { return status; }
std::string GetStatusString() { return statusString; }
std::string GetStatusString();
/**
* Gets how much portion of the map has completed loading.