diff options
author | Robert Adams | 2015-09-08 04:54:16 -0700 |
---|---|---|
committer | Robert Adams | 2015-09-08 04:54:16 -0700 |
commit | e5367d822be9b05e74c859afe2d2956a3e95aa33 (patch) | |
tree | e904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/OptionalModules | |
parent | add lost admin_reset_land method (diff) | |
parent | Deleted access control spec from [LoginService] section of standalone config.... (diff) | |
download | opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2 opensim-SC-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz |
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules.
AVN physics hasn't been moved to new location.
Does not compile yet.
Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/OptionalModules')
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; |