1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/debug.h"
24 #include "nel/misc/common.h"
25 #include "nel/misc/mem_stream.h"
26 #include "nel/misc/time_nl.h"
27 #include "nel/misc/config_file.h"
29 #include "nel/net/udp_sock.h"
30 #include "nel/net/callback_client.h"
31 #include "nel/net/inet_address.h"
32 #include "nel/net/udp_sim_sock.h"
39 #include "nel/3d/u_driver.h"
40 #include "nel/3d/u_scene.h"
41 #include "nel/3d/u_camera.h"
42 #include "nel/3d/u_instance.h"
43 #include "nel/3d/u_animation_set.h"
44 #include "nel/3d/u_play_list.h"
45 #include "nel/3d/u_play_list_manager.h"
46 #include "nel/3d/u_text_context.h"
47 #include "nel/3d/u_texture.h"
48 #include "nel/3d/event_mouse_listener.h"
62 using namespace NLMISC
;
63 using namespace NLNET
;
69 // must be increase at each version and must be the same value as the server
72 string ServerAddr
= "itsalive.nevrax.org"; // ldserver
73 uint16 UDPPort
= 45455;
74 uint16 TCPPort
= 45456;
76 uint32 MaxUDPPacketSize
= 1000;
78 CUdpSimSock
*UdpSock
= NULL
;
84 string ConnectionName
;
86 CConfigFile ConfigFile
;
90 CGraph
FpsGraph ("frame rate (fps)", 10.0f
, 110.0f
, 100.0f
, 100.0f
, CRGBA(128,0,0,128), 1000, 150.0f
);
91 CGraph
DownloadGraph ("download (bps)", 10.0f
, 260.0f
, 100.0f
, 100.0f
, CRGBA(0,0,128,128), 1000, 20000.0f
);
92 CGraph
UploadGraph ("upload (bps)", 10.0f
, 360.0f
, 100.0f
, 100.0f
, CRGBA(0,128,128,128), 1000, 20000.0f
);
93 CGraph
LagGraph ("lag (ms)", 150.0f
, 110.0f
, 100.0f
, 100.0f
, CRGBA(128,64,64,128), 100000, 2000.0f
);
101 void exit (const string
&reason
)
104 InfoLog
->displayRawNL ("%s", reason
.c_str());
105 InfoLog
->displayRawNL ("Press <enter> to exit");
111 // Config file functions
114 void createConfigFile()
116 FILE *fp
= nlfopen ("client.cfg", "wt");
119 InfoLog
->displayRawNL ("Can't create client.cfg");
123 fprintf (fp
, "ServerAddress = \"%s\";\n", ServerAddr
.c_str());
124 fprintf (fp
, "SimInLag = 0;\n");
125 fprintf (fp
, "SimInPacketLost = 0;\n");
126 fprintf (fp
, "SimOutLag = 0;\n");
127 fprintf (fp
, "SimOutPacketLost = 0;\n");
128 fprintf (fp
, "SimOutPacketDuplication = 0;\n");
129 fprintf (fp
, "SimOutPacketDisordering = 0;\n");
130 fprintf (fp
, "ConnectionName = \"\";\n");
135 void checkConnectionName ()
137 if (ConnectionName
.size() > 30)
139 exit ("Bad connection name (must be <= 30 characters)");
142 if (ConnectionName
.size() > 0 && ConnectionName
[ConnectionName
.size()-1] == '\n')
144 ConnectionName
= ConnectionName
.substr (0, ConnectionName
.size()-1);
147 if (ConnectionName
.size() <= 0)
149 exit ("Bad connection name (must be > 0 character)");
152 for (uint i
= 0; i
< ConnectionName
.size(); i
++)
154 if (!isalnum(ConnectionName
[i
]))
156 exit ("Bad connection name, only alpha numeric characters is allowed (char '%c' is not alphanum)");
161 void loadConfigFile ()
163 FILE *fp
= nlfopen ("client.cfg", "rt");
173 ConfigFile
.load ("client.cfg");
175 // set internet simulation values
176 CUdpSimSock::setSimValues (ConfigFile
);
178 ServerAddr
= ConfigFile
.getVar("ServerAddress").asString();
180 ConnectionName
= ConfigFile
.getVar("ConnectionName").asString();
182 if (ConnectionName
.empty())
184 InfoLog
->displayRawNL ("Please, enter a connection name");
185 InfoLog
->displayRawNL ("(only alphanumeric character limited to 30 character, no space)");
186 InfoLog
->displayRawNL ("For example enter your name and/or your location (ie: \"AceHome\"),");
187 InfoLog
->displayRawNL ("It'll be use to find your stat file easier:");
189 if (fgets (cn
, 127, stdin
) == NULL
)
191 exit ("Error during the keyboard scanning");
194 checkConnectionName ();
195 ConfigFile
.getVar ("ConnectionName").setAsString(ConnectionName
);
200 checkConnectionName ();
209 void cbInfo (CMessage
&msgin
, TSockId from
, CCallbackNetBase
&netbase
)
213 InfoLog
->displayRawNL ("%s", line
.c_str());
216 string token
= "MeanPongTime ";
217 string::size_type pos
=line
.find (token
);
218 string::size_type pos2
=line
.find (" ", pos
+token
.size());
220 NLMISC::fromString(line
.substr (pos
+token
.size(), pos2
-pos
-token
.size()), val
);
221 LagGraph
.addOneValue (val
);
225 void cbInit (CMessage
&msgin
, TSockId from
, CCallbackNetBase
&netbase
)
227 msgin
.serial (Session
);
229 // create the UDP connection
230 nlassert (UdpSock
== NULL
);
231 UdpSock
= new CUdpSimSock( false );
234 UdpSock
->connect( CInetAddress (ServerAddr
, UDPPort
) );
236 catch (const Exception
&e
)
238 InfoLog
->displayRawNL ("Cannot connect to remote UDP host '%s': %s", ServerAddr
.c_str(), e
.what() );
243 void cbStart (CMessage
&msgin
, TSockId from
, CCallbackNetBase
&netbase
)
245 InfoLog
->displayRawNL ("Bench is starting..");
250 void cbDisconnect (TSockId from
, void *arg
)
252 exit ("Lost the server connection. You should not have the last client version\nGet it here: http://www.nevrax.org/download/bench.zip");
255 TCallbackItem CallbackArray
[] =
259 { "START", cbStart
},
267 int main( int argc
, char **argv
)
270 DebugLog
->addNegativeFilter(" ");
272 InfoLog
->displayRawNL ("\nNevrax UDP benchmark client\n\nPress <CTRL-C> to exit");
274 CPath::addSearchPath(UDP_DIR
);
278 CCallbackClient
*cc
= new CCallbackClient
;
280 cc
->addCallbackArray (CallbackArray
, sizeof(CallbackArray
)/sizeof(CallbackArray
[0]));
281 cc
->setDisconnectionCallback (cbDisconnect
, NULL
);
285 InfoLog
->displayRawNL ("Try to connect to %s:%d", ServerAddr
.c_str(), TCPPort
);
286 cc
->connect(CInetAddress (ServerAddr
, TCPPort
));
288 CMessage
msgout ("INIT");
289 msgout
.serial (ConnectionName
);
290 msgout
.serial (Version
);
293 InfoLog
->displayRawNL ("Waiting the server answer...");
295 catch(const Exception
&e
)
297 InfoLog
->displayRawNL ("Can't connect to %s:%d (%s)\n", ServerAddr
.c_str(), TCPPort
, e
.what());
301 uint8
*packet
= new uint8
[MaxUDPPacketSize
];
306 UDriver
*Driver
= UDriver::createDriver();
307 Driver
->setDisplay(UDriver::CMode(800, 600, 32, true));
308 UScene
*Scene
= Driver
->createScene(false);
309 UCamera Camera
= Scene
->getCam();
310 Camera
.setTransformMode(UTransform::DirectMatrix
);
311 UTextContext
*TextContext
= Driver
->createTextContext(CPath::lookup("n019003l.pfb"));
312 TextContext
->setFontSize(18);
314 Camera
.setPerspective(80*(float)Pi
/180, 1.33f
, 0.15f
, 1000);
316 CEvent3dMouseListener MouseListener
;
317 MouseListener
.addToServer(Driver
->EventServer
);
318 MouseListener
.setFrustrum(Camera
.getFrustum());
319 MouseListener
.setHotSpot(CVector(0,0,0));
321 initMat
.setPos(CVector(0,-5,0));
322 MouseListener
.setMatrix(initMat
);
328 while (cc
->connected ())
333 Camera
.setMatrix(MouseListener
.getViewMatrix());
335 Driver
->EventServer
.pump();
336 if(Driver
->AsyncListener
.isKeyPushed(KeyESCAPE
))
339 Driver
->clearBuffers(CRGBA(255,255,255,0));
343 CGraph::render (*Driver
, *TextContext
);
345 Driver
->swapBuffers();
347 FpsGraph
.addValue (1);
352 CConfigFile::checkConfigFiles ();
354 // update TCP connection
357 // update UDP connection
362 // init the UDP connection
364 msgout
.serial (Mode
);
365 msgout
.serial (Session
);
366 uint32 size
= msgout
.length();
368 UploadGraph
.addValue ((float)size
);
370 UdpSock
->send (msgout
.buffer(), size
);
371 nldebug ("Sent init udp connection");
375 while (UdpSock
->dataAvailable())
377 psize
= MaxUDPPacketSize
;
378 UdpSock
->receive (packet
, psize
);
380 DownloadGraph
.addValue ((float)psize
);
382 CMemStream
msgin( true );
383 memcpy (msgin
.bufferToFill (psize
), packet
, psize
);
394 // I received a ping, send a pong
397 msgout
.serial (Mode
);
402 while (msgout
.length() < 200)
403 msgout
.serial (dummy
);
405 uint32 size
= msgout
.length();
406 nlassert (size
== 200);
409 UploadGraph
.addValue ((float)size
);
411 UdpSock
->send (msgout
.buffer(), size
);