UFO: Alien Invasion
Loading...
Searching...
No Matches
mp_callbacks.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24*/
25
26#include "../../cl_shared.h"
27#include "../../ui/ui_data.h"
28#include "mp_callbacks.h"
29#include "mp_serverlist.h"
30#include "../cl_game.h"
31
32static const cgame_import_t* cgi;
33
41
42static void GAME_MP_Connect_f (void)
43{
44 if (!selectedServer && cgi->Cmd_Argc() != 2 && cgi->Cmd_Argc() != 3) {
45 cgi->Com_Printf("Usage: %s <server> [<port>]\n", cgi->Cmd_Argv(0));
46 return;
47 }
48
49 char server[MAX_VAR];
50 char serverport[16];
51 if (cgi->Cmd_Argc() == 2) {
52 Q_strncpyz(server, cgi->Cmd_Argv(1), sizeof(server));
53 Q_strncpyz(serverport, DOUBLEQUOTE(PORT_SERVER), sizeof(serverport));
54 } else if (cgi->Cmd_Argc() == 3) {
55 Q_strncpyz(server, cgi->Cmd_Argv(1), sizeof(server));
56 Q_strncpyz(serverport, cgi->Cmd_Argv(2), sizeof(serverport));
57 } else {
58 assert(selectedServer);
59 Q_strncpyz(server, selectedServer->node, sizeof(server));
60 Q_strncpyz(serverport, selectedServer->service, sizeof(serverport));
61 }
62
63 if (cgi->GAME_IsTeamEmpty() && !cgi->GAME_LoadDefaultTeam(true)) {
64 cgi->UI_Popup(_("Error"), "%s", _("Assemble a team first"));
65 return;
66 }
67
68 if (cgi->Cvar_GetInteger("mn_server_need_password")) {
69 cgi->UI_PushWindow("serverpassword");
70 return;
71 }
72
73 /* if running a local server, kill it and reissue */
74 cgi->SV_Shutdown("Server quit.", false);
75 cgi->CL_Disconnect();
76
77 cgi->GAME_SetServerInfo(server, serverport);
78
79 cgi->CL_SetClientState(ca_connecting);
80
81 cgi->HUD_InitUI("missionoptions");
82}
83
84static void GAME_MP_RconCallback (struct net_stream* s)
85{
86 AutoPtr<dbuffer> buf(cgi->NET_ReadMsg(s));
87 if (!buf) {
88 cgi->NET_StreamFree(s);
89 return;
90 }
91 const int cmd = cgi->NET_ReadByte(buf);
92 if (cmd != svc_oob) {
93 cgi->NET_StreamFree(s);
94 return;
95 }
96 char commandBuf[8];
97 cgi->NET_ReadStringLine(buf, commandBuf, sizeof(commandBuf));
98
99 if (Q_streq(commandBuf, "print")) {
100 char paramBuf[2048];
101 cgi->NET_ReadString(buf, paramBuf, sizeof(paramBuf));
102 cgi->Com_Printf("%s\n", paramBuf);
103 }
104 cgi->NET_StreamFree(s);
105}
106
112bool GAME_MP_Rcon (const char* password, const char* command)
113{
114 if (Q_strnull(password)) {
115 cgi->Com_Printf("You must set 'rcon_password' before issuing a rcon command.\n");
116 return false;
117 }
118
119 if (cgi->CL_GetClientState() >= ca_connected) {
120 cgi->NET_OOB_Printf2(SV_CMD_RCON " %s %s", password, command);
121 return true;
122 } else if (rcon_address->string) {
123 const char* port;
124
125 if (strstr(rcon_address->string, ":"))
126 port = strstr(rcon_address->string, ":") + 1;
127 else
129
130 struct net_stream* s = cgi->NET_Connect(rcon_address->string, port, nullptr);
131 if (s) {
132 cgi->NET_OOB_Printf(s, SV_CMD_RCON " %s %s", password, command);
133 cgi->NET_StreamSetCallback(s, &GAME_MP_RconCallback);
134 return true;
135 }
136 }
137
138 cgi->Com_Printf("You are not connected to any server\n");
139 return false;
140}
141
146static void GAME_MP_Rcon_f (void)
147{
148 if (cgi->Cmd_Argc() < 2) {
149 cgi->Com_Printf("Usage: %s <command>\n", cgi->Cmd_Argv(0));
150 return;
151 }
152
153 if (!rcon_client_password->string) {
154 cgi->Com_Printf("You must set 'rcon_password' before issuing a rcon command.\n");
155 return;
156 }
157
158 if (!GAME_MP_Rcon(rcon_client_password->string, cgi->Cmd_Args()))
159 Com_Printf("Could not send the rcon command\n");
160}
161
162static void GAME_MP_StartGame_f (void)
163{
164 if (cgi->Com_ServerState())
165 cgi->Cmd_ExecuteString("startgame");
166 else
167 cgi->Cmd_ExecuteString("rcon startgame");
168}
169
173static void GAME_MP_Disconnect_f (void)
174{
175 cgi->SV_ShutdownWhenEmpty();
176 cgi->CL_Drop();
177}
178
182static void GAME_MP_Reconnect_f (void)
183{
184 if (cgi->Com_ServerState())
185 return;
186
187 if (cgi->CL_GetClientState() >= ca_connecting) {
188 cgi->Com_Printf("disconnecting...\n");
189 cgi->CL_Disconnect();
190 }
191
192 cgi->CL_SetClientState(ca_connecting);
193 cgi->Com_Printf("reconnecting...\n");
194}
195
202{
203 /* reset menu text */
204 cgi->UI_ResetData(TEXT_STANDARD);
205
206 if (cgi->Com_ServerState())
207 cgi->Cvar_Set("cl_admin", "1");
208 else
209 cgi->Cvar_Set("cl_admin", "0");
210
211 cgi->NET_OOB_Printf2(SV_CMD_TEAMINFO " %i", PROTOCOL_VERSION);
212 cgi->UI_RegisterText(TEXT_STANDARD, _("Select a free team or your coop team"));
213}
214
215static bool GAME_MP_SetTeamNum (int teamnum)
216{
217 if (teamData.maxPlayersPerTeam > teamData.teamCount[teamnum]) {
218 static char buf[MAX_VAR];
219 cgi->Cvar_SetValue("cl_teamnum", teamnum);
220 Com_sprintf(buf, sizeof(buf), _("Current team: %i"), teamnum);
221 cgi->UI_RegisterText(TEXT_STANDARD, buf);
222 return true;
223 }
224
225 cgi->UI_RegisterText(TEXT_STANDARD, _("Team is already in use"));
226 cgi->Com_DPrintf(DEBUG_CLIENT, "team %i is already in use: %i (max: %i)\n",
227 teamnum, teamData.teamCount[teamnum], teamData.maxPlayersPerTeam);
228 return false;
229}
230
235static void GAME_MP_TeamNum_f (void)
236{
237 int i = cgi->Cvar_GetInteger("cl_teamnum");
238
239 if (i <= TEAM_CIVILIAN || i > teamData.maxteams) {
240 cgi->Cvar_SetValue("cl_teamnum", TEAM_DEFAULT);
241 i = TEAM_DEFAULT;
242 }
243
244 if (Q_streq(cgi->Cmd_Argv(0), "teamnum_dec")) {
245 for (i--; i > TEAM_CIVILIAN; i--) {
247 break;
248 }
249 } else {
250 for (i++; i <= teamData.maxteams; i++) {
252 break;
253 }
254 }
255
257}
258
264static int GAME_MP_CompleteNetworkAddress (const char* partial, const char** match)
265{
266 int n = 0;
267 for (int i = 0; i != MAX_BOOKMARKS; ++i) {
268 char const* const adrStr = cgi->Cvar_GetString(va("adr%i", i));
269 if (adrStr[0] != '\0' && cgi->Cmd_GenericCompleteFunction(adrStr, partial, match)) {
270 cgi->Com_Printf("%s\n", adrStr);
271 ++n;
272 }
273 }
274 return n;
275}
276
277static void GAME_MP_InitUI_f (void)
278{
279 uiNode_t* gameTypes = nullptr;
280 for (int i = 0; i < cgi->csi->numGTs; i++) {
281 const gametype_t* gt = &cgi->csi->gts[i];
282 cgi->UI_AddOption(&gameTypes, gt->id, _(gt->name), gt->id);
283 }
284 cgi->UI_RegisterOption(TEXT_LIST, gameTypes);
285}
286
287static const cmdList_t mpCallbacks[] = {
288 {"mp_selectteam_init", GAME_MP_SelectTeam_Init_f, "Function that gets all connected players and let you choose a free team"},
289 {"mp_init_ui", GAME_MP_InitUI_f, nullptr},
290 {"teamnum_dec", GAME_MP_TeamNum_f, "Decrease the preferred teamnum"},
291 {"teamnum_inc", GAME_MP_TeamNum_f, "Increase the preferred teamnum"},
292 {"pingservers", GAME_MP_PingServers_f, "Ping all servers in local network to get the serverlist"},
293 {"disconnect", GAME_MP_Disconnect_f, "Disconnect from the current server"},
294 {"connect", GAME_MP_Connect_f, "Connect to given ip"},
295 {"reconnect", GAME_MP_Reconnect_f, "Reconnect to last server"},
296 {"rcon", GAME_MP_Rcon_f, "Execute a rcon command - see rcon_password"},
297 {"cl_startgame", GAME_MP_StartGame_f, "Forces a gamestart if you are the admin"},
298 {nullptr, nullptr, nullptr}
299};
301{
302 cgi = import;
303 rcon_client_password = cgi->Cvar_Get("rcon_password", "", 0, "Remote console password");
304 rcon_address = cgi->Cvar_Get("rcon_address", "", 0, "Address of the host you would like to control via rcon");
305 info_password = cgi->Cvar_Get("password", "", CVAR_USERINFO, nullptr);
306 cl_maxsoldiersperteam = cgi->Cvar_Get("sv_maxsoldiersperteam", "4", CVAR_ARCHIVE | CVAR_SERVERINFO, "How many soldiers may one team have");
307 cl_maxsoldiersperplayer = cgi->Cvar_Get("sv_maxsoldiersperplayer", DOUBLEQUOTE(MAX_ACTIVETEAM), CVAR_ARCHIVE | CVAR_SERVERINFO, "How many soldiers one player is able to control in a given team");
308 cl_roundtimelimit = cgi->Cvar_Get("sv_roundtimelimit", "90", CVAR_ARCHIVE | CVAR_SERVERINFO, "Timelimit in seconds for multiplayer rounds");
309
310 cgi->Cmd_TableAddList(mpCallbacks);
311 cgi->Cmd_AddParamCompleteFunction("connect", GAME_MP_CompleteNetworkAddress);
312 cgi->Cmd_AddParamCompleteFunction("rcon", GAME_MP_CompleteNetworkAddress);
313
314 cl_maxsoldiersperteam->modified = false;
315 cl_maxsoldiersperplayer->modified = false;
316}
317
319{
320 cgi->Cmd_TableRemoveList(mpCallbacks);
321
322 cgi->Cvar_Delete("rcon_address");
323}
Shared game type headers.
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
@ ca_connecting
Definition cl_shared.h:78
@ ca_connected
Definition cl_shared.h:79
cvar_t * port
Definition common.cpp:58
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define PROTOCOL_VERSION
Definition common.h:134
#define PORT_SERVER
Definition common.h:137
@ svc_oob
Definition common.h:156
const cgame_import_t * cgi
#define CVAR_USERINFO
Definition cvar.h:41
#define CVAR_SERVERINFO
Definition cvar.h:42
#define CVAR_ARCHIVE
Definition cvar.h:40
#define DEBUG_CLIENT
Definition defines.h:59
#define TEAM_DEFAULT
Definition defines.h:51
#define MAX_ACTIVETEAM
Definition defines.h:41
cvar_t * password
Definition g_main.cpp:67
voidpf void * buf
Definition ioapi.h:42
static const cmdList_t mpCallbacks[]
void GAME_MP_CallbacksInit(const cgame_import_t *import)
static void GAME_MP_RconCallback(struct net_stream *s)
bool GAME_MP_Rcon(const char *password, const char *command)
Sends an rcon command to the gameserver that the user is currently connected to, or if this is not th...
static void GAME_MP_Rcon_f(void)
static cvar_t * rcon_address
static void GAME_MP_Reconnect_f(void)
The server is changing levels.
static int GAME_MP_CompleteNetworkAddress(const char *partial, const char **match)
Autocomplete function for some network functions.
static void GAME_MP_SelectTeam_Init_f(void)
Send the SV_CMD_TEAMINFO command to server.
void GAME_MP_CallbacksShutdown(void)
static void GAME_MP_InitUI_f(void)
cvar_t * cl_roundtimelimit
static cvar_t * info_password
static void GAME_MP_TeamNum_f(void)
Increase or decrease the teamnum.
teamData_t teamData
cvar_t * rcon_client_password
static void GAME_MP_Connect_f(void)
cvar_t * cl_maxsoldiersperteam
cvar_t * cl_maxsoldiersperplayer
static void GAME_MP_Disconnect_f(void)
Binding for disconnect console command.
static bool GAME_MP_SetTeamNum(int teamnum)
static void GAME_MP_StartGame_f(void)
Serverlist menu callbacks headers for multiplayer.
void GAME_MP_PingServers_f(void)
The first function called when entering the multiplayer menu, then CL_Frame takes over.
serverList_t * selectedServer
Serverlist management headers for multiplayer.
#define MAX_BOOKMARKS
#define SV_CMD_RCON
Definition q_shared.h:589
#define SV_CMD_TEAMINFO
Definition q_shared.h:591
#define TEAM_CIVILIAN
Definition q_shared.h:61
QGL_EXTERN GLint i
Definition r_gl.h:113
#define Q_streq(a, b)
Definition shared.h:136
bool Q_strnull(const char *string)
Definition shared.h:138
#define DOUBLEQUOTE(x)
Definition shared.h:90
#define MAX_VAR
Definition shared.h:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition shared.cpp:494
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition cvar.h:71
char name[MAX_VAR]
Definition q_shared.h:343
char id[MAX_VAR]
Definition q_shared.h:342
Atomic structure used to define most of the UI.
Definition ui_nodes.h:80
Data and interface to share data.
@ TEXT_LIST
Definition ui_dataids.h:31
@ TEXT_STANDARD
Definition ui_dataids.h:30