1 (* Copyright (C) DooM 2D:Forever Developers
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, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 e_log
, e_fixedbuffer
, ENet
, ENetTypes
, ENetPlatform
, Classes
;
25 NET_PROTOCOL_VER
= 167;
31 NET_CHAN_IMPORTANT
= 1;
34 NET_CHAN_PLAYERPOS
= 4;
36 NET_CHAN_MONSTERPOS
= 6;
37 NET_CHAN_LARGEDATA
= 7;
39 NET_CHAN_DOWNLOAD
= 9;
50 NET_DISC_NONE
: enet_uint32
= 0;
51 NET_DISC_PROTOCOL
: enet_uint32
= 1;
52 NET_DISC_VERSION
: enet_uint32
= 2;
53 NET_DISC_FULL
: enet_uint32
= 3;
54 NET_DISC_KICK
: enet_uint32
= 4;
55 NET_DISC_DOWN
: enet_uint32
= 5;
56 NET_DISC_PASSWORD
: enet_uint32
= 6;
57 NET_DISC_TEMPBAN
: enet_uint32
= 7;
58 NET_DISC_BAN
: enet_uint32
= 8;
59 NET_DISC_MAX
: enet_uint32
= 8;
65 BANLIST_FILENAME
= 'banlist.txt';
74 RequestedFullUpdate
: Boolean;
82 pTNetClient
= ^TNetClient
;
84 AByte
= array of Byte;
87 NetInitDone
: Boolean = False;
88 NetMode
: Byte = NET_NONE
;
90 NetServerName
: string = 'Unnamed Server';
91 NetPassword
: string = '';
92 NetPort
: Word = 25666;
94 NetAllowRCON
: Boolean = False;
95 NetRCONPassword
: string = '';
97 NetTimeToUpdate
: Cardinal = 0;
98 NetTimeToReliable
: Cardinal = 0;
99 NetTimeToMaster
: Cardinal = 0;
101 NetHost
: pENetHost
= nil;
102 NetPeer
: pENetPeer
= nil;
104 NetAddr
: ENetAddress
;
106 NetPongAddr
: ENetAddress
;
107 NetPongSock
: ENetSocket
= ENET_SOCKET_NULL
;
109 NetUseMaster
: Boolean = True;
110 NetSlistAddr
: ENetAddress
;
111 NetSlistIP
: string = 'mpms.doom2d.org';
112 NetSlistPort
: Word = 25665;
114 NetClientIP
: string = '127.0.0.1';
115 NetClientPort
: Word = 25666;
117 NetIn
, NetOut
: TBuffer
;
119 NetClients
: array of TNetClient
;
120 NetClientCount
: Byte = 0;
121 NetMaxClients
: Byte = 255;
122 NetBannedHosts
: array of TBanRecord
;
124 NetState
: Integer = NET_STATE_NONE
;
126 NetMyID
: Integer = -1;
127 NetPlrUID1
: Integer = -1;
128 NetPlrUID2
: Integer = -1;
130 NetInterpLevel
: Integer = 1;
131 NetUpdateRate
: Cardinal = 0; // as soon as possible
132 NetRelupdRate
: Cardinal = 18; // around two times a second
133 NetMasterRate
: Cardinal = 60000;
135 NetForcePlayerUpdate
: Boolean = False;
136 NetPredictSelf
: Boolean = True;
137 NetGotKeys
: Boolean = False;
139 NetGotEverything
: Boolean = False;
141 function g_Net_Init(): Boolean;
142 procedure g_Net_Cleanup();
143 procedure g_Net_Free();
144 procedure g_Net_Flush();
146 function g_Net_Host(IPAddr
: LongWord; Port
: enet_uint16
; MaxClients
: Cardinal = 16): Boolean;
147 procedure g_Net_Host_Die();
148 procedure g_Net_Host_Send(ID
: Integer; Reliable
: Boolean; Chan
: Byte = NET_CHAN_GAME
);
149 function g_Net_Host_Update(): enet_size_t
;
151 function g_Net_Connect(IP
: string; Port
: enet_uint16
): Boolean;
152 procedure g_Net_Disconnect(Forced
: Boolean = False);
153 procedure g_Net_Client_Send(Reliable
: Boolean; Chan
: Byte = NET_CHAN_GAME
);
154 function g_Net_Client_Update(): enet_size_t
;
155 function g_Net_Client_UpdateWhileLoading(): enet_size_t
;
157 function g_Net_Client_ByName(Name
: string): pTNetClient
;
158 function g_Net_Client_ByPlayer(PID
: Word): pTNetClient
;
159 function g_Net_ClientName_ByID(ID
: Integer): string;
161 procedure g_Net_SendData(Data
:AByte
; peer
: pENetPeer
; Reliable
: Boolean; Chan
: Byte = NET_CHAN_DOWNLOAD
);
162 function g_Net_Wait_Event(msgId
: Word): TMemoryStream
;
164 function IpToStr(IP
: LongWord): string;
165 function StrToIp(IPstr
: string; var IP
: LongWord): Boolean;
167 function g_Net_IsHostBanned(IP
: LongWord; Perm
: Boolean = False): Boolean;
168 procedure g_Net_BanHost(IP
: LongWord; Perm
: Boolean = True); overload
;
169 procedure g_Net_BanHost(IP
: string; Perm
: Boolean = True); overload
;
170 function g_Net_UnbanHost(IP
: string): Boolean; overload
;
171 function g_Net_UnbanHost(IP
: LongWord): Boolean; overload
;
172 procedure g_Net_UnbanNonPermHosts();
173 procedure g_Net_SaveBanList();
179 e_input
, g_nethandler
, g_netmsg
, g_netmaster
, g_player
, g_window
, g_console
,
180 g_main
, g_game
, g_language
, g_weapons
;
183 { /// SERVICE FUNCTIONS /// }
186 function g_Net_FindSlot(): Integer;
195 for I
:= Low(NetClients
) to High(NetClients
) do
197 if NetClients
[I
].Used
then
206 if C
>= NetMaxClients
then
214 if (Length(NetClients
) >= NetMaxClients
) then
218 SetLength(NetClients
, Length(NetClients
) + 1);
219 N
:= High(NetClients
);
225 NetClients
[N
].Used
:= True;
226 NetClients
[N
].ID
:= N
;
227 NetClients
[N
].RequestedFullUpdate
:= False;
228 NetClients
[N
].RCONAuth
:= False;
229 NetClients
[N
].Voted
:= False;
230 NetClients
[N
].Player
:= 0;
236 function g_Net_Init(): Boolean;
242 e_Buffer_Clear(@NetIn
);
243 e_Buffer_Clear(@NetOut
);
244 SetLength(NetClients
, 0);
250 NetAddr
.port
:= 25666;
251 SetLength(NetBannedHosts
, 0);
252 if FileExists(DataDir
+ BANLIST_FILENAME
) then
254 Assign(F
, DataDir
+ BANLIST_FILENAME
);
259 if StrToIp(IPstr
, IP
) then
266 Result
:= (enet_initialize() = 0);
269 procedure g_Net_Flush();
271 enet_host_flush(NetHost
);
274 procedure g_Net_Cleanup();
276 e_Buffer_Clear(@NetIn
);
277 e_Buffer_Clear(@NetOut
);
279 SetLength(NetClients
, 0);
289 NetState
:= NET_STATE_NONE
;
291 NetPongSock
:= ENET_SOCKET_NULL
;
293 NetTimeToMaster
:= 0;
294 NetTimeToUpdate
:= 0;
295 NetTimeToReliable
:= 0;
300 procedure g_Net_Free();
305 NetInitDone
:= False;
309 { /// SERVER FUNCTIONS /// }
312 function g_Net_Host(IPAddr
: LongWord; Port
: enet_uint16
; MaxClients
: Cardinal = 16): Boolean;
314 if NetMode
<> NET_NONE
then
316 g_Console_Add(_lc
[I_NET_MSG_ERROR
] + _lc
[I_NET_ERR_INGAME
]);
323 g_Console_Add(_lc
[I_NET_MSG
] + Format(_lc
[I_NET_MSG_HOST
], [Port
]));
324 if not NetInitDone
then
326 if (not g_Net_Init()) then
328 g_Console_Add(_lc
[I_NET_MSG_FERROR
] + _lc
[I_NET_ERR_ENET
]);
336 NetAddr
.host
:= IPAddr
;
337 NetAddr
.port
:= Port
;
339 NetHost
:= enet_host_create(@NetAddr
, NET_MAXCLIENTS
, NET_CHANS
, 0, 0);
341 if (NetHost
= nil) then
343 g_Console_Add(_lc
[I_NET_MSG_ERROR
] + Format(_lc
[I_NET_ERR_HOST
], [Port
]));
349 NetPongSock
:= enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM
);
350 if NetPongSock
<> ENET_SOCKET_NULL
then
352 NetPongAddr
.host
:= IPAddr
;
353 NetPongAddr
.port
:= Port
+ 1;
354 if enet_socket_bind(NetPongSock
, @NetPongAddr
) < 0 then
356 enet_socket_destroy(NetPongSock
);
357 NetPongSock
:= ENET_SOCKET_NULL
;
360 enet_socket_set_option(NetPongSock
, ENET_SOCKOPT_NONBLOCK
, 1);
363 NetMode
:= NET_SERVER
;
364 e_Buffer_Clear(@NetOut
);
367 procedure g_Net_Host_Die();
371 if NetMode
<> NET_SERVER
then Exit
;
373 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_HOST_DISCALL
]);
374 for I
:= 0 to High(NetClients
) do
375 if NetClients
[I
].Used
then
376 enet_peer_disconnect(NetClients
[I
].Peer
, NET_DISC_DOWN
);
378 while enet_host_service(NetHost
, @NetEvent
, 1000) > 0 do
379 if NetEvent
.kind
= ENET_EVENT_TYPE_RECEIVE
then
380 enet_packet_destroy(NetEvent
.packet
);
382 for I
:= 0 to High(NetClients
) do
383 if NetClients
[I
].Used
then
385 FreeMemory(NetClients
[I
].Peer
^.data
);
386 NetClients
[I
].Peer
^.data
:= nil;
387 enet_peer_reset(NetClients
[I
].Peer
);
388 NetClients
[I
].Peer
:= nil;
389 NetClients
[I
].Used
:= False;
392 if (NetMPeer
<> nil) and (NetMHost
<> nil) then g_Net_Slist_Disconnect
;
393 if NetPongSock
<> ENET_SOCKET_NULL
then
394 enet_socket_destroy(NetPongSock
);
396 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_HOST_DIE
]);
397 enet_host_destroy(NetHost
);
402 e_WriteLog('NET: Server stopped', MSG_NOTIFY
);
406 procedure g_Net_Host_Send(ID
: Integer; Reliable
: Boolean; Chan
: Byte = NET_CHAN_GAME
);
412 F
:= LongWord(ENET_PACKET_FLAG_RELIABLE
)
418 if ID
> High(NetClients
) then Exit
;
419 if NetClients
[ID
].Peer
= nil then Exit
;
421 P
:= enet_packet_create(Addr(NetOut
.Data
), NetOut
.Len
, F
);
422 if not Assigned(P
) then Exit
;
424 enet_peer_send(NetClients
[ID
].Peer
, Chan
, P
);
428 P
:= enet_packet_create(Addr(NetOut
.Data
), NetOut
.Len
, F
);
429 if not Assigned(P
) then Exit
;
431 enet_host_widecast(NetHost
, Chan
, P
);
435 e_Buffer_Clear(@NetOut
);
438 procedure g_Net_Host_CheckPings();
444 Ping
: array [0..9] of Byte;
447 if NetPongSock
= ENET_SOCKET_NULL
then Exit
;
449 Buf
.data
:= Addr(Ping
[0]);
450 Buf
.dataLength
:= 2+8;
454 Len
:= enet_socket_receive(NetPongSock
, @ClAddr
, @Buf
, 1);
455 if Len
< 0 then Exit
;
457 if (Ping
[0] = Ord('D')) and (Ping
[1] = Ord('F')) then
459 ClTime
:= Int64(Addr(Ping
[2])^);
461 e_Buffer_Clear(@NetOut
);
462 e_Buffer_Write(@NetOut
, Byte(Ord('D')));
463 e_Buffer_Write(@NetOut
, Byte(Ord('F')));
464 e_Buffer_Write(@NetOut
, ClTime
);
465 g_Net_Slist_WriteInfo();
467 if gPlayer1
<> nil then Inc(NPl
);
468 if gPlayer2
<> nil then Inc(NPl
);
469 e_Buffer_Write(@NetOut
, NPl
);
470 e_Buffer_Write(@NetOut
, gNumBots
);
472 Buf
.data
:= Addr(NetOut
.Data
[0]);
473 Buf
.dataLength
:= NetOut
.WritePos
;
474 enet_socket_send(NetPongSock
, @ClAddr
, @Buf
, 1);
476 e_Buffer_Clear(@NetOut
);
480 function g_Net_Host_Update(): enet_size_t
;
494 g_Net_Host_CheckPings
;
497 while (enet_host_service(NetHost
, @NetEvent
, 0) > 0) do
499 case (NetEvent
.kind
) of
500 ENET_EVENT_TYPE_CONNECT
:
502 IP
:= IpToStr(NetEvent
.Peer
^.address
.host
);
503 Port
:= NetEvent
.Peer
^.address
.port
;
504 g_Console_Add(_lc
[I_NET_MSG
] +
505 Format(_lc
[I_NET_MSG_HOST_CONN
], [IP
, Port
]));
507 if (NetEvent
.data
<> NET_PROTOCOL_VER
) then
509 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_HOST_REJECT
] +
510 _lc
[I_NET_DISC_PROTOCOL
]);
511 NetEvent
.peer
^.data
:= GetMemory(SizeOf(Byte));
512 Byte(NetEvent
.peer
^.data
^) := 255;
513 enet_peer_disconnect(NetEvent
.peer
, NET_DISC_PROTOCOL
);
514 enet_host_flush(NetHost
);
518 ID
:= g_Net_FindSlot();
522 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_HOST_REJECT
] +
523 _lc
[I_NET_DISC_FULL
]);
524 NetEvent
.Peer
^.data
:= GetMemory(SizeOf(Byte));
525 Byte(NetEvent
.peer
^.data
^) := 255;
526 enet_peer_disconnect(NetEvent
.peer
, NET_DISC_FULL
);
527 enet_host_flush(NetHost
);
531 NetClients
[ID
].Peer
:= NetEvent
.peer
;
532 NetClients
[ID
].Peer
^.data
:= GetMemory(SizeOf(Byte));
533 Byte(NetClients
[ID
].Peer
^.data
^) := ID
;
534 NetClients
[ID
].State
:= NET_STATE_AUTH
;
535 NetClients
[ID
].RCONAuth
:= False;
537 enet_peer_timeout(NetEvent
.peer
, ENET_PEER_TIMEOUT_LIMIT
* 2, ENET_PEER_TIMEOUT_MINIMUM
* 2, ENET_PEER_TIMEOUT_MAXIMUM
* 2);
540 g_Console_Add(_lc
[I_NET_MSG
] + Format(_lc
[I_NET_MSG_HOST_ADD
], [ID
]));
543 ENET_EVENT_TYPE_RECEIVE
:
545 ID
:= Byte(NetEvent
.peer
^.data
^);
546 if ID
> High(NetClients
) then Exit
;
547 TC
:= @NetClients
[ID
];
549 g_Net_HostMsgHandler(TC
, NetEvent
.packet
);
552 ENET_EVENT_TYPE_DISCONNECT
:
554 ID
:= Byte(NetEvent
.peer
^.data
^);
555 if ID
> High(NetClients
) then Exit
;
556 TC
:= @NetClients
[ID
];
557 if TC
= nil then Exit
;
559 if not (TC
^.Used
) then Exit
;
561 TP
:= g_Player_Get(TC
^.Player
);
566 TP
.Kill(K_SIMPLEKILL
, 0, HIT_DISCON
);
567 g_Console_Add(Format(_lc
[I_PLAYER_LEAVE
], [TP
.Name
]), True);
568 e_WriteLog('NET: Client ' + TP
.Name
+ ' [' + IntToStr(ID
) + '] disconnected.', MSG_NOTIFY
);
569 g_Player_Remove(TP
.UID
);
573 TC
^.State
:= NET_STATE_NONE
;
576 TC
^.RequestedFullUpdate
:= False;
578 FreeMemory(NetEvent
.peer
^.data
);
579 NetEvent
.peer
^.data
:= nil;
580 g_Console_Add(_lc
[I_NET_MSG
] + Format(_lc
[I_NET_MSG_HOST_DISC
], [ID
]));
583 if NetUseMaster
then g_Net_Slist_Update
;
590 { /// CLIENT FUNCTIONS /// }
593 procedure g_Net_Disconnect(Forced
: Boolean = False);
595 if NetMode
<> NET_CLIENT
then Exit
;
596 if (NetHost
= nil) or (NetPeer
= nil) then Exit
;
600 enet_peer_disconnect(NetPeer
, NET_DISC_NONE
);
602 while (enet_host_service(NetHost
, @NetEvent
, 1500) > 0) do
604 if (NetEvent
.kind
= ENET_EVENT_TYPE_DISCONNECT
) then
610 if (NetEvent
.kind
= ENET_EVENT_TYPE_RECEIVE
) then
611 enet_packet_destroy(NetEvent
.packet
);
614 if NetPeer
<> nil then
616 enet_peer_reset(NetPeer
);
622 e_WriteLog('NET: Kicked from server: ' + IntToStr(NetEvent
.data
), MSG_NOTIFY
);
623 if (NetEvent
.data
<= NET_DISC_MAX
) then
624 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_KICK
] +
625 _lc
[TStrings_Locale(Cardinal(I_NET_DISC_NONE
) + NetEvent
.data
)], True);
628 if NetHost
<> nil then
630 enet_host_destroy(NetHost
);
633 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_CLIENT_DISC
]);
636 e_WriteLog('NET: Disconnected', MSG_NOTIFY
);
639 procedure g_Net_Client_Send(Reliable
: Boolean; Chan
: Byte = NET_CHAN_GAME
);
645 F
:= LongWord(ENET_PACKET_FLAG_RELIABLE
)
649 P
:= enet_packet_create(Addr(NetOut
.Data
), NetOut
.Len
, F
);
650 if not Assigned(P
) then Exit
;
652 enet_peer_send(NetPeer
, Chan
, P
);
654 e_Buffer_Clear(@NetOut
);
657 function g_Net_Client_Update(): enet_size_t
;
660 while (enet_host_service(NetHost
, @NetEvent
, 0) > 0) do
662 case NetEvent
.kind
of
663 ENET_EVENT_TYPE_RECEIVE
:
664 g_Net_ClientMsgHandler(NetEvent
.packet
);
666 ENET_EVENT_TYPE_DISCONNECT
:
668 g_Net_Disconnect(True);
676 function g_Net_Client_UpdateWhileLoading(): enet_size_t
;
679 while (enet_host_service(NetHost
, @NetEvent
, 0) > 0) do
681 case NetEvent
.kind
of
682 ENET_EVENT_TYPE_RECEIVE
:
683 g_Net_ClientLightMsgHandler(NetEvent
.packet
);
685 ENET_EVENT_TYPE_DISCONNECT
:
687 g_Net_Disconnect(True);
696 function g_Net_Connect(IP
: string; Port
: enet_uint16
): Boolean;
700 if NetMode
<> NET_NONE
then
702 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_ERR_INGAME
], True);
709 g_Console_Add(_lc
[I_NET_MSG
] + Format(_lc
[I_NET_MSG_CLIENT_CONN
],
711 if not NetInitDone
then
713 if (not g_Net_Init()) then
715 g_Console_Add(_lc
[I_NET_MSG_FERROR
] + _lc
[I_NET_ERR_ENET
], True);
723 NetHost
:= enet_host_create(nil, 1, NET_CHANS
, 0, 0);
725 if (NetHost
= nil) then
727 g_Console_Add(_lc
[I_NET_MSG_ERROR
] + _lc
[I_NET_ERR_CLIENT
], True);
733 enet_address_set_host(@NetAddr
, PChar(Addr(IP
[1])));
734 NetAddr
.port
:= Port
;
736 NetPeer
:= enet_host_connect(NetHost
, @NetAddr
, NET_CHANS
, NET_PROTOCOL_VER
);
738 if (NetPeer
= nil) then
740 g_Console_Add(_lc
[I_NET_MSG_ERROR
] + _lc
[I_NET_ERR_CLIENT
], True);
741 enet_host_destroy(NetHost
);
750 while (enet_host_service(NetHost
, @NetEvent
, 0) > 0) do
752 if (NetEvent
.kind
= ENET_EVENT_TYPE_CONNECT
) then
754 g_Console_Add(_lc
[I_NET_MSG
] + _lc
[I_NET_MSG_CLIENT_DONE
]);
755 NetMode
:= NET_CLIENT
;
756 e_Buffer_Clear(@NetOut
);
757 enet_peer_timeout(NetPeer
, ENET_PEER_TIMEOUT_LIMIT
* 2, ENET_PEER_TIMEOUT_MINIMUM
* 2, ENET_PEER_TIMEOUT_MAXIMUM
* 2);
759 NetClientPort
:= Port
;
768 if e_KeyPressed(IK_ESCAPE
) or e_KeyPressed(IK_SPACE
) then
772 g_Console_Add(_lc
[I_NET_MSG_ERROR
] + _lc
[I_NET_ERR_TIMEOUT
], True);
773 if NetPeer
<> nil then enet_peer_reset(NetPeer
);
774 if NetHost
<> nil then
776 enet_host_destroy(NetHost
);
783 function IpToStr(IP
: LongWord): string;
791 Result
:= Result
+ IntToStr(e_Raw_Read_Byte(Ptr
)) + '.';
792 Result
:= Result
+ IntToStr(e_Raw_Read_Byte(Ptr
)) + '.';
793 Result
:= Result
+ IntToStr(e_Raw_Read_Byte(Ptr
)) + '.';
794 Result
:= Result
+ IntToStr(e_Raw_Read_Byte(Ptr
));
798 function StrToIp(IPstr
: string; var IP
: LongWord): Boolean;
802 Result
:= enet_address_set_host(@EAddr
, PChar(@IPstr
[1])) = 0;
806 function g_Net_Client_ByName(Name
: string): pTNetClient
;
812 for a
:= Low(NetClients
) to High(NetClients
) do
813 if (NetClients
[a
].Used
) and (NetClients
[a
].State
= NET_STATE_GAME
) then
815 pl
:= g_Player_Get(NetClients
[a
].Player
);
816 if pl
= nil then continue
;
817 if Copy(LowerCase(pl
.Name
), 1, Length(Name
)) <> LowerCase(Name
) then continue
;
818 if NetClients
[a
].Peer
<> nil then
820 Result
:= @NetClients
[a
];
826 function g_Net_Client_ByPlayer(PID
: Word): pTNetClient
;
831 for a
:= Low(NetClients
) to High(NetClients
) do
832 if (NetClients
[a
].Used
) and (NetClients
[a
].State
= NET_STATE_GAME
) then
833 if NetClients
[a
].Player
= PID
then
835 Result
:= @NetClients
[a
];
840 function g_Net_ClientName_ByID(ID
: Integer): string;
846 if ID
= NET_EVERYONE
then
848 for a
:= Low(NetClients
) to High(NetClients
) do
849 if (NetClients
[a
].ID
= ID
) and (NetClients
[a
].Used
) and (NetClients
[a
].State
= NET_STATE_GAME
) then
851 pl
:= g_Player_Get(NetClients
[a
].Player
);
852 if pl
= nil then Exit
;
857 procedure g_Net_SendData(Data
:AByte
; peer
: pENetPeer
; Reliable
: Boolean; Chan
: Byte = NET_CHAN_DOWNLOAD
);
861 dataLength
: Cardinal;
863 dataLength
:= Length(Data
);
866 F
:= LongWord(ENET_PACKET_FLAG_RELIABLE
)
870 if (peer
<> nil) then
872 P
:= enet_packet_create(@Data
[0], dataLength
, F
);
873 if not Assigned(P
) then Exit
;
874 enet_peer_send(peer
, Chan
, P
);
878 P
:= enet_packet_create(@Data
[0], dataLength
, F
);
879 if not Assigned(P
) then Exit
;
880 enet_host_widecast(NetHost
, Chan
, P
);
883 enet_host_flush(NetHost
);
886 function g_Net_Wait_Event(msgId
: Word): TMemoryStream
;
888 downloadEvent
: ENetEvent
;
892 msgStream
: TMemoryStream
;
894 FillChar(downloadEvent
, SizeOf(downloadEvent
), 0);
899 while (enet_host_service(NetHost
, @downloadEvent
, 0) > 0) do
901 if (downloadEvent
.kind
= ENET_EVENT_TYPE_RECEIVE
) then
903 Ptr
:= downloadEvent
.packet
^.data
;
907 if (MID
= msgId
) then
909 msgStream
:= TMemoryStream
.Create
;
910 msgStream
.SetSize(downloadEvent
.packet
^.dataLength
);
911 msgStream
.WriteBuffer(Ptr
^, downloadEvent
.packet
^.dataLength
);
912 msgStream
.Seek(0, soFromBeginning
);
915 enet_packet_destroy(downloadEvent
.packet
);
919 enet_packet_destroy(downloadEvent
.packet
);
923 if (downloadEvent
.kind
= ENET_EVENT_TYPE_DISCONNECT
) then
925 if (downloadEvent
.data
<= NET_DISC_MAX
) then
926 g_Console_Add(_lc
[I_NET_MSG_ERROR
] + _lc
[I_NET_ERR_CONN
] + ' ' +
927 _lc
[TStrings_Locale(Cardinal(I_NET_DISC_NONE
) + downloadEvent
.data
)], True);
937 if e_KeyPressed(IK_ESCAPE
) or e_KeyPressed(IK_SPACE
) then
943 function g_Net_IsHostBanned(IP
: LongWord; Perm
: Boolean = False): Boolean;
948 if NetBannedHosts
= nil then
950 for I
:= 0 to High(NetBannedHosts
) do
951 if (NetBannedHosts
[I
].IP
= IP
) and ((not Perm
) or (NetBannedHosts
[I
].Perm
)) then
958 procedure g_Net_BanHost(IP
: LongWord; Perm
: Boolean = True); overload
;
964 if g_Net_IsHostBanned(IP
, Perm
) then
968 for I
:= Low(NetBannedHosts
) to High(NetBannedHosts
) do
969 if NetBannedHosts
[I
].IP
= 0 then
977 SetLength(NetBannedHosts
, Length(NetBannedHosts
) + 1);
978 P
:= High(NetBannedHosts
);
981 NetBannedHosts
[P
].IP
:= IP
;
982 NetBannedHosts
[P
].Perm
:= Perm
;
985 procedure g_Net_BanHost(IP
: string; Perm
: Boolean = True); overload
;
992 g_Net_BanHost(a
, Perm
);
995 procedure g_Net_UnbanNonPermHosts();
999 if NetBannedHosts
= nil then
1001 for I
:= Low(NetBannedHosts
) to High(NetBannedHosts
) do
1002 if (NetBannedHosts
[I
].IP
> 0) and not NetBannedHosts
[I
].Perm
then
1004 NetBannedHosts
[I
].IP
:= 0;
1005 NetBannedHosts
[I
].Perm
:= True;
1009 function g_Net_UnbanHost(IP
: string): Boolean; overload
;
1013 Result
:= StrToIp(IP
, a
);
1015 Result
:= g_Net_UnbanHost(a
);
1018 function g_Net_UnbanHost(IP
: LongWord): Boolean; overload
;
1025 if NetBannedHosts
= nil then
1027 for I
:= 0 to High(NetBannedHosts
) do
1028 if NetBannedHosts
[I
].IP
= IP
then
1030 NetBannedHosts
[I
].IP
:= 0;
1031 NetBannedHosts
[I
].Perm
:= True;
1033 // no break here to clear all bans of this host, perm and non-perm
1037 procedure g_Net_SaveBanList();
1042 Assign(F
, DataDir
+ BANLIST_FILENAME
);
1044 if NetBannedHosts
<> nil then
1045 for I
:= 0 to High(NetBannedHosts
) do
1046 if NetBannedHosts
[I
].Perm
and (NetBannedHosts
[I
].IP
> 0) then
1047 Writeln(F
, IpToStr(NetBannedHosts
[I
].IP
));