]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/stand_server.cpp
fix messages having wrong identifier
[taylor/freespace2.git] / src / network / stand_server.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9
10
11 #include "pstypes.h"
12 #include "osregistry.h"
13 #include "multi_options.h"
14 #include "gamesequence.h"
15 #include "timer.h"
16 #include "version.h"
17 #include "multi.h"
18 #include "stand_gui.h"
19 #include "multi_pmsg.h"
20 #include "multi_endgame.h"
21 #include "multimsgs.h"
22 #include "multiutil.h"
23
24 #include <libwebsockets.h>
25 #include <string>
26 #include <vector>
27
28
29
30 static std::string Standalone_debug_state;
31 static std::string Standalone_ping_str;
32 static std::string Standalone_player_info;
33 static std::string Standalone_message;
34
35 #define STANDALONE_MAX_BAN              50
36 static std::vector<std::string> Standalone_ban_list;
37
38 #define STD_STATS_UPDATE_TIME           500             // ms between updating player stats
39 #define STD_NG_UPDATE_TIME                      100             // ms between updating netgame information
40 #define STD_PING_UPDATE_TIME            1000    // ms between updating pings
41
42 static int Standalone_stats_stamp = -1;
43 static int Standalone_ng_stamp = -1;
44 static int Standalone_ping_stamp = -1;
45
46 static int Standalone_update_flags = 0;
47
48 #define STD_UFLAG_DEBUG_STATE           (1<<0)
49 #define STD_UFLAG_TITLE                         (1<<1)
50 #define STD_UFLAG_CONN                          (1<<2)
51
52 #define STD_UFLAG_SERVER_NAME           (1<<3)
53 #define STD_UFLAG_HOST_PASS                     (1<<4)
54 #define STD_UFLAG_SET_PING                      (1<<5)
55
56 #define STD_UFLAG_PLAYER_INFO           (1<<6)
57
58 #define STD_UFLAG_S_MESSAGE                     (1<<7)
59
60 #define STD_UFLAG_GENERAL                       (STD_UFLAG_DEBUG_STATE|STD_UFLAG_TITLE)
61 #define STD_UFLAG_TAB_SERVER            (STD_UFLAG_SERVER_NAME|STD_UFLAG_HOST_PASS|STD_UFLAG_CONN|STD_UFLAG_SET_PING)
62 #define STD_UFLAG_TAB_PLAYER            (STD_UFLAG_PLAYER_INFO)
63 #define STD_UFLAG_TAB_GS                        (STD_UFLAG_S_MESSAGE)
64
65 #define STD_UFLAG_ALL                           (STD_UFLAG_GENERAL|STD_UFLAG_TAB_SERVER|STD_UFLAG_TAB_PLAYER)
66
67
68 static lws_context *stand_context = NULL;
69
70
71 static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
72 {
73         bool try_reuse = false;
74
75         switch (reason) {
76                 case LWS_CALLBACK_HTTP: {
77                         if (len < 1) {
78                                 lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL);
79                                 try_reuse = true;
80
81                                 break;
82                         }
83
84                         int     ret = lws_serve_http_file(wsi, "./standalone.html", "text/html", NULL, 0);
85
86                         if ( (ret < 0) || ((ret > 0) && lws_http_transaction_completed(wsi)) ) {
87                                 // error or can't reuse connection, close the socket
88                                 return -1;
89                         }
90
91                         break;
92                 }
93
94                 case LWS_CALLBACK_HTTP_BODY_COMPLETION: {
95                         lws_return_http_status(wsi, HTTP_STATUS_OK, NULL);
96                         try_reuse = true;
97
98                         break;
99                 }
100
101                 case LWS_CALLBACK_HTTP_FILE_COMPLETION: {
102                         try_reuse = true;
103
104                         break;
105                 }
106
107                 default:
108                         break;
109         }
110
111         if (try_reuse) {
112                 if (lws_http_transaction_completed(wsi)) {
113                         return -1;
114                 }
115         }
116
117         return 0;
118 }
119
120 static int callback_standalone(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
121 {
122         #define MAX_BUF_SIZE    1050
123         unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_BUF_SIZE + LWS_SEND_BUFFER_POST_PADDING];
124         unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
125         int rval;
126         int size;
127
128         switch (reason) {
129                 case LWS_CALLBACK_ESTABLISHED: {
130                         Standalone_stats_stamp = -1;
131                         Standalone_ng_stamp = -1;
132
133                         Standalone_update_flags = STD_UFLAG_ALL;
134
135                         break;
136                 }
137
138                 case LWS_CALLBACK_SERVER_WRITEABLE: {
139                         if (Standalone_update_flags & STD_UFLAG_TITLE) {
140                                 size = SDL_snprintf((char *)p, 64, "T:%s %d.%02d.%02d", XSTR("FreeSpace Standalone", 935), FS_VERSION_MAJOR, FS_VERSION_MINOR, FS_VERSION_BUILD);
141
142                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
143
144                                 if (rval < size) {
145                                         lwsl_err("ERROR sending title string!\n");
146                                         return -1;
147                                 }
148
149                                 Standalone_update_flags &= ~STD_UFLAG_TITLE;
150                         }
151
152                         if (Standalone_update_flags & STD_UFLAG_DEBUG_STATE) {
153                                 size = SDL_snprintf((char *)p, 32, "D:%s", Standalone_debug_state.c_str());
154
155                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
156
157                                 if (rval < size) {
158                                         lwsl_err("ERROR sending debug state!\n");
159                                         return -1;
160                                 }
161
162                                 Standalone_update_flags &= ~STD_UFLAG_DEBUG_STATE;
163                         }
164
165                         if (Standalone_update_flags & STD_UFLAG_SERVER_NAME) {
166                                 size = SDL_snprintf((char *)p, MAX_GAMENAME_LEN, "S:name %s", Netgame.name);
167
168                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
169
170                                 if (rval < size) {
171                                         lwsl_err("ERROR sending debug state!\n");
172                                         return -1;
173                                 }
174
175                                 Standalone_update_flags &= ~STD_UFLAG_SERVER_NAME;
176                         }
177
178                         if (Standalone_update_flags & STD_UFLAG_HOST_PASS) {
179                                 size = SDL_snprintf((char *)p, STD_PASSWD_LEN, "S:pass %s", Multi_options_g.std_passwd);
180
181                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
182
183                                 if (rval < size) {
184                                         lwsl_err("ERROR sending debug state!\n");
185                                         return -1;
186                                 }
187
188                                 Standalone_update_flags &= ~STD_UFLAG_HOST_PASS;
189                         }
190
191                         if (Standalone_update_flags & STD_UFLAG_CONN) {
192                                 std::string conn_str;
193                                 char ip_address[60];
194
195                                 conn_str.reserve(1024);
196
197                                 for (int i = 0; i < MAX_PLAYERS; i++) {
198                                         net_player *np = &Net_players[i];
199
200                                         if ( MULTI_CONNECTED((*np)) && (Net_player != np) ) {
201                                                 conn_str.append(np->player->callsign);
202                                                 conn_str.append(",");
203
204                                                 psnet_addr_to_string(ip_address, SDL_arraysize(ip_address), &np->p_info.addr);
205                                                 conn_str.append(ip_address);
206                                                 conn_str.append(",");
207
208                                                 if (np->s_info.ping.ping_avg > -1) {
209                                                         if (np->s_info.ping.ping_avg >= 1000) {
210                                                                 SDL_snprintf(ip_address, SDL_arraysize(ip_address), "%s", XSTR("> 1 sec", 914));
211                                                         } else {
212                                                                 SDL_snprintf(ip_address, SDL_arraysize(ip_address), "%d%s", np->s_info.ping.ping_avg, XSTR(" ms", 915));
213                                                         }
214                                                 }
215
216                                                 conn_str.append(";");
217                                         }
218                                 }
219
220                                 SDL_assert(conn_str.length() < 1024);
221
222                                 size = SDL_snprintf((char *)p, MAX_BUF_SIZE, "S:conn %s", conn_str.c_str());
223
224                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
225
226                                 if (rval < size) {
227                                         lwsl_err("ERROR sending debug state!\n");
228                                         return -1;
229                                 }
230
231                                 Standalone_update_flags &= ~STD_UFLAG_CONN;
232                         }
233
234                         if ( (Standalone_update_flags & STD_UFLAG_SET_PING) && !Standalone_ping_str.empty() ) {
235                                 SDL_assert(Standalone_ping_str.length() < 1024);
236
237                                 size = SDL_snprintf((char *)p, MAX_BUF_SIZE, "S:ping %s", Standalone_ping_str.c_str());
238
239                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
240
241                                 if (rval < size) {
242                                         lwsl_err("ERROR sending debug state!\n");
243                                         return -1;
244                                 }
245
246                                 Standalone_ping_str.clear();
247                                 Standalone_update_flags &= ~ STD_UFLAG_SET_PING;
248                         }
249
250                         if ( (Standalone_update_flags & STD_UFLAG_PLAYER_INFO) && !Standalone_player_info.empty() ) {
251                                 size = SDL_snprintf((char *)p, MAX_BUF_SIZE, "P:info %s", Standalone_player_info.c_str());
252
253                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
254
255                                 if (rval < size) {
256                                         lwsl_err("ERROR sending debug state!\n");
257                                         return -1;
258                                 }
259
260                                 Standalone_player_info.clear();
261                                 Standalone_update_flags &= ~STD_UFLAG_PLAYER_INFO;
262                         }
263
264                         if ( (Standalone_update_flags & STD_UFLAG_S_MESSAGE) && !Standalone_message.empty() ) {
265                                 size = SDL_snprintf((char *)p, MAX_BUF_SIZE, "G:mesg %s", Standalone_message.c_str());
266
267                                 rval = lws_write(wsi, p, size, LWS_WRITE_TEXT);
268
269                                 if (rval < size) {
270                                         lwsl_err("ERROR sending debug state!\n");
271                                         return -1;
272                                 }
273
274                                 Standalone_message.clear();
275                                 Standalone_update_flags &= ~STD_UFLAG_S_MESSAGE;
276                         }
277
278                         break;
279                 }
280
281                 case LWS_CALLBACK_RECEIVE: {
282                         if (in != NULL && len > 0) {
283                                 const char *msg = (const char *)in;
284                                 char mtype = msg[0];
285
286                                 if ( !SDL_strcmp(msg, "shutdown") ) {
287                                         gameseq_post_event(GS_EVENT_QUIT_GAME);
288                                         return -1;
289                                 }
290
291                                 // server tab
292                                 if (mtype == 'S') {
293                                         if (len >= 7) {
294                                                 if ( !SDL_strncmp(msg+2, "name ", 5) ) {
295                                                         SDL_strlcpy(Netgame.name, msg+7, SDL_arraysize(Netgame.name));
296                                                         SDL_strlcpy(Multi_options_g.std_pname, Netgame.name, SDL_arraysize(Multi_options_g.std_pname));
297                                                 } else if ( !SDL_strncmp(msg+2, "pass ", 5) ) {
298                                                         SDL_strlcpy(Multi_options_g.std_passwd, msg+7, SDL_arraysize(Multi_options_g.std_passwd));
299                                                 }
300                                         }
301                                 }
302                                 // multi-player tab
303                                 else if (mtype == 'M') {
304
305                                 }
306                                 // player info tab
307                                 else if (mtype == 'P') {
308                                         if (len >= 7) {
309                                                 if ( !SDL_strncmp(msg+2, "info ", 5) ) {
310                                                         for (int i = 0; i < MAX_PLAYERS; i++) {
311                                                                 net_player *np = &Net_players[i];
312
313                                                                 if ( MULTI_CONNECTED((*np)) && (Net_player != np) ) {
314                                                                         if ( !SDL_strcmp(msg+7, np->player->callsign) ) {
315                                                                                 std_pinfo_display_player_info(np);
316
317                                                                                 break;
318                                                                         }
319                                                                 }
320                                                         }
321                                                 }
322                                         }
323                                 }
324                                 // god stuff tab
325                                 else if (mtype == 'G') {
326                                         if (len >= 7) {
327                                                 if ( !SDL_strncmp(msg+2, "smsg ", 5) ) {
328                                                         char txt[256];
329
330                                                         SDL_strlcpy(txt, msg+7, SDL_arraysize(txt));
331
332                                                         if (SDL_strlen(txt) > 0) {
333                                                                 send_game_chat_packet(Net_player, txt, MULTI_MSG_ALL, NULL);
334
335                                                                 std_add_chat_text(txt, MY_NET_PLAYER_NUM, 1);
336                                                         }
337                                                 } else if ( !SDL_strcmp(msg+2, "mrefresh") ) {
338                                                         if (MULTI_IS_TRACKER_GAME) {
339                                                                 cf_delete(MULTI_VALID_MISSION_FILE, CF_TYPE_DATA);
340
341                                                                 multi_update_valid_missions();
342                                                         }
343                                                 }
344                                         }
345                                 }
346                         }
347
348                         break;
349                 }
350
351                 default:
352                         break;
353         }
354
355         return 0;
356 }
357
358 static struct lws_protocols stand_protocols[] = {
359         {
360                 "http-only",
361                 callback_http,
362                 0,
363                 0
364         },
365         {
366                 "standalone",
367                 callback_standalone,
368                 0,
369                 0
370         },
371         // terminator
372         {
373                 NULL,
374                 NULL,
375                 0,
376                 0
377         }
378 };
379
380
381
382
383 void std_deinit_standalone()
384 {
385         if (stand_context) {
386                 lws_cancel_service(stand_context);
387                 lws_context_destroy(stand_context);
388                 stand_context = NULL;
389         }
390 }
391
392 void std_init_standalone()
393 {
394         struct lws_context_creation_info info;
395
396         if (stand_context) {
397                 return;
398         }
399
400         SDL_zero(info);
401
402         info.port = Multi_options_g.port;
403
404         info.protocols = stand_protocols;
405
406         info.gid = -1;
407         info.uid = -1;
408
409         info.ka_time = 0;
410         info.ka_probes = 0;
411         info.ka_interval = 0;
412
413         stand_context = lws_create_context(&info);
414
415         if (stand_context == NULL) {
416                 SDL_assert_always(1);
417         }
418
419         Standalone_stats_stamp = -1;
420         Standalone_ng_stamp = -1;
421         Standalone_ping_stamp = -1;
422
423         Standalone_update_flags = STD_UFLAG_ALL;
424 }
425
426 void std_do_gui_frame()
427 {
428         // maybe update selected player stats
429         if ( (Standalone_stats_stamp == -1) || timestamp_elapsed(Standalone_stats_stamp) ) {
430                 Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
431         }
432
433         // maybe update netgame info
434         if ( (Standalone_ng_stamp == -1) || timestamp_elapsed(Standalone_ng_stamp) ) {
435                 Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
436         }
437
438         // update connection ping times
439         if ( !Standalone_ping_str.empty() && ((Standalone_ping_stamp == -1) || timestamp_elapsed(Standalone_ping_stamp)) ) {
440                 Standalone_ping_stamp = timestamp(STD_PING_UPDATE_TIME);
441                 Standalone_update_flags |= STD_UFLAG_SET_PING;
442         }
443
444         if (Standalone_update_flags) {
445                 lws_callback_on_writable_all_protocol(stand_context, &stand_protocols[1]);
446         }
447
448         lws_service(stand_context, 0);
449 }
450
451 void std_debug_set_standalone_state_string(const char *str)
452 {
453         Standalone_debug_state = str;
454
455         Standalone_update_flags |= STD_UFLAG_DEBUG_STATE;
456 }
457
458 void std_connect_set_gamename(const char *name)
459 {
460         if (name == NULL) {
461                 // if a permanent name exists, use that instead of the default
462                 if ( SDL_strlen(Multi_options_g.std_pname) ) {
463                         SDL_strlcpy(Netgame.name, Multi_options_g.std_pname, SDL_arraysize(Netgame.name));
464                 } else {
465                         SDL_strlcpy(Netgame.name, XSTR("Standalone Server", 916), SDL_arraysize(Netgame.name));
466                 }
467         } else {
468                 SDL_strlcpy(Netgame.name, name, SDL_arraysize(Netgame.name));
469         }
470
471         Standalone_update_flags |= STD_UFLAG_SERVER_NAME;
472 }
473
474 int std_connect_set_connect_count()
475 {
476         int count = 0;
477
478         for (int i = 0; i < MAX_PLAYERS; i++) {
479                 if (MULTI_CONNECTED(Net_players[i]) && (Net_player != &Net_players[i]) ) {
480                         count++;
481                 }
482         }
483
484         return count;
485 }
486
487 void std_add_player(net_player *p)
488 {
489         Standalone_update_flags |= STD_UFLAG_CONN;
490
491         // check to see if this guy is the host
492         std_connect_set_host_connect_status();
493 }
494
495 int std_remove_player(net_player *p)
496 {
497         int count;
498
499         Standalone_update_flags |= STD_UFLAG_CONN;
500
501         // update the host connect count
502         std_connect_set_host_connect_status();
503
504         // update the currently connected players
505         count = std_connect_set_connect_count();
506
507         if (count == 0) {
508                 multi_quit_game(PROMPT_NONE);
509                 return 1;
510         }
511
512         return 0;
513 }
514
515 void std_update_player_ping(net_player *p)
516 {
517         char ip_address[60];
518
519         if (p->s_info.ping.ping_avg > -1) {
520                 psnet_addr_to_string(ip_address, SDL_arraysize(ip_address), &p->p_info.addr);
521
522                 Standalone_ping_str.append(ip_address);
523
524                 if (p->s_info.ping.ping_avg > 1000) {
525                         SDL_snprintf(ip_address, SDL_arraysize(ip_address), ",%s;", XSTR("> 1 sec", 914));
526                 } else {
527                         SDL_snprintf(ip_address, SDL_arraysize(ip_address), ",%d%s;", p->s_info.ping.ping_avg, XSTR(" ms", 915));
528                 }
529
530                 Standalone_ping_str.append(ip_address);
531         }
532 }
533
534 void std_pinfo_display_player_info(net_player *p)
535 {
536         char sml_ping[30];
537
538         Standalone_player_info.clear();
539         Standalone_player_info.reserve(256);
540
541         // ship type
542         Standalone_player_info.append(Ship_info[p->p_info.ship_class].name);
543         Standalone_player_info.append(";");
544
545         // avg ping time
546         if (p->s_info.ping.ping_avg > 1000) {
547                 SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%s", XSTR("> 1 sec", 914));
548         } else {
549                 SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d%s", p->s_info.ping.ping_avg, XSTR(" ms", 915));
550         }
551
552         Standalone_player_info.append(sml_ping);
553         Standalone_player_info.append(";");
554
555         scoring_struct *ptr = &p->player->stats;
556
557         // all-time stats
558         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->p_shots_fired);
559         Standalone_player_info.append(sml_ping);
560         Standalone_player_info.append(",");
561         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->p_shots_hit);
562         Standalone_player_info.append(sml_ping);
563         Standalone_player_info.append(",");
564         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->p_bonehead_hits);
565         Standalone_player_info.append(sml_ping);
566         Standalone_player_info.append(",");
567         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->p_shots_hit / (float)ptr->p_shots_fired)));
568         Standalone_player_info.append(sml_ping);
569         Standalone_player_info.append(",");
570         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->p_bonehead_hits / (float)ptr->p_shots_fired)));
571         Standalone_player_info.append(sml_ping);
572         Standalone_player_info.append(",");
573         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->s_shots_fired);
574         Standalone_player_info.append(sml_ping);
575         Standalone_player_info.append(",");
576         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->s_shots_hit);
577         Standalone_player_info.append(sml_ping);
578         Standalone_player_info.append(",");
579         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->s_bonehead_hits);
580         Standalone_player_info.append(sml_ping);
581         Standalone_player_info.append(",");
582         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->s_shots_hit / (float)ptr->s_shots_fired)));
583         Standalone_player_info.append(sml_ping);
584         Standalone_player_info.append(",");
585         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->s_bonehead_hits / (float)ptr->s_shots_fired)));
586         Standalone_player_info.append(sml_ping);
587         Standalone_player_info.append(",");
588         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->assists);
589         Standalone_player_info.append(sml_ping);
590         Standalone_player_info.append(";");     // <- end of block
591
592         // mission stats
593         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->mp_shots_fired);
594         Standalone_player_info.append(sml_ping);
595         Standalone_player_info.append(",");
596         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->mp_shots_hit);
597         Standalone_player_info.append(sml_ping);
598         Standalone_player_info.append(",");
599         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->mp_bonehead_hits);
600         Standalone_player_info.append(sml_ping);
601         Standalone_player_info.append(",");
602         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->mp_shots_hit / (float)ptr->mp_shots_fired)));
603         Standalone_player_info.append(sml_ping);
604         Standalone_player_info.append(",");
605         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->mp_bonehead_hits / (float)ptr->mp_shots_fired)));
606         Standalone_player_info.append(sml_ping);
607         Standalone_player_info.append(",");
608         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->ms_shots_fired);
609         Standalone_player_info.append(sml_ping);
610         Standalone_player_info.append(",");
611         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->ms_shots_hit);
612         Standalone_player_info.append(sml_ping);
613         Standalone_player_info.append(",");
614         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->ms_bonehead_hits);
615         Standalone_player_info.append(sml_ping);
616         Standalone_player_info.append(",");
617         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->ms_shots_hit / (float)ptr->ms_shots_fired)));
618         Standalone_player_info.append(sml_ping);
619         Standalone_player_info.append(",");
620         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", (int)(100.0f * ((float)ptr->ms_bonehead_hits / (float)ptr->ms_shots_fired)));
621         Standalone_player_info.append(sml_ping);
622         Standalone_player_info.append(",");
623         SDL_snprintf(sml_ping, SDL_arraysize(sml_ping), "%d", ptr->m_assists);
624         Standalone_player_info.append(sml_ping);
625
626         Standalone_update_flags |= STD_UFLAG_PLAYER_INFO;
627 }
628
629 void std_add_chat_text(const char *text, int player_index, int add_id)
630 {
631         char id[32];
632
633         if ( (player_index < 0) || (player_index >= MAX_PLAYERS) ) {
634                 return;
635         }
636
637         // format the chat text nicely
638         if (add_id) {
639                 if ( MULTI_STANDALONE(Net_players[player_index]) ) {
640                         SDL_snprintf(id, SDL_arraysize(id), XSTR("<SERVER> %s", 924), "");
641                 } else {
642                         SDL_snprintf(id, SDL_arraysize(id), "%s: ", Net_players[player_index].player->callsign);
643                 }
644
645                 Standalone_message.append(id);
646         }
647
648         Standalone_message.append(text);
649         Standalone_message.append("\n");
650
651         Standalone_update_flags |= STD_UFLAG_S_MESSAGE;
652 }
653
654 void std_reset_timestamps()
655 {
656         // reset the stats update stamp
657         Standalone_stats_stamp = timestamp(STD_STATS_UPDATE_TIME);
658
659         // reset the netgame controls update timestamp
660         Standalone_ng_stamp = timestamp(STD_NG_UPDATE_TIME);
661
662         // reset the ping update stamp
663         Standalone_ping_stamp = timestamp(STD_PING_UPDATE_TIME);
664 }
665
666 void std_add_ban(const char *name)
667 {
668         if ( (name == NULL) || !SDL_strlen(name) ) {
669                 return;
670         }
671
672         if (Standalone_ban_list.size() >= STANDALONE_MAX_BAN) {
673                 return;
674         }
675
676         Standalone_ban_list.push_back(name);
677 }
678
679 int std_player_is_banned(const char *name)
680 {
681         if ( Standalone_ban_list.empty() ) {
682                 return 0;
683         }
684
685         for (size_t i = 0; i < Standalone_ban_list.size(); i++) {
686                 if ( !SDL_strcasecmp(name, Standalone_ban_list[i].c_str()) ) {
687                         return 1;
688                 }
689         }
690
691         return 0;
692 }
693
694 int std_is_host_passwd()
695 {
696         return (SDL_strlen(Multi_options_g.std_passwd) > 0) ? 1 : 0;
697 }
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715 int std_pinfo_maybe_update_player_info(net_player *p)
716 {
717         STUB_FUNCTION;
718
719         return 0;
720 }
721
722 void std_connect_set_host_connect_status()
723 {
724         STUB_FUNCTION;
725 }
726
727 void std_create_gen_dialog(const char *title)
728 {
729         STUB_FUNCTION;
730 }
731
732 void std_destroy_gen_dialog()
733 {
734         STUB_FUNCTION;
735 }
736
737 void std_gen_set_text(const char *str, int field_num)
738 {
739         STUB_FUNCTION;
740 }
741
742 void std_multi_add_goals()
743 {
744         STUB_FUNCTION;
745 }
746
747 void std_multi_set_standalone_mission_name(const char *mission_name)
748 {
749         STUB_FUNCTION;
750 }
751
752 void std_multi_set_standalone_missiontime(float mission_time)
753 {
754         STUB_FUNCTION;
755 }
756
757 void std_multi_setup_goal_tree()
758 {
759         STUB_FUNCTION;
760 }
761
762 void std_multi_update_goals()
763 {
764         STUB_FUNCTION;
765 }
766
767 void std_multi_update_netgame_info_controls()
768 {
769         STUB_FUNCTION;
770 }
771
772 void std_reset_standalone_gui()
773 {
774         STUB_FUNCTION;
775 }
776
777 void std_set_standalone_fps(float fps)
778 {
779         STUB_FUNCTION;
780 }