]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/standalone.html
when multi game ends go back to PXO if we should
[taylor/freespace2.git] / src / network / standalone.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8" http-equiv="Content-Language" content="en"/>
5 <title>FreeSpace Standalone</title>
6
7 <script>
8 var std = new WebSocket("ws://" + document.URL.substr(7).split('/')[0], "standalone");
9
10 try {
11         std.onclose = function(event) {
12                 if (event.code == 1006) {
13                         popup("Connection Error;Connection rejected by server;")
14                 } else {
15                         document.getElementById("dbg").textContent = "socket closed: " + event.code;
16                 }
17         };
18
19         std.onmessage = function(msg) {
20                 if (msg.data == "reset") {
21                         reset_ui();
22                 } else if (msg.data.substring(0, 6) == "popup ") {
23                         popup(msg.data.substr(6));
24                 } else if (msg.data[0] == 'D') {
25                         document.getElementById("dbg").textContent = msg.data.substr(2);
26                 } else if (msg.data[0] == 'T') {
27                         document.title = msg.data.substr(2);
28                 } else if (msg.data[0] == 'S') {
29                         do_server_tab(msg.data.substr(2));
30                 } else if (msg.data[0] == 'M') {
31                         do_multi_tab(msg.data.substr(2));
32                 } else if (msg.data[0] == 'P') {
33                         do_player_tab(msg.data.substr(2));
34                 } else if (msg.data[0] == 'G') {
35                         do_gs_tab(msg.data.substr(2));
36                 }
37         };
38 } catch (exception) {
39         alert('<p>Error ' + exception);
40 }
41
42 function shutdown() {
43         std.send("shutdown");
44         std.close();
45         reset_ui();
46         popup("Shutdown;Shutdown complete;");
47 }
48
49 function popup(msg) {
50         var modal = document.getElementById("pop");
51         var content = [ document.getElementById("pop-t"), document.getElementById("pop-1"), document.getElementById("pop-2") ];
52         var x;
53
54         if (msg.length) {
55                 var fields = msg.split(';');
56
57                 for (x = 0; x < fields.length; x++) {
58                         content[x].textContent = fields[x];
59                 }
60
61                 modal.style.display = "block";
62         } else {
63                 modal.style.display = "none";
64         }
65 }
66
67 function reset_ui() {
68         var table;
69         var len;
70         var j;
71
72         /* hide popup */
73         document.getElementById("pop").style.display = "none";
74
75         /* server tab */
76         document.getElementById("s_ncon").textContent = "0";
77         table = document.getElementById("s_conn");
78         len = table.rows.length;
79
80         for (j = 1; j < len; j++) {
81                 table.rows[j].onclick = '';
82                 table.rows[j].cells[0].innerHTML = '&nbsp;';
83                 table.rows[j].cells[1].innerHTML = "";
84         }
85
86         /* multi-player tab */
87         document.getElementById("fps_rel").textContent = "0.0";
88         document.getElementById("m_name").textContent = "";
89         document.getElementById("m_time").textContent = "";
90
91         document.getElementById("m_ng_p").textContent = "";
92         document.getElementById("m_ng_o").textContent = "";
93         document.getElementById("m_ng_s").textContent = "";
94         document.getElementById("m_ng_r").textContent = "";
95
96         table = document.getElementById("m_g");
97         len = table.rows.length;
98
99         for (j = 1; j < len; j++) {
100                 var cell = table.rows[j].cells[0];
101
102                 if (cell.childNodes.length > 1) {
103                         cell.removeChild(cell.childNodes[1]);
104                 }
105         }
106
107         /* player info tab */
108         document.getElementById("p_p").selectedIndex = -1;
109         document.getElementById("p_s_t").textContent = "";
110         document.getElementById("p_ping").textContent = "";
111
112         table = document.getElementById("p_s");
113         len = table.rows.length;
114
115         for (j = 1; j < len; j++) {
116                 table.rows[j].cells[1].innerHTML = "";
117                 table.rows[j].cells[2].innerHTML = "";
118         }
119
120         /* gs tab */
121         document.getElementById("g_p").selectedIndex = -1;
122         document.getElementById("g_b").value = "";
123 }
124
125 function do_server_tab(msg) {
126         var table;
127         var row;
128         var j;
129         var len;
130
131         if (msg.substring(0, 5) == "name ") {
132                 document.getElementById("s_name").value = msg.substr(5);
133         } else if (msg.substring(0, 5) == "pass ") {
134                 document.getElementById("s_pass").value = msg.substr(5);
135         } else if (msg.substring(0, 5) == "ping ") {
136                 table = document.getElementById("s_conn");
137                 var ping_list = msg.substr(5).split(',', 12);
138                 len = ping_list.length;
139
140                 for (j = 0; j < len; j++) {
141                         table.rows[j+1].cells[1].innerHTML = ping_list[j];
142                 }
143         } else if (msg.substring(0, 5) == "conn ") {
144                 table = document.getElementById("s_conn");
145                 var players = document.getElementById("p_p");
146                 var cur_player;
147                 var new_index = -1;
148                 var gs_players = document.getElementById("g_p");
149                 var connections = msg.substr(5).split(';', 12);
150
151                 /* save currently selected player to restore later */
152                 if (players.selectedIndex != -1) {
153                         cur_player = players.value;
154                 }
155
156                 while (players.options.length) {
157                         players.remove(0);
158                         gs_players.remove(0);
159                 }
160
161                 /* new connections */
162                 len = connections.length;
163
164                 document.getElementById("s_ncon").textContent = len;
165
166                 for (j = 0; j < len; j++) {
167                         var conn = connections[j].split(',');
168                         row = table.rows[j+1];
169
170                         var option = document.createElement("option");
171                         option.text = conn[0];
172                         gs_players.add(option);
173
174                         option = document.createElement("option");
175                         option.text = conn[0];
176                         players.add(option);
177
178                         /* maybe reselect player */
179                         if ( Boolean(cur_player) && conn[0] == cur_player ) {
180                                 new_index = j;
181                         }
182
183                         row.cells[0].innerHTML = conn[1];
184
185                         row.onclick = function() { kick_conn(conn[0], conn[1]); };
186                 }
187
188                 len = table.rows.length;
189
190                 for (j = j+1; j < len; j++) {
191                         row = table.rows[j];
192
193                         row.onclick = '';
194                         row.cells[0].innerHTML = "&nbsp;"
195                         row.cells[1].innerHTML = "";
196                 }
197         
198                 gs_players.selectedIndex = -1;
199                 players.selectedIndex = new_index;
200
201                 if (new_index != -1) {
202                         players.value = cur_player;
203                 }
204
205                 /* re-request player info, or reset values */
206                 get_pinfo();
207         }
208 }
209
210 function do_multi_tab(msg) {
211         if (msg.substring(0, 5) == "rfps ") {
212                 document.getElementById("fps_rel").textContent = msg.substr(4);
213         } else if (msg.substring(0, 5) == "name ") {
214                 document.getElementById("m_name").textContent = msg.substr(5);
215         } else if (msg.substring(0, 5) == "time ") {
216                 document.getElementById("m_time").textContent = msg.substr(5);
217         } else if (msg.substring(0, 5) == "info ") {
218                 var nginfo = msg.substr(5).split(',');
219                 document.getElementById("m_ng_p").textContent = nginfo[0];
220                 document.getElementById("m_ng_o").textContent = nginfo[1];
221                 document.getElementById("m_ng_s").textContent = nginfo[2];
222                 document.getElementById("m_ng_r").textContent = nginfo[3];
223         } else if (msg.substring(0, 5) == "goal ") {
224                 var objectives = msg.substr(5).split(';');
225                 var gtable = document.getElementById("m_g");
226                 var j;
227                 var j_len;
228                 var x;
229                 var x_len;
230
231                 j_len = objectives.length;
232
233                 for (j = 0; j < j_len; j++) {
234                         var goals = objectives[j].split(',');
235                         var cell = gtable.rows[j+1].cells[0];
236
237                         if (cell.childNodes.length > 1) {
238                                 cell.removeChild(cell.childNodes[1]);
239                         }
240
241                         var list = document.createElement("ul");
242  
243                         x_len = goals.length;
244
245                         for (x = 0; x < x_len; x++) {
246                                 var item = document.createElement("li");
247                                 item.innerHTML = goals[x].substr(2);
248
249                                 var status = goals[x].substring(0, 2);
250                                 if (status == "c ") {
251                                         item.style.color = "green";
252                                 } else if (status == "f ") {
253                                         item.style.color = "red";
254                                 } else {
255                                         item.style.color = "#555";
256                                 }
257
258                                 list.appendChild(item);
259                         }
260
261                         cell.appendChild(list);
262                 }
263         }
264 }
265
266 function do_player_tab(msg) {
267         if (msg.substring(0, 5) == "info ") {
268                 var pinfo = msg.substr(5).split(';');
269
270                 document.getElementById("p_s_t").textContent = pinfo[0];
271                 document.getElementById("p_ping").textContent = pinfo[1];
272
273                 var all_stats = pinfo[2].split(',');
274                 var mission_stats = pinfo[3].split(',');
275                 var table = document.getElementById("p_s");
276                 var j;
277                 var len = table.rows.length;
278
279                 for (j = 0; j < len; j++) {
280                         var row = table.rows[j+1];
281
282                         row.cells[1].innerHTML = all_stats[j];
283                         row.cells[2].innerHTML = mission_stats[j];
284                 }
285         }
286 }
287
288 function do_gs_tab(msg) {
289         if (msg.substring(0, 5) == "mesg ") {
290                 document.getElementById("g_b").value += msg.substr(5);
291         }
292 }
293
294 function change_s_name() {
295         std.send("S:name " + document.getElementById("s_name").value);
296 }
297
298 function change_s_pass() {
299         std.send("S:pass " + document.getElementById("s_pass").value);
300 }
301
302 function kick_conn(name, addr) {
303         var kick = confirm("Kick player? \n\n" + name + "@" + addr);
304
305         if (kick) {
306                 std.send("S:kick " + addr);
307         }
308 }
309
310 function send_smsg() {
311         var smsg = document.getElementById("g_m");
312         std.send("G:smsg " + smsg.value);
313         smsg.value = "";
314 }
315
316 function mrefresh() {
317         std.send("G:mrefresh");
318 }
319
320 function switch_tab(tab) {
321         var tabbox = document.getElementById("tab-box");
322         var nav = document.getElementById("nav");
323         var x;
324
325         for (x = 0; x < 4; x++) {
326                 if (tab == x) {
327                         nav.children[x].children[0].className = "active";
328                         tabbox.children[x].className = "tab-visible";
329                 } else {
330                         nav.children[x].children[0].className = '';
331                         tabbox.children[x].className = "tab-hidden";
332                 }
333         }
334 }
335
336 function smsg_submit(e) {
337         e = e || window.event;
338
339         if (e.keyCode == 13) {
340                 document.getElementById("g_s").click();
341                 return false;
342         }
343
344         return true;
345 }
346
347 function get_pinfo() {
348         var players = document.getElementById("p_p");
349
350         if (players.selectedIndex != -1) {
351                 std.send("P:info " + players.value);
352         } else {
353                 document.getElementById("p_s_t").textContent = "";
354                 document.getElementById("p_ping").textContent = "";
355
356                 var table = document.getElementById("p_s");
357                 var len = table.rows.length;
358
359                 for (var j = 1; j < len; j++) {
360                         table.rows[j].cells[1].innerHTML = "";
361                         table.rows[j].cells[2].innerHTML = "";
362                 }
363         }
364 }
365
366 function set_fps() {
367         var fps = document.getElementById("m_fps").value;
368         document.getElementById("fps_connap").textContent = fps;
369
370         std.send("M:fps " + fps);
371 }
372 </script>
373
374 <style type="text/css">
375 body {
376         font-family: Arial, Helvetica, sans-serif
377 }
378
379 .container {
380         width: 35em;
381         margin: 0 auto
382 }
383
384 .tab-box {
385         background-color: #ddd;
386         padding: 10px 25px
387 }
388
389 .tab-hidden {
390         display: none
391 }
392
393 .tab-visible {
394         display: inline-block;
395         width: 100%
396 }
397
398 .button {
399         border: none;
400         border-radius: 4px;
401         background-color: #444;
402         color: #eee;
403         padding: 5px 10px;
404         text-align: center;
405         text-decoration: none;
406         display: inline-block;
407         font-size: 14px;
408         cursor: pointer
409 }
410
411 .button:hover {
412         background-color: #111;
413         color: #fff
414 }
415
416 #nav {
417         list-style-type: none;
418         margin: 0;
419         padding: 0;
420         overflow: hidden;
421         background-color: #3a3a3a
422 }
423
424 #nav li {
425         float: left
426 }
427
428 #nav a {
429         display: inline-block;
430         color: #e2e2e2;
431         text-align: center;
432         padding: 14px 16px;
433         text-decoration: none;
434         transition: .3s;
435         font-size: 17px;
436         cursor: pointer;
437         outline: 0
438 }
439
440 a:hover,
441 #nav a.active {
442         background-color: #111;
443         color: #fff
444 }
445
446 #nav li.shutdown {
447         float: right;
448         padding-left: 30px
449 }
450
451 #nav li.shutdown a {
452         background-color: #8b0000
453 }
454
455 #nav li.shutdown a:hover {
456         background-color: red;
457         color: #fff
458 }
459
460 #dbg {
461         font-size: smaller;
462         color: #696969;
463         float: right;
464         padding: 2px 4px
465 }
466
467 #s_name,
468 #s_pass {
469         width: 20em;
470         border: none;
471         padding: 5px 10px
472 }
473
474 #s_conn,
475 #p_s {
476         border: 1px solid #444;
477         border-spacing: 0;
478         border-collapse: collapse;
479         width: 100%;
480         min-height: 13em
481 }
482
483 #s_conn th,
484 #p_s th {
485         background-color: #444;
486         color: #fff;
487         padding: 5px 10px;
488         text-align: left;
489         font-size: small
490 }
491
492 #s_conn td,
493 #p_s td {
494         padding: 5px 15px;
495         text-align: left;
496         font-family: Courier New, Courier, monospace;
497         font-size: small
498 }
499
500 #s_conn tr:nth-child(odd),
501 #p_s tr:nth-child(odd) {
502         background-color: #d5d5d5
503 }
504
505 #s_conn tr:hover,
506 #s_conn tr:hover:nth-child(odd) {
507         background-color: #eaeaea
508 }
509
510 table.s_n_p td {
511         padding: 5px 0
512 }
513
514 table.s_n_p label {
515         padding-right: 10px
516 }
517
518 #g_m {
519         margin-top: 10px;
520         padding: 5px 10px;
521         border: none;
522         width: 100%;
523         box-sizing: border-box
524 }
525
526 div.players {
527         margin-top: 10px;
528         margin-bottom: 30px
529 }
530
531 .players select,
532 .players option {
533         min-width: 20em;
534         padding: 2px 8px;
535         margin-left: 10px
536 }
537
538 #g_b {
539         width: 100%;
540         box-sizing: border-box;
541         resize: none;
542         background-color: #fff;
543         border: 1px solid #bbb;
544         border-radius: 2px
545 }
546
547 .inf {
548         margin-bottom: 30px;
549         border: none;
550         border-collapse: collapse
551 }
552
553 .inf td {
554         padding: 5px 0
555 }
556
557 .inf span {
558         font-family: Courier New, Courier, monospace;
559         font-size: small;
560         padding: 5px 10px;
561         min-width: 12em;
562         margin-left: 10px
563 }
564
565 .m_f {
566         display: inline-block;
567         width: 100%;
568         margin-bottom: 20px
569 }
570
571 .m_f span {
572         font-family: Courier New, Courier, monospace;
573         padding: 5px 0 5px 10px
574 }
575
576 #m_fps {
577         width: 100%;
578         margin: 10px 0;
579         box-sizing: border-box
580 }
581
582 .m_fc {
583         display: block;
584         float: left
585 }
586
587 .m_fr {
588         display: block;
589         float: right
590 }
591
592 #m_g,
593 .m_i {
594         border: none;
595         border-collapse: collapse;
596         display: inline-block
597 }
598
599 .m_i {
600         float: right
601 }
602
603 #m_g {
604         float: left;
605         min-width: 15em;
606         min-height: 17em;
607         background-color: #fff;
608         margin-bottom: 15px
609 }
610
611 #m_g th,
612 .m_i th {
613         padding: 5px;
614         text-align: left
615 }
616
617 .m_i th {
618         border-bottom: 1px solid #444
619 }
620
621 #m_g th {
622         background-color: #ddd;
623         width: 15em
624 }
625
626 #m_g td,
627 .m_i td {
628         padding: 5px 10px;
629         font-size: small
630 }
631
632 #m_g ul {
633         padding: 0 1.5em;
634         margin: 0
635 }
636
637 #pop {
638         display: none;
639         position: fixed;
640         z-index: 1;
641         left: 0;
642         top: 0;
643         width: 100%;
644         height: 100%;
645         overflow: auto;
646         background-color: #000;
647         background-color: rgba(0, 0, 0, .4)
648 }
649
650 .pop-c {
651         background-color: #fefefe;
652         margin: 10em auto;
653         border: 2px solid #111;
654         width: 25em
655 }
656
657 #pop-t {
658         background-color: #444;
659         color: #fff;
660         padding: 10px;
661         font-weight: 700
662 }
663
664 .pop-b {
665         padding: 20px;
666         margin-top: 2em;
667         height: 4em
668 }
669 </style>
670 </head>
671
672 <body>
673
674 <div class="container">
675         <ul id="nav">
676                 <li><a onclick="switch_tab(0);" href="javascript:void(0);" class="active">Server</a></li>
677                 <li><a onclick="switch_tab(1);" href="javascript:void(0);">Multi-Player</a></li>
678                 <li><a onclick="switch_tab(2);" href="javascript:void(0);">Player Info</a></li>
679                 <li><a onclick="switch_tab(3);" href="javascript:void(0);">God Stuff</a></li>
680                 <li class="shutdown"><a onclick="shutdown();" href="javascript:void(0);">Shutdown</a></li>
681         </ul>
682
683         <div class="tab-box" id="tab-box">
684                 <!-- server tab -->
685                 <div class="tab-visible">
686                         <table class="s_n_p">
687                                 <tr><td><label for="s_name">Server Name </label></td><td><input id="s_name" type="text" value="" maxlength="31" onchange="change_s_name();"></td></tr>
688                                 <tr><td><label for="s_pass">Host Password </label></td><td><input id="s_pass" type="text" value="" maxlength="15" onchange="change_s_pass();"></td></tr>
689                         </table>
690                         <hr>
691                         <p>Connections : <span id="s_ncon">0</span></p>
692                         <p>
693                                 <table id="s_conn">
694                                         <tr><th style="min-width:20em;">IP Address</th><th style="min-width:6em;">Ping</th></tr>
695                                         <tr><td>&nbsp;</td><td></td></tr>
696                                         <tr><td>&nbsp;</td><td></td></tr>
697                                         <tr><td>&nbsp;</td><td></td></tr>
698                                         <tr><td>&nbsp;</td><td></td></tr>
699                                         <tr><td>&nbsp;</td><td></td></tr>
700                                         <tr><td>&nbsp;</td><td></td></tr>
701                                         <tr><td>&nbsp;</td><td></td></tr>
702                                         <tr><td>&nbsp;</td><td></td></tr>
703                                         <tr><td>&nbsp;</td><td></td></tr>
704                                         <tr><td>&nbsp;</td><td></td></tr>
705                                         <tr><td>&nbsp;</td><td></td></tr>
706                                         <tr><td>&nbsp;</td><td></td></tr>
707                                 </table>
708                         </p>
709                 </div>
710
711                 <!-- multi-player tab -->
712                 <div class="tab-hidden">
713                         <div class="m_f">
714                                 <input type="range" id="m_fps" min="10" max="120" value="60" step="1" oninput="set_fps();">
715                                 <div class="m_fc">
716                                         Frame Cap: <span id="fps_connap">60</span>
717                                 </div>
718                                 <div class="m_fr">
719                                         Realiazed FPS: <span id="fps_rel">0.0</span>
720                                 </div>
721                         </div>
722                         <hr>
723                         <table class="inf">
724                                 <tr><td>Mission Name: </td><td><span id="m_name"></span></td></tr>
725                                 <tr><td>Mission Time: </td><td><span id="m_time"></span></td></tr>
726                         </table>
727                         <table id="m_g">
728                                 <tr><th>Mission Goals</th></tr>
729                                 <tr><td>Primary Objectives</td></tr>
730                                 <tr><td>Secondary Objectives</td></tr>
731                                 <tr><td>Bonus Objectives</td></tr>
732                         </table>
733                         <table class="m_i">
734                                 <tr><th colspan="2">Netgame Information</th></tr>
735                                 <tr><td>Max Players</td><td><span id="m_ng_p"></span></td></tr>
736                                 <tr><td>Max Observers</td><td><span id="m_ng_o"></span></td></tr>
737                                 <tr><td>Security</td><td><span id="m_ng_s"></span></td></tr>
738                                 <tr><td>Respawns</td><td><span id="m_ng_r"></span></td></tr>
739                         </table>
740                 </div>
741
742                 <!-- player tab -->
743                 <div class="tab-hidden">
744                         <div class="players">
745                                 <label for="p_p">Player</label>
746                                 <select id="p_p" onchange="get_pinfo();">
747                                 </select>
748                         </div>
749                         <table class="inf">
750                                 <tr><td>Ship Type: </td><td><span id="p_s_t"></span></td></tr>
751                                 <tr><td>Avg Ping: </td><td><span id="p_ping"></span></td></tr>
752                         </table>
753                         <p>
754                                 <table id="p_s">
755                                         <tr><th>Stats</th><th>All Time</th><th>Mission</th></tr>
756                                         <tr><td>Primary Shots</td><td></td><td></td></tr>
757                                         <tr><td>Primary Hits</td><td></td><td></td></tr>
758                                         <tr><td>Primary BH Hits</td><td></td><td></td></tr>
759                                         <tr><td>Primary Hit %</td><td></td><td></td></tr>
760                                         <tr><td>Primary BH Hit %</td><td></td><td></td></tr>
761                                         <tr><td>Secondary Shots</td><td></td><td></td></tr>
762                                         <tr><td>Secondary Hits</td><td></td><td></td></tr>
763                                         <tr><td>Secondary BH Hits</td><td></td><td></td></tr>
764                                         <tr><td>Secondary Hit %</td><td></td><td></td></tr>
765                                         <tr><td>Secondary BH Hit %</td><td></td><td></td></tr>
766                                         <tr><td>Assists</td><td></td><td></td></tr>
767                                 </table>
768                         </p>
769                 </div>
770
771                 <!-- gs tab -->
772                 <div class="tab-hidden">
773                         <div class="players">
774                                 <label for="g_p">Player</label>
775                                 <select id="g_p">
776                                 </select>
777                         </div>
778                         <div>
779                                 <p>
780                                         <label for="g_m">Server Message</label>
781                                         <br>
782                                         <input id="g_m" type="text" value="" onkeypress="return smsg_submit(event);">
783                                         <input id="g_s" type="button" onclick="send_smsg();" style="display:none;">
784                                 </p>
785                                 <textarea readonly rows="20" id="g_b" autocomplete="off"></textarea>
786                         </div>
787                         <p>
788                                 <input class="button" type="button" value="Refresh Missions" onclick="mrefresh();">
789                         </p>
790                 </div>
791         </div>
792
793         <div id="dbg"></div>
794 </div>
795
796 <div id="pop">
797         <div class="pop-c">
798                 <div id="pop-t"></div>
799                 <div class="pop-b">
800                         <span id="pop-1"></span>&nbsp;<span id="pop-2"></span>
801                 </div>
802         </div>
803 </div>
804
805 </body>
806 </html>