Display a progress bar when receiving a map

Replaces the old useless "num-bytes-loaded/16777216" message with a
real progress bar.
This commit is contained in:
yvt 2019-05-19 16:25:39 +09:00
parent 97ed5d46ad
commit cd3304ef24
No known key found for this signature in database
GPG Key ID: 48F2768FA8D07C92
4 changed files with 75 additions and 32 deletions

View File

@ -867,20 +867,34 @@ namespace spades {
MakeVector4(1, 1, 1, 0.95f));
img = renderer->RegisterImage("Gfx/White.tga");
float pos = timeSinceInit / 3.6f;
pos -= floorf(pos);
pos = 1.f - pos * 2.0f;
for (float v = 0; v < 0.6f; v += 0.14f) {
float p = pos + v;
if (p < 0.01f || p > .99f)
continue;
p = asin(p * 2.f - 1.f);
p = p / (float)M_PI + 0.5f;
float op = p * (1.f - p) * 4.f;
renderer->SetColorAlphaPremultiplied(MakeVector4(op, op, op, op));
if (net->GetStatus() == NetClientStatusReceivingMap) {
// Normal progress bar
float progress = net->GetMapReceivingProgress();
renderer->SetColorAlphaPremultiplied(MakeVector4(0.2f, 0.2f, 0.2f, 0.2f));
renderer->DrawImage(img, AABB2(scrWidth - 236.f, scrHeight - 18.f, 222.f, 4.f));
renderer->SetColorAlphaPremultiplied(MakeVector4(1.0f, 1.0f, 1.0f, 1.0f));
renderer->DrawImage(
img, AABB2(scrWidth - 236.f + p * 234.f, scrHeight - 18.f, 4.f, 4.f));
img, AABB2(scrWidth - 236.f, scrHeight - 18.f, 222.f * progress, 4.f));
} else {
// Indeterminate progress bar
float pos = timeSinceInit / 3.6f;
pos -= floorf(pos);
pos = 1.f - pos * 2.0f;
for (float v = 0; v < 0.6f; v += 0.14f) {
float p = pos + v;
if (p < 0.01f || p > .99f)
continue;
p = asin(p * 2.f - 1.f);
p = p / (float)M_PI + 0.5f;
float op = p * (1.f - p) * 4.f;
renderer->SetColorAlphaPremultiplied(MakeVector4(op, op, op, op));
renderer->DrawImage(
img, AABB2(scrWidth - 236.f + p * 234.f, scrHeight - 18.f, 4.f, 4.f));
}
}
DrawAlert();

View File

@ -70,7 +70,7 @@ namespace spades {
}
};
GameMapLoader::GameMapLoader() {
GameMapLoader::GameMapLoader() : progressCell{0} {
SPADES_MARK_FUNCTION();
auto pipe = CreatePipeStream();

View File

@ -28,6 +28,7 @@
#include "CTFGameMode.h"
#include "Client.h"
#include "GameMap.h"
#include "GameMapLoader.h"
#include "Grenade.h"
#include "NetClient.h"
#include "Player.h"
@ -525,22 +526,24 @@ namespace spades {
SPRaise("Unexpected packet: %d", (int)reader.GetType());
}
mapSize = reader.ReadInt();
auto mapSize = reader.ReadInt();
SPLog("Map size advertised by the server: %lu", (unsigned long)mapSize);
mapLoader.reset(new GameMapLoader());
status = NetClientStatusReceivingMap;
statusString = _Tr("NetClient", "Loading snapshot");
}
} else if (status == NetClientStatusReceivingMap) {
SPAssert(mapLoader);
if (event.type == ENET_EVENT_TYPE_RECEIVE) {
auto &reader = readerOrNone.value();
if (reader.GetType() == PacketTypeMapChunk) {
std::vector<char> dt = reader.GetData();
dt.erase(dt.begin());
mapData.insert(mapData.end(), dt.begin(), dt.end());
statusString = _Tr("NetClient", "Loading snapshot ({0}/{1})",
mapData.size(), mapSize);
mapLoader->AddRawChunk(dt.data() + 1, dt.size() - 1);
} else {
reader.DumpDebug();
@ -580,8 +583,7 @@ namespace spades {
} catch (const std::exception &ex) {
if (strstr(ex.what(), "File truncated") ||
strstr(ex.what(), "EOF reached")) {
SPLog("Map decoder returned error:\n%s",
ex.what());
SPLog("Map decoder returned error:\n%s", ex.what());
Disconnect();
statusString = _Tr("NetClient", "Error");
throw;
@ -597,7 +599,7 @@ namespace spades {
// cancel the reload packets on map change and
// they would cause an error if we would
// process them
} else {
} else {
// Save the packet for later
savedPackets.push_back(reader.GetData());
}
@ -1275,7 +1277,12 @@ namespace spades {
case PacketTypeMapStart: {
// next map!
client->SetWorld(NULL);
mapSize = reader.ReadInt();
auto mapSize = reader.ReadInt();
SPLog("Map size advertised by the server: %lu", (unsigned long)mapSize);
mapLoader.reset(new GameMapLoader());
status = NetClientStatusReceivingMap;
statusString = _Tr("NetClient", "Loading snapshot");
} break;
@ -1751,12 +1758,18 @@ namespace spades {
void NetClient::MapLoaded() {
SPADES_MARK_FUNCTION();
MemoryStream compressed(mapData.data(), mapData.size());
DeflateStream inflate(&compressed, CompressModeDecompress, false);
GameMap *map;
map = GameMap::Load(&inflate);
SPLog("Map decoding succeeded.");
SPAssert(mapLoader);
// 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);
SPLog("Waiting for the game map decoding to complete...");
mapLoader->MarkEOF();
mapLoader->WaitComplete();
GameMap *map = mapLoader->TakeGameMap();
SPLog("The game map was decoded successfully.");
// now initialize world
World *w = new World(properties);
@ -1766,8 +1779,6 @@ namespace spades {
client->SetWorld(w);
mapData.clear();
SPAssert(GetWorld());
SPLog("World loaded. Processing saved packets (%d)...", (int)savedPackets.size());
@ -1790,6 +1801,12 @@ namespace spades {
}
}
float NetClient::GetMapReceivingProgress() {
SPAssert(status == NetClientStatusReceivingMap);
return mapLoader->GetProgress();
}
NetClient::BandwidthMonitor::BandwidthMonitor(ENetHost *host)
: host(host), lastDown(0.0), lastUp(0.0) {
sw.Reset();

View File

@ -58,14 +58,18 @@ namespace spades {
struct WeaponInput;
class Grenade;
struct GameProperties;
class GameMapLoader;
class NetClient {
Client *client;
NetClientStatus status;
ENetHost *host;
ENetPeer *peer;
std::string statusString;
unsigned int mapSize;
std::vector<char> mapData;
/** Only valid in the `NetClientStatusReceivingMap` state */
std::unique_ptr<GameMapLoader> mapLoader;
std::shared_ptr<GameProperties> properties;
int protocolVersion;
@ -133,6 +137,14 @@ namespace spades {
std::string GetStatusString() { return statusString; }
/**
* Gets how much portion of the map has completed loading.
* `GetStatus()` must be `NetClientStatusReceivingMap`.
*
* @return A value in range `[0, 1]`.
*/
float GetMapReceivingProgress();
/**
* Return a non-null reference to `GameProperties` for this connection.
* Must be the connected state.