diff --git a/src/game/g_net.pas b/src/game/g_net.pas
index b9f28b981c9bccac022b724867106534932cc390..0f3df0f81f384348afba14eeaa326f3ce4ff6f42 100644 (file)
--- a/src/game/g_net.pas
+++ b/src/game/g_net.pas
e_log, e_msg, ENet, Classes, MAPDEF{$IFDEF USE_MINIUPNPC}, miniupnpc;{$ELSE};{$ENDIF}
const
- NET_PROTOCOL_VER = 173;
+ NET_PROTOCOL_VER = 180;
NET_MAXCLIENTS = 24;
NET_CHANS = 11;
NET_CLIENT = 2;
NET_BUFSIZE = $FFFF;
+ NET_PING_PORT = $DF2D;
NET_EVERYONE = -1;
BANLIST_FILENAME = 'banlist.txt';
NETDUMP_FILENAME = 'netdump';
+ {$IFDEF FREEBSD}
+ NilThreadId = nil;
+ {$ELSE}
+ NilThreadId = 0;
+ {$ENDIF}
+
type
TNetClient = record
ID: Byte;
NetIGDService: TURLStr;
{$ENDIF}
- NetPortThread: TThreadID = 0;
+ NetPortThread: TThreadID = NilThreadId;
NetDumpFile: TStream;
function g_Net_Client_ByPlayer(PID: Word): pTNetClient;
function g_Net_ClientName_ByID(ID: Integer): string;
-procedure g_Net_SendData(Data:AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD);
+procedure g_Net_SendData(Data: AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD);
function g_Net_Wait_Event(msgId: Word): TMemoryStream;
function IpToStr(IP: LongWord): string;
uses
SysUtils,
e_input, g_nethandler, g_netmsg, g_netmaster, g_player, g_window, g_console,
- g_main, g_game, g_language, g_weapons, utils;
+ g_main, g_game, g_language, g_weapons, utils, ctypes;
+
+var
+ g_Net_DownloadTimeout: Single;
{ /// SERVICE FUNCTIONS /// }
NetMode := NET_NONE;
- if NetPortThread <> 0 then
+ if NetPortThread <> NilThreadId then
WaitForThreadTerminate(NetPortThread, 66666);
- NetPortThread := 0;
+ NetPortThread := NilThreadId;
g_Net_UnforwardPorts();
if NetDump then
if NetPongSock <> ENET_SOCKET_NULL then
begin
NetPongAddr.host := IPAddr;
- NetPongAddr.port := Port + 1;
+ NetPongAddr.port := NET_PING_PORT;
if enet_socket_bind(NetPongSock, @NetPongAddr) < 0 then
begin
enet_socket_destroy(NetPongSock);
NetOut.Clear();
NetOut.Write(Byte(Ord('D')));
NetOut.Write(Byte(Ord('F')));
+ NetOut.Write(NetPort);
NetOut.Write(ClTime);
g_Net_Slist_WriteInfo();
NPl := 0;
Result := 0;
if NetUseMaster then
- begin
g_Net_Slist_Check;
- g_Net_Host_CheckPings;
- end;
+ g_Net_Host_CheckPings;
while (enet_host_service(NetHost, @NetEvent, 0) > 0) do
begin
ProcessLoading(true);
- if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) or e_KeyPressed(VK_ESCAPE) then
+ if e_KeyPressed(IK_SPACE) or e_KeyPressed(IK_ESCAPE) or e_KeyPressed(VK_ESCAPE) or
+ e_KeyPressed(JOY0_JUMP) or e_KeyPressed(JOY1_JUMP) or e_KeyPressed(JOY2_JUMP) or e_KeyPressed(JOY3_JUMP) then
OuterLoop := False;
end;
end;
end;
-procedure g_Net_SendData(Data:AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD);
+procedure g_Net_SendData(Data: AByte; peer: pENetPeer; Reliable: Boolean; Chan: Byte = NET_CHAN_DOWNLOAD);
var
P: pENetPacket;
F: enet_uint32;
enet_host_flush(NetHost);
end;
+function UserRequestExit: Boolean;
+begin
+ Result := e_KeyPressed(IK_SPACE) or
+ e_KeyPressed(IK_ESCAPE) or
+ e_KeyPressed(VK_ESCAPE) or
+ e_KeyPressed(JOY0_JUMP) or
+ e_KeyPressed(JOY1_JUMP) or
+ e_KeyPressed(JOY2_JUMP) or
+ e_KeyPressed(JOY3_JUMP)
+end;
+
function g_Net_Wait_Event(msgId: Word): TMemoryStream;
-var
- downloadEvent: ENetEvent;
- OuterLoop: Boolean;
- MID: Byte;
- Ptr: Pointer;
- msgStream: TMemoryStream;
+ var
+ ev: ENetEvent;
+ rMsgId: Byte;
+ Ptr: Pointer;
+ stream: TMemoryStream;
+ status: cint;
begin
- FillChar(downloadEvent, SizeOf(downloadEvent), 0);
- msgStream := nil;
- OuterLoop := True;
- while OuterLoop do
- begin
- while (enet_host_service(NetHost, @downloadEvent, 0) > 0) do
+ FillChar(ev, SizeOf(ev), 0);
+ stream := nil;
+ repeat
+ status := enet_host_service(NetHost, @ev, Trunc(g_Net_DownloadTimeout * 1000));
+ if status > 0 then
begin
- if (downloadEvent.kind = ENET_EVENT_TYPE_RECEIVE) then
- begin
- Ptr := downloadEvent.packet^.data;
-
- MID := Byte(Ptr^);
-
- if (MID = msgId) then
+ case ev.kind of
+ ENET_EVENT_TYPE_RECEIVE:
+ begin
+ Ptr := ev.packet^.data;
+ rMsgId := Byte(Ptr^);
+ if rMsgId = msgId then
+ begin
+ stream := TMemoryStream.Create;
+ stream.SetSize(ev.packet^.dataLength);
+ stream.WriteBuffer(Ptr^, ev.packet^.dataLength);
+ stream.Seek(0, soFromBeginning);
+ status := 1 (* received *)
+ end
+ else
+ begin
+ (* looks that game state always received, so ignore it *)
+ e_LogWritefln('g_Net_Wait_Event(%s): skip message %s', [msgId, rMsgId]);
+ status := 2 (* continue *)
+ end
+ end;
+ ENET_EVENT_TYPE_DISCONNECT:
begin
- msgStream := TMemoryStream.Create;
- msgStream.SetSize(downloadEvent.packet^.dataLength);
- msgStream.WriteBuffer(Ptr^, downloadEvent.packet^.dataLength);
- msgStream.Seek(0, soFromBeginning);
-
- OuterLoop := False;
- enet_packet_destroy(downloadEvent.packet);
- break;
- end
- else begin
- enet_packet_destroy(downloadEvent.packet);
+ if (ev.data <= NET_DISC_MAX) then
+ g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' + _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + ev.data)], True);
+ status := -2 (* error: disconnected *)
end;
- end
else
- if (downloadEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then
- begin
- if (downloadEvent.data <= NET_DISC_MAX) then
- g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' +
- _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + downloadEvent.data)], True);
- OuterLoop := False;
- Break;
- end;
+ g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' unknown ENet event ' + IntToStr(Ord(ev.kind)), True);
+ status := -3 (* error: unknown event *)
+ end;
+ enet_packet_destroy(ev.packet)
+ end
+ else
+ begin
+ g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' timeout reached', True);
+ status := 0 (* error: timeout *)
end;
-
ProcessLoading(true);
-
- if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) or e_KeyPressed(VK_ESCAPE) then
- break;
- end;
- Result := msgStream;
+ until (status <> 2) or UserRequestExit();
+ Result := stream
end;
function g_Net_IsHostBanned(IP: LongWord; Perm: Boolean = False): Boolean;
if ForwardPongPort then
begin
- StrPort := IntToStr(NetPort + 1);
+ StrPort := IntToStr(NET_PING_PORT);
I := UPNP_AddPortMapping(
Urls.controlURL, Addr(data.first.servicetype[1]),
PChar(StrPort), PChar(StrPort), Addr(LanAddr[0]), PChar('D2DF'),
{$ENDIF}
initialization
-
+ conRegVar('cl_downloadtimeout', @g_Net_DownloadTimeout, 0.0, 1000000.0, '', 'timeout in seconds, 0 to disable it');
+ g_Net_DownloadTimeout := 60;
NetIn.Alloc(NET_BUFSIZE);
NetOut.Alloc(NET_BUFSIZE);
-
finalization
-
NetIn.Free();
NetOut.Free();
-
end.