aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/OptionalModules')
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs1
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs99
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs486
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs149
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs36
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs46
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs44
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs433
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs264
-rw-r--r--OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs337
-rwxr-xr-xOpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs2
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs94
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs139
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs202
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs878
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs270
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs94
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs43
-rw-r--r--OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs40
-rwxr-xr-xOpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs623
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs1
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs308
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs329
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs277
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs263
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs39
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs159
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs80
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs288
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs276
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs70
-rw-r--r--OpenSim/Region/OptionalModules/UserStatistics/WebStatsModule.cs1203
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs1
37 files changed, 6948 insertions, 631 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
index ed1bab4..eef3c92 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
@@ -35,7 +35,6 @@ using Nini.Config;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.StructuredData; 36using OpenMetaverse.StructuredData;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
index 8095b28..1cb4747 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
@@ -42,7 +42,6 @@ using OpenMetaverse;
42using OpenMetaverse.StructuredData; 42using OpenMetaverse.StructuredData;
43 43
44using OpenSim.Framework; 44using OpenSim.Framework;
45using OpenSim.Framework.Communications;
46using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Services.Interfaces; 46using OpenSim.Services.Interfaces;
48 47
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
index e03e71d..9a42bac 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
@@ -37,7 +37,6 @@ using OpenMetaverse.Messages.Linden;
37using OpenMetaverse.Packets; 37using OpenMetaverse.Packets;
38using OpenMetaverse.StructuredData; 38using OpenMetaverse.StructuredData;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Framework.Servers; 40using OpenSim.Framework.Servers;
42using OpenSim.Framework.Servers.HttpServer; 41using OpenSim.Framework.Servers.HttpServer;
43using OpenSim.Region.ClientStack.Linden; 42using OpenSim.Region.ClientStack.Linden;
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
index a040f43..20555e4 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
@@ -41,7 +41,6 @@ using OpenMetaverse;
41using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
42 42
43using OpenSim.Framework; 43using OpenSim.Framework;
44using OpenSim.Framework.Communications;
45using OpenSim.Region.Framework.Interfaces; 44using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
47 46
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs
new file mode 100644
index 0000000..50276ae
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/DataRequestHandler.cs
@@ -0,0 +1,99 @@
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*/
28
29using System.Collections;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Capabilities;
36using OpenSim.Framework.Servers;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Scenes;
39using Caps = OpenSim.Framework.Capabilities.Caps;
40
41namespace OpenSim.Region.DataSnapshot
42{
43 public class DataRequestHandler
44 {
45// private Scene m_scene = null;
46 private DataSnapshotManager m_externalData = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 public DataRequestHandler(Scene scene, DataSnapshotManager externalData)
50 {
51// m_scene = scene;
52 m_externalData = externalData;
53
54 //Register HTTP handler
55 if (MainServer.Instance.AddHTTPHandler("collector", OnGetSnapshot))
56 {
57 m_log.Info("[DATASNAPSHOT]: Set up snapshot service");
58 }
59 // Register validation callback handler
60 MainServer.Instance.AddHTTPHandler("validate", OnValidate);
61
62 }
63
64 public Hashtable OnGetSnapshot(Hashtable keysvals)
65 {
66 m_log.Debug("[DATASNAPSHOT] Received collection request");
67 Hashtable reply = new Hashtable();
68 int statuscode = 200;
69
70 string snapObj = (string)keysvals["region"];
71
72 XmlDocument response = m_externalData.GetSnapshot(snapObj);
73
74 reply["str_response_string"] = response.OuterXml;
75 reply["int_response_code"] = statuscode;
76 reply["content_type"] = "text/xml";
77
78 return reply;
79 }
80
81 public Hashtable OnValidate(Hashtable keysvals)
82 {
83 m_log.Debug("[DATASNAPSHOT] Received validation request");
84 Hashtable reply = new Hashtable();
85 int statuscode = 200;
86
87 string secret = (string)keysvals["secret"];
88 if (secret == m_externalData.Secret.ToString())
89 statuscode = 403;
90
91 reply["str_response_string"] = string.Empty;
92 reply["int_response_code"] = statuscode;
93 reply["content_type"] = "text/plain";
94
95 return reply;
96 }
97
98 }
99}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs b/OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs
new file mode 100644
index 0000000..4e766eb
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/DataSnapshotManager.cs
@@ -0,0 +1,486 @@
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*/
28
29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Linq;
33using System.Net;
34using System.Reflection;
35using System.Text;
36using System.Xml;
37using log4net;
38using Nini.Config;
39using OpenMetaverse;
40using Mono.Addins;
41using OpenSim.Framework;
42using OpenSim.Region.DataSnapshot.Interfaces;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes;
45
46namespace OpenSim.Region.DataSnapshot
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DataSnapshotManager")]
49 public class DataSnapshotManager : ISharedRegionModule, IDataSnapshot
50 {
51 #region Class members
52 //Information from config
53 private bool m_enabled = false;
54 private bool m_configLoaded = false;
55 private List<string> m_disabledModules = new List<string>();
56 private Dictionary<string, string> m_gridinfo = new Dictionary<string, string>();
57 private string m_snapsDir = "DataSnapshot";
58 private string m_exposure_level = "minimum";
59
60 //Lists of stuff we need
61 private List<Scene> m_scenes = new List<Scene>();
62 private List<IDataSnapshotProvider> m_dataproviders = new List<IDataSnapshotProvider>();
63
64 //Various internal objects
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66 internal object m_syncInit = new object();
67
68 //DataServices and networking
69 private string m_dataServices = "noservices";
70 public string m_listener_port = ConfigSettings.DefaultRegionHttpPort.ToString();
71 public string m_hostname = "127.0.0.1";
72 private UUID m_Secret = UUID.Random();
73 private bool m_servicesNotified = false;
74
75 //Update timers
76 private int m_period = 20; // in seconds
77 private int m_maxStales = 500;
78 private int m_stales = 0;
79 private int m_lastUpdate = 0;
80
81 //Program objects
82 private SnapshotStore m_snapStore = null;
83
84 #endregion
85
86 #region Properties
87
88 public string ExposureLevel
89 {
90 get { return m_exposure_level; }
91 }
92
93 public UUID Secret
94 {
95 get { return m_Secret; }
96 }
97
98 #endregion
99
100 #region Region Module interface
101
102 public void Initialise(IConfigSource config)
103 {
104 if (!m_configLoaded)
105 {
106 m_configLoaded = true;
107 //m_log.Debug("[DATASNAPSHOT]: Loading configuration");
108 //Read from the config for options
109 lock (m_syncInit)
110 {
111 try
112 {
113 m_enabled = config.Configs["DataSnapshot"].GetBoolean("index_sims", m_enabled);
114 string gatekeeper = Util.GetConfigVarFromSections<string>(config, "GatekeeperURI",
115 new string[] { "Startup", "Hypergrid", "GridService" }, String.Empty);
116 // Legacy. Remove soon!
117 if (string.IsNullOrEmpty(gatekeeper))
118 {
119 IConfig conf = config.Configs["GridService"];
120 if (conf != null)
121 gatekeeper = conf.GetString("Gatekeeper", gatekeeper);
122 }
123 if (!string.IsNullOrEmpty(gatekeeper))
124 m_gridinfo.Add("gatekeeperURL", gatekeeper);
125
126 m_gridinfo.Add(
127 "name", config.Configs["DataSnapshot"].GetString("gridname", "the lost continent of hippo"));
128 m_exposure_level = config.Configs["DataSnapshot"].GetString("data_exposure", m_exposure_level);
129 m_period = config.Configs["DataSnapshot"].GetInt("default_snapshot_period", m_period);
130 m_maxStales = config.Configs["DataSnapshot"].GetInt("max_changes_before_update", m_maxStales);
131 m_snapsDir = config.Configs["DataSnapshot"].GetString("snapshot_cache_directory", m_snapsDir);
132 m_listener_port = config.Configs["Network"].GetString("http_listener_port", m_listener_port);
133
134 m_dataServices = config.Configs["DataSnapshot"].GetString("data_services", m_dataServices);
135 // New way of spec'ing data services, one per line
136 AddDataServicesVars(config.Configs["DataSnapshot"]);
137
138 String[] annoying_string_array = config.Configs["DataSnapshot"].GetString("disable_modules", "").Split(".".ToCharArray());
139 foreach (String bloody_wanker in annoying_string_array)
140 {
141 m_disabledModules.Add(bloody_wanker);
142 }
143 m_lastUpdate = Environment.TickCount;
144 }
145 catch (Exception)
146 {
147 m_log.Warn("[DATASNAPSHOT]: Could not load configuration. DataSnapshot will be disabled.");
148 m_enabled = false;
149 return;
150 }
151
152 }
153
154 }
155
156 }
157
158 public void AddRegion(Scene scene)
159 {
160 if (!m_enabled)
161 return;
162
163 m_log.DebugFormat("[DATASNAPSHOT]: Module added to Scene {0}.", scene.RegionInfo.RegionName);
164
165 if (!m_servicesNotified)
166 {
167 m_hostname = scene.RegionInfo.ExternalHostName;
168 m_snapStore = new SnapshotStore(m_snapsDir, m_gridinfo, m_listener_port, m_hostname);
169
170 //Hand it the first scene, assuming that all scenes have the same BaseHTTPServer
171 new DataRequestHandler(scene, this);
172
173 if (m_dataServices != "" && m_dataServices != "noservices")
174 NotifyDataServices(m_dataServices, "online");
175
176 m_servicesNotified = true;
177 }
178
179 m_scenes.Add(scene);
180 m_snapStore.AddScene(scene);
181
182 Assembly currentasm = Assembly.GetExecutingAssembly();
183
184 foreach (Type pluginType in currentasm.GetTypes())
185 {
186 if (pluginType.IsPublic)
187 {
188 if (!pluginType.IsAbstract)
189 {
190 if (pluginType.GetInterface("IDataSnapshotProvider") != null)
191 {
192 IDataSnapshotProvider module = (IDataSnapshotProvider)Activator.CreateInstance(pluginType);
193 module.Initialize(scene, this);
194 module.OnStale += MarkDataStale;
195
196 m_dataproviders.Add(module);
197 m_snapStore.AddProvider(module);
198
199 m_log.Debug("[DATASNAPSHOT]: Added new data provider type: " + pluginType.Name);
200 }
201 }
202 }
203 }
204
205 }
206
207 public void RemoveRegion(Scene scene)
208 {
209 if (!m_enabled)
210 return;
211
212 m_log.Info("[DATASNAPSHOT]: Region " + scene.RegionInfo.RegionName + " is being removed, removing from indexing");
213 Scene restartedScene = SceneForUUID(scene.RegionInfo.RegionID);
214
215 m_scenes.Remove(restartedScene);
216 m_snapStore.RemoveScene(restartedScene);
217
218 //Getting around the fact that we can't remove objects from a collection we are enumerating over
219 List<IDataSnapshotProvider> providersToRemove = new List<IDataSnapshotProvider>();
220
221 foreach (IDataSnapshotProvider provider in m_dataproviders)
222 {
223 if (provider.GetParentScene == restartedScene)
224 {
225 providersToRemove.Add(provider);
226 }
227 }
228
229 foreach (IDataSnapshotProvider provider in providersToRemove)
230 {
231 m_dataproviders.Remove(provider);
232 m_snapStore.RemoveProvider(provider);
233 }
234
235 m_snapStore.RemoveScene(restartedScene);
236 }
237
238 public void PostInitialise()
239 {
240 }
241
242 public void RegionLoaded(Scene scene)
243 {
244 if (!m_enabled)
245 return;
246
247 m_log.DebugFormat("[DATASNAPSHOT]: Marking scene {0} as stale.", scene.RegionInfo.RegionName);
248 m_snapStore.ForceSceneStale(scene);
249 }
250
251 public void Close()
252 {
253 if (!m_enabled)
254 return;
255
256 if (m_enabled && m_dataServices != "" && m_dataServices != "noservices")
257 NotifyDataServices(m_dataServices, "offline");
258 }
259
260
261 public string Name
262 {
263 get { return "External Data Generator"; }
264 }
265
266 public Type ReplaceableInterface
267 {
268 get { return null; }
269 }
270
271 #endregion
272
273 #region Associated helper functions
274
275 public Scene SceneForName(string name)
276 {
277 foreach (Scene scene in m_scenes)
278 if (scene.RegionInfo.RegionName == name)
279 return scene;
280
281 return null;
282 }
283
284 public Scene SceneForUUID(UUID id)
285 {
286 foreach (Scene scene in m_scenes)
287 if (scene.RegionInfo.RegionID == id)
288 return scene;
289
290 return null;
291 }
292
293 private void AddDataServicesVars(IConfig config)
294 {
295 // Make sure the services given this way aren't in m_dataServices already
296 List<string> servs = new List<string>(m_dataServices.Split(new char[] { ';' }));
297
298 StringBuilder sb = new StringBuilder();
299 string[] keys = config.GetKeys();
300
301 if (keys.Length > 0)
302 {
303 IEnumerable<string> serviceKeys = keys.Where(value => value.StartsWith("DATA_SRV_"));
304 foreach (string serviceKey in serviceKeys)
305 {
306 string keyValue = config.GetString(serviceKey, string.Empty).Trim();
307 if (!servs.Contains(keyValue))
308 sb.Append(keyValue).Append(";");
309 }
310 }
311
312 m_dataServices = (m_dataServices == "noservices") ? sb.ToString() : sb.Append(m_dataServices).ToString();
313 }
314
315 #endregion
316
317 #region [Public] Snapshot storage functions
318
319 /**
320 * Reply to the http request
321 */
322 public XmlDocument GetSnapshot(string regionName)
323 {
324 CheckStale();
325
326 XmlDocument requestedSnap = new XmlDocument();
327 requestedSnap.AppendChild(requestedSnap.CreateXmlDeclaration("1.0", null, null));
328 requestedSnap.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
329
330 XmlNode regiondata = requestedSnap.CreateNode(XmlNodeType.Element, "regiondata", "");
331 try
332 {
333 if (string.IsNullOrEmpty(regionName))
334 {
335 XmlNode timerblock = requestedSnap.CreateNode(XmlNodeType.Element, "expire", "");
336 timerblock.InnerText = m_period.ToString();
337 regiondata.AppendChild(timerblock);
338
339 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
340 foreach (Scene scene in m_scenes)
341 {
342 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
343 }
344 }
345 else
346 {
347 Scene scene = SceneForName(regionName);
348 regiondata.AppendChild(m_snapStore.GetScene(scene, requestedSnap));
349 }
350 requestedSnap.AppendChild(regiondata);
351 regiondata.AppendChild(requestedSnap.CreateWhitespace("\r\n"));
352 }
353 catch (XmlException e)
354 {
355 m_log.Warn("[DATASNAPSHOT]: XmlException while trying to load snapshot: " + e.ToString());
356 requestedSnap = GetErrorMessage(regionName, e);
357 }
358 catch (Exception e)
359 {
360 m_log.Warn("[DATASNAPSHOT]: Caught unknown exception while trying to load snapshot: " + e.StackTrace);
361 requestedSnap = GetErrorMessage(regionName, e);
362 }
363
364
365 return requestedSnap;
366 }
367
368 private XmlDocument GetErrorMessage(string regionName, Exception e)
369 {
370 XmlDocument errorMessage = new XmlDocument();
371 XmlNode error = errorMessage.CreateNode(XmlNodeType.Element, "error", "");
372 XmlNode region = errorMessage.CreateNode(XmlNodeType.Element, "region", "");
373 region.InnerText = regionName;
374
375 XmlNode exception = errorMessage.CreateNode(XmlNodeType.Element, "exception", "");
376 exception.InnerText = e.ToString();
377
378 error.AppendChild(region);
379 error.AppendChild(exception);
380 errorMessage.AppendChild(error);
381
382 return errorMessage;
383 }
384
385 #endregion
386
387 #region External data services
388 private void NotifyDataServices(string servicesStr, string serviceName)
389 {
390 Stream reply = null;
391 string delimStr = ";";
392 char [] delimiter = delimStr.ToCharArray();
393
394 string[] services = servicesStr.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
395
396 for (int i = 0; i < services.Length; i++)
397 {
398 string url = services[i].Trim();
399 using (RestClient cli = new RestClient(url))
400 {
401 cli.AddQueryParameter("service", serviceName);
402 cli.AddQueryParameter("host", m_hostname);
403 cli.AddQueryParameter("port", m_listener_port);
404 cli.AddQueryParameter("secret", m_Secret.ToString());
405 cli.RequestMethod = "GET";
406 try
407 {
408 reply = cli.Request(null);
409 }
410 catch (WebException)
411 {
412 m_log.Warn("[DATASNAPSHOT]: Unable to notify " + url);
413 }
414 catch (Exception e)
415 {
416 m_log.Warn("[DATASNAPSHOT]: Ignoring unknown exception " + e.ToString());
417 }
418
419 byte[] response = new byte[1024];
420 // int n = 0;
421 try
422 {
423 // n = reply.Read(response, 0, 1024);
424 reply.Read(response, 0, 1024);
425 }
426 catch (Exception e)
427 {
428 m_log.WarnFormat("[DATASNAPSHOT]: Unable to decode reply from data service. Ignoring. {0}", e.StackTrace);
429 }
430 // This is not quite working, so...
431 // string responseStr = Util.UTF8.GetString(response);
432 m_log.Info("[DATASNAPSHOT]: data service " + url + " notified. Secret: " + m_Secret);
433 }
434 }
435 }
436 #endregion
437
438 #region Latency-based update functions
439
440 public void MarkDataStale(IDataSnapshotProvider provider)
441 {
442 //Behavior here: Wait m_period seconds, then update if there has not been a request in m_period seconds
443 //or m_maxStales has been exceeded
444 m_stales++;
445 }
446
447 private void CheckStale()
448 {
449 // Wrap check
450 if (Environment.TickCount < m_lastUpdate)
451 {
452 m_lastUpdate = Environment.TickCount;
453 }
454
455 if (m_stales >= m_maxStales)
456 {
457 if (Environment.TickCount - m_lastUpdate >= 20000)
458 {
459 m_stales = 0;
460 m_lastUpdate = Environment.TickCount;
461 MakeEverythingStale();
462 }
463 }
464 else
465 {
466 if (m_lastUpdate + 1000 * m_period < Environment.TickCount)
467 {
468 m_stales = 0;
469 m_lastUpdate = Environment.TickCount;
470 MakeEverythingStale();
471 }
472 }
473 }
474
475 public void MakeEverythingStale()
476 {
477 m_log.Debug("[DATASNAPSHOT]: Marking all scenes as stale.");
478 foreach (Scene scene in m_scenes)
479 {
480 m_snapStore.ForceSceneStale(scene);
481 }
482 }
483 #endregion
484
485 }
486}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs
new file mode 100644
index 0000000..8da9e8c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/EstateSnapshot.cs
@@ -0,0 +1,149 @@
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.Xml;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33using OpenSim.Region.DataSnapshot.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Interfaces;
36
37namespace OpenSim.Region.DataSnapshot.Providers
38{
39 public class EstateSnapshot : IDataSnapshotProvider
40 {
41 /* This module doesn't check for changes, since it's *assumed* there are none.
42 * Nevertheless, it's possible to have changes, since all the fields are public.
43 * There's no event to subscribe to. :/
44 *
45 * I don't think anything changes the fields beyond RegionModule PostInit, however.
46 */
47 private Scene m_scene = null;
48 // private DataSnapshotManager m_parent = null;
49 private bool m_stale = true;
50
51 #region IDataSnapshotProvider Members
52
53 public XmlNode RequestSnapshotData(XmlDocument factory)
54 {
55 //Estate data section - contains who owns a set of sims and the name of the set.
56 //Now in DataSnapshotProvider module form!
57 XmlNode estatedata = factory.CreateNode(XmlNodeType.Element, "estate", "");
58
59 UUID ownerid = m_scene.RegionInfo.EstateSettings.EstateOwner;
60
61 UserAccount userInfo = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, ownerid);
62 //TODO: Change to query userserver about the master avatar UUID ?
63 String firstname;
64 String lastname;
65
66 if (userInfo != null)
67 {
68 firstname = userInfo.FirstName;
69 lastname = userInfo.LastName;
70
71 //TODO: Fix the marshalling system to have less copypasta gruntwork
72 XmlNode user = factory.CreateNode(XmlNodeType.Element, "user", "");
73// XmlAttribute type = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "type", "");
74// type.Value = "owner";
75// user.Attributes.Append(type);
76
77 //TODO: Create more TODOs
78 XmlNode username = factory.CreateNode(XmlNodeType.Element, "name", "");
79 username.InnerText = firstname + " " + lastname;
80 user.AppendChild(username);
81
82 XmlNode useruuid = factory.CreateNode(XmlNodeType.Element, "uuid", "");
83 useruuid.InnerText = ownerid.ToString();
84 user.AppendChild(useruuid);
85
86 estatedata.AppendChild(user);
87 }
88
89 XmlNode estatename = factory.CreateNode(XmlNodeType.Element, "name", "");
90 estatename.InnerText = m_scene.RegionInfo.EstateSettings.EstateName.ToString();
91 estatedata.AppendChild(estatename);
92
93 XmlNode estateid = factory.CreateNode(XmlNodeType.Element, "id", "");
94 estateid.InnerText = m_scene.RegionInfo.EstateSettings.EstateID.ToString();
95 estatedata.AppendChild(estateid);
96
97 XmlNode parentid = factory.CreateNode(XmlNodeType.Element, "parentid", "");
98 parentid.InnerText = m_scene.RegionInfo.EstateSettings.ParentEstateID.ToString();
99 estatedata.AppendChild(parentid);
100
101 XmlNode flags = factory.CreateNode(XmlNodeType.Element, "flags", "");
102
103 XmlAttribute teleport = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "teleport", "");
104 teleport.Value = m_scene.RegionInfo.EstateSettings.AllowDirectTeleport.ToString();
105 flags.Attributes.Append(teleport);
106
107 XmlAttribute publicaccess = (XmlAttribute)factory.CreateNode(XmlNodeType.Attribute, "public", "");
108 publicaccess.Value = m_scene.RegionInfo.EstateSettings.PublicAccess.ToString();
109 flags.Attributes.Append(publicaccess);
110
111 estatedata.AppendChild(flags);
112
113 this.Stale = false;
114 return estatedata;
115 }
116
117 public void Initialize(Scene scene, DataSnapshotManager parent)
118 {
119 m_scene = scene;
120 // m_parent = parent;
121 }
122
123 public Scene GetParentScene
124 {
125 get { return m_scene; }
126 }
127
128 public String Name {
129 get { return "EstateSnapshot"; }
130 }
131
132 public bool Stale
133 {
134 get {
135 return m_stale;
136 }
137 set {
138 m_stale = value;
139
140 if (m_stale)
141 OnStale(this);
142 }
143 }
144
145 public event ProviderStale OnStale;
146
147 #endregion
148 }
149}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs
new file mode 100644
index 0000000..3b3db65
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshot.cs
@@ -0,0 +1,36 @@
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.Xml;
29
30namespace OpenSim.Region.DataSnapshot.Interfaces
31{
32 public interface IDataSnapshot
33 {
34 XmlDocument GetSnapshot(string regionName);
35 }
36}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs
new file mode 100644
index 0000000..daea373
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/Interfaces/IDataSnapshotProvider.cs
@@ -0,0 +1,46 @@
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*/
28
29using System;
30using System.Xml;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.DataSnapshot.Interfaces
34{
35 public delegate void ProviderStale(IDataSnapshotProvider provider);
36
37 public interface IDataSnapshotProvider
38 {
39 XmlNode RequestSnapshotData(XmlDocument document);
40 void Initialize(Scene scene, DataSnapshotManager parent);
41 Scene GetParentScene { get; }
42 String Name { get; }
43 bool Stale { get; set; }
44 event ProviderStale OnStale;
45 }
46}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs
new file mode 100644
index 0000000..54a87f9
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/LLSDDiscovery.cs
@@ -0,0 +1,44 @@
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 OpenSim.Framework.Capabilities;
29
30namespace OpenSim.Region.DataSnapshot
31{
32 [OSDMap]
33 public class LLSDDiscoveryResponse
34 {
35 public OSDArray snapshot_resources;
36 }
37
38 [OSDMap]
39 public class LLSDDiscoveryDataURL
40 {
41 public string snapshot_format;
42 public string snapshot_url;
43 }
44}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs
new file mode 100644
index 0000000..b8c90cd
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/LandSnapshot.cs
@@ -0,0 +1,433 @@
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.Generic;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35
36using OpenSim.Region.CoreModules.World.Land;
37using OpenSim.Region.DataSnapshot.Interfaces;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41
42namespace OpenSim.Region.DataSnapshot.Providers
43{
44 public class LandSnapshot : IDataSnapshotProvider
45 {
46 private Scene m_scene = null;
47 private DataSnapshotManager m_parent = null;
48 //private Dictionary<int, Land> m_landIndexed = new Dictionary<int, Land>();
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 private bool m_stale = true;
51
52 #region Dead code
53
54 /*
55 * David, I don't think we need this at all. When we do the snapshot, we can
56 * simply look into the parcels that are marked for ShowDirectory -- see
57 * conditional in RequestSnapshotData
58 *
59 //Revise this, look for more direct way of checking for change in land
60 #region Client hooks
61
62 public void OnNewClient(IClientAPI client)
63 {
64 //Land hooks
65 client.OnParcelDivideRequest += ParcelSplitHook;
66 client.OnParcelJoinRequest += ParcelSplitHook;
67 client.OnParcelPropertiesUpdateRequest += ParcelPropsHook;
68 }
69
70 public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client)
71 {
72 PrepareData();
73 }
74
75 public void ParcelPropsHook(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
76 {
77 PrepareData();
78 }
79
80 #endregion
81
82 public void PrepareData()
83 {
84 m_log.Info("[EXTERNALDATA]: Generating land data.");
85
86 m_landIndexed.Clear();
87
88 //Index sim land
89 foreach (KeyValuePair<int, Land> curLand in m_scene.LandManager.landList)
90 {
91 //if ((curLand.Value.LandData.landFlags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory)
92 //{
93 m_landIndexed.Add(curLand.Key, curLand.Value.Copy());
94 //}
95 }
96 }
97
98 public Dictionary<int,Land> IndexedLand {
99 get { return m_landIndexed; }
100 }
101 */
102
103 #endregion
104
105 #region IDataSnapshotProvider members
106
107 public void Initialize(Scene scene, DataSnapshotManager parent)
108 {
109 m_scene = scene;
110 m_parent = parent;
111
112 //Brought back from the dead for staleness checks.
113 m_scene.EventManager.OnNewClient += OnNewClient;
114 }
115
116 public Scene GetParentScene
117 {
118 get { return m_scene; }
119 }
120
121 public XmlNode RequestSnapshotData(XmlDocument nodeFactory)
122 {
123 ILandChannel landChannel = m_scene.LandChannel;
124 List<ILandObject> parcels = landChannel.AllParcels();
125
126 IDwellModule dwellModule = m_scene.RequestModuleInterface<IDwellModule>();
127
128 XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "parceldata", "");
129 if (parcels != null)
130 {
131
132 //foreach (KeyValuePair<int, Land> curParcel in m_landIndexed)
133 foreach (ILandObject parcel_interface in parcels)
134 {
135 // Play it safe
136 if (!(parcel_interface is LandObject))
137 continue;
138
139 LandObject land = (LandObject)parcel_interface;
140
141 LandData parcel = land.LandData;
142 if (m_parent.ExposureLevel.Equals("all") ||
143 (m_parent.ExposureLevel.Equals("minimum") &&
144 (parcel.Flags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory))
145 {
146
147 //TODO: make better method of marshalling data from LandData to XmlNode
148 XmlNode xmlparcel = nodeFactory.CreateNode(XmlNodeType.Element, "parcel", "");
149
150 // Attributes of the parcel node
151 XmlAttribute scripts_attr = nodeFactory.CreateAttribute("scripts");
152 scripts_attr.Value = GetScriptsPermissions(parcel);
153 XmlAttribute build_attr = nodeFactory.CreateAttribute("build");
154 build_attr.Value = GetBuildPermissions(parcel);
155 XmlAttribute public_attr = nodeFactory.CreateAttribute("public");
156 public_attr.Value = GetPublicPermissions(parcel);
157 // Check the category of the Parcel
158 XmlAttribute category_attr = nodeFactory.CreateAttribute("category");
159 category_attr.Value = ((int)parcel.Category).ToString();
160 // Check if the parcel is for sale
161 XmlAttribute forsale_attr = nodeFactory.CreateAttribute("forsale");
162 forsale_attr.Value = CheckForSale(parcel);
163 XmlAttribute sales_attr = nodeFactory.CreateAttribute("salesprice");
164 sales_attr.Value = parcel.SalePrice.ToString();
165
166 XmlAttribute directory_attr = nodeFactory.CreateAttribute("showinsearch");
167 directory_attr.Value = GetShowInSearch(parcel);
168 //XmlAttribute entities_attr = nodeFactory.CreateAttribute("entities");
169 //entities_attr.Value = land.primsOverMe.Count.ToString();
170 xmlparcel.Attributes.Append(directory_attr);
171 xmlparcel.Attributes.Append(scripts_attr);
172 xmlparcel.Attributes.Append(build_attr);
173 xmlparcel.Attributes.Append(public_attr);
174 xmlparcel.Attributes.Append(category_attr);
175 xmlparcel.Attributes.Append(forsale_attr);
176 xmlparcel.Attributes.Append(sales_attr);
177 //xmlparcel.Attributes.Append(entities_attr);
178
179
180 //name, description, area, and UUID
181 XmlNode name = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
182 name.InnerText = parcel.Name;
183 xmlparcel.AppendChild(name);
184
185 XmlNode desc = nodeFactory.CreateNode(XmlNodeType.Element, "description", "");
186 desc.InnerText = parcel.Description;
187 xmlparcel.AppendChild(desc);
188
189 XmlNode uuid = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
190 uuid.InnerText = parcel.GlobalID.ToString();
191 xmlparcel.AppendChild(uuid);
192
193 XmlNode area = nodeFactory.CreateNode(XmlNodeType.Element, "area", "");
194 area.InnerText = parcel.Area.ToString();
195 xmlparcel.AppendChild(area);
196
197 //default location
198 XmlNode tpLocation = nodeFactory.CreateNode(XmlNodeType.Element, "location", "");
199 Vector3 loc = parcel.UserLocation;
200 if (loc.Equals(Vector3.Zero)) // This test is moot at this point: the location is wrong by default
201 loc = new Vector3((parcel.AABBMax.X + parcel.AABBMin.X) / 2, (parcel.AABBMax.Y + parcel.AABBMin.Y) / 2, (parcel.AABBMax.Z + parcel.AABBMin.Z) / 2);
202 tpLocation.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString();
203 xmlparcel.AppendChild(tpLocation);
204
205 XmlNode infouuid = nodeFactory.CreateNode(XmlNodeType.Element, "infouuid", "");
206 uint x = (uint)loc.X, y = (uint)loc.Y;
207 findPointInParcel(land, ref x, ref y); // find a suitable spot
208 infouuid.InnerText = Util.BuildFakeParcelID(
209 m_scene.RegionInfo.RegionHandle, x, y).ToString();
210 xmlparcel.AppendChild(infouuid);
211
212 XmlNode dwell = nodeFactory.CreateNode(XmlNodeType.Element, "dwell", "");
213 if (dwellModule != null)
214 dwell.InnerText = dwellModule.GetDwell(parcel.GlobalID).ToString();
215 else
216 dwell.InnerText = "0";
217 xmlparcel.AppendChild(dwell);
218
219 //TODO: figure how to figure out teleport system landData.landingType
220
221 //land texture snapshot uuid
222 if (parcel.SnapshotID != UUID.Zero)
223 {
224 XmlNode textureuuid = nodeFactory.CreateNode(XmlNodeType.Element, "image", "");
225 textureuuid.InnerText = parcel.SnapshotID.ToString();
226 xmlparcel.AppendChild(textureuuid);
227 }
228
229 string groupName = String.Empty;
230
231 //attached user and group
232 if (parcel.GroupID != UUID.Zero)
233 {
234 XmlNode groupblock = nodeFactory.CreateNode(XmlNodeType.Element, "group", "");
235 XmlNode groupuuid = nodeFactory.CreateNode(XmlNodeType.Element, "groupuuid", "");
236 groupuuid.InnerText = parcel.GroupID.ToString();
237 groupblock.AppendChild(groupuuid);
238
239 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
240 if (gm != null)
241 {
242 GroupRecord g = gm.GetGroupRecord(parcel.GroupID);
243 if (g != null)
244 groupName = g.GroupName;
245 }
246
247 XmlNode groupname = nodeFactory.CreateNode(XmlNodeType.Element, "groupname", "");
248 groupname.InnerText = groupName;
249 groupblock.AppendChild(groupname);
250
251 xmlparcel.AppendChild(groupblock);
252 }
253
254 XmlNode userblock = nodeFactory.CreateNode(XmlNodeType.Element, "owner", "");
255
256 UUID userOwnerUUID = parcel.OwnerID;
257
258 XmlNode useruuid = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
259 useruuid.InnerText = userOwnerUUID.ToString();
260 userblock.AppendChild(useruuid);
261
262 if (!parcel.IsGroupOwned)
263 {
264 try
265 {
266 XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
267 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, userOwnerUUID);
268 username.InnerText = account.FirstName + " " + account.LastName;
269 userblock.AppendChild(username);
270 }
271 catch (Exception)
272 {
273 //m_log.Info("[DATASNAPSHOT]: Cannot find owner name; ignoring this parcel");
274 }
275
276 }
277 else
278 {
279 XmlNode username = nodeFactory.CreateNode(XmlNodeType.Element, "name", "");
280 username.InnerText = groupName;
281 userblock.AppendChild(username);
282 }
283
284 xmlparcel.AppendChild(userblock);
285
286 parent.AppendChild(xmlparcel);
287 }
288 }
289 //snap.AppendChild(parent);
290 }
291
292 this.Stale = false;
293 return parent;
294 }
295
296 public String Name
297 {
298 get { return "LandSnapshot"; }
299 }
300
301 public bool Stale
302 {
303 get
304 {
305 return m_stale;
306 }
307 set
308 {
309 m_stale = value;
310
311 if (m_stale)
312 OnStale(this);
313 }
314 }
315
316 public event ProviderStale OnStale;
317
318 #endregion
319
320 #region Helper functions
321
322 private string GetScriptsPermissions(LandData parcel)
323 {
324 if ((parcel.Flags & (uint)ParcelFlags.AllowOtherScripts) == (uint)ParcelFlags.AllowOtherScripts)
325 return "true";
326 else
327 return "false";
328
329 }
330
331 private string GetPublicPermissions(LandData parcel)
332 {
333 if ((parcel.Flags & (uint)ParcelFlags.UseAccessList) == (uint)ParcelFlags.UseAccessList)
334 return "false";
335 else
336 return "true";
337
338 }
339
340 private string GetBuildPermissions(LandData parcel)
341 {
342 if ((parcel.Flags & (uint)ParcelFlags.CreateObjects) == (uint)ParcelFlags.CreateObjects)
343 return "true";
344 else
345 return "false";
346
347 }
348
349 private string CheckForSale(LandData parcel)
350 {
351 if ((parcel.Flags & (uint)ParcelFlags.ForSale) == (uint)ParcelFlags.ForSale)
352 return "true";
353 else
354 return "false";
355 }
356
357 private string GetShowInSearch(LandData parcel)
358 {
359 if ((parcel.Flags & (uint)ParcelFlags.ShowDirectory) == (uint)ParcelFlags.ShowDirectory)
360 return "true";
361 else
362 return "false";
363
364 }
365
366 #endregion
367
368 #region Change detection hooks
369
370 public void OnNewClient(IClientAPI client)
371 {
372 //Land hooks
373 client.OnParcelDivideRequest += delegate(int west, int south, int east, int north,
374 IClientAPI remote_client) { this.Stale = true; };
375 client.OnParcelJoinRequest += delegate(int west, int south, int east, int north,
376 IClientAPI remote_client) { this.Stale = true; };
377 client.OnParcelPropertiesUpdateRequest += delegate(LandUpdateArgs args, int local_id,
378 IClientAPI remote_client) { this.Stale = true; };
379 client.OnParcelBuy += delegate(UUID agentId, UUID groupId, bool final, bool groupOwned,
380 bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated)
381 { this.Stale = true; };
382 }
383
384 public void ParcelSplitHook(int west, int south, int east, int north, IClientAPI remote_client)
385 {
386 this.Stale = true;
387 }
388
389 public void ParcelPropsHook(LandUpdateArgs args, int local_id, IClientAPI remote_client)
390 {
391 this.Stale = true;
392 }
393
394 #endregion
395
396 // this is needed for non-convex parcels (example: rectangular parcel, and in the exact center
397 // another, smaller rectangular parcel). Both will have the same initial coordinates.
398 private void findPointInParcel(ILandObject land, ref uint refX, ref uint refY)
399 {
400 m_log.DebugFormat("[DATASNAPSHOT] trying {0}, {1}", refX, refY);
401 // the point we started with already is in the parcel
402 if (land.ContainsPoint((int)refX, (int)refY)) return;
403
404 // ... otherwise, we have to search for a point within the parcel
405 uint startX = (uint)land.LandData.AABBMin.X;
406 uint startY = (uint)land.LandData.AABBMin.Y;
407 uint endX = (uint)land.LandData.AABBMax.X;
408 uint endY = (uint)land.LandData.AABBMax.Y;
409
410 // default: center of the parcel
411 refX = (startX + endX) / 2;
412 refY = (startY + endY) / 2;
413 // If the center point is within the parcel, take that one
414 if (land.ContainsPoint((int)refX, (int)refY)) return;
415
416 // otherwise, go the long way.
417 for (uint y = startY; y <= endY; ++y)
418 {
419 for (uint x = startX; x <= endX; ++x)
420 {
421 if (land.ContainsPoint((int)x, (int)y))
422 {
423 // found a point
424 refX = x;
425 refY = y;
426 return;
427 }
428 }
429 }
430 }
431 }
432}
433
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs b/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs
new file mode 100644
index 0000000..0bb4044
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/ObjectSnapshot.cs
@@ -0,0 +1,264 @@
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.Generic;
30using System.Reflection;
31using System.Xml;
32using log4net;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.DataSnapshot.Interfaces;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.DataSnapshot.Providers
40{
41 public class ObjectSnapshot : IDataSnapshotProvider
42 {
43 private Scene m_scene = null;
44 // private DataSnapshotManager m_parent = null;
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 private bool m_stale = true;
47
48 private static UUID m_DefaultImage = new UUID("89556747-24cb-43ed-920b-47caed15465f");
49 private static UUID m_BlankImage = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
50
51
52 public void Initialize(Scene scene, DataSnapshotManager parent)
53 {
54 m_scene = scene;
55 // m_parent = parent;
56
57 //To check for staleness, we must catch all incoming client packets.
58 m_scene.EventManager.OnNewClient += OnNewClient;
59 m_scene.EventManager.OnParcelPrimCountAdd += delegate(SceneObjectGroup obj) { this.Stale = true; };
60 }
61
62 public void OnNewClient(IClientAPI client)
63 {
64 //Detect object data changes by hooking into the IClientAPI.
65 //Very dirty, and breaks whenever someone changes the client API.
66
67 client.OnAddPrim += delegate (UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot,
68 PrimitiveBaseShape shape, byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
69 byte RayEndIsIntersection) { this.Stale = true; };
70 client.OnLinkObjects += delegate (IClientAPI remoteClient, uint parent, List<uint> children)
71 { this.Stale = true; };
72 client.OnDelinkObjects += delegate(List<uint> primIds, IClientAPI clientApi) { this.Stale = true; };
73 client.OnGrabUpdate += delegate(UUID objectID, Vector3 offset, Vector3 grapPos,
74 IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs) { this.Stale = true; };
75 client.OnObjectAttach += delegate(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt,
76 bool silent) { this.Stale = true; };
77 client.OnObjectDuplicate += delegate(uint localID, Vector3 offset, uint dupeFlags, UUID AgentID,
78 UUID GroupID) { this.Stale = true; };
79 client.OnObjectDuplicateOnRay += delegate(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
80 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart, bool BypassRaycast,
81 bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates) { this.Stale = true; };
82 client.OnObjectIncludeInSearch += delegate(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
83 { this.Stale = true; };
84 client.OnObjectPermissions += delegate(IClientAPI controller, UUID agentID, UUID sessionID,
85 byte field, uint localId, uint mask, byte set) { this.Stale = true; };
86 client.OnRezObject += delegate(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd,
87 Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
88 bool RezSelected,
89 bool RemoveItem, UUID fromTaskID) { this.Stale = true; };
90 }
91
92 public Scene GetParentScene
93 {
94 get { return m_scene; }
95 }
96
97 public XmlNode RequestSnapshotData(XmlDocument nodeFactory)
98 {
99 m_log.Debug("[DATASNAPSHOT]: Generating object data for scene " + m_scene.RegionInfo.RegionName);
100
101 XmlNode parent = nodeFactory.CreateNode(XmlNodeType.Element, "objectdata", "");
102 XmlNode node;
103
104 EntityBase[] entities = m_scene.Entities.GetEntities();
105 foreach (EntityBase entity in entities)
106 {
107 // only objects, not avatars
108 if (entity is SceneObjectGroup)
109 {
110 SceneObjectGroup obj = (SceneObjectGroup)entity;
111
112// m_log.Debug("[DATASNAPSHOT]: Found object " + obj.Name + " in scene");
113
114 // libomv will complain about PrimFlags.JointWheel
115 // being obsolete, so we...
116 #pragma warning disable 0612
117 if ((obj.RootPart.Flags & PrimFlags.JointWheel) == PrimFlags.JointWheel)
118 {
119 SceneObjectPart m_rootPart = obj.RootPart;
120
121 ILandObject land = m_scene.LandChannel.GetLandObject(m_rootPart.AbsolutePosition.X, m_rootPart.AbsolutePosition.Y);
122
123 XmlNode xmlobject = nodeFactory.CreateNode(XmlNodeType.Element, "object", "");
124 node = nodeFactory.CreateNode(XmlNodeType.Element, "uuid", "");
125 node.InnerText = obj.UUID.ToString();
126 xmlobject.AppendChild(node);
127
128 node = nodeFactory.CreateNode(XmlNodeType.Element, "title", "");
129 node.InnerText = m_rootPart.Name;
130 xmlobject.AppendChild(node);
131
132 node = nodeFactory.CreateNode(XmlNodeType.Element, "description", "");
133 node.InnerText = m_rootPart.Description;
134 xmlobject.AppendChild(node);
135
136 node = nodeFactory.CreateNode(XmlNodeType.Element, "flags", "");
137 node.InnerText = String.Format("{0:x}", (uint)m_rootPart.Flags);
138 xmlobject.AppendChild(node);
139
140 node = nodeFactory.CreateNode(XmlNodeType.Element, "regionuuid", "");
141 node.InnerText = m_scene.RegionInfo.RegionSettings.RegionUUID.ToString();
142 xmlobject.AppendChild(node);
143
144 if (land != null && land.LandData != null)
145 {
146 node = nodeFactory.CreateNode(XmlNodeType.Element, "parceluuid", "");
147 node.InnerText = land.LandData.GlobalID.ToString();
148 xmlobject.AppendChild(node);
149 }
150 else
151 {
152 // Something is wrong with this object. Let's not list it.
153 m_log.WarnFormat("[DATASNAPSHOT]: Bad data for object {0} ({1}) in region {2}", obj.Name, obj.UUID, m_scene.RegionInfo.RegionName);
154 continue;
155 }
156
157 node = nodeFactory.CreateNode(XmlNodeType.Element, "location", "");
158 Vector3 loc = obj.AbsolutePosition;
159 node.InnerText = loc.X.ToString() + "/" + loc.Y.ToString() + "/" + loc.Z.ToString();
160 xmlobject.AppendChild(node);
161
162 string bestImage = GuessImage(obj);
163 if (bestImage != string.Empty)
164 {
165 node = nodeFactory.CreateNode(XmlNodeType.Element, "image", "");
166 node.InnerText = bestImage;
167 xmlobject.AppendChild(node);
168 }
169
170 parent.AppendChild(xmlobject);
171 }
172 #pragma warning disable 0612
173 }
174 }
175 this.Stale = false;
176 return parent;
177 }
178
179 public String Name
180 {
181 get { return "ObjectSnapshot"; }
182 }
183
184 public bool Stale
185 {
186 get
187 {
188 return m_stale;
189 }
190 set
191 {
192 m_stale = value;
193
194 if (m_stale)
195 OnStale(this);
196 }
197 }
198
199 public event ProviderStale OnStale;
200
201 /// <summary>
202 /// Guesses the best image, based on a simple heuristic. It guesses only for boxes.
203 /// We're optimizing for boxes, because those are the most common objects
204 /// marked "Show in search" -- boxes with content inside.For other shapes,
205 /// it's really hard to tell which texture should be grabbed.
206 /// </summary>
207 /// <param name="sog"></param>
208 /// <returns></returns>
209 private string GuessImage(SceneObjectGroup sog)
210 {
211 string bestguess = string.Empty;
212 Dictionary<UUID, int> counts = new Dictionary<UUID, int>();
213
214 PrimitiveBaseShape shape = sog.RootPart.Shape;
215 if (shape != null && shape.ProfileShape == ProfileShape.Square)
216 {
217 Primitive.TextureEntry textures = shape.Textures;
218 if (textures != null)
219 {
220 if (textures.DefaultTexture != null &&
221 textures.DefaultTexture.TextureID != UUID.Zero &&
222 textures.DefaultTexture.TextureID != m_DefaultImage &&
223 textures.DefaultTexture.TextureID != m_BlankImage &&
224 textures.DefaultTexture.RGBA.A < 50f)
225 {
226 counts[textures.DefaultTexture.TextureID] = 8;
227 }
228
229 if (textures.FaceTextures != null)
230 {
231 foreach (Primitive.TextureEntryFace tentry in textures.FaceTextures)
232 {
233 if (tentry != null)
234 {
235 if (tentry.TextureID != UUID.Zero && tentry.TextureID != m_DefaultImage && tentry.TextureID != m_BlankImage && tentry.RGBA.A < 50)
236 {
237 int c = 0;
238 counts.TryGetValue(tentry.TextureID, out c);
239 counts[tentry.TextureID] = c + 1;
240 // decrease the default texture count
241 if (counts.ContainsKey(textures.DefaultTexture.TextureID))
242 counts[textures.DefaultTexture.TextureID] = counts[textures.DefaultTexture.TextureID] - 1;
243 }
244 }
245 }
246 }
247
248 // Let's pick the most unique texture
249 int min = 9999;
250 foreach (KeyValuePair<UUID, int> kv in counts)
251 {
252 if (kv.Value < min && kv.Value >= 1)
253 {
254 bestguess = kv.Key.ToString();
255 min = kv.Value;
256 }
257 }
258 }
259 }
260
261 return bestguess;
262 }
263 }
264}
diff --git a/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs b/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs
new file mode 100644
index 0000000..480aaaf
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/DataSnapshot/SnapshotStore.cs
@@ -0,0 +1,337 @@
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.Generic;
30using System.IO;
31using System.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using System.Xml;
35using log4net;
36using OpenSim.Region.DataSnapshot.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38
39namespace OpenSim.Region.DataSnapshot
40{
41 public class SnapshotStore
42 {
43 #region Class Members
44 private String m_directory = "unyuu"; //not an attempt at adding RM references to core SVN, honest
45 private Dictionary<Scene, bool> m_scenes = null;
46 private List<IDataSnapshotProvider> m_providers = null;
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 private Dictionary<String, String> m_gridinfo = null;
49 private bool m_cacheEnabled = true;
50 private string m_listener_port = "9000"; //TODO: Set default port over 9000
51 private string m_hostname = "127.0.0.1";
52 #endregion
53
54 public SnapshotStore(string directory, Dictionary<String, String> gridinfo, string port, string hostname) {
55 m_directory = directory;
56 m_scenes = new Dictionary<Scene, bool>();
57 m_providers = new List<IDataSnapshotProvider>();
58 m_gridinfo = gridinfo;
59 m_listener_port = port;
60 m_hostname = hostname;
61
62 if (Directory.Exists(m_directory))
63 {
64 m_log.Info("[DATASNAPSHOT]: Response and fragment cache directory already exists.");
65 }
66 else
67 {
68 // Try to create the directory.
69 m_log.Info("[DATASNAPSHOT]: Creating directory " + m_directory);
70 try
71 {
72 Directory.CreateDirectory(m_directory);
73 }
74 catch (Exception e)
75 {
76 m_log.Error("[DATASNAPSHOT]: Failed to create directory " + m_directory, e);
77
78 //This isn't a horrible problem, just disable cacheing.
79 m_cacheEnabled = false;
80 m_log.Error("[DATASNAPSHOT]: Could not create directory, response cache has been disabled.");
81 }
82 }
83 }
84
85 public void ForceSceneStale(Scene scene) {
86 m_scenes[scene] = true;
87 }
88
89 #region Fragment storage
90 public XmlNode GetFragment(IDataSnapshotProvider provider, XmlDocument factory)
91 {
92 XmlNode data = null;
93
94 if (provider.Stale || !m_cacheEnabled)
95 {
96 data = provider.RequestSnapshotData(factory);
97
98 if (m_cacheEnabled)
99 {
100 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
101
102 try
103 {
104 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
105 {
106 snapXWriter.Formatting = Formatting.Indented;
107 snapXWriter.WriteStartDocument();
108 data.WriteTo(snapXWriter);
109 snapXWriter.WriteEndDocument();
110 }
111 }
112 catch (Exception e)
113 {
114 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
115 }
116
117 }
118
119 //mark provider as not stale, parent scene as stale
120 provider.Stale = false;
121 m_scenes[provider.GetParentScene] = true;
122
123 m_log.Debug("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name);
124 }
125 else
126 {
127 String path = DataFileNameFragment(provider.GetParentScene, provider.Name);
128
129 XmlDocument fragDocument = new XmlDocument();
130 fragDocument.PreserveWhitespace = true;
131 fragDocument.Load(path);
132 foreach (XmlNode node in fragDocument)
133 {
134 data = factory.ImportNode(node, true);
135 }
136
137 m_log.Debug("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name);
138 }
139
140 return data;
141 }
142 #endregion
143
144 #region Response storage
145 public XmlNode GetScene(Scene scene, XmlDocument factory)
146 {
147 m_log.Debug("[DATASNAPSHOT]: Data requested for scene " + scene.RegionInfo.RegionName);
148
149 if (!m_scenes.ContainsKey(scene)) {
150 m_scenes.Add(scene, true); //stale by default
151 }
152
153 XmlNode regionElement = null;
154
155 if (!m_scenes[scene])
156 {
157 m_log.Debug("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache.");
158 //get snapshot from cache
159 String path = DataFileNameScene(scene);
160
161 XmlDocument fragDocument = new XmlDocument();
162 fragDocument.PreserveWhitespace = true;
163
164 fragDocument.Load(path);
165
166 foreach (XmlNode node in fragDocument)
167 {
168 regionElement = factory.ImportNode(node, true);
169 }
170
171 m_log.Debug("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName);
172 }
173 else
174 {
175 m_log.Debug("[DATASNAPSHOT]: Attempting to generate snapshot.");
176 //make snapshot
177 regionElement = MakeRegionNode(scene, factory);
178
179 regionElement.AppendChild(GetGridSnapshotData(factory));
180 XmlNode regionData = factory.CreateNode(XmlNodeType.Element, "data", "");
181
182 foreach (IDataSnapshotProvider dataprovider in m_providers)
183 {
184 if (dataprovider.GetParentScene == scene)
185 {
186 regionData.AppendChild(GetFragment(dataprovider, factory));
187 }
188 }
189
190 regionElement.AppendChild(regionData);
191
192 factory.AppendChild(regionElement);
193
194 //save snapshot
195 String path = DataFileNameScene(scene);
196
197 try
198 {
199 using (XmlTextWriter snapXWriter = new XmlTextWriter(path, Encoding.Default))
200 {
201 snapXWriter.Formatting = Formatting.Indented;
202 snapXWriter.WriteStartDocument();
203 regionElement.WriteTo(snapXWriter);
204 snapXWriter.WriteEndDocument();
205 }
206 }
207 catch (Exception e)
208 {
209 m_log.WarnFormat("[DATASNAPSHOT]: Exception on writing to file {0}: {1}", path, e.Message);
210 }
211
212 m_scenes[scene] = false;
213
214 m_log.Debug("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName);
215 }
216
217 return regionElement;
218 }
219
220 #endregion
221
222 #region Helpers
223 private string DataFileNameFragment(Scene scene, String fragmentName)
224 {
225 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName + "_" + fragmentName), "xml"));
226 }
227
228 private string DataFileNameScene(Scene scene)
229 {
230 return Path.Combine(m_directory, Path.ChangeExtension(Sanitize(scene.RegionInfo.RegionName), "xml"));
231 //return (m_snapsDir + Path.DirectorySeparatorChar + scene.RegionInfo.RegionName + ".xml");
232 }
233
234 private static string Sanitize(string name)
235 {
236 string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars()));
237 string invalidReStr = string.Format(@"[{0}]", invalidChars);
238 string newname = Regex.Replace(name, invalidReStr, "_");
239 return newname.Replace('.', '_');
240 }
241
242 private XmlNode MakeRegionNode(Scene scene, XmlDocument basedoc)
243 {
244 XmlNode docElement = basedoc.CreateNode(XmlNodeType.Element, "region", "");
245
246 XmlAttribute attr = basedoc.CreateAttribute("category");
247 attr.Value = GetRegionCategory(scene);
248 docElement.Attributes.Append(attr);
249
250 attr = basedoc.CreateAttribute("entities");
251 attr.Value = scene.Entities.Count.ToString();
252 docElement.Attributes.Append(attr);
253
254 //attr = basedoc.CreateAttribute("parcels");
255 //attr.Value = scene.LandManager.landList.Count.ToString();
256 //docElement.Attributes.Append(attr);
257
258
259 XmlNode infoblock = basedoc.CreateNode(XmlNodeType.Element, "info", "");
260
261 XmlNode infopiece = basedoc.CreateNode(XmlNodeType.Element, "uuid", "");
262 infopiece.InnerText = scene.RegionInfo.RegionID.ToString();
263 infoblock.AppendChild(infopiece);
264
265 infopiece = basedoc.CreateNode(XmlNodeType.Element, "url", "");
266 infopiece.InnerText = "http://" + m_hostname + ":" + m_listener_port;
267 infoblock.AppendChild(infopiece);
268
269 infopiece = basedoc.CreateNode(XmlNodeType.Element, "name", "");
270 infopiece.InnerText = scene.RegionInfo.RegionName;
271 infoblock.AppendChild(infopiece);
272
273 infopiece = basedoc.CreateNode(XmlNodeType.Element, "handle", "");
274 infopiece.InnerText = scene.RegionInfo.RegionHandle.ToString();
275 infoblock.AppendChild(infopiece);
276
277 docElement.AppendChild(infoblock);
278
279 m_log.Debug("[DATASNAPSHOT]: Generated region node");
280 return docElement;
281 }
282
283 private String GetRegionCategory(Scene scene)
284 {
285 if (scene.RegionInfo.RegionSettings.Maturity == 0)
286 return "PG";
287
288 if (scene.RegionInfo.RegionSettings.Maturity == 1)
289 return "Mature";
290
291 if (scene.RegionInfo.RegionSettings.Maturity == 2)
292 return "Adult";
293
294 return "Unknown";
295 }
296
297 private XmlNode GetGridSnapshotData(XmlDocument factory)
298 {
299 XmlNode griddata = factory.CreateNode(XmlNodeType.Element, "grid", "");
300
301 foreach (KeyValuePair<String, String> GridData in m_gridinfo)
302 {
303 //TODO: make it lowercase tag names for diva
304 XmlNode childnode = factory.CreateNode(XmlNodeType.Element, GridData.Key, "");
305 childnode.InnerText = GridData.Value;
306 griddata.AppendChild(childnode);
307 }
308
309 m_log.Debug("[DATASNAPSHOT]: Got grid snapshot data");
310
311 return griddata;
312 }
313 #endregion
314
315 #region Manage internal collections
316 public void AddScene(Scene newScene)
317 {
318 m_scenes.Add(newScene, true);
319 }
320
321 public void RemoveScene(Scene deadScene)
322 {
323 m_scenes.Remove(deadScene);
324 }
325
326 public void AddProvider(IDataSnapshotProvider newProvider)
327 {
328 m_providers.Add(newProvider);
329 }
330
331 public void RemoveProvider(IDataSnapshotProvider deadProvider)
332 {
333 m_providers.Remove(deadProvider);
334 }
335 #endregion
336 }
337}
diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
index 3083a33..1d9179c 100755
--- a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
+++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs
@@ -36,7 +36,7 @@ using OpenSim.Framework.Console;
36using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 36using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
37using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.PhysicsModules.SharedBase;
40 40
41namespace OpenSim.Region.OptionalModules.PhysicsParameters 41namespace OpenSim.Region.OptionalModules.PhysicsParameters
42{ 42{
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs
new file mode 100644
index 0000000..721d396
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerClientEventForwarder.cs
@@ -0,0 +1,94 @@
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.Generic;
30using OpenMetaverse;
31using OpenSim.Region.Framework.Scenes;
32
33namespace OpenSim.Region.RegionCombinerModule
34{
35public class RegionCombinerClientEventForwarder
36 {
37 private Scene m_rootScene;
38 private Dictionary<UUID, Scene> m_virtScene = new Dictionary<UUID, Scene>();
39 private Dictionary<UUID,RegionCombinerIndividualEventForwarder> m_forwarders = new Dictionary<UUID,
40 RegionCombinerIndividualEventForwarder>();
41
42 public RegionCombinerClientEventForwarder(RegionConnections rootScene)
43 {
44 m_rootScene = rootScene.RegionScene;
45 }
46
47 public void AddSceneToEventForwarding(Scene virtualScene)
48 {
49 lock (m_virtScene)
50 {
51 if (m_virtScene.ContainsKey(virtualScene.RegionInfo.originRegionID))
52 {
53 m_virtScene[virtualScene.RegionInfo.originRegionID] = virtualScene;
54 }
55 else
56 {
57 m_virtScene.Add(virtualScene.RegionInfo.originRegionID, virtualScene);
58 }
59 }
60
61 lock (m_forwarders)
62 {
63 // TODO: Fix this to unregister if this happens
64 if (m_forwarders.ContainsKey(virtualScene.RegionInfo.originRegionID))
65 m_forwarders.Remove(virtualScene.RegionInfo.originRegionID);
66
67 RegionCombinerIndividualEventForwarder forwarder =
68 new RegionCombinerIndividualEventForwarder(m_rootScene, virtualScene);
69 m_forwarders.Add(virtualScene.RegionInfo.originRegionID, forwarder);
70
71 virtualScene.EventManager.OnNewClient += forwarder.ClientConnect;
72 virtualScene.EventManager.OnClientClosed += forwarder.ClientClosed;
73 }
74 }
75
76 public void RemoveSceneFromEventForwarding (Scene virtualScene)
77 {
78 lock (m_forwarders)
79 {
80 RegionCombinerIndividualEventForwarder forwarder = m_forwarders[virtualScene.RegionInfo.originRegionID];
81 virtualScene.EventManager.OnNewClient -= forwarder.ClientConnect;
82 virtualScene.EventManager.OnClientClosed -= forwarder.ClientClosed;
83 m_forwarders.Remove(virtualScene.RegionInfo.originRegionID);
84 }
85 lock (m_virtScene)
86 {
87 if (m_virtScene.ContainsKey(virtualScene.RegionInfo.originRegionID))
88 {
89 m_virtScene.Remove(virtualScene.RegionInfo.originRegionID);
90 }
91 }
92 }
93 }
94} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs
new file mode 100644
index 0000000..83732e2
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerIndividualEventForwarder.cs
@@ -0,0 +1,139 @@
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 OpenMetaverse;
30using OpenSim.Framework;
31using OpenSim.Region.CoreModules.Avatar.Attachments;
32using OpenSim.Region.CoreModules.Avatar.Gods;
33using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes;
35
36namespace OpenSim.Region.RegionCombinerModule
37{
38 public class RegionCombinerIndividualEventForwarder
39 {
40 private Scene m_rootScene;
41 private Scene m_virtScene;
42
43 public RegionCombinerIndividualEventForwarder(Scene rootScene, Scene virtScene)
44 {
45 m_rootScene = rootScene;
46 m_virtScene = virtScene;
47 }
48
49 public void ClientConnect(IClientAPI client)
50 {
51 m_virtScene.UnSubscribeToClientPrimEvents(client);
52 m_virtScene.UnSubscribeToClientPrimRezEvents(client);
53 m_virtScene.UnSubscribeToClientInventoryEvents(client);
54 if(m_virtScene.AttachmentsModule != null)
55 ((AttachmentsModule)m_virtScene.AttachmentsModule).UnsubscribeFromClientEvents(client);
56 //m_virtScene.UnSubscribeToClientTeleportEvents(client);
57 m_virtScene.UnSubscribeToClientScriptEvents(client);
58
59 IGodsModule virtGodsModule = m_virtScene.RequestModuleInterface<IGodsModule>();
60 if (virtGodsModule != null)
61 ((GodsModule)virtGodsModule).UnsubscribeFromClientEvents(client);
62
63 m_virtScene.UnSubscribeToClientNetworkEvents(client);
64
65 m_rootScene.SubscribeToClientPrimEvents(client);
66 client.OnAddPrim += LocalAddNewPrim;
67 client.OnRezObject += LocalRezObject;
68
69 m_rootScene.SubscribeToClientInventoryEvents(client);
70 if (m_rootScene.AttachmentsModule != null)
71 ((AttachmentsModule)m_rootScene.AttachmentsModule).SubscribeToClientEvents(client);
72 //m_rootScene.SubscribeToClientTeleportEvents(client);
73 m_rootScene.SubscribeToClientScriptEvents(client);
74
75 IGodsModule rootGodsModule = m_virtScene.RequestModuleInterface<IGodsModule>();
76 if (rootGodsModule != null)
77 ((GodsModule)rootGodsModule).UnsubscribeFromClientEvents(client);
78
79 m_rootScene.SubscribeToClientNetworkEvents(client);
80 }
81
82 public void ClientClosed(UUID clientid, Scene scene)
83 {
84 }
85
86 /// <summary>
87 /// Fixes position based on the region the Rez event came in on
88 /// </summary>
89 /// <param name="remoteclient"></param>
90 /// <param name="itemid"></param>
91 /// <param name="rayend"></param>
92 /// <param name="raystart"></param>
93 /// <param name="raytargetid"></param>
94 /// <param name="bypassraycast"></param>
95 /// <param name="rayendisintersection"></param>
96 /// <param name="rezselected"></param>
97 /// <param name="removeitem"></param>
98 /// <param name="fromtaskid"></param>
99 private void LocalRezObject(IClientAPI remoteclient, UUID itemid, Vector3 rayend, Vector3 raystart,
100 UUID raytargetid, byte bypassraycast, bool rayendisintersection, bool rezselected, bool removeitem,
101 UUID fromtaskid)
102 {
103 int differenceX = (int)m_virtScene.RegionInfo.RegionLocX - (int)m_rootScene.RegionInfo.RegionLocX;
104 int differenceY = (int)m_virtScene.RegionInfo.RegionLocY - (int)m_rootScene.RegionInfo.RegionLocY;
105 rayend.X += differenceX * (int)Constants.RegionSize;
106 rayend.Y += differenceY * (int)Constants.RegionSize;
107 raystart.X += differenceX * (int)Constants.RegionSize;
108 raystart.Y += differenceY * (int)Constants.RegionSize;
109
110 m_rootScene.RezObject(remoteclient, itemid, rayend, raystart, raytargetid, bypassraycast,
111 rayendisintersection, rezselected, removeitem, fromtaskid);
112 }
113 /// <summary>
114 /// Fixes position based on the region the AddPrimShape event came in on
115 /// </summary>
116 /// <param name="ownerid"></param>
117 /// <param name="groupid"></param>
118 /// <param name="rayend"></param>
119 /// <param name="rot"></param>
120 /// <param name="shape"></param>
121 /// <param name="bypassraycast"></param>
122 /// <param name="raystart"></param>
123 /// <param name="raytargetid"></param>
124 /// <param name="rayendisintersection"></param>
125 private void LocalAddNewPrim(UUID ownerid, UUID groupid, Vector3 rayend, Quaternion rot,
126 PrimitiveBaseShape shape, byte bypassraycast, Vector3 raystart, UUID raytargetid,
127 byte rayendisintersection)
128 {
129 int differenceX = (int)m_virtScene.RegionInfo.RegionLocX - (int)m_rootScene.RegionInfo.RegionLocX;
130 int differenceY = (int)m_virtScene.RegionInfo.RegionLocY - (int)m_rootScene.RegionInfo.RegionLocY;
131 rayend.X += differenceX * (int)Constants.RegionSize;
132 rayend.Y += differenceY * (int)Constants.RegionSize;
133 raystart.X += differenceX * (int)Constants.RegionSize;
134 raystart.Y += differenceY * (int)Constants.RegionSize;
135 m_rootScene.AddNewPrim(ownerid, groupid, rayend, rot, shape, bypassraycast, raystart, raytargetid,
136 rayendisintersection);
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
new file mode 100644
index 0000000..e5e76e9
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerLargeLandChannel.cs
@@ -0,0 +1,202 @@
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.Generic;
30using System.Reflection;
31using log4net;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.CoreModules.World.Land;
36
37namespace OpenSim.Region.RegionCombinerModule
38{
39 public class RegionCombinerLargeLandChannel : ILandChannel
40 {
41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 private RegionData RegData;
44 private ILandChannel RootRegionLandChannel;
45 private readonly List<RegionData> RegionConnections;
46
47 #region ILandChannel Members
48
49 public RegionCombinerLargeLandChannel(RegionData regData, ILandChannel rootRegionLandChannel,
50 List<RegionData> regionConnections)
51 {
52 RegData = regData;
53 RootRegionLandChannel = rootRegionLandChannel;
54 RegionConnections = regionConnections;
55 }
56
57 public List<ILandObject> ParcelsNearPoint(Vector3 position)
58 {
59 //m_log.DebugFormat("[LANDPARCELNEARPOINT]: {0}>", position);
60 return RootRegionLandChannel.ParcelsNearPoint(position - RegData.Offset);
61 }
62
63 public List<ILandObject> AllParcels()
64 {
65 return RootRegionLandChannel.AllParcels();
66 }
67
68 public void Clear(bool setupDefaultParcel)
69 {
70 RootRegionLandChannel.Clear(setupDefaultParcel);
71 }
72
73 public ILandObject GetLandObject(Vector3 position)
74 {
75 return GetLandObject(position.X, position.Y);
76 }
77
78 public ILandObject GetLandObject(int x, int y)
79 {
80 return GetLandObject((float)x, (float)y);
81
82// m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
83//
84// if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
85// {
86// return RootRegionLandChannel.GetLandObject(x, y);
87// }
88// else
89// {
90// int offsetX = (x / (int)Constants.RegionSize);
91// int offsetY = (y / (int)Constants.RegionSize);
92// offsetX *= (int)Constants.RegionSize;
93// offsetY *= (int)Constants.RegionSize;
94//
95// foreach (RegionData regionData in RegionConnections)
96// {
97// if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
98// {
99// m_log.DebugFormat(
100// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
101// regionData.RegionScene.Name, offsetX, offsetY);
102//
103// return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
104// }
105// }
106// //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
107// //obj.LandData.Name = "NO LAND";
108// //return obj;
109// }
110//
111// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
112//
113// return null;
114 }
115
116 public ILandObject GetLandObject(int localID)
117 {
118 // XXX: Possibly should be looking in every land channel, not just the root.
119 return RootRegionLandChannel.GetLandObject(localID);
120 }
121
122 public ILandObject GetLandObject(float x, float y)
123 {
124// m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y);
125
126 if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize)
127 {
128 return RootRegionLandChannel.GetLandObject(x, y);
129 }
130 else
131 {
132 int offsetX = (int)(x/(int) Constants.RegionSize);
133 int offsetY = (int)(y/(int) Constants.RegionSize);
134 offsetX *= (int) Constants.RegionSize;
135 offsetY *= (int) Constants.RegionSize;
136
137 foreach (RegionData regionData in RegionConnections)
138 {
139 if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY)
140 {
141// m_log.DebugFormat(
142// "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}",
143// regionData.RegionScene.Name, offsetX, offsetY);
144
145 return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY);
146 }
147 }
148
149// ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene);
150// obj.LandData.Name = "NO LAND";
151// return obj;
152 }
153
154// m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y);
155
156 return null;
157 }
158
159 public bool IsForcefulBansAllowed()
160 {
161 return RootRegionLandChannel.IsForcefulBansAllowed();
162 }
163
164 public void UpdateLandObject(int localID, LandData data)
165 {
166 RootRegionLandChannel.UpdateLandObject(localID, data);
167 }
168
169 public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
170 {
171 RootRegionLandChannel.Join(start_x, start_y, end_x, end_y, attempting_user_id);
172 }
173
174 public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
175 {
176 RootRegionLandChannel.Subdivide(start_x, start_y, end_x, end_y, attempting_user_id);
177 }
178
179 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
180 {
181 RootRegionLandChannel.ReturnObjectsInParcel(localID, returnType, agentIDs, taskIDs, remoteClient);
182 }
183
184 public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
185 {
186 RootRegionLandChannel.setParcelObjectMaxOverride(overrideDel);
187 }
188
189 public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
190 {
191 RootRegionLandChannel.setSimulatorObjectMaxOverride(overrideDel);
192 }
193
194 public void SetParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
195 {
196 RootRegionLandChannel.SetParcelOtherCleanTime(remoteClient, localID, otherCleanTime);
197 }
198
199 public void sendClientInitialLandInfo(IClientAPI remoteClient) { }
200 #endregion
201 }
202} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs
new file mode 100644
index 0000000..98b0ae1
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerModule.cs
@@ -0,0 +1,878 @@
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.Generic;
30using System.Reflection;
31using log4net;
32using Nini.Config;
33using OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Framework.Client;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Console;
39using OpenSim.Region.PhysicsModules.SharedBase;
40using Mono.Addins;
41
42namespace OpenSim.Region.RegionCombinerModule
43{
44 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionCombinerModule")]
45 public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48// private static string LogHeader = "[REGION COMBINER MODULE]";
49
50 public string Name
51 {
52 get { return "RegionCombinerModule"; }
53 }
54
55 public Type ReplaceableInterface
56 {
57 get { return null; }
58 }
59
60 /// <summary>
61 /// Is this module enabled?
62 /// </summary>
63 private bool m_combineContiguousRegions = false;
64
65 /// <summary>
66 /// This holds the root regions for the megaregions.
67 /// </summary>
68 /// <remarks>
69 /// Usually there is only ever one megaregion (and hence only one entry here).
70 /// </remarks>
71 private Dictionary<UUID, RegionConnections> m_regions = new Dictionary<UUID, RegionConnections>();
72
73 /// <summary>
74 /// The scenes that comprise the megaregion.
75 /// </summary>
76 private Dictionary<UUID, Scene> m_startingScenes = new Dictionary<UUID, Scene>();
77
78 public void Initialise(IConfigSource source)
79 {
80 IConfig myConfig = source.Configs["Startup"];
81 m_combineContiguousRegions = myConfig.GetBoolean("CombineContiguousRegions", false);
82
83 MainConsole.Instance.Commands.AddCommand(
84 "RegionCombinerModule", false, "fix-phantoms", "fix-phantoms",
85 "Fixes phantom objects after an import to a megaregion or a change from a megaregion back to normal regions",
86 FixPhantoms);
87 }
88
89 public void Close()
90 {
91 }
92
93 public void AddRegion(Scene scene)
94 {
95 if (m_combineContiguousRegions)
96 scene.RegisterModuleInterface<IRegionCombinerModule>(this);
97 }
98
99 public void RemoveRegion(Scene scene)
100 {
101 lock (m_startingScenes)
102 m_startingScenes.Remove(scene.RegionInfo.originRegionID);
103 }
104
105 public void RegionLoaded(Scene scene)
106 {
107 lock (m_startingScenes)
108 m_startingScenes.Add(scene.RegionInfo.originRegionID, scene);
109
110 if (m_combineContiguousRegions)
111 {
112 RegionLoadedDoWork(scene);
113
114 scene.EventManager.OnNewPresence += NewPresence;
115 }
116 }
117
118 public bool IsRootForMegaregion(UUID regionId)
119 {
120 lock (m_regions)
121 return m_regions.ContainsKey(regionId);
122 }
123
124 public Vector2 GetSizeOfMegaregion(UUID regionId)
125 {
126 lock (m_regions)
127 {
128 if (m_regions.ContainsKey(regionId))
129 {
130 RegionConnections rootConn = m_regions[regionId];
131
132 return new Vector2((float)rootConn.XEnd, (float)rootConn.YEnd);
133 }
134 }
135
136 throw new Exception(string.Format("Region with id {0} not found", regionId));
137 }
138
139 // Test to see if this postiion (relative to the region) is within the area covered
140 // by this megaregion.
141 public bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy)
142 {
143 bool ret = false;
144 if (xx < 0 || yy < 0)
145 return ret;
146
147 foreach (RegionConnections rootRegion in m_regions.Values)
148 {
149 if (currentRegion == rootRegion.RegionId)
150 {
151 // The caller is in the root region so this is an easy test
152 if (xx < rootRegion.XEnd && yy < rootRegion.YEnd)
153 {
154 ret = true;
155 }
156 break;
157 }
158 else
159 {
160 // Maybe the caller is in one of the sub-regions
161 foreach (RegionData childRegion in rootRegion.ConnectedRegions)
162 {
163 if (currentRegion == childRegion.RegionId)
164 {
165 // This is a child. Diddle the offsets and check if in
166 Vector3 positionInMegaregion = childRegion.Offset;
167 positionInMegaregion.X += xx;
168 positionInMegaregion.Y += yy;
169 if (positionInMegaregion.X < rootRegion.XEnd && positionInMegaregion.Y < rootRegion.YEnd)
170 {
171 ret = true;
172 }
173 break;
174 }
175 }
176 }
177 }
178
179 return ret;
180 }
181
182 private void NewPresence(ScenePresence presence)
183 {
184 if (presence.IsChildAgent)
185 {
186 byte[] throttleData;
187
188 try
189 {
190 throttleData = presence.ControllingClient.GetThrottlesPacked(1);
191 }
192 catch (NotImplementedException)
193 {
194 return;
195 }
196
197 if (throttleData == null)
198 return;
199
200 if (throttleData.Length == 0)
201 return;
202
203 if (throttleData.Length != 28)
204 return;
205
206 byte[] adjData;
207 int pos = 0;
208
209 if (!BitConverter.IsLittleEndian)
210 {
211 byte[] newData = new byte[7 * 4];
212 Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4);
213
214 for (int i = 0; i < 7; i++)
215 Array.Reverse(newData, i * 4, 4);
216
217 adjData = newData;
218 }
219 else
220 {
221 adjData = throttleData;
222 }
223
224 // 0.125f converts from bits to bytes
225 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
226 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
227 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
228 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
229 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
230 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
231 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
232 // State is a subcategory of task that we allocate a percentage to
233
234
235 //int total = resend + land + wind + cloud + task + texture + asset;
236
237 byte[] data = new byte[7 * 4];
238 int ii = 0;
239
240 Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4;
241 Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4;
242 Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4;
243 Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4;
244 Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4;
245 Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4;
246 Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4);
247
248 try
249 {
250 presence.ControllingClient.SetChildAgentThrottle(data);
251 }
252 catch (NotImplementedException)
253 {
254 return;
255 }
256 }
257 }
258
259 private void RegionLoadedDoWork(Scene scene)
260 {
261/*
262 // For testing on a single instance
263 if (scene.RegionInfo.RegionLocX == 1004 && scene.RegionInfo.RegionLocY == 1000)
264 return;
265 //
266*/
267
268 RegionConnections newConn = new RegionConnections();
269 newConn.ConnectedRegions = new List<RegionData>();
270 newConn.RegionScene = scene;
271 newConn.RegionLandChannel = scene.LandChannel;
272 newConn.RegionId = scene.RegionInfo.originRegionID;
273 newConn.X = scene.RegionInfo.RegionLocX;
274 newConn.Y = scene.RegionInfo.RegionLocY;
275 newConn.XEnd = scene.RegionInfo.RegionSizeX;
276 newConn.YEnd = scene.RegionInfo.RegionSizeX;
277
278 lock (m_regions)
279 {
280 bool connectedYN = false;
281
282 foreach (RegionConnections rootConn in m_regions.Values)
283 {
284 #region commented
285 /*
286 // If we're one region over +x +y
287 //xxy
288 //xxx
289 //xxx
290 if ((((int)conn.X * (int)Constants.RegionSize) + conn.XEnd
291 == (regionConnections.X * (int)Constants.RegionSize))
292 && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd
293 == (regionConnections.Y * (int)Constants.RegionSize)))
294 {
295 Vector3 offset = Vector3.Zero;
296 offset.X = (((regionConnections.X * (int) Constants.RegionSize)) -
297 ((conn.X * (int) Constants.RegionSize)));
298 offset.Y = (((regionConnections.Y * (int) Constants.RegionSize)) -
299 ((conn.Y * (int) Constants.RegionSize)));
300
301 Vector3 extents = Vector3.Zero;
302 extents.Y = regionConnections.YEnd + conn.YEnd;
303 extents.X = conn.XEnd + conn.XEnd;
304
305 m_log.DebugFormat("Scene: {0} to the northwest of Scene{1}. Offset: {2}. Extents:{3}",
306 conn.RegionScene.RegionInfo.RegionName,
307 regionConnections.RegionScene.RegionInfo.RegionName,
308 offset, extents);
309
310 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
311
312 connectedYN = true;
313 break;
314 }
315 */
316
317 /*
318 //If we're one region over x +y
319 //xxx
320 //xxx
321 //xyx
322 if ((((int)conn.X * (int)Constants.RegionSize)
323 == (regionConnections.X * (int)Constants.RegionSize))
324 && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd
325 == (regionConnections.Y * (int)Constants.RegionSize)))
326 {
327 Vector3 offset = Vector3.Zero;
328 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
329 ((conn.X * (int)Constants.RegionSize)));
330 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
331 ((conn.Y * (int)Constants.RegionSize)));
332
333 Vector3 extents = Vector3.Zero;
334 extents.Y = regionConnections.YEnd + conn.YEnd;
335 extents.X = conn.XEnd;
336
337 m_log.DebugFormat("Scene: {0} to the north of Scene{1}. Offset: {2}. Extents:{3}",
338 conn.RegionScene.RegionInfo.RegionName,
339 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
340
341 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
342 connectedYN = true;
343 break;
344 }
345 */
346
347 /*
348 // If we're one region over -x +y
349 //xxx
350 //xxx
351 //yxx
352 if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd
353 == (regionConnections.X * (int)Constants.RegionSize))
354 && (((int)conn.Y * (int)Constants.RegionSize) - conn.YEnd
355 == (regionConnections.Y * (int)Constants.RegionSize)))
356 {
357 Vector3 offset = Vector3.Zero;
358 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
359 ((conn.X * (int)Constants.RegionSize)));
360 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
361 ((conn.Y * (int)Constants.RegionSize)));
362
363 Vector3 extents = Vector3.Zero;
364 extents.Y = regionConnections.YEnd + conn.YEnd;
365 extents.X = conn.XEnd + conn.XEnd;
366
367 m_log.DebugFormat("Scene: {0} to the northeast of Scene. Offset: {2}. Extents:{3}",
368 conn.RegionScene.RegionInfo.RegionName,
369 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
370
371 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
372
373
374 connectedYN = true;
375 break;
376 }
377 */
378
379 /*
380 // If we're one region over -x y
381 //xxx
382 //yxx
383 //xxx
384 if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd
385 == (regionConnections.X * (int)Constants.RegionSize))
386 && (((int)conn.Y * (int)Constants.RegionSize)
387 == (regionConnections.Y * (int)Constants.RegionSize)))
388 {
389 Vector3 offset = Vector3.Zero;
390 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
391 ((conn.X * (int)Constants.RegionSize)));
392 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
393 ((conn.Y * (int)Constants.RegionSize)));
394
395 Vector3 extents = Vector3.Zero;
396 extents.Y = regionConnections.YEnd;
397 extents.X = conn.XEnd + conn.XEnd;
398
399 m_log.DebugFormat("Scene: {0} to the east of Scene{1} Offset: {2}. Extents:{3}",
400 conn.RegionScene.RegionInfo.RegionName,
401 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
402
403 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
404
405 connectedYN = true;
406 break;
407 }
408 */
409
410 /*
411 // If we're one region over -x -y
412 //yxx
413 //xxx
414 //xxx
415 if ((((int)conn.X * (int)Constants.RegionSize) - conn.XEnd
416 == (regionConnections.X * (int)Constants.RegionSize))
417 && (((int)conn.Y * (int)Constants.RegionSize) + conn.YEnd
418 == (regionConnections.Y * (int)Constants.RegionSize)))
419 {
420 Vector3 offset = Vector3.Zero;
421 offset.X = (((regionConnections.X * (int)Constants.RegionSize)) -
422 ((conn.X * (int)Constants.RegionSize)));
423 offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) -
424 ((conn.Y * (int)Constants.RegionSize)));
425
426 Vector3 extents = Vector3.Zero;
427 extents.Y = regionConnections.YEnd + conn.YEnd;
428 extents.X = conn.XEnd + conn.XEnd;
429
430 m_log.DebugFormat("Scene: {0} to the northeast of Scene{1} Offset: {2}. Extents:{3}",
431 conn.RegionScene.RegionInfo.RegionName,
432 regionConnections.RegionScene.RegionInfo.RegionName, offset, extents);
433
434 scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, extents);
435
436 connectedYN = true;
437 break;
438 }
439 */
440 #endregion
441
442
443 // Check to see if this new region is adjacent to the root region.
444 // Note that we expect the regions to be combined from the root region outward
445 // thus the requirement for the ordering in the configuration files.
446
447 // If we're one region over +x y (i.e. root region is to the west)
448 //xxx
449 //xxy
450 //xxx
451 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY)
452 {
453 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
454 break;
455 }
456
457 // If we're one region over x +y (i.e. root region is to the south)
458 //xyx
459 //xxx
460 //xxx
461 if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
462 {
463 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
464 break;
465 }
466
467 // If we're one region over +x +y (i.e. root region is to the south-west)
468 //xxy
469 //xxx
470 //xxx
471 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
472 {
473 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
474 break;
475 }
476 }
477
478 // If !connectYN means that this region is a root region
479 if (!connectedYN)
480 {
481 DoWorkForRootRegion(newConn, scene);
482 }
483 }
484 }
485
486 private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
487 {
488 // Offset (in meters) from the base of this region to the base of the root region.
489 Vector3 offset = Vector3.Zero;
490 offset.X = newConn.PosX - rootConn.PosX;
491 offset.Y = newConn.PosY - rootConn.PosY;
492
493 // The new total size of the region (in meters)
494 // We just extend the X and Y dimensions so the extent might temporarily include areas without regions.
495 Vector3 extents = Vector3.Zero;
496 extents.X = Math.Max(rootConn.XEnd, offset.X + newConn.RegionScene.RegionInfo.RegionSizeX);
497 extents.Y = Math.Max(rootConn.YEnd, offset.Y + newConn.RegionScene.RegionInfo.RegionSizeY);
498
499 rootConn.UpdateExtents(extents);
500
501 m_log.DebugFormat(
502 "[REGION COMBINER MODULE]: Root region {0} is to the west of region {1}, Offset: {2}, Extents: {3}",
503 rootConn.RegionScene.RegionInfo.RegionName,
504 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
505
506 RegionData ConnectedRegion = new RegionData();
507 ConnectedRegion.Offset = offset;
508 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
509 ConnectedRegion.RegionScene = scene;
510 rootConn.ConnectedRegions.Add(ConnectedRegion);
511
512 // Inform root region Physics about the extents of this region
513 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
514
515 // Inform Child region that it needs to forward it's terrain to the root region
516 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
517
518 // Reset Terrain.. since terrain loads before we get here, we need to load
519 // it again so it loads in the root region
520 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
521
522 // Create a client event forwarder and add this region's events to the root region.
523 if (rootConn.ClientEventForwarder != null)
524 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
525
526 return true;
527 }
528
529 /*
530 * 20140215 radams1: The border stuff was removed and the addition of regions to the mega-regions
531 * was generalized. These functions are not needed for the generalized solution but left for reference.
532 private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
533 {
534 Vector3 offset = Vector3.Zero;
535 offset.X = newConn.PosX - rootConn.PosX;
536 offset.Y = newConn.PosY - rootConn.PosY;
537
538 Vector3 extents = Vector3.Zero;
539 extents.Y = newConn.YEnd + rootConn.YEnd;
540 extents.X = rootConn.XEnd;
541 rootConn.UpdateExtents(extents);
542
543 RegionData ConnectedRegion = new RegionData();
544 ConnectedRegion.Offset = offset;
545 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
546 ConnectedRegion.RegionScene = scene;
547 rootConn.ConnectedRegions.Add(ConnectedRegion);
548
549 m_log.DebugFormat(
550 "[REGION COMBINER MODULE]: Root region {0} is to the south of region {1}, Offset: {2}, Extents: {3}",
551 rootConn.RegionScene.RegionInfo.RegionName,
552 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
553
554 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
555 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
556
557 // Reset Terrain.. since terrain normally loads first.
558 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
559 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
560 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
561
562 if (rootConn.ClientEventForwarder != null)
563 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
564
565 return true;
566 }
567
568 private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
569 {
570 Vector3 offset = Vector3.Zero;
571 offset.X = newConn.PosX - rootConn.PosX;
572 offset.Y = newConn.PosY - rootConn.PosY;
573
574 Vector3 extents = Vector3.Zero;
575
576 // We do not want to inflate the extents for regions strictly to the NE of the root region, since this
577 // would double count regions strictly to the north and east that have already been added.
578// extents.Y = regionConnections.YEnd + conn.YEnd;
579// extents.X = regionConnections.XEnd + conn.XEnd;
580// conn.UpdateExtents(extents);
581
582 extents.Y = rootConn.YEnd;
583 extents.X = rootConn.XEnd;
584
585 RegionData ConnectedRegion = new RegionData();
586 ConnectedRegion.Offset = offset;
587 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
588 ConnectedRegion.RegionScene = scene;
589
590 rootConn.ConnectedRegions.Add(ConnectedRegion);
591
592 m_log.DebugFormat(
593 "[REGION COMBINER MODULE]: Region {0} is to the southwest of Scene {1}, Offset: {2}, Extents: {3}",
594 rootConn.RegionScene.RegionInfo.RegionName,
595 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
596
597 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
598 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
599
600 // Reset Terrain.. since terrain normally loads first.
601 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
602 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
603 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
604
605 if (rootConn.ClientEventForwarder != null)
606 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
607
608 return true;
609
610 //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);
611 }
612 */
613
614 private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene)
615 {
616 m_log.DebugFormat("[REGION COMBINER MODULE]: Adding root region {0}", scene.RegionInfo.RegionName);
617
618 RegionData rdata = new RegionData();
619 rdata.Offset = Vector3.Zero;
620 rdata.RegionId = scene.RegionInfo.originRegionID;
621 rdata.RegionScene = scene;
622 // save it's land channel
623 rootConn.RegionLandChannel = scene.LandChannel;
624
625 // Substitue our landchannel
626 RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel,
627 rootConn.ConnectedRegions);
628
629 scene.LandChannel = lnd;
630
631 // Forward the permissions modules of each of the connected regions to the root region
632 lock (m_regions)
633 {
634 foreach (RegionData r in rootConn.ConnectedRegions)
635 {
636 ForwardPermissionRequests(rootConn, r.RegionScene);
637 }
638
639 // Create the root region's Client Event Forwarder
640 rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn);
641
642 // Sets up the CoarseLocationUpdate forwarder for this root region
643 scene.EventManager.OnNewPresence += SetCoarseLocationDelegate;
644
645 // Adds this root region to a dictionary of regions that are connectable
646 m_regions.Add(scene.RegionInfo.originRegionID, rootConn);
647 }
648 }
649
650 private void SetCoarseLocationDelegate(ScenePresence presence)
651 {
652 presence.SetSendCoarseLocationMethod(SendCoarseLocationUpdates);
653 }
654
655 // This delegate was refactored for non-combined regions.
656 // This combined region version will not use the pre-compiled lists of locations and ids
657 private void SendCoarseLocationUpdates(UUID sceneId, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
658 {
659 RegionConnections connectiondata = null;
660 lock (m_regions)
661 {
662 if (m_regions.ContainsKey(sceneId))
663 connectiondata = m_regions[sceneId];
664 else
665 return;
666 }
667
668 List<Vector3> CoarseLocations = new List<Vector3>();
669 List<UUID> AvatarUUIDs = new List<UUID>();
670
671 connectiondata.RegionScene.ForEachRootScenePresence(delegate(ScenePresence sp)
672 {
673 if (sp.UUID != presence.UUID)
674 {
675 CoarseLocations.Add(sp.AbsolutePosition);
676 AvatarUUIDs.Add(sp.UUID);
677 }
678 });
679
680 DistributeCoarseLocationUpdates(CoarseLocations, AvatarUUIDs, connectiondata, presence);
681 }
682
683 private void DistributeCoarseLocationUpdates(List<Vector3> locations, List<UUID> uuids,
684 RegionConnections connectiondata, ScenePresence rootPresence)
685 {
686 RegionData[] rdata = connectiondata.ConnectedRegions.ToArray();
687 //List<IClientAPI> clients = new List<IClientAPI>();
688 Dictionary<Vector2, RegionCoarseLocationStruct> updates = new Dictionary<Vector2, RegionCoarseLocationStruct>();
689
690 // Root Region entry
691 RegionCoarseLocationStruct rootupdatedata = new RegionCoarseLocationStruct();
692 rootupdatedata.Locations = new List<Vector3>();
693 rootupdatedata.Uuids = new List<UUID>();
694 rootupdatedata.Offset = Vector2.Zero;
695
696 rootupdatedata.UserAPI = rootPresence.ControllingClient;
697
698 if (rootupdatedata.UserAPI != null)
699 updates.Add(Vector2.Zero, rootupdatedata);
700
701 //Each Region needs an entry or we will end up with dead minimap dots
702 foreach (RegionData regiondata in rdata)
703 {
704 Vector2 offset = new Vector2(regiondata.Offset.X, regiondata.Offset.Y);
705 RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
706 updatedata.Locations = new List<Vector3>();
707 updatedata.Uuids = new List<UUID>();
708 updatedata.Offset = offset;
709
710 if (offset == Vector2.Zero)
711 updatedata.UserAPI = rootPresence.ControllingClient;
712 else
713 updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata);
714
715 if (updatedata.UserAPI != null)
716 updates.Add(offset, updatedata);
717 }
718
719 // go over the locations and assign them to an IClientAPI
720 for (int i = 0; i < locations.Count; i++)
721 //{locations[i]/(int) Constants.RegionSize;
722 {
723 Vector3 pPosition = new Vector3((int)locations[i].X / (int)Constants.RegionSize,
724 (int)locations[i].Y / (int)Constants.RegionSize, locations[i].Z);
725 Vector2 offset = new Vector2(pPosition.X*(int) Constants.RegionSize,
726 pPosition.Y*(int) Constants.RegionSize);
727
728 if (!updates.ContainsKey(offset))
729 {
730 // This shouldn't happen
731 RegionCoarseLocationStruct updatedata = new RegionCoarseLocationStruct();
732 updatedata.Locations = new List<Vector3>();
733 updatedata.Uuids = new List<UUID>();
734 updatedata.Offset = offset;
735
736 if (offset == Vector2.Zero)
737 updatedata.UserAPI = rootPresence.ControllingClient;
738 else
739 updatedata.UserAPI = LocateUsersChildAgentIClientAPI(offset, rootPresence.UUID, rdata);
740
741 updates.Add(offset,updatedata);
742 }
743
744 updates[offset].Locations.Add(locations[i]);
745 updates[offset].Uuids.Add(uuids[i]);
746 }
747
748 // Send out the CoarseLocationupdates from their respective client connection based on where the avatar is
749 foreach (Vector2 offset in updates.Keys)
750 {
751 if (updates[offset].UserAPI != null)
752 {
753 updates[offset].UserAPI.SendCoarseLocationUpdate(updates[offset].Uuids,updates[offset].Locations);
754 }
755 }
756 }
757
758 /// <summary>
759 /// Locates a the Client of a particular region in an Array of RegionData based on offset
760 /// </summary>
761 /// <param name="offset"></param>
762 /// <param name="uUID"></param>
763 /// <param name="rdata"></param>
764 /// <returns>IClientAPI or null</returns>
765 private IClientAPI LocateUsersChildAgentIClientAPI(Vector2 offset, UUID uUID, RegionData[] rdata)
766 {
767 IClientAPI returnclient = null;
768 foreach (RegionData r in rdata)
769 {
770 if (r.Offset.X == offset.X && r.Offset.Y == offset.Y)
771 {
772 return r.RegionScene.SceneGraph.GetControllingClient(uUID);
773 }
774 }
775
776 return returnclient;
777 }
778
779 public void PostInitialise()
780 {
781 }
782
783// /// <summary>
784// /// TODO:
785// /// </summary>
786// /// <param name="rdata"></param>
787// public void UnCombineRegion(RegionData rdata)
788// {
789// lock (m_regions)
790// {
791// if (m_regions.ContainsKey(rdata.RegionId))
792// {
793// // uncombine root region and virtual regions
794// }
795// else
796// {
797// foreach (RegionConnections r in m_regions.Values)
798// {
799// foreach (RegionData rd in r.ConnectedRegions)
800// {
801// if (rd.RegionId == rdata.RegionId)
802// {
803// // uncombine virtual region
804// }
805// }
806// }
807// }
808// }
809// }
810
811 public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion)
812 {
813 if (BigRegion.PermissionModule == null)
814 BigRegion.PermissionModule = new RegionCombinerPermissionModule(BigRegion.RegionScene);
815
816 VirtualRegion.Permissions.OnBypassPermissions += BigRegion.PermissionModule.BypassPermissions;
817 VirtualRegion.Permissions.OnSetBypassPermissions += BigRegion.PermissionModule.SetBypassPermissions;
818 VirtualRegion.Permissions.OnPropagatePermissions += BigRegion.PermissionModule.PropagatePermissions;
819 VirtualRegion.Permissions.OnGenerateClientFlags += BigRegion.PermissionModule.GenerateClientFlags;
820 VirtualRegion.Permissions.OnAbandonParcel += BigRegion.PermissionModule.CanAbandonParcel;
821 VirtualRegion.Permissions.OnReclaimParcel += BigRegion.PermissionModule.CanReclaimParcel;
822 VirtualRegion.Permissions.OnDeedParcel += BigRegion.PermissionModule.CanDeedParcel;
823 VirtualRegion.Permissions.OnDeedObject += BigRegion.PermissionModule.CanDeedObject;
824 VirtualRegion.Permissions.OnIsGod += BigRegion.PermissionModule.IsGod;
825 VirtualRegion.Permissions.OnDuplicateObject += BigRegion.PermissionModule.CanDuplicateObject;
826 VirtualRegion.Permissions.OnDeleteObject += BigRegion.PermissionModule.CanDeleteObject; //MAYBE FULLY IMPLEMENTED
827 VirtualRegion.Permissions.OnEditObject += BigRegion.PermissionModule.CanEditObject; //MAYBE FULLY IMPLEMENTED
828 VirtualRegion.Permissions.OnEditParcelProperties += BigRegion.PermissionModule.CanEditParcelProperties; //MAYBE FULLY IMPLEMENTED
829 VirtualRegion.Permissions.OnInstantMessage += BigRegion.PermissionModule.CanInstantMessage;
830 VirtualRegion.Permissions.OnInventoryTransfer += BigRegion.PermissionModule.CanInventoryTransfer; //NOT YET IMPLEMENTED
831 VirtualRegion.Permissions.OnIssueEstateCommand += BigRegion.PermissionModule.CanIssueEstateCommand; //FULLY IMPLEMENTED
832 VirtualRegion.Permissions.OnMoveObject += BigRegion.PermissionModule.CanMoveObject; //MAYBE FULLY IMPLEMENTED
833 VirtualRegion.Permissions.OnObjectEntry += BigRegion.PermissionModule.CanObjectEntry;
834 VirtualRegion.Permissions.OnReturnObjects += BigRegion.PermissionModule.CanReturnObjects; //NOT YET IMPLEMENTED
835 VirtualRegion.Permissions.OnRezObject += BigRegion.PermissionModule.CanRezObject; //MAYBE FULLY IMPLEMENTED
836 VirtualRegion.Permissions.OnRunConsoleCommand += BigRegion.PermissionModule.CanRunConsoleCommand;
837 VirtualRegion.Permissions.OnRunScript += BigRegion.PermissionModule.CanRunScript; //NOT YET IMPLEMENTED
838 VirtualRegion.Permissions.OnCompileScript += BigRegion.PermissionModule.CanCompileScript;
839 VirtualRegion.Permissions.OnSellParcel += BigRegion.PermissionModule.CanSellParcel;
840 VirtualRegion.Permissions.OnTakeObject += BigRegion.PermissionModule.CanTakeObject;
841 VirtualRegion.Permissions.OnTakeCopyObject += BigRegion.PermissionModule.CanTakeCopyObject;
842 VirtualRegion.Permissions.OnTerraformLand += BigRegion.PermissionModule.CanTerraformLand;
843 VirtualRegion.Permissions.OnLinkObject += BigRegion.PermissionModule.CanLinkObject; //NOT YET IMPLEMENTED
844 VirtualRegion.Permissions.OnDelinkObject += BigRegion.PermissionModule.CanDelinkObject; //NOT YET IMPLEMENTED
845 VirtualRegion.Permissions.OnBuyLand += BigRegion.PermissionModule.CanBuyLand; //NOT YET IMPLEMENTED
846 VirtualRegion.Permissions.OnViewNotecard += BigRegion.PermissionModule.CanViewNotecard; //NOT YET IMPLEMENTED
847 VirtualRegion.Permissions.OnViewScript += BigRegion.PermissionModule.CanViewScript; //NOT YET IMPLEMENTED
848 VirtualRegion.Permissions.OnEditNotecard += BigRegion.PermissionModule.CanEditNotecard; //NOT YET IMPLEMENTED
849 VirtualRegion.Permissions.OnEditScript += BigRegion.PermissionModule.CanEditScript; //NOT YET IMPLEMENTED
850 VirtualRegion.Permissions.OnCreateObjectInventory += BigRegion.PermissionModule.CanCreateObjectInventory; //NOT IMPLEMENTED HERE
851 VirtualRegion.Permissions.OnEditObjectInventory += BigRegion.PermissionModule.CanEditObjectInventory;//MAYBE FULLY IMPLEMENTED
852 VirtualRegion.Permissions.OnCopyObjectInventory += BigRegion.PermissionModule.CanCopyObjectInventory; //NOT YET IMPLEMENTED
853 VirtualRegion.Permissions.OnDeleteObjectInventory += BigRegion.PermissionModule.CanDeleteObjectInventory; //NOT YET IMPLEMENTED
854 VirtualRegion.Permissions.OnResetScript += BigRegion.PermissionModule.CanResetScript;
855 VirtualRegion.Permissions.OnCreateUserInventory += BigRegion.PermissionModule.CanCreateUserInventory; //NOT YET IMPLEMENTED
856 VirtualRegion.Permissions.OnCopyUserInventory += BigRegion.PermissionModule.CanCopyUserInventory; //NOT YET IMPLEMENTED
857 VirtualRegion.Permissions.OnEditUserInventory += BigRegion.PermissionModule.CanEditUserInventory; //NOT YET IMPLEMENTED
858 VirtualRegion.Permissions.OnDeleteUserInventory += BigRegion.PermissionModule.CanDeleteUserInventory; //NOT YET IMPLEMENTED
859 VirtualRegion.Permissions.OnTeleport += BigRegion.PermissionModule.CanTeleport; //NOT YET IMPLEMENTED
860 }
861
862 #region console commands
863
864 public void FixPhantoms(string module, string[] cmdparams)
865 {
866 List<Scene> scenes = new List<Scene>(m_startingScenes.Values);
867
868 foreach (Scene s in scenes)
869 {
870 MainConsole.Instance.OutputFormat("Fixing phantoms for {0}", s.RegionInfo.RegionName);
871
872 s.ForEachSOG(so => so.AbsolutePosition = so.AbsolutePosition);
873 }
874 }
875
876 #endregion
877 }
878}
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs
new file mode 100644
index 0000000..ddfe3e0
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCombinerPermissionModule.cs
@@ -0,0 +1,270 @@
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.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.RegionCombinerModule
36{
37 public class RegionCombinerPermissionModule
38 {
39 private Scene m_rootScene;
40
41 public RegionCombinerPermissionModule(Scene RootScene)
42 {
43 m_rootScene = RootScene;
44 }
45
46 #region Permission Override
47
48 public bool BypassPermissions()
49 {
50 return m_rootScene.Permissions.BypassPermissions();
51 }
52
53 public void SetBypassPermissions(bool value)
54 {
55 m_rootScene.Permissions.SetBypassPermissions(value);
56 }
57
58 public bool PropagatePermissions()
59 {
60 return m_rootScene.Permissions.PropagatePermissions();
61 }
62
63 public uint GenerateClientFlags(UUID userid, UUID objectidid)
64 {
65 return m_rootScene.Permissions.GenerateClientFlags(userid,objectidid);
66 }
67
68 public bool CanAbandonParcel(UUID user, ILandObject parcel, Scene scene)
69 {
70 return m_rootScene.Permissions.CanAbandonParcel(user,parcel);
71 }
72
73 public bool CanReclaimParcel(UUID user, ILandObject parcel, Scene scene)
74 {
75 return m_rootScene.Permissions.CanReclaimParcel(user, parcel);
76 }
77
78 public bool CanDeedParcel(UUID user, ILandObject parcel, Scene scene)
79 {
80 return m_rootScene.Permissions.CanDeedParcel(user, parcel);
81 }
82
83 public bool CanDeedObject(UUID user, UUID @group, Scene scene)
84 {
85 return m_rootScene.Permissions.CanDeedObject(user,@group);
86 }
87
88 public bool IsGod(UUID user, Scene requestfromscene)
89 {
90 return m_rootScene.Permissions.IsGod(user);
91 }
92
93 public bool CanDuplicateObject(int objectcount, UUID objectid, UUID owner, Scene scene, Vector3 objectposition)
94 {
95 return m_rootScene.Permissions.CanDuplicateObject(objectcount, objectid, owner, objectposition);
96 }
97
98 public bool CanDeleteObject(UUID objectid, UUID deleter, Scene scene)
99 {
100 return m_rootScene.Permissions.CanDeleteObject(objectid, deleter);
101 }
102
103 public bool CanEditObject(UUID objectid, UUID editorid, Scene scene)
104 {
105 return m_rootScene.Permissions.CanEditObject(objectid, editorid);
106 }
107
108 public bool CanEditParcelProperties(UUID user, ILandObject parcel, GroupPowers g, Scene scene, bool allowManager)
109 {
110 return m_rootScene.Permissions.CanEditParcelProperties(user, parcel, g, allowManager);
111 }
112
113 public bool CanInstantMessage(UUID user, UUID target, Scene startscene)
114 {
115 return m_rootScene.Permissions.CanInstantMessage(user, target);
116 }
117
118 public bool CanInventoryTransfer(UUID user, UUID target, Scene startscene)
119 {
120 return m_rootScene.Permissions.CanInventoryTransfer(user, target);
121 }
122
123 public bool CanIssueEstateCommand(UUID user, Scene requestfromscene, bool ownercommand)
124 {
125 return m_rootScene.Permissions.CanIssueEstateCommand(user, ownercommand);
126 }
127
128 public bool CanMoveObject(UUID objectid, UUID moverid, Scene scene)
129 {
130 return m_rootScene.Permissions.CanMoveObject(objectid, moverid);
131 }
132
133 public bool CanObjectEntry(UUID objectid, bool enteringregion, Vector3 newpoint, Scene scene)
134 {
135 return m_rootScene.Permissions.CanObjectEntry(objectid, enteringregion, newpoint);
136 }
137
138 public bool CanReturnObjects(ILandObject land, UUID user, List<SceneObjectGroup> objects, Scene scene)
139 {
140 return m_rootScene.Permissions.CanReturnObjects(land, user, objects);
141 }
142
143 public bool CanRezObject(int objectcount, UUID owner, Vector3 objectposition, Scene scene)
144 {
145 return m_rootScene.Permissions.CanRezObject(objectcount, owner, objectposition);
146 }
147
148 public bool CanRunConsoleCommand(UUID user, Scene requestfromscene)
149 {
150 return m_rootScene.Permissions.CanRunConsoleCommand(user);
151 }
152
153 public bool CanRunScript(UUID script, UUID objectid, UUID user, Scene scene)
154 {
155 return m_rootScene.Permissions.CanRunScript(script, objectid, user);
156 }
157
158 public bool CanCompileScript(UUID owneruuid, int scripttype, Scene scene)
159 {
160 return m_rootScene.Permissions.CanCompileScript(owneruuid, scripttype);
161 }
162
163 public bool CanSellParcel(UUID user, ILandObject parcel, Scene scene)
164 {
165 return m_rootScene.Permissions.CanSellParcel(user, parcel);
166 }
167
168 public bool CanTakeObject(UUID objectid, UUID stealer, Scene scene)
169 {
170 return m_rootScene.Permissions.CanTakeObject(objectid, stealer);
171 }
172
173 public bool CanTakeCopyObject(UUID objectid, UUID userid, Scene inscene)
174 {
175 return m_rootScene.Permissions.CanTakeObject(objectid, userid);
176 }
177
178 public bool CanTerraformLand(UUID user, Vector3 position, Scene requestfromscene)
179 {
180 return m_rootScene.Permissions.CanTerraformLand(user, position);
181 }
182
183 public bool CanLinkObject(UUID user, UUID objectid)
184 {
185 return m_rootScene.Permissions.CanLinkObject(user, objectid);
186 }
187
188 public bool CanDelinkObject(UUID user, UUID objectid)
189 {
190 return m_rootScene.Permissions.CanDelinkObject(user, objectid);
191 }
192
193 public bool CanBuyLand(UUID user, ILandObject parcel, Scene scene)
194 {
195 return m_rootScene.Permissions.CanBuyLand(user, parcel);
196 }
197
198 public bool CanViewNotecard(UUID script, UUID objectid, UUID user, Scene scene)
199 {
200 return m_rootScene.Permissions.CanViewNotecard(script, objectid, user);
201 }
202
203 public bool CanViewScript(UUID script, UUID objectid, UUID user, Scene scene)
204 {
205 return m_rootScene.Permissions.CanViewScript(script, objectid, user);
206 }
207
208 public bool CanEditNotecard(UUID notecard, UUID objectid, UUID user, Scene scene)
209 {
210 return m_rootScene.Permissions.CanEditNotecard(notecard, objectid, user);
211 }
212
213 public bool CanEditScript(UUID script, UUID objectid, UUID user, Scene scene)
214 {
215 return m_rootScene.Permissions.CanEditScript(script, objectid, user);
216 }
217
218 public bool CanCreateObjectInventory(int invtype, UUID objectid, UUID userid)
219 {
220 return m_rootScene.Permissions.CanCreateObjectInventory(invtype, objectid, userid);
221 }
222
223 public bool CanEditObjectInventory(UUID objectid, UUID editorid, Scene scene)
224 {
225 return m_rootScene.Permissions.CanEditObjectInventory(objectid, editorid);
226 }
227
228 public bool CanCopyObjectInventory(UUID itemid, UUID objectid, UUID userid)
229 {
230 return m_rootScene.Permissions.CanCopyObjectInventory(itemid, objectid, userid);
231 }
232
233 public bool CanDeleteObjectInventory(UUID itemid, UUID objectid, UUID userid)
234 {
235 return m_rootScene.Permissions.CanDeleteObjectInventory(itemid, objectid, userid);
236 }
237
238 public bool CanResetScript(UUID prim, UUID script, UUID user, Scene scene)
239 {
240 return m_rootScene.Permissions.CanResetScript(prim, script, user);
241 }
242
243 public bool CanCreateUserInventory(int invtype, UUID userid)
244 {
245 return m_rootScene.Permissions.CanCreateUserInventory(invtype, userid);
246 }
247
248 public bool CanCopyUserInventory(UUID itemid, UUID userid)
249 {
250 return m_rootScene.Permissions.CanCopyUserInventory(itemid, userid);
251 }
252
253 public bool CanEditUserInventory(UUID itemid, UUID userid)
254 {
255 return m_rootScene.Permissions.CanEditUserInventory(itemid, userid);
256 }
257
258 public bool CanDeleteUserInventory(UUID itemid, UUID userid)
259 {
260 return m_rootScene.Permissions.CanDeleteUserInventory(itemid, userid);
261 }
262
263 public bool CanTeleport(UUID userid, Scene scene)
264 {
265 return m_rootScene.Permissions.CanTeleport(userid);
266 }
267
268 #endregion
269 }
270}
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs
new file mode 100644
index 0000000..6bf1c4a
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionConnections.cs
@@ -0,0 +1,94 @@
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.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.RegionCombinerModule
36{
37 public class RegionConnections
38 {
39 /// <summary>
40 /// Root Region ID
41 /// </summary>
42 public UUID RegionId;
43
44 /// <summary>
45 /// Root Region Scene
46 /// </summary>
47 public Scene RegionScene;
48
49 /// <summary>
50 /// LargeLandChannel for combined region
51 /// </summary>
52 public ILandChannel RegionLandChannel;
53
54 /// <summary>
55 /// The x map co-ordinate for this region (where each co-ordinate is a Constants.RegionSize block).
56 /// </summary>
57 public uint X;
58
59 /// <summary>
60 /// The y co-ordinate for this region (where each cor-odinate is a Constants.RegionSize block).
61 /// </summary>
62 public uint Y;
63
64 /// <summary>
65 /// The X meters position of this connection.
66 /// </summary>
67 public uint PosX { get { return Util.RegionToWorldLoc(X); } }
68
69 /// <summary>
70 /// The Y meters co-ordinate of this connection.
71 /// </summary>
72 public uint PosY { get { return Util.RegionToWorldLoc(Y); } }
73
74 /// <summary>
75 /// The size of the megaregion in meters.
76 /// </summary>
77 public uint XEnd;
78
79 /// <summary>
80 /// The size of the megaregion in meters.
81 /// </summary>
82 public uint YEnd;
83
84 public List<RegionData> ConnectedRegions;
85 public RegionCombinerPermissionModule PermissionModule;
86 public RegionCombinerClientEventForwarder ClientEventForwarder;
87
88 public void UpdateExtents(Vector3 extents)
89 {
90 XEnd = (uint)extents.X;
91 YEnd = (uint)extents.Y;
92 }
93 }
94}
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs
new file mode 100644
index 0000000..224ac99
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionCourseLocation.cs
@@ -0,0 +1,43 @@
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.Generic;
30using OpenMetaverse;
31using OpenSim.Framework;
32
33namespace OpenSim.Region.RegionCombinerModule
34{
35
36 struct RegionCoarseLocationStruct
37 {
38 public List<Vector3> Locations;
39 public List<UUID> Uuids;
40 public IClientAPI UserAPI;
41 public Vector2 Offset;
42 }
43} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs
new file mode 100644
index 0000000..42fca9f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/RegionCombinerModule/RegionData.cs
@@ -0,0 +1,40 @@
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 OpenMetaverse;
29using OpenSim.Region.Framework.Scenes;
30
31namespace OpenSim.Region.RegionCombinerModule
32{
33 public class RegionData
34 {
35 public UUID RegionId;
36 public Scene RegionScene;
37 // Offset of this region from the base of the root region.
38 public Vector3 Offset;
39 }
40} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs b/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs
deleted file mode 100755
index ff4afbf..0000000
--- a/OpenSim/Region/OptionalModules/Scripting/ExtendedPhysics/ExtendedPhysics.cs
+++ /dev/null
@@ -1,623 +0,0 @@
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 copyrightD
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 */
27using System;
28using System.Collections.Generic;
29using System.Linq;
30using System.Reflection;
31using System.Text;
32using System.Threading;
33
34using OpenSim.Framework;
35using OpenSim.Region.CoreModules;
36using OpenSim.Region.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Region.Physics.Manager;
40
41using Mono.Addins;
42using Nini.Config;
43using log4net;
44using OpenMetaverse;
45
46namespace OpenSim.Region.OptionalModules.Scripting
47{
48[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49public class ExtendedPhysics : INonSharedRegionModule
50{
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 private static string LogHeader = "[EXTENDED PHYSICS]";
53
54 // =============================================================
55 // Since BulletSim is a plugin, this these values aren't defined easily in one place.
56 // This table must correspond to an identical table in BSScene.
57
58 // Per scene functions. See BSScene.
59
60 // Per avatar functions. See BSCharacter.
61
62 // Per prim functions. See BSPrim.
63 public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
64 public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
65 public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed";
66 public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType";
67 public const string PhysFunctGetLinkType = "BulletSim.GetLinkType";
68 public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams";
69 public const string PhysFunctAxisLockLimits = "BulletSim.AxisLockLimits";
70
71 // =============================================================
72
73 private IConfig Configuration { get; set; }
74 private bool Enabled { get; set; }
75 private Scene BaseScene { get; set; }
76 private IScriptModuleComms Comms { get; set; }
77
78 #region INonSharedRegionModule
79
80 public string Name { get { return this.GetType().Name; } }
81
82 public void Initialise(IConfigSource config)
83 {
84 BaseScene = null;
85 Enabled = false;
86 Configuration = null;
87 Comms = null;
88
89 try
90 {
91 if ((Configuration = config.Configs["ExtendedPhysics"]) != null)
92 {
93 Enabled = Configuration.GetBoolean("Enabled", Enabled);
94 }
95 }
96 catch (Exception e)
97 {
98 m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e);
99 }
100
101 m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not"));
102 }
103
104 public void Close()
105 {
106 if (BaseScene != null)
107 {
108 BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
109 BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated;
110 BaseScene = null;
111 }
112 }
113
114 public void AddRegion(Scene scene)
115 {
116 }
117
118 public void RemoveRegion(Scene scene)
119 {
120 if (BaseScene != null && BaseScene == scene)
121 {
122 Close();
123 }
124 }
125
126 public void RegionLoaded(Scene scene)
127 {
128 if (!Enabled) return;
129
130 BaseScene = scene;
131
132 Comms = BaseScene.RequestModuleInterface<IScriptModuleComms>();
133 if (Comms == null)
134 {
135 m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader);
136 Enabled = false;
137
138 return;
139 }
140
141 // Register as LSL functions all the [ScriptInvocation] marked methods.
142 Comms.RegisterScriptInvocations(this);
143 Comms.RegisterConstants(this);
144
145 // When an object is modified, we might need to update its extended physics parameters
146 BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
147 BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated;
148
149 }
150
151 public Type ReplaceableInterface { get { return null; } }
152
153 #endregion // INonSharedRegionModule
154
155 private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
156 {
157 }
158
159 // Event generated when some property of a prim changes.
160 private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate)
161 {
162 }
163
164 [ScriptConstant]
165 public const int PHYS_CENTER_OF_MASS = 1 << 0;
166
167 [ScriptInvocation]
168 public string physGetEngineType(UUID hostID, UUID scriptID)
169 {
170 string ret = string.Empty;
171
172 if (BaseScene.PhysicsScene != null)
173 {
174 ret = BaseScene.PhysicsScene.EngineType;
175 }
176
177 return ret;
178 }
179
180 // Code for specifying params.
181 // The choice if 14700 is arbitrary and only serves to catch parameter code misuse.
182 [ScriptConstant]
183 public const int PHYS_AXIS_LOCK_LINEAR = 14700;
184 [ScriptConstant]
185 public const int PHYS_AXIS_LOCK_LINEAR_X = 14701;
186 [ScriptConstant]
187 public const int PHYS_AXIS_LIMIT_LINEAR_X = 14702;
188 [ScriptConstant]
189 public const int PHYS_AXIS_LOCK_LINEAR_Y = 14703;
190 [ScriptConstant]
191 public const int PHYS_AXIS_LIMIT_LINEAR_Y = 14704;
192 [ScriptConstant]
193 public const int PHYS_AXIS_LOCK_LINEAR_Z = 14705;
194 [ScriptConstant]
195 public const int PHYS_AXIS_LIMIT_LINEAR_Z = 14706;
196 [ScriptConstant]
197 public const int PHYS_AXIS_LOCK_ANGULAR = 14707;
198 [ScriptConstant]
199 public const int PHYS_AXIS_LOCK_ANGULAR_X = 14708;
200 [ScriptConstant]
201 public const int PHYS_AXIS_LIMIT_ANGULAR_X = 14709;
202 [ScriptConstant]
203 public const int PHYS_AXIS_LOCK_ANGULAR_Y = 14710;
204 [ScriptConstant]
205 public const int PHYS_AXIS_LIMIT_ANGULAR_Y = 14711;
206 [ScriptConstant]
207 public const int PHYS_AXIS_LOCK_ANGULAR_Z = 14712;
208 [ScriptConstant]
209 public const int PHYS_AXIS_LIMIT_ANGULAR_Z = 14713;
210 [ScriptConstant]
211 public const int PHYS_AXIS_UNLOCK_LINEAR = 14714;
212 [ScriptConstant]
213 public const int PHYS_AXIS_UNLOCK_LINEAR_X = 14715;
214 [ScriptConstant]
215 public const int PHYS_AXIS_UNLOCK_LINEAR_Y = 14716;
216 [ScriptConstant]
217 public const int PHYS_AXIS_UNLOCK_LINEAR_Z = 14717;
218 [ScriptConstant]
219 public const int PHYS_AXIS_UNLOCK_ANGULAR = 14718;
220 [ScriptConstant]
221 public const int PHYS_AXIS_UNLOCK_ANGULAR_X = 14719;
222 [ScriptConstant]
223 public const int PHYS_AXIS_UNLOCK_ANGULAR_Y = 14720;
224 [ScriptConstant]
225 public const int PHYS_AXIS_UNLOCK_ANGULAR_Z = 14721;
226 [ScriptConstant]
227 public const int PHYS_AXIS_UNLOCK = 14722;
228 // physAxisLockLimits()
229 [ScriptInvocation]
230 public int physAxisLock(UUID hostID, UUID scriptID, object[] parms)
231 {
232 int ret = -1;
233 if (!Enabled) return ret;
234
235 PhysicsActor rootPhysActor;
236 if (GetRootPhysActor(hostID, out rootPhysActor))
237 {
238 object[] parms2 = AddToBeginningOfArray(rootPhysActor, null, parms);
239 ret = MakeIntError(rootPhysActor.Extension(PhysFunctAxisLockLimits, parms2));
240 }
241
242 return ret;
243 }
244
245 [ScriptConstant]
246 public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0;
247 [ScriptConstant]
248 public const int PHYS_LINKSET_TYPE_COMPOUND = 1;
249 [ScriptConstant]
250 public const int PHYS_LINKSET_TYPE_MANUAL = 2;
251
252 [ScriptInvocation]
253 public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
254 {
255 int ret = -1;
256 if (!Enabled) return ret;
257
258 // The part that is requesting the change.
259 SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID);
260
261 if (requestingPart != null)
262 {
263 // The change is always made to the root of a linkset.
264 SceneObjectGroup containingGroup = requestingPart.ParentGroup;
265 SceneObjectPart rootPart = containingGroup.RootPart;
266
267 if (rootPart != null)
268 {
269 PhysicsActor rootPhysActor = rootPart.PhysActor;
270 if (rootPhysActor != null)
271 {
272 if (rootPhysActor.IsPhysical)
273 {
274 // Change a physical linkset by making non-physical, waiting for one heartbeat so all
275 // the prim and linkset state is updated, changing the type and making the
276 // linkset physical again.
277 containingGroup.ScriptSetPhysicsStatus(false);
278 Thread.Sleep(150); // longer than one heartbeat tick
279
280 // A kludge for the moment.
281 // Since compound linksets move the children but don't generate position updates to the
282 // simulator, it is possible for compound linkset children to have out-of-sync simulator
283 // and physical positions. The following causes the simulator to push the real child positions
284 // down into the physics engine to get everything synced.
285 containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition);
286 containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation);
287
288 object[] parms2 = { rootPhysActor, null, linksetType };
289 ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
290 Thread.Sleep(150); // longer than one heartbeat tick
291
292 containingGroup.ScriptSetPhysicsStatus(true);
293 }
294 else
295 {
296 // Non-physical linksets don't have a physical instantiation so there is no state to
297 // worry about being updated.
298 object[] parms2 = { rootPhysActor, null, linksetType };
299 ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
300 }
301 }
302 else
303 {
304 m_log.WarnFormat("{0} physSetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}",
305 LogHeader, rootPart.Name, hostID);
306 }
307 }
308 else
309 {
310 m_log.WarnFormat("{0} physSetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}",
311 LogHeader, requestingPart.Name, hostID);
312 }
313 }
314 else
315 {
316 m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
317 }
318 return ret;
319 }
320
321 [ScriptInvocation]
322 public int physGetLinksetType(UUID hostID, UUID scriptID)
323 {
324 int ret = -1;
325 if (!Enabled) return ret;
326
327 PhysicsActor rootPhysActor;
328 if (GetRootPhysActor(hostID, out rootPhysActor))
329 {
330 object[] parms2 = { rootPhysActor, null };
331 ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2));
332 }
333 else
334 {
335 m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
336 }
337 return ret;
338 }
339
340 [ScriptConstant]
341 public const int PHYS_LINK_TYPE_FIXED = 1234;
342 [ScriptConstant]
343 public const int PHYS_LINK_TYPE_HINGE = 4;
344 [ScriptConstant]
345 public const int PHYS_LINK_TYPE_SPRING = 9;
346 [ScriptConstant]
347 public const int PHYS_LINK_TYPE_6DOF = 6;
348 [ScriptConstant]
349 public const int PHYS_LINK_TYPE_SLIDER = 7;
350
351 // physChangeLinkType(integer linkNum, integer typeCode)
352 [ScriptInvocation]
353 public int physChangeLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode)
354 {
355 int ret = -1;
356 if (!Enabled) return ret;
357
358 PhysicsActor rootPhysActor;
359 PhysicsActor childPhysActor;
360
361 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
362 {
363 object[] parms2 = { rootPhysActor, childPhysActor, typeCode };
364 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
365 }
366
367 return ret;
368 }
369
370 // physGetLinkType(integer linkNum)
371 [ScriptInvocation]
372 public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum)
373 {
374 int ret = -1;
375 if (!Enabled) return ret;
376
377 PhysicsActor rootPhysActor;
378 PhysicsActor childPhysActor;
379
380 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
381 {
382 object[] parms2 = { rootPhysActor, childPhysActor };
383 ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms2));
384 }
385
386 return ret;
387 }
388
389 // physChangeLinkFixed(integer linkNum)
390 // Change the link between the root and the linkNum into a fixed, static physical connection.
391 [ScriptInvocation]
392 public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum)
393 {
394 int ret = -1;
395 if (!Enabled) return ret;
396
397 PhysicsActor rootPhysActor;
398 PhysicsActor childPhysActor;
399
400 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
401 {
402 object[] parms2 = { rootPhysActor, childPhysActor , PHYS_LINK_TYPE_FIXED };
403 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
404 }
405
406 return ret;
407 }
408
409 // Code for specifying params.
410 // The choice if 14400 is arbitrary and only serves to catch parameter code misuse.
411 public const int PHYS_PARAM_MIN = 14401;
412
413 [ScriptConstant]
414 public const int PHYS_PARAM_FRAMEINA_LOC = 14401;
415 [ScriptConstant]
416 public const int PHYS_PARAM_FRAMEINA_ROT = 14402;
417 [ScriptConstant]
418 public const int PHYS_PARAM_FRAMEINB_LOC = 14403;
419 [ScriptConstant]
420 public const int PHYS_PARAM_FRAMEINB_ROT = 14404;
421 [ScriptConstant]
422 public const int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405;
423 [ScriptConstant]
424 public const int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406;
425 [ScriptConstant]
426 public const int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407;
427 [ScriptConstant]
428 public const int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408;
429 [ScriptConstant]
430 public const int PHYS_PARAM_USE_FRAME_OFFSET = 14409;
431 [ScriptConstant]
432 public const int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410;
433 [ScriptConstant]
434 public const int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411;
435 [ScriptConstant]
436 public const int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412;
437 [ScriptConstant]
438 public const int PHYS_PARAM_CFM = 14413;
439 [ScriptConstant]
440 public const int PHYS_PARAM_ERP = 14414;
441 [ScriptConstant]
442 public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415;
443 [ScriptConstant]
444 public const int PHYS_PARAM_SPRING_AXIS_ENABLE = 14416;
445 [ScriptConstant]
446 public const int PHYS_PARAM_SPRING_DAMPING = 14417;
447 [ScriptConstant]
448 public const int PHYS_PARAM_SPRING_STIFFNESS = 14418;
449 [ScriptConstant]
450 public const int PHYS_PARAM_LINK_TYPE = 14419;
451 [ScriptConstant]
452 public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420;
453 [ScriptConstant]
454 public const int PHYS_PARAM_SPRING_EQUILIBRIUM_POINT = 14421;
455
456 public const int PHYS_PARAM_MAX = 14421;
457
458 // Used when specifying a parameter that has settings for the three linear and three angular axis
459 [ScriptConstant]
460 public const int PHYS_AXIS_ALL = -1;
461 [ScriptConstant]
462 public const int PHYS_AXIS_LINEAR_ALL = -2;
463 [ScriptConstant]
464 public const int PHYS_AXIS_ANGULAR_ALL = -3;
465 [ScriptConstant]
466 public const int PHYS_AXIS_LINEAR_X = 0;
467 [ScriptConstant]
468 public const int PHYS_AXIS_LINEAR_Y = 1;
469 [ScriptConstant]
470 public const int PHYS_AXIS_LINEAR_Z = 2;
471 [ScriptConstant]
472 public const int PHYS_AXIS_ANGULAR_X = 3;
473 [ScriptConstant]
474 public const int PHYS_AXIS_ANGULAR_Y = 4;
475 [ScriptConstant]
476 public const int PHYS_AXIS_ANGULAR_Z = 5;
477
478 // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...])
479 [ScriptInvocation]
480 public int physChangeLinkParams(UUID hostID, UUID scriptID, int linkNum, object[] parms)
481 {
482 int ret = -1;
483 if (!Enabled) return ret;
484
485 PhysicsActor rootPhysActor;
486 PhysicsActor childPhysActor;
487
488 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
489 {
490 object[] parms2 = AddToBeginningOfArray(rootPhysActor, childPhysActor, parms);
491 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2));
492 }
493
494 return ret;
495 }
496
497 private bool GetRootPhysActor(UUID hostID, out PhysicsActor rootPhysActor)
498 {
499 SceneObjectGroup containingGroup;
500 SceneObjectPart rootPart;
501 return GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor);
502 }
503
504 private bool GetRootPhysActor(UUID hostID, out SceneObjectGroup containingGroup, out SceneObjectPart rootPart, out PhysicsActor rootPhysActor)
505 {
506 bool ret = false;
507 rootPhysActor = null;
508 containingGroup = null;
509 rootPart = null;
510
511 SceneObjectPart requestingPart;
512
513 requestingPart = BaseScene.GetSceneObjectPart(hostID);
514 if (requestingPart != null)
515 {
516 // The type is is always on the root of a linkset.
517 containingGroup = requestingPart.ParentGroup;
518 if (containingGroup != null && !containingGroup.IsDeleted)
519 {
520 rootPart = containingGroup.RootPart;
521 if (rootPart != null)
522 {
523 rootPhysActor = rootPart.PhysActor;
524 if (rootPhysActor != null)
525 {
526 ret = true;
527 }
528 else
529 {
530 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
531 LogHeader, rootPart.Name, hostID);
532 }
533 }
534 else
535 {
536 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not exist. RequestingPartName={1}, hostID={2}",
537 LogHeader, requestingPart.Name, hostID);
538 }
539 }
540 else
541 {
542 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Containing group missing or deleted. hostID={1}", LogHeader, hostID);
543 }
544 }
545 else
546 {
547 m_log.WarnFormat("{0} GetRootAndChildPhysActors: cannot find script object in scene. hostID={1}", LogHeader, hostID);
548 }
549
550 return ret;
551 }
552
553 // Find the root and child PhysActors based on the linkNum.
554 // Return 'true' if both are found and returned.
555 private bool GetRootAndChildPhysActors(UUID hostID, int linkNum, out PhysicsActor rootPhysActor, out PhysicsActor childPhysActor)
556 {
557 bool ret = false;
558 rootPhysActor = null;
559 childPhysActor = null;
560
561 SceneObjectGroup containingGroup;
562 SceneObjectPart rootPart;
563
564 if (GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor))
565 {
566 SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum);
567 if (linkPart != null)
568 {
569 childPhysActor = linkPart.PhysActor;
570 if (childPhysActor != null)
571 {
572 ret = true;
573 }
574 else
575 {
576 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}",
577 LogHeader, rootPart.Name, hostID, linkNum);
578 }
579 }
580 else
581 {
582 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}",
583 LogHeader, rootPart.Name, hostID, linkNum);
584 }
585 }
586 else
587 {
588 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
589 LogHeader, rootPart.Name, hostID);
590 }
591
592 return ret;
593 }
594
595 // Return an array of objects with the passed object as the first object of a new array
596 private object[] AddToBeginningOfArray(object firstOne, object secondOne, object[] prevArray)
597 {
598 object[] newArray = new object[2 + prevArray.Length];
599 newArray[0] = firstOne;
600 newArray[1] = secondOne;
601 prevArray.CopyTo(newArray, 2);
602 return newArray;
603 }
604
605 // Extension() returns an object. Convert that object into the integer error we expect to return.
606 private int MakeIntError(object extensionRet)
607 {
608 int ret = -1;
609 if (extensionRet != null)
610 {
611 try
612 {
613 ret = (int)extensionRet;
614 }
615 catch
616 {
617 ret = -1;
618 }
619 }
620 return ret;
621 }
622}
623}
diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
index 5ed1514..47b9c09 100644
--- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SOPObject.cs
@@ -34,7 +34,7 @@ using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object; 36using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object;
37using OpenSim.Region.Physics.Manager; 37using OpenSim.Region.PhysicsModules.SharedBase;
38using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType; 38using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType;
39using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType; 39using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType;
40 40
diff --git a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
index 97133c0..4b7295d 100644
--- a/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/XmlRpcRouterModule/XmlRpcGridRouterModule.cs
@@ -35,7 +35,6 @@ using OpenMetaverse;
35using Mono.Addins; 35using Mono.Addins;
36 36
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
40using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Client; 40using OpenSim.Framework.Client;
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs
new file mode 100644
index 0000000..6a1112c
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/ActiveConnectionsAJAX.cs
@@ -0,0 +1,308 @@
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.Reflection;
32using System.Text;
33using Mono.Data.SqliteClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Monitoring;
39
40namespace OpenSim.Region.UserStatistics
41{
42 public class ActiveConnectionsAJAX : IStatsController
43 {
44 private Vector3 DefaultNeighborPosition = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 70);
45
46 #region IStatsController Members
47
48 public string ReportName
49 {
50 get { return ""; }
51 }
52
53 public Hashtable ProcessModel(Hashtable pParams)
54 {
55 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
56
57 Hashtable nh = new Hashtable();
58 nh.Add("hdata", m_scene);
59
60 return nh;
61 }
62
63 public string RenderView(Hashtable pModelResult)
64 {
65 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
66
67 StringBuilder output = new StringBuilder();
68 HTMLUtil.OL_O(ref output, "");
69 foreach (Scene scene in all_scenes)
70 {
71 HTMLUtil.LI_O(ref output, String.Empty);
72 output.Append(scene.RegionInfo.RegionName);
73 HTMLUtil.OL_O(ref output, String.Empty);
74 scene.ForEachScenePresence(delegate(ScenePresence av)
75 {
76 Dictionary<string, string> queues = new Dictionary<string, string>();
77 if (av.ControllingClient is IStatsCollector)
78 {
79 IStatsCollector isClient = (IStatsCollector)av.ControllingClient;
80 queues = decodeQueueReport(isClient.Report());
81 }
82 HTMLUtil.LI_O(ref output, String.Empty);
83 output.Append(av.Name);
84 output.Append("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
85 output.Append((av.IsChildAgent ? "Child" : "Root"));
86 if (av.AbsolutePosition == DefaultNeighborPosition)
87 {
88 output.Append("<br />Position: ?");
89 }
90 else
91 {
92 output.Append(string.Format("<br /><NOBR>Position: <{0},{1},{2}></NOBR>", (int)av.AbsolutePosition.X,
93 (int)av.AbsolutePosition.Y,
94 (int)av.AbsolutePosition.Z));
95 }
96 Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1));
97
98 HTMLUtil.UL_O(ref output, String.Empty);
99
100 foreach (string throttlename in throttles.Keys)
101 {
102 HTMLUtil.LI_O(ref output, String.Empty);
103 output.Append(throttlename);
104 output.Append(":");
105 output.Append(throttles[throttlename].ToString());
106 if (queues.ContainsKey(throttlename))
107 {
108 output.Append("/");
109 output.Append(queues[throttlename]);
110 }
111 HTMLUtil.LI_C(ref output);
112 }
113 if (queues.ContainsKey("Incoming") && queues.ContainsKey("Outgoing"))
114 {
115 HTMLUtil.LI_O(ref output, "red");
116 output.Append("SEND:");
117 output.Append(queues["Outgoing"]);
118 output.Append("/");
119 output.Append(queues["Incoming"]);
120 HTMLUtil.LI_C(ref output);
121 }
122
123 HTMLUtil.UL_C(ref output);
124 HTMLUtil.LI_C(ref output);
125 });
126 HTMLUtil.OL_C(ref output);
127 }
128 HTMLUtil.OL_C(ref output);
129 return output.ToString();
130 }
131
132 /// <summary>
133 /// Convert active connections information to JSON string. Returns a structure:
134 /// <pre>
135 /// {"regionName": {
136 /// "presenceName": {
137 /// "name": "presenceName",
138 /// "position": "<x,y,z>",
139 /// "isRoot": "false",
140 /// "throttle": {
141 /// },
142 /// "queue": {
143 /// }
144 /// },
145 /// ... // multiple presences in the scene
146 /// },
147 /// ... // multiple regions in the sim
148 /// }
149 ///
150 /// </pre>
151 /// </summary>
152 /// <param name="pModelResult"></param>
153 /// <returns></returns>
154 public string RenderJson(Hashtable pModelResult)
155 {
156 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
157
158 OSDMap regionInfo = new OSDMap();
159 foreach (Scene scene in all_scenes)
160 {
161 OSDMap sceneInfo = new OpenMetaverse.StructuredData.OSDMap();
162 List<ScenePresence> avatarInScene = scene.GetScenePresences();
163 foreach (ScenePresence av in avatarInScene)
164 {
165 OSDMap presenceInfo = new OSDMap();
166 presenceInfo.Add("Name", new OSDString(av.Name));
167
168 Dictionary<string,string> queues = new Dictionary<string, string>();
169 if (av.ControllingClient is IStatsCollector)
170 {
171 IStatsCollector isClient = (IStatsCollector) av.ControllingClient;
172 queues = decodeQueueReport(isClient.Report());
173 }
174 OSDMap queueInfo = new OpenMetaverse.StructuredData.OSDMap();
175 foreach (KeyValuePair<string, string> kvp in queues) {
176 queueInfo.Add(kvp.Key, new OSDString(kvp.Value));
177 }
178 sceneInfo.Add("queues", queueInfo);
179
180 if (av.IsChildAgent)
181 presenceInfo.Add("isRoot", new OSDString("false"));
182 else
183 presenceInfo.Add("isRoot", new OSDString("true"));
184
185 if (av.AbsolutePosition == DefaultNeighborPosition)
186 {
187 presenceInfo.Add("position", new OSDString("<0, 0, 0>"));
188 }
189 else
190 {
191 presenceInfo.Add("position", new OSDString(string.Format("<{0},{1},{2}>",
192 (int)av.AbsolutePosition.X,
193 (int) av.AbsolutePosition.Y,
194 (int) av.AbsolutePosition.Z)) );
195 }
196
197 Dictionary<string, int> throttles = DecodeClientThrottles(av.ControllingClient.GetThrottlesPacked(1));
198 OSDMap throttleInfo = new OpenMetaverse.StructuredData.OSDMap();
199 foreach (string throttlename in throttles.Keys)
200 {
201 throttleInfo.Add(throttlename, new OSDString(throttles[throttlename].ToString()));
202 }
203 presenceInfo.Add("throttle", throttleInfo);
204
205 sceneInfo.Add(av.Name, presenceInfo);
206 }
207 regionInfo.Add(scene.RegionInfo.RegionName, sceneInfo);
208 }
209 return regionInfo.ToString();
210 }
211
212 public Dictionary<string, int> DecodeClientThrottles(byte[] throttle)
213 {
214 Dictionary<string, int> returndict = new Dictionary<string, int>();
215 // From mantis http://opensimulator.org/mantis/view.php?id=1374
216 // it appears that sometimes we are receiving empty throttle byte arrays.
217 // TODO: Investigate this behaviour
218 if (throttle.Length == 0)
219 {
220 return new Dictionary<string, int>();
221 }
222
223 int tResend = -1;
224 int tLand = -1;
225 int tWind = -1;
226 int tCloud = -1;
227 int tTask = -1;
228 int tTexture = -1;
229 int tAsset = -1;
230 int tall = -1;
231 const int singlefloat = 4;
232
233 //Agent Throttle Block contains 7 single floatingpoint values.
234 int j = 0;
235
236 // Some Systems may be big endian...
237 // it might be smart to do this check more often...
238 if (!BitConverter.IsLittleEndian)
239 for (int i = 0; i < 7; i++)
240 Array.Reverse(throttle, j + i * singlefloat, singlefloat);
241
242 // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_
243 // bytes
244 // Convert to integer, since.. the full fp space isn't used.
245 tResend = (int)BitConverter.ToSingle(throttle, j);
246 returndict.Add("Resend", tResend);
247 j += singlefloat;
248 tLand = (int)BitConverter.ToSingle(throttle, j);
249 returndict.Add("Land", tLand);
250 j += singlefloat;
251 tWind = (int)BitConverter.ToSingle(throttle, j);
252 returndict.Add("Wind", tWind);
253 j += singlefloat;
254 tCloud = (int)BitConverter.ToSingle(throttle, j);
255 returndict.Add("Cloud", tCloud);
256 j += singlefloat;
257 tTask = (int)BitConverter.ToSingle(throttle, j);
258 returndict.Add("Task", tTask);
259 j += singlefloat;
260 tTexture = (int)BitConverter.ToSingle(throttle, j);
261 returndict.Add("Texture", tTexture);
262 j += singlefloat;
263 tAsset = (int)BitConverter.ToSingle(throttle, j);
264 returndict.Add("Asset", tAsset);
265
266 tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
267 returndict.Add("All", tall);
268
269 return returndict;
270 }
271 public Dictionary<string,string> decodeQueueReport(string rep)
272 {
273 Dictionary<string, string> returndic = new Dictionary<string, string>();
274 if (rep.Length == 79)
275 {
276 int pos = 1;
277 returndic.Add("All", rep.Substring((6 * pos), 8)); pos++;
278 returndic.Add("Incoming", rep.Substring((7 * pos), 8)); pos++;
279 returndic.Add("Outgoing", rep.Substring((7 * pos) , 8)); pos++;
280 returndic.Add("Resend", rep.Substring((7 * pos) , 8)); pos++;
281 returndic.Add("Land", rep.Substring((7 * pos) , 8)); pos++;
282 returndic.Add("Wind", rep.Substring((7 * pos) , 8)); pos++;
283 returndic.Add("Cloud", rep.Substring((7 * pos) , 8)); pos++;
284 returndic.Add("Task", rep.Substring((7 * pos) , 8)); pos++;
285 returndic.Add("Texture", rep.Substring((7 * pos), 8)); pos++;
286 returndic.Add("Asset", rep.Substring((7 * pos), 8));
287 /*
288 * return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
289 SendQueue.Count(),
290 IncomingPacketQueue.Count,
291 OutgoingPacketQueue.Count,
292 ResendOutgoingPacketQueue.Count,
293 LandOutgoingPacketQueue.Count,
294 WindOutgoingPacketQueue.Count,
295 CloudOutgoingPacketQueue.Count,
296 TaskOutgoingPacketQueue.Count,
297 TextureOutgoingPacketQueue.Count,
298 AssetOutgoingPacketQueue.Count);
299 */
300 }
301
302
303
304 return returndic;
305 }
306 #endregion
307 }
308}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs
new file mode 100644
index 0000000..4a6f7be
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Clients_report.cs
@@ -0,0 +1,329 @@
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.Text;
32using Mono.Data.SqliteClient;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim.Region.Framework.Scenes;
36
37namespace OpenSim.Region.UserStatistics
38{
39 public class Clients_report : IStatsController
40 {
41 #region IStatsController Members
42
43 public string ReportName
44 {
45 get { return "Client"; }
46 }
47
48 /// <summary>
49 /// Return summar information in the form:
50 /// <pre>
51 /// {"totalUsers": "34",
52 /// "totalSessions": "233",
53 /// ...
54 /// }
55 /// </pre>
56 /// </summary>
57 /// <param name="pModelResult"></param>
58 /// <returns></returns>
59 public string RenderJson(Hashtable pModelResult) {
60 stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
61
62 OSDMap summaryInfo = new OpenMetaverse.StructuredData.OSDMap();
63 summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
64 summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
65 summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
66 summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
67 summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
68 summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
69 summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
70 summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
71 return summaryInfo.ToString();
72 }
73
74 public Hashtable ProcessModel(Hashtable pParams)
75 {
76 SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"];
77
78
79 List<ClientVersionData> clidata = new List<ClientVersionData>();
80 List<ClientVersionData> cliRegData = new List<ClientVersionData>();
81 Hashtable regionTotals = new Hashtable();
82
83 Hashtable modeldata = new Hashtable();
84 modeldata.Add("Scenes", pParams["Scenes"]);
85 modeldata.Add("Reports", pParams["Reports"]);
86 int totalclients = 0;
87 int totalregions = 0;
88
89 lock (dbConn)
90 {
91 string sql = "select count(distinct region_id) as regcnt from stats_session_data";
92
93 SqliteCommand cmd = new SqliteCommand(sql, dbConn);
94 SqliteDataReader sdr = cmd.ExecuteReader();
95 if (sdr.HasRows)
96 {
97 sdr.Read();
98 totalregions = Convert.ToInt32(sdr["regcnt"]);
99 }
100
101 sdr.Close();
102 sdr.Dispose();
103
104 sql =
105 "select client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by client_version order by count(*) desc LIMIT 10;";
106
107 cmd = new SqliteCommand(sql, dbConn);
108 sdr = cmd.ExecuteReader();
109 if (sdr.HasRows)
110 {
111 while (sdr.Read())
112 {
113 ClientVersionData udata = new ClientVersionData();
114 udata.version = sdr["client_version"].ToString();
115 udata.count = Convert.ToInt32(sdr["cnt"]);
116 udata.fps = Convert.ToSingle(sdr["simfps"]);
117 clidata.Add(udata);
118 totalclients += udata.count;
119
120 }
121 }
122 sdr.Close();
123 sdr.Dispose();
124
125 if (totalregions > 1)
126 {
127 sql =
128 "select region_id, client_version, count(*) as cnt, avg(avg_sim_fps) as simfps from stats_session_data group by region_id, client_version order by region_id, count(*) desc;";
129 cmd = new SqliteCommand(sql, dbConn);
130
131 sdr = cmd.ExecuteReader();
132
133 if (sdr.HasRows)
134 {
135 while (sdr.Read())
136 {
137 ClientVersionData udata = new ClientVersionData();
138 udata.version = sdr["client_version"].ToString();
139 udata.count = Convert.ToInt32(sdr["cnt"]);
140 udata.fps = Convert.ToSingle(sdr["simfps"]);
141 udata.region_id = UUID.Parse(sdr["region_id"].ToString());
142 cliRegData.Add(udata);
143 }
144 }
145 sdr.Close();
146 sdr.Dispose();
147
148
149 }
150
151 }
152
153 foreach (ClientVersionData cvd in cliRegData)
154 {
155
156 if (regionTotals.ContainsKey(cvd.region_id))
157 {
158 int regiontotal = (int)regionTotals[cvd.region_id];
159 regiontotal += cvd.count;
160 regionTotals[cvd.region_id] = regiontotal;
161 }
162 else
163 {
164 regionTotals.Add(cvd.region_id, cvd.count);
165 }
166
167
168
169 }
170
171 modeldata["ClientData"] = clidata;
172 modeldata["ClientRegionData"] = cliRegData;
173 modeldata["RegionTotals"] = regionTotals;
174 modeldata["Total"] = totalclients;
175
176 return modeldata;
177 }
178
179 public string RenderView(Hashtable pModelResult)
180 {
181 List<ClientVersionData> clidata = (List<ClientVersionData>) pModelResult["ClientData"];
182 int totalclients = (int)pModelResult["Total"];
183 Hashtable regionTotals = (Hashtable) pModelResult["RegionTotals"];
184 List<ClientVersionData> cliRegData = (List<ClientVersionData>) pModelResult["ClientRegionData"];
185 List<Scene> m_scenes = (List<Scene>)pModelResult["Scenes"];
186 Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"];
187
188 const string STYLESHEET =
189 @"
190<STYLE>
191body
192{
193 font-size:15px; font-family:Helvetica, Verdana; color:Black;
194}
195TABLE.defaultr { }
196TR.defaultr { padding: 5px; }
197TD.header { font-weight:bold; padding:5px; }
198TD.content {}
199TD.contentright { text-align: right; }
200TD.contentcenter { text-align: center; }
201TD.align_top { vertical-align: top; }
202</STYLE>
203";
204
205 StringBuilder output = new StringBuilder();
206 HTMLUtil.HtmlHeaders_O(ref output);
207 output.Append(STYLESHEET);
208 HTMLUtil.HtmlHeaders_C(ref output);
209
210 HTMLUtil.AddReportLinks(ref output, reports, "");
211
212 HTMLUtil.TABLE_O(ref output, "defaultr");
213 HTMLUtil.TR_O(ref output, "");
214 HTMLUtil.TD_O(ref output, "header");
215 output.Append("ClientVersion");
216 HTMLUtil.TD_C(ref output);
217 HTMLUtil.TD_O(ref output, "header");
218 output.Append("Count/%");
219 HTMLUtil.TD_C(ref output);
220 HTMLUtil.TD_O(ref output, "header");
221 output.Append("SimFPS");
222 HTMLUtil.TD_C(ref output);
223 HTMLUtil.TR_C(ref output);
224
225 foreach (ClientVersionData cvd in clidata)
226 {
227 HTMLUtil.TR_O(ref output, "");
228 HTMLUtil.TD_O(ref output, "content");
229 string linkhref = "sessions.report?VersionString=" + cvd.version;
230 HTMLUtil.A(ref output, cvd.version, linkhref, "");
231 HTMLUtil.TD_C(ref output);
232 HTMLUtil.TD_O(ref output, "content");
233 output.Append(cvd.count);
234 output.Append("/");
235 if (totalclients > 0)
236 output.Append((((float)cvd.count / (float)totalclients)*100).ToString());
237 else
238 output.Append(0);
239
240 output.Append("%");
241 HTMLUtil.TD_C(ref output);
242 HTMLUtil.TD_O(ref output, "content");
243 output.Append(cvd.fps);
244 HTMLUtil.TD_C(ref output);
245 HTMLUtil.TR_C(ref output);
246 }
247 HTMLUtil.TABLE_C(ref output);
248
249 if (cliRegData.Count > 0)
250 {
251 HTMLUtil.TABLE_O(ref output, "defaultr");
252 HTMLUtil.TR_O(ref output, "");
253 HTMLUtil.TD_O(ref output, "header");
254 output.Append("Region");
255 HTMLUtil.TD_C(ref output);
256 HTMLUtil.TD_O(ref output, "header");
257 output.Append("ClientVersion");
258 HTMLUtil.TD_C(ref output);
259 HTMLUtil.TD_O(ref output, "header");
260 output.Append("Count/%");
261 HTMLUtil.TD_C(ref output);
262 HTMLUtil.TD_O(ref output, "header");
263 output.Append("SimFPS");
264 HTMLUtil.TD_C(ref output);
265 HTMLUtil.TR_C(ref output);
266
267 foreach (ClientVersionData cvd in cliRegData)
268 {
269 HTMLUtil.TR_O(ref output, "");
270 HTMLUtil.TD_O(ref output, "content");
271 output.Append(regionNamefromUUID(m_scenes, cvd.region_id));
272 HTMLUtil.TD_C(ref output);
273 HTMLUtil.TD_O(ref output, "content");
274 output.Append(cvd.version);
275 HTMLUtil.TD_C(ref output);
276 HTMLUtil.TD_O(ref output, "content");
277 output.Append(cvd.count);
278 output.Append("/");
279 if ((int)regionTotals[cvd.region_id] > 0)
280 output.Append((((float)cvd.count / (float)((int)regionTotals[cvd.region_id])) * 100).ToString());
281 else
282 output.Append(0);
283
284 output.Append("%");
285 HTMLUtil.TD_C(ref output);
286 HTMLUtil.TD_O(ref output, "content");
287 output.Append(cvd.fps);
288 HTMLUtil.TD_C(ref output);
289 HTMLUtil.TR_C(ref output);
290 }
291 HTMLUtil.TABLE_C(ref output);
292
293 }
294
295 output.Append("</BODY>");
296 output.Append("</HTML>");
297 return output.ToString();
298 }
299 public string regionNamefromUUID(List<Scene> scenes, UUID region_id)
300 {
301 string returnstring = string.Empty;
302 foreach (Scene sn in scenes)
303 {
304 if (region_id == sn.RegionInfo.originRegionID)
305 {
306 returnstring = sn.RegionInfo.RegionName;
307 break;
308 }
309 }
310
311 if (returnstring.Length == 0)
312 {
313 returnstring = region_id.ToString();
314 }
315
316 return returnstring;
317 }
318
319 #endregion
320 }
321
322 public struct ClientVersionData
323 {
324 public UUID region_id;
325 public string version;
326 public int count;
327 public float fps;
328 }
329}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs
new file mode 100644
index 0000000..fabe3d4
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Default_Report.cs
@@ -0,0 +1,277 @@
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.Reflection;
32using System.Text;
33using Mono.Data.SqliteClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework.Monitoring;
38
39
40namespace OpenSim.Region.UserStatistics
41{
42 public class Default_Report : IStatsController
43 {
44
45 public string ReportName
46 {
47 get { return "Home"; }
48 }
49
50 #region IStatsController Members
51
52 public Hashtable ProcessModel(Hashtable pParams)
53 {
54 SqliteConnection conn = (SqliteConnection)pParams["DatabaseConnection"];
55 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
56
57 stats_default_page_values mData = rep_DefaultReport_data(conn, m_scene);
58 mData.sim_stat_data = (Dictionary<UUID,USimStatsData>)pParams["SimStats"];
59 mData.stats_reports = (Dictionary<string, IStatsController>) pParams["Reports"];
60
61 Hashtable nh = new Hashtable();
62 nh.Add("hdata", mData);
63 nh.Add("Reports", pParams["Reports"]);
64
65 return nh;
66 }
67
68 public string RenderView(Hashtable pModelResult)
69 {
70 stats_default_page_values mData = (stats_default_page_values) pModelResult["hdata"];
71 return rep_Default_report_view(mData);
72 }
73
74 #endregion
75
76 public string rep_Default_report_view(stats_default_page_values values)
77 {
78
79
80 StringBuilder output = new StringBuilder();
81
82
83
84 const string TableClass = "defaultr";
85 const string TRClass = "defaultr";
86 const string TDHeaderClass = "header";
87 const string TDDataClass = "content";
88 //const string TDDataClassRight = "contentright";
89 const string TDDataClassCenter = "contentcenter";
90
91 const string STYLESHEET =
92 @"
93<STYLE>
94body
95{
96 font-size:15px; font-family:Helvetica, Verdana; color:Black;
97}
98TABLE.defaultr { }
99TR.defaultr { padding: 5px; }
100TD.header { font-weight:bold; padding:5px; }
101TD.content {}
102TD.contentright { text-align: right; }
103TD.contentcenter { text-align: center; }
104TD.align_top { vertical-align: top; }
105</STYLE>
106";
107 HTMLUtil.HtmlHeaders_O(ref output);
108
109 HTMLUtil.InsertProtoTypeAJAX(ref output);
110 string[] ajaxUpdaterDivs = new string[3];
111 int[] ajaxUpdaterSeconds = new int[3];
112 string[] ajaxUpdaterReportFragments = new string[3];
113
114 ajaxUpdaterDivs[0] = "activeconnections";
115 ajaxUpdaterSeconds[0] = 10;
116 ajaxUpdaterReportFragments[0] = "activeconnectionsajax.html";
117
118 ajaxUpdaterDivs[1] = "activesimstats";
119 ajaxUpdaterSeconds[1] = 20;
120 ajaxUpdaterReportFragments[1] = "simstatsajax.html";
121
122 ajaxUpdaterDivs[2] = "activelog";
123 ajaxUpdaterSeconds[2] = 5;
124 ajaxUpdaterReportFragments[2] = "activelogajax.html";
125
126 HTMLUtil.InsertPeriodicUpdaters(ref output, ajaxUpdaterDivs, ajaxUpdaterSeconds, ajaxUpdaterReportFragments);
127
128 output.Append(STYLESHEET);
129 HTMLUtil.HtmlHeaders_C(ref output);
130 HTMLUtil.AddReportLinks(ref output, values.stats_reports, "");
131 HTMLUtil.TABLE_O(ref output, TableClass);
132 HTMLUtil.TR_O(ref output, TRClass);
133 HTMLUtil.TD_O(ref output, TDHeaderClass);
134 output.Append("# Users Total");
135 HTMLUtil.TD_C(ref output);
136 HTMLUtil.TD_O(ref output, TDHeaderClass);
137 output.Append("# Sessions Total");
138 HTMLUtil.TD_C(ref output);
139 HTMLUtil.TD_O(ref output, TDHeaderClass);
140 output.Append("Avg Client FPS");
141 HTMLUtil.TD_C(ref output);
142 HTMLUtil.TD_O(ref output, TDHeaderClass);
143 output.Append("Avg Client Mem Use");
144 HTMLUtil.TD_C(ref output);
145 HTMLUtil.TD_O(ref output, TDHeaderClass);
146 output.Append("Avg Sim FPS");
147 HTMLUtil.TD_C(ref output);
148 HTMLUtil.TD_O(ref output, TDHeaderClass);
149 output.Append("Avg Ping");
150 HTMLUtil.TD_C(ref output);
151 HTMLUtil.TD_O(ref output, TDHeaderClass);
152 output.Append("KB Out Total");
153 HTMLUtil.TD_C(ref output);
154 HTMLUtil.TD_O(ref output, TDHeaderClass);
155 output.Append("KB In Total");
156 HTMLUtil.TD_C(ref output);
157 HTMLUtil.TR_C(ref output);
158 HTMLUtil.TR_O(ref output, TRClass);
159 HTMLUtil.TD_O(ref output, TDDataClass);
160 output.Append(values.total_num_users);
161 HTMLUtil.TD_C(ref output);
162 HTMLUtil.TD_O(ref output, TDDataClass);
163 output.Append(values.total_num_sessions);
164 HTMLUtil.TD_C(ref output);
165 HTMLUtil.TD_O(ref output, TDDataClassCenter);
166 output.Append(values.avg_client_fps);
167 HTMLUtil.TD_C(ref output);
168 HTMLUtil.TD_O(ref output, TDDataClassCenter);
169 output.Append(values.avg_client_mem_use);
170 HTMLUtil.TD_C(ref output);
171 HTMLUtil.TD_O(ref output, TDDataClassCenter);
172 output.Append(values.avg_sim_fps);
173 HTMLUtil.TD_C(ref output);
174 HTMLUtil.TD_O(ref output, TDDataClassCenter);
175 output.Append(values.avg_ping);
176 HTMLUtil.TD_C(ref output);
177 HTMLUtil.TD_O(ref output, TDDataClassCenter);
178 output.Append(values.total_kb_out);
179 HTMLUtil.TD_C(ref output);
180 HTMLUtil.TD_O(ref output, TDDataClassCenter);
181 output.Append(values.total_kb_in);
182 HTMLUtil.TD_C(ref output);
183 HTMLUtil.TR_C(ref output);
184 HTMLUtil.TABLE_C(ref output);
185
186 HTMLUtil.HR(ref output, "");
187 HTMLUtil.TABLE_O(ref output, "");
188 HTMLUtil.TR_O(ref output, "");
189 HTMLUtil.TD_O(ref output, "align_top");
190 output.Append("<DIV id=\"activeconnections\">Active Connections loading...</DIV>");
191 HTMLUtil.TD_C(ref output);
192 HTMLUtil.TD_O(ref output, "align_top");
193 output.Append("<DIV id=\"activesimstats\">SimStats loading...</DIV>");
194 output.Append("<DIV id=\"activelog\">ActiveLog loading...</DIV>");
195 HTMLUtil.TD_C(ref output);
196 HTMLUtil.TR_C(ref output);
197 HTMLUtil.TABLE_C(ref output);
198 output.Append("</BODY></HTML>");
199 // TODO: FIXME: template
200 return output.ToString();
201 }
202
203
204
205 public stats_default_page_values rep_DefaultReport_data(SqliteConnection db, List<Scene> m_scene)
206 {
207 stats_default_page_values returnstruct = new stats_default_page_values();
208 returnstruct.all_scenes = m_scene.ToArray();
209 lock (db)
210 {
211 string SQL = @"SELECT COUNT(DISTINCT agent_id) as agents, COUNT(*) as sessions, AVG(avg_fps) as client_fps,
212 AVG(avg_sim_fps) as savg_sim_fps, AVG(avg_ping) as sav_ping, SUM(n_out_kb) as num_in_kb,
213 SUM(n_out_pk) as num_in_packets, SUM(n_in_kb) as num_out_kb, SUM(n_in_pk) as num_out_packets, AVG(mem_use) as sav_mem_use
214 FROM stats_session_data;";
215 SqliteCommand cmd = new SqliteCommand(SQL, db);
216 SqliteDataReader sdr = cmd.ExecuteReader();
217 if (sdr.HasRows)
218 {
219 sdr.Read();
220 returnstruct.total_num_users = Convert.ToInt32(sdr["agents"]);
221 returnstruct.total_num_sessions = Convert.ToInt32(sdr["sessions"]);
222 returnstruct.avg_client_fps = Convert.ToSingle(sdr["client_fps"]);
223 returnstruct.avg_sim_fps = Convert.ToSingle(sdr["savg_sim_fps"]);
224 returnstruct.avg_ping = Convert.ToSingle(sdr["sav_ping"]);
225 returnstruct.total_kb_out = Convert.ToSingle(sdr["num_out_kb"]);
226 returnstruct.total_kb_in = Convert.ToSingle(sdr["num_in_kb"]);
227 returnstruct.avg_client_mem_use = Convert.ToSingle(sdr["sav_mem_use"]);
228
229 }
230 }
231 return returnstruct;
232 }
233
234 /// <summary>
235 /// Return summar information in the form:
236 /// <pre>
237 /// {"totalUsers": "34",
238 /// "totalSessions": "233",
239 /// ...
240 /// }
241 /// </pre>
242 /// </summary>
243 /// <param name="pModelResult"></param>
244 /// <returns></returns>
245 public string RenderJson(Hashtable pModelResult) {
246 stats_default_page_values values = (stats_default_page_values) pModelResult["hdata"];
247
248 OSDMap summaryInfo = new OSDMap();
249 summaryInfo.Add("totalUsers", new OSDString(values.total_num_users.ToString()));
250 summaryInfo.Add("totalSessions", new OSDString(values.total_num_sessions.ToString()));
251 summaryInfo.Add("averageClientFPS", new OSDString(values.avg_client_fps.ToString()));
252 summaryInfo.Add("averageClientMem", new OSDString(values.avg_client_mem_use.ToString()));
253 summaryInfo.Add("averageSimFPS", new OSDString(values.avg_sim_fps.ToString()));
254 summaryInfo.Add("averagePingTime", new OSDString(values.avg_ping.ToString()));
255 summaryInfo.Add("totalKBOut", new OSDString(values.total_kb_out.ToString()));
256 summaryInfo.Add("totalKBIn", new OSDString(values.total_kb_in.ToString()));
257 return summaryInfo.ToString();
258 }
259 }
260
261 public struct stats_default_page_values
262 {
263 public int total_num_users;
264 public int total_num_sessions;
265 public float avg_client_fps;
266 public float avg_client_mem_use;
267 public float avg_sim_fps;
268 public float avg_ping;
269 public float total_kb_out;
270 public float total_kb_in;
271 public float avg_client_resends;
272 public Scene[] all_scenes;
273 public Dictionary<UUID, USimStatsData> sim_stat_data;
274 public Dictionary<string, IStatsController> stats_reports;
275 }
276
277}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs b/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs
new file mode 100644
index 0000000..c07619f
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/HTMLUtil.cs
@@ -0,0 +1,263 @@
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.Generic;
30using System.Text;
31
32namespace OpenSim.Region.UserStatistics
33{
34 public static class HTMLUtil
35 {
36
37 public static void TR_O(ref StringBuilder o, string pclass)
38 {
39 o.Append("<tr");
40 if (pclass.Length > 0)
41 {
42 GenericClass(ref o, pclass);
43 }
44 o.Append(">\n\t");
45 }
46
47 public static void TR_C(ref StringBuilder o)
48 {
49 o.Append("</tr>\n");
50 }
51
52 public static void TD_O(ref StringBuilder o, string pclass)
53 {
54 TD_O(ref o, pclass, 0, 0);
55 }
56
57 public static void TD_O(ref StringBuilder o, string pclass, int rowspan, int colspan)
58 {
59 o.Append("<td");
60 if (pclass.Length > 0)
61 {
62 GenericClass(ref o, pclass);
63 }
64 if (rowspan > 1)
65 {
66 o.Append(" rowspan=\"");
67 o.Append(rowspan);
68 o.Append("\"");
69 }
70 if (colspan > 1)
71 {
72 o.Append(" colspan=\"");
73 o.Append(colspan);
74 o.Append("\"");
75 }
76 o.Append(">");
77 }
78
79 public static void TD_C(ref StringBuilder o)
80 {
81 o.Append("</td>");
82 }
83
84 public static void TABLE_O(ref StringBuilder o, string pclass)
85 {
86 o.Append("<table");
87 if (pclass.Length > 0)
88 {
89 GenericClass(ref o, pclass);
90 }
91 o.Append(">\n\t");
92 }
93
94 public static void TABLE_C(ref StringBuilder o)
95 {
96 o.Append("</table>\n");
97 }
98
99 public static void BLOCKQUOTE_O(ref StringBuilder o, string pclass)
100 {
101 o.Append("<blockquote");
102 if (pclass.Length > 0)
103 {
104 GenericClass(ref o, pclass);
105 }
106 o.Append(" />\n");
107 }
108
109 public static void BLOCKQUOTE_C(ref StringBuilder o)
110 {
111 o.Append("</blockquote>\n");
112 }
113
114 public static void BR(ref StringBuilder o)
115 {
116 o.Append("<br />\n");
117 }
118
119 public static void HR(ref StringBuilder o, string pclass)
120 {
121 o.Append("<hr");
122 if (pclass.Length > 0)
123 {
124 GenericClass(ref o, pclass);
125 }
126 o.Append(" />\n");
127 }
128
129 public static void UL_O(ref StringBuilder o, string pclass)
130 {
131 o.Append("<ul");
132 if (pclass.Length > 0)
133 {
134 GenericClass(ref o, pclass);
135 }
136 o.Append(" />\n");
137 }
138
139 public static void UL_C(ref StringBuilder o)
140 {
141 o.Append("</ul>\n");
142 }
143
144 public static void OL_O(ref StringBuilder o, string pclass)
145 {
146 o.Append("<ol");
147 if (pclass.Length > 0)
148 {
149 GenericClass(ref o, pclass);
150 }
151 o.Append(" />\n");
152 }
153
154 public static void OL_C(ref StringBuilder o)
155 {
156 o.Append("</ol>\n");
157 }
158
159 public static void LI_O(ref StringBuilder o, string pclass)
160 {
161 o.Append("<li");
162 if (pclass.Length > 0)
163 {
164 GenericClass(ref o, pclass);
165 }
166 o.Append(" />\n");
167 }
168
169 public static void LI_C(ref StringBuilder o)
170 {
171 o.Append("</li>\n");
172 }
173
174 public static void GenericClass(ref StringBuilder o, string pclass)
175 {
176 o.Append(" class=\"");
177 o.Append(pclass);
178 o.Append("\"");
179 }
180
181 public static void InsertProtoTypeAJAX(ref StringBuilder o)
182 {
183 o.Append("<script type=\"text/javascript\" src=\"prototype.js\"></script>\n");
184 o.Append("<script type=\"text/javascript\" src=\"updater.js\"></script>\n");
185 }
186
187 public static void InsertPeriodicUpdaters(ref StringBuilder o, string[] divID, int[] seconds, string[] reportfrag)
188 {
189 o.Append("<script type=\"text/javascript\">\n");
190 o.Append(
191 @"
192 // <![CDATA[
193 document.observe('dom:loaded', function() {
194 /*
195 first arg : div to update
196 second arg : interval to poll in seconds
197 third arg : file to get data
198 */
199");
200 for (int i = 0; i < divID.Length; i++)
201 {
202
203 o.Append("new updater('");
204 o.Append(divID[i]);
205 o.Append("', ");
206 o.Append(seconds[i]);
207 o.Append(", '");
208 o.Append(reportfrag[i]);
209 o.Append("');\n");
210 }
211
212 o.Append(@"
213 });
214 // ]]>
215 </script>");
216 }
217
218 public static void HtmlHeaders_O(ref StringBuilder o)
219 {
220 o.Append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n");
221 o.Append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"nl\">");
222 o.Append("<head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\" />");
223 }
224
225 public static void HtmlHeaders_C(ref StringBuilder o)
226 {
227 o.Append("</HEAD>");
228 o.Append("<BODY>");
229 }
230
231 public static void AddReportLinks(ref StringBuilder o, Dictionary<string, IStatsController> reports, string pClass)
232 {
233 int repcount = 0;
234 foreach (string str in reports.Keys)
235 {
236 if (reports[str].ReportName.Length > 0)
237 {
238 if (repcount > 0)
239 {
240 o.Append("|&nbsp;&nbsp;");
241 }
242 A(ref o, reports[str].ReportName, str, pClass);
243 o.Append("&nbsp;&nbsp;");
244 repcount++;
245 }
246 }
247 }
248
249 public static void A(ref StringBuilder o, string linktext, string linkhref, string pClass)
250 {
251 o.Append("<A");
252 if (pClass.Length > 0)
253 {
254 GenericClass(ref o, pClass);
255 }
256 o.Append(" href=\"");
257 o.Append(linkhref);
258 o.Append("\">");
259 o.Append(linktext);
260 o.Append("</A>");
261 }
262 }
263}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs
new file mode 100644
index 0000000..80c4487
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/IStatsReport.cs
@@ -0,0 +1,39 @@
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.Collections;
29
30namespace OpenSim.Region.UserStatistics
31{
32 public interface IStatsController
33 {
34 string ReportName { get; }
35 Hashtable ProcessModel(Hashtable pParams);
36 string RenderView(Hashtable pModelResult);
37 string RenderJson(Hashtable pModelResult);
38 }
39}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs
new file mode 100644
index 0000000..4d45b80
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/LogLinesAJAX.cs
@@ -0,0 +1,159 @@
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.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using Mono.Data.SqliteClient;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Framework.Monitoring;
39
40namespace OpenSim.Region.UserStatistics
41{
42 public class LogLinesAJAX : IStatsController
43 {
44 private Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
45
46 private Regex webFormat = new Regex(@"[^\s]*\s([^,]*),[^\s]*\s([A-Z]*)[^\s-][^\[]*\[([^\]]*)\]([^\n]*)",
47 RegexOptions.Singleline | RegexOptions.Compiled);
48 private Regex TitleColor = new Regex(@"[^\s]*\s(?:[^,]*),[^\s]*\s(?:[A-Z]*)[^\s-][^\[]*\[([^\]]*)\](?:[^\n]*)",
49 RegexOptions.Singleline | RegexOptions.Compiled);
50
51
52 #region IStatsController Members
53
54 public string ReportName
55 {
56 get { return ""; }
57 }
58
59 public Hashtable ProcessModel(Hashtable pParams)
60 {
61 Hashtable nh = new Hashtable();
62 nh.Add("loglines", pParams["LogLines"]);
63 return nh;
64 }
65
66 public string RenderView(Hashtable pModelResult)
67 {
68 StringBuilder output = new StringBuilder();
69
70 HTMLUtil.HR(ref output, "");
71 output.Append("<H3>ActiveLog</H3>\n");
72
73 string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n");
74
75 string[] result = Regex.Split(tmp, "\n");
76
77 string formatopen = "";
78 string formatclose = "";
79
80 for (int i = 0; i < result.Length; i++)
81 {
82 if (result[i].Length >= 30)
83 {
84 string logtype = result[i].Substring(24, 6);
85 switch (logtype)
86 {
87 case "WARN ":
88 formatopen = "<font color=\"#7D7C00\">";
89 formatclose = "</font>";
90 break;
91
92 case "ERROR ":
93 formatopen = "<font color=\"#FF0000\">";
94 formatclose = "</font>";
95 break;
96
97 default:
98 formatopen = "";
99 formatclose = "";
100 break;
101
102 }
103 }
104 StringBuilder replaceStr = new StringBuilder();
105 //string titlecolorresults =
106
107 string formatresult = Regex.Replace(TitleColor.Replace(result[i], "$1"), "[^ABCDEFabcdef0-9]", "");
108 if (formatresult.Length > 6)
109 {
110 formatresult = formatresult.Substring(0, 6);
111
112 }
113 for (int j = formatresult.Length; j <= 5; j++)
114 formatresult += "0";
115 replaceStr.Append("$1 - [<font color=\"#");
116 replaceStr.Append(formatresult);
117 replaceStr.Append("\">$3</font>] $4<br />");
118 string repstr = replaceStr.ToString();
119
120 output.Append(formatopen);
121 output.Append(webFormat.Replace(result[i], repstr));
122 output.Append(formatclose);
123 }
124
125
126 return output.ToString();
127 }
128
129 /// <summary>
130 /// Return the last log lines. Output in the format:
131 /// <pre>
132 /// {"logLines": [
133 /// "line1",
134 /// "line2",
135 /// ...
136 /// ]
137 /// }
138 /// </pre>
139 /// </summary>
140 /// <param name="pModelResult"></param>
141 /// <returns></returns>
142 public string RenderJson(Hashtable pModelResult)
143 {
144 OSDMap logInfo = new OpenMetaverse.StructuredData.OSDMap();
145
146 OSDArray logLines = new OpenMetaverse.StructuredData.OSDArray();
147 string tmp = normalizeEndLines.Replace(pModelResult["loglines"].ToString(), "\n");
148 string[] result = Regex.Split(tmp, "\n");
149 for (int i = 0; i < result.Length; i++)
150 {
151 logLines.Add(new OSDString(result[i]));
152 }
153 logInfo.Add("logLines", logLines);
154 return logInfo.ToString();
155 }
156
157 #endregion
158 }
159}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs
new file mode 100644
index 0000000..6f8b2aa
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Prototype_distributor.cs
@@ -0,0 +1,80 @@
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.IO;
30using System.Collections;
31using System.Collections.Generic;
32using System.Text;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.UserStatistics
36{
37 public class Prototype_distributor : IStatsController
38 {
39 private string jsFileName = "prototype.js";
40 private string prototypejs = string.Empty;
41
42 public Prototype_distributor()
43 {
44 jsFileName = "prototype.js";
45 }
46
47 public Prototype_distributor(string jsName)
48 {
49 jsFileName = jsName;
50 }
51
52 public string ReportName
53 {
54 get { return ""; }
55 }
56 public Hashtable ProcessModel(Hashtable pParams)
57 {
58 Hashtable pResult = new Hashtable();
59 pResult["js"] = jsFileName;
60 return pResult;
61 }
62
63 public string RenderView(Hashtable pModelResult)
64 {
65 string fileName = (string)pModelResult["js"];
66 using (StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/" + fileName, FileMode.Open)))
67 {
68 prototypejs = fs.ReadToEnd();
69 fs.Close();
70 }
71 return prototypejs;
72 }
73
74 public string RenderJson(Hashtable pModelResult)
75 {
76 return "{}";
77 }
78
79 }
80}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs
new file mode 100644
index 0000000..0e94912
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Sessions_Report.cs
@@ -0,0 +1,288 @@
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.Text;
32using Mono.Data.SqliteClient;
33using OpenMetaverse;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.UserStatistics
37{
38 public class Sessions_Report : IStatsController
39 {
40 #region IStatsController Members
41
42 public string ReportName
43 {
44 get { return "Sessions"; }
45 }
46
47 public Hashtable ProcessModel(Hashtable pParams)
48 {
49 Hashtable modeldata = new Hashtable();
50 modeldata.Add("Scenes", pParams["Scenes"]);
51 modeldata.Add("Reports", pParams["Reports"]);
52 SqliteConnection dbConn = (SqliteConnection)pParams["DatabaseConnection"];
53 List<SessionList> lstSessions = new List<SessionList>();
54 Hashtable requestvars = (Hashtable) pParams["RequestVars"];
55
56
57 string puserUUID = string.Empty;
58 string clientVersionString = string.Empty;
59 int queryparams = 0;
60
61 if (requestvars != null)
62 {
63 if (requestvars.ContainsKey("UserID"))
64 {
65 UUID testUUID = UUID.Zero;
66 if (UUID.TryParse(requestvars["UserID"].ToString(), out testUUID))
67 {
68 puserUUID = requestvars["UserID"].ToString();
69
70 }
71 }
72
73 if (requestvars.ContainsKey("VersionString"))
74 {
75 clientVersionString = requestvars["VersionString"].ToString();
76 }
77 }
78
79 lock (dbConn)
80 {
81 string sql =
82 "SELECT distinct a.name_f, a.name_l, a.Agent_ID, b.Session_ID, b.client_version, b.last_updated, b.start_time FROM stats_session_data a LEFT OUTER JOIN stats_session_data b ON a.Agent_ID = b.Agent_ID";
83
84 if (puserUUID.Length > 0)
85 {
86 if (queryparams == 0)
87 sql += " WHERE";
88 else
89 sql += " AND";
90
91 sql += " b.agent_id=:agent_id";
92 queryparams++;
93 }
94
95 if (clientVersionString.Length > 0)
96 {
97 if (queryparams == 0)
98 sql += " WHERE";
99 else
100 sql += " AND";
101
102 sql += " b.client_version=:client_version";
103 queryparams++;
104 }
105
106 sql += " ORDER BY a.name_f, a.name_l, b.last_updated;";
107
108 SqliteCommand cmd = new SqliteCommand(sql, dbConn);
109
110 if (puserUUID.Length > 0)
111 cmd.Parameters.Add(new SqliteParameter(":agent_id", puserUUID));
112 if (clientVersionString.Length > 0)
113 cmd.Parameters.Add(new SqliteParameter(":client_version", clientVersionString));
114
115 SqliteDataReader sdr = cmd.ExecuteReader();
116
117 if (sdr.HasRows)
118 {
119 UUID userUUID = UUID.Zero;
120
121 SessionList activeSessionList = new SessionList();
122 activeSessionList.user_id=UUID.Random();
123 while (sdr.Read())
124 {
125 UUID readUUID = UUID.Parse(sdr["agent_id"].ToString());
126 if (readUUID != userUUID)
127 {
128 activeSessionList = new SessionList();
129 activeSessionList.user_id = readUUID;
130 activeSessionList.firstname = sdr["name_f"].ToString();
131 activeSessionList.lastname = sdr["name_l"].ToString();
132 activeSessionList.sessions = new List<ShortSessionData>();
133 lstSessions.Add(activeSessionList);
134 }
135
136 ShortSessionData ssd = new ShortSessionData();
137
138 ssd.last_update = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["last_updated"]));
139 ssd.start_time = Utils.UnixTimeToDateTime((uint)Convert.ToInt32(sdr["start_time"]));
140 ssd.session_id = UUID.Parse(sdr["session_id"].ToString());
141 ssd.client_version = sdr["client_version"].ToString();
142 activeSessionList.sessions.Add(ssd);
143
144 userUUID = activeSessionList.user_id;
145 }
146 }
147 sdr.Close();
148 sdr.Dispose();
149
150 }
151 modeldata["SessionData"] = lstSessions;
152 return modeldata;
153 }
154
155 public string RenderView(Hashtable pModelResult)
156 {
157 List<SessionList> lstSession = (List<SessionList>) pModelResult["SessionData"];
158 Dictionary<string, IStatsController> reports = (Dictionary<string, IStatsController>)pModelResult["Reports"];
159
160 const string STYLESHEET =
161 @"
162<STYLE>
163body
164{
165 font-size:15px; font-family:Helvetica, Verdana; color:Black;
166}
167TABLE.defaultr { }
168TR.defaultr { padding: 5px; }
169TD.header { font-weight:bold; padding:5px; }
170TD.content {}
171TD.contentright { text-align: right; }
172TD.contentcenter { text-align: center; }
173TD.align_top { vertical-align: top; }
174</STYLE>
175";
176
177 StringBuilder output = new StringBuilder();
178 HTMLUtil.HtmlHeaders_O(ref output);
179 output.Append(STYLESHEET);
180 HTMLUtil.HtmlHeaders_C(ref output);
181
182 HTMLUtil.AddReportLinks(ref output, reports, "");
183
184 HTMLUtil.TABLE_O(ref output, "defaultr");
185 HTMLUtil.TR_O(ref output, "defaultr");
186 HTMLUtil.TD_O(ref output, "header");
187 output.Append("FirstName");
188 HTMLUtil.TD_C(ref output);
189 HTMLUtil.TD_O(ref output, "header");
190 output.Append("LastName");
191 HTMLUtil.TD_C(ref output);
192 HTMLUtil.TD_O(ref output, "header");
193 output.Append("SessionEnd");
194 HTMLUtil.TD_C(ref output);
195 HTMLUtil.TD_O(ref output, "header");
196 output.Append("SessionLength");
197 HTMLUtil.TD_C(ref output);
198 HTMLUtil.TD_O(ref output, "header");
199 output.Append("Client");
200 HTMLUtil.TD_C(ref output);
201 HTMLUtil.TR_C(ref output);
202 if (lstSession.Count == 0)
203 {
204 HTMLUtil.TR_O(ref output, "");
205 HTMLUtil.TD_O(ref output, "align_top", 1, 5);
206 output.Append("No results for that query");
207 HTMLUtil.TD_C(ref output);
208 HTMLUtil.TR_C(ref output);
209 }
210 foreach (SessionList ssnlst in lstSession)
211 {
212 int cnt = 0;
213 foreach (ShortSessionData sesdata in ssnlst.sessions)
214 {
215 HTMLUtil.TR_O(ref output, "");
216 if (cnt++ == 0)
217 {
218 HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1);
219 output.Append(ssnlst.firstname);
220 HTMLUtil.TD_C(ref output);
221 HTMLUtil.TD_O(ref output, "align_top", ssnlst.sessions.Count, 1);
222 output.Append(ssnlst.lastname);
223 HTMLUtil.TD_C(ref output);
224 }
225 HTMLUtil.TD_O(ref output, "content");
226 output.Append(sesdata.last_update.ToShortDateString());
227 output.Append(" - ");
228 output.Append(sesdata.last_update.ToShortTimeString());
229 HTMLUtil.TD_C(ref output);
230 HTMLUtil.TD_O(ref output, "content");
231 TimeSpan dtlength = sesdata.last_update.Subtract(sesdata.start_time);
232 if (dtlength.Days > 0)
233 {
234 output.Append(dtlength.Days);
235 output.Append(" Days ");
236 }
237 if (dtlength.Hours > 0)
238 {
239 output.Append(dtlength.Hours);
240 output.Append(" Hours ");
241 }
242 if (dtlength.Minutes > 0)
243 {
244 output.Append(dtlength.Minutes);
245 output.Append(" Minutes");
246 }
247 HTMLUtil.TD_C(ref output);
248 HTMLUtil.TD_O(ref output, "content");
249 output.Append(sesdata.client_version);
250 HTMLUtil.TD_C(ref output);
251 HTMLUtil.TR_C(ref output);
252
253 }
254 HTMLUtil.TR_O(ref output, "");
255 HTMLUtil.TD_O(ref output, "align_top", 1, 5);
256 HTMLUtil.HR(ref output, "");
257 HTMLUtil.TD_C(ref output);
258 HTMLUtil.TR_C(ref output);
259 }
260 HTMLUtil.TABLE_C(ref output);
261 output.Append("</BODY>\n</HTML>");
262 return output.ToString();
263 }
264
265 public class SessionList
266 {
267 public string firstname;
268 public string lastname;
269 public UUID user_id;
270 public List<ShortSessionData> sessions;
271 }
272
273 public struct ShortSessionData
274 {
275 public UUID session_id;
276 public string client_version;
277 public DateTime last_update;
278 public DateTime start_time;
279 }
280
281 public string RenderJson(Hashtable pModelResult)
282 {
283 return "{}";
284 }
285 #endregion
286 }
287
288}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs
new file mode 100644
index 0000000..06d9e91
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/SimStatsAJAX.cs
@@ -0,0 +1,276 @@
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.Reflection;
32using System.Text;
33using Mono.Data.SqliteClient;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Framework.Monitoring;
38
39namespace OpenSim.Region.UserStatistics
40{
41 public class SimStatsAJAX : IStatsController
42 {
43 #region IStatsController Members
44
45 public string ReportName
46 {
47 get { return ""; }
48 }
49
50 public Hashtable ProcessModel(Hashtable pParams)
51 {
52 List<Scene> m_scene = (List<Scene>)pParams["Scenes"];
53
54 Hashtable nh = new Hashtable();
55 nh.Add("hdata", m_scene);
56 nh.Add("simstats", pParams["SimStats"]);
57 return nh;
58 }
59
60 public string RenderView(Hashtable pModelResult)
61 {
62 StringBuilder output = new StringBuilder();
63 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
64 Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"];
65
66 const string TableClass = "defaultr";
67 const string TRClass = "defaultr";
68 const string TDHeaderClass = "header";
69 const string TDDataClass = "content";
70 //const string TDDataClassRight = "contentright";
71 const string TDDataClassCenter = "contentcenter";
72
73 foreach (USimStatsData sdata in sdatadic.Values)
74 {
75
76
77 foreach (Scene sn in all_scenes)
78 {
79 if (sn.RegionInfo.RegionID == sdata.RegionId)
80 {
81 output.Append("<H2>");
82 output.Append(sn.RegionInfo.RegionName);
83 output.Append("</H2>");
84 }
85 }
86 HTMLUtil.TABLE_O(ref output, TableClass);
87 HTMLUtil.TR_O(ref output, TRClass);
88 HTMLUtil.TD_O(ref output, TDHeaderClass);
89 output.Append("Dilatn");
90 HTMLUtil.TD_C(ref output);
91 HTMLUtil.TD_O(ref output, TDHeaderClass);
92 output.Append("SimFPS");
93 HTMLUtil.TD_C(ref output);
94 HTMLUtil.TD_O(ref output, TDHeaderClass);
95 output.Append("PhysFPS");
96 HTMLUtil.TD_C(ref output);
97 HTMLUtil.TD_O(ref output, TDHeaderClass);
98 output.Append("AgntUp");
99 HTMLUtil.TD_C(ref output);
100 HTMLUtil.TD_O(ref output, TDHeaderClass);
101 output.Append("RootAg");
102 HTMLUtil.TD_C(ref output);
103 HTMLUtil.TD_O(ref output, TDHeaderClass);
104 output.Append("ChldAg");
105 HTMLUtil.TD_C(ref output);
106 HTMLUtil.TD_O(ref output, TDHeaderClass);
107 output.Append("Prims");
108 HTMLUtil.TD_C(ref output);
109 HTMLUtil.TD_O(ref output, TDHeaderClass);
110 output.Append("ATvPrm");
111 HTMLUtil.TD_C(ref output);
112 HTMLUtil.TD_O(ref output, TDHeaderClass);
113 output.Append("AtvScr");
114 HTMLUtil.TD_C(ref output);
115 HTMLUtil.TD_O(ref output, TDHeaderClass);
116 output.Append("ScrLPS");
117 HTMLUtil.TD_C(ref output);
118 HTMLUtil.TR_C(ref output);
119 HTMLUtil.TR_O(ref output, TRClass);
120 HTMLUtil.TD_O(ref output, TDDataClass);
121 output.Append(sdata.TimeDilation);
122 HTMLUtil.TD_C(ref output);
123 HTMLUtil.TD_O(ref output, TDDataClass);
124 output.Append(sdata.SimFps);
125 HTMLUtil.TD_C(ref output);
126 HTMLUtil.TD_O(ref output, TDDataClassCenter);
127 output.Append(sdata.PhysicsFps);
128 HTMLUtil.TD_C(ref output);
129 HTMLUtil.TD_O(ref output, TDDataClassCenter);
130 output.Append(sdata.AgentUpdates);
131 HTMLUtil.TD_C(ref output);
132 HTMLUtil.TD_O(ref output, TDDataClassCenter);
133 output.Append(sdata.RootAgents);
134 HTMLUtil.TD_C(ref output);
135 HTMLUtil.TD_O(ref output, TDDataClassCenter);
136 output.Append(sdata.ChildAgents);
137 HTMLUtil.TD_C(ref output);
138 HTMLUtil.TD_O(ref output, TDDataClassCenter);
139 output.Append(sdata.TotalPrims);
140 HTMLUtil.TD_C(ref output);
141 HTMLUtil.TD_O(ref output, TDDataClassCenter);
142 output.Append(sdata.ActivePrims);
143 HTMLUtil.TD_C(ref output);
144 HTMLUtil.TD_O(ref output, TDDataClassCenter);
145 output.Append(sdata.ActiveScripts);
146 HTMLUtil.TD_C(ref output);
147 HTMLUtil.TD_O(ref output, TDDataClassCenter);
148 output.Append(sdata.ScriptLinesPerSecond);
149 HTMLUtil.TD_C(ref output);
150 HTMLUtil.TR_C(ref output);
151 HTMLUtil.TR_O(ref output, TRClass);
152 HTMLUtil.TD_O(ref output, TDHeaderClass);
153 output.Append("FrmMS");
154 HTMLUtil.TD_C(ref output);
155 HTMLUtil.TD_O(ref output, TDHeaderClass);
156 output.Append("AgtMS");
157 HTMLUtil.TD_C(ref output);
158 HTMLUtil.TD_O(ref output, TDHeaderClass);
159 output.Append("PhysMS");
160 HTMLUtil.TD_C(ref output);
161 HTMLUtil.TD_O(ref output, TDHeaderClass);
162 output.Append("OthrMS");
163 HTMLUtil.TD_C(ref output);
164 HTMLUtil.TD_O(ref output, TDHeaderClass);
165 output.Append("OutPPS");
166 HTMLUtil.TD_C(ref output);
167 HTMLUtil.TD_O(ref output, TDHeaderClass);
168 output.Append("InPPS");
169 HTMLUtil.TD_C(ref output);
170 HTMLUtil.TD_O(ref output, TDHeaderClass);
171 output.Append("NoAckKB");
172 HTMLUtil.TD_C(ref output);
173 HTMLUtil.TD_O(ref output, TDHeaderClass);
174 output.Append("PndDWN");
175 HTMLUtil.TD_C(ref output);
176 HTMLUtil.TD_O(ref output, TDHeaderClass);
177 output.Append("PndUP");
178 HTMLUtil.TD_C(ref output);
179 HTMLUtil.TR_C(ref output);
180 HTMLUtil.TR_O(ref output, TRClass);
181 HTMLUtil.TD_O(ref output, TDDataClass);
182 output.Append(sdata.TotalFrameTime);
183 HTMLUtil.TD_C(ref output);
184 HTMLUtil.TD_O(ref output, TDDataClass);
185 output.Append(sdata.AgentFrameTime);
186 HTMLUtil.TD_C(ref output);
187 HTMLUtil.TD_O(ref output, TDDataClassCenter);
188 output.Append(sdata.PhysicsFrameTime);
189 HTMLUtil.TD_C(ref output);
190 HTMLUtil.TD_O(ref output, TDDataClassCenter);
191 output.Append(sdata.OtherFrameTime);
192 HTMLUtil.TD_C(ref output);
193 HTMLUtil.TD_O(ref output, TDDataClassCenter);
194 output.Append(sdata.OutPacketsPerSecond);
195 HTMLUtil.TD_C(ref output);
196 HTMLUtil.TD_O(ref output, TDDataClassCenter);
197 output.Append(sdata.InPacketsPerSecond);
198 HTMLUtil.TD_C(ref output);
199 HTMLUtil.TD_O(ref output, TDDataClassCenter);
200 output.Append(sdata.UnackedBytes);
201 HTMLUtil.TD_C(ref output);
202 HTMLUtil.TD_O(ref output, TDDataClassCenter);
203 output.Append(sdata.PendingDownloads);
204 HTMLUtil.TD_C(ref output);
205 HTMLUtil.TD_O(ref output, TDDataClassCenter);
206 output.Append(sdata.PendingUploads);
207 HTMLUtil.TD_C(ref output);
208 HTMLUtil.TR_C(ref output);
209 HTMLUtil.TABLE_C(ref output);
210
211 }
212
213 return output.ToString();
214 }
215
216 /// <summary>
217 /// Return stat information for all regions in the sim. Returns data of the form:
218 /// <pre>
219 /// {"REGIONNAME": {
220 /// "region": "REGIONNAME",
221 /// "timeDilation": "101",
222 /// ... // the rest of the stat info
223 /// },
224 /// ... // entries for each region
225 /// }
226 /// </pre>
227 /// </summary>
228 /// <param name="pModelResult"></param>
229 /// <returns></returns>
230 public string RenderJson(Hashtable pModelResult)
231 {
232 List<Scene> all_scenes = (List<Scene>) pModelResult["hdata"];
233 Dictionary<UUID, USimStatsData> sdatadic = (Dictionary<UUID,USimStatsData>)pModelResult["simstats"];
234
235 OSDMap allStatsInfo = new OpenMetaverse.StructuredData.OSDMap();
236 foreach (USimStatsData sdata in sdatadic.Values)
237 {
238 OSDMap statsInfo = new OpenMetaverse.StructuredData.OSDMap();
239 string regionName = "unknown";
240 foreach (Scene sn in all_scenes)
241 {
242 if (sn.RegionInfo.RegionID == sdata.RegionId)
243 {
244 regionName = sn.RegionInfo.RegionName;
245 break;
246 }
247 }
248 statsInfo.Add("region", new OSDString(regionName));
249 statsInfo.Add("timeDilation", new OSDString(sdata.TimeDilation.ToString()));
250 statsInfo.Add("simFPS", new OSDString(sdata.SimFps.ToString()));
251 statsInfo.Add("physicsFPS", new OSDString(sdata.PhysicsFps.ToString()));
252 statsInfo.Add("agentUpdates", new OSDString(sdata.AgentUpdates.ToString()));
253 statsInfo.Add("rootAgents", new OSDString(sdata.RootAgents.ToString()));
254 statsInfo.Add("childAgents", new OSDString(sdata.ChildAgents.ToString()));
255 statsInfo.Add("totalPrims", new OSDString(sdata.TotalPrims.ToString()));
256 statsInfo.Add("activePrims", new OSDString(sdata.ActivePrims.ToString()));
257 statsInfo.Add("activeScripts", new OSDString(sdata.ActiveScripts.ToString()));
258 statsInfo.Add("scriptLinesPerSec", new OSDString(sdata.ScriptLinesPerSecond.ToString()));
259 statsInfo.Add("totalFrameTime", new OSDString(sdata.TotalFrameTime.ToString()));
260 statsInfo.Add("agentFrameTime", new OSDString(sdata.AgentFrameTime.ToString()));
261 statsInfo.Add("physicsFrameTime", new OSDString(sdata.PhysicsFrameTime.ToString()));
262 statsInfo.Add("otherFrameTime", new OSDString(sdata.OtherFrameTime.ToString()));
263 statsInfo.Add("outPacketsPerSec", new OSDString(sdata.OutPacketsPerSecond.ToString()));
264 statsInfo.Add("inPacketsPerSec", new OSDString(sdata.InPacketsPerSecond.ToString()));
265 statsInfo.Add("unackedByptes", new OSDString(sdata.UnackedBytes.ToString()));
266 statsInfo.Add("pendingDownloads", new OSDString(sdata.PendingDownloads.ToString()));
267 statsInfo.Add("pendingUploads", new OSDString(sdata.PendingUploads.ToString()));
268
269 allStatsInfo.Add(regionName, statsInfo);
270 }
271 return allStatsInfo.ToString();
272 }
273
274 #endregion
275 }
276}
diff --git a/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs
new file mode 100644
index 0000000..601e06b
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/UserStatistics/Updater_distributor.cs
@@ -0,0 +1,70 @@
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.IO;
30using System.Collections;
31using System.Collections.Generic;
32using System.Text;
33using OpenSim.Framework;
34
35namespace OpenSim.Region.UserStatistics
36{
37 public class Updater_distributor : IStatsController
38 {
39 private string updaterjs = string.Empty;
40
41 public string ReportName
42 {
43 get { return ""; }
44 }
45
46 public Hashtable ProcessModel(Hashtable pParams)
47 {
48 Hashtable pResult = new Hashtable();
49 if (updaterjs.Length == 0)
50 {
51 StreamReader fs = new StreamReader(new FileStream(Util.dataDir() + "/data/updater.js", FileMode.Open));
52 updaterjs = fs.ReadToEnd();
53 fs.Close();
54 fs.Dispose();
55 }
56 pResult["js"] = updaterjs;
57 return pResult;
58 }
59
60 public string RenderView(Hashtable pModelResult)
61 {
62 return pModelResult["js"].ToString();
63 }
64
65 public string RenderJson(Hashtable pModelResult) {
66 return "{}";
67 }
68
69 }
70} \ No newline at end of file
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
diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
index 2345e38..a892cf4 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs
@@ -33,7 +33,6 @@ using Nini.Config;
33using NUnit.Framework; 33using NUnit.Framework;
34using OpenMetaverse; 34using OpenMetaverse;
35using OpenSim.Framework; 35using OpenSim.Framework;
36using OpenSim.Framework.Communications;
37using OpenSim.Region.CoreModules.Avatar.Attachments; 36using OpenSim.Region.CoreModules.Avatar.Attachments;
38using OpenSim.Region.CoreModules.Avatar.AvatarFactory; 37using OpenSim.Region.CoreModules.Avatar.AvatarFactory;
39using OpenSim.Region.CoreModules.Framework.InventoryAccess; 38using OpenSim.Region.CoreModules.Framework.InventoryAccess;