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 {$IFNDEF HEADLESS}
181 {$ENDIF}
187 // ////////////////////////////////////////////////////////////////////////// //
188 var
199 //==========================================================================
200 //
201 // GetTimerMS
202 //
203 //==========================================================================
205 begin
210 //==========================================================================
211 //
212 // findByPeer
213 //
214 //==========================================================================
216 var
218 begin
224 //==========================================================================
225 //
226 // ShutdownAll
227 //
228 //==========================================================================
230 var
234 begin
237 begin
239 begin
242 begin
246 //mlist[f].disconnect(false);
253 begin
257 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
258 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
259 // thank you, enet. let's ignore failures altogether then.
261 // if (sres < 0) then break;
266 begin
268 continue;
272 begin
274 //mlist[idx].disconnect(false);
276 end
278 begin
281 end
283 begin
293 //==========================================================================
294 //
295 // DisconnectAll
296 //
297 //==========================================================================
299 var
301 begin
303 begin
309 //==========================================================================
310 //
311 // ConnectAll
312 //
313 //==========================================================================
315 var
317 begin
318 // set flags; pulse will take care of the rest
320 begin
321 // force reconnect
323 // force updating
325 begin
333 //==========================================================================
334 //
335 // UpdateAll
336 //
337 //==========================================================================
339 var
341 begin
342 // set flags; pulse will take care of the rest
344 begin
352 //**************************************************************************
353 //
354 // public api
355 //
356 //**************************************************************************
358 //==========================================================================
359 //
360 // g_Net_Slist_Private
361 //
362 // make this server private
363 //
364 //==========================================================================
366 begin
372 //==========================================================================
373 //
374 // g_Net_Slist_Public
375 //
376 // make this server public
377 //
378 //==========================================================================
380 begin
382 begin
389 //==========================================================================
390 //
391 // g_Net_Slist_ServerUpdate
392 //
393 // called while the server is running
394 //
395 //==========================================================================
397 begin
402 // called when the server is started
404 begin
407 begin
414 //==========================================================================
415 //
416 // g_Net_Slist_ServerClosed
417 //
418 // called when the server is stopped
419 //
420 //==========================================================================
422 var
424 begin
426 begin
429 begin
437 //==========================================================================
438 //
439 // g_Net_Slist_ServerPlayerComes
440 //
441 // called when new netword player comes
442 //
443 //==========================================================================
445 begin
450 //==========================================================================
451 //
452 // g_Net_Slist_ServerPlayerLeaves
453 //
454 // called when new netword player comes
455 //
456 //==========================================================================
458 begin
463 //==========================================================================
464 //
465 // g_Net_Slist_ServerMapStarted
466 //
467 // started new map
468 //
469 //==========================================================================
471 begin
476 //==========================================================================
477 //
478 // g_Net_Slist_ServerRenamed
479 //
480 // this server renamed (or password mode changed, or other params changed)
481 //
482 //==========================================================================
484 begin
489 //**************************************************************************
490 //
491 // TMasterHost
492 //
493 //**************************************************************************
495 //==========================================================================
496 //
497 // TMasterHost.Create
498 //
499 //==========================================================================
501 begin
523 //==========================================================================
524 //
525 // TMasterHost.clear
526 //
527 //==========================================================================
529 begin
543 //==========================================================================
544 //
545 // TMasterHost.setAddress
546 //
547 //==========================================================================
549 begin
565 if (length(hostStr) > 0) then hostName := hostStr else hostName := IntToStr(enetAddr.host)+':'+IntToStr(ea.port);
571 //==========================================================================
572 //
573 // TMasterHost.isValid
574 //
575 //==========================================================================
577 begin
582 //==========================================================================
583 //
584 // TMasterHost.isAlive
585 //
586 // not disconnected
587 //
588 //==========================================================================
590 begin
595 //==========================================================================
596 //
597 // TMasterHost.isConnecting
598 //
599 // is connection in progress?
600 //
601 //==========================================================================
603 begin
608 //==========================================================================
609 //
610 // TMasterHost.isConnected
611 //
612 //==========================================================================
614 begin
619 //==========================================================================
620 //
621 // TMasterHost.connectedEvent
622 //
623 //==========================================================================
625 begin
631 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
635 //==========================================================================
636 //
637 // TMasterHost.disconnectedEvent
638 //
639 //==========================================================================
641 begin
645 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
649 //==========================================================================
650 //
651 // TMasterHost.receivedEvent
652 //
653 // `pkt` is never `nil`
654 //
655 //==========================================================================
657 var
663 begin
666 // packet type
673 //slUrgent := '';
675 // number of items
677 //g_Console_Add(_lc[I_NET_MSG]+Format(_lc[I_NET_SLIST_RETRIEVED], [Cnt, hostName]), True);
680 begin
683 begin
701 begin
702 // new master, supports version reports
705 begin
706 { TODO }
709 // even newer master, supports extra info
711 begin
713 if (slMOTD <> '') then e_LogWritefln('got MOTD from master at [%s]: %s', [hostName, slMOTD], TMsgType.Notify);
715 // check if the message has updated and the user has to read it again
718 if (s <> '') then e_LogWritefln('got urgent from master at [%s]: %s', [hostName, s], TMsgType.Notify);
724 //==========================================================================
725 //
726 // TMasterHost.disconnect
727 //
728 //==========================================================================
730 begin
732 begin
735 begin
740 end
741 else
742 begin
744 // main pulse will take care of the rest
747 end
748 else
749 begin
750 // just in case
758 //if (spamConsole) then g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_DISC], [hostName]));
762 //==========================================================================
763 //
764 // TMasterHost.connect
765 //
766 //==========================================================================
768 begin
772 begin
774 if (NetHostConReqTime = -1) then e_LogWritefln('ketmar broke master [%s] logic! (000)', [hostName], TMsgType.Notify);
775 if (isAlive()) then e_LogWritefln('ketmar broke master [%s] logic! (001)', [hostName], TMsgType.Notify);
776 end
777 else
778 begin
794 begin
796 exit;
804 //==========================================================================
805 //
806 // TMasterHost.writeInfo
807 //
808 //==========================================================================
810 var
812 begin
830 //==========================================================================
831 //
832 // TMasterHost.update
833 //
834 //==========================================================================
836 var
838 begin
841 begin
843 exit;
849 begin
850 try
853 //writeln(formatstrf('%08x', [NetAddr.host]), ' : ', NetAddr.host);
859 begin
861 begin
867 finally
870 end
871 else
872 begin
878 //==========================================================================
879 //
880 // TMasterHost.remove
881 //
882 //==========================================================================
884 var
886 begin
894 try
900 begin
903 finally
909 //==========================================================================
910 //
911 // TMasterHost.pulse
912 //
913 // this performs various scheduled tasks, if necessary
914 //
915 //==========================================================================
917 var
920 begin
924 // process pending connection timeout
926 begin
928 begin
930 // do not spam with error messages, it looks like the master is down
931 //g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
934 exit;
936 // send update, if necessary
938 begin
944 begin
945 //e_LogWritefln('update timeout: %d', [Integer(mrate)], TMsgType.Notify);
953 //**************************************************************************
954 //
955 // other functions
956 //
957 //**************************************************************************
958 type
961 var
965 //==========================================================================
966 //
967 // parseAddressPort
968 //
969 //==========================================================================
971 var
975 begin
987 begin
992 begin
993 try
995 except
1007 begin
1009 end
1010 else
1011 begin
1013 begin
1015 exit;
1024 //==========================================================================
1025 //
1026 // addMasterRecord
1027 //
1028 //==========================================================================
1030 var
1033 begin
1036 begin
1038 begin
1040 exit;
1045 begin
1056 //==========================================================================
1057 //
1058 // g_Net_Slist_Set
1059 //
1060 //==========================================================================
1062 var
1067 begin
1073 //writeln('list=[', list, ']');
1075 begin
1080 //writeln(' sa=[', sa, ']');
1084 // remove unknown master servers
1087 begin
1090 begin
1099 //**************************************************************************
1100 //
1101 // main pulse
1102 //
1103 //**************************************************************************
1105 //==========================================================================
1106 //
1107 // isMasterReportsEnabled
1108 //
1109 //==========================================================================
1111 begin
1116 //==========================================================================
1117 //
1118 // g_Net_Slist_Pulse
1119 //
1120 // non-zero timeout ignores current status (used to fetch server list)
1121 //
1122 //==========================================================================
1124 var
1131 begin
1135 begin
1137 begin
1140 exit;
1145 begin
1148 begin
1149 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_create)', TMsgType.Notify);
1152 Exit;
1158 // reconnect/disconnect/pulse for each master
1160 begin
1163 begin
1164 // not connected; try to reconnect if we're asking for a host list, or we are in netgame, and we are the host
1166 begin
1167 if (mlist[f].lastDisconnectTime = 0) or (ct < mlist[f].lastDisconnectTime) or (ct-mlist[f].lastDisconnectTime >= 1000*NMASTER_TIMEOUT_RECONNECT) then
1168 begin
1171 end
1172 else
1173 begin
1174 //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);
1177 end
1178 else
1179 begin
1180 // if we're not in slist query, and not in netgame (or not a host), disconnect
1182 begin
1184 begin
1195 // fuck! https://www.mail-archive.com/enet-discuss@cubik.org/msg00852.html
1196 // tl;dr: on shitdows, we can get -1 sometimes, and it is *NOT* a failure.
1197 // thank you, enet. let's ignore failures altogether then.
1201 begin
1202 {
1203 if (sres < 0) then
1204 begin
1205 e_LogWriteln(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CLIENT] + ' (host_service)', TMsgType.Notify);
1206 for f := 0 to High(mlist) do mlist[f].clear();
1207 SetLength(mlist, 0);
1208 enet_host_destroy(NetMHost);
1209 NetMHost := nil;
1210 exit;
1211 end;
1212 }
1216 begin
1219 end
1220 else
1221 begin
1223 begin
1225 end
1227 begin
1229 end
1231 begin
1244 //**************************************************************************
1245 //
1246 // gui and server list
1247 //
1248 //**************************************************************************
1250 //==========================================================================
1251 //
1252 // PingServer
1253 //
1254 //==========================================================================
1256 var
1260 begin
1274 //==========================================================================
1275 //
1276 // PingBcast
1277 //
1278 //==========================================================================
1280 var
1282 begin
1292 //==========================================================================
1293 //
1294 // g_Net_Slist_Fetch
1295 //
1296 //==========================================================================
1298 var
1311 begin
1315 begin
1333 begin
1348 begin
1369 var
1375 begin
1380 begin
1382 exit;
1390 begin
1398 // TODO: what should we identify the build with?
1402 try
1406 // wait until all servers connected and answered
1409 begin
1413 begin
1414 {
1415 e_LogWritefln(' master #%d: [%s] valid=%d; alive=%d; connected=%d; connecting=%d',
1416 [f, mlist[f].hostName, Integer(mlist[f].isValid()), Integer(mlist[f].isAlive()),
1417 Integer(mlist[f].isConnected()), Integer(mlist[f].isConnecting())], TMsgType.Notify);
1418 }
1421 begin
1423 begin
1426 begin
1427 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_WCONN], [mlist[f].hostName]));
1431 end
1433 begin
1436 end
1438 begin
1439 //g_Console_Add(Format(_lc[I_NET_MSG]+_lc[I_NET_SLIST_CONN], [mlist[f].hostName]));
1441 begin
1444 begin
1446 begin
1452 end
1454 begin
1456 end
1458 begin
1462 end
1464 begin
1469 // check for timeout
1476 begin
1479 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
1563 begin
1585 begin
1590 break;
1594 begin
1604 finally
1610 //==========================================================================
1611 //
1612 // GetServerFromTable
1613 //
1614 //==========================================================================
1615 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1616 begin
1632 Exit;
1634 Exit;
1639 //==========================================================================
1640 //
1641 // g_Serverlist_GenerateTable
1642 //
1643 //==========================================================================
1645 var
1649 var
1651 begin
1654 Exit;
1656 begin
1658 continue;
1660 begin
1662 Exit;
1667 var
1669 begin
1677 var
1680 begin
1684 begin
1691 var
1694 begin
1698 begin
1704 begin
1707 Exit;
1710 begin
1713 begin
1719 end
1720 else
1721 begin
1734 //==========================================================================
1735 //
1736 // g_Serverlist_Control
1737 //
1738 //==========================================================================
1740 var
1743 begin
1747 Exit;
1749 {$IFDEF HEADLESS}
1751 {$ELSE}
1753 {$ENDIF}
1758 begin
1762 {$IFNDEF HEADLESS}
1767 {$ENDIF}
1768 Exit;
1771 // if there's a message on the screen,
1773 begin
1774 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1775 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1777 Exit;
1781 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1782 begin
1784 begin
1787 {$IFNDEF HEADLESS}
1788 r_Render_Draw;
1789 sys_Repaint;
1790 {$ENDIF}
1793 begin
1796 end
1797 else
1804 end
1805 else
1810 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1811 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1812 begin
1814 begin
1817 begin
1818 {$IFNDEF HEADLESS}
1821 {$ENDIF}
1823 {$IFNDEF HEADLESS}
1825 {$ENDIF}
1829 Exit;
1830 end
1831 else
1836 Exit;
1838 end
1839 else
1843 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1844 begin
1846 begin
1854 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1855 begin
1857 begin
1866 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
1867 begin
1869 begin
1877 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
1878 begin
1880 begin
1881 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
1900 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
1901 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
1902 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
1903 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
1904 then