Skip to content
Merged

Fixxx #105

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/server/PlayerInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class CPlayerInfo

bool connected; //unused
float pingMs = -1.0f;

// Last time any datagram was received from this client
std::chrono::steady_clock::time_point lastSeenAt = std::chrono::steady_clock::now();
};

#endif
2 changes: 2 additions & 0 deletions include/server/Server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class Server {
void dispatchPacket(PacketPtr &pkt, sockaddr_in &cliaddr);
void receiveConnect(NetConnect &pkt, const sockaddr_in &cliaddr);
void receiveDisconnect(NetDisconnect &pkt, const sockaddr_in &cliaddr);
void removePlayer(std::vector<CPlayerInfo>::iterator player);
void timeoutSilentClients();
void receivePlayerInputs(NetPlayerInputs &pkt, const sockaddr_in &clieaddr);
void receivePlayerMouseInputs(NetPlayerMouseInputs &pkt, const sockaddr_in &clieddr);
void receiveMessage(NetMessage &pkt, const sockaddr_in &cliaddr);
Expand Down
3 changes: 3 additions & 0 deletions src/client/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ void Renderer::clearCache()
maxRenderedChunkDist = 0.0f;
cameraFrustum = Frustum();
frustumEyePos = glm::dvec3(0.0);
livingEntities.clear();
itemEntities.clear();
entitiesMap.clear();
}

void Renderer::updateChunk(const NetModifiedBlockData &pkt)
Expand Down
80 changes: 63 additions & 17 deletions src/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,14 @@
if (p != players.end()) {
p->recvRel.expectedSeq = 1;
p->recvRel.lastProgressAt = currTick;
p->lastSeenAt = currTick;
}
}
return;
}

player->lastSeenAt = currTick;

// Known peer: route through the reliability layer.
auto result = reliabilityIngest(player->recvRel, std::move(pkt), currTick);
if (result.nack) {
Expand Down Expand Up @@ -337,6 +340,10 @@
if (tick > 0 && tick % static_cast<int>(TPS) == 0)
despawnDistantMobs();

// Evict crashed / silently-gone clients once per second.
if (tick > 0 && tick % static_cast<int>(TPS) == 0)
timeoutSilentClients();

// Broadcast every 20 ticks (~1s)
if (tick % static_cast<int>(TPS) == 0)
broadcastSkyTime();
Expand Down Expand Up @@ -464,37 +471,45 @@
}
}

void Server::receiveDisconnect(NetDisconnect &pkt, const sockaddr_in &cliaddr)

Check warning on line 474 in src/server/Server.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make the type of this parameter a reference-to-const. The current type of "pkt" is "struct NetDisconnect &".

See more on https://sonarcloud.io/project/issues?id=ldominiq_ft_minecraft&issues=AZ5QIBB5qZzNMdwcMrOX&open=AZ5QIBB5qZzNMdwcMrOX&pullRequest=105
{
(void)pkt;
auto player = NetUtils::findPlayerByAddr(players, cliaddr);
if (player == players.end())
return ;
removePlayer(player);
}

void Server::removePlayer(std::vector<CPlayerInfo>::iterator player)
{
const auto &ent = std::find(world->livingEntities.begin(), world->livingEntities.end(), player->movement);
if (ent == world->livingEntities.end())
return ;
const bool hasEntity = ent != world->livingEntities.end();

for (CPlayerInfo &p : players)
if (hasEntity)
{
if (player->movement == p.movement) continue;
for (CPlayerInfo &p : players)
{
if (player->movement == p.movement) continue;

NetEntityMove pkt;
NetEntityMove pkt;

pkt.eEntityType = ent->get()->getEntityType();
pkt.entityID = ent->get()->getID();
pkt.type = -1;
pkt.eEntityType = ent->get()->getEntityType();
pkt.entityID = ent->get()->getID();
pkt.type = -1;
pkt.flags = pkt.flags | PacketFlags::Reliable;

//not really needed info
pkt.positionX = ent->get()->getPosition().x;
pkt.positionY = ent->get()->getPosition().y;
pkt.positionZ = ent->get()->getPosition().z;
//not really needed info
pkt.positionX = ent->get()->getPosition().x;
pkt.positionY = ent->get()->getPosition().y;
pkt.positionZ = ent->get()->getPosition().z;

pkt.yaw = ent->get()->yaw;
pkt.pitch = ent->get()->pitch;
pkt.yaw = ent->get()->yaw;
pkt.pitch = ent->get()->pitch;

pkt.entityName = ent->get()->getName();
pkt.entityName = ent->get()->getName();

sendPacketTo(pkt, p.addr);
sendPacketTo(pkt, p.addr);
}
}

// Push back to inventory items in crafting station and hand to prevent lose
Expand Down Expand Up @@ -533,11 +548,39 @@
messages.push_back(player->movement->getName() + " left the game.");

// Erase rather than clear: ids are never reused, so the entry stays dead.
// Always drop the player from players/PlayerKnownChunks even if the
// living-entity lookup failed, otherwise timeoutSilentClients() would
// keep re-timing-out the same stale entry.
world->PlayerKnownChunks.erase(player->id);
world->livingEntities.erase(ent);
if (hasEntity)
world->livingEntities.erase(ent);
players.erase(player);
}

void Server::timeoutSilentClients()
{
// A connected client streams NetPlayerInputs every tick (~20/s), so any gap
// this long means it crashed or its NetDisconnect was dropped on exit.
constexpr auto CLIENT_TIMEOUT = std::chrono::seconds(10);

for (auto it = players.begin(); it != players.end();)
{
if (currTick - it->lastSeenAt > CLIENT_TIMEOUT)
{
std::cout << "[Server] Client '" << it->movement->getName()
<< "' timed out (no packets for "
<< std::chrono::duration_cast<std::chrono::seconds>(CLIENT_TIMEOUT).count()
<< "s), removing.\n";

size_t idx = static_cast<size_t>(it - players.begin());

Check warning on line 575 in src/server/Server.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace the redundant type with "auto".

See more on https://sonarcloud.io/project/issues?id=ldominiq_ft_minecraft&issues=AZ5QIBB5qZzNMdwcMrOY&open=AZ5QIBB5qZzNMdwcMrOY&pullRequest=105
removePlayer(it);
it = players.begin() + idx;
}
else
++it;
}
}

void Server::receivePlayerInputs(NetPlayerInputs &pkt, const sockaddr_in &cliaddr)
{
auto player = NetUtils::findPlayerByAddr(players, cliaddr);
Expand Down Expand Up @@ -988,6 +1031,7 @@
pkt.eEntityType = e->getEntityType();
pkt.entityID = e->getID();
pkt.type = -1;
pkt.flags = pkt.flags | PacketFlags::Reliable;
pkt.positionX = e->getPositionD().x;
pkt.positionY = e->getPositionD().y;
pkt.positionZ = e->getPositionD().z;
Expand Down Expand Up @@ -1021,6 +1065,7 @@
ent->onDeath(*world); // respawn now after animation window
ent->deathBroadcast = false; // reset for potential respawn
ent->diedByExplosion = false;
world->updateRegionStreaming(players);
}
else {
le = world->livingEntities.erase(le);
Expand All @@ -1045,6 +1090,7 @@
pkt.eEntityType = ent->getEntityType();
pkt.entityID = ent->getID();
pkt.type = static_cast<uint16_t>(-1);
pkt.flags = pkt.flags | PacketFlags::Reliable;
pkt.positionX = ent->getPositionD().x;
pkt.positionY = ent->getPositionD().y;
pkt.positionZ = ent->getPositionD().z;
Expand Down
Loading