mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-17 13:57:05 +02:00
Server: remove players who have been away too long
Server: remove players who have been away too long A dedicated server can remove players who are away from their game. - "afk_kick_minutes" in the config's "players" section: 1 to 1440, or 0 (the default) for never. "afk-kick <minutes>|off" from the console or an admin; a change is saved and applies at once. - Away is doing nothing a player at their game does: not moving or turning, not speaking, not sending chat, and not placing, moving or removing an object. - A minute before the limit the player is told in chat; at the limit they are removed with a message saying why and that they can join again. The log has an "[afk]" line. - Admins are never removed for it. The time starts once a player's game has loaded the map, and starts over after a map change and when the setting is changed.
This commit is contained in:
1 parent
9ab985e778
commit
46cf65df0a
7 files changed
+80
-2
No files matched your search
+34
-1
@@ -763,6 +763,7 @@ bool Host::accept_data(Guest &source, const Packet &p) {
|
||||
if (!source.moved_at || moved > 0.05f * 0.05f || std::abs(facing) < 0.9995f) {
|
||||
source.still_at = root;
|
||||
source.moved_at = now_;
|
||||
active(source);
|
||||
}
|
||||
}
|
||||
return check_speed(source, p.time_us); // last: a speed-check kick frees `source`
|
||||
@@ -890,7 +891,10 @@ void Host::receive(std::uint64_t peer, std::span<const std::uint8_t> bytes, std:
|
||||
log_("[map] " + guest_name(*link) + " finished loading (" + std::to_string((now_ - since) / 1000000) + " s)");
|
||||
link->world_ready = p.world_ready;
|
||||
if (p.world_ready) link->travel_since = link->loading_since = 0;
|
||||
if (arrived) meet_later(*link);
|
||||
if (arrived) {
|
||||
meet_later(*link);
|
||||
active(*link); // the time away starts once they are in
|
||||
}
|
||||
return;
|
||||
}
|
||||
case PacketKind::map_request: {
|
||||
@@ -1007,6 +1011,7 @@ void Host::receive(std::uint64_t peer, std::span<const std::uint8_t> bytes, std:
|
||||
// A listen host's; the server's physics are the game's own.
|
||||
if (p.kind == PacketKind::physics_tuning || p.kind == PacketKind::physics_extras) return;
|
||||
if (p.kind == PacketKind::chat) {
|
||||
active(*link);
|
||||
if (!routed_source(p, link->member, peer, true, id_) ||
|
||||
link->chat_rate.accept(now_, p.text, 1) != ChatRate::Verdict::accepted)
|
||||
return;
|
||||
@@ -1062,8 +1067,10 @@ void Host::receive(std::uint64_t peer, std::span<const std::uint8_t> bytes, std:
|
||||
if (!routed_source(p, link->member, peer, true, id_)) return;
|
||||
if (p.kind == PacketKind::away) return drop(peer, "A player ended their session.");
|
||||
if (p.kind == PacketKind::objects) {
|
||||
const auto before = link->objects.revision();
|
||||
if (link->objects.receive(p.objects) == ObjectState::Result::invalid)
|
||||
return drop(peer, "Invalid shared object revision or layout.");
|
||||
if (link->objects.revision() != before) active(*link);
|
||||
link->last_packet = now_;
|
||||
return;
|
||||
}
|
||||
@@ -1074,6 +1081,7 @@ void Host::receive(std::uint64_t peer, std::span<const std::uint8_t> bytes, std:
|
||||
link->received_voice = true;
|
||||
link->voice_sequence = p.sequence;
|
||||
link->last_packet = now_;
|
||||
active(*link);
|
||||
broadcast(p, false, true, p.source);
|
||||
return;
|
||||
}
|
||||
@@ -1100,6 +1108,30 @@ void Host::receive_cosmetics() {
|
||||
}
|
||||
}
|
||||
|
||||
// Players who have been away longer than the server allows ("afk_kick_minutes") are removed,
|
||||
// with a warning a minute before. Away is doing nothing a player at their game does: not
|
||||
// moving, speaking, typing in chat or changing their objects. Admins stay, and so does anyone
|
||||
// whose game is still loading the map.
|
||||
void Host::remove_away() {
|
||||
if (!config_.afk_kick) return;
|
||||
const auto limit = static_cast<std::uint64_t>(config_.afk_kick) * 60000000;
|
||||
std::vector<std::uint64_t> away;
|
||||
for (auto &[id, guest] : guests_) {
|
||||
auto &g = *guest;
|
||||
if (!g.handshaken || !g.world_ready || !g.active_at || is_admin(id)) continue;
|
||||
const auto idle = now_ - g.active_at;
|
||||
if (idle >= limit) away.push_back(id);
|
||||
else if (!g.away_warned && limit > 60000000 && idle >= limit - 60000000) {
|
||||
g.away_warned = true;
|
||||
reply(g, "You have been away a while: move or say something within a minute to stay on the server.");
|
||||
}
|
||||
}
|
||||
for (const auto id : away) {
|
||||
if (const auto *g = find(id)) log_("[afk] " + guest_name(*g) + " was removed after " + std::to_string(config_.afk_kick) + " min away.");
|
||||
drop(id, "You were removed from the server for being away too long. You can join again.");
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Objects ---------------------------------------------------------------------------------
|
||||
void Host::sync_objects() {
|
||||
if (now_ < next_object_update_) return;
|
||||
@@ -1519,6 +1551,7 @@ void Host::tick(std::uint64_t now) {
|
||||
roster_dirty_ = true;
|
||||
}
|
||||
tick_rotation();
|
||||
remove_away();
|
||||
std::erase_if(vote_cooldowns_, [&](const auto &entry) { return now_ >= entry.second; });
|
||||
join_backoff_.prune(now_);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user