UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
mp_callbacks.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 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 
32 static const cgame_import_t* cgi;
33 
41 
42 static 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 
84 static void GAME_MP_RconCallback (struct net_stream* s)
85 {
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 
112 bool 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
128  port = DOUBLEQUOTE(PORT_SERVER);
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 
146 static 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 
162 static 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 
173 static void GAME_MP_Disconnect_f (void)
174 {
175  cgi->SV_ShutdownWhenEmpty();
176  cgi->CL_Drop();
177 }
178 
182 static 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 
201 static void GAME_MP_SelectTeam_Init_f (void)
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 
215 static 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 
235 static 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--) {
246  if (GAME_MP_SetTeamNum(i))
247  break;
248  }
249  } else {
250  for (i++; i <= teamData.maxteams; i++) {
251  if (GAME_MP_SetTeamNum(i))
252  break;
253  }
254  }
255 
257 }
258 
264 static 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 
277 static 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 
287 static 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 }
int numGTs
Definition: q_shared.h:568
bool Q_strnull(const char *string)
Definition: shared.h:138
char name[MAX_VAR]
Definition: q_shared.h:343
static int GAME_MP_CompleteNetworkAddress(const char *partial, const char **match)
Autocomplete function for some network functions.
serverList_t * selectedServer
char id[MAX_VAR]
Definition: q_shared.h:342
#define CVAR_USERINFO
Definition: cvar.h:41
static const cmdList_t mpCallbacks[]
#define MAX_BOOKMARKS
Definition: mp_serverlist.h:28
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
#define SV_CMD_TEAMINFO
Definition: q_shared.h:591
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
static void GAME_MP_InitUI_f(void)
cvar_t * cl_roundtimelimit
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...
#define _(String)
Definition: cl_shared.h:43
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
int maxPlayersPerTeam
Definition: mp_callbacks.h:33
Serverlist menu callbacks headers for multiplayer.
char * service
Definition: mp_serverlist.h:32
static void GAME_MP_Rcon_f(void)
csi_t * csi
Definition: cgame.h:100
cvar_t * rcon_client_password
Definition: autoptr.h:3
#define TEAM_CIVILIAN
Definition: q_shared.h:61
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
static void GAME_MP_StartGame_f(void)
cvar_t * cl_maxsoldiersperplayer
voidpf void * buf
Definition: ioapi.h:42
#define CVAR_ARCHIVE
Definition: cvar.h:40
const char *IMPORT * Cvar_GetString(const char *varName)
const char *IMPORT * Cmd_Args(void)
static void GAME_MP_TeamNum_f(void)
Increase or decrease the teamnum.
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
#define DEBUG_CLIENT
Definition: defines.h:59
#define MAX_VAR
Definition: shared.h:36
static void GAME_MP_Disconnect_f(void)
Binding for disconnect console command.
dbuffer *IMPORT * NET_ReadMsg(struct net_stream *s)
Serverlist management headers for multiplayer.
gametype_t gts[MAX_GAMETYPES]
Definition: q_shared.h:567
void GAME_MP_CallbacksInit(const cgame_import_t *import)
static const cgame_import_t * cgi
Definition: cmd.h:86
#define TEAM_DEFAULT
Definition: defines.h:51
Atomic structure used to define most of the UI.
Definition: ui_nodes.h:80
cvar_t *IMPORT * Cvar_Get(const char *varName, const char *value, int flags, const char *desc)
static void GAME_MP_RconCallback(struct net_stream *s)
static cvar_t * info_password
struct net_stream *IMPORT * NET_Connect(const char *node, const char *service, stream_onclose_func *onclose)
cvar_t * password
Definition: g_main.cpp:67
QGL_EXTERN GLint i
Definition: r_gl.h:113
char * string
Definition: cvar.h:73
static void GAME_MP_Reconnect_f(void)
The server is changing levels.
teamData_t teamData
static bool GAME_MP_SetTeamNum(int teamnum)
void GAME_MP_PingServers_f(void)
The first function called when entering the multiplayer menu, then CL_Frame takes over...
cvar_t * port
Definition: common.cpp:58
void GAME_MP_CallbacksShutdown(void)
static void GAME_MP_SelectTeam_Init_f(void)
Send the SV_CMD_TEAMINFO command to server.
#define MAX_ACTIVETEAM
Definition: defines.h:41
static cvar_t * rcon_address
#define Q_streq(a, b)
Definition: shared.h:136
#define SV_CMD_RCON
Definition: q_shared.h:589
bool modified
Definition: cvar.h:79
const char uiNode_t *IMPORT * UI_AddOption(uiNode_t **tree, const char *name, const char *label, const char *value)
#define PROTOCOL_VERSION
Definition: common.h:134
const char *IMPORT * Cmd_Argv(int n)
cvar_t * cl_maxsoldiersperteam
#define DOUBLEQUOTE(x)
Definition: shared.h:90
#define CVAR_SERVERINFO
Definition: cvar.h:42
static void GAME_MP_Connect_f(void)
#define PORT_SERVER
Definition: common.h:137
int teamCount[MAX_TEAMS]
Definition: mp_callbacks.h:31