aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
diff options
context:
space:
mode:
authorRobert Adams2015-09-08 04:54:16 -0700
committerRobert Adams2015-09-08 04:54:16 -0700
commite5367d822be9b05e74c859afe2d2956a3e95aa33 (patch)
treee904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
parentadd lost admin_reset_land method (diff)
parentDeleted access control spec from [LoginService] section of standalone config.... (diff)
downloadopensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip
opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz
opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2
opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules. AVN physics hasn't been moved to new location. Does not compile yet. Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs')
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs1203
1 files changed, 1203 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
new file mode 100644
index 0000000..bd5289f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs
@@ -0,0 +1,1203 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net; // to be used for REST-->Grid shortly
33using System.Reflection;
34using System.Text;
35using System.Threading;
36using log4net;
37using Nini.Config;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45using Mono.Data.SqliteClient;
46using Mono.Addins;
47
48using Caps = OpenSim.Framework.Capabilities.Caps;
49
50using OSD = OpenMetaverse.StructuredData.OSD;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53namespace OpenSim.Region.UserStatistics
54{
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebStatsModule")]
56 public class WebStatsModule : ISharedRegionModule
57 {
58 private static readonly ILog m_log =
59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60
61 private static SqliteConnection dbConn;
62
63 /// <summary>
64 /// User statistics sessions keyed by agent ID
65 /// </summary>
66 private Dictionary<UUID, UserSession> m_sessions = new Dictionary<UUID, UserSession>();
67
68 private List<Scene> m_scenes = new List<Scene>();
69 private Dictionary<string, IStatsController> reports = new Dictionary<string, IStatsController>();
70 private Dictionary<UUID, USimStatsData> m_simstatsCounters = new Dictionary<UUID, USimStatsData>();
71 private const int updateStatsMod = 6;
72 private int updateLogMod = 1;
73 private volatile int updateLogCounter = 0;
74 private volatile int concurrencyCounter = 0;
75 private bool enabled = false;
76 private string m_loglines = String.Empty;
77 private volatile int lastHit = 12000;
78
79 #region ISharedRegionModule
80
81 public virtual void Initialise(IConfigSource config)
82 {
83 IConfig cnfg = config.Configs["WebStats"];
84
85 if (cnfg != null)
86 enabled = cnfg.GetBoolean("enabled", false);
87 }
88
89 public virtual void PostInitialise()
90 {
91 if (!enabled)
92 return;
93
94 if (Util.IsWindows())
95 Util.LoadArchSpecificWindowsDll("sqlite3.dll");
96
97 //IConfig startupConfig = config.Configs["Startup"];
98
99 dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3");
100 dbConn.Open();
101 CreateTables(dbConn);
102
103 Prototype_distributor protodep = new Prototype_distributor();
104 Updater_distributor updatedep = new Updater_distributor();
105 ActiveConnectionsAJAX ajConnections = new ActiveConnectionsAJAX();
106 SimStatsAJAX ajSimStats = new SimStatsAJAX();
107 LogLinesAJAX ajLogLines = new LogLinesAJAX();
108 Default_Report defaultReport = new Default_Report();
109 Clients_report clientReport = new Clients_report();
110 Sessions_Report sessionsReport = new Sessions_Report();
111
112 reports.Add("prototype.js", protodep);
113 reports.Add("updater.js", updatedep);
114 reports.Add("activeconnectionsajax.html", ajConnections);
115 reports.Add("simstatsajax.html", ajSimStats);
116 reports.Add("activelogajax.html", ajLogLines);
117 reports.Add("default.report", defaultReport);
118 reports.Add("clients.report", clientReport);
119 reports.Add("sessions.report", sessionsReport);
120
121 reports.Add("sim.css", new Prototype_distributor("sim.css"));
122 reports.Add("sim.html", new Prototype_distributor("sim.html"));
123 reports.Add("jquery.js", new Prototype_distributor("jquery.js"));
124
125 ////
126 // Add Your own Reports here (Do Not Modify Lines here Devs!)
127 ////
128
129 ////
130 // End Own reports section
131 ////
132
133 MainServer.Instance.AddHTTPHandler("/SStats/", HandleStatsRequest);
134 MainServer.Instance.AddHTTPHandler("/CAPS/VS/", HandleUnknownCAPSRequest);
135 }
136
137 public virtual void AddRegion(Scene scene)
138 {
139 if (!enabled)
140 return;
141
142 lock (m_scenes)
143 {
144 m_scenes.Add(scene);
145 updateLogMod = m_scenes.Count * 2;
146
147 m_simstatsCounters.Add(scene.RegionInfo.RegionID, new USimStatsData(scene.RegionInfo.RegionID));
148
149 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
150 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
151 scene.EventManager.OnClientClosed += OnClientClosed;
152 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
153 scene.StatsReporter.OnSendStatsResult += ReceiveClassicSimStatsPacket;
154 }
155 }
156
157 public void RegionLoaded(Scene scene)
158 {
159 }
160
161 public void RemoveRegion(Scene scene)
162 {
163 if (!enabled)
164 return;
165
166 lock (m_scenes)
167 {
168 m_scenes.Remove(scene);
169 updateLogMod = m_scenes.Count * 2;
170 m_simstatsCounters.Remove(scene.RegionInfo.RegionID);
171 }
172 }
173
174 public virtual void Close()
175 {
176 if (!enabled)
177 return;
178
179 dbConn.Close();
180 dbConn.Dispose();
181 m_sessions.Clear();
182 m_scenes.Clear();
183 reports.Clear();
184 m_simstatsCounters.Clear();
185 }
186
187 public virtual string Name
188 {
189 get { return "ViewerStatsModule"; }
190 }
191
192 public Type ReplaceableInterface
193 {
194 get { return null; }
195 }
196
197 #endregion
198
199 private void ReceiveClassicSimStatsPacket(SimStats stats)
200 {
201 if (!enabled)
202 return;
203
204 try
205 {
206 // Ignore the update if there's a report running right now
207 // ignore the update if there hasn't been a hit in 30 seconds.
208 if (concurrencyCounter > 0 || System.Environment.TickCount - lastHit > 30000)
209 return;
210
211 // We will conduct this under lock so that fields such as updateLogCounter do not potentially get
212 // confused if a scene is removed.
213 // XXX: Possibly the scope of this lock could be reduced though it's not critical.
214 lock (m_scenes)
215 {
216 if (updateLogMod != 0 && updateLogCounter++ % updateLogMod == 0)
217 {
218 m_loglines = readLogLines(10);
219
220 if (updateLogCounter > 10000)
221 updateLogCounter = 1;
222 }
223
224 USimStatsData ss = m_simstatsCounters[stats.RegionUUID];
225
226 if ((++ss.StatsCounter % updateStatsMod) == 0)
227 {
228 ss.ConsumeSimStats(stats);
229 }
230 }
231 }
232 catch (KeyNotFoundException)
233 {
234 }
235 }
236
237 private Hashtable HandleUnknownCAPSRequest(Hashtable request)
238 {
239 //string regpath = request["uri"].ToString();
240 int response_code = 200;
241 string contenttype = "text/html";
242 UpdateUserStats(ParseViewerStats(request["body"].ToString(), UUID.Zero), dbConn);
243 Hashtable responsedata = new Hashtable();
244
245 responsedata["int_response_code"] = response_code;
246 responsedata["content_type"] = contenttype;
247 responsedata["keepalive"] = false;
248 responsedata["str_response_string"] = string.Empty;
249 return responsedata;
250 }
251
252 private Hashtable HandleStatsRequest(Hashtable request)
253 {
254 lastHit = System.Environment.TickCount;
255 Hashtable responsedata = new Hashtable();
256 string regpath = request["uri"].ToString();
257 int response_code = 404;
258 string contenttype = "text/html";
259 bool jsonFormatOutput = false;
260
261 string strOut = string.Empty;
262
263 // The request patch should be "/SStats/reportName" where 'reportName'
264 // is one of the names added to the 'reports' hashmap.
265 regpath = regpath.Remove(0, 8);
266 if (regpath.Length == 0) regpath = "default.report";
267 if (reports.ContainsKey(regpath))
268 {
269 IStatsController rep = reports[regpath];
270 Hashtable repParams = new Hashtable();
271
272 if (request.ContainsKey("json"))
273 jsonFormatOutput = true;
274
275 if (request.ContainsKey("requestvars"))
276 repParams["RequestVars"] = request["requestvars"];
277 else
278 repParams["RequestVars"] = new Hashtable();
279
280 if (request.ContainsKey("querystringkeys"))
281 repParams["QueryStringKeys"] = request["querystringkeys"];
282 else
283 repParams["QueryStringKeys"] = new string[0];
284
285
286 repParams["DatabaseConnection"] = dbConn;
287 repParams["Scenes"] = m_scenes;
288 repParams["SimStats"] = m_simstatsCounters;
289 repParams["LogLines"] = m_loglines;
290 repParams["Reports"] = reports;
291
292 concurrencyCounter++;
293
294 if (jsonFormatOutput)
295 {
296 strOut = rep.RenderJson(rep.ProcessModel(repParams));
297 contenttype = "text/json";
298 }
299 else
300 {
301 strOut = rep.RenderView(rep.ProcessModel(repParams));
302 }
303
304 if (regpath.EndsWith("js"))
305 {
306 contenttype = "text/javascript";
307 }
308
309 if (regpath.EndsWith("css"))
310 {
311 contenttype = "text/css";
312 }
313
314 concurrencyCounter--;
315
316 response_code = 200;
317 }
318 else
319 {
320 strOut = MainServer.Instance.GetHTTP404("");
321 }
322
323 responsedata["int_response_code"] = response_code;
324 responsedata["content_type"] = contenttype;
325 responsedata["keepalive"] = false;
326 responsedata["str_response_string"] = strOut;
327
328 return responsedata;
329 }
330
331 private void CreateTables(SqliteConnection db)
332 {
333 using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db))
334 {
335 createcmd.ExecuteNonQuery();
336 }
337 }
338
339 private void OnRegisterCaps(UUID agentID, Caps caps)
340 {
341// m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps);
342
343 string capsPath = "/CAPS/VS/" + UUID.Random();
344 caps.RegisterHandler(
345 "ViewerStats",
346 new RestStreamHandler(
347 "POST",
348 capsPath,
349 (request, path, param, httpRequest, httpResponse)
350 => ViewerStatsReport(request, path, param, agentID, caps),
351 "ViewerStats",
352 agentID.ToString()));
353 }
354
355 private void OnDeRegisterCaps(UUID agentID, Caps caps)
356 {
357 }
358
359 protected virtual void AddEventHandlers()
360 {
361 lock (m_scenes)
362 {
363 updateLogMod = m_scenes.Count * 2;
364 foreach (Scene scene in m_scenes)
365 {
366 scene.EventManager.OnRegisterCaps += OnRegisterCaps;
367 scene.EventManager.OnDeregisterCaps += OnDeRegisterCaps;
368 scene.EventManager.OnClientClosed += OnClientClosed;
369 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
370 }
371 }
372 }
373
374 private void OnMakeRootAgent(ScenePresence agent)
375 {
376// m_log.DebugFormat(
377// "[WEB STATS MODULE]: Looking for session {0} for {1} in {2}",
378// agent.ControllingClient.SessionId, agent.Name, agent.Scene.Name);
379
380 lock (m_sessions)
381 {
382 UserSession uid;
383
384 if (!m_sessions.ContainsKey(agent.UUID))
385 {
386 UserSessionData usd = UserSessionUtil.newUserSessionData();
387 uid = new UserSession();
388 uid.name_f = agent.Firstname;
389 uid.name_l = agent.Lastname;
390 uid.session_data = usd;
391
392 m_sessions.Add(agent.UUID, uid);
393 }
394 else
395 {
396 uid = m_sessions[agent.UUID];
397 }
398
399 uid.region_id = agent.Scene.RegionInfo.RegionID;
400 uid.session_id = agent.ControllingClient.SessionId;
401 }
402 }
403
404 private void OnClientClosed(UUID agentID, Scene scene)
405 {
406 lock (m_sessions)
407 {
408 if (m_sessions.ContainsKey(agentID) && m_sessions[agentID].region_id == scene.RegionInfo.RegionID)
409 {
410 m_sessions.Remove(agentID);
411 }
412 }
413 }
414
415 private string readLogLines(int amount)
416 {
417 Encoding encoding = Encoding.ASCII;
418 int sizeOfChar = encoding.GetByteCount("\n");
419 byte[] buffer = encoding.GetBytes("\n");
420 string logfile = Util.logFile();
421 FileStream fs = new FileStream(logfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
422 Int64 tokenCount = 0;
423 Int64 endPosition = fs.Length / sizeOfChar;
424
425 for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar)
426 {
427 fs.Seek(-position, SeekOrigin.End);
428 fs.Read(buffer, 0, buffer.Length);
429
430 if (encoding.GetString(buffer) == "\n")
431 {
432 tokenCount++;
433 if (tokenCount == amount)
434 {
435 byte[] returnBuffer = new byte[fs.Length - fs.Position];
436 fs.Read(returnBuffer, 0, returnBuffer.Length);
437 fs.Close();
438 fs.Dispose();
439 return encoding.GetString(returnBuffer);
440 }
441 }
442 }
443
444 // handle case where number of tokens in file is less than numberOfTokens
445 fs.Seek(0, SeekOrigin.Begin);
446 buffer = new byte[fs.Length];
447 fs.Read(buffer, 0, buffer.Length);
448 fs.Close();
449 fs.Dispose();
450 return encoding.GetString(buffer);
451 }
452
453 /// <summary>
454 /// Callback for a viewerstats cap
455 /// </summary>
456 /// <param name="request"></param>
457 /// <param name="path"></param>
458 /// <param name="param"></param>
459 /// <param name="agentID"></param>
460 /// <param name="caps"></param>
461 /// <returns></returns>
462 private string ViewerStatsReport(string request, string path, string param,
463 UUID agentID, Caps caps)
464 {
465// m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID);
466
467 UpdateUserStats(ParseViewerStats(request, agentID), dbConn);
468
469 return String.Empty;
470 }
471
472 private UserSession ParseViewerStats(string request, UUID agentID)
473 {
474 UserSession uid = new UserSession();
475 UserSessionData usd;
476 OSD message = OSDParser.DeserializeLLSDXml(request);
477 OSDMap mmap;
478
479 lock (m_sessions)
480 {
481 if (agentID != UUID.Zero)
482 {
483 if (!m_sessions.ContainsKey(agentID))
484 {
485 m_log.WarnFormat("[WEB STATS MODULE]: no session for stat disclosure for agent {0}", agentID);
486 return new UserSession();
487 }
488
489 uid = m_sessions[agentID];
490
491// m_log.DebugFormat("[WEB STATS MODULE]: Got session {0} for {1}", uid.session_id, agentID);
492 }
493 else
494 {
495 // parse through the beginning to locate the session
496 if (message.Type != OSDType.Map)
497 return new UserSession();
498
499 mmap = (OSDMap)message;
500 {
501 UUID sessionID = mmap["session_id"].AsUUID();
502
503 if (sessionID == UUID.Zero)
504 return new UserSession();
505
506
507 // search through each session looking for the owner
508 foreach (UUID usersessionid in m_sessions.Keys)
509 {
510 // got it!
511 if (m_sessions[usersessionid].session_id == sessionID)
512 {
513 agentID = usersessionid;
514 uid = m_sessions[usersessionid];
515 break;
516 }
517
518 }
519
520 // can't find a session
521 if (agentID == UUID.Zero)
522 {
523 return new UserSession();
524 }
525 }
526 }
527 }
528
529 usd = uid.session_data;
530
531 if (message.Type != OSDType.Map)
532 return new UserSession();
533
534 mmap = (OSDMap)message;
535 {
536 if (mmap["agent"].Type != OSDType.Map)
537 return new UserSession();
538 OSDMap agent_map = (OSDMap)mmap["agent"];
539 usd.agent_id = agentID;
540 usd.name_f = uid.name_f;
541 usd.name_l = uid.name_l;
542 usd.region_id = uid.region_id;
543 usd.a_language = agent_map["language"].AsString();
544 usd.mem_use = (float)agent_map["mem_use"].AsReal();
545 usd.meters_traveled = (float)agent_map["meters_traveled"].AsReal();
546 usd.regions_visited = agent_map["regions_visited"].AsInteger();
547 usd.run_time = (float)agent_map["run_time"].AsReal();
548 usd.start_time = (float)agent_map["start_time"].AsReal();
549 usd.client_version = agent_map["version"].AsString();
550
551 UserSessionUtil.UpdateMultiItems(ref usd, agent_map["agents_in_view"].AsInteger(),
552 (float)agent_map["ping"].AsReal(),
553 (float)agent_map["sim_fps"].AsReal(),
554 (float)agent_map["fps"].AsReal());
555
556 if (mmap["downloads"].Type != OSDType.Map)
557 return new UserSession();
558 OSDMap downloads_map = (OSDMap)mmap["downloads"];
559 usd.d_object_kb = (float)downloads_map["object_kbytes"].AsReal();
560 usd.d_texture_kb = (float)downloads_map["texture_kbytes"].AsReal();
561 usd.d_world_kb = (float)downloads_map["workd_kbytes"].AsReal();
562
563// m_log.DebugFormat("[WEB STATS MODULE]: mmap[\"session_id\"] = [{0}]", mmap["session_id"].AsUUID());
564
565 usd.session_id = mmap["session_id"].AsUUID();
566
567 if (mmap["system"].Type != OSDType.Map)
568 return new UserSession();
569 OSDMap system_map = (OSDMap)mmap["system"];
570
571 usd.s_cpu = system_map["cpu"].AsString();
572 usd.s_gpu = system_map["gpu"].AsString();
573 usd.s_os = system_map["os"].AsString();
574 usd.s_ram = system_map["ram"].AsInteger();
575
576 if (mmap["stats"].Type != OSDType.Map)
577 return new UserSession();
578
579 OSDMap stats_map = (OSDMap)mmap["stats"];
580 {
581
582 if (stats_map["failures"].Type != OSDType.Map)
583 return new UserSession();
584 OSDMap stats_failures = (OSDMap)stats_map["failures"];
585 usd.f_dropped = stats_failures["dropped"].AsInteger();
586 usd.f_failed_resends = stats_failures["failed_resends"].AsInteger();
587 usd.f_invalid = stats_failures["invalid"].AsInteger();
588 usd.f_resent = stats_failures["resent"].AsInteger();
589 usd.f_send_packet = stats_failures["send_packet"].AsInteger();
590
591 if (stats_map["net"].Type != OSDType.Map)
592 return new UserSession();
593 OSDMap stats_net = (OSDMap)stats_map["net"];
594 {
595 if (stats_net["in"].Type != OSDType.Map)
596 return new UserSession();
597
598 OSDMap net_in = (OSDMap)stats_net["in"];
599 usd.n_in_kb = (float)net_in["kbytes"].AsReal();
600 usd.n_in_pk = net_in["packets"].AsInteger();
601
602 if (stats_net["out"].Type != OSDType.Map)
603 return new UserSession();
604 OSDMap net_out = (OSDMap)stats_net["out"];
605
606 usd.n_out_kb = (float)net_out["kbytes"].AsReal();
607 usd.n_out_pk = net_out["packets"].AsInteger();
608 }
609 }
610 }
611
612 uid.session_data = usd;
613 m_sessions[agentID] = uid;
614
615// m_log.DebugFormat(
616// "[WEB STATS MODULE]: Parse data for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
617
618 return uid;
619 }
620
621 private void UpdateUserStats(UserSession uid, SqliteConnection db)
622 {
623// m_log.DebugFormat(
624// "[WEB STATS MODULE]: Updating user stats for {0} {1}, session {2}", uid.name_f, uid.name_l, uid.session_id);
625
626 if (uid.session_id == UUID.Zero)
627 return;
628
629 lock (db)
630 {
631 using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db))
632 {
633 updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString()));
634 updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString()));
635 updatecmd.Parameters.Add(new SqliteParameter(":region_id", uid.session_data.region_id.ToString()));
636 updatecmd.Parameters.Add(new SqliteParameter(":last_updated", (int) uid.session_data.last_updated));
637 updatecmd.Parameters.Add(new SqliteParameter(":remote_ip", uid.session_data.remote_ip));
638 updatecmd.Parameters.Add(new SqliteParameter(":name_f", uid.session_data.name_f));
639 updatecmd.Parameters.Add(new SqliteParameter(":name_l", uid.session_data.name_l));
640 updatecmd.Parameters.Add(new SqliteParameter(":avg_agents_in_view", uid.session_data.avg_agents_in_view));
641 updatecmd.Parameters.Add(new SqliteParameter(":min_agents_in_view",
642 (int) uid.session_data.min_agents_in_view));
643 updatecmd.Parameters.Add(new SqliteParameter(":max_agents_in_view",
644 (int) uid.session_data.max_agents_in_view));
645 updatecmd.Parameters.Add(new SqliteParameter(":mode_agents_in_view",
646 (int) uid.session_data.mode_agents_in_view));
647 updatecmd.Parameters.Add(new SqliteParameter(":avg_fps", uid.session_data.avg_fps));
648 updatecmd.Parameters.Add(new SqliteParameter(":min_fps", uid.session_data.min_fps));
649 updatecmd.Parameters.Add(new SqliteParameter(":max_fps", uid.session_data.max_fps));
650 updatecmd.Parameters.Add(new SqliteParameter(":mode_fps", uid.session_data.mode_fps));
651 updatecmd.Parameters.Add(new SqliteParameter(":a_language", uid.session_data.a_language));
652 updatecmd.Parameters.Add(new SqliteParameter(":mem_use", uid.session_data.mem_use));
653 updatecmd.Parameters.Add(new SqliteParameter(":meters_traveled", uid.session_data.meters_traveled));
654 updatecmd.Parameters.Add(new SqliteParameter(":avg_ping", uid.session_data.avg_ping));
655 updatecmd.Parameters.Add(new SqliteParameter(":min_ping", uid.session_data.min_ping));
656 updatecmd.Parameters.Add(new SqliteParameter(":max_ping", uid.session_data.max_ping));
657 updatecmd.Parameters.Add(new SqliteParameter(":mode_ping", uid.session_data.mode_ping));
658 updatecmd.Parameters.Add(new SqliteParameter(":regions_visited", uid.session_data.regions_visited));
659 updatecmd.Parameters.Add(new SqliteParameter(":run_time", uid.session_data.run_time));
660 updatecmd.Parameters.Add(new SqliteParameter(":avg_sim_fps", uid.session_data.avg_sim_fps));
661 updatecmd.Parameters.Add(new SqliteParameter(":min_sim_fps", uid.session_data.min_sim_fps));
662 updatecmd.Parameters.Add(new SqliteParameter(":max_sim_fps", uid.session_data.max_sim_fps));
663 updatecmd.Parameters.Add(new SqliteParameter(":mode_sim_fps", uid.session_data.mode_sim_fps));
664 updatecmd.Parameters.Add(new SqliteParameter(":start_time", uid.session_data.start_time));
665 updatecmd.Parameters.Add(new SqliteParameter(":client_version", uid.session_data.client_version));
666 updatecmd.Parameters.Add(new SqliteParameter(":s_cpu", uid.session_data.s_cpu));
667 updatecmd.Parameters.Add(new SqliteParameter(":s_gpu", uid.session_data.s_gpu));
668 updatecmd.Parameters.Add(new SqliteParameter(":s_os", uid.session_data.s_os));
669 updatecmd.Parameters.Add(new SqliteParameter(":s_ram", uid.session_data.s_ram));
670 updatecmd.Parameters.Add(new SqliteParameter(":d_object_kb", uid.session_data.d_object_kb));
671 updatecmd.Parameters.Add(new SqliteParameter(":d_texture_kb", uid.session_data.d_texture_kb));
672 updatecmd.Parameters.Add(new SqliteParameter(":d_world_kb", uid.session_data.d_world_kb));
673 updatecmd.Parameters.Add(new SqliteParameter(":n_in_kb", uid.session_data.n_in_kb));
674 updatecmd.Parameters.Add(new SqliteParameter(":n_in_pk", uid.session_data.n_in_pk));
675 updatecmd.Parameters.Add(new SqliteParameter(":n_out_kb", uid.session_data.n_out_kb));
676 updatecmd.Parameters.Add(new SqliteParameter(":n_out_pk", uid.session_data.n_out_pk));
677 updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped));
678 updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends));
679 updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid));
680 updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit));
681 updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent));
682 updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet));
683
684// StringBuilder parameters = new StringBuilder();
685// SqliteParameterCollection spc = updatecmd.Parameters;
686// foreach (SqliteParameter sp in spc)
687// parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value);
688//
689// m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters);
690
691// m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id);
692
693 updatecmd.ExecuteNonQuery();
694 }
695 }
696 }
697
698 #region SQL
699 private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data (
700 session_id VARCHAR(36) NOT NULL PRIMARY KEY,
701 agent_id VARCHAR(36) NOT NULL DEFAULT '',
702 region_id VARCHAR(36) NOT NULL DEFAULT '',
703 last_updated INT NOT NULL DEFAULT '0',
704 remote_ip VARCHAR(16) NOT NULL DEFAULT '',
705 name_f VARCHAR(50) NOT NULL DEFAULT '',
706 name_l VARCHAR(50) NOT NULL DEFAULT '',
707 avg_agents_in_view FLOAT NOT NULL DEFAULT '0',
708 min_agents_in_view INT NOT NULL DEFAULT '0',
709 max_agents_in_view INT NOT NULL DEFAULT '0',
710 mode_agents_in_view INT NOT NULL DEFAULT '0',
711 avg_fps FLOAT NOT NULL DEFAULT '0',
712 min_fps FLOAT NOT NULL DEFAULT '0',
713 max_fps FLOAT NOT NULL DEFAULT '0',
714 mode_fps FLOAT NOT NULL DEFAULT '0',
715 a_language VARCHAR(25) NOT NULL DEFAULT '',
716 mem_use FLOAT NOT NULL DEFAULT '0',
717 meters_traveled FLOAT NOT NULL DEFAULT '0',
718 avg_ping FLOAT NOT NULL DEFAULT '0',
719 min_ping FLOAT NOT NULL DEFAULT '0',
720 max_ping FLOAT NOT NULL DEFAULT '0',
721 mode_ping FLOAT NOT NULL DEFAULT '0',
722 regions_visited INT NOT NULL DEFAULT '0',
723 run_time FLOAT NOT NULL DEFAULT '0',
724 avg_sim_fps FLOAT NOT NULL DEFAULT '0',
725 min_sim_fps FLOAT NOT NULL DEFAULT '0',
726 max_sim_fps FLOAT NOT NULL DEFAULT '0',
727 mode_sim_fps FLOAT NOT NULL DEFAULT '0',
728 start_time FLOAT NOT NULL DEFAULT '0',
729 client_version VARCHAR(255) NOT NULL DEFAULT '',
730 s_cpu VARCHAR(255) NOT NULL DEFAULT '',
731 s_gpu VARCHAR(255) NOT NULL DEFAULT '',
732 s_os VARCHAR(2255) NOT NULL DEFAULT '',
733 s_ram INT NOT NULL DEFAULT '0',
734 d_object_kb FLOAT NOT NULL DEFAULT '0',
735 d_texture_kb FLOAT NOT NULL DEFAULT '0',
736 d_world_kb FLOAT NOT NULL DEFAULT '0',
737 n_in_kb FLOAT NOT NULL DEFAULT '0',
738 n_in_pk INT NOT NULL DEFAULT '0',
739 n_out_kb FLOAT NOT NULL DEFAULT '0',
740 n_out_pk INT NOT NULL DEFAULT '0',
741 f_dropped INT NOT NULL DEFAULT '0',
742 f_failed_resends INT NOT NULL DEFAULT '0',
743 f_invalid INT NOT NULL DEFAULT '0',
744 f_off_circuit INT NOT NULL DEFAULT '0',
745 f_resent INT NOT NULL DEFAULT '0',
746 f_send_packet INT NOT NULL DEFAULT '0'
747 );";
748
749 private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data (
750session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view,
751mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping,
752regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram,
753d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit,
754f_resent, f_send_packet
755)
756VALUES
757(
758:session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view,
759:mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping,
760:regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram,
761:d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit,
762:f_resent, :f_send_packet
763)
764";
765
766 #endregion
767
768 }
769
770 public static class UserSessionUtil
771 {
772 public static UserSessionData newUserSessionData()
773 {
774 UserSessionData obj = ZeroSession(new UserSessionData());
775 return obj;
776 }
777
778 public static void UpdateMultiItems(ref UserSessionData s, int agents_in_view, float ping, float sim_fps, float fps)
779 {
780 // don't insert zero values here or it'll skew the statistics.
781 if (agents_in_view == 0 && fps == 0 && sim_fps == 0 && ping == 0)
782 return;
783 s._agents_in_view.Add(agents_in_view);
784 s._fps.Add(fps);
785 s._sim_fps.Add(sim_fps);
786 s._ping.Add(ping);
787
788 int[] __agents_in_view = s._agents_in_view.ToArray();
789
790 s.avg_agents_in_view = ArrayAvg_i(__agents_in_view);
791 s.min_agents_in_view = ArrayMin_i(__agents_in_view);
792 s.max_agents_in_view = ArrayMax_i(__agents_in_view);
793 s.mode_agents_in_view = ArrayMode_i(__agents_in_view);
794
795 float[] __fps = s._fps.ToArray();
796 s.avg_fps = ArrayAvg_f(__fps);
797 s.min_fps = ArrayMin_f(__fps);
798 s.max_fps = ArrayMax_f(__fps);
799 s.mode_fps = ArrayMode_f(__fps);
800
801 float[] __sim_fps = s._sim_fps.ToArray();
802 s.avg_sim_fps = ArrayAvg_f(__sim_fps);
803 s.min_sim_fps = ArrayMin_f(__sim_fps);
804 s.max_sim_fps = ArrayMax_f(__sim_fps);
805 s.mode_sim_fps = ArrayMode_f(__sim_fps);
806
807 float[] __ping = s._ping.ToArray();
808 s.avg_ping = ArrayAvg_f(__ping);
809 s.min_ping = ArrayMin_f(__ping);
810 s.max_ping = ArrayMax_f(__ping);
811 s.mode_ping = ArrayMode_f(__ping);
812 }
813
814 #region Statistics
815
816 public static int ArrayMin_i(int[] arr)
817 {
818 int cnt = arr.Length;
819 if (cnt == 0)
820 return 0;
821
822 Array.Sort(arr);
823 return arr[0];
824 }
825
826 public static int ArrayMax_i(int[] arr)
827 {
828 int cnt = arr.Length;
829 if (cnt == 0)
830 return 0;
831
832 Array.Sort(arr);
833 return arr[cnt-1];
834 }
835
836 public static float ArrayMin_f(float[] arr)
837 {
838 int cnt = arr.Length;
839 if (cnt == 0)
840 return 0;
841
842 Array.Sort(arr);
843 return arr[0];
844 }
845
846 public static float ArrayMax_f(float[] arr)
847 {
848 int cnt = arr.Length;
849 if (cnt == 0)
850 return 0;
851
852 Array.Sort(arr);
853 return arr[cnt - 1];
854 }
855
856 public static float ArrayAvg_i(int[] arr)
857 {
858 int cnt = arr.Length;
859
860 if (cnt == 0)
861 return 0;
862
863 float result = arr[0];
864
865 for (int i = 1; i < cnt; i++)
866 result += arr[i];
867
868 return result / cnt;
869 }
870
871 public static float ArrayAvg_f(float[] arr)
872 {
873 int cnt = arr.Length;
874
875 if (cnt == 0)
876 return 0;
877
878 float result = arr[0];
879
880 for (int i = 1; i < cnt; i++)
881 result += arr[i];
882
883 return result / cnt;
884 }
885
886 public static float ArrayMode_f(float[] arr)
887 {
888 List<float> mode = new List<float>();
889
890 float[] srtArr = new float[arr.Length];
891 float[,] freq = new float[arr.Length, 2];
892 Array.Copy(arr, srtArr, arr.Length);
893 Array.Sort(srtArr);
894
895 float tmp = srtArr[0];
896 int index = 0;
897 int i = 0;
898 while (i < srtArr.Length)
899 {
900 freq[index, 0] = tmp;
901
902 while (tmp == srtArr[i])
903 {
904 freq[index, 1]++;
905 i++;
906
907 if (i > srtArr.Length - 1)
908 break;
909 }
910
911 if (i < srtArr.Length)
912 {
913 tmp = srtArr[i];
914 index++;
915 }
916
917 }
918
919 Array.Clear(srtArr, 0, srtArr.Length);
920
921 for (i = 0; i < srtArr.Length; i++)
922 srtArr[i] = freq[i, 1];
923
924 Array.Sort(srtArr);
925
926 if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1)
927 return 0;
928
929 float freqtest = (float)freq.Length / freq.Rank;
930
931 for (i = 0; i < freqtest; i++)
932 {
933 if (freq[i, 1] == srtArr[index])
934 mode.Add(freq[i, 0]);
935
936 }
937
938 return mode.ToArray()[0];
939 }
940
941 public static int ArrayMode_i(int[] arr)
942 {
943 List<int> mode = new List<int>();
944
945 int[] srtArr = new int[arr.Length];
946 int[,] freq = new int[arr.Length, 2];
947 Array.Copy(arr, srtArr, arr.Length);
948 Array.Sort(srtArr);
949
950 int tmp = srtArr[0];
951 int index = 0;
952 int i = 0;
953 while (i < srtArr.Length)
954 {
955 freq[index, 0] = tmp;
956
957 while (tmp == srtArr[i])
958 {
959 freq[index, 1]++;
960 i++;
961
962 if (i > srtArr.Length - 1)
963 break;
964 }
965
966 if (i < srtArr.Length)
967 {
968 tmp = srtArr[i];
969 index++;
970 }
971
972 }
973
974 Array.Clear(srtArr, 0, srtArr.Length);
975
976 for (i = 0; i < srtArr.Length; i++)
977 srtArr[i] = freq[i, 1];
978
979 Array.Sort(srtArr);
980
981 if ((srtArr[srtArr.Length - 1]) == 0 || (srtArr[srtArr.Length - 1]) == 1)
982 return 0;
983
984 float freqtest = (float)freq.Length / freq.Rank;
985
986 for (i = 0; i < freqtest; i++)
987 {
988 if (freq[i, 1] == srtArr[index])
989 mode.Add(freq[i, 0]);
990
991 }
992
993 return mode.ToArray()[0];
994 }
995
996 #endregion
997
998 private static UserSessionData ZeroSession(UserSessionData s)
999 {
1000 s.session_id = UUID.Zero;
1001 s.agent_id = UUID.Zero;
1002 s.region_id = UUID.Zero;
1003 s.last_updated = Util.UnixTimeSinceEpoch();
1004 s.remote_ip = "";
1005 s.name_f = "";
1006 s.name_l = "";
1007 s.avg_agents_in_view = 0;
1008 s.min_agents_in_view = 0;
1009 s.max_agents_in_view = 0;
1010 s.mode_agents_in_view = 0;
1011 s.avg_fps = 0;
1012 s.min_fps = 0;
1013 s.max_fps = 0;
1014 s.mode_fps = 0;
1015 s.a_language = "";
1016 s.mem_use = 0;
1017 s.meters_traveled = 0;
1018 s.avg_ping = 0;
1019 s.min_ping = 0;
1020 s.max_ping = 0;
1021 s.mode_ping = 0;
1022 s.regions_visited = 0;
1023 s.run_time = 0;
1024 s.avg_sim_fps = 0;
1025 s.min_sim_fps = 0;
1026 s.max_sim_fps = 0;
1027 s.mode_sim_fps = 0;
1028 s.start_time = 0;
1029 s.client_version = "";
1030 s.s_cpu = "";
1031 s.s_gpu = "";
1032 s.s_os = "";
1033 s.s_ram = 0;
1034 s.d_object_kb = 0;
1035 s.d_texture_kb = 0;
1036 s.d_world_kb = 0;
1037 s.n_in_kb = 0;
1038 s.n_in_pk = 0;
1039 s.n_out_kb = 0;
1040 s.n_out_pk = 0;
1041 s.f_dropped = 0;
1042 s.f_failed_resends = 0;
1043 s.f_invalid = 0;
1044 s.f_off_circuit = 0;
1045 s.f_resent = 0;
1046 s.f_send_packet = 0;
1047 s._ping = new List<float>();
1048 s._fps = new List<float>();
1049 s._sim_fps = new List<float>();
1050 s._agents_in_view = new List<int>();
1051 return s;
1052 }
1053 }
1054 #region structs
1055
1056 public class UserSession
1057 {
1058 public UUID session_id;
1059 public UUID region_id;
1060 public string name_f;
1061 public string name_l;
1062 public UserSessionData session_data;
1063 }
1064
1065 public struct UserSessionData
1066 {
1067 public UUID session_id;
1068 public UUID agent_id;
1069 public UUID region_id;
1070 public float last_updated;
1071 public string remote_ip;
1072 public string name_f;
1073 public string name_l;
1074 public float avg_agents_in_view;
1075 public float min_agents_in_view;
1076 public float max_agents_in_view;
1077 public float mode_agents_in_view;
1078 public float avg_fps;
1079 public float min_fps;
1080 public float max_fps;
1081 public float mode_fps;
1082 public string a_language;
1083 public float mem_use;
1084 public float meters_traveled;
1085 public float avg_ping;
1086 public float min_ping;
1087 public float max_ping;
1088 public float mode_ping;
1089 public int regions_visited;
1090 public float run_time;
1091 public float avg_sim_fps;
1092 public float min_sim_fps;
1093 public float max_sim_fps;
1094 public float mode_sim_fps;
1095 public float start_time;
1096 public string client_version;
1097 public string s_cpu;
1098 public string s_gpu;
1099 public string s_os;
1100 public int s_ram;
1101 public float d_object_kb;
1102 public float d_texture_kb;
1103 public float d_world_kb;
1104 public float n_in_kb;
1105 public int n_in_pk;
1106 public float n_out_kb;
1107 public int n_out_pk;
1108 public int f_dropped;
1109 public int f_failed_resends;
1110 public int f_invalid;
1111 public int f_off_circuit;
1112 public int f_resent;
1113 public int f_send_packet;
1114 public List<float> _ping;
1115 public List<float> _fps;
1116 public List<float> _sim_fps;
1117 public List<int> _agents_in_view;
1118 }
1119
1120 #endregion
1121
1122 public class USimStatsData
1123 {
1124 private UUID m_regionID = UUID.Zero;
1125 private volatile int m_statcounter = 0;
1126 private volatile float m_timeDilation;
1127 private volatile float m_simFps;
1128 private volatile float m_physicsFps;
1129 private volatile float m_agentUpdates;
1130 private volatile float m_rootAgents;
1131 private volatile float m_childAgents;
1132 private volatile float m_totalPrims;
1133 private volatile float m_activePrims;
1134 private volatile float m_totalFrameTime;
1135 private volatile float m_netFrameTime;
1136 private volatile float m_physicsFrameTime;
1137 private volatile float m_otherFrameTime;
1138 private volatile float m_imageFrameTime;
1139 private volatile float m_inPacketsPerSecond;
1140 private volatile float m_outPacketsPerSecond;
1141 private volatile float m_unackedBytes;
1142 private volatile float m_agentFrameTime;
1143 private volatile float m_pendingDownloads;
1144 private volatile float m_pendingUploads;
1145 private volatile float m_activeScripts;
1146 private volatile float m_scriptLinesPerSecond;
1147
1148 public UUID RegionId { get { return m_regionID; } }
1149 public int StatsCounter { get { return m_statcounter; } set { m_statcounter = value;}}
1150 public float TimeDilation { get { return m_timeDilation; } }
1151 public float SimFps { get { return m_simFps; } }
1152 public float PhysicsFps { get { return m_physicsFps; } }
1153 public float AgentUpdates { get { return m_agentUpdates; } }
1154 public float RootAgents { get { return m_rootAgents; } }
1155 public float ChildAgents { get { return m_childAgents; } }
1156 public float TotalPrims { get { return m_totalPrims; } }
1157 public float ActivePrims { get { return m_activePrims; } }
1158 public float TotalFrameTime { get { return m_totalFrameTime; } }
1159 public float NetFrameTime { get { return m_netFrameTime; } }
1160 public float PhysicsFrameTime { get { return m_physicsFrameTime; } }
1161 public float OtherFrameTime { get { return m_otherFrameTime; } }
1162 public float ImageFrameTime { get { return m_imageFrameTime; } }
1163 public float InPacketsPerSecond { get { return m_inPacketsPerSecond; } }
1164 public float OutPacketsPerSecond { get { return m_outPacketsPerSecond; } }
1165 public float UnackedBytes { get { return m_unackedBytes; } }
1166 public float AgentFrameTime { get { return m_agentFrameTime; } }
1167 public float PendingDownloads { get { return m_pendingDownloads; } }
1168 public float PendingUploads { get { return m_pendingUploads; } }
1169 public float ActiveScripts { get { return m_activeScripts; } }
1170 public float ScriptLinesPerSecond { get { return m_scriptLinesPerSecond; } }
1171
1172 public USimStatsData(UUID pRegionID)
1173 {
1174 m_regionID = pRegionID;
1175 }
1176
1177 public void ConsumeSimStats(SimStats stats)
1178 {
1179 m_regionID = stats.RegionUUID;
1180 m_timeDilation = stats.StatsBlock[0].StatValue;
1181 m_simFps = stats.StatsBlock[1].StatValue;
1182 m_physicsFps = stats.StatsBlock[2].StatValue;
1183 m_agentUpdates = stats.StatsBlock[3].StatValue;
1184 m_rootAgents = stats.StatsBlock[4].StatValue;
1185 m_childAgents = stats.StatsBlock[5].StatValue;
1186 m_totalPrims = stats.StatsBlock[6].StatValue;
1187 m_activePrims = stats.StatsBlock[7].StatValue;
1188 m_totalFrameTime = stats.StatsBlock[8].StatValue;
1189 m_netFrameTime = stats.StatsBlock[9].StatValue;
1190 m_physicsFrameTime = stats.StatsBlock[10].StatValue;
1191 m_otherFrameTime = stats.StatsBlock[11].StatValue;
1192 m_imageFrameTime = stats.StatsBlock[12].StatValue;
1193 m_inPacketsPerSecond = stats.StatsBlock[13].StatValue;
1194 m_outPacketsPerSecond = stats.StatsBlock[14].StatValue;
1195 m_unackedBytes = stats.StatsBlock[15].StatValue;
1196 m_agentFrameTime = stats.StatsBlock[16].StatValue;
1197 m_pendingDownloads = stats.StatsBlock[17].StatValue;
1198 m_pendingUploads = stats.StatsBlock[18].StatValue;
1199 m_activeScripts = stats.StatsBlock[19].StatValue;
1200 m_scriptLinesPerSecond = stats.ExtraStatsBlock[0].StatValue;
1201 }
1202 }
1203} \ No newline at end of file