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
1068 //writeln('list=[', list, ']');
1070 begin
1075 //writeln(' sa=[', sa, ']');
1079 // remove unknown master servers
1082 begin
1085 begin
1094 //**************************************************************************
1095 //
1096 // main pulse
1097 //
1098 //**************************************************************************
1100 //==========================================================================
1101 //
1102 // isMasterReportsEnabled
1103 //
1104 //==========================================================================
1106 begin
1111 //==========================================================================
1112 //
1113 // g_Net_Slist_Pulse
1114 //
1115 // non-zero timeout ignores current status (used to fetch server list)
1116 //
1117 //==========================================================================
1119 var
1126 begin
1130 begin
1132 begin
1135 exit;
1140 begin
1143 begin
1144 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_create)', TMsgType.Notify);
1147 Exit;
1153 // reconnect/disconnect/pulse for each master
1155 begin
1158 begin
1159 // not connected; try to reconnect if we're asking for a host list, or we are in netgame, and we are the host
1161 begin
1162 if (mlist[f].lastDisconnectTime = 0) or (ct < mlist[f].lastDisconnectTime) or (ct-mlist[f].lastDisconnectTime >= 1000*NMASTER_TIMEOUT_RECONNECT) then
1163 begin
1166 end
1167 else
1168 begin
1169 //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);
1172 end
1173 else
1174 begin
1175 // if we're not in slist query, and not in netgame (or not a host), disconnect
1177 begin
1179 begin
1190 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
1191 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
1192 // thank you, enet. let's ignore failures altogether then.
1196 begin
1197 {
1198 if (sres < 0) then
1199 begin
1200 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_service)', TMsgType.Notify);
1201 for f := 0 to High(mlist) do mlist[f].clear();
1202 SetLength(mlist, 0);
1203 enet_host_destroy(NetMHost);
1204 NetMHost := nil;
1205 exit;
1206 end;
1207 }
1211 begin
1214 end
1215 else
1216 begin
1218 begin
1220 end
1222 begin
1224 end
1226 begin
1239 //**************************************************************************
1240 //
1241 // gui and server list
1242 //
1243 //**************************************************************************
1245 //==========================================================================
1246 //
1247 // PingServer
1248 //
1249 //==========================================================================
1251 var
1255 begin
1269 //==========================================================================
1270 //
1271 // PingBcast
1272 //
1273 //==========================================================================
1275 var
1277 begin
1287 //==========================================================================
1288 //
1289 // g_Net_Slist_Fetch
1290 //
1291 //==========================================================================
1293 var
1306 begin
1310 begin
1328 begin
1343 begin
1364 var
1370 begin
1375 begin
1377 exit;
1385 begin
1393 // TODO: what should we identify the build with?
1397 try
1401 // wait until all servers connected and answered
1404 begin
1408 begin
1409 {
1410 e_LogWritefln(' master #%d: [%s] valid=%d; alive=%d; connected=%d; connecting=%d',
1411 [f, mlist[f].hostName, Integer(mlist[f].isValid()), Integer(mlist[f].isAlive()),
1412 Integer(mlist[f].isConnected()), Integer(mlist[f].isConnecting())], TMsgType.Notify);
1413 }
1416 begin
1418 begin
1421 begin
1422 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_WCONN], [mlist[f].hostName]));
1426 end
1428 begin
1431 end
1433 begin
1434 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
1436 begin
1439 begin
1441 begin
1447 end
1449 begin
1451 end
1453 begin
1457 end
1459 begin
1464 // check for timeout
1471 begin
1474 exit;
1479 {
1480 slUrgent := '';
1481 slReadUrgent := true;
1482 }
1486 begin
1489 begin
1492 begin
1494 begin
1496 break;
1500 begin
1508 begin
1510 begin
1516 begin
1524 begin
1526 exit;
1545 begin
1558 begin
1580 begin
1585 break;
1589 begin
1599 finally
1605 //==========================================================================
1606 //
1607 // GetServerFromTable
1608 //
1609 //==========================================================================
1610 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1611 begin
1627 Exit;
1629 Exit;
1634 //==========================================================================
1635 //
1636 // g_Serverlist_Draw
1637 //
1638 //==========================================================================
1640 var
1648 begin
1665 e_TextureFontPrintEx(gScreenWidth div 2 - mw, gScreenHeight-24, ip, gStdFont, 225, 225, 225, 1);
1667 // MOTD
1669 begin
1675 // Urgent message
1677 begin
1696 Exit;
1700 begin
1707 Exit;
1712 begin
1719 else
1721 end else
1748 begin
1750 // Name and map
1754 // Ping and similar count
1757 else
1760 else
1761 e_TextureFontPrintEx(mx - 68, y, IntToStr(Srv.Ping) + _lc[I_NET_SLIST_PING_MS], gStdFont, 255, 255, 255, 1);
1764 e_TextureFontPrintEx(mx - 68, y + 16, '< ' + IntToStr(Length(ST[I].Indices)) + ' >', gStdFont, 210, 210, 210, 1);
1766 // Game mode
1769 // Players
1770 e_TextureFontPrintEx(mx + 54, y, IntToStr(Srv.Players) + '/' + IntToStr(Srv.MaxPlayers), gStdFont, 255, 255, 255, 1);
1771 e_TextureFontPrintEx(mx + 54, y + 16, IntToStr(Srv.LocalPl) + '+' + IntToStr(Srv.Bots), gStdFont, 210, 210, 210, 1);
1773 // Version
1786 //==========================================================================
1787 //
1788 // g_Serverlist_GenerateTable
1789 //
1790 //==========================================================================
1792 var
1796 var
1798 begin
1801 Exit;
1803 begin
1805 continue;
1807 begin
1809 Exit;
1814 var
1816 begin
1824 var
1827 begin
1831 begin
1838 var
1841 begin
1845 begin
1851 begin
1854 Exit;
1857 begin
1860 begin
1866 end
1867 else
1868 begin
1881 //==========================================================================
1882 //
1883 // g_Serverlist_Control
1884 //
1885 //==========================================================================
1887 var
1890 begin
1894 Exit;
1901 begin
1909 Exit;
1912 // if there's a message on the screen,
1914 begin
1915 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1916 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1918 Exit;
1922 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1923 begin
1925 begin
1928 g_Game_Draw;
1929 sys_Repaint;
1932 begin
1935 end
1936 else
1943 end
1944 else
1949 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1950 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1951 begin
1953 begin
1956 begin
1964 Exit;
1965 end
1966 else
1971 Exit;
1973 end
1974 else
1978 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1979 begin
1981 begin
1989 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1990 begin
1992 begin
2001 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
2002 begin
2004 begin
2012 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
2013 begin
2015 begin
2016 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
2035 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
2036 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
2037 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
2038 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
2039 then