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;
1486 {
1487 slUrgent := '';
1488 slReadUrgent := true;
1489 }
1493 begin
1496 begin
1499 begin
1501 begin
1503 break;
1507 begin
1515 begin
1517 begin
1523 begin
1531 begin
1533 exit;
1552 begin
1565 begin
1587 begin
1592 break;
1596 begin
1606 finally
1612 //==========================================================================
1613 //
1614 // GetServerFromTable
1615 //
1616 //==========================================================================
1617 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1618 begin
1634 Exit;
1636 Exit;
1641 //==========================================================================
1642 //
1643 // g_Serverlist_GenerateTable
1644 //
1645 //==========================================================================
1647 var
1651 var
1653 begin
1656 Exit;
1658 begin
1660 continue;
1662 begin
1664 Exit;
1669 var
1671 begin
1679 var
1682 begin
1686 begin
1693 var
1696 begin
1700 begin
1706 begin
1709 Exit;
1712 begin
1715 begin
1721 end
1722 else
1723 begin
1736 //==========================================================================
1737 //
1738 // g_Serverlist_Control
1739 //
1740 //==========================================================================
1742 var
1745 begin
1749 Exit;
1751 {$IFDEF HEADLESS}
1753 {$ELSE}
1755 {$ENDIF}
1760 begin
1764 {$IFDEF ENABLE_MENU}
1769 {$ENDIF}
1770 Exit;
1773 // if there's a message on the screen,
1775 begin
1776 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1777 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1779 Exit;
1783 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1784 begin
1786 begin
1789 {$IFNDEF HEADLESS}
1790 r_Render_Draw;
1791 sys_Repaint;
1792 {$ENDIF}
1795 begin
1798 end
1799 else
1806 end
1807 else
1812 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1813 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1814 begin
1816 begin
1819 begin
1820 {$IFDEF ENABLE_MENU}
1823 {$ENDIF}
1825 {$IFDEF ENABLE_MENU}
1827 {$ENDIF}
1831 Exit;
1832 end
1833 else
1838 Exit;
1840 end
1841 else
1845 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1846 begin
1848 begin
1856 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1857 begin
1859 begin
1868 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
1869 begin
1871 begin
1879 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
1880 begin
1882 begin
1883 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
1902 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
1903 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
1904 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
1905 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
1906 then