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;
1483 {
1484 slUrgent := '';
1485 slReadUrgent := true;
1486 }
1490 begin
1493 begin
1496 begin
1498 begin
1500 break;
1504 begin
1512 begin
1514 begin
1520 begin
1528 begin
1530 exit;
1549 begin
1562 begin
1584 begin
1589 break;
1593 begin
1603 finally
1609 //==========================================================================
1610 //
1611 // GetServerFromTable
1612 //
1613 //==========================================================================
1614 function GetServerFromTable (Index: Integer; SL: TNetServerList; ST: TNetServerTable): TNetServer;
1615 begin
1631 Exit;
1633 Exit;
1638 //==========================================================================
1639 //
1640 // g_Serverlist_GenerateTable
1641 //
1642 //==========================================================================
1644 var
1648 var
1650 begin
1653 Exit;
1655 begin
1657 continue;
1659 begin
1661 Exit;
1666 var
1668 begin
1676 var
1679 begin
1683 begin
1690 var
1693 begin
1697 begin
1703 begin
1706 Exit;
1709 begin
1712 begin
1718 end
1719 else
1720 begin
1733 //==========================================================================
1734 //
1735 // g_Serverlist_Control
1736 //
1737 //==========================================================================
1739 var
1742 begin
1746 Exit;
1748 {$IFDEF HEADLESS}
1750 {$ELSE}
1752 {$ENDIF}
1757 begin
1761 {$IFNDEF HEADLESS}
1766 {$ENDIF}
1767 Exit;
1770 // if there's a message on the screen,
1772 begin
1773 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1774 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1776 Exit;
1780 e_KeyPressed(JOY0_ACTIVATE) or e_KeyPressed(JOY1_ACTIVATE) or e_KeyPressed(JOY2_ACTIVATE) or e_KeyPressed(JOY3_ACTIVATE) then
1781 begin
1783 begin
1786 {$IFNDEF HEADLESS}
1787 r_Render_Draw;
1788 sys_Repaint;
1789 {$ENDIF}
1792 begin
1795 end
1796 else
1803 end
1804 else
1809 if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or
1810 e_KeyPressed(JOY0_ATTACK) or e_KeyPressed(JOY1_ATTACK) or e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) then
1811 begin
1813 begin
1816 begin
1817 {$IFNDEF HEADLESS}
1820 {$ENDIF}
1822 {$IFNDEF HEADLESS}
1824 {$ENDIF}
1828 Exit;
1829 end
1830 else
1835 Exit;
1837 end
1838 else
1842 e_KeyPressed(JOY0_DOWN) or e_KeyPressed(JOY1_DOWN) or e_KeyPressed(JOY2_DOWN) or e_KeyPressed(JOY3_DOWN) then
1843 begin
1845 begin
1853 e_KeyPressed(JOY0_UP) or e_KeyPressed(JOY1_UP) or e_KeyPressed(JOY2_UP) or e_KeyPressed(JOY3_UP) then
1854 begin
1856 begin
1865 e_KeyPressed(JOY0_RIGHT) or e_KeyPressed(JOY1_RIGHT) or e_KeyPressed(JOY2_RIGHT) or e_KeyPressed(JOY3_RIGHT) then
1866 begin
1868 begin
1876 e_KeyPressed(JOY0_LEFT) or e_KeyPressed(JOY1_LEFT) or e_KeyPressed(JOY2_LEFT) or e_KeyPressed(JOY3_LEFT) then
1877 begin
1879 begin
1880 if ST[slSelection].Current = 0 then ST[slSelection].Current := Length(ST[slSelection].Indices);
1899 (not e_KeyPressed(JOY0_UP)) and (not e_KeyPressed(JOY1_UP)) and (not e_KeyPressed(JOY2_UP)) and (not e_KeyPressed(JOY3_UP)) and
1900 (not e_KeyPressed(JOY0_DOWN)) and (not e_KeyPressed(JOY1_DOWN)) and (not e_KeyPressed(JOY2_DOWN)) and (not e_KeyPressed(JOY3_DOWN)) and
1901 (not e_KeyPressed(JOY0_LEFT)) and (not e_KeyPressed(JOY1_LEFT)) and (not e_KeyPressed(JOY2_LEFT)) and (not e_KeyPressed(JOY3_LEFT)) and
1902 (not e_KeyPressed(JOY0_RIGHT)) and (not e_KeyPressed(JOY1_RIGHT)) and (not e_KeyPressed(JOY2_RIGHT)) and (not e_KeyPressed(JOY3_RIGHT))
1903 then