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)
168 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
176 implementation
178 uses
179 {$IFDEF ENABLE_MENU}
181 {$ENDIF}
182 {$IFNDEF HEADLESS}
184 {$ENDIF}
190 // ////////////////////////////////////////////////////////////////////////// //
191 var
202 //==========================================================================
203 //
204 // GetTimerMS
205 //
206 //==========================================================================
208 begin
213 //==========================================================================
214 //
215 // findByPeer
216 //
217 //==========================================================================
219 var
221 begin
227 //==========================================================================
228 //
229 // ShutdownAll
230 //
231 //==========================================================================
233 var
237 begin
240 begin
242 begin
245 begin
249 //mlist[f].disconnect(false);
256 begin
260 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
261 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
262 // thank you, enet. let's ignore failures altogether then.
264 // if (sres < 0) then break;
269 begin
271 continue;
275 begin
277 //mlist[idx].disconnect(false);
279 end
281 begin
284 end
286 begin
296 //==========================================================================
297 //
298 // DisconnectAll
299 //
300 //==========================================================================
302 var
304 begin
306 begin
312 //==========================================================================
313 //
314 // ConnectAll
315 //
316 //==========================================================================
318 var
320 begin
321 // set flags; pulse will take care of the rest
323 begin
324 // force reconnect
326 // force updating
328 begin
336 //==========================================================================
337 //
338 // UpdateAll
339 //
340 //==========================================================================
342 var
344 begin
345 // set flags; pulse will take care of the rest
347 begin
355 //**************************************************************************
356 //
357 // public api
358 //
359 //**************************************************************************
361 //==========================================================================
362 //
363 // g_Net_Slist_Private
364 //
365 // make this server private
366 //
367 //==========================================================================
369 begin
375 //==========================================================================
376 //
377 // g_Net_Slist_Public
378 //
379 // make this server public
380 //
381 //==========================================================================
383 begin
385 begin
392 //==========================================================================
393 //
394 // g_Net_Slist_ServerUpdate
395 //
396 // called while the server is running
397 //
398 //==========================================================================
400 begin
405 // called when the server is started
407 begin
410 begin
417 //==========================================================================
418 //
419 // g_Net_Slist_ServerClosed
420 //
421 // called when the server is stopped
422 //
423 //==========================================================================
425 var
427 begin
429 begin
432 begin
440 //==========================================================================
441 //
442 // g_Net_Slist_ServerPlayerComes
443 //
444 // called when new netword player comes
445 //
446 //==========================================================================
448 begin
453 //==========================================================================
454 //
455 // g_Net_Slist_ServerPlayerLeaves
456 //
457 // called when new netword player comes
458 //
459 //==========================================================================
461 begin
466 //==========================================================================
467 //
468 // g_Net_Slist_ServerMapStarted
469 //
470 // started new map
471 //
472 //==========================================================================
474 begin
479 //==========================================================================
480 //
481 // g_Net_Slist_ServerRenamed
482 //
483 // this server renamed (or password mode changed, or other params changed)
484 //
485 //==========================================================================
487 begin
492 //**************************************************************************
493 //
494 // TMasterHost
495 //
496 //**************************************************************************
498 //==========================================================================
499 //
500 // TMasterHost.Create
501 //
502 //==========================================================================
504 begin
526 //==========================================================================
527 //
528 // TMasterHost.clear
529 //
530 //==========================================================================
532 begin
546 //==========================================================================
547 //
548 // TMasterHost.setAddress
549 //
550 //==========================================================================
552 begin
568 if (length(hostStr) > 0) then hostName := hostStr else hostName := IntToStr(enetAddr.host)+':'+IntToStr(ea.port);
574 //==========================================================================
575 //
576 // TMasterHost.isValid
577 //
578 //==========================================================================
580 begin
585 //==========================================================================
586 //
587 // TMasterHost.isAlive
588 //
589 // not disconnected
590 //
591 //==========================================================================
593 begin
598 //==========================================================================
599 //
600 // TMasterHost.isConnecting
601 //
602 // is connection in progress?
603 //
604 //==========================================================================
606 begin
611 //==========================================================================
612 //
613 // TMasterHost.isConnected
614 //
615 //==========================================================================
617 begin
622 //==========================================================================
623 //
624 // TMasterHost.connectedEvent
625 //
626 //==========================================================================
628 begin
634 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
638 //==========================================================================
639 //
640 // TMasterHost.disconnectedEvent
641 //
642 //==========================================================================
644 begin
648 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
652 //==========================================================================
653 //
654 // TMasterHost.receivedEvent
655 //
656 // `pkt` is never `nil`
657 //
658 //==========================================================================
660 var
666 begin
669 // packet type
676 //slUrgent := '';
678 // number of items
680 //g_Console_Add(_lc[I_NET_MSG]+Format(_lc[I_NET_SLIST_RETRIEVED], [Cnt, hostName]), True);
683 begin
686 begin
704 begin
705 // new master, supports version reports
708 begin
709 { TODO }
712 // even newer master, supports extra info
714 begin
716 if (slMOTD <> '') then e_LogWritefln('got MOTD from master at [%s]: %s', [hostName, slMOTD], TMsgType.Notify);
718 // check if the message has updated and the user has to read it again
721 if (s <> '') then e_LogWritefln('got urgent from master at [%s]: %s', [hostName, s], TMsgType.Notify);
727 //==========================================================================
728 //
729 // TMasterHost.disconnect
730 //
731 //==========================================================================
733 begin
735 begin
738 begin
743 end
744 else
745 begin
747 // main pulse will take care of the rest
750 end
751 else
752 begin
753 // just in case
761 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
765 //==========================================================================
766 //
767 // TMasterHost.connect
768 //
769 //==========================================================================
771 begin
775 begin
777 if (NetHostConReqTime = -1) then e_LogWritefln('ketmar broke master [%s] logic! (000)', [hostName], TMsgType.Notify);
778 if (isAlive()) then e_LogWritefln('ketmar broke master [%s] logic! (001)', [hostName], TMsgType.Notify);
779 end
780 else
781 begin
797 begin
799 exit;
807 //==========================================================================
808 //
809 // TMasterHost.writeInfo
810 //
811 //==========================================================================
813 var
815 begin
833 //==========================================================================
834 //
835 // TMasterHost.update
836 //
837 //==========================================================================
839 var
841 begin
844 begin
846 exit;
852 begin
853 try
856 //writeln(formatstrf('%08x', [NetAddr.host]), ' : ', NetAddr.host);
862 begin
864 begin
870 finally
873 end
874 else
875 begin
881 //==========================================================================
882 //
883 // TMasterHost.remove
884 //
885 //==========================================================================
887 var
889 begin
897 try
903 begin
906 finally
912 //==========================================================================
913 //
914 // TMasterHost.pulse
915 //
916 // this performs various scheduled tasks, if necessary
917 //
918 //==========================================================================
920 var
923 begin
927 // process pending connection timeout
929 begin
931 begin
933 // do not spam with error messages, it looks like the master is down
934 //g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
937 exit;
939 // send update, if necessary
941 begin
947 begin
948 //e_LogWritefln('update timeout: %d', [Integer(mrate)], TMsgType.Notify);
956 //**************************************************************************
957 //
958 // other functions
959 //
960 //**************************************************************************
961 type
964 var
968 //==========================================================================
969 //
970 // parseAddressPort
971 //
972 //==========================================================================
974 var
978 begin
990 begin
995 begin
996 try
998 except
1010 begin
1012 end
1013 else
1014 begin
1016 begin
1018 exit;
1027 //==========================================================================
1028 //
1029 // addMasterRecord
1030 //
1031 //==========================================================================
1033 var
1036 begin
1039 begin
1041 begin
1043 exit;
1048 begin
1059 //==========================================================================
1060 //
1061 // g_Net_Slist_Set
1062 //
1063 //==========================================================================
1065 var
1070 begin
1076 //writeln('list=[', list, ']');
1078 begin
1083 //writeln(' sa=[', sa, ']');
1087 // remove unknown master servers
1090 begin
1093 begin
1102 //**************************************************************************
1103 //
1104 // main pulse
1105 //
1106 //**************************************************************************
1108 //==========================================================================
1109 //
1110 // isMasterReportsEnabled
1111 //
1112 //==========================================================================
1114 begin
1119 //==========================================================================
1120 //
1121 // g_Net_Slist_Pulse
1122 //
1123 // non-zero timeout ignores current status (used to fetch server list)
1124 //
1125 //==========================================================================
1127 var
1134 begin
1138 begin
1140 begin
1143 exit;
1148 begin
1151 begin
1152 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_create)', TMsgType.Notify);
1155 Exit;
1161 // reconnect/disconnect/pulse for each master
1163 begin
1166 begin
1167 // not connected; try to reconnect if we're asking for a host list, or we are in netgame, and we are the host
1169 begin
1170 if (mlist[f].lastDisconnectTime = 0) or (ct < mlist[f].lastDisconnectTime) or (ct-mlist[f].lastDisconnectTime >= 1000*NMASTER_TIMEOUT_RECONNECT) then
1171 begin
1174 end
1175 else
1176 begin
1177 //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);
1180 end
1181 else
1182 begin
1183 // if we're not in slist query, and not in netgame (or not a host), disconnect
1185 begin
1187 begin
1198 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
1199 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
1200 // thank you, enet. let's ignore failures altogether then.
1204 begin
1205 {
1206 if (sres < 0) then
1207 begin
1208 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_service)', TMsgType.Notify);
1209 for f := 0 to High(mlist) do mlist[f].clear();
1210 SetLength(mlist, 0);
1211 enet_host_destroy(NetMHost);
1212 NetMHost := nil;
1213 exit;
1214 end;
1215 }
1219 begin
1222 end
1223 else
1224 begin
1226 begin
1228 end
1230 begin
1232 end
1234 begin
1247 //**************************************************************************
1248 //
1249 // gui and server list
1250 //
1251 //**************************************************************************
1253 //==========================================================================
1254 //
1255 // PingServer
1256 //
1257 //==========================================================================
1259 var
1263 begin
1277 //==========================================================================
1278 //
1279 // PingBcast
1280 //
1281 //==========================================================================
1283 var
1285 begin
1295 //==========================================================================
1296 //
1297 // g_Net_Slist_Fetch
1298 //
1299 //==========================================================================
1301 var
1314 begin
1318 begin
1336 begin
1351 begin
1372 var
1378 begin
1383 begin
1385 exit;
1393 begin
1401 // TODO: what should we identify the build with?
1405 try
1409 // wait until all servers connected and answered
1412 begin
1416 begin
1417 {
1418 e_LogWritefln(' master #%d: [%s] valid=%d; alive=%d; connected=%d; connecting=%d',
1419 [f, mlist[f].hostName, Integer(mlist[f].isValid()), Integer(mlist[f].isAlive()),
1420 Integer(mlist[f].isConnected()), Integer(mlist[f].isConnecting())], TMsgType.Notify);
1421 }
1424 begin
1426 begin
1429 begin
1430 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_WCONN], [mlist[f].hostName]));
1434 end
1436 begin
1439 end
1441 begin
1442 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
1444 begin
1447 begin
1449 begin
1455 end
1457 begin
1459 end
1461 begin
1465 end
1467 begin
1472 // check for timeout
1479 begin
1482 exit;
1487 {
1488 slUrgent := '';
1489 slReadUrgent := true;
1490 }
1494 begin
1497 begin
1500 begin
1502 begin
1504 break;
1508 begin
1516 begin
1518 begin
1524 begin
1532 begin
1534 exit;
1553 begin
1566 begin
1588 begin
1593 break;
1597 begin
1607 finally
1613 //==========================================================================
1614 //
1615 // GetServerFromTable
1616 //
1617 //==========================================================================
1618 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1619 begin
1635 Exit;
1637 Exit;
1642 //==========================================================================
1643 //
1644 // g_Serverlist_GenerateTable
1645 //
1646 //==========================================================================
1648 var
1652 var
1654 begin
1657 Exit;
1659 begin
1661 continue;
1663 begin
1665 Exit;
1670 var
1672 begin
1680 var
1683 begin
1687 begin
1694 var
1697 begin
1701 begin
1707 begin
1710 Exit;
1713 begin
1716 begin
1722 end
1723 else
1724 begin
1737 //==========================================================================
1738 //
1739 // g_Serverlist_Control
1740 //
1741 //==========================================================================
1743 var
1746 begin
1750 Exit;
1752 {$IFDEF HEADLESS}
1754 {$ELSE}
1756 {$ENDIF}
1761 begin
1765 {$IFDEF ENABLE_MENU}
1770 {$ENDIF}
1771 Exit;
1774 // if there's a message on the screen,
1776 begin
1777 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1778 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1780 Exit;
1784 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1785 begin
1787 begin
1790 {$IFNDEF HEADLESS}
1791 r_Render_Draw;
1792 sys_Repaint;
1793 {$ENDIF}
1796 begin
1799 end
1800 else
1807 end
1808 else
1813 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1814 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1815 begin
1817 begin
1820 begin
1821 {$IFDEF ENABLE_MENU}
1824 {$ENDIF}
1826 {$IFDEF ENABLE_MENU}
1828 {$ENDIF}
1832 Exit;
1833 end
1834 else
1839 Exit;
1841 end
1842 else
1846 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1847 begin
1849 begin
1857 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1858 begin
1860 begin
1869 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
1870 begin
1872 begin
1880 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
1881 begin
1883 begin
1884 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
1903 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
1904 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
1905 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
1906 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
1907 then