source: tags/1.3.0/Network/UNetworkServer.pas

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