diff options
Diffstat (limited to 'OpenSim/Region/OptionalModules')
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; | |||
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenMetaverse.StructuredData; | 36 | using OpenMetaverse.StructuredData; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Region.Framework.Interfaces; | 38 | using OpenSim.Region.Framework.Interfaces; |
40 | using OpenSim.Region.Framework.Scenes; | 39 | using OpenSim.Region.Framework.Scenes; |
41 | using OpenSim.Services.Interfaces; | 40 | using 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; | |||
42 | using OpenMetaverse.StructuredData; | 42 | using OpenMetaverse.StructuredData; |
43 | 43 | ||
44 | using OpenSim.Framework; | 44 | using OpenSim.Framework; |
45 | using OpenSim.Framework.Communications; | ||
46 | using OpenSim.Region.Framework.Interfaces; | 45 | using OpenSim.Region.Framework.Interfaces; |
47 | using OpenSim.Services.Interfaces; | 46 | using 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; | |||
37 | using OpenMetaverse.Packets; | 37 | using OpenMetaverse.Packets; |
38 | using OpenMetaverse.StructuredData; | 38 | using OpenMetaverse.StructuredData; |
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Framework.Communications; | ||
41 | using OpenSim.Framework.Servers; | 40 | using OpenSim.Framework.Servers; |
42 | using OpenSim.Framework.Servers.HttpServer; | 41 | using OpenSim.Framework.Servers.HttpServer; |
43 | using OpenSim.Region.ClientStack.Linden; | 42 | using 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; | |||
41 | using OpenMetaverse.StructuredData; | 41 | using OpenMetaverse.StructuredData; |
42 | 42 | ||
43 | using OpenSim.Framework; | 43 | using OpenSim.Framework; |
44 | using OpenSim.Framework.Communications; | ||
45 | using OpenSim.Region.Framework.Interfaces; | 44 | using OpenSim.Region.Framework.Interfaces; |
46 | using OpenSim.Services.Interfaces; | 45 | using 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 | |||
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using System.Xml; | ||
32 | using log4net; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Capabilities; | ||
36 | using OpenSim.Framework.Servers; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
40 | |||
41 | namespace 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 | |||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Linq; | ||
33 | using System.Net; | ||
34 | using System.Reflection; | ||
35 | using System.Text; | ||
36 | using System.Xml; | ||
37 | using log4net; | ||
38 | using Nini.Config; | ||
39 | using OpenMetaverse; | ||
40 | using Mono.Addins; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Region.DataSnapshot.Interfaces; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | |||
46 | namespace 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 | |||
28 | using System; | ||
29 | using System.Xml; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | |||
33 | using OpenSim.Region.DataSnapshot.Interfaces; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | |||
37 | namespace 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 | |||
28 | using System.Xml; | ||
29 | |||
30 | namespace 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 | |||
29 | using System; | ||
30 | using System.Xml; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | |||
33 | namespace 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 | |||
28 | using OpenSim.Framework.Capabilities; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Xml; | ||
32 | using log4net; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | |||
36 | using OpenSim.Region.CoreModules.World.Land; | ||
37 | using OpenSim.Region.DataSnapshot.Interfaces; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | |||
42 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Xml; | ||
32 | using log4net; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.DataSnapshot.Interfaces; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | |||
39 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Text.RegularExpressions; | ||
34 | using System.Xml; | ||
35 | using log4net; | ||
36 | using OpenSim.Region.DataSnapshot.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | |||
39 | namespace 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; | |||
36 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | 36 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; |
37 | using OpenSim.Region.Framework.Interfaces; | 37 | using OpenSim.Region.Framework.Interfaces; |
38 | using OpenSim.Region.Framework.Scenes; | 38 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Region.Physics.Manager; | 39 | using OpenSim.Region.PhysicsModules.SharedBase; |
40 | 40 | ||
41 | namespace OpenSim.Region.OptionalModules.PhysicsParameters | 41 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | |||
33 | namespace OpenSim.Region.RegionCombinerModule | ||
34 | { | ||
35 | public 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 | |||
28 | using System; | ||
29 | using OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.CoreModules.Avatar.Attachments; | ||
32 | using OpenSim.Region.CoreModules.Avatar.Gods; | ||
33 | using OpenSim.Region.Framework.Interfaces; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | |||
36 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using OpenSim.Region.CoreModules.World.Land; | ||
36 | |||
37 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Client; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Framework.Console; | ||
39 | using OpenSim.Region.PhysicsModules.SharedBase; | ||
40 | using Mono.Addins; | ||
41 | |||
42 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework.Interfaces; | ||
33 | using OpenSim.Region.Framework.Scenes; | ||
34 | |||
35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework.Interfaces; | ||
33 | using OpenSim.Region.Framework.Scenes; | ||
34 | |||
35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | |||
33 | namespace 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 | |||
28 | using OpenMetaverse; | ||
29 | using OpenSim.Region.Framework.Scenes; | ||
30 | |||
31 | namespace 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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Linq; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Threading; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.CoreModules; | ||
36 | using OpenSim.Region.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Region.Physics.Manager; | ||
40 | |||
41 | using Mono.Addins; | ||
42 | using Nini.Config; | ||
43 | using log4net; | ||
44 | using OpenMetaverse; | ||
45 | |||
46 | namespace OpenSim.Region.OptionalModules.Scripting | ||
47 | { | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
49 | public 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; | |||
34 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
35 | using OpenSim.Region.Framework.Scenes; | 35 | using OpenSim.Region.Framework.Scenes; |
36 | using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object; | 36 | using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object; |
37 | using OpenSim.Region.Physics.Manager; | 37 | using OpenSim.Region.PhysicsModules.SharedBase; |
38 | using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType; | 38 | using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType; |
39 | using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType; | 39 | using 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; | |||
35 | using Mono.Addins; | 35 | using Mono.Addins; |
36 | 36 | ||
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Framework.Servers; | 38 | using OpenSim.Framework.Servers; |
40 | using OpenSim.Framework.Servers.HttpServer; | 39 | using OpenSim.Framework.Servers.HttpServer; |
41 | using OpenSim.Framework.Client; | 40 | using 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using Mono.Data.SqliteClient; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Framework.Monitoring; | ||
39 | |||
40 | namespace 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(" "); | ||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Text; | ||
32 | using Mono.Data.SqliteClient; | ||
33 | using OpenMetaverse; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | |||
37 | namespace 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> | ||
191 | body | ||
192 | { | ||
193 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
194 | } | ||
195 | TABLE.defaultr { } | ||
196 | TR.defaultr { padding: 5px; } | ||
197 | TD.header { font-weight:bold; padding:5px; } | ||
198 | TD.content {} | ||
199 | TD.contentright { text-align: right; } | ||
200 | TD.contentcenter { text-align: center; } | ||
201 | TD.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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using Mono.Data.SqliteClient; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Framework.Monitoring; | ||
38 | |||
39 | |||
40 | namespace 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> | ||
94 | body | ||
95 | { | ||
96 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
97 | } | ||
98 | TABLE.defaultr { } | ||
99 | TR.defaultr { padding: 5px; } | ||
100 | TD.header { font-weight:bold; padding:5px; } | ||
101 | TD.content {} | ||
102 | TD.contentright { text-align: right; } | ||
103 | TD.contentcenter { text-align: center; } | ||
104 | TD.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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Text; | ||
31 | |||
32 | namespace 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("| "); | ||
241 | } | ||
242 | A(ref o, reports[str].ReportName, str, pClass); | ||
243 | o.Append(" "); | ||
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 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Text.RegularExpressions; | ||
34 | using Mono.Data.SqliteClient; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Framework.Monitoring; | ||
39 | |||
40 | namespace 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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Text; | ||
33 | using OpenSim.Framework; | ||
34 | |||
35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Text; | ||
32 | using Mono.Data.SqliteClient; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Framework; | ||
35 | |||
36 | namespace 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> | ||
163 | body | ||
164 | { | ||
165 | font-size:15px; font-family:Helvetica, Verdana; color:Black; | ||
166 | } | ||
167 | TABLE.defaultr { } | ||
168 | TR.defaultr { padding: 5px; } | ||
169 | TD.header { font-weight:bold; padding:5px; } | ||
170 | TD.content {} | ||
171 | TD.contentright { text-align: right; } | ||
172 | TD.contentcenter { text-align: center; } | ||
173 | TD.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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using Mono.Data.SqliteClient; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Region.Framework.Scenes; | ||
37 | using OpenSim.Framework.Monitoring; | ||
38 | |||
39 | namespace 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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Collections; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Text; | ||
33 | using OpenSim.Framework; | ||
34 | |||
35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; // to be used for REST-->Grid shortly | ||
33 | using System.Reflection; | ||
34 | using System.Text; | ||
35 | using System.Threading; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.StructuredData; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using Mono.Data.SqliteClient; | ||
46 | using Mono.Addins; | ||
47 | |||
48 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
49 | |||
50 | using OSD = OpenMetaverse.StructuredData.OSD; | ||
51 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
52 | |||
53 | namespace 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 ( | ||
750 | 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, | ||
751 | 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, | ||
752 | 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, | ||
753 | 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, | ||
754 | f_resent, f_send_packet | ||
755 | ) | ||
756 | VALUES | ||
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; | |||
33 | using NUnit.Framework; | 33 | using NUnit.Framework; |
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Communications; | ||
37 | using OpenSim.Region.CoreModules.Avatar.Attachments; | 36 | using OpenSim.Region.CoreModules.Avatar.Attachments; |
38 | using OpenSim.Region.CoreModules.Avatar.AvatarFactory; | 37 | using OpenSim.Region.CoreModules.Avatar.AvatarFactory; |
39 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | 38 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; |