summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 6b0ba68)
raw | patch | inline | side by side (parent: 6b0ba68)
author | fgsfds <pvt.fgsfds@gmail.com> | |
Mon, 26 Aug 2019 20:18:25 +0000 (23:18 +0300) | ||
committer | fgsfds <pvt.fgsfds@gmail.com> | |
Mon, 26 Aug 2019 20:18:25 +0000 (23:18 +0300) |
diff --git a/src/engine/e_msg.pas b/src/engine/e_msg.pas
index 6433511f3abd87e2d2570a4e05b272f3e1ecb7a8..a2ecc52e3e9a40e6a2c58dede4d26344e35847b3 100644 (file)
--- a/src/engine/e_msg.pas
+++ b/src/engine/e_msg.pas
function AssignBuffer(P: Pointer; N: Integer; Full: Boolean = False): Boolean;
procedure BeginReading();
+ procedure Seek(Pos: Integer);
+ procedure Skip(Size: Integer);
+ function BytesLeft(): Integer;
function ReadData(V: Pointer; N: Integer): Integer;
function ReadChar(): Char;
function ReadByte(): Byte;
procedure Write(V: Int64); overload;
procedure Write(V: String); overload;
procedure Write(V: TMD5Digest); overload;
+ procedure Write(V: TMsg);
end;
type
begin
if not OwnMemory then
raise Exception.Create('TMsg.Free: called on borrowed memory');
+ Clear();
OwnMemory := False;
FreeMem(Data);
Data := nil;
CurSize := CurSize + N;
end;
+procedure TMsg.Write(V: TMsg);
+begin
+ if CurSize + V.CurSize > MaxSize then
+ begin
+ Overflow := True;
+ raise Exception.Create('TMsg.WriteData: buffer overrun!');
+ Exit;
+ end;
+ Move(V.Data^, (Data + CurSize)^, V.CurSize);
+ CurSize := CurSize + V.CurSize;
+end;
+
procedure TMsg.Write(V: Byte); overload;
begin
WriteData(@V, 1);
Bit := 0;
end;
+procedure TMsg.Seek(Pos: Integer);
+begin
+ if Pos > CurSize then
+ raise Exception.Create('TMsg.Seek: buffer overrun!');
+ ReadCount := Pos;
+end;
+
+procedure TMsg.Skip(Size: Integer);
+begin
+ if ReadCount + Size > CurSize then
+ raise Exception.Create('TMsg.Skip: buffer overrun!');
+ ReadCount := ReadCount + Size;
+end;
+
+function TMsg.BytesLeft(): Integer;
+begin
+ Result := CurSize - ReadCount;
+end;
+
function TMsg.ReadData(V: Pointer; N: Integer): Integer;
begin
Result := 0;
diff --git a/src/game/g_game.pas b/src/game/g_game.pas
index 7b8324325dffae8ff5a131987a28a9326f555b87..77fd80ac499b78f21c870be4cb5a75d167fca1e2 100644 (file)
--- a/src/game/g_game.pas
+++ b/src/game/g_game.pas
if not InMsg.Init(Ptr, NetEvent.packet^.dataLength, True) then
continue;
+ InMsg.ReadLongWord(); // skip size
MID := InMsg.ReadByte();
if (MID = NET_MSG_INFO) and (State = 0) then
diff --git a/src/game/g_net.pas b/src/game/g_net.pas
index 907a5beefd437b163adaf1ef934dbc29c55fee58..83c8398991ff1ed0429f97212a1f80df69f55440 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 = 180;
+ NET_PROTOCOL_VER = 181;
NET_MAXCLIENTS = 24;
NET_CHANS = 11;
NET_EVERYONE = -1;
+ NET_UNRELIABLE = 0;
+ NET_RELIABLE = 1;
+
NET_DISC_NONE: enet_uint32 = 0;
NET_DISC_PROTOCOL: enet_uint32 = 1;
NET_DISC_VERSION: enet_uint32 = 2;
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;
+ NetOut: array [0..1] of TMsg;
end;
TBanRecord = record
IP: LongWord;
NetClientPort: Word = 25666;
NetIn, NetOut: TMsg;
+ NetBuf: array [0..1] of TMsg;
NetClients: array of TNetClient;
NetClientCount: Byte = 0;
begin
NetIn.Clear();
NetOut.Clear();
+ NetBuf[NET_UNRELIABLE].Clear();
+ NetBuf[NET_RELIABLE].Clear();
SetLength(NetClients, 0);
NetPeer := nil;
NetHost := nil;
end;
procedure g_Net_Flush();
+var
+ T: Integer;
+ P: pENetPacket;
+ F, Chan: enet_uint32;
+ I: Integer;
begin
- enet_host_flush(NetHost);
+ F := 0;
+ Chan := NET_CHAN_GAME;
+
+ if NetMode = NET_SERVER then
+ for T := NET_UNRELIABLE to NET_RELIABLE do
+ begin
+ if NetBuf[T].CurSize > 0 then
+ begin
+ P := enet_packet_create(NetBuf[T].Data, NetBuf[T].CurSize, F);
+ if not Assigned(P) then continue;
+ enet_host_broadcast(NetHost, Chan, P);
+ NetBuf[T].Clear();
+ end;
+
+ for I := Low(NetClients) to High(NetClients) do
+ begin
+ if not NetClients[I].Used then continue;
+ if NetClients[I].NetOut[T].CurSize <= 0 then continue;
+ P := enet_packet_create(NetClients[I].NetOut[T].Data, NetClients[I].NetOut[T].CurSize, F);
+ if not Assigned(P) then continue;
+ enet_peer_send(NetClients[I].Peer, Chan, P);
+ NetClients[I].NetOut[T].Clear();
+ end;
+
+ // next and last iteration is always RELIABLE
+ F := LongWord(ENET_PACKET_FLAG_RELIABLE);
+ Chan := NET_CHAN_IMPORTANT;
+ end
+ else if NetMode = NET_CLIENT then
+ for T := NET_UNRELIABLE to NET_RELIABLE do
+ begin
+ if NetBuf[T].CurSize > 0 then
+ begin
+ P := enet_packet_create(NetBuf[T].Data, NetBuf[T].CurSize, F);
+ if not Assigned(P) then continue;
+ enet_peer_send(NetPeer, Chan, P);
+ NetBuf[T].Clear();
+ end;
+ // next and last iteration is always RELIABLE
+ F := LongWord(ENET_PACKET_FLAG_RELIABLE);
+ Chan := NET_CHAN_IMPORTANT;
+ end;
end;
procedure g_Net_Cleanup();
begin
NetIn.Clear();
NetOut.Clear();
+ NetBuf[NET_UNRELIABLE].Clear();
+ NetBuf[NET_RELIABLE].Clear();
SetLength(NetClients, 0);
NetClientCount := 0;
NetMode := NET_SERVER;
NetOut.Clear();
+ NetBuf[NET_UNRELIABLE].Clear();
+ NetBuf[NET_RELIABLE].Clear();
if NetDump then
g_Net_DumpStart();
enet_peer_reset(NetClients[I].Peer);
NetClients[I].Peer := nil;
NetClients[I].Used := False;
+ NetClients[I].NetOut[NET_UNRELIABLE].Free();
+ NetClients[I].NetOut[NET_RELIABLE].Free();
end;
if (NetMPeer <> nil) and (NetMHost <> nil) then g_Net_Slist_Disconnect;
procedure g_Net_Host_Send(ID: Integer; Reliable: Boolean; Chan: Byte = NET_CHAN_GAME);
var
- P: pENetPacket;
- F: enet_uint32;
+ T: Integer;
begin
if (Reliable) then
- F := LongWord(ENET_PACKET_FLAG_RELIABLE)
+ T := NET_RELIABLE
else
- F := 0;
+ T := NET_UNRELIABLE;
if (ID >= 0) then
begin
if ID > High(NetClients) then Exit;
if NetClients[ID].Peer = nil then Exit;
-
- P := enet_packet_create(NetOut.Data, NetOut.CurSize, F);
- if not Assigned(P) then Exit;
-
- enet_peer_send(NetClients[ID].Peer, Chan, P);
+ // write size first
+ NetClients[ID].NetOut[T].Write(Integer(NetOut.CurSize));
+ NetClients[ID].NetOut[T].Write(NetOut);
end
else
begin
- P := enet_packet_create(NetOut.Data, NetOut.CurSize, F);
- if not Assigned(P) then Exit;
-
- enet_host_broadcast(NetHost, Chan, P);
+ // write size first
+ NetBuf[T].Write(Integer(NetOut.CurSize));
+ NetBuf[T].Write(NetOut);
end;
if NetDump then g_Net_DumpSendBuffer();
- g_Net_Flush();
NetOut.Clear();
end;
Byte(NetClients[ID].Peer^.data^) := ID;
NetClients[ID].State := NET_STATE_AUTH;
NetClients[ID].RCONAuth := False;
+ NetClients[ID].NetOut[NET_UNRELIABLE].Alloc(NET_BUFSIZE*2);
+ NetClients[ID].NetOut[NET_RELIABLE].Alloc(NET_BUFSIZE*2);
enet_peer_timeout(NetEvent.peer, ENET_PEER_TIMEOUT_LIMIT * 2, ENET_PEER_TIMEOUT_MINIMUM * 2, ENET_PEER_TIMEOUT_MAXIMUM * 2);
TC := @NetClients[ID];
if NetDump then g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength);
- g_Net_HostMsgHandler(TC, NetEvent.packet);
+ g_Net_Host_HandlePacket(TC, NetEvent.packet, g_Net_HostMsgHandler);
end;
ENET_EVENT_TYPE_DISCONNECT:
TC^.Peer := nil;
TC^.Player := 0;
TC^.RequestedFullUpdate := False;
+ TC^.NetOut[NET_UNRELIABLE].Free();
+ TC^.NetOut[NET_RELIABLE].Free();
FreeMemory(NetEvent.peer^.data);
NetEvent.peer^.data := nil;
procedure g_Net_Client_Send(Reliable: Boolean; Chan: Byte = NET_CHAN_GAME);
var
- P: pENetPacket;
- F: enet_uint32;
+ T: Integer;
begin
if (Reliable) then
- F := LongWord(ENET_PACKET_FLAG_RELIABLE)
+ T := NET_RELIABLE
else
- F := 0;
+ T := NET_UNRELIABLE;
- P := enet_packet_create(NetOut.Data, NetOut.CurSize, F);
- if not Assigned(P) then Exit;
+ // write size first
+ NetBuf[T].Write(Integer(NetOut.CurSize));
+ NetBuf[T].Write(NetOut);
- enet_peer_send(NetPeer, Chan, P);
if NetDump then g_Net_DumpSendBuffer();
- g_Net_Flush();
NetOut.Clear();
+ g_Net_Flush(); // FIXME: for now, send immediately
end;
function g_Net_Client_Update(): enet_size_t;
ENET_EVENT_TYPE_RECEIVE:
begin
if NetDump then g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength);
- g_Net_ClientMsgHandler(NetEvent.packet);
+ g_Net_Client_HandlePacket(NetEvent.packet, g_Net_ClientMsgHandler);
end;
ENET_EVENT_TYPE_DISCONNECT:
ENET_EVENT_TYPE_RECEIVE:
begin
if NetDump then g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength);
- g_Net_ClientLightMsgHandler(NetEvent.packet);
+ g_Net_Client_HandlePacket(NetEvent.packet, g_Net_ClientLightMsgHandler);
end;
ENET_EVENT_TYPE_DISCONNECT:
g_Net_DownloadTimeout := 60;
NetIn.Alloc(NET_BUFSIZE);
NetOut.Alloc(NET_BUFSIZE);
+ NetBuf[NET_UNRELIABLE].Alloc(NET_BUFSIZE*2);
+ NetBuf[NET_RELIABLE].Alloc(NET_BUFSIZE*2);
finalization
NetIn.Free();
NetOut.Free();
+ NetBuf[NET_UNRELIABLE].Free();
+ NetBuf[NET_RELIABLE].Free();
end.
index ac57351ce2abf65d42e2cf3ddd2b73d1fb555fc4..dadef20a3acf022e4716002a1c960bb2892eb757 100644 (file)
interface
-uses g_net, g_netmsg, ENet;
+uses e_msg, g_net, g_netmsg, ENet;
-procedure g_Net_ClientMsgHandler(P: pENetPacket);
-procedure g_Net_ClientLightMsgHandler(P: pENetPacket);
-procedure g_Net_HostMsgHandler(S: pTNetClient; P: pENetPacket);
+type
+ TNetClientMsgHandler = function (M: TMsg): Boolean;
+ TNetHostMsgHandler = function (S: pTNetClient; M: TMsg): Boolean;
+
+procedure g_Net_Client_HandlePacket(P: pENetPacket; Handler: TNetClientMsgHandler);
+procedure g_Net_Host_HandlePacket(S: pTNetClient; P: pENetPacket; Handler: TNetHostMsgHandler);
+
+function g_Net_ClientMsgHandler(NetMsg: TMsg): Boolean;
+function g_Net_ClientLightMsgHandler(NetMsg: TMsg): Boolean;
+function g_Net_HostMsgHandler(S: pTNetClient; NetMsg: TMsg): Boolean;
implementation
-uses e_msg;
+uses sysutils, g_console;
-procedure g_Net_ClientMsgHandler(P: pENetPacket);
+procedure g_Net_Client_HandlePacket(P: pENetPacket; Handler: TNetClientMsgHandler);
var
- MID: Byte;
+ MNext: Integer;
+ MSize: LongWord;
+ MHandled: Boolean;
NetMsg: TMsg;
begin
if not NetMsg.Init(P^.data, P^.dataLength, True) then
Exit;
+ MNext := 0;
+
+ while NetMsg.BytesLeft() > 0 do
+ begin
+ MSize := NetMsg.ReadLongWord();
+ MNext := NetMsg.ReadCount + MSize;
+ MHandled := Handler(NetMsg); // TODO: maybe do something with this bool
+ NetMsg.Seek(MNext);
+ end;
+
+ enet_packet_destroy(P);
+end;
+
+procedure g_Net_Host_HandlePacket(S: pTNetClient; P: pENetPacket; Handler: TNetHostMsgHandler);
+var
+ MNext: Integer;
+ MSize: LongWord;
+ MHandled: Boolean;
+ NetMsg: TMsg;
+begin
+ if not NetMsg.Init(P^.data, P^.dataLength, True) then
+ Exit;
+
+ MNext := 0;
+
+ while NetMsg.BytesLeft() > 0 do
+ begin
+ MSize := NetMsg.ReadLongWord();
+ MNext := NetMsg.ReadCount + MSize;
+ MHandled := Handler(S, NetMsg); // TODO: maybe do something with this bool
+ NetMsg.Seek(MNext);
+ end;
+
+ enet_packet_destroy(P);
+end;
+
+
+function g_Net_ClientMsgHandler(NetMsg: TMsg): Boolean;
+var
+ MID: Byte;
+begin
+ Result := True;
MID := NetMsg.ReadByte();
case MID of
NET_MSG_TIME_SYNC: MC_RECV_TimeSync(NetMsg);
NET_MSG_VOTE_EVENT: MC_RECV_VoteEvent(NetMsg);
- end;
- enet_packet_destroy(P);
+ else
+ begin
+ Result := False;
+ g_Console_Add('unknown message ID: ' + IntToStr(MID));
+ end;
+ end;
end;
-procedure g_Net_ClientLightMsgHandler(P: pENetPacket);
+function g_Net_ClientLightMsgHandler(NetMsg: TMsg): Boolean;
var
MID: Byte;
- NetMsg: TMsg;
begin
- if not NetMsg.Init(P^.data, P^.dataLength, True) then
- Exit;
-
+ Result := True;
MID := NetMsg.ReadByte();
case MID of
NET_MSG_PLR: if NetState <> NET_STATE_AUTH then MC_RECV_PlayerCreate(NetMsg);
NET_MSG_PLRDEL: if NetState <> NET_STATE_AUTH then MC_RECV_PlayerDelete(NetMsg);
- end;
- enet_packet_destroy(P);
+ else Result := False;
+ end;
end;
-procedure g_Net_HostMsgHandler(S: pTNetClient; P: pENetPacket);
+function g_Net_HostMsgHandler(S: pTNetClient; NetMsg: TMsg): Boolean;
var
MID: Byte;
- NetMsg: TMsg;
begin
- if not NetMsg.Init(P^.data, P^.dataLength, True) then
- Exit;
-
+ Result := True;
MID := NetMsg.ReadByte();
+ g_Console_Add('MID = ' + IntTOStr(MID));
case MID of
NET_MSG_INFO: MH_RECV_Info(S, NetMsg);
NET_MSG_VOTE_EVENT: MH_RECV_Vote(S, NetMsg);
end;
-
- enet_packet_destroy(P);
end;
end.
diff --git a/src/game/g_netmsg.pas b/src/game/g_netmsg.pas
index bffbcebd729077018f5b1ad41ef34148cd80fdc7..ec78e3020b83f0328be0831527027955a9ca6b4f 100644 (file)
--- a/src/game/g_netmsg.pas
+++ b/src/game/g_netmsg.pas
begin
MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000, 'N', ID);
end;
+
+ g_Net_Flush();
end;
procedure MH_SEND_Info(ID: Byte);
diff --git a/src/game/g_window.pas b/src/game/g_window.pas
index 88b229aa220b888697903da121c21f01e0bbe0f4..d703ea2fc2088a829bfa3af1bf07b83d31b44f16 100644 (file)
--- a/src/game/g_window.pas
+++ b/src/game/g_window.pas
else if (NetMode = NET_CLIENT) then g_Net_Client_Update();
end;
+ if NetMode = NET_SERVER then g_Net_Flush();
+
g_Map_ProfilersEnd();
g_Mons_ProfilersEnd();