The blockSpectators global is redundant.
See https://gitlab.com/xonotic/xonotic-data.pk3dir/-/merge_requests/1289
Players are now given the grace period and SPECTATE_WARNING when
sv_spectate is disabled during a game, as well as when `nospectators` is
voted.
Centreprints are added and displayed when they don't conflict with join
restriction centreprints.
seta notification_CENTER_SEQUENCE_COMPLETED "1" "0 = off, 1 = centerprint"
seta notification_CENTER_SEQUENCE_COUNTER "1" "0 = off, 1 = centerprint"
seta notification_CENTER_SEQUENCE_COUNTER_FEWMORE "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_SPECTATE_NOTALLOWED "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_SPECTATE_WARNING "1" "0 = off, 1 = centerprint"
seta notification_CENTER_SUPERWEAPON_BROKEN "1" "0 = off, 1 = centerprint"
seta notification_CENTER_SUPERWEAPON_LOST "1" "0 = off, 1 = centerprint"
seta notification_CENTER_SUPERWEAPON_PICKUP "1" "0 = off, 1 = centerprint"
MSG_CENTER_NOTIF(SEQUENCE_COUNTER, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^BGThere are more to go..."), "")
MSG_CENTER_NOTIF(SEQUENCE_COUNTER_FEWMORE, N_ENABLE, 0, 1, "f1", CPID_Null, "0 0", _("^BGOnly %s^BG more to go..."), "")
+ MSG_CENTER_NOTIF(SPECTATE_WARNING, N_ENABLE, 0, 1, "f1secs", CPID_PREVENT_JOIN, "0 0", _("^F2You have to become a player within the next %s, otherwise you will be kicked, because spectating isn't allowed at this time!"), "") // same string as INFO_SPECTATE_WARNING
+ MSG_CENTER_NOTIF(SPECTATE_NOTALLOWED, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^F2Spectating isn't allowed at this time!"), "")
+
MSG_CENTER_NOTIF(SUPERWEAPON_BROKEN, N_ENABLE, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have broken down"), "")
MSG_CENTER_NOTIF(SUPERWEAPON_LOST, N_ENABLE, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have been lost"), "")
MSG_CENTER_NOTIF(SUPERWEAPON_PICKUP, N_ENABLE, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You now have a superweapon"), "")
bot_relinkplayerlist();
CS(this).spectatortime = time;
- if (blockSpectators)
- {
+ if (!autocvar_sv_spectate)
+ // no centreprint here: player forced to join, or informed of why they can't via centreprint
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
- }
CS(this).jointime = time;
anticheat_prethink(this);
// Check if spectating is allowed
- if (!autocvar_sv_spectate) blockSpectators = 1;
-
- if (blockSpectators && IS_REAL_CLIENT(this)
- && (IS_SPEC(this) || IS_OBSERVER(this)) && !INGAME(this)
- && time > (CS(this).spectatortime + autocvar_g_maxplayers_spectator_blocktime))
+ if (!autocvar_sv_spectate && IS_REAL_CLIENT(this)
+ && (IS_SPEC(this) || IS_OBSERVER(this)) && !INGAME(this))
{
- if (dropclient_schedule(this))
- Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
+ float cutoff = CS(this).spectatortime + autocvar_g_maxplayers_spectator_blocktime;
+ if (time > cutoff + MIN_SPEC_TIME * 0.5)
+ {
+ // sv_spectate was disabled recently (or the server was stalled far too long)
+ CS(this).spectatortime = time; // reset the grace period
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
+ }
+ else if (time > cutoff)
+ if (dropclient_schedule(this))
+ Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
}
// Check for nameless players
string autocvar_sv_quickmenu_file;
bool autocvar_sv_servermodelsonly;
bool autocvar_sv_showspectators;
-int autocvar_sv_spectate;
+bool autocvar_sv_spectate;
bool autocvar_sv_teamnagger;
float autocvar_sv_player_scale;
const int RESPAWN_SILENT = BIT(1);
const int RESPAWN_DENY = BIT(2);
-float blockSpectators; // if set, new or existing spectators or observers will be removed unless they become a player within g_maxplayers_spectator_blocktime seconds
.float spectatortime; // point in time since the client is spectating or observing
.bool player_blocked;
}
else if (this.killindicator_teamchange == -2)
{
- if (blockSpectators)
+ if (!autocvar_sv_spectate)
+ // shouldn't get here because of condition in ClientCommand_spectate()
Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
if (this.wants_join)
if (mutator_returnvalue == MUT_SPECCMD_RETURN) return;
if ((IS_PLAYER(caller) || mutator_returnvalue == MUT_SPECCMD_FORCE || caller.wants_join))
- if (autocvar_sv_spectate == 1)
+ if (autocvar_sv_spectate)
ClientKill_TeamChange(caller, -2); // observe
+ else
+ Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_SPECTATE_NOTALLOWED);
}
return; // never fall through to usage
}
LOG_HELPF("This command works only when the server is running.");
return;
}
- blockSpectators = 1;
- // give every spectator <g_maxplayers_spectator_blocktime> seconds time to become a player
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && (IS_SPEC(it) || IS_OBSERVER(it)) && !INGAME(it), {
- CS(it).spectatortime = time;
- Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
- });
- bprint(strcat("^7All spectators will be automatically kicked when not joining the game after ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds!\n"));
+ cvar_settemp("sv_spectate", "0");
+ // if sv_spectate was enabled PlayerFrame() sends SPECTATE_WARNING notifications
return;
}
{
LOG_HELP("Usage:^3 sv_cmd nospectators");
LOG_HELP(" No arguments required.");
+ LOG_HELP("Temporarily disables the ^3sv_spectate ^7cvar.");
return;
}
}
set teamplay_lockonrestart 0 "lock teams once all players readied up and the game restarted (no new players can join after restart unless using the server-command unlockteams)"
set g_maxplayers 0 "maximum number of players allowed to play at the same time, 0 means unlimited, -1 uses the map setting or unlimited if not set (rounded to multiple of team number)"
-set g_maxplayers_spectator_blocktime 5 "if the players voted for the \"nospectators\" command, this setting defines the number of seconds a observer/spectator has time to join the game before they get kicked"
+set g_maxplayers_spectator_blocktime 5 "if sv_spectate is disabled, such as by voting for \"nospectators\", this setting defines the number of seconds an observer/spectator has to join the game before they get kicked"
// tournament mod
set g_warmup 0 "splits the game into warmup and match stages, 1 means the match starts when g_warmup_majority_factor of players are ready OR g_warmup_limit is hit, >1 also requires at least g_warmup players (including bots) to join, -1 means that minimum player requrement is set by the map (lower bound of 2 or 2 per team)"
set sv_spectator_speed_multiplier 1.5 "base movement speed factor of spectators, all movement settings scale off this"
set sv_spectator_speed_multiplier_min 1 "minimum movement speed factor for spectators as determined by scrolling"
set sv_spectator_speed_multiplier_max 5 "maximum movement speed factor for spectators as determined by scrolling"
-set sv_spectate 1 "if set to 1, new clients are allowed to spectate or observe the game, if set to 0 joining clients spawn as players immediately (no spectating)"
+set sv_spectate 1 "if set to 1 clients are allowed to spectate or observe the game, if set to 0 clients spawn as players immediately or are kicked after g_maxplayers_spectator_blocktime if that's not possible (incompatible with spec-based features such as sv_maxidle_playertospectator and g_balance_teams_queue)"
set sv_defaultcharacter 0 "master switch, if set to 1 the further configuration for replacing all player models, skins and colors is taken from the sv_defaultplayermodel, sv_defaultplayerskin and sv_defaultplayercolors variables"
set sv_defaultcharacterskin 0 "if set to 1 the further configuration for replacing all skins is taken from the sv_defaultplayerskin variables"
set sv_defaultplayermodel "models/player/erebus.iqm" "default model selection, only works if sv_defaultcharacter is set to 1; you may append a :<skinnumber> suffix to model names; you can specify multiple, separated by space, and a random one will be chosen"