source: tags/1.3.1/Network/UNetworkServer.pas

Last change on this file was 424, checked in by chronos, 2 years ago
  • Modified: Update Common package to version 0.10.
  • Modified: fgl unit replaced by Generics.Collections.
File size: 8.4 KB
Line 
1unit UNetworkServer;
2
3interface
4
5uses
6 Classes, SysUtils{$IFDEF UNIX}, Generics.Collections, fpAsync, fpsock,
7 fphttpclient{$ENDIF}, Protocol;
8
9{$IFDEF UNIX}
10type
11 TNetworkServer = class;
12 TNetworkServerPlayer = class;
13
14 { TTCPServerThread }
15
16 TTCPServerThread = class(TThread)
17 TCPServer: TTCPServer;
18 procedure Execute; override;
19 end;
20
21 { TNetworkServerConnection }
22
23 TNetworkServerConnection = class
24 private
25 DataAvailableHandle: Pointer;
26 ReceiveBuffer: TMemoryStream;
27 procedure DisconnectExecute(Sender: TObject);
28 procedure DataAvailableSync;
29 procedure DataAvailableExecute(Sender: TObject);
30 public
31 NetworkServer: TNetworkServer;
32 Socket: TSocketStream;
33 ServerEventLoop: TEventLoop;
34 Player: TNetworkServerPlayer;
35 Connected: Boolean;
36 procedure Run;
37 constructor Create;
38 destructor Destroy; override;
39 end;
40
41 { TNetworkServerPlayer }
42
43 TNetworkServerPlayer = class
44 private
45 Buffer: TMemoryStream;
46 public
47 NetworkServer: TNetworkServer;
48 Id: Integer;
49 Connection: TNetworkServerConnection;
50 constructor Create;
51 destructor Destroy; override;
52 procedure Client(Command: TCommand; Player: Integer; var Data);
53 function Server(Command: TCommand; Player, Subject: Integer; var Data): Integer;
54 end;
55
56 { TNetworkServerPlayers }
57
58 TNetworkServerPlayers = class(TObjectList<TNetworkServerPlayer>)
59 function SearchById(Id: Integer): TNetworkServerPlayer;
60 end;
61
62 { TNetworkServer }
63
64 TNetworkServer = class
65 private
66 Players: TNetworkServerPlayers;
67 Connections: TObjectList<TNetworkServerConnection>;
68 TCPServerThread: TTCPServerThread;
69 ServerEventLoop: TEventLoop;
70 procedure ConnectExecute(Sender: TConnectionBasedSocket; AStream: TSocketStream);
71 procedure Client(Command: TCommand; Player: integer; var Data);
72 public
73 TCPServer: TTCPServer;
74 Server: TServerCall;
75 constructor Create;
76 destructor Destroy; override;
77 end;
78
79var
80 NetworkServer: TNetworkServer;
81{$ENDIF}
82
83procedure Client(Command, Player: integer; var Data); stdcall;
84
85
86implementation
87
88{$IFDEF UNIX}
89uses
90 Global, UNetworkCommon;
91{$ENDIF}
92
93procedure Client(Command, Player: integer; var Data);
94begin
95 {$IFDEF UNIX}
96 if not Assigned(NetworkServer) then begin
97 NetworkServer := TNetworkServer.Create;
98 end;
99 case TCommand(Command) of
100 cmReleaseModule: begin
101 FreeAndNil(NetworkServer);
102 end;
103 end;
104 NetworkServer.Client(TCommand(Command), Player, Data);
105 {$ENDIF}
106end;
107
108{$IFDEF UNIX}
109
110{ TNetworkServerPlayers }
111
112function TNetworkServerPlayers.SearchById(Id: Integer): TNetworkServerPlayer;
113var
114 I: Integer;
115begin
116 I := 0;
117 while (I < Count) and (Items[I].Id <> Id) do Inc(I);
118 if I < Count then Result := Items[I]
119 else Result := nil;
120end;
121
122{ TNetworkServerPlayer }
123
124constructor TNetworkServerPlayer.Create;
125begin
126 Buffer := TMemoryStream.Create;
127end;
128
129destructor TNetworkServerPlayer.Destroy;
130begin
131 if Assigned(Connection) then Connection.Player := nil;
132 FreeAndNil(Buffer);
133 inherited;
134end;
135
136procedure TNetworkServerPlayer.Client(Command: TCommand; Player: Integer; var Data);
137begin
138 if Assigned(Connection) then begin
139 with Connection.Socket do begin
140 if Buffer.Size > 0 then begin
141 Buffer.Position := 0;
142 CopyFrom(Buffer, Buffer.Size);
143 Buffer.Clear;
144 end;
145 WriteDWord(DWord(Command));
146 WriteDWord(DWord(Player));
147 if GetCommandDataSize(Command) > 0 then
148 Write(Data, GetCommandDataSize(Command));
149 end;
150 end else begin
151 with Buffer do begin
152 WriteDWord(DWord(Command));
153 WriteDWord(DWord(Player));
154 if GetCommandDataSize(Command) > 0 then
155 Write(Data, GetCommandDataSize(Command));
156 end;
157 end;
158end;
159
160function TNetworkServerPlayer.Server(Command: TCommand; Player,
161 Subject: Integer; var Data): Integer;
162begin
163 NetworkServer.Server(Integer(Command), Player, Subject, Data);
164end;
165
166{ TNetworkServerConnection }
167
168procedure TNetworkServerConnection.DisconnectExecute(Sender: TObject);
169begin
170 {Connected := False;
171 if Assigned(Player) then begin
172 Player.Connection := nil;
173 Player := nil;
174 end;
175 }
176end;
177
178procedure TNetworkServerConnection.DataAvailableSync;
179var
180 Data: array of Byte;
181 ReadCount: Integer;
182 PlayerIndex: Integer;
183 Subject: Integer;
184 Command: TCommand;
185begin
186 StreamAppend(ReceiveBuffer, Socket);
187 while ReceiveBuffer.Size >= 3 * SizeOf(Integer) do begin
188 ReceiveBuffer.Position := 0;
189
190 Command := TCommand(ReceiveBuffer.ReadDWord);
191 PlayerIndex := ReceiveBuffer.ReadDWord;
192 Subject := ReceiveBuffer.ReadDWord;
193 SetLength(Data, GetCommandDataSize(TCommand(Command)));
194 if Length(Data) > 0 then begin
195 ReadCount := ReceiveBuffer.Read(Data[0], Length(Data));
196 SetLength(Data, ReadCount);
197 end;
198 if Assigned(Player) then begin
199 if Length(Data) > 0 then
200 Player.Server(Command, PlayerIndex, Subject, Data[0])
201 else Player.Server(Command, PlayerIndex, Subject, nil^);
202 end;
203 StreamRemoveRead(ReceiveBuffer);
204 end;
205end;
206
207procedure TNetworkServerConnection.DataAvailableExecute(Sender: TObject);
208begin
209 NetworkServer.TCPServerThread.Synchronize(NetworkServer.TCPServerThread, DataAvailableSync);
210 Sleep(10); // TODO: How to reset this event
211end;
212
213procedure TNetworkServerConnection.Run;
214begin
215 Socket.OnDisconnect := DisconnectExecute;
216 DataAvailableHandle := NetworkServer.TCPServer.EventLoop.SetDataAvailableNotify(Socket.Handle, DataAvailableExecute, nil);
217 Connected := True;
218end;
219
220constructor TNetworkServerConnection.Create;
221begin
222 ReceiveBuffer := TMemoryStream.Create;
223end;
224
225destructor TNetworkServerConnection.Destroy;
226begin
227 if Assigned(Player) then Player.Connection := nil;
228 if Assigned(DataAvailableHandle) then
229 NetworkServer.TCPServer.EventLoop.ClearDataAvailableNotify(DataAvailableHandle);
230 FreeAndNil(Socket);
231 NetworkServer.Connections.Remove(Self);
232 FreeAndNil(ReceiveBuffer);
233 inherited;
234end;
235
236{ TNetworkServer }
237
238procedure TNetworkServer.ConnectExecute(Sender: TConnectionBasedSocket;
239 AStream: TSocketStream);
240var
241 NewConnection: TNetworkServerConnection;
242 Player: TNetworkServerPlayer;
243 I: Integer;
244 InitModuleData: TInitModuleData;
245begin
246 NewConnection := TNetworkServerConnection.Create;
247 NewConnection.Socket := AStream;
248 NewConnection.NetworkServer := Self;
249 Connections.Add(NewConnection);
250 NewConnection.Run;
251
252 // Search for player without connection
253 Player := nil;
254 for I := 0 to Players.Count - 1 do begin
255 if not Assigned(Players[I].Connection) then begin
256 Player := Players[I];
257 Break;
258 end;
259 end;
260 if Assigned(Player) then begin
261 NewConnection.Player := Player;
262 Player.Connection := NewConnection;
263 Player.Client(cmInitModule, Player.Id, InitModuleData);
264 end else AStream.Free;
265end;
266
267procedure TNetworkServer.Client(Command: TCommand; Player: integer; var Data);
268var
269 Cmd: TCommand;
270 NewPlayer: TNetworkServerPlayer;
271 I: Integer;
272 ServerPlayer: TNetworkServerPlayer;
273begin
274 if Player <> -1 then begin
275 NewPlayer := TNetworkServerPlayer.Create;
276 NewPlayer.Id := Player;
277 NewPlayer.NetworkServer := Self;
278 Players.Add(NewPlayer);
279 end;
280
281 Cmd := TCommand(Command);
282 case Cmd of
283 cmInitModule: begin
284 TInitModuleData(Data).Flags := aiThreaded;
285 Server := TInitModuleData(Data).Server;
286 end;
287 else begin
288 if Player = -1 then begin
289 // Send to all
290 for I := 0 to NetworkServer.Players.Count - 1 do
291 NetworkServer.Players[I].Client(Cmd, Player, Data);
292 end else begin
293 ServerPlayer := NetworkServer.Players.SearchById(Player);
294 if Assigned(ServerPlayer) then
295 ServerPlayer.Client(Cmd, Player, Data);
296 end;
297 end;
298 end;
299end;
300
301constructor TNetworkServer.Create;
302begin
303 Players := TNetworkServerPlayers.Create;
304 ServerEventLoop := TEventLoop.Create;
305 Connections := TObjectList<TNetworkServerConnection>.Create;
306 TCPServer := TTCPServer.Create(nil);
307 with TCPServer do begin
308 EventLoop := ServerEventLoop;
309 Port := CevoNetworkPort;
310 OnConnect := ConnectExecute;
311 Active := True;
312 end;
313 TCPServerThread := TTCPServerThread.Create(True);
314 TCPServerThread.TCPServer := TCPServer;
315 TCPServerThread.Start;
316end;
317
318destructor TNetworkServer.Destroy;
319begin
320 ServerEventLoop.Break;
321 FreeAndNil(TCPServerThread);
322 FreeAndNil(ServerEventLoop);
323 FreeAndNil(TCPServer);
324 FreeAndNil(Connections);
325 FreeAndNil(Players);
326 inherited;
327end;
328
329{ TTCPServerThread }
330
331procedure TTCPServerThread.Execute;
332begin
333 TCPServer.EventLoop.Run;
334end;
335
336{$ENDIF}
337
338end.
339
Note: See TracBrowser for help on using the repository browser.