X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_net.pas;h=38c0597ec337683556deea2d646fdbffd82f93f6;hb=907f02bbf5d1e65c2ce052d883d522e30e7c7a8f;hp=1b7a5035da6e67c3db9279cedf4e95d3b2cb6901;hpb=7817765f4dca5289934f837ee4d63316b9797f86;p=d2df-sdl.git diff --git a/src/game/g_net.pas b/src/game/g_net.pas index 1b7a503..38c0597 100644 --- a/src/game/g_net.pas +++ b/src/game/g_net.pas @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . *) -{$MODE DELPHI} +{$INCLUDE g_amodes.inc} unit g_net; interface @@ -22,10 +22,9 @@ uses e_log, e_fixedbuffer, ENet, Classes; const - NET_PROTOCOL_VER = 168; + NET_PROTOCOL_VER = 172; NET_MAXCLIENTS = 24; - NET_CHANS = 11; NET_CHAN_SERVICE = 0; NET_CHAN_IMPORTANT = 1; @@ -39,6 +38,13 @@ const NET_CHAN_DOWNLOAD = 9; NET_CHAN_SHOTS = 10; + CH_RELIABLE = 0; + CH_UNRELIABLE = 1; + CH_DOWNLOAD = 2; + CH_MAX = CH_UNRELIABLE; // don't change this + + NET_CHANS = 3; + NET_NONE = 0; NET_SERVER = 1; NET_CLIENT = 2; @@ -63,17 +69,19 @@ const NET_STATE_GAME = 2; BANLIST_FILENAME = 'banlist.txt'; + NETDUMP_FILENAME = 'netdump'; type TNetClient = record - ID: Byte; - Used: Boolean; - State: Byte; - Peer: pENetPeer; - Player: Word; + ID: Byte; + Used: Boolean; + State: Byte; + Peer: pENetPeer; + Player: Word; RequestedFullUpdate: Boolean; RCONAuth: Boolean; Voted: Boolean; + SendBuf: array [0..CH_MAX] of TBuffer; end; TBanRecord = record IP: LongWord; @@ -86,6 +94,7 @@ type var NetInitDone: Boolean = False; NetMode: Byte = NET_NONE; + NetDump: Boolean = False; NetServerName: string = 'Unnamed Server'; NetPassword: string = ''; @@ -115,11 +124,12 @@ var NetClientPort: Word = 25666; NetIn, NetOut: TBuffer; + NetSend: array [0..CH_MAX] of TBuffer; - NetClients: array of TNetClient; + NetClients: array of TNetClient = nil; NetClientCount: Byte = 0; NetMaxClients: Byte = 255; - NetBannedHosts: array of TBanRecord; + NetBannedHosts: array of TBanRecord = nil; NetState: Integer = NET_STATE_NONE; @@ -138,6 +148,8 @@ var NetGotEverything: Boolean = False; + NetDumpFile: TStream; + function g_Net_Init(): Boolean; procedure g_Net_Cleanup(); procedure g_Net_Free(); @@ -147,12 +159,14 @@ function g_Net_Host(IPAddr: LongWord; Port: enet_uint16; MaxClients: Cardinal = procedure g_Net_Host_Die(); procedure g_Net_Host_Send(ID: Integer; Reliable: Boolean; Chan: Byte = NET_CHAN_GAME); function g_Net_Host_Update(): enet_size_t; +procedure g_Net_Host_FlushBuffers(); function g_Net_Connect(IP: string; Port: enet_uint16): Boolean; procedure g_Net_Disconnect(Forced: Boolean = False); procedure g_Net_Client_Send(Reliable: Boolean; Chan: Byte = NET_CHAN_GAME); function g_Net_Client_Update(): enet_size_t; function g_Net_Client_UpdateWhileLoading(): enet_size_t; +procedure g_Net_Client_FlushBuffers(); function g_Net_Client_ByName(Name: string): pTNetClient; function g_Net_Client_ByPlayer(PID: Word): pTNetClient; @@ -172,17 +186,44 @@ function g_Net_UnbanHost(IP: LongWord): Boolean; overload; procedure g_Net_UnbanNonPermHosts(); procedure g_Net_SaveBanList(); +procedure g_Net_DumpStart(); +procedure g_Net_DumpSendBuffer(Buf: pTBuffer); +procedure g_Net_DumpRecvBuffer(Buf: penet_uint8; Len: LongWord); +procedure g_Net_DumpEnd(); + implementation uses SysUtils, e_input, g_nethandler, g_netmsg, g_netmaster, g_player, g_window, g_console, - g_main, g_game, g_language, g_weapons; + g_main, g_game, g_language, g_weapons, utils; { /// SERVICE FUNCTIONS /// } +procedure SendBuffer(B: pTBuffer; Ch: Integer; Peer: pENetPeer); +var + P: pENetPacket; + Fl: enet_uint32; +begin + if Ch = CH_RELIABLE then Fl := ENET_PACKET_FLAG_RELIABLE + else Fl := 0; + if B^.WritePos > 0 then + begin + P := enet_packet_create(Addr(B^.Data), B^.WritePos, Fl); + if P <> nil then + begin + if Peer = nil then + enet_host_broadcast(NetHost, Ch, P) + else + enet_peer_send(Peer, Ch, P); + end; + if NetDump then g_Net_DumpSendBuffer(B); + e_Buffer_Clear(B); + end; +end; + function g_Net_FindSlot(): Integer; var I: Integer; @@ -228,6 +269,9 @@ begin NetClients[N].RCONAuth := False; NetClients[N].Voted := False; NetClients[N].Player := 0; + NetClients[N].Peer := nil; + for I := 0 to CH_MAX do + e_Buffer_Clear(Addr(NetClients[N].SendBuf[CH_MAX])); end; Result := N; @@ -238,9 +282,12 @@ var F: TextFile; IPstr: string; IP: LongWord; + I: Integer; begin e_Buffer_Clear(@NetIn); e_Buffer_Clear(@NetOut); + for I := 0 to CH_MAX do + e_Buffer_Clear(@NetSend[i]); SetLength(NetClients, 0); NetPeer := nil; NetHost := nil; @@ -268,13 +315,21 @@ end; procedure g_Net_Flush(); begin + if NetMode = NET_SERVER then + g_Net_Host_FlushBuffers() + else + g_Net_Client_FlushBuffers(); enet_host_flush(NetHost); end; procedure g_Net_Cleanup(); +var + I: Integer; begin e_Buffer_Clear(@NetIn); e_Buffer_Clear(@NetOut); + for i := 0 to CH_MAX do + e_Buffer_Clear(@NetSend[i]); SetLength(NetClients, 0); NetClientCount := 0; @@ -295,6 +350,9 @@ begin NetTimeToReliable := 0; NetMode := NET_NONE; + + if NetDump then + g_Net_DumpEnd(); end; procedure g_Net_Free(); @@ -362,6 +420,9 @@ begin NetMode := NET_SERVER; e_Buffer_Clear(@NetOut); + + if NetDump then + g_Net_DumpStart(); end; procedure g_Net_Host_Die(); @@ -402,36 +463,48 @@ begin e_WriteLog('NET: Server stopped', MSG_NOTIFY); end; +procedure g_Net_Host_FlushBuffers(); +var + I: Integer; +begin + // send broadcast + SendBuffer(@NetSend[CH_RELIABLE], CH_RELIABLE, nil); + SendBuffer(@NetSend[CH_UNRELIABLE], CH_UNRELIABLE, nil); + // send to individual clients + if NetClients <> nil then + for I := Low(NetClients) to High(NetClients) do + with NetClients[I] do + begin + SendBuffer(@SendBuf[CH_RELIABLE], CH_RELIABLE, Peer); + SendBuffer(@SendBuf[CH_UNRELIABLE], CH_UNRELIABLE, Peer); + end; +end; procedure g_Net_Host_Send(ID: Integer; Reliable: Boolean; Chan: Byte = NET_CHAN_GAME); var - P: pENetPacket; - F: enet_uint32; + I: Integer; + B: pTBuffer; begin if (Reliable) then - F := LongWord(ENET_PACKET_FLAG_RELIABLE) + I := CH_RELIABLE else - F := 0; + I := CH_UNRELIABLE; if (ID >= 0) then begin - if ID > High(NetClients) then Exit; - if NetClients[ID].Peer = nil then Exit; - - P := enet_packet_create(Addr(NetOut.Data), NetOut.Len, F); - if not Assigned(P) then Exit; - - enet_peer_send(NetClients[ID].Peer, Chan, P); + if (ID > High(NetClients)) or (NetClients[ID].Peer = nil) then + begin + e_Buffer_Clear(@NetOut); + Exit; + end; + B := Addr(NetClients[ID].SendBuf[I]); end else begin - P := enet_packet_create(Addr(NetOut.Data), NetOut.Len, F); - if not Assigned(P) then Exit; - - enet_host_broadcast(NetHost, Chan, P); + B := Addr(NetSend[I]); end; - g_Net_Flush(); + e_Buffer_Write(B, @NetOut); e_Buffer_Clear(@NetOut); end; @@ -481,7 +554,7 @@ function g_Net_Host_Update(): enet_size_t; var IP: string; Port: Word; - ID: Integer; + ID, I: Integer; TC: pTNetClient; TP: TPlayer; begin @@ -545,7 +618,8 @@ begin ID := Byte(NetEvent.peer^.data^); if ID > High(NetClients) then Exit; TC := @NetClients[ID]; - + if NetDump then + g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength); g_Net_HostMsgHandler(TC, NetEvent.packet); end; @@ -636,21 +710,21 @@ begin e_WriteLog('NET: Disconnected', MSG_NOTIFY); end; +procedure g_Net_Client_FlushBuffers(); +begin + SendBuffer(@NetSend[CH_RELIABLE], CH_RELIABLE, NetPeer); + SendBuffer(@NetSend[CH_UNRELIABLE], CH_UNRELIABLE, NetPeer); +end; + procedure g_Net_Client_Send(Reliable: Boolean; Chan: Byte = NET_CHAN_GAME); var - P: pENetPacket; - F: enet_uint32; + I: Integer; begin if (Reliable) then - F := LongWord(ENET_PACKET_FLAG_RELIABLE) + I := CH_RELIABLE else - F := 0; - - P := enet_packet_create(Addr(NetOut.Data), NetOut.Len, F); - if not Assigned(P) then Exit; - - enet_peer_send(NetPeer, Chan, P); - g_Net_Flush(); + I := CH_UNRELIABLE; + e_Buffer_Write(@NetSend[I], @NetOut); e_Buffer_Clear(@NetOut); end; @@ -661,7 +735,11 @@ begin begin case NetEvent.kind of ENET_EVENT_TYPE_RECEIVE: + begin + if NetDump then + g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength); g_Net_ClientMsgHandler(NetEvent.packet); + end; ENET_EVENT_TYPE_DISCONNECT: begin @@ -680,7 +758,11 @@ begin begin case NetEvent.kind of ENET_EVENT_TYPE_RECEIVE: + begin + if NetDump then + g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength); g_Net_ClientLightMsgHandler(NetEvent.packet); + end; ENET_EVENT_TYPE_DISCONNECT: begin @@ -690,7 +772,6 @@ begin end; end; end; - g_Net_Flush(); end; function g_Net_Connect(IP: string; Port: enet_uint16): Boolean; @@ -757,6 +838,8 @@ begin enet_peer_timeout(NetPeer, ENET_PEER_TIMEOUT_LIMIT * 2, ENET_PEER_TIMEOUT_MINIMUM * 2, ENET_PEER_TIMEOUT_MAXIMUM * 2); NetClientIP := IP; NetClientPort := Port; + if NetDump then + g_Net_DumpStart(); Exit; end; end; @@ -871,13 +954,13 @@ begin begin P := enet_packet_create(@Data[0], dataLength, F); if not Assigned(P) then Exit; - enet_peer_send(peer, Chan, P); + enet_peer_send(peer, CH_DOWNLOAD, P); end else begin P := enet_packet_create(@Data[0], dataLength, F); if not Assigned(P) then Exit; - enet_host_broadcast(NetHost, Chan, P); + enet_host_broadcast(NetHost, CH_DOWNLOAD, P); end; enet_host_flush(NetHost); @@ -889,6 +972,7 @@ var OuterLoop: Boolean; MID: Byte; Ptr: Pointer; + Len: LongWord; msgStream: TMemoryStream; begin FillChar(downloadEvent, SizeOf(downloadEvent), 0); @@ -898,17 +982,18 @@ begin begin while (enet_host_service(NetHost, @downloadEvent, 0) > 0) do begin - if (downloadEvent.kind = ENET_EVENT_TYPE_RECEIVE) then + if (downloadEvent.kind = ENET_EVENT_TYPE_RECEIVE) and (downloadEvent.packet^.dataLength > 2) then begin - Ptr := downloadEvent.packet^.data; - + Len := PWord(downloadEvent.packet^.data)^; + if Len = 0 then break; + Ptr := downloadEvent.packet^.data + 2; // skip length MID := Byte(Ptr^); if (MID = msgId) then begin msgStream := TMemoryStream.Create; - msgStream.SetSize(downloadEvent.packet^.dataLength); - msgStream.WriteBuffer(Ptr^, downloadEvent.packet^.dataLength); + msgStream.SetSize(downloadEvent.packet^.dataLength - 2); + msgStream.WriteBuffer(Ptr^, downloadEvent.packet^.dataLength - 2); msgStream.Seek(0, soFromBeginning); OuterLoop := False; @@ -1048,4 +1133,43 @@ begin CloseFile(F); end; +procedure g_Net_DumpStart(); +begin + if NetMode = NET_SERVER then + NetDumpFile := createDiskFile(NETDUMP_FILENAME + '_server') + else + NetDumpFile := createDiskFile(NETDUMP_FILENAME + '_client'); +end; + +procedure g_Net_DumpSendBuffer(Buf: pTBuffer); +begin + writeInt(NetDumpFile, Byte($BA)); + writeInt(NetDumpFile, Byte($BE)); + writeInt(NetDumpFile, Byte($FF)); + writeInt(NetDumpFile, gTime); + writeInt(NetDumpFile, Byte($FF)); + writeInt(NetDumpFile, LongWord(Buf^.WritePos)); + writeInt(NetDumpFile, Byte($FF)); + NetDumpFile.WriteBuffer(Buf^.Data[0], Buf^.WritePos); +end; + +procedure g_Net_DumpRecvBuffer(Buf: penet_uint8; Len: LongWord); +begin + if (Buf = nil) or (Len = 0) then Exit; + writeInt(NetDumpFile, Byte($B0)); + writeInt(NetDumpFile, Byte($0B)); + writeInt(NetDumpFile, Byte($FF)); + writeInt(NetDumpFile, gTime); + writeInt(NetDumpFile, Byte($FF)); + writeInt(NetDumpFile, Len); + writeInt(NetDumpFile, Byte($FF)); + NetDumpFile.WriteBuffer(Buf^, Len); +end; + +procedure g_Net_DumpEnd(); +begin + NetDumpFile.Free(); + NetDumpFile := nil; +end; + end.