2001-02-19 21:15:25 +00:00
|
|
|
/*
|
|
|
|
sv_user.c
|
|
|
|
|
|
|
|
server code for moving users
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
2002-07-31 05:19:03 +00:00
|
|
|
#include "QF/cbuf.h"
|
2002-07-31 22:13:15 +00:00
|
|
|
#include "QF/idparse.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/checksum.h"
|
2001-07-30 04:33:59 +00:00
|
|
|
#include "QF/clip_hull.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/cmd.h"
|
|
|
|
#include "QF/cvar.h"
|
2002-07-31 05:19:03 +00:00
|
|
|
#include "QF/dstring.h"
|
2002-07-05 06:43:47 +00:00
|
|
|
#include "QF/hash.h"
|
2001-03-27 20:33:07 +00:00
|
|
|
#include "QF/msg.h"
|
2002-08-27 07:16:28 +00:00
|
|
|
#include "QF/quakefs.h"
|
2001-05-30 04:34:06 +00:00
|
|
|
#include "QF/sys.h"
|
|
|
|
#include "QF/va.h"
|
2001-07-30 04:33:59 +00:00
|
|
|
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "compat.h"
|
|
|
|
|
2005-05-05 07:31:31 +00:00
|
|
|
#include "qw/msg_ucmd.h"
|
2004-02-21 05:09:02 +00:00
|
|
|
#include "qw/msg_ucmd.h"
|
|
|
|
|
2005-05-08 08:04:50 +00:00
|
|
|
#include "qw/bothdefs.h"
|
2005-05-02 04:09:15 +00:00
|
|
|
#include "qw/pmove.h"
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "qw/include/server.h"
|
|
|
|
#include "qw/include/sv_gib.h"
|
|
|
|
#include "qw/include/sv_progs.h"
|
|
|
|
#include "qw/include/sv_recorder.h"
|
2001-02-19 21:15:25 +00:00
|
|
|
#include "world.h"
|
|
|
|
|
2002-07-05 06:43:47 +00:00
|
|
|
typedef struct ucmd_s {
|
|
|
|
const char *name;
|
2003-04-28 15:56:09 +00:00
|
|
|
void (*func) (void *userdata);
|
2002-07-05 21:15:19 +00:00
|
|
|
unsigned no_redirect:1;
|
|
|
|
unsigned overridable:1;
|
|
|
|
unsigned freeable:1;
|
2003-04-28 15:56:09 +00:00
|
|
|
void *userdata;
|
|
|
|
void (*on_free) (void *userdata);
|
2002-07-05 06:43:47 +00:00
|
|
|
} ucmd_t;
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
edict_t *sv_player;
|
|
|
|
|
|
|
|
usercmd_t cmd;
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
int sv_maxrate;
|
|
|
|
static cvar_t sv_maxrate_cvar = {
|
|
|
|
.name = "sv_maxrate",
|
|
|
|
.description =
|
|
|
|
"Maximum allowable rate",
|
|
|
|
.default_value = "10000",
|
|
|
|
.flags = CVAR_SERVERINFO,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_maxrate },
|
|
|
|
};
|
|
|
|
// capped)
|
|
|
|
int sv_antilag;
|
|
|
|
static cvar_t sv_antilag_cvar = {
|
|
|
|
.name = "sv_antilag",
|
|
|
|
.description =
|
|
|
|
"Attempt to backdate impacts to compensate for lag. 0=completely off. "
|
|
|
|
"1=mod-controlled. 2=forced, which might break certain uses of "
|
|
|
|
"traceline.",
|
|
|
|
.default_value = "1",
|
|
|
|
.flags = CVAR_SERVERINFO,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_antilag },
|
|
|
|
};
|
|
|
|
float sv_antilag_frac;
|
|
|
|
static cvar_t sv_antilag_frac_cvar = {
|
|
|
|
.name = "sv_antilag_frac",
|
|
|
|
.description =
|
|
|
|
"FIXME something to do with sv_antilag",
|
|
|
|
.default_value = "1",
|
|
|
|
.flags = CVAR_SERVERINFO,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_antilag_frac },
|
|
|
|
};
|
2012-06-28 07:03:56 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
float sv_accelerate;
|
|
|
|
static cvar_t sv_accelerate_cvar = {
|
|
|
|
.name = "sv_accelerate",
|
|
|
|
.description =
|
|
|
|
"None",
|
|
|
|
.default_value = "10",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_accelerate },
|
|
|
|
};
|
|
|
|
float sv_airaccelerate;
|
|
|
|
static cvar_t sv_airaccelerate_cvar = {
|
|
|
|
.name = "sv_airaccelerate",
|
|
|
|
.description =
|
|
|
|
"Sets how quickly the players accelerate in air",
|
|
|
|
.default_value = "0.7",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_airaccelerate },
|
|
|
|
};
|
|
|
|
float sv_maxspeed;
|
|
|
|
static cvar_t sv_maxspeed_cvar = {
|
|
|
|
.name = "sv_maxspeed",
|
|
|
|
.description =
|
|
|
|
"None",
|
|
|
|
.default_value = "320",
|
|
|
|
.flags = CVAR_SERVERINFO,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_maxspeed },
|
|
|
|
};
|
|
|
|
float sv_spectatormaxspeed;
|
|
|
|
static cvar_t sv_spectatormaxspeed_cvar = {
|
|
|
|
.name = "sv_spectatormaxspeed",
|
|
|
|
.description =
|
|
|
|
"Sets the maximum speed a spectator can move",
|
|
|
|
.default_value = "500",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_spectatormaxspeed },
|
|
|
|
};
|
|
|
|
float sv_wateraccelerate;
|
|
|
|
static cvar_t sv_wateraccelerate_cvar = {
|
|
|
|
.name = "sv_wateraccelerate",
|
|
|
|
.description =
|
|
|
|
"Sets the water acceleration value",
|
|
|
|
.default_value = "10",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_wateraccelerate },
|
|
|
|
};
|
|
|
|
float sv_waterfriction;
|
|
|
|
static cvar_t sv_waterfriction_cvar = {
|
|
|
|
.name = "sv_waterfriction",
|
|
|
|
.description =
|
|
|
|
"Sets the water friction value",
|
|
|
|
.default_value = "4",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_waterfriction },
|
|
|
|
};
|
2011-12-22 04:42:39 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
int sv_allowfake;
|
|
|
|
static cvar_t sv_allowfake_cvar = {
|
|
|
|
.name = "sv_allowfake",
|
|
|
|
.description =
|
|
|
|
"Allow 'fake' messages (FuhQuake $\\). 1 = always, 2 = only say_team",
|
|
|
|
.default_value = "2",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_allowfake },
|
|
|
|
};
|
2004-04-27 03:45:26 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
float cl_rollspeed;
|
|
|
|
static cvar_t cl_rollspeed_cvar = {
|
|
|
|
.name = "cl_rollspeed",
|
|
|
|
.description =
|
|
|
|
"How quickly you straighten out after strafing",
|
|
|
|
.default_value = "200",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &cl_rollspeed },
|
|
|
|
};
|
|
|
|
float cl_rollangle;
|
|
|
|
static cvar_t cl_rollangle_cvar = {
|
|
|
|
.name = "cl_rollangle",
|
|
|
|
.description =
|
|
|
|
"How much your screen tilts when strafing",
|
|
|
|
.default_value = "2.0",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &cl_rollangle },
|
|
|
|
};
|
|
|
|
int sv_spectalk;
|
|
|
|
static cvar_t sv_spectalk_cvar = {
|
|
|
|
.name = "sv_spectalk",
|
|
|
|
.description =
|
|
|
|
"Toggles the ability of spectators to talk to players",
|
|
|
|
.default_value = "1",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_spectalk },
|
|
|
|
};
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
int sv_kickfake;
|
|
|
|
static cvar_t sv_kickfake_cvar = {
|
|
|
|
.name = "sv_kickfake",
|
|
|
|
.description =
|
|
|
|
"Kick users sending to send fake talk messages",
|
|
|
|
.default_value = "0",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_kickfake },
|
|
|
|
};
|
2002-08-22 23:04:44 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
int sv_mapcheck;
|
|
|
|
static cvar_t sv_mapcheck_cvar = {
|
|
|
|
.name = "sv_mapcheck",
|
|
|
|
.description =
|
|
|
|
"Toggle the use of map checksumming to check for players who edit maps"
|
|
|
|
" to cheat",
|
|
|
|
.default_value = "1",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_mapcheck },
|
|
|
|
};
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
int sv_timecheck_mode;
|
|
|
|
static cvar_t sv_timecheck_mode_cvar = {
|
|
|
|
.name = "sv_timecheck_mode",
|
|
|
|
.description =
|
|
|
|
"select between timekick (0, default) and timecheck (1)",
|
|
|
|
.default_value = "0",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_timecheck_mode },
|
|
|
|
};
|
|
|
|
int sv_timekick;
|
|
|
|
static cvar_t sv_timekick_cvar = {
|
|
|
|
.name = "sv_timekick",
|
|
|
|
.description =
|
|
|
|
"Time cheat protection",
|
|
|
|
.default_value = "3",
|
|
|
|
.flags = CVAR_SERVERINFO,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_timekick },
|
|
|
|
};
|
|
|
|
float sv_timekick_fuzz;
|
|
|
|
static cvar_t sv_timekick_fuzz_cvar = {
|
|
|
|
.name = "sv_timekick_fuzz",
|
|
|
|
.description =
|
|
|
|
"Time cheat \"fuzz factor\" in milliseconds",
|
|
|
|
.default_value = "30",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_timekick_fuzz },
|
|
|
|
};
|
|
|
|
float sv_timekick_interval;
|
|
|
|
static cvar_t sv_timekick_interval_cvar = {
|
|
|
|
.name = "sv_timekick_interval",
|
|
|
|
.description =
|
|
|
|
"Time cheat check interval in seconds",
|
|
|
|
.default_value = "30",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_float, .value = &sv_timekick_interval },
|
|
|
|
};
|
|
|
|
int sv_timecheck_fuzz;
|
|
|
|
static cvar_t sv_timecheck_fuzz_cvar = {
|
|
|
|
.name = "sv_timecheck_fuzz",
|
|
|
|
.description =
|
|
|
|
"Milliseconds of tolerance before time cheat throttling kicks in.",
|
|
|
|
.default_value = "250",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_timecheck_fuzz },
|
|
|
|
};
|
|
|
|
int sv_timecheck_decay;
|
|
|
|
static cvar_t sv_timecheck_decay_cvar = {
|
|
|
|
.name = "sv_timecheck_decay",
|
|
|
|
.description =
|
|
|
|
"Rate at which time inaccuracies are \"forgiven\".",
|
|
|
|
.default_value = "2",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = &cexpr_int, .value = &sv_timecheck_decay },
|
|
|
|
};
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
char *sv_http_url_base;
|
|
|
|
static cvar_t sv_http_url_base_cvar = {
|
|
|
|
.name = "sv_http_url_base",
|
|
|
|
.description =
|
|
|
|
"set to base url for http redirects of downloaded files",
|
|
|
|
.default_value = "",
|
|
|
|
.flags = CVAR_NONE,
|
|
|
|
.value = { .type = 0, .value = &sv_http_url_base },
|
|
|
|
};
|
2007-03-20 14:37:50 +00:00
|
|
|
|
2021-03-27 10:52:59 +00:00
|
|
|
static void OutofBandPrintf (netadr_t where, const char *fmt, ...) __attribute__ ((format (PRINTF, 2, 3)));
|
2003-05-07 04:24:50 +00:00
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
// USER STRINGCMD EXECUTION host_client and sv_player will be valid.
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2005-05-02 04:09:15 +00:00
|
|
|
void
|
|
|
|
SV_WriteWorldVars (netchan_t *netchan)
|
|
|
|
{
|
|
|
|
|
|
|
|
// send full levelname
|
|
|
|
MSG_WriteString (&netchan->message,
|
|
|
|
PR_GetString (&sv_pr_state,
|
|
|
|
SVstring (sv.edicts, message)));
|
|
|
|
|
|
|
|
// send the movevars
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.gravity);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.stopspeed);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.maxspeed);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.spectatormaxspeed);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.accelerate);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.airaccelerate);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.wateraccelerate);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.friction);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.waterfriction);
|
|
|
|
MSG_WriteFloat (&netchan->message, movevars.entgravity);
|
|
|
|
|
|
|
|
// send music
|
|
|
|
MSG_WriteByte (&netchan->message, svc_cdtrack);
|
|
|
|
MSG_WriteByte (&netchan->message, SVfloat (sv.edicts, sounds));
|
|
|
|
|
|
|
|
// send server info string
|
|
|
|
MSG_WriteByte (&netchan->message, svc_stufftext);
|
|
|
|
MSG_WriteString (&netchan->message,
|
2021-01-31 07:01:20 +00:00
|
|
|
va (0, "fullserverinfo \"%s\"\n",
|
2005-05-02 04:09:15 +00:00
|
|
|
Info_MakeString (svs.info, 0)));
|
|
|
|
}
|
|
|
|
|
2010-01-13 06:48:54 +00:00
|
|
|
/*
|
|
|
|
SV_New_f
|
|
|
|
|
|
|
|
Sends the first message from the server to a connected client.
|
|
|
|
This will be sent on the initial connection and upon each server load.
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_New_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-11-07 08:24:56 +00:00
|
|
|
int playernum;
|
2005-05-02 04:09:15 +00:00
|
|
|
const char *gamedir;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->state == cs_spawned)
|
|
|
|
return;
|
2004-02-22 01:32:55 +00:00
|
|
|
|
2005-05-02 04:09:15 +00:00
|
|
|
gamedir = Info_ValueForKey (svs.info, "*gamedir");
|
|
|
|
if (!gamedir[0])
|
|
|
|
gamedir = "qw";
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->state = cs_connected;
|
|
|
|
host_client->connection_started = realtime;
|
|
|
|
|
|
|
|
// send the info about the new client to all connected clients
|
|
|
|
|
2004-02-22 05:40:08 +00:00
|
|
|
// NOTE: This doesn't go through MSG_ReliableWrite since it's before the
|
2002-08-22 23:04:44 +00:00
|
|
|
// user spawns. These functions are written to not overflow
|
2004-02-22 05:40:08 +00:00
|
|
|
if (host_client->backbuf.num_backbuf) {
|
2010-01-13 06:48:54 +00:00
|
|
|
SV_Printf ("WARNING %s: [SV_New] Back buffered (%d), clearing\n",
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->name, host_client->netchan.message.cursize);
|
2004-02-22 05:40:08 +00:00
|
|
|
host_client->backbuf.num_backbuf = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
SZ_Clear (&host_client->netchan.message);
|
|
|
|
}
|
2005-05-02 04:09:15 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
// send the serverdata
|
|
|
|
MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
|
2001-11-07 08:24:56 +00:00
|
|
|
MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
|
|
|
|
MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
|
|
|
|
MSG_WriteString (&host_client->netchan.message, gamedir);
|
|
|
|
|
|
|
|
playernum = NUM_FOR_EDICT (&sv_pr_state, host_client->edict) - 1;
|
|
|
|
if (host_client->spectator)
|
|
|
|
playernum |= 128;
|
|
|
|
MSG_WriteByte (&host_client->netchan.message, playernum);
|
|
|
|
|
2005-05-02 04:09:15 +00:00
|
|
|
SV_WriteWorldVars (&host_client->netchan);
|
2003-02-28 05:09:46 +00:00
|
|
|
|
|
|
|
// Trigger GIB connection event
|
|
|
|
if (sv_client_connect_e->func)
|
2010-01-13 06:48:54 +00:00
|
|
|
GIB_Event_Callback (sv_client_connect_e, 1,
|
2021-01-31 07:01:20 +00:00
|
|
|
va (0, "%u", host_client->userid));
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2005-05-02 09:00:17 +00:00
|
|
|
void
|
|
|
|
SV_WriteSoundlist (netchan_t *netchan, int n)
|
|
|
|
{
|
|
|
|
const char **s;
|
|
|
|
|
2005-05-05 07:31:31 +00:00
|
|
|
MSG_WriteByte (&netchan->message, svc_soundlist);
|
2005-05-02 09:00:17 +00:00
|
|
|
MSG_WriteByte (&netchan->message, n);
|
|
|
|
for (s = sv.sound_precache + 1 + n;
|
|
|
|
*s && netchan->message.cursize < (MAX_MSGLEN / 2);
|
|
|
|
s++, n++)
|
|
|
|
MSG_WriteString (&netchan->message, *s);
|
|
|
|
|
|
|
|
MSG_WriteByte (&netchan->message, 0);
|
|
|
|
|
|
|
|
// next msg
|
|
|
|
if (*s)
|
|
|
|
MSG_WriteByte (&netchan->message, n);
|
|
|
|
else
|
|
|
|
MSG_WriteByte (&netchan->message, 0);
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Soundlist_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-11-07 08:24:56 +00:00
|
|
|
unsigned n;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->state != cs_connected) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("soundlist not valid -- already spawned\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// handle the case of a level changing while a client was connecting
|
|
|
|
if (atoi (Cmd_Argv (1)) != svs.spawncount) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Soundlist_f from different level\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-11-07 08:24:56 +00:00
|
|
|
n = atoi (Cmd_Argv (2));
|
|
|
|
if (n >= MAX_SOUNDS) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Soundlist_f: Invalid soundlist index\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-02-22 05:40:08 +00:00
|
|
|
// NOTE: This doesn't go through MSG_ReliableWrite since it's before the
|
2002-08-22 23:04:44 +00:00
|
|
|
// user spawns. These functions are written to not overflow
|
2004-02-22 05:40:08 +00:00
|
|
|
if (host_client->backbuf.num_backbuf) {
|
2005-05-08 00:47:37 +00:00
|
|
|
SV_Printf ("WARNING %s: [SV_Soundlist] Back buffered (%d), clearing",
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->name, host_client->netchan.message.cursize);
|
2004-02-22 05:40:08 +00:00
|
|
|
host_client->backbuf.num_backbuf = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
SZ_Clear (&host_client->netchan.message);
|
|
|
|
}
|
|
|
|
|
2005-05-02 09:00:17 +00:00
|
|
|
SV_WriteSoundlist (&host_client->netchan, n);
|
|
|
|
}
|
2001-11-07 08:24:56 +00:00
|
|
|
|
2005-05-02 09:00:17 +00:00
|
|
|
void
|
|
|
|
SV_WriteModellist (netchan_t *netchan, int n)
|
|
|
|
{
|
|
|
|
const char **s;
|
|
|
|
|
2005-05-05 07:31:31 +00:00
|
|
|
MSG_WriteByte (&netchan->message, svc_modellist);
|
2005-05-02 09:00:17 +00:00
|
|
|
MSG_WriteByte (&netchan->message, n);
|
|
|
|
for (s = sv.model_precache + 1 + n;
|
|
|
|
*s && netchan->message.cursize < (MAX_MSGLEN / 2);
|
|
|
|
s++, n++)
|
|
|
|
MSG_WriteString (&netchan->message, *s);
|
|
|
|
MSG_WriteByte (&netchan->message, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// next msg
|
|
|
|
if (*s)
|
2005-05-02 09:00:17 +00:00
|
|
|
MSG_WriteByte (&netchan->message, n);
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
2005-05-02 09:00:17 +00:00
|
|
|
MSG_WriteByte (&netchan->message, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Modellist_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-11-07 08:24:56 +00:00
|
|
|
unsigned n;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->state != cs_connected) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("modellist not valid -- already spawned\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// handle the case of a level changing while a client was connecting
|
|
|
|
if (atoi (Cmd_Argv (1)) != svs.spawncount) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Modellist_f from different level\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-11-07 08:24:56 +00:00
|
|
|
n = atoi (Cmd_Argv (2));
|
|
|
|
if (n >= MAX_MODELS) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Modellist_f: Invalid modellist index\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-02-22 05:40:08 +00:00
|
|
|
// NOTE: This doesn't go through MSG_ReliableWrite since it's before the
|
2002-08-22 23:04:44 +00:00
|
|
|
// user spawns. These functions are written to not overflow
|
2004-02-22 05:40:08 +00:00
|
|
|
if (host_client->backbuf.num_backbuf) {
|
2001-11-07 08:24:56 +00:00
|
|
|
SV_Printf ("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing",
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->name, host_client->netchan.message.cursize);
|
2004-02-22 05:40:08 +00:00
|
|
|
host_client->backbuf.num_backbuf = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
SZ_Clear (&host_client->netchan.message);
|
|
|
|
}
|
|
|
|
|
2005-05-02 09:00:17 +00:00
|
|
|
SV_WriteModellist (&host_client->netchan, n);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_PreSpawn_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2021-03-29 08:24:30 +00:00
|
|
|
const char *command;
|
|
|
|
int buf, size;
|
|
|
|
unsigned check;
|
2002-08-22 23:04:44 +00:00
|
|
|
sizebuf_t *msg;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->state != cs_connected) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("prespawn not valid -- already spawned\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// handle the case of a level changing while a client was connecting
|
|
|
|
if (atoi (Cmd_Argv (1)) != svs.spawncount) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_PreSpawn_f from different level\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = atoi (Cmd_Argv (2));
|
|
|
|
if (buf >= sv.num_signon_buffers)
|
|
|
|
buf = 0;
|
|
|
|
|
|
|
|
if (!buf) {
|
|
|
|
// should be three numbers following containing checksums
|
|
|
|
check = atoi (Cmd_Argv (3));
|
|
|
|
|
2021-03-29 10:58:00 +00:00
|
|
|
// Sys_MaskPrintf (SYS_dev, , "Client check = %d\n", check);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (sv_mapcheck && check != sv.worldmodel->brush.checksum &&
|
2021-02-01 10:31:11 +00:00
|
|
|
check != sv.worldmodel->brush.checksum2) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Map model file does "
|
2002-08-22 23:04:44 +00:00
|
|
|
"not match (%s), %i != %i/%i.\n"
|
|
|
|
"You may need a new version of the map, or the "
|
|
|
|
"proper install files.\n",
|
2021-02-01 10:31:11 +00:00
|
|
|
sv.modelname, check,
|
|
|
|
sv.worldmodel->brush.checksum,
|
|
|
|
sv.worldmodel->brush.checksum2);
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_DropClient (host_client);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-08-01 00:38:16 +00:00
|
|
|
host_client->prespawned = true;
|
|
|
|
|
2001-07-22 18:44:55 +00:00
|
|
|
if (buf == sv.num_signon_buffers - 1)
|
2021-01-31 07:01:20 +00:00
|
|
|
command = va (0, "cmd spawn %i 0\n", svs.spawncount);
|
2001-07-22 06:55:09 +00:00
|
|
|
else
|
2021-01-31 07:01:20 +00:00
|
|
|
command = va (0, "cmd prespawn %i %i\n", svs.spawncount, buf + 1);
|
2001-07-22 06:55:09 +00:00
|
|
|
|
2003-03-21 21:25:44 +00:00
|
|
|
size = sv.signon_buffer_size[buf] + 1 + strlen (command) + 1;
|
2001-07-22 06:55:09 +00:00
|
|
|
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableCheckBlock (&host_client->backbuf, size);
|
|
|
|
if (host_client->backbuf.num_backbuf)
|
|
|
|
msg = &host_client->backbuf.backbuf;
|
2001-07-22 06:55:09 +00:00
|
|
|
else
|
|
|
|
msg = &host_client->netchan.message;
|
|
|
|
|
|
|
|
SZ_Write (msg, sv.signon_buffers[buf], sv.signon_buffer_size[buf]);
|
|
|
|
|
|
|
|
MSG_WriteByte (msg, svc_stufftext);
|
|
|
|
MSG_WriteString (msg, command);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2003-08-21 03:50:30 +00:00
|
|
|
void
|
|
|
|
SV_Spawn (client_t *client)
|
|
|
|
{
|
|
|
|
edict_t *ent;
|
|
|
|
|
|
|
|
// set up the edict
|
|
|
|
ent = client->edict;
|
|
|
|
|
2013-01-17 05:11:54 +00:00
|
|
|
memset (&E_fld (ent, 0), 0, sv_pr_state.progs->entityfields * 4);
|
2003-08-21 03:50:30 +00:00
|
|
|
SVfloat (ent, colormap) = NUM_FOR_EDICT (&sv_pr_state, ent);
|
|
|
|
SVfloat (ent, team) = 0; // FIXME
|
2005-05-07 10:46:19 +00:00
|
|
|
SVstring (ent, netname) = PR_SetString (&sv_pr_state, client->name);
|
2003-08-21 03:50:30 +00:00
|
|
|
|
2005-05-07 10:46:19 +00:00
|
|
|
client->entgravity = 1.0;
|
2003-08-21 03:50:30 +00:00
|
|
|
if (sv_fields.gravity != -1)
|
|
|
|
SVfloat (ent, gravity) = 1.0;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
client->maxspeed = sv_maxspeed;
|
2003-08-21 03:50:30 +00:00
|
|
|
if (sv_fields.maxspeed != -1)
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
SVfloat (ent, maxspeed) = sv_maxspeed;
|
2003-08-21 03:50:30 +00:00
|
|
|
}
|
|
|
|
|
2005-05-05 07:31:31 +00:00
|
|
|
void
|
|
|
|
SV_WriteSpawn1 (backbuf_t *backbuf, int n)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
client_t *client;
|
|
|
|
|
|
|
|
// normally this could overflow, but no need to check due to backbuf
|
|
|
|
for (i = n, client = svs.clients + n; i < MAX_CLIENTS; i++, client++)
|
|
|
|
SV_FullClientUpdateToClient (client, backbuf);
|
|
|
|
|
|
|
|
// send all current light styles
|
|
|
|
for (i = 0; i < MAX_LIGHTSTYLES; i++) {
|
|
|
|
MSG_ReliableWrite_Begin (backbuf, svc_lightstyle,
|
|
|
|
3 + (sv.lightstyles[i] ?
|
|
|
|
strlen (sv.lightstyles[i]) : 1));
|
|
|
|
MSG_ReliableWrite_Byte (backbuf, (char) i);
|
|
|
|
MSG_ReliableWrite_String (backbuf, sv.lightstyles[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SV_WriteSpawn2 (backbuf_t *backbuf)
|
|
|
|
{
|
|
|
|
|
|
|
|
MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6);
|
|
|
|
MSG_ReliableWrite_Byte (backbuf, STAT_TOTALSECRETS);
|
|
|
|
MSG_ReliableWrite_Long (backbuf, *sv_globals.total_secrets);
|
|
|
|
|
|
|
|
MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6);
|
|
|
|
MSG_ReliableWrite_Byte (backbuf, STAT_TOTALMONSTERS);
|
|
|
|
MSG_ReliableWrite_Long (backbuf, *sv_globals.total_monsters);
|
|
|
|
|
|
|
|
MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6);
|
|
|
|
MSG_ReliableWrite_Byte (backbuf, STAT_SECRETS);
|
|
|
|
MSG_ReliableWrite_Long (backbuf, *sv_globals.found_secrets);
|
|
|
|
|
|
|
|
MSG_ReliableWrite_Begin (backbuf, svc_updatestatlong, 6);
|
|
|
|
MSG_ReliableWrite_Byte (backbuf, STAT_MONSTERS);
|
|
|
|
MSG_ReliableWrite_Long (backbuf, *sv_globals.killed_monsters);
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Spawn_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2005-05-05 07:31:31 +00:00
|
|
|
int n;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->state != cs_connected) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("Spawn not valid -- already spawned\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// handle the case of a level changing while a client was connecting
|
|
|
|
if (atoi (Cmd_Argv (1)) != svs.spawncount) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Spawn_f from different level\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-08-01 00:38:16 +00:00
|
|
|
// make sure they're not trying to cheat by spawning without prespawning
|
|
|
|
if (host_client->prespawned == false) {
|
2002-08-22 23:04:44 +00:00
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s has been kicked for trying to "
|
|
|
|
"spawn before prespawning!\n", host_client->name);
|
2001-08-01 00:38:16 +00:00
|
|
|
SV_DropClient (host_client);
|
|
|
|
return;
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
n = atoi (Cmd_Argv (2));
|
|
|
|
|
|
|
|
// make sure n is valid
|
|
|
|
if (n < 0 || n > MAX_CLIENTS) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Spawn_f invalid client start\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-08-01 00:38:16 +00:00
|
|
|
|
|
|
|
host_client->spawned = true;
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
// send all current names, colors, and frag counts
|
|
|
|
// FIXME: is this a good thing?
|
|
|
|
SZ_Clear (&host_client->netchan.message);
|
|
|
|
|
|
|
|
// send current status of all other players
|
2005-05-05 07:31:31 +00:00
|
|
|
SV_WriteSpawn1 (&host_client->backbuf, n);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-08-21 03:50:30 +00:00
|
|
|
SV_Spawn (host_client);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2005-05-05 07:31:31 +00:00
|
|
|
SV_WriteSpawn2 (&host_client->backbuf);
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
//
|
|
|
|
// force stats to be updated
|
|
|
|
//
|
|
|
|
memset (host_client->stats, 0, sizeof (host_client->stats));
|
|
|
|
|
|
|
|
// get the client to check and download skins
|
|
|
|
// when that is completed, a begin command will be issued
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_stufftext, 8);
|
|
|
|
MSG_ReliableWrite_String (&host_client->backbuf, "skins\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_SpawnSpectator (void)
|
|
|
|
{
|
2003-09-03 22:17:04 +00:00
|
|
|
VectorZero (SVvector (sv_player, origin));
|
|
|
|
VectorZero (SVvector (sv_player, view_ofs));
|
2001-08-08 20:28:53 +00:00
|
|
|
SVvector (sv_player, view_ofs)[2] = 22;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// search for an info_playerstart to spawn the spectator at
|
2022-01-16 13:15:18 +00:00
|
|
|
for (unsigned i = MAX_CLIENTS - 1; i < sv.num_edicts; i++) {
|
|
|
|
edict_t *e = EDICT_NUM (&sv_pr_state, i);
|
2002-08-22 23:04:44 +00:00
|
|
|
if (!strcmp (PR_GetString (&sv_pr_state, SVstring (e, classname)),
|
|
|
|
"info_player_start")) {
|
2001-08-08 20:28:53 +00:00
|
|
|
VectorCopy (SVvector (e, origin), SVvector (sv_player, origin));
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Begin_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
unsigned int pmodel = 0, emodel = 0;
|
|
|
|
int i;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-03-03 17:08:45 +00:00
|
|
|
if (host_client->state != cs_connected)
|
2001-02-19 21:15:25 +00:00
|
|
|
return; // don't begin again
|
|
|
|
|
|
|
|
host_client->state = cs_spawned;
|
|
|
|
|
|
|
|
// handle the case of a level changing while a client was connecting
|
|
|
|
if (atoi (Cmd_Argv (1)) != svs.spawncount) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_Begin_f from different level\n");
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_New_f (0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-08-01 00:38:16 +00:00
|
|
|
// make sure they're not trying to cheat by beginning without spawning
|
|
|
|
if (host_client->spawned == false) {
|
2002-08-22 23:04:44 +00:00
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s has been kicked for trying to "
|
|
|
|
"begin before spawning!\n"
|
|
|
|
"Have a nice day!\n", // 1 string!
|
|
|
|
host_client->name);
|
2001-08-01 00:38:16 +00:00
|
|
|
SV_DropClient (host_client);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (host_client->spectator) {
|
|
|
|
SV_SpawnSpectator ();
|
|
|
|
|
2003-11-21 06:09:21 +00:00
|
|
|
if (sv_funcs.SpectatorConnect) {
|
2001-02-19 21:15:25 +00:00
|
|
|
// copy spawn parms out of the client_t
|
|
|
|
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
2001-03-01 08:34:30 +00:00
|
|
|
sv_globals.parms[i] = host_client->spawn_parms[i];
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// call the spawn function
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.time = sv.time;
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
2003-11-21 06:09:21 +00:00
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.SpectatorConnect);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// copy spawn parms out of the client_t
|
|
|
|
for (i = 0; i < NUM_SPAWN_PARMS; i++)
|
2001-03-01 08:34:30 +00:00
|
|
|
sv_globals.parms[i] = host_client->spawn_parms[i];
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// call the spawn function
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.time = sv.time;
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.ClientConnect);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// actually spawn the player
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.time = sv.time;
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.PutClientInServer);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// clear the net statistics, because connecting gives a bogus picture
|
|
|
|
host_client->last_check = -1;
|
2003-01-30 20:31:44 +00:00
|
|
|
host_client->msecs = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->netchan.frame_latency = 0;
|
|
|
|
host_client->netchan.frame_rate = 0;
|
|
|
|
host_client->netchan.drop_count = 0;
|
|
|
|
host_client->netchan.good_count = 0;
|
|
|
|
|
|
|
|
// check he's not cheating
|
|
|
|
pmodel = atoi (Info_ValueForKey (host_client->userinfo, "pmodel"));
|
|
|
|
emodel = atoi (Info_ValueForKey (host_client->userinfo, "emodel"));
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
if (pmodel != sv.model_player_checksum || emodel
|
|
|
|
!= sv.eyes_player_checksum)
|
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard "
|
|
|
|
"player/eyes model detected\n", host_client->name);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// if we are paused, tell the client
|
|
|
|
if (sv.paused) {
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_setpause, 2);
|
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, sv.paused);
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Server is paused.\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
// send a fixangle over the reliable channel to make sure it gets there
|
|
|
|
// Never send a roll angle, because savegames can catch the server
|
|
|
|
// in a state where it is expecting the client to correct the angle
|
|
|
|
// and it won't happen if the game was just loaded, so you wind up
|
|
|
|
// with a permanent head tilt
|
|
|
|
ent = EDICT_NUM (&sv_pr_state, 1 + (host_client - svs.clients));
|
|
|
|
MSG_WriteByte (&host_client->netchan.message, svc_setangle);
|
|
|
|
for (i = 0; i < 2; i++)
|
2001-12-12 21:56:09 +00:00
|
|
|
MSG_WriteAngle (&host_client->netchan.message,
|
|
|
|
SVvector (ent, angles)[i]);
|
2001-02-19 21:15:25 +00:00
|
|
|
MSG_WriteAngle (&host_client->netchan.message, 0);
|
|
|
|
#endif
|
2003-02-28 05:09:46 +00:00
|
|
|
|
|
|
|
// Trigger GIB events
|
|
|
|
if (sv_client_spawn_e->func)
|
2021-01-31 07:01:20 +00:00
|
|
|
GIB_Event_Callback (sv_client_spawn_e, 1, va (0, "%u",
|
2003-03-21 21:25:44 +00:00
|
|
|
host_client->userid));
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_NextDownload_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2003-08-05 01:45:52 +00:00
|
|
|
byte buffer[768]; // FIXME protocol limit? could be bigger?
|
2004-07-13 19:14:01 +00:00
|
|
|
int percent, size;
|
|
|
|
size_t r;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (!host_client->download)
|
|
|
|
return;
|
|
|
|
|
2001-11-07 08:24:56 +00:00
|
|
|
r = host_client->downloadsize - host_client->downloadcount;
|
2003-08-05 01:45:52 +00:00
|
|
|
if (r > sizeof (buffer))
|
|
|
|
r = sizeof (buffer);
|
2001-11-07 08:24:56 +00:00
|
|
|
r = Qread (host_client->download, buffer, r);
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_download, 6 + r);
|
|
|
|
MSG_ReliableWrite_Short (&host_client->backbuf, r);
|
2001-11-07 08:24:56 +00:00
|
|
|
|
|
|
|
host_client->downloadcount += r;
|
|
|
|
size = host_client->downloadsize;
|
|
|
|
if (!size)
|
|
|
|
size = 1;
|
|
|
|
percent = host_client->downloadcount * 100 / size;
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, percent);
|
|
|
|
MSG_ReliableWrite_SZ (&host_client->backbuf, buffer, r);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->downloadcount != host_client->downloadsize)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Qclose (host_client->download);
|
|
|
|
host_client->download = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_NextUpload (void)
|
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
int percent, size;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2022-03-31 08:27:04 +00:00
|
|
|
if (!host_client->upload) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Upload denied\n");
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_stufftext, 8);
|
|
|
|
MSG_ReliableWrite_String (&host_client->backbuf, "stopul");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// suck out rest of packet
|
2001-02-23 23:16:13 +00:00
|
|
|
size = MSG_ReadShort (net_message);
|
|
|
|
MSG_ReadByte (net_message);
|
|
|
|
net_message->readcount += size;
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-23 23:16:13 +00:00
|
|
|
size = MSG_ReadShort (net_message);
|
|
|
|
percent = MSG_ReadByte (net_message);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2022-03-31 08:27:04 +00:00
|
|
|
if (!host_client->upload_started) {
|
|
|
|
host_client->upload_started = 1;
|
2003-05-23 17:17:01 +00:00
|
|
|
SV_Printf ("Receiving %s from %d...\n", host_client->uploadfn->str,
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->userid);
|
|
|
|
if (host_client->remote_snap)
|
|
|
|
OutofBandPrintf (host_client->snap_from,
|
|
|
|
"Server receiving %s from %d...\n",
|
2003-05-23 17:17:01 +00:00
|
|
|
host_client->uploadfn->str, host_client->userid);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
Qwrite (host_client->upload, net_message->message->data +
|
|
|
|
net_message->readcount, size);
|
2001-02-23 23:16:13 +00:00
|
|
|
net_message->readcount += size;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_dev, "UPLOAD: %d received\n", size);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (percent != 100) {
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_stufftext, 8);
|
|
|
|
MSG_ReliableWrite_String (&host_client->backbuf, "nextul\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
} else {
|
|
|
|
Qclose (host_client->upload);
|
|
|
|
host_client->upload = NULL;
|
|
|
|
|
2003-05-23 17:17:01 +00:00
|
|
|
SV_Printf ("%s upload completed.\n", host_client->uploadfn->str);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (host_client->remote_snap) {
|
2002-08-22 23:04:44 +00:00
|
|
|
char *p;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-05-23 17:17:01 +00:00
|
|
|
if ((p = strchr (host_client->uploadfn->str, '/')) != NULL)
|
2001-02-19 21:15:25 +00:00
|
|
|
p++;
|
|
|
|
else
|
2003-05-23 17:17:01 +00:00
|
|
|
p = host_client->uploadfn->str;
|
2002-08-22 23:04:44 +00:00
|
|
|
OutofBandPrintf (host_client->snap_from, "%s upload completed.\n"
|
|
|
|
"To download, enter:\ndownload %s\n",
|
2003-05-23 17:17:01 +00:00
|
|
|
host_client->uploadfn->str, p);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2003-05-23 17:17:01 +00:00
|
|
|
dstring_delete (host_client->uploadfn);
|
|
|
|
host_client->uploadfn = 0;
|
2022-03-31 08:27:04 +00:00
|
|
|
host_client->upload_started = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_BeginDownload_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-07-15 07:04:17 +00:00
|
|
|
const char *name;
|
2014-01-23 02:57:57 +00:00
|
|
|
int http, zip;
|
2002-08-27 07:16:28 +00:00
|
|
|
QFile *file;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
name = Cmd_Argv (1);
|
|
|
|
// hacked by zoid to allow more conrol over download
|
|
|
|
// first off, no .. or global allow check
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (strstr (name, "..") || !allow_download
|
2001-02-19 21:15:25 +00:00
|
|
|
// leading dot is no good
|
|
|
|
|| *name == '.'
|
|
|
|
// next up, skin check
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
|| (strncmp (name, "skins/", 6) == 0 && !allow_download_skins)
|
2001-02-19 21:15:25 +00:00
|
|
|
// now models
|
2002-08-22 23:04:44 +00:00
|
|
|
|| (strncmp (name, "progs/", 6) == 0 &&
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
!allow_download_models)
|
2001-02-19 21:15:25 +00:00
|
|
|
// now sounds
|
2002-08-22 23:04:44 +00:00
|
|
|
|| (strncmp (name, "sound/", 6) == 0 &&
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
!allow_download_sounds)
|
2001-02-19 21:15:25 +00:00
|
|
|
// now maps (note special case for maps, must not be in pak)
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
|| (strncmp (name, "maps/", 5) == 0 && !allow_download_maps)
|
2012-05-21 23:23:22 +00:00
|
|
|
// MUST be in a subdirectory
|
2001-02-19 21:15:25 +00:00
|
|
|
|| !strstr (name, "/")) { // don't allow anything with .. path
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_download, 4);
|
|
|
|
MSG_ReliableWrite_Short (&host_client->backbuf, -1);
|
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (host_client->download) {
|
|
|
|
Qclose (host_client->download);
|
|
|
|
host_client->download = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
zip = strchr (Info_ValueForKey (host_client->userinfo, "*cap"), 'z') != 0;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
http = sv_http_url_base[0]
|
2007-03-20 14:37:50 +00:00
|
|
|
&& strchr (Info_ValueForKey (host_client->userinfo, "*cap"), 'h');
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2014-01-23 02:57:57 +00:00
|
|
|
file = _QFS_FOpenFile (name, !zip);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
host_client->download = file;
|
2021-07-22 09:02:36 +00:00
|
|
|
host_client->downloadsize = file ? Qfilesize (file) : 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->downloadcount = 0;
|
|
|
|
|
|
|
|
if (!host_client->download
|
2002-08-22 23:04:44 +00:00
|
|
|
// ZOID: special check for maps, if it came from a pak file, don't
|
|
|
|
// allow download
|
2013-11-24 06:18:42 +00:00
|
|
|
|| (strncmp (name, "maps/", 5) == 0 && qfs_foundfile.in_pak)) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (host_client->download) {
|
|
|
|
Qclose (host_client->download);
|
|
|
|
host_client->download = NULL;
|
|
|
|
}
|
|
|
|
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("Couldn't download %s to %s\n", name, host_client->name);
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_download, 4);
|
2007-03-20 14:41:54 +00:00
|
|
|
MSG_ReliableWrite_Short (&host_client->backbuf, DL_NOFILE);
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-20 14:37:50 +00:00
|
|
|
if (http) {
|
|
|
|
int size;
|
2013-11-24 13:45:42 +00:00
|
|
|
int ren = zip && strcmp (qfs_foundfile.realname, name);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
SV_Printf ("http redirect: %s/%s\n", sv_http_url_base,
|
2013-11-24 13:45:42 +00:00
|
|
|
qfs_foundfile.realname);
|
|
|
|
size = ren ? strlen (qfs_foundfile.realname) * 2 : strlen (name);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
size += strlen (sv_http_url_base) + 7;
|
2007-03-20 14:37:50 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_download, size);
|
2007-03-20 14:41:54 +00:00
|
|
|
MSG_ReliableWrite_Short (&host_client->backbuf, DL_HTTP);
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, 0);
|
2012-05-21 23:23:22 +00:00
|
|
|
MSG_ReliableWrite_String (&host_client->backbuf,
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
va (0, "%s/%s", sv_http_url_base,
|
2013-11-24 13:45:42 +00:00
|
|
|
ren ? qfs_foundfile.realname : name));
|
2007-03-20 14:37:50 +00:00
|
|
|
MSG_ReliableWrite_String (&host_client->backbuf,
|
2013-11-24 13:45:42 +00:00
|
|
|
ren ? qfs_foundfile.realname : "");
|
2007-03-24 13:56:14 +00:00
|
|
|
if (host_client->download) {
|
|
|
|
Qclose (host_client->download);
|
|
|
|
host_client->download = NULL;
|
|
|
|
}
|
2007-03-20 14:37:50 +00:00
|
|
|
} else {
|
2013-11-24 13:45:42 +00:00
|
|
|
if (zip && strcmp (qfs_foundfile.realname, name)) {
|
|
|
|
SV_Printf ("download renamed to %s\n", qfs_foundfile.realname);
|
2007-03-20 14:37:50 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_download,
|
2013-11-24 13:45:42 +00:00
|
|
|
strlen (qfs_foundfile.realname) + 5);
|
2007-03-20 14:41:54 +00:00
|
|
|
MSG_ReliableWrite_Short (&host_client->backbuf, DL_RENAME);
|
2007-03-20 14:37:50 +00:00
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, 0);
|
2013-11-24 13:45:42 +00:00
|
|
|
MSG_ReliableWrite_String (&host_client->backbuf,
|
|
|
|
qfs_foundfile.realname);
|
2007-03-20 14:37:50 +00:00
|
|
|
MSG_Reliable_FinishWrite (&host_client->backbuf);
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2002-07-05 06:43:47 +00:00
|
|
|
SV_NextDownload_f (0);
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("Downloading %s to %s\n", name, host_client->name);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2023-06-13 09:06:11 +00:00
|
|
|
SV_Say (bool team)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
char *i, *p;
|
2003-08-05 01:45:52 +00:00
|
|
|
dstring_t *text;
|
2021-03-29 08:27:06 +00:00
|
|
|
const char *t1 = 0, *t2, *type;
|
2002-08-22 23:04:44 +00:00
|
|
|
client_t *client;
|
2002-10-04 02:29:03 +00:00
|
|
|
int tmp, j, cls = 0;
|
2005-05-01 09:07:20 +00:00
|
|
|
sizebuf_t *dbuf;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (Cmd_Argc () < 2)
|
|
|
|
return;
|
|
|
|
|
2004-04-27 03:45:26 +00:00
|
|
|
if (host_client->state < cs_connected)
|
|
|
|
return;
|
|
|
|
|
2003-08-05 01:45:52 +00:00
|
|
|
if (team)
|
|
|
|
t1 = Info_ValueForKey (host_client->userinfo, "team");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (fp_messages) {
|
2002-06-20 16:15:27 +00:00
|
|
|
if (!sv.paused && realtime < host_client->lockedtill) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_CHAT,
|
2002-06-20 16:15:27 +00:00
|
|
|
"You can't talk for %d more seconds\n",
|
|
|
|
(int) (host_client->lockedtill - realtime));
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
tmp = host_client->whensaidhead - fp_messages + 1;
|
|
|
|
if (tmp < 0)
|
|
|
|
tmp = 10 + tmp;
|
2002-08-22 23:04:44 +00:00
|
|
|
if (!sv.paused && host_client->whensaid[tmp]
|
2001-02-19 21:15:25 +00:00
|
|
|
&& (realtime - host_client->whensaid[tmp] < fp_persecond)) {
|
2002-06-20 16:15:27 +00:00
|
|
|
host_client->lockedtill = realtime + fp_secondsdead;
|
2001-02-19 21:15:25 +00:00
|
|
|
if (fp_msg[0])
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_CHAT,
|
2001-02-19 21:15:25 +00:00
|
|
|
"FloodProt: %s\n", fp_msg);
|
|
|
|
else
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_CHAT,
|
2001-02-19 21:15:25 +00:00
|
|
|
"FloodProt: You can't talk for %d seconds.\n",
|
|
|
|
fp_secondsdead);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
host_client->whensaidhead++;
|
|
|
|
if (host_client->whensaidhead > 9)
|
|
|
|
host_client->whensaidhead = 0;
|
|
|
|
host_client->whensaid[host_client->whensaidhead] = realtime;
|
|
|
|
}
|
|
|
|
|
2021-07-28 06:01:45 +00:00
|
|
|
p = Hunk_TempAlloc (0, strlen (Cmd_Args (1)) + 1);
|
2003-11-21 20:04:16 +00:00
|
|
|
strcpy (p, Cmd_Args (1));
|
|
|
|
|
|
|
|
if (*p == '"') {
|
|
|
|
p++;
|
|
|
|
p[strlen (p) - 1] = 0;
|
|
|
|
}
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (!sv_allowfake || (!team && sv_allowfake == 2)) {
|
2004-04-27 03:45:26 +00:00
|
|
|
for (i = p; *i; i++) {
|
|
|
|
if (*i == 13) { // ^M
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (sv_kickfake) {
|
2004-04-27 03:45:26 +00:00
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked for "
|
|
|
|
"attempting to fake messages\n",
|
|
|
|
host_client->name);
|
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "You were kicked "
|
|
|
|
"for attempting to fake messages\n");
|
|
|
|
SV_DropClient (host_client);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
*i = '#';
|
|
|
|
}
|
2003-11-21 20:04:16 +00:00
|
|
|
}
|
2004-04-27 03:45:26 +00:00
|
|
|
}
|
2003-11-21 20:04:16 +00:00
|
|
|
|
2003-11-21 06:09:21 +00:00
|
|
|
if (sv_funcs.ChatMessage) {
|
2004-01-05 07:10:32 +00:00
|
|
|
PR_PushFrame (&sv_pr_state);
|
2005-06-12 09:54:01 +00:00
|
|
|
PR_RESET_PARAMS (&sv_pr_state);
|
2004-01-05 07:10:32 +00:00
|
|
|
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, p);
|
2006-12-05 09:55:37 +00:00
|
|
|
P_FLOAT (&sv_pr_state, 1) = (float) team;
|
2003-11-21 06:09:21 +00:00
|
|
|
|
|
|
|
*sv_globals.time = sv.time;
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.ChatMessage);
|
2004-01-05 07:10:32 +00:00
|
|
|
PR_PopFrame (&sv_pr_state);
|
2003-11-21 06:09:21 +00:00
|
|
|
if (R_FLOAT (&sv_pr_state))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-08-05 01:45:52 +00:00
|
|
|
text = dstring_new ();
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (host_client->spectator && (!sv_spectalk || team)) {
|
2003-08-05 01:45:52 +00:00
|
|
|
type = "2";
|
2021-03-29 08:27:06 +00:00
|
|
|
dsprintf (text, "[SPEC] %s: ", host_client->name);
|
2003-08-05 01:45:52 +00:00
|
|
|
} else if (team) {
|
|
|
|
type = "1";
|
2021-03-29 08:27:06 +00:00
|
|
|
dsprintf (text, "(%s): ", host_client->name);
|
2003-08-05 01:45:52 +00:00
|
|
|
} else {
|
|
|
|
type = "0";
|
2021-03-29 08:27:06 +00:00
|
|
|
dsprintf (text, "%s: ", host_client->name);
|
2003-08-05 01:45:52 +00:00
|
|
|
}
|
|
|
|
|
2003-02-16 19:46:34 +00:00
|
|
|
if (sv_chat_e->func)
|
2021-01-31 07:01:20 +00:00
|
|
|
GIB_Event_Callback (sv_chat_e, 2, va (0, "%i", host_client->userid), p,
|
2003-03-21 21:25:44 +00:00
|
|
|
type);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-08-05 01:45:52 +00:00
|
|
|
dstring_appendstr (text, p);
|
|
|
|
dstring_appendstr (text, "\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2004-03-15 20:41:34 +00:00
|
|
|
SV_Printf ("%s", text->str);
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
|
2004-04-06 22:02:45 +00:00
|
|
|
if (client->state < cs_connected) // Clients connecting can hear. //FIXME record to mvd?
|
2001-02-19 21:15:25 +00:00
|
|
|
continue;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (host_client->spectator && !sv_spectalk)
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!client->spectator)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (team) {
|
|
|
|
// the spectator team
|
|
|
|
if (host_client->spectator) {
|
|
|
|
if (!client->spectator)
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
t2 = Info_ValueForKey (client->userinfo, "team");
|
|
|
|
if (strcmp (t1, t2) || client->spectator)
|
|
|
|
continue; // on different teams
|
|
|
|
}
|
|
|
|
}
|
2002-10-04 02:29:03 +00:00
|
|
|
cls |= 1 << j;
|
2003-08-05 01:45:52 +00:00
|
|
|
SV_ClientPrintf (0, client, PRINT_CHAT, "%s", text->str);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2002-10-04 02:29:03 +00:00
|
|
|
|
2005-05-01 09:07:20 +00:00
|
|
|
if (!sv.recorders || !cls) {
|
2003-08-05 01:45:52 +00:00
|
|
|
dstring_delete (text);
|
2002-10-04 02:29:03 +00:00
|
|
|
return;
|
2003-08-05 01:45:52 +00:00
|
|
|
}
|
2002-10-04 02:29:03 +00:00
|
|
|
// non-team messages should be seen allways, even if not tracking any
|
|
|
|
// player
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (!team && ((host_client->spectator && sv_spectalk)
|
2002-10-04 02:29:03 +00:00
|
|
|
|| !host_client->spectator)) {
|
2005-05-01 09:07:20 +00:00
|
|
|
dbuf = SVR_WriteBegin (dem_all, 0, strlen (text->str) + 3);
|
2002-10-04 02:29:03 +00:00
|
|
|
} else {
|
2005-05-01 09:07:20 +00:00
|
|
|
dbuf = SVR_WriteBegin (dem_multiple, cls, strlen (text->str) + 3);
|
2002-10-04 02:29:03 +00:00
|
|
|
}
|
2005-05-01 09:07:20 +00:00
|
|
|
MSG_WriteByte (dbuf, svc_print);
|
|
|
|
MSG_WriteByte (dbuf, PRINT_CHAT);
|
|
|
|
MSG_WriteString (dbuf, text->str);
|
2003-08-05 01:45:52 +00:00
|
|
|
dstring_delete (text);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Say_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
SV_Say (false);
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Say_Team_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
SV_Say (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_Pings_f
|
|
|
|
|
|
|
|
The client is showing the scoreboard, so send new ping times for all
|
|
|
|
clients
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Pings_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
client_t *client;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
|
2003-03-05 03:56:50 +00:00
|
|
|
if (client->state != cs_spawned && client->state != cs_server)
|
2001-02-19 21:15:25 +00:00
|
|
|
continue;
|
|
|
|
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_updateping, 4);
|
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, j);
|
|
|
|
MSG_ReliableWrite_Short (&host_client->backbuf, SV_CalcPing (client));
|
|
|
|
MSG_ReliableWrite_Begin (&host_client->backbuf, svc_updatepl, 4);
|
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, j);
|
|
|
|
MSG_ReliableWrite_Byte (&host_client->backbuf, client->lossage);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Kill_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2001-08-08 20:28:53 +00:00
|
|
|
if (SVfloat (sv_player, health) <= 0) {
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_BeginRedirect (RD_CLIENT);
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH,
|
2001-02-21 23:45:49 +00:00
|
|
|
"Can't suicide -- already dead!\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_EndRedirect ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.time = sv.time;
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.ClientKill);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SV_TogglePause (const char *msg)
|
|
|
|
{
|
|
|
|
client_t *cl;
|
2002-08-22 23:04:44 +00:00
|
|
|
int i;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
sv.paused ^= 1;
|
2004-02-19 08:58:42 +00:00
|
|
|
net_nochoke = sv.paused;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (msg)
|
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s", msg);
|
|
|
|
|
|
|
|
// send notification to all clients
|
|
|
|
for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) {
|
2003-03-03 17:08:45 +00:00
|
|
|
if (cl->state < cs_zombie)
|
2001-02-19 21:15:25 +00:00
|
|
|
continue;
|
2004-02-22 05:40:08 +00:00
|
|
|
MSG_ReliableWrite_Begin (&cl->backbuf, svc_setpause, 2);
|
|
|
|
MSG_ReliableWrite_Byte (&cl->backbuf, sv.paused);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Pause_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
char st[sizeof (host_client->name) + 32];
|
|
|
|
static double lastpausetime;
|
|
|
|
double currenttime;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
currenttime = Sys_DoubleTime ();
|
|
|
|
|
|
|
|
if (lastpausetime + 1 > currenttime) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH,
|
2002-08-22 23:04:44 +00:00
|
|
|
"Pause flood not allowed.\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lastpausetime = currenttime;
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (!pausable) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Pause not allowed.\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (host_client->spectator) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH,
|
2001-02-19 21:15:25 +00:00
|
|
|
"Spectators can not pause.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sv.paused)
|
|
|
|
snprintf (st, sizeof (st), "%s paused the game\n", host_client->name);
|
|
|
|
else
|
2002-08-22 23:04:44 +00:00
|
|
|
snprintf (st, sizeof (st), "%s unpaused the game\n",
|
|
|
|
host_client->name);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
SV_TogglePause (st);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_Drop_f
|
|
|
|
|
|
|
|
The client is going to disconnect, so remove the connection immediately
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Drop_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
SV_EndRedirect ();
|
|
|
|
if (!host_client->spectator)
|
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s dropped\n", host_client->name);
|
|
|
|
SV_DropClient (host_client);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_PTrack_f
|
|
|
|
|
|
|
|
Change the bandwidth estimate for a client
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_PTrack_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
edict_t *ent, *tent;
|
2002-08-22 23:04:44 +00:00
|
|
|
int i;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (!host_client->spectator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Cmd_Argc () != 2) {
|
|
|
|
// turn off tracking
|
|
|
|
host_client->spec_track = 0;
|
|
|
|
ent = EDICT_NUM (&sv_pr_state, host_client - svs.clients + 1);
|
|
|
|
tent = EDICT_NUM (&sv_pr_state, 0);
|
2001-08-08 20:28:53 +00:00
|
|
|
SVentity (ent, goalentity) = EDICT_TO_PROG (&sv_pr_state, tent);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = atoi (Cmd_Argv (1));
|
2003-08-25 01:11:23 +00:00
|
|
|
if (i < 0 || i >= MAX_CLIENTS
|
|
|
|
|| (svs.clients[i].state != cs_spawned
|
|
|
|
&& svs.clients[i].state != cs_server)
|
|
|
|
|| svs.clients[i].spectator) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH,
|
|
|
|
"Invalid client to track\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->spec_track = 0;
|
|
|
|
ent = EDICT_NUM (&sv_pr_state, host_client - svs.clients + 1);
|
|
|
|
tent = EDICT_NUM (&sv_pr_state, 0);
|
2001-08-08 20:28:53 +00:00
|
|
|
SVentity (ent, goalentity) = EDICT_TO_PROG (&sv_pr_state, tent);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
host_client->spec_track = i + 1; // now tracking
|
|
|
|
|
|
|
|
ent = EDICT_NUM (&sv_pr_state, host_client - svs.clients + 1);
|
|
|
|
tent = EDICT_NUM (&sv_pr_state, i + 1);
|
2001-08-08 20:28:53 +00:00
|
|
|
SVentity (ent, goalentity) = EDICT_TO_PROG (&sv_pr_state, tent);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_Rate_f
|
|
|
|
|
|
|
|
Change the bandwidth estimate for a client
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Rate_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
int rate;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (Cmd_Argc () != 2) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Current rate is %i\n",
|
2001-02-19 21:15:25 +00:00
|
|
|
(int) (1.0 / host_client->netchan.rate + 0.5));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = atoi (Cmd_Argv (1));
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (sv_maxrate) {
|
|
|
|
rate = bound (500, rate, sv_maxrate);
|
2001-02-19 21:15:25 +00:00
|
|
|
} else {
|
2002-06-17 16:18:34 +00:00
|
|
|
rate = max (500, rate);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->netchan.rate = 1.0 / rate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_Msg_f
|
|
|
|
|
|
|
|
Change the message level for a client
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_Msg_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
if (Cmd_Argc () != 2) {
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH,
|
|
|
|
"Current msg level is %i\n",
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->messagelevel);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
host_client->messagelevel = atoi (Cmd_Argv (1));
|
|
|
|
|
2002-10-04 02:29:03 +00:00
|
|
|
SV_ClientPrintf (1, host_client, PRINT_HIGH, "Msg level set to %i\n",
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->messagelevel);
|
|
|
|
}
|
|
|
|
|
2003-11-21 06:09:21 +00:00
|
|
|
void
|
|
|
|
SV_SetUserinfo (client_t *client, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
char *oldvalue = 0;
|
2007-05-16 21:21:30 +00:00
|
|
|
int send_changes = 1;
|
2003-11-21 06:09:21 +00:00
|
|
|
|
|
|
|
if (sv_setinfo_e->func || sv_funcs.UserInfoChanged)
|
|
|
|
oldvalue = strdup (Info_ValueForKey (client->userinfo, key));
|
|
|
|
if (!Info_SetValueForKey (client->userinfo, key, value,
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
!sv_highchars)) {
|
2003-11-21 06:09:21 +00:00
|
|
|
// key hasn't changed
|
|
|
|
if (oldvalue)
|
|
|
|
free (oldvalue);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// process any changed values
|
|
|
|
SV_ExtractFromUserinfo (client);
|
|
|
|
|
|
|
|
// trigger a GIB event
|
|
|
|
if (sv_setinfo_e->func)
|
2021-01-31 07:01:20 +00:00
|
|
|
GIB_Event_Callback (sv_setinfo_e, 4, va (0, "%d", client->userid),
|
2003-11-21 06:09:21 +00:00
|
|
|
key, oldvalue, value);
|
|
|
|
|
|
|
|
if (sv_funcs.UserInfoChanged) {
|
2004-01-05 07:10:32 +00:00
|
|
|
PR_PushFrame (&sv_pr_state);
|
2003-11-21 06:09:21 +00:00
|
|
|
*sv_globals.time = sv.time;
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, client->edict);
|
2005-06-12 09:54:01 +00:00
|
|
|
PR_RESET_PARAMS (&sv_pr_state);
|
2004-01-05 07:10:32 +00:00
|
|
|
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key);
|
|
|
|
P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue);
|
|
|
|
P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value);
|
2020-02-25 08:28:32 +00:00
|
|
|
sv_pr_state.pr_argc = 3;
|
2003-11-21 06:09:21 +00:00
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoChanged);
|
2004-01-05 07:10:32 +00:00
|
|
|
PR_PopFrame (&sv_pr_state);
|
2007-05-16 10:00:19 +00:00
|
|
|
send_changes = !R_FLOAT (&sv_pr_state);
|
2003-11-21 06:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (oldvalue)
|
|
|
|
free (oldvalue);
|
|
|
|
|
2007-05-16 10:00:19 +00:00
|
|
|
if (send_changes && Info_FilterForKey (key, client_info_filters)) {
|
2003-11-21 06:09:21 +00:00
|
|
|
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
|
|
|
|
MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, key);
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
/*
|
|
|
|
SV_SetInfo_f
|
|
|
|
|
|
|
|
Allow clients to change userinfo
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_SetInfo_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2003-11-21 06:09:21 +00:00
|
|
|
const char *key;
|
|
|
|
const char *value;
|
2003-05-16 16:17:24 +00:00
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
if (Cmd_Argc () == 1) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("User info settings:\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
Info_Print (host_client->userinfo);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Cmd_Argc () != 3) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("usage: setinfo [ <key> <value> ]\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Cmd_Argv (1)[0] == '*')
|
|
|
|
return; // don't set priveledged values
|
|
|
|
|
2003-11-21 06:09:21 +00:00
|
|
|
key = Cmd_Argv (1);
|
|
|
|
value = Cmd_Argv (2);
|
2003-08-05 01:45:52 +00:00
|
|
|
|
2003-11-21 06:09:21 +00:00
|
|
|
if (sv_funcs.UserInfoCallback) {
|
2004-01-05 07:10:32 +00:00
|
|
|
PR_PushFrame (&sv_pr_state);
|
2003-11-21 06:09:21 +00:00
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
2005-06-12 09:54:01 +00:00
|
|
|
PR_RESET_PARAMS (&sv_pr_state);
|
2004-01-05 07:10:32 +00:00
|
|
|
P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key);
|
|
|
|
P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, value);
|
2020-02-25 08:28:32 +00:00
|
|
|
sv_pr_state.pr_argc = 2;
|
2003-11-21 06:09:21 +00:00
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoCallback);
|
2004-01-05 07:10:32 +00:00
|
|
|
PR_PopFrame (&sv_pr_state);
|
2007-05-15 10:58:19 +00:00
|
|
|
if (R_FLOAT (&sv_pr_state))
|
|
|
|
return;
|
2001-07-20 04:30:33 +00:00
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-11-21 06:09:21 +00:00
|
|
|
SV_SetUserinfo (host_client, key, value);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_ShowServerinfo_f
|
|
|
|
|
|
|
|
Dump serverinfo into a string
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_ShowServerinfo_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
Info_Print (svs.info);
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
SV_NoSnap_f (void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2003-05-23 17:17:01 +00:00
|
|
|
if (host_client->uploadfn) {
|
|
|
|
dstring_delete (host_client->uploadfn);
|
|
|
|
host_client->uploadfn = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s refused remote screenshot\n",
|
|
|
|
host_client->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ucmd_t ucmds[] = {
|
2002-07-05 21:15:19 +00:00
|
|
|
{"new", SV_New_f, 0, 0},
|
|
|
|
{"modellist", SV_Modellist_f, 0, 0},
|
|
|
|
{"soundlist", SV_Soundlist_f, 0, 0},
|
|
|
|
{"prespawn", SV_PreSpawn_f, 0, 0},
|
|
|
|
{"spawn", SV_Spawn_f, 0, 0},
|
|
|
|
{"begin", SV_Begin_f, 1, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"drop", SV_Drop_f, 0, 0},
|
|
|
|
{"pings", SV_Pings_f, 0, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2012-05-21 23:23:22 +00:00
|
|
|
// issued by hand at client consoles
|
2002-07-05 21:15:19 +00:00
|
|
|
{"rate", SV_Rate_f, 0, 0},
|
|
|
|
{"kill", SV_Kill_f, 1, 1},
|
|
|
|
{"pause", SV_Pause_f, 1, 0},
|
|
|
|
{"msg", SV_Msg_f, 0, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"say", SV_Say_f, 1, 1},
|
|
|
|
{"say_team", SV_Say_Team_f, 1, 1},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"setinfo", SV_SetInfo_f, 1, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"serverinfo", SV_ShowServerinfo_f,0, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"download", SV_BeginDownload_f, 1, 0},
|
|
|
|
{"nextdl", SV_NextDownload_f, 0, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"ptrack", SV_PTrack_f, 0, 1}, // ZOID - used with autocam
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
{"snap", SV_NoSnap_f, 0, 0},
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2002-07-05 06:43:47 +00:00
|
|
|
static hashtab_t *ucmd_table;
|
2003-11-21 06:09:21 +00:00
|
|
|
int (*ucmd_unknown)(void);
|
2002-07-05 06:43:47 +00:00
|
|
|
|
|
|
|
static void
|
2003-04-28 15:56:09 +00:00
|
|
|
call_qc_hook (void *qc_hook)
|
2002-07-05 06:43:47 +00:00
|
|
|
{
|
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
2022-01-18 06:32:43 +00:00
|
|
|
PR_ExecuteProgram (&sv_pr_state, (pr_func_t) (intptr_t) qc_hook);
|
2002-07-05 06:43:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
2012-07-18 13:34:37 +00:00
|
|
|
ucmds_getkey (const void *_a, void *unused)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
ucmd_t *a = (ucmd_t*)_a;
|
2002-07-05 06:43:47 +00:00
|
|
|
return a->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ucmds_free (void *_c, void *unused)
|
|
|
|
{
|
|
|
|
ucmd_t *c = (ucmd_t*)_c;
|
|
|
|
if (c->freeable) {
|
2003-04-28 15:56:09 +00:00
|
|
|
if (c->on_free)
|
|
|
|
c->on_free (c->userdata);
|
2002-07-05 06:43:47 +00:00
|
|
|
free ((char *)c->name);
|
|
|
|
free (c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-06-03 06:01:47 +00:00
|
|
|
/*
|
|
|
|
hash and compare functions: user commands are accessed by name but
|
|
|
|
removed by pointer (because they are overridable and multiple commands
|
|
|
|
can be stored under the same command name) so we define a get_hash
|
|
|
|
functions that hashes the key and a compare function that compares the
|
|
|
|
pointer.
|
|
|
|
*/
|
2003-04-28 19:55:03 +00:00
|
|
|
|
2007-04-04 07:48:14 +00:00
|
|
|
static uintptr_t
|
2012-07-18 13:34:37 +00:00
|
|
|
ucmd_get_hash (const void *_a, void *data)
|
2003-04-28 19:55:03 +00:00
|
|
|
{
|
|
|
|
ucmd_t *a = (ucmd_t*)_a;
|
|
|
|
return Hash_String (a->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-07-18 13:34:37 +00:00
|
|
|
ucmd_compare (const void *a, const void *b, void *data)
|
2003-04-28 19:55:03 +00:00
|
|
|
{
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
2003-04-28 15:56:09 +00:00
|
|
|
/*
|
|
|
|
SV_AddUserCommand
|
|
|
|
|
|
|
|
Adds a new user command. Returns a pointer to the command object (to be
|
|
|
|
used by SV_RemoveUserCommand) if succesful, NULL if the command already
|
|
|
|
exists and is not overridable.
|
|
|
|
*/
|
|
|
|
void *
|
2003-06-03 06:01:47 +00:00
|
|
|
SV_AddUserCommand (const char *name, void (*func) (void *userdata), int flags,
|
|
|
|
void *userdata, void (*on_free) (void *userdata))
|
2002-07-05 06:43:47 +00:00
|
|
|
{
|
2003-04-28 15:56:09 +00:00
|
|
|
ucmd_t *cmd;
|
2002-07-05 06:43:47 +00:00
|
|
|
|
|
|
|
cmd = Hash_Find (ucmd_table, name);
|
2003-04-28 15:56:09 +00:00
|
|
|
if (cmd && !cmd->overridable)
|
|
|
|
return NULL;
|
|
|
|
|
2002-07-05 21:15:19 +00:00
|
|
|
cmd = calloc (1, sizeof (ucmd_t));
|
2002-07-05 06:43:47 +00:00
|
|
|
cmd->freeable = 1;
|
|
|
|
cmd->name = strdup (name);
|
2003-04-28 15:56:09 +00:00
|
|
|
cmd->func = func;
|
|
|
|
cmd->no_redirect = (flags & UCMD_NO_REDIRECT) ? 1 : 0;
|
|
|
|
cmd->overridable = (flags & UCMD_OVERRIDABLE) ? 1 : 0;
|
|
|
|
cmd->userdata = userdata;
|
|
|
|
cmd->on_free = on_free;
|
2002-07-05 06:43:47 +00:00
|
|
|
Hash_Add (ucmd_table, cmd);
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2003-04-28 15:56:09 +00:00
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-05-21 23:23:22 +00:00
|
|
|
Removes a user command added with SV_AddUserCommand. Returns true if
|
2003-04-28 15:56:09 +00:00
|
|
|
successful, false if not.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
SV_RemoveUserCommand (void *cmd)
|
|
|
|
{
|
|
|
|
void *ele = Hash_DelElement(ucmd_table, cmd);
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2003-04-28 15:56:09 +00:00
|
|
|
if (!ele)
|
|
|
|
return 0;
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2003-04-28 15:56:09 +00:00
|
|
|
Hash_Free (ucmd_table, ele);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-02-14 03:28:38 +00:00
|
|
|
PF_SV_AddUserCommand (progs_t *pr, void *data)
|
2003-04-28 15:56:09 +00:00
|
|
|
{
|
|
|
|
const char *name = P_GSTRING (pr, 0);
|
|
|
|
ucmd_t *cmd;
|
2012-05-21 23:23:22 +00:00
|
|
|
cmd = SV_AddUserCommand (name, call_qc_hook,
|
2003-04-28 15:56:09 +00:00
|
|
|
P_INT (pr, 2) ? UCMD_NO_REDIRECT : 0,
|
2007-04-04 07:48:14 +00:00
|
|
|
(void *) (intptr_t) P_FUNCTION (pr, 1),
|
2003-04-28 15:56:09 +00:00
|
|
|
NULL);
|
2012-05-21 23:23:22 +00:00
|
|
|
|
2003-04-28 15:56:09 +00:00
|
|
|
if (!cmd)
|
|
|
|
SV_Printf ("%s already a user command\n", name);
|
2002-07-05 06:43:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SV_SetupUserCommands (void)
|
|
|
|
{
|
2003-04-17 00:01:48 +00:00
|
|
|
size_t i;
|
2002-07-05 06:43:47 +00:00
|
|
|
|
|
|
|
Hash_FlushTable (ucmd_table);
|
|
|
|
for (i = 0; i < sizeof (ucmds) / sizeof (ucmds[0]); i++)
|
|
|
|
Hash_Add (ucmd_table, &ucmds[i]);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_ExecuteUserCommand
|
|
|
|
|
|
|
|
Uhh...execute user command. :)
|
|
|
|
*/
|
|
|
|
void
|
2001-07-15 07:04:17 +00:00
|
|
|
SV_ExecuteUserCommand (const char *s)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
|
|
|
ucmd_t *u;
|
|
|
|
|
2002-07-31 05:19:03 +00:00
|
|
|
COM_TokenizeString (s, sv_args);
|
|
|
|
cmd_args = sv_args;
|
2001-02-19 21:15:25 +00:00
|
|
|
sv_player = host_client->edict;
|
|
|
|
|
2002-07-31 05:19:03 +00:00
|
|
|
u = (ucmd_t*) Hash_Find (ucmd_table, sv_args->argv[0]->str);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (!u) {
|
2005-05-01 04:08:47 +00:00
|
|
|
if (!ucmd_unknown || !ucmd_unknown ()) {
|
2003-11-21 06:09:21 +00:00
|
|
|
SV_BeginRedirect (RD_CLIENT);
|
|
|
|
SV_Printf ("Bad user command: %s\n", sv_args->argv[0]->str);
|
|
|
|
SV_EndRedirect ();
|
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
} else {
|
|
|
|
if (!u->no_redirect)
|
|
|
|
SV_BeginRedirect (RD_CLIENT);
|
2003-12-06 05:06:27 +00:00
|
|
|
u->func (u->userdata);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (!u->no_redirect)
|
|
|
|
SV_EndRedirect ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
// USER CMD EXECUTION =========================================================
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
SV_CalcRoll
|
|
|
|
|
|
|
|
Used by view and sv_user
|
|
|
|
*/
|
2003-01-06 18:28:13 +00:00
|
|
|
static float
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_CalcRoll (vec3_t angles, vec3_t velocity)
|
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
vec3_t forward, right, up;
|
|
|
|
float side, sign, value;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
AngleVectors (angles, forward, right, up);
|
|
|
|
side = DotProduct (velocity, right);
|
|
|
|
sign = side < 0 ? -1 : 1;
|
|
|
|
side = fabs (side);
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
value = cl_rollangle;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (side < cl_rollspeed)
|
|
|
|
side = side * value / cl_rollspeed;
|
2001-02-19 21:15:25 +00:00
|
|
|
else
|
|
|
|
side = value;
|
|
|
|
|
|
|
|
return side * sign;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
vec3_t pmove_mins, pmove_maxs;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2001-02-19 21:15:25 +00:00
|
|
|
AddLinksToPmove (areanode_t *node)
|
|
|
|
{
|
|
|
|
edict_t *check;
|
2022-01-16 13:15:18 +00:00
|
|
|
pr_uint_t pl, i;
|
2002-08-22 23:04:44 +00:00
|
|
|
link_t *l, *next;
|
2001-02-19 21:15:25 +00:00
|
|
|
physent_t *pe;
|
|
|
|
|
|
|
|
pl = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
|
|
|
|
// touch linked edicts
|
|
|
|
for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) {
|
|
|
|
next = l->next;
|
|
|
|
check = EDICT_FROM_AREA (l);
|
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
if (SVentity (check, owner) == pl)
|
2001-02-19 21:15:25 +00:00
|
|
|
continue; // player's own missile
|
2001-08-08 20:28:53 +00:00
|
|
|
if (SVfloat (check, solid) == SOLID_BSP
|
2002-08-22 23:04:44 +00:00
|
|
|
|| SVfloat (check, solid) == SOLID_BBOX
|
|
|
|
|| SVfloat (check, solid) == SOLID_SLIDEBOX) {
|
2001-02-19 21:15:25 +00:00
|
|
|
if (check == sv_player)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
2001-08-08 20:28:53 +00:00
|
|
|
if (SVvector (check, absmin)[i] > pmove_maxs[i]
|
|
|
|
|| SVvector (check, absmax)[i] < pmove_mins[i])
|
2001-02-19 21:15:25 +00:00
|
|
|
break;
|
|
|
|
if (i != 3)
|
|
|
|
continue;
|
|
|
|
if (pmove.numphysent == MAX_PHYSENTS)
|
|
|
|
return;
|
|
|
|
pe = &pmove.physents[pmove.numphysent];
|
|
|
|
pmove.numphysent++;
|
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
VectorCopy (SVvector (check, origin), pe->origin);
|
2011-09-05 12:05:09 +00:00
|
|
|
VectorCopy (SVvector (check, angles), pe->angles);
|
2001-02-19 21:15:25 +00:00
|
|
|
pe->info = NUM_FOR_EDICT (&sv_pr_state, check);
|
|
|
|
|
2001-07-27 19:48:15 +00:00
|
|
|
if (sv_fields.rotated_bbox != -1
|
2022-01-18 04:21:06 +00:00
|
|
|
&& SVint (check, rotated_bbox)) {
|
|
|
|
int h = SVint (check, rotated_bbox) - 1;
|
2002-08-22 23:04:44 +00:00
|
|
|
|
2001-07-30 04:33:59 +00:00
|
|
|
pe->hull = pf_hull_list[h]->hulls[1];
|
2001-02-19 21:15:25 +00:00
|
|
|
} else {
|
2001-07-27 19:48:15 +00:00
|
|
|
pe->hull = 0;
|
2001-08-08 20:28:53 +00:00
|
|
|
if (SVfloat (check, solid) == SOLID_BSP) {
|
|
|
|
pe->model = sv.models[(int) (SVfloat (check, modelindex))];
|
2001-07-27 02:45:01 +00:00
|
|
|
} else {
|
2001-07-27 19:48:15 +00:00
|
|
|
pe->model = NULL;
|
2001-08-08 20:28:53 +00:00
|
|
|
VectorCopy (SVvector (check, mins), pe->mins);
|
|
|
|
VectorCopy (SVvector (check, maxs), pe->maxs);
|
2001-07-26 21:37:34 +00:00
|
|
|
}
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// recurse down both sides
|
|
|
|
if (node->axis == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (pmove_maxs[node->axis] > node->dist)
|
|
|
|
AddLinksToPmove (node->children[0]);
|
|
|
|
|
|
|
|
if (pmove_mins[node->axis] < node->dist)
|
|
|
|
AddLinksToPmove (node->children[1]);
|
|
|
|
}
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
byte playertouch[(MAX_EDICTS + 7) / 8];
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
/*
|
|
|
|
SV_PreRunCmd
|
|
|
|
|
|
|
|
Done before running a player command. Clears the touch array
|
|
|
|
*/
|
2003-03-10 16:39:40 +00:00
|
|
|
void
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_PreRunCmd (void)
|
|
|
|
{
|
|
|
|
memset (playertouch, 0, sizeof (playertouch));
|
|
|
|
}
|
|
|
|
|
2002-09-27 03:32:20 +00:00
|
|
|
static void
|
|
|
|
adjust_usecs (usercmd_t *ucmd)
|
|
|
|
{
|
|
|
|
int passed;
|
|
|
|
|
|
|
|
if (host_client->last_check == -1.0)
|
|
|
|
return;
|
|
|
|
passed = (int) ((realtime - host_client->last_check) * 1000.0);
|
|
|
|
host_client->msecs += passed - ucmd->msec;
|
|
|
|
if (host_client->msecs >= 0) {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
host_client->msecs -= sv_timecheck_decay;
|
2002-09-27 03:32:20 +00:00
|
|
|
} else {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
host_client->msecs += sv_timecheck_decay;
|
2002-09-27 03:32:20 +00:00
|
|
|
}
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (abs (host_client->msecs) > sv_timecheck_fuzz) {
|
|
|
|
int fuzz = sv_timecheck_fuzz;
|
2002-09-27 03:32:20 +00:00
|
|
|
host_client->msecs = bound (-fuzz, host_client->msecs, fuzz);
|
|
|
|
ucmd->msec = passed;
|
|
|
|
}
|
2003-01-10 18:09:09 +00:00
|
|
|
host_client->last_check = realtime;
|
2002-09-27 03:32:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_usecs (usercmd_t *ucmd)
|
|
|
|
{
|
|
|
|
double tmp_time;
|
|
|
|
int tmp_time1;
|
|
|
|
|
|
|
|
host_client->msecs += ucmd->msec;
|
|
|
|
if (host_client->spectator)
|
|
|
|
return;
|
|
|
|
if (host_client->last_check == -1.0)
|
|
|
|
return;
|
|
|
|
tmp_time = realtime - host_client->last_check;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (tmp_time < sv_timekick_interval)
|
2002-09-27 03:32:20 +00:00
|
|
|
return;
|
2003-01-10 18:09:09 +00:00
|
|
|
host_client->last_check = realtime;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
tmp_time1 = tmp_time * (1000 + sv_timekick_fuzz);
|
2003-01-10 18:09:09 +00:00
|
|
|
if (host_client->msecs >= tmp_time1) {
|
|
|
|
host_client->msec_cheating++;
|
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "%s thinks there are %d ms "
|
|
|
|
"in %d seconds (Strike %d/%d)\n",
|
|
|
|
host_client->name, host_client->msecs,
|
|
|
|
(int) tmp_time, host_client->msec_cheating,
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
sv_timekick);
|
|
|
|
if (host_client->msec_cheating >= sv_timekick) {
|
2003-01-10 18:09:09 +00:00
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "Strike %d for %s!!\n",
|
|
|
|
host_client->msec_cheating, host_client->name);
|
|
|
|
SV_BroadcastPrintf (PRINT_HIGH, "Please see "
|
|
|
|
"http://www.quakeforge.net/speed_cheat.php "
|
|
|
|
"for information on QuakeForge's time cheat "
|
|
|
|
"protection. That page explains how some may "
|
|
|
|
"be cheating without knowing it.\n");
|
|
|
|
SV_DropClient (host_client);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
host_client->msecs = 0;
|
2002-09-27 03:32:20 +00:00
|
|
|
}
|
|
|
|
|
2003-03-10 16:39:40 +00:00
|
|
|
void
|
2023-06-13 09:06:11 +00:00
|
|
|
SV_RunCmd (usercmd_t *ucmd, bool inside)
|
2001-02-19 21:15:25 +00:00
|
|
|
{
|
2002-09-27 03:32:20 +00:00
|
|
|
int oldmsec, i, n;
|
2001-02-19 21:15:25 +00:00
|
|
|
edict_t *ent;
|
|
|
|
|
2002-09-12 04:57:40 +00:00
|
|
|
if (!inside) {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (sv_timecheck_mode) {
|
2002-09-27 03:32:20 +00:00
|
|
|
adjust_usecs (ucmd);
|
|
|
|
} else {
|
|
|
|
check_usecs (ucmd);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2003-01-10 18:09:09 +00:00
|
|
|
if (host_client->last_check == -1.0)
|
|
|
|
host_client->last_check = realtime;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cmd = *ucmd;
|
|
|
|
|
|
|
|
// chop up very long commands
|
|
|
|
if (cmd.msec > 50) {
|
|
|
|
oldmsec = ucmd->msec;
|
|
|
|
cmd.msec = oldmsec / 2;
|
|
|
|
SV_RunCmd (&cmd, 1);
|
|
|
|
cmd.msec = oldmsec / 2;
|
|
|
|
cmd.impulse = 0;
|
|
|
|
SV_RunCmd (&cmd, 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
if (!SVfloat (sv_player, fixangle))
|
|
|
|
VectorCopy (ucmd->angles, SVvector (sv_player, v_angle));
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
SVfloat (sv_player, button0) = ucmd->buttons & 1;
|
2001-02-19 21:15:25 +00:00
|
|
|
// 1999-10-29 +USE fix by Maddes start
|
|
|
|
if (!nouse) {
|
2001-08-08 20:28:53 +00:00
|
|
|
SVfloat (sv_player, button1) = (ucmd->buttons & 4) >> 2;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
// 1999-10-29 +USE fix by Maddes end
|
2001-08-08 20:28:53 +00:00
|
|
|
SVfloat (sv_player, button2) = (ucmd->buttons & 2) >> 1;
|
2001-02-19 21:15:25 +00:00
|
|
|
if (ucmd->impulse)
|
2001-08-08 20:28:53 +00:00
|
|
|
SVfloat (sv_player, impulse) = ucmd->impulse;
|
2002-06-20 16:15:27 +00:00
|
|
|
if (host_client->cuff_time > realtime)
|
2001-09-09 04:51:08 +00:00
|
|
|
SVfloat (sv_player, button0) = SVfloat (sv_player, impulse) = 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// angles
|
|
|
|
// show 1/3 the pitch angle and all the roll angle
|
2003-03-10 16:39:40 +00:00
|
|
|
if (SVfloat (sv_player, health) > 0) { //FIXME hardcoded mod info
|
2001-08-08 20:28:53 +00:00
|
|
|
if (!SVfloat (sv_player, fixangle)) {
|
2002-08-22 23:04:44 +00:00
|
|
|
SVvector (sv_player, angles)[PITCH] =
|
|
|
|
-SVvector (sv_player, v_angle)[PITCH] / 3;
|
|
|
|
SVvector (sv_player, angles)[YAW] =
|
|
|
|
SVvector (sv_player, v_angle)[YAW];
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2001-08-08 20:28:53 +00:00
|
|
|
SVvector (sv_player, angles)[ROLL] =
|
2002-08-22 23:04:44 +00:00
|
|
|
SV_CalcRoll (SVvector (sv_player, angles),
|
|
|
|
SVvector (sv_player, velocity)) * 4;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sv_frametime = min (0.1, ucmd->msec * 0.001);
|
|
|
|
|
|
|
|
if (!host_client->spectator) {
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.frametime = sv_frametime;
|
|
|
|
*sv_globals.time = sv.time;
|
2002-05-31 21:05:58 +00:00
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.PlayerPreThink);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
SV_RunThink (sv_player);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++)
|
2002-08-22 23:04:44 +00:00
|
|
|
pmove.origin[i] = SVvector (sv_player, origin)[i]
|
2001-08-08 20:28:53 +00:00
|
|
|
+ (SVvector (sv_player, mins)[i] - player_mins[i]);
|
|
|
|
VectorCopy (SVvector (sv_player, velocity), pmove.velocity);
|
|
|
|
VectorCopy (SVvector (sv_player, v_angle), pmove.angles);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
pmove.flying = SVfloat (sv_player, movetype) == MOVETYPE_FLY;
|
2001-02-19 21:15:25 +00:00
|
|
|
pmove.spectator = host_client->spectator;
|
2001-08-08 20:28:53 +00:00
|
|
|
pmove.waterjumptime = SVfloat (sv_player, teleport_time);
|
2003-08-27 23:11:57 +00:00
|
|
|
if (pmove.waterjumptime)
|
|
|
|
pmove.waterjumptime -= sv.time;
|
2001-02-19 21:15:25 +00:00
|
|
|
pmove.numphysent = 1;
|
|
|
|
pmove.physents[0].model = sv.worldmodel;
|
|
|
|
pmove.cmd = *ucmd;
|
2001-08-08 20:28:53 +00:00
|
|
|
pmove.dead = SVfloat (sv_player, health) <= 0;
|
2001-02-19 21:15:25 +00:00
|
|
|
pmove.oldbuttons = host_client->oldbuttons;
|
2002-09-13 04:30:18 +00:00
|
|
|
pmove.oldonground = host_client->oldonground;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
movevars.entgravity = host_client->entgravity;
|
|
|
|
movevars.maxspeed = host_client->maxspeed;
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
pmove_mins[i] = pmove.origin[i] - 256;
|
|
|
|
pmove_maxs[i] = pmove.origin[i] + 256;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
AddAllEntsToPmove ();
|
|
|
|
#else
|
|
|
|
AddLinksToPmove (sv_areanodes);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
int before, after;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
before = PM_TestPlayerPosition (pmove.origin);
|
|
|
|
PlayerMove ();
|
|
|
|
after = PM_TestPlayerPosition (pmove.origin);
|
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
if (SVfloat (sv_player, health) > 0 && before && !after)
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("player %s got stuck in playermove!!!!\n",
|
2001-02-19 21:15:25 +00:00
|
|
|
host_client->name);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
PlayerMove ();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
host_client->oldbuttons = pmove.oldbuttons;
|
2002-09-13 04:30:18 +00:00
|
|
|
host_client->oldonground = pmove.oldonground;
|
2003-08-27 23:11:57 +00:00
|
|
|
if (pmove.waterjumptime > 0)
|
|
|
|
pmove.waterjumptime += sv.time;
|
|
|
|
else
|
|
|
|
pmove.waterjumptime = 0;
|
2001-08-08 20:28:53 +00:00
|
|
|
SVfloat (sv_player, teleport_time) = pmove.waterjumptime;
|
|
|
|
SVfloat (sv_player, waterlevel) = waterlevel;
|
|
|
|
SVfloat (sv_player, watertype) = watertype;
|
2001-02-19 21:15:25 +00:00
|
|
|
if (onground != -1) {
|
2002-08-22 23:04:44 +00:00
|
|
|
SVfloat (sv_player, flags) = (int) SVfloat (sv_player, flags) |
|
|
|
|
FL_ONGROUND;
|
2001-08-08 20:28:53 +00:00
|
|
|
SVentity (sv_player, groundentity) =
|
2002-08-22 23:04:44 +00:00
|
|
|
EDICT_TO_PROG (&sv_pr_state,
|
|
|
|
EDICT_NUM (&sv_pr_state,
|
|
|
|
pmove.physents[onground].info));
|
2001-02-19 21:15:25 +00:00
|
|
|
} else {
|
2002-08-22 23:04:44 +00:00
|
|
|
SVfloat (sv_player, flags) =
|
|
|
|
(int) SVfloat (sv_player, flags) & ~FL_ONGROUND;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < 3; i++)
|
2001-08-08 20:28:53 +00:00
|
|
|
SVvector (sv_player, origin)[i] =
|
|
|
|
pmove.origin[i] - (SVvector (sv_player, mins)[i] - player_mins[i]);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
// truncate velocity the same way the net protocol will
|
|
|
|
for (i = 0; i < 3; i++)
|
2001-08-08 20:28:53 +00:00
|
|
|
SVvector (sv_player, velocity)[i] = (int) pmove.velocity[i];
|
2001-02-19 21:15:25 +00:00
|
|
|
#else
|
2001-08-08 20:28:53 +00:00
|
|
|
VectorCopy (pmove.velocity, SVvector (sv_player, velocity));
|
2001-02-19 21:15:25 +00:00
|
|
|
#endif
|
|
|
|
|
2001-08-08 20:28:53 +00:00
|
|
|
VectorCopy (pmove.angles, SVvector (sv_player, v_angle));
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (!host_client->spectator) {
|
|
|
|
// link into place and touch triggers
|
|
|
|
SV_LinkEdict (sv_player, true);
|
|
|
|
|
|
|
|
// touch other objects
|
|
|
|
for (i = 0; i < pmove.numtouch; i++) {
|
2004-11-02 08:40:00 +00:00
|
|
|
n = pmove.touchindex[i]->info;
|
2001-02-19 21:15:25 +00:00
|
|
|
ent = EDICT_NUM (&sv_pr_state, n);
|
2001-08-08 20:28:53 +00:00
|
|
|
if (!SVfunc (ent, touch) || (playertouch[n / 8] & (1 << (n % 8))))
|
2001-02-19 21:15:25 +00:00
|
|
|
continue;
|
2002-05-31 21:05:58 +00:00
|
|
|
sv_pr_touch (ent, sv_player);
|
2001-02-19 21:15:25 +00:00
|
|
|
playertouch[n / 8] |= 1 << (n % 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_PostRunCmd
|
|
|
|
|
|
|
|
Done after running a player command.
|
|
|
|
*/
|
2003-03-10 16:39:40 +00:00
|
|
|
void
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_PostRunCmd (void)
|
|
|
|
{
|
|
|
|
// run post-think
|
|
|
|
|
|
|
|
if (!host_client->spectator) {
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.time = sv.time;
|
2002-05-31 21:05:58 +00:00
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.PlayerPostThink);
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_RunNewmis ();
|
2003-11-21 06:09:21 +00:00
|
|
|
} else if (sv_funcs.SpectatorThink) {
|
2001-03-01 08:34:30 +00:00
|
|
|
*sv_globals.time = sv.time;
|
2002-05-31 21:05:58 +00:00
|
|
|
*sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player);
|
2003-11-21 06:09:21 +00:00
|
|
|
PR_ExecuteProgram (&sv_pr_state, sv_funcs.SpectatorThink);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
SV_ExecuteClientMessage
|
|
|
|
|
|
|
|
The current net_message is parsed for the given client
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
SV_ExecuteClientMessage (client_t *cl)
|
|
|
|
{
|
2002-08-22 23:04:44 +00:00
|
|
|
byte checksum, calculatedChecksum;
|
2001-10-18 04:44:58 +00:00
|
|
|
const char *s;
|
2001-02-19 21:15:25 +00:00
|
|
|
client_frame_t *frame;
|
2002-08-22 23:04:44 +00:00
|
|
|
int checksumIndex, seq_hash, c;
|
|
|
|
usercmd_t oldest, oldcmd, newcmd;
|
2023-06-13 09:06:11 +00:00
|
|
|
bool move_issued = false; // allow only one move command
|
2002-08-22 23:04:44 +00:00
|
|
|
vec3_t o;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// make sure the reply sequence number matches the incoming
|
2012-05-21 23:23:22 +00:00
|
|
|
// sequence number
|
2001-02-19 21:15:25 +00:00
|
|
|
if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
|
|
|
|
cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
|
|
|
|
else
|
2002-08-22 23:04:44 +00:00
|
|
|
cl->send_message = false; // don't reply, sequences have slipped
|
2010-12-22 04:10:27 +00:00
|
|
|
|
|
|
|
// setup delta information
|
|
|
|
cl->delta.cur_frame = cl->netchan.incoming_acknowledged & UPDATE_MASK;
|
|
|
|
cl->delta.out_frame = cl->netchan.outgoing_sequence & UPDATE_MASK;
|
|
|
|
cl->delta.in_frame = cl->netchan.incoming_sequence & UPDATE_MASK;
|
|
|
|
|
|
|
|
// calc ping time
|
|
|
|
frame = &cl->delta.frames[cl->delta.cur_frame];
|
|
|
|
frame->ping_time = realtime - frame->senttime;
|
|
|
|
|
2012-06-28 07:03:56 +00:00
|
|
|
cl->laggedents_count = 0;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (sv_antilag) {
|
2012-06-28 07:03:56 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_CLIENTS; i++) {
|
|
|
|
cl->laggedents[i].present = frame->playerpresent[i];
|
|
|
|
if (cl->laggedents[i].present) {
|
|
|
|
VectorCopy(frame->playerpositions[i],
|
|
|
|
cl->laggedents[i].laggedpos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cl->laggedents_count = MAX_CLIENTS;
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
cl->laggedents_frac = sv_antilag_frac;
|
2012-06-28 07:03:56 +00:00
|
|
|
}
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
// save time for ping calculations
|
2005-04-30 08:45:17 +00:00
|
|
|
cl->delta.frames[cl->delta.out_frame].senttime = realtime;
|
|
|
|
cl->delta.frames[cl->delta.out_frame].ping_time = -1;
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
host_client = cl;
|
|
|
|
sv_player = host_client->edict;
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
// seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
|
2001-02-19 21:15:25 +00:00
|
|
|
seq_hash = cl->netchan.incoming_sequence;
|
|
|
|
|
2002-08-22 23:04:44 +00:00
|
|
|
// mark time so clients will know how much to predict other players
|
2001-02-19 21:15:25 +00:00
|
|
|
cl->localtime = sv.time;
|
2005-04-30 08:45:17 +00:00
|
|
|
cl->delta.delta_sequence = -1; // no delta unless requested
|
2001-02-19 21:15:25 +00:00
|
|
|
while (1) {
|
2001-02-23 23:16:13 +00:00
|
|
|
if (net_message->badread) {
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_ReadClientMessage: badread\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_DropClient (cl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-23 23:16:13 +00:00
|
|
|
c = MSG_ReadByte (net_message);
|
2001-02-19 21:15:25 +00:00
|
|
|
if (c == -1)
|
|
|
|
return; // Ender: Patched :)
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
default:
|
2001-07-11 23:11:29 +00:00
|
|
|
SV_Printf ("SV_ReadClientMessage: unknown command char\n");
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_DropClient (cl);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case clc_nop:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case clc_delta:
|
2005-04-30 08:45:17 +00:00
|
|
|
cl->delta.delta_sequence = MSG_ReadByte (net_message);
|
2001-02-19 21:15:25 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case clc_move:
|
|
|
|
if (move_issued)
|
|
|
|
return; // someone is trying to cheat...
|
|
|
|
|
|
|
|
move_issued = true;
|
|
|
|
|
2001-02-23 23:16:13 +00:00
|
|
|
checksumIndex = MSG_GetReadCount (net_message);
|
|
|
|
checksum = (byte) MSG_ReadByte (net_message);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
// read loss percentage
|
2001-02-23 23:16:13 +00:00
|
|
|
cl->lossage = MSG_ReadByte (net_message);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
2005-04-27 12:16:15 +00:00
|
|
|
MSG_ReadDeltaUsercmd (net_message, &nullcmd, &oldest);
|
|
|
|
MSG_ReadDeltaUsercmd (net_message, &oldest, &oldcmd);
|
|
|
|
MSG_ReadDeltaUsercmd (net_message, &oldcmd, &newcmd);
|
2001-02-19 21:15:25 +00:00
|
|
|
|
|
|
|
if (cl->state != cs_spawned)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// if the checksum fails, ignore the rest of the packet
|
|
|
|
calculatedChecksum =
|
2002-08-22 23:04:44 +00:00
|
|
|
COM_BlockSequenceCRCByte (net_message->message->data +
|
|
|
|
checksumIndex + 1,
|
2001-02-23 23:16:13 +00:00
|
|
|
MSG_GetReadCount (net_message) -
|
2001-02-19 21:15:25 +00:00
|
|
|
checksumIndex - 1, seq_hash);
|
|
|
|
|
|
|
|
if (calculatedChecksum != checksum) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_dev,
|
2010-11-23 05:09:30 +00:00
|
|
|
"Failed command checksum for %s(%d) "
|
|
|
|
"(%d != %d)\n",
|
|
|
|
cl->name, cl->netchan.incoming_sequence,
|
|
|
|
checksum, calculatedChecksum);
|
2001-02-19 21:15:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sv.paused) {
|
|
|
|
SV_PreRunCmd ();
|
|
|
|
|
2005-05-08 06:35:46 +00:00
|
|
|
if (cl->netchan.net_drop < 20) {
|
|
|
|
while (cl->netchan.net_drop > 2) {
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_RunCmd (&cl->lastcmd, 0);
|
2005-05-08 06:35:46 +00:00
|
|
|
cl->netchan.net_drop--;
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2005-05-08 06:35:46 +00:00
|
|
|
if (cl->netchan.net_drop > 1)
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_RunCmd (&oldest, 0);
|
2005-05-08 06:35:46 +00:00
|
|
|
if (cl->netchan.net_drop > 0)
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_RunCmd (&oldcmd, 0);
|
|
|
|
}
|
|
|
|
SV_RunCmd (&newcmd, 0);
|
|
|
|
|
|
|
|
SV_PostRunCmd ();
|
|
|
|
}
|
|
|
|
|
|
|
|
cl->lastcmd = newcmd;
|
|
|
|
cl->lastcmd.buttons = 0; // avoid multiple fires on lag
|
|
|
|
break;
|
|
|
|
|
|
|
|
case clc_stringcmd:
|
2001-02-23 23:16:13 +00:00
|
|
|
s = MSG_ReadString (net_message);
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_ExecuteUserCommand (s);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case clc_tmove:
|
2001-12-12 21:56:09 +00:00
|
|
|
MSG_ReadCoordV (net_message, o);
|
2010-01-13 06:42:26 +00:00
|
|
|
// allowed for only spectators
|
2001-02-19 21:15:25 +00:00
|
|
|
if (host_client->spectator) {
|
2001-08-08 20:28:53 +00:00
|
|
|
VectorCopy (o, SVvector (sv_player, origin));
|
2001-02-19 21:15:25 +00:00
|
|
|
SV_LinkEdict (sv_player, false);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case clc_upload:
|
|
|
|
SV_NextUpload ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 12:54:03 +00:00
|
|
|
#define bi(x,np,params...) {#x, PF_##x, -1, np, {params}}
|
|
|
|
#define p(type) PR_PARAM(type)
|
|
|
|
#define P(a, s) { .size = (s), .alignment = BITOP_LOG2 (a), }
|
2004-01-06 05:51:09 +00:00
|
|
|
static builtin_t builtins[] = {
|
2022-01-23 12:54:03 +00:00
|
|
|
bi(SV_AddUserCommand, 3, p(string), p(func), p(int)),
|
2004-01-06 05:51:09 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
static void
|
|
|
|
SV_MaxRate_f (void *data, const cvar_t *cvar)
|
|
|
|
{
|
|
|
|
client_t *cl;
|
|
|
|
int maxrate = sv_maxrate;
|
|
|
|
int i, rate = 2500;
|
|
|
|
const char *val;
|
|
|
|
|
|
|
|
Cvar_Info (data, cvar);
|
|
|
|
for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) {
|
|
|
|
if (!cl->userinfo)
|
|
|
|
continue;
|
|
|
|
val = Info_ValueForKey (cl->userinfo, "rate");
|
|
|
|
if (strlen (val)) {
|
|
|
|
rate = atoi (val);
|
|
|
|
|
|
|
|
if (maxrate) {
|
|
|
|
rate = bound (500, rate, maxrate);
|
|
|
|
} else {
|
|
|
|
rate = max (500, rate);
|
|
|
|
}
|
|
|
|
cl->netchan.rate = 1.0 / rate;
|
|
|
|
}
|
|
|
|
SV_ClientPrintf (1, cl, PRINT_HIGH, "Net rate set to %i\n", rate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-19 21:15:25 +00:00
|
|
|
void
|
|
|
|
SV_UserInit (void)
|
|
|
|
{
|
2020-03-25 06:43:16 +00:00
|
|
|
ucmd_table = Hash_NewTable (251, ucmds_getkey, ucmds_free, 0, 0);
|
2003-04-28 19:55:03 +00:00
|
|
|
Hash_SetHashCompare (ucmd_table, ucmd_get_hash, ucmd_compare);
|
2022-01-23 15:20:05 +00:00
|
|
|
PR_RegisterBuiltins (&sv_pr_state, builtins, 0);
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
Cvar_Register (&cl_rollspeed_cvar, 0, 0);
|
|
|
|
Cvar_Register (&cl_rollangle_cvar, 0, 0);
|
|
|
|
|
|
|
|
Cvar_Register (&sv_antilag_cvar, Cvar_Info, &sv_antilag);
|
|
|
|
Cvar_Register (&sv_antilag_frac_cvar, Cvar_Info, &sv_antilag_frac);
|
|
|
|
|
|
|
|
Cvar_Register (&sv_allowfake_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_spectalk_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_mapcheck_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_timecheck_mode_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_timekick_cvar, Cvar_Info, &sv_timekick);
|
|
|
|
Cvar_Register (&sv_timekick_fuzz_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_timekick_interval_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_timecheck_fuzz_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_timecheck_decay_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_kickfake_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_http_url_base_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_maxrate_cvar, SV_MaxRate_f, 0);
|
|
|
|
Cvar_Register (&sv_maxspeed_cvar, Cvar_Info, &sv_maxspeed);
|
|
|
|
Cvar_Register (&sv_spectatormaxspeed_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_accelerate_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_airaccelerate_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_wateraccelerate_cvar, 0, 0);
|
|
|
|
Cvar_Register (&sv_waterfriction_cvar, 0, 0);
|
2001-02-19 21:15:25 +00:00
|
|
|
}
|
2003-05-07 04:24:50 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
OutofBandPrintf (netadr_t where, const char *fmt, ...)
|
|
|
|
{
|
2011-09-07 01:35:42 +00:00
|
|
|
// 0 for davsprintf
|
|
|
|
static const char header[] = {0xff, 0xff, 0xff, 0xff, A2C_PRINT, 0};
|
|
|
|
static dstring_t *send = 0;
|
2003-05-07 04:24:50 +00:00
|
|
|
va_list argptr;
|
2011-09-07 01:35:42 +00:00
|
|
|
int len;
|
2003-05-07 04:24:50 +00:00
|
|
|
|
2011-09-07 01:35:42 +00:00
|
|
|
if (!send)
|
|
|
|
send = dstring_new ();
|
|
|
|
send->size = sizeof (header);
|
|
|
|
dstring_adjust (send);
|
|
|
|
memcpy (send->str, header, sizeof (header));
|
2003-05-07 04:24:50 +00:00
|
|
|
va_start (argptr, fmt);
|
2011-09-07 01:35:42 +00:00
|
|
|
davsprintf (send, fmt, argptr);
|
2003-05-07 04:24:50 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
2011-09-07 01:35:42 +00:00
|
|
|
len = min (send->size, 1024);
|
|
|
|
Netchan_SendPacket (len, send->str, where);
|
2003-05-07 04:24:50 +00:00
|
|
|
}
|