1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE ../shared/a_modes.inc}
18 interface
20 uses
23 const
33 const
34 // all timeouts in seconds
37 //NMASTER_TIMEOUT_RECONNECT = 30; // 5 minutes
38 //NMASTER_FORCE_UPDATE_TIMEOUT = 20;
39 //NMASTER_FORCE_UPDATE_TIMEOUT = 0;
41 type
65 type
67 public
70 public
73 // inside the game, calling `connect()` is disasterous, as it is blocking.
74 // so we'll use this variable to indicate if "connected" event is received.
79 updateSent: Boolean; // was at least one update sent? (used to decide if we should call `remove()`)
81 // server list request working flags
87 // temporary mark
91 private
94 public
106 // call as often as you want, the object will do the rest
107 // but try to call this at least once in 100 msecs
124 var
139 // make this server private
141 // make this server public
144 // called while the server is running
146 // called when the server is started
148 // called when the server is stopped
151 // called when new netword player comes
153 // called when new netword player comes
155 // started new map
157 // this server renamed (or password mode changed, or other params changed)
160 // non-zero timeout ignores current status (used to fetch server list)
172 implementation
174 uses
180 // ////////////////////////////////////////////////////////////////////////// //
181 var
194 //==========================================================================
195 //
196 // GetTimerMS
197 //
198 //==========================================================================
200 begin
205 //==========================================================================
206 //
207 // findByPeer
208 //
209 //==========================================================================
211 var
213 begin
219 //==========================================================================
220 //
221 // ShutdownAll
222 //
223 //==========================================================================
225 var
229 begin
232 begin
234 begin
237 begin
241 //mlist[f].disconnect(false);
248 begin
252 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
253 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
254 // thank you, enet. let's ignore failures altogether then.
256 // if (sres < 0) then break;
261 begin
263 continue;
267 begin
269 //mlist[idx].disconnect(false);
271 end
273 begin
276 end
278 begin
288 //==========================================================================
289 //
290 // DisconnectAll
291 //
292 //==========================================================================
294 var
296 begin
298 begin
304 //==========================================================================
305 //
306 // ConnectAll
307 //
308 //==========================================================================
310 var
312 begin
313 // set flags; pulse will take care of the rest
315 begin
316 // force reconnect
318 // force updating
320 begin
328 //==========================================================================
329 //
330 // UpdateAll
331 //
332 //==========================================================================
334 var
336 begin
337 // set flags; pulse will take care of the rest
339 begin
347 //**************************************************************************
348 //
349 // public api
350 //
351 //**************************************************************************
353 //==========================================================================
354 //
355 // g_Net_Slist_Private
356 //
357 // make this server private
358 //
359 //==========================================================================
361 begin
367 //==========================================================================
368 //
369 // g_Net_Slist_Public
370 //
371 // make this server public
372 //
373 //==========================================================================
375 begin
377 begin
384 //==========================================================================
385 //
386 // g_Net_Slist_ServerUpdate
387 //
388 // called while the server is running
389 //
390 //==========================================================================
392 begin
397 // called when the server is started
399 begin
402 begin
409 //==========================================================================
410 //
411 // g_Net_Slist_ServerClosed
412 //
413 // called when the server is stopped
414 //
415 //==========================================================================
417 var
419 begin
421 begin
424 begin
432 //==========================================================================
433 //
434 // g_Net_Slist_ServerPlayerComes
435 //
436 // called when new netword player comes
437 //
438 //==========================================================================
440 begin
445 //==========================================================================
446 //
447 // g_Net_Slist_ServerPlayerLeaves
448 //
449 // called when new netword player comes
450 //
451 //==========================================================================
453 begin
458 //==========================================================================
459 //
460 // g_Net_Slist_ServerMapStarted
461 //
462 // started new map
463 //
464 //==========================================================================
466 begin
471 //==========================================================================
472 //
473 // g_Net_Slist_ServerRenamed
474 //
475 // this server renamed (or password mode changed, or other params changed)
476 //
477 //==========================================================================
479 begin
484 //**************************************************************************
485 //
486 // TMasterHost
487 //
488 //**************************************************************************
490 //==========================================================================
491 //
492 // TMasterHost.Create
493 //
494 //==========================================================================
496 begin
518 //==========================================================================
519 //
520 // TMasterHost.clear
521 //
522 //==========================================================================
524 begin
538 //==========================================================================
539 //
540 // TMasterHost.setAddress
541 //
542 //==========================================================================
544 begin
560 if (length(hostStr) > 0) then hostName := hostStr else hostName := IntToStr(enetAddr.host)+':'+IntToStr(ea.port);
566 //==========================================================================
567 //
568 // TMasterHost.isValid
569 //
570 //==========================================================================
572 begin
577 //==========================================================================
578 //
579 // TMasterHost.isAlive
580 //
581 // not disconnected
582 //
583 //==========================================================================
585 begin
590 //==========================================================================
591 //
592 // TMasterHost.isConnecting
593 //
594 // is connection in progress?
595 //
596 //==========================================================================
598 begin
603 //==========================================================================
604 //
605 // TMasterHost.isConnected
606 //
607 //==========================================================================
609 begin
614 //==========================================================================
615 //
616 // TMasterHost.connectedEvent
617 //
618 //==========================================================================
620 begin
626 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
630 //==========================================================================
631 //
632 // TMasterHost.disconnectedEvent
633 //
634 //==========================================================================
636 begin
640 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
644 //==========================================================================
645 //
646 // TMasterHost.receivedEvent
647 //
648 // `pkt` is never `nil`
649 //
650 //==========================================================================
652 var
658 begin
661 // packet type
668 //slUrgent := '';
670 // number of items
672 //g_Console_Add(_lc[I_NET_MSG]+Format(_lc[I_NET_SLIST_RETRIEVED], [Cnt, hostName]), True);
675 begin
678 begin
696 begin
697 // new master, supports version reports
700 begin
701 { TODO }
704 // even newer master, supports extra info
706 begin
708 if (slMOTD <> '') then e_LogWritefln('got MOTD from master at [%s]: %s', [hostName, slMOTD], TMsgType.Notify);
710 // check if the message has updated and the user has to read it again
713 if (s <> '') then e_LogWritefln('got urgent from master at [%s]: %s', [hostName, s], TMsgType.Notify);
719 //==========================================================================
720 //
721 // TMasterHost.disconnect
722 //
723 //==========================================================================
725 begin
727 begin
730 begin
735 end
736 else
737 begin
739 // main pulse will take care of the rest
742 end
743 else
744 begin
745 // just in case
753 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
757 //==========================================================================
758 //
759 // TMasterHost.connect
760 //
761 //==========================================================================
763 begin
767 begin
769 if (NetHostConReqTime = -1) then e_LogWritefln('ketmar broke master [%s] logic! (000)', [hostName], TMsgType.Notify);
770 if (isAlive()) then e_LogWritefln('ketmar broke master [%s] logic! (001)', [hostName], TMsgType.Notify);
771 end
772 else
773 begin
789 begin
791 exit;
799 //==========================================================================
800 //
801 // TMasterHost.writeInfo
802 //
803 //==========================================================================
805 var
807 begin
825 //==========================================================================
826 //
827 // TMasterHost.update
828 //
829 //==========================================================================
831 var
833 begin
836 begin
838 exit;
844 begin
845 try
848 //writeln(formatstrf('%08x', [NetAddr.host]), ' : ', NetAddr.host);
854 begin
856 begin
862 finally
865 end
866 else
867 begin
873 //==========================================================================
874 //
875 // TMasterHost.remove
876 //
877 //==========================================================================
879 var
881 begin
889 try
895 begin
898 finally
904 //==========================================================================
905 //
906 // TMasterHost.pulse
907 //
908 // this performs various scheduled tasks, if necessary
909 //
910 //==========================================================================
912 var
915 begin
919 // process pending connection timeout
921 begin
923 begin
925 // do not spam with error messages, it looks like the master is down
926 //g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
929 exit;
931 // send update, if necessary
933 begin
939 begin
940 //e_LogWritefln('update timeout: %d', [Integer(mrate)], TMsgType.Notify);
948 //**************************************************************************
949 //
950 // other functions
951 //
952 //**************************************************************************
953 type
956 var
960 //==========================================================================
961 //
962 // parseAddressPort
963 //
964 //==========================================================================
966 var
970 begin
982 begin
987 begin
988 try
990 except
1002 begin
1004 end
1005 else
1006 begin
1008 begin
1010 exit;
1019 //==========================================================================
1020 //
1021 // addMasterRecord
1022 //
1023 //==========================================================================
1025 var
1028 begin
1031 begin
1033 begin
1035 exit;
1040 begin
1051 //==========================================================================
1052 //
1053 // g_Net_Slist_Set
1054 //
1055 //==========================================================================
1057 var
1062 begin
1069 begin
1075 //writeln('list=[', list, ']');
1077 begin
1082 //writeln(' sa=[', sa, ']');
1086 // remove unknown master servers
1089 begin
1092 begin
1101 //**************************************************************************
1102 //
1103 // main pulse
1104 //
1105 //**************************************************************************
1107 //==========================================================================
1108 //
1109 // isMasterReportsEnabled
1110 //
1111 //==========================================================================
1113 begin
1118 //==========================================================================
1119 //
1120 // g_Net_Slist_Pulse
1121 //
1122 // non-zero timeout ignores current status (used to fetch server list)
1123 //
1124 //==========================================================================
1126 var
1133 begin
1137 begin
1139 begin
1142 exit;
1147 begin
1150 begin
1151 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_create)', TMsgType.Notify);
1154 Exit;
1160 // reconnect/disconnect/pulse for each master
1162 begin
1165 begin
1166 // not connected; try to reconnect if we're asking for a host list, or we are in netgame, and we are the host
1168 begin
1169 if (mlist[f].lastDisconnectTime = 0) or (ct < mlist[f].lastDisconnectTime) or (ct-mlist[f].lastDisconnectTime >= 1000*NMASTER_TIMEOUT_RECONNECT) then
1170 begin
1173 end
1174 else
1175 begin
1176 //e_LogWritefln('DEAD master [%s]: ct=%d; ldt=%d; diff=%d', [mlist[f].hostName, Integer(ct), Integer(mlist[f].lastDisconnectTime), Integer(ct-mlist[f].lastDisconnectTime)], TMsgType.Notify);
1179 end
1180 else
1181 begin
1182 // if we're not in slist query, and not in netgame (or not a host), disconnect
1184 begin
1186 begin
1197 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
1198 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
1199 // thank you, enet. let's ignore failures altogether then.
1203 begin
1204 {
1205 if (sres < 0) then
1206 begin
1207 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_service)', TMsgType.Notify);
1208 for f := 0 to High(mlist) do mlist[f].clear();
1209 SetLength(mlist, 0);
1210 enet_host_destroy(NetMHost);
1211 NetMHost := nil;
1212 exit;
1213 end;
1214 }
1218 begin
1221 end
1222 else
1223 begin
1225 begin
1227 end
1229 begin
1231 end
1233 begin
1246 //**************************************************************************
1247 //
1248 // gui and server list
1249 //
1250 //**************************************************************************
1252 //==========================================================================
1253 //
1254 // PingServer
1255 //
1256 //==========================================================================
1258 var
1262 begin
1276 //==========================================================================
1277 //
1278 // PingBcast
1279 //
1280 //==========================================================================
1282 var
1284 begin
1294 //==========================================================================
1295 //
1296 // g_Net_Slist_Fetch
1297 //
1298 //==========================================================================
1300 var
1313 begin
1317 begin
1335 begin
1350 begin
1371 var
1376 begin
1381 begin
1383 exit;
1391 begin
1399 // TODO: what should we identify the build with?
1403 try
1407 // wait until all servers connected and answered
1410 begin
1414 begin
1415 {
1416 e_LogWritefln(' master #%d: [%s] valid=%d; alive=%d; connected=%d; connecting=%d',
1417 [f, mlist[f].hostName, Integer(mlist[f].isValid()), Integer(mlist[f].isAlive()),
1418 Integer(mlist[f].isConnected()), Integer(mlist[f].isConnecting())], TMsgType.Notify);
1419 }
1422 begin
1424 begin
1427 begin
1428 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_WCONN], [mlist[f].hostName]));
1432 end
1434 begin
1437 end
1439 begin
1440 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
1442 begin
1445 begin
1447 begin
1453 end
1455 begin
1457 end
1459 begin
1463 end
1465 begin
1470 // check for timeout
1477 begin
1480 exit;
1484 {
1485 slUrgent := '';
1486 slReadUrgent := true;
1487 }
1491 begin
1494 begin
1497 begin
1499 begin
1501 break;
1505 begin
1513 begin
1515 begin
1521 begin
1529 begin
1531 exit;
1550 begin
1566 begin
1568 begin
1584 break;
1592 finally
1598 //==========================================================================
1599 //
1600 // GetServerFromTable
1601 //
1602 //==========================================================================
1603 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1604 begin
1620 Exit;
1622 Exit;
1627 //==========================================================================
1628 //
1629 // g_Serverlist_Draw
1630 //
1631 //==========================================================================
1633 var
1641 begin
1658 e_TextureFontPrintEx(gScreenWidth div 2 - mw, gScreenHeight-24, ip, gStdFont, 225, 225, 225, 1);
1660 // MOTD
1662 begin
1668 // Urgent message
1670 begin
1689 Exit;
1693 begin
1700 Exit;
1705 begin
1712 else
1714 end else
1741 begin
1743 // Name and map
1747 // Ping and similar count
1750 else
1753 else
1754 e_TextureFontPrintEx(mx - 68, y, IntToStr(Srv.Ping) + _lc[I_NET_SLIST_PING_MS], gStdFont, 255, 255, 255, 1);
1757 e_TextureFontPrintEx(mx - 68, y + 16, '< ' + IntToStr(Length(ST[I].Indices)) + ' >', gStdFont, 210, 210, 210, 1);
1759 // Game mode
1762 // Players
1763 e_TextureFontPrintEx(mx + 54, y, IntToStr(Srv.Players) + '/' + IntToStr(Srv.MaxPlayers), gStdFont, 255, 255, 255, 1);
1764 e_TextureFontPrintEx(mx + 54, y + 16, IntToStr(Srv.LocalPl) + '+' + IntToStr(Srv.Bots), gStdFont, 210, 210, 210, 1);
1766 // Version
1779 //==========================================================================
1780 //
1781 // g_Serverlist_GenerateTable
1782 //
1783 //==========================================================================
1785 var
1789 var
1791 begin
1794 Exit;
1796 begin
1798 continue;
1800 begin
1802 Exit;
1807 var
1809 begin
1817 var
1820 begin
1824 begin
1831 var
1834 begin
1838 begin
1844 begin
1847 Exit;
1849 begin
1852 begin
1858 end
1859 else
1860 begin
1873 //==========================================================================
1874 //
1875 // g_Serverlist_Control
1876 //
1877 //==========================================================================
1879 var
1882 begin
1886 Exit;
1893 begin
1901 Exit;
1904 // if there's a message on the screen,
1906 begin
1907 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1908 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1910 Exit;
1914 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1915 begin
1917 begin
1920 g_Game_Draw;
1921 sys_Repaint;
1924 begin
1927 end
1928 else
1935 end
1936 else
1941 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1942 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1943 begin
1945 begin
1948 begin
1956 Exit;
1957 end
1958 else
1963 Exit;
1965 end
1966 else
1970 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1971 begin
1973 begin
1981 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1982 begin
1984 begin
1993 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
1994 begin
1996 begin
2004 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
2005 begin
2007 begin
2008 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
2027 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
2028 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
2029 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
2030 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
2031 then