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
90 private
93 public
105 // call as often as you want, the object will do the rest
106 // but try to call this at least once in 100 msecs
123 var
138 // make this server private
140 // make this server public
143 // called while the server is running
145 // called when the server is started
147 // called when the server is stopped
150 // called when new netword player comes
152 // called when new netword player comes
154 // started new map
156 // this server renamed (or password mode changed, or other params changed)
159 // non-zero timeout ignores current status (used to fetch server list)
171 implementation
173 uses
179 // ////////////////////////////////////////////////////////////////////////// //
180 var
193 //==========================================================================
194 //
195 // GetTimerMS
196 //
197 //==========================================================================
199 begin
204 //==========================================================================
205 //
206 // findByPeer
207 //
208 //==========================================================================
210 var
212 begin
218 //==========================================================================
219 //
220 // ShutdownAll
221 //
222 //==========================================================================
224 var
228 begin
231 begin
233 begin
236 begin
240 //mlist[f].disconnect(false);
247 begin
251 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
252 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
253 // thank you, enet. let's ignore failures altogether then.
255 // if (sres < 0) then break;
260 begin
262 continue;
266 begin
268 //mlist[idx].disconnect(false);
270 end
272 begin
275 end
277 begin
287 //==========================================================================
288 //
289 // DisconnectAll
290 //
291 //==========================================================================
293 var
295 begin
297 begin
303 //==========================================================================
304 //
305 // ConnectAll
306 //
307 //==========================================================================
309 var
311 begin
312 // set flags; pulse will take care of the rest
314 begin
315 // force reconnect
317 // force updating
319 begin
327 //==========================================================================
328 //
329 // UpdateAll
330 //
331 //==========================================================================
333 var
335 begin
336 // set flags; pulse will take care of the rest
338 begin
346 //**************************************************************************
347 //
348 // public api
349 //
350 //**************************************************************************
352 //==========================================================================
353 //
354 // g_Net_Slist_Private
355 //
356 // make this server private
357 //
358 //==========================================================================
360 begin
366 //==========================================================================
367 //
368 // g_Net_Slist_Public
369 //
370 // make this server public
371 //
372 //==========================================================================
374 begin
376 begin
383 //==========================================================================
384 //
385 // g_Net_Slist_ServerUpdate
386 //
387 // called while the server is running
388 //
389 //==========================================================================
391 begin
396 // called when the server is started
398 begin
401 begin
408 //==========================================================================
409 //
410 // g_Net_Slist_ServerClosed
411 //
412 // called when the server is stopped
413 //
414 //==========================================================================
416 var
418 begin
420 begin
423 begin
431 //==========================================================================
432 //
433 // g_Net_Slist_ServerPlayerComes
434 //
435 // called when new netword player comes
436 //
437 //==========================================================================
439 begin
444 //==========================================================================
445 //
446 // g_Net_Slist_ServerPlayerLeaves
447 //
448 // called when new netword player comes
449 //
450 //==========================================================================
452 begin
457 //==========================================================================
458 //
459 // g_Net_Slist_ServerMapStarted
460 //
461 // started new map
462 //
463 //==========================================================================
465 begin
470 //==========================================================================
471 //
472 // g_Net_Slist_ServerRenamed
473 //
474 // this server renamed (or password mode changed, or other params changed)
475 //
476 //==========================================================================
478 begin
483 //**************************************************************************
484 //
485 // TMasterHost
486 //
487 //**************************************************************************
489 //==========================================================================
490 //
491 // TMasterHost.Create
492 //
493 //==========================================================================
495 begin
515 //==========================================================================
516 //
517 // TMasterHost.clear
518 //
519 //==========================================================================
521 begin
535 //==========================================================================
536 //
537 // TMasterHost.setAddress
538 //
539 //==========================================================================
541 begin
557 if (length(hostStr) > 0) then hostName := hostStr else hostName := IntToStr(enetAddr.host)+':'+IntToStr(ea.port);
563 //==========================================================================
564 //
565 // TMasterHost.isValid
566 //
567 //==========================================================================
569 begin
574 //==========================================================================
575 //
576 // TMasterHost.isAlive
577 //
578 // not disconnected
579 //
580 //==========================================================================
582 begin
587 //==========================================================================
588 //
589 // TMasterHost.isConnecting
590 //
591 // is connection in progress?
592 //
593 //==========================================================================
595 begin
600 //==========================================================================
601 //
602 // TMasterHost.isConnected
603 //
604 //==========================================================================
606 begin
611 //==========================================================================
612 //
613 // TMasterHost.connectedEvent
614 //
615 //==========================================================================
617 begin
623 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
627 //==========================================================================
628 //
629 // TMasterHost.disconnectedEvent
630 //
631 //==========================================================================
633 begin
637 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
641 //==========================================================================
642 //
643 // TMasterHost.receivedEvent
644 //
645 // `pkt` is never `nil`
646 //
647 //==========================================================================
649 var
655 begin
658 // packet type
665 //slUrgent := '';
667 // number of items
669 //g_Console_Add(_lc[I_NET_MSG]+Format(_lc[I_NET_SLIST_RETRIEVED], [Cnt, hostName]), True);
672 begin
675 begin
693 begin
694 // new master, supports version reports
697 begin
698 { TODO }
701 // even newer master, supports extra info
703 begin
705 if (slMOTD <> '') then e_LogWritefln('got MOTD from master at [%s]: %s', [hostName, slMOTD], TMsgType.Notify);
707 // check if the message has updated and the user has to read it again
710 if (s <> '') then e_LogWritefln('got urgent from master at [%s]: %s', [hostName, s], TMsgType.Notify);
716 //==========================================================================
717 //
718 // TMasterHost.disconnect
719 //
720 //==========================================================================
722 begin
724 begin
727 begin
732 end
733 else
734 begin
736 // main pulse will take care of the rest
739 end
740 else
741 begin
742 // just in case
750 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
754 //==========================================================================
755 //
756 // TMasterHost.connect
757 //
758 //==========================================================================
760 begin
764 begin
766 if (NetHostConReqTime = -1) then e_LogWritefln('ketmar broke master [%s] logic! (000)', [hostName], TMsgType.Notify);
767 if (isAlive()) then e_LogWritefln('ketmar broke master [%s] logic! (001)', [hostName], TMsgType.Notify);
768 end
769 else
770 begin
785 begin
787 exit;
795 //==========================================================================
796 //
797 // TMasterHost.writeInfo
798 //
799 //==========================================================================
801 var
803 begin
821 //==========================================================================
822 //
823 // TMasterHost.update
824 //
825 //==========================================================================
827 var
829 begin
832 begin
834 exit;
840 begin
841 try
844 //writeln(formatstrf('%08x', [NetAddr.host]), ' : ', NetAddr.host);
850 begin
852 begin
858 finally
861 end
862 else
863 begin
869 //==========================================================================
870 //
871 // TMasterHost.remove
872 //
873 //==========================================================================
875 var
877 begin
885 try
891 begin
894 finally
900 //==========================================================================
901 //
902 // TMasterHost.pulse
903 //
904 // this performs various scheduled tasks, if necessary
905 //
906 //==========================================================================
908 var
911 begin
915 // process pending connection timeout
917 begin
919 begin
921 // do not spam with error messages, it looks like the master is down
922 //g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
925 exit;
927 // send update, if necessary
929 begin
935 begin
936 //e_LogWritefln('update timeout: %d', [Integer(mrate)], TMsgType.Notify);
944 //**************************************************************************
945 //
946 // other functions
947 //
948 //**************************************************************************
949 type
952 var
956 //==========================================================================
957 //
958 // parseAddressPort
959 //
960 //==========================================================================
962 var
966 begin
978 begin
983 begin
984 try
986 except
998 begin
1000 end
1001 else
1002 begin
1004 begin
1006 exit;
1015 //==========================================================================
1016 //
1017 // addMasterRecord
1018 //
1019 //==========================================================================
1021 var
1024 begin
1027 begin
1029 begin
1031 exit;
1036 begin
1047 //==========================================================================
1048 //
1049 // g_Net_Slist_Set
1050 //
1051 //==========================================================================
1053 var
1058 begin
1065 begin
1071 //writeln('list=[', list, ']');
1073 begin
1078 //writeln(' sa=[', sa, ']');
1082 // remove unknown master servers
1085 begin
1088 begin
1097 //**************************************************************************
1098 //
1099 // main pulse
1100 //
1101 //**************************************************************************
1103 //==========================================================================
1104 //
1105 // isMasterReportsEnabled
1106 //
1107 //==========================================================================
1109 begin
1114 //==========================================================================
1115 //
1116 // g_Net_Slist_Pulse
1117 //
1118 // non-zero timeout ignores current status (used to fetch server list)
1119 //
1120 //==========================================================================
1122 var
1129 begin
1133 begin
1135 begin
1138 exit;
1143 begin
1146 begin
1147 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_create)', TMsgType.Notify);
1150 Exit;
1156 // reconnect/disconnect/pulse for each master
1158 begin
1161 begin
1162 // not connected; try to reconnect if we're asking for a host list, or we are in netgame, and we are the host
1164 begin
1165 if (mlist[f].lastDisconnectTime = 0) or (ct < mlist[f].lastDisconnectTime) or (ct-mlist[f].lastDisconnectTime >= 1000*NMASTER_TIMEOUT_RECONNECT) then
1166 begin
1169 end
1170 else
1171 begin
1172 //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);
1175 end
1176 else
1177 begin
1178 // if we're not in slist query, and not in netgame (or not a host), disconnect
1180 begin
1182 begin
1193 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
1194 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
1195 // thank you, enet. let's ignore failures altogether then.
1199 begin
1200 {
1201 if (sres < 0) then
1202 begin
1203 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_service)', TMsgType.Notify);
1204 for f := 0 to High(mlist) do mlist[f].clear();
1205 SetLength(mlist, 0);
1206 enet_host_destroy(NetMHost);
1207 NetMHost := nil;
1208 exit;
1209 end;
1210 }
1214 begin
1217 end
1218 else
1219 begin
1221 begin
1223 end
1225 begin
1227 end
1229 begin
1242 //**************************************************************************
1243 //
1244 // gui and server list
1245 //
1246 //**************************************************************************
1248 //==========================================================================
1249 //
1250 // PingServer
1251 //
1252 //==========================================================================
1254 var
1258 begin
1272 //==========================================================================
1273 //
1274 // PingBcast
1275 //
1276 //==========================================================================
1278 var
1280 begin
1290 //==========================================================================
1291 //
1292 // g_Net_Slist_Fetch
1293 //
1294 //==========================================================================
1296 var
1309 begin
1313 begin
1331 begin
1346 begin
1367 var
1372 begin
1377 begin
1379 exit;
1389 // TODO: what should we identify the build with?
1393 try
1397 // wait until all servers connected and answered
1400 begin
1404 begin
1405 {
1406 e_LogWritefln(' master #%d: [%s] valid=%d; alive=%d; connected=%d; connecting=%d',
1407 [f, mlist[f].hostName, Integer(mlist[f].isValid()), Integer(mlist[f].isAlive()),
1408 Integer(mlist[f].isConnected()), Integer(mlist[f].isConnecting())], TMsgType.Notify);
1409 }
1412 begin
1415 begin
1416 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_WCONN], [mlist[f].hostName]));
1420 end
1422 begin
1423 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
1425 begin
1428 begin
1430 begin
1436 end
1438 begin
1440 end
1442 begin
1445 end
1447 begin
1452 // check for timeout
1459 begin
1462 exit;
1466 {
1467 slUrgent := '';
1468 slReadUrgent := true;
1469 }
1473 begin
1476 begin
1479 begin
1481 begin
1483 break;
1487 begin
1495 begin
1497 begin
1503 begin
1511 begin
1513 exit;
1532 begin
1548 begin
1550 begin
1566 break;
1574 finally
1580 //==========================================================================
1581 //
1582 // GetServerFromTable
1583 //
1584 //==========================================================================
1585 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1586 begin
1602 Exit;
1604 Exit;
1609 //==========================================================================
1610 //
1611 // g_Serverlist_Draw
1612 //
1613 //==========================================================================
1615 var
1623 begin
1640 e_TextureFontPrintEx(gScreenWidth div 2 - mw, gScreenHeight-24, ip, gStdFont, 225, 225, 225, 1);
1642 // MOTD
1644 begin
1650 // Urgent message
1652 begin
1671 Exit;
1675 begin
1682 Exit;
1687 begin
1694 else
1696 end else
1723 begin
1725 // Name and map
1729 // Ping and similar count
1732 else
1735 else
1736 e_TextureFontPrintEx(mx - 68, y, IntToStr(Srv.Ping) + _lc[I_NET_SLIST_PING_MS], gStdFont, 255, 255, 255, 1);
1739 e_TextureFontPrintEx(mx - 68, y + 16, '< ' + IntToStr(Length(ST[I].Indices)) + ' >', gStdFont, 210, 210, 210, 1);
1741 // Game mode
1744 // Players
1745 e_TextureFontPrintEx(mx + 54, y, IntToStr(Srv.Players) + '/' + IntToStr(Srv.MaxPlayers), gStdFont, 255, 255, 255, 1);
1746 e_TextureFontPrintEx(mx + 54, y + 16, IntToStr(Srv.LocalPl) + '+' + IntToStr(Srv.Bots), gStdFont, 210, 210, 210, 1);
1748 // Version
1761 //==========================================================================
1762 //
1763 // g_Serverlist_GenerateTable
1764 //
1765 //==========================================================================
1767 var
1771 var
1773 begin
1776 Exit;
1778 begin
1780 continue;
1782 begin
1784 Exit;
1789 var
1791 begin
1799 var
1802 begin
1806 begin
1813 var
1816 begin
1820 begin
1826 begin
1829 Exit;
1831 begin
1834 begin
1840 end
1841 else
1842 begin
1855 //==========================================================================
1856 //
1857 // g_Serverlist_Control
1858 //
1859 //==========================================================================
1861 var
1864 begin
1868 Exit;
1875 begin
1883 Exit;
1886 // if there's a message on the screen,
1888 begin
1889 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1890 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1892 Exit;
1896 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1897 begin
1899 begin
1902 g_Game_Draw;
1903 sys_Repaint;
1906 begin
1909 end
1910 else
1917 end
1918 else
1923 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1924 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1925 begin
1927 begin
1930 begin
1938 Exit;
1939 end
1940 else
1945 Exit;
1947 end
1948 else
1952 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1953 begin
1955 begin
1963 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1964 begin
1966 begin
1975 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
1976 begin
1978 begin
1986 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
1987 begin
1989 begin
1990 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
2009 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
2010 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
2011 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
2012 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
2013 then