UFO: Alien Invasion
Loading...
Searching...
No Matches
sv_user.cpp
Go to the documentation of this file.
1
5
6/*
7All original material Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9Original file from Quake 2 v3.21: quake2-2.31/server/sv_users.c
10Copyright (C) 1997-2001 Id Software, Inc.
11
12This program is free software; you can redistribute it and/or
13modify it under the terms of the GNU General Public License
14as published by the Free Software Foundation; either version 2
15of the License, or (at your option) any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20
21See the GNU General Public License for more details.
22
23You should have received a copy of the GNU General Public License
24along with this program; if not, write to the Free Software
25Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27*/
28
29#include "server.h"
31
37{
38 assert(client);
39 Com_DPrintf(DEBUG_SERVER, "Set state for client '%s' to %i\n", client->name, state);
40 client->state = state;
41}
42
43/*
44============================================================
45USER STRINGCMD EXECUTION
46============================================================
47*/
48
56static void SV_New_f (client_t* cl)
57{
58 Com_DPrintf(DEBUG_SERVER, "New() from %s\n", cl->name);
59
60 if (cl->state != cs_connected) {
61 if (cl->state == cs_spawning) {
62 /* client typed 'reconnect/new' while connecting. */
63 Com_Printf("SV_New_f: client typed 'reconnect/new' while connecting\n");
64 SV_ClientCommand(cl, "\ndisconnect\nreconnect\n");
65 SV_DropClient(cl, "");
66 } else
67 Com_DPrintf(DEBUG_SERVER, "WARNING: Illegal 'new' from %s, client state %d. This shouldn't happen...\n", cl->name, cl->state);
68 return;
69 }
70
71 /* client state to prevent multiple new from causing high cpu / overflows. */
73
74 /* serverdata needs to go over for all types of servers
75 * to make sure the protocol is right, and to set the gamedir */
76
77 /* send the serverdata */
78 {
79 const int playernum = cl - SV_GetClient(0);
80 dbuffer msg;
83
84 NET_WriteShort(&msg, playernum);
85
86 /* send full levelname */
88
89 NET_WriteMsg(cl->stream, msg);
90 }
91
92 /* game server */
93 if (Com_ServerState() == ss_game) {
94 for (int i = 0; i < MAX_CONFIGSTRINGS; i++) {
95 /* CS_TILES and CS_POSITIONS can stretch over multiple configstrings,
96 * so don't send the middle parts again. */
97 if (i > CS_TILES && i < CS_POSITIONS)
98 continue;
99 if (i > CS_POSITIONS && i < CS_MODELS)
100 continue;
101
102 const char* configString = SV_GetConfigString(i);
103 if (!Q_strvalid(configString))
104 continue;
105
106 Com_DPrintf(DEBUG_SERVER, "sending configstring %d: %s\n", i, configString);
107
108 dbuffer msg;
110 NET_WriteShort(&msg, i);
111 NET_WriteString(&msg, configString);
112 /* enqueue and free msg */
113 NET_WriteMsg(cl->stream, msg);
114 }
115 }
116
118}
119
123static void SV_Begin_f (client_t* cl)
124{
125 bool began;
126
127 Com_DPrintf(DEBUG_SERVER, "Begin() from %s\n", cl->name);
128
129 /* could be abused to respawn or cause spam/other mod-specific problems */
130 if (cl->state != cs_spawning) {
131 Com_Printf("EXPLOIT: Illegal 'begin' from %s (already spawned), client dropped.\n", cl->name);
132 SV_DropClient(cl, "Illegal begin\n");
133 return;
134 }
135
136 /* call the game begin function */
137 {
138 ScopedMutex scopedMutex(svs.serverMutex);
139 began = svs.ge->ClientBegin(*cl->player);
140 }
141
142 if (!began) {
143 SV_DropClient(cl, "'begin' failed\n");
144 return;
145 }
147
149}
150
155{
156 Com_DPrintf(DEBUG_SERVER, "StartMatch() from %s\n", cl->name);
157
158 if (cl->state != cs_spawned) {
159 SV_DropClient(cl, "Invalid state\n");
160 return;
161 }
162
163 {
164 ScopedMutex scopedMutex(svs.serverMutex);
165 svs.ge->ClientStartMatch(*cl->player);
166 }
167
169}
170
171/*============================================================================ */
172
177{
178 SV_DropClient(cl, "Disconnect\n");
179}
180
181
186{
187 char info[MAX_INFO_STRING];
188 Info_Print(Cvar_Serverinfo(info, sizeof(info)));
189}
190
191
192typedef struct {
193 const char* name;
194 void (*func) (client_t* client);
195} ucmd_t;
196
197static const ucmd_t ucmds[] = {
198 /* auto issued */
202
204
205 /* issued by hand at client consoles */
207
208 {nullptr, nullptr}
209};
210
214static void SV_ExecuteUserCommand (client_t* cl, const char* s)
215{
216 Cmd_TokenizeString(s, false, false);
217
218 for (const ucmd_t* u = ucmds; u->name; u++)
219 if (Q_streq(Cmd_Argv(0), u->name)) {
220 Com_DPrintf(DEBUG_SERVER, "SV_ExecuteUserCommand: %s\n", s);
221 u->func(cl);
222 return;
223 }
224
225 if (Com_ServerState() == ss_game) {
226 Com_DPrintf(DEBUG_SERVER, "SV_ExecuteUserCommand: client command: %s\n", s);
227 ScopedMutex scopedMutex(svs.serverMutex);
228 svs.ge->ClientCommand(*cl->player);
229 }
230}
231
236{
237 if (cmd == -1)
238 return;
239
240 switch (cmd) {
241 default:
242 Com_Printf("SV_ExecuteClientMessage: unknown command char '%d'\n", cmd);
243 SV_DropClient(cl, "Unknown command\n");
244 return;
245
246 case clc_nop:
247 break;
248
249 case clc_ack:
250 cl->lastmessage = svs.realtime;
251 break;
252
253 case clc_userinfo:
254 NET_ReadString(msg, cl->userinfo, sizeof(cl->userinfo));
255 Com_DPrintf(DEBUG_SERVER, "userinfo from client: %s\n", cl->userinfo);
257 break;
258
259 case clc_stringcmd: {
260 char str[MAX_CLC_STRINGCMD];
261 NET_ReadString(msg, str, sizeof(str));
262
263 Com_DPrintf(DEBUG_SERVER, "stringcmd from client: %s\n", str);
265
266 if (cl->state == cs_free)
267 return; /* disconnect command */
268 break;
269 }
270
271 case clc_action: {
272 /* client actions are handled by the game module */
273 ScopedMutex scopedMutex(svs.serverMutex);
274 sv->messageBuffer = msg;
275 svs.ge->ClientAction(*cl->player);
276 sv->messageBuffer = nullptr;
277 break;
278 }
279
280 case clc_endround: {
281 /* player wants to end round */
282 ScopedMutex scopedMutex(svs.serverMutex);
283 sv->messageBuffer = msg;
284 svs.ge->ClientEndRound(*cl->player);
285 sv->messageBuffer = nullptr;
286 break;
287 }
288
289 case clc_teaminfo: {
290 /* player sends team info */
291 /* actors spawn accordingly */
292 ScopedMutex scopedMutex(svs.serverMutex);
293 sv->messageBuffer = msg;
294 svs.ge->ClientTeamInfo(*cl->player);
295 sv->messageBuffer = nullptr;
297 break;
298 }
299
300 case clc_initactorstates: {
301 /* player sends team info */
302 /* actors spawn accordingly */
303 ScopedMutex scopedMutex(svs.serverMutex);
304 sv->messageBuffer = msg;
305 svs.ge->ClientInitActorStates(*cl->player);
306 sv->messageBuffer = nullptr;
307 break;
308 }
309 }
310}
311
313{
314 return sv->state;
315}
316
318{
319 sv->state = state;
320}
clientBattleScape_t cl
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition cmd.cpp:516
void Cmd_TokenizeString(const char *text, bool macroExpand, bool replaceWhitespaces)
Parses the given string into command line tokens.
Definition cmd.cpp:565
void Cbuf_InsertFromDefer(void)
Copies back any deferred commands.
Definition cmd.cpp:201
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition common.cpp:440
int Com_ServerState(void)
Check whether we are the server or have a singleplayer tactical mission.
Definition common.cpp:578
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
@ clc_stringcmd
Definition common.h:181
@ clc_teaminfo
Definition common.h:177
@ clc_action
Definition common.h:179
@ clc_userinfo
Definition common.h:180
@ clc_nop
Definition common.h:174
@ clc_ack
Definition common.h:175
@ clc_initactorstates
Definition common.h:178
@ clc_endround
Definition common.h:176
#define PROTOCOL_VERSION
Definition common.h:134
@ svc_configstring
Definition common.h:154
@ svc_serverdata
Definition common.h:153
#define MAX_CLC_STRINGCMD
Definition common.h:163
const char * Cvar_Serverinfo(char *info, size_t infoSize)
Returns an info string containing all the CVAR_SERVERINFO cvars.
Definition cvar.cpp:977
#define DEBUG_SERVER
Definition defines.h:60
void Info_Print(const char *s)
Prints info strings (like userinfo or serverinfo - CVAR_USERINFO, CVAR_SERVERINFO).
#define MAX_INFO_STRING
Definition infostring.h:36
int NET_ReadString(dbuffer *buf, char *string, size_t length)
Definition netpack.cpp:302
void NET_WriteShort(dbuffer *buf, int c)
Definition netpack.cpp:45
void NET_WriteMsg(struct net_stream *s, dbuffer &buf)
Enqueue the buffer in the net stream for ONE client.
Definition netpack.cpp:569
void NET_WriteByte(dbuffer *buf, byte c)
Definition netpack.cpp:39
void NET_WriteLong(dbuffer *buf, int c)
Definition netpack.cpp:52
void NET_WriteString(dbuffer *buf, const char *str)
Definition netpack.cpp:59
#define NET_STATE_INFO
Definition q_shared.h:612
#define CS_TILES
Definition q_shared.h:325
#define NET_STATE_BEGIN
Definition q_shared.h:609
#define CS_POSITIONS
Definition q_shared.h:326
#define NET_STATE_DISCONNECT
Definition q_shared.h:611
#define NET_STATE_NEW
Definition q_shared.h:608
#define MAX_CONFIGSTRINGS
Definition q_shared.h:330
#define CS_NAME
Definition q_shared.h:309
#define CL_PRECACHE
Definition q_shared.h:601
#define CS_MODELS
Definition q_shared.h:327
#define NET_STATE_STARTMATCH
Definition q_shared.h:610
QGL_EXTERN void(APIENTRY *qglActiveTexture)(GLenum texture)
QGL_EXTERN GLint i
Definition r_gl.h:113
Main server include file.
char * SV_GetConfigString(int index)
Definition sv_main.cpp:77
client_t * SV_GetClient(int index)
Definition sv_main.cpp:174
client_state_t
Definition server.h:139
@ cs_spawned
Definition server.h:145
@ cs_connected
Definition server.h:141
@ cs_free
Definition server.h:140
@ cs_spawning
Definition server.h:142
@ cs_began
Definition server.h:143
server_state_t
Definition server.h:95
@ ss_game
Definition server.h:99
serverInstanceGame_t * sv
Definition sv_init.cpp:36
serverInstanceStatic_t svs
Definition sv_init.cpp:35
void SV_ClientCommand(client_t *client, const char *fmt,...) __attribute__((format(__printf__
void SV_DropClient(client_t *drop, const char *message)
Called when the player is totally leaving the server, either willingly or unwillingly....
Definition sv_main.cpp:184
void SV_UserinfoChanged(client_t *cl)
Pull specific info from a newly changed userinfo string into a more C friendly form.
Definition sv_main.cpp:921
#define Q_strvalid(string)
Definition shared.h:141
#define Q_streq(a, b)
Definition shared.h:136
char name[32]
Definition server.h:159
client_state_t state
Definition server.h:156
void(* func)(client_t *client)
Definition sv_user.cpp:194
const char * name
Definition sv_user.cpp:193
static void SV_Disconnect_f(client_t *cl)
The client is going to disconnect, so remove the connection immediately.
Definition sv_user.cpp:176
static void SV_Begin_f(client_t *cl)
Definition sv_user.cpp:123
static const ucmd_t ucmds[]
Definition sv_user.cpp:197
server_state_t SV_GetServerState(void)
Definition sv_user.cpp:312
static void SV_ExecuteUserCommand(client_t *cl, const char *s)
Definition sv_user.cpp:214
void SV_ExecuteClientMessage(client_t *cl, int cmd, dbuffer *msg)
The current net_message is parsed for the given client.
Definition sv_user.cpp:235
static void SV_ShowServerinfo_f(client_t *cl)
Dumps the serverinfo info string.
Definition sv_user.cpp:185
void SV_SetServerState(server_state_t state)
Definition sv_user.cpp:317
void SV_SetClientState(client_t *client, client_state_t state)
Set the client state.
Definition sv_user.cpp:36
static void SV_StartMatch_f(client_t *cl)
Definition sv_user.cpp:154
static void SV_New_f(client_t *cl)
Sends the first message from the server to a connected client. This will be sent on the initial conne...
Definition sv_user.cpp:56