diff options
Diffstat (limited to '')
15 files changed, 2143 insertions, 228 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index 89a4d30..d22f3f4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | |||
@@ -26,27 +26,25 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
30 | using Nini.Config; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Framework.Scenes; | ||
34 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using System; | ||
36 | using System.Reflection; | ||
37 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | ||
38 | using System.Collections.Specialized; | 31 | using System.Collections.Specialized; |
39 | using System.Reflection; | ||
40 | using System.IO; | 32 | using System.IO; |
33 | using System.Reflection; | ||
41 | using System.Web; | 34 | using System.Web; |
42 | using System.Xml; | 35 | using System.Xml; |
43 | using log4net; | 36 | using log4net; |
44 | using Mono.Addins; | 37 | using Mono.Addins; |
38 | using Nini.Config; | ||
39 | using OpenMetaverse; | ||
45 | using OpenMetaverse.Messages.Linden; | 40 | using OpenMetaverse.Messages.Linden; |
46 | using OpenMetaverse.StructuredData; | 41 | using OpenMetaverse.StructuredData; |
42 | using OpenSim.Framework; | ||
47 | using OpenSim.Framework.Capabilities; | 43 | using OpenSim.Framework.Capabilities; |
48 | using OpenSim.Framework.Servers; | 44 | using OpenSim.Framework.Servers; |
49 | using OpenSim.Framework.Servers.HttpServer; | 45 | using OpenSim.Framework.Servers.HttpServer; |
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Region.Framework.Interfaces; | ||
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 48 | using Caps = OpenSim.Framework.Capabilities.Caps; |
51 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | 49 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; |
52 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | 50 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; |
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs new file mode 100644 index 0000000..5b228ee --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | |||
@@ -0,0 +1,1328 @@ | |||
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.Text; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.Globalization; | ||
34 | using System.Net; | ||
35 | using System.Net.Sockets; | ||
36 | using System.Reflection; | ||
37 | using System.Xml; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.StructuredData; | ||
40 | using log4net; | ||
41 | using Nini.Config; | ||
42 | using Nwc.XmlRpc; | ||
43 | using OpenSim.Framework; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | using Mono.Addins; | ||
48 | using OpenSim.Services.Connectors.Hypergrid; | ||
49 | |||
50 | namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles | ||
51 | { | ||
52 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")] | ||
53 | public class UserProfileModule : IProfileModule, INonSharedRegionModule | ||
54 | { | ||
55 | /// <summary> | ||
56 | /// Logging | ||
57 | /// </summary> | ||
58 | static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | // The pair of Dictionaries are used to handle the switching of classified ads | ||
61 | // by maintaining a cache of classified id to creator id mappings and an interest | ||
62 | // count. The entries are removed when the interest count reaches 0. | ||
63 | Dictionary<UUID,UUID> classifiedCache = new Dictionary<UUID, UUID>(); | ||
64 | Dictionary<UUID,int> classifiedInterest = new Dictionary<UUID, int>(); | ||
65 | |||
66 | public Scene Scene | ||
67 | { | ||
68 | get; private set; | ||
69 | } | ||
70 | |||
71 | /// <summary> | ||
72 | /// Gets or sets the ConfigSource. | ||
73 | /// </summary> | ||
74 | /// <value> | ||
75 | /// The configuration | ||
76 | /// </value> | ||
77 | public IConfigSource Config { | ||
78 | get; | ||
79 | set; | ||
80 | } | ||
81 | |||
82 | /// <summary> | ||
83 | /// Gets or sets the URI to the profile server. | ||
84 | /// </summary> | ||
85 | /// <value> | ||
86 | /// The profile server URI. | ||
87 | /// </value> | ||
88 | public string ProfileServerUri { | ||
89 | get; | ||
90 | set; | ||
91 | } | ||
92 | |||
93 | IProfileModule ProfileModule | ||
94 | { | ||
95 | get; set; | ||
96 | } | ||
97 | |||
98 | IUserManagement UserManagementModule | ||
99 | { | ||
100 | get; set; | ||
101 | } | ||
102 | |||
103 | /// <summary> | ||
104 | /// Gets or sets a value indicating whether this | ||
105 | /// <see cref="BlueWall.SlipStream.ProfileModule.UserProfileModule"/> is enabled. | ||
106 | /// </summary> | ||
107 | /// <value> | ||
108 | /// <c>true</c> if enabled; otherwise, <c>false</c>. | ||
109 | /// </value> | ||
110 | public bool Enabled { | ||
111 | get; | ||
112 | set; | ||
113 | } | ||
114 | |||
115 | #region IRegionModuleBase implementation | ||
116 | /// <summary> | ||
117 | /// This is called to initialize the region module. For shared modules, this is called exactly once, after | ||
118 | /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after | ||
119 | /// the instace for the region has been created. | ||
120 | /// </summary> | ||
121 | /// <param name='source'> | ||
122 | /// Source. | ||
123 | /// </param> | ||
124 | public void Initialise(IConfigSource source) | ||
125 | { | ||
126 | Config = source; | ||
127 | ReplaceableInterface = typeof(IProfileModule); | ||
128 | |||
129 | IConfig profileConfig = Config.Configs["UserProfiles"]; | ||
130 | |||
131 | if (profileConfig == null) | ||
132 | { | ||
133 | Enabled = false; | ||
134 | return; | ||
135 | } | ||
136 | |||
137 | // If we find ProfileURL then we configure for FULL support | ||
138 | // else we setup for BASIC support | ||
139 | ProfileServerUri = profileConfig.GetString("ProfileServiceURL", ""); | ||
140 | if (ProfileServerUri == "") | ||
141 | { | ||
142 | Enabled = false; | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | m_log.Debug("[PROFILES]: Full Profiles Enabled"); | ||
147 | ReplaceableInterface = null; | ||
148 | Enabled = true; | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Adds the region. | ||
153 | /// </summary> | ||
154 | /// <param name='scene'> | ||
155 | /// Scene. | ||
156 | /// </param> | ||
157 | public void AddRegion(Scene scene) | ||
158 | { | ||
159 | if(!Enabled) | ||
160 | return; | ||
161 | |||
162 | Scene = scene; | ||
163 | Scene.RegisterModuleInterface<IProfileModule>(this); | ||
164 | Scene.EventManager.OnNewClient += OnNewClient; | ||
165 | Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent; | ||
166 | |||
167 | UserManagementModule = Scene.RequestModuleInterface<IUserManagement>(); | ||
168 | } | ||
169 | |||
170 | void HandleOnMakeRootAgent (ScenePresence obj) | ||
171 | { | ||
172 | GetImageAssets(((IScenePresence)obj).UUID); | ||
173 | } | ||
174 | |||
175 | /// <summary> | ||
176 | /// Removes the region. | ||
177 | /// </summary> | ||
178 | /// <param name='scene'> | ||
179 | /// Scene. | ||
180 | /// </param> | ||
181 | public void RemoveRegion(Scene scene) | ||
182 | { | ||
183 | if(!Enabled) | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | /// <summary> | ||
188 | /// This will be called once for every scene loaded. In a shared module this will be multiple times in one | ||
189 | /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion | ||
190 | /// has been called in all modules for that scene, providing an opportunity to request another module's | ||
191 | /// interface, or hook an event from another module. | ||
192 | /// </summary> | ||
193 | /// <param name='scene'> | ||
194 | /// Scene. | ||
195 | /// </param> | ||
196 | public void RegionLoaded(Scene scene) | ||
197 | { | ||
198 | if(!Enabled) | ||
199 | return; | ||
200 | } | ||
201 | |||
202 | /// <summary> | ||
203 | /// If this returns non-null, it is the type of an interface that this module intends to register. This will | ||
204 | /// cause the loader to defer loading of this module until all other modules have been loaded. If no other | ||
205 | /// module has registered the interface by then, this module will be activated, else it will remain inactive, | ||
206 | /// letting the other module take over. This should return non-null ONLY in modules that are intended to be | ||
207 | /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party | ||
208 | /// provided modules. | ||
209 | /// </summary> | ||
210 | /// <value> | ||
211 | /// The replaceable interface. | ||
212 | /// </value> | ||
213 | public Type ReplaceableInterface | ||
214 | { | ||
215 | get; private set; | ||
216 | } | ||
217 | |||
218 | /// <summary> | ||
219 | /// Called as the instance is closed. | ||
220 | /// </summary> | ||
221 | public void Close() | ||
222 | { | ||
223 | } | ||
224 | |||
225 | /// <value> | ||
226 | /// The name of the module | ||
227 | /// </value> | ||
228 | /// <summary> | ||
229 | /// Gets the module name. | ||
230 | /// </summary> | ||
231 | public string Name | ||
232 | { | ||
233 | get { return "UserProfileModule"; } | ||
234 | } | ||
235 | #endregion IRegionModuleBase implementation | ||
236 | |||
237 | #region Region Event Handlers | ||
238 | /// <summary> | ||
239 | /// Raises the new client event. | ||
240 | /// </summary> | ||
241 | /// <param name='client'> | ||
242 | /// Client. | ||
243 | /// </param> | ||
244 | void OnNewClient(IClientAPI client) | ||
245 | { | ||
246 | //Profile | ||
247 | client.OnRequestAvatarProperties += RequestAvatarProperties; | ||
248 | client.OnUpdateAvatarProperties += AvatarPropertiesUpdate; | ||
249 | client.OnAvatarInterestUpdate += AvatarInterestsUpdate; | ||
250 | |||
251 | // Classifieds | ||
252 | client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest); | ||
253 | client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate; | ||
254 | client.OnClassifiedInfoRequest += ClassifiedInfoRequest; | ||
255 | client.OnClassifiedDelete += ClassifiedDelete; | ||
256 | |||
257 | // Picks | ||
258 | client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest); | ||
259 | client.AddGenericPacketHandler("pickinforequest", PickInfoRequest); | ||
260 | client.OnPickInfoUpdate += PickInfoUpdate; | ||
261 | client.OnPickDelete += PickDelete; | ||
262 | |||
263 | // Notes | ||
264 | client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest); | ||
265 | client.OnAvatarNotesUpdate += NotesUpdate; | ||
266 | } | ||
267 | #endregion Region Event Handlers | ||
268 | |||
269 | #region Classified | ||
270 | /// | ||
271 | /// <summary> | ||
272 | /// Handles the avatar classifieds request. | ||
273 | /// </summary> | ||
274 | /// <param name='sender'> | ||
275 | /// Sender. | ||
276 | /// </param> | ||
277 | /// <param name='method'> | ||
278 | /// Method. | ||
279 | /// </param> | ||
280 | /// <param name='args'> | ||
281 | /// Arguments. | ||
282 | /// </param> | ||
283 | public void ClassifiedsRequest(Object sender, string method, List<String> args) | ||
284 | { | ||
285 | if (!(sender is IClientAPI)) | ||
286 | return; | ||
287 | |||
288 | IClientAPI remoteClient = (IClientAPI)sender; | ||
289 | |||
290 | UUID targetID; | ||
291 | UUID.TryParse(args[0], out targetID); | ||
292 | |||
293 | // Can't handle NPC yet... | ||
294 | ScenePresence p = FindPresence(targetID); | ||
295 | |||
296 | if (null != p) | ||
297 | { | ||
298 | if (p.PresenceType == PresenceType.Npc) | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | string serverURI = string.Empty; | ||
303 | bool foreign = GetUserProfileServerURI(targetID, out serverURI); | ||
304 | UUID creatorId = UUID.Zero; | ||
305 | |||
306 | OSDMap parameters= new OSDMap(); | ||
307 | UUID.TryParse(args[0], out creatorId); | ||
308 | parameters.Add("creatorId", OSD.FromUUID(creatorId)); | ||
309 | OSD Params = (OSD)parameters; | ||
310 | if(!JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) | ||
311 | { | ||
312 | // Error Handling here! | ||
313 | // if(parameters.ContainsKey("message") | ||
314 | } | ||
315 | |||
316 | parameters = (OSDMap)Params; | ||
317 | |||
318 | OSDArray list = (OSDArray)parameters["result"]; | ||
319 | |||
320 | Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>(); | ||
321 | |||
322 | foreach(OSD map in list) | ||
323 | { | ||
324 | OSDMap m = (OSDMap)map; | ||
325 | UUID cid = m["classifieduuid"].AsUUID(); | ||
326 | string name = m["name"].AsString(); | ||
327 | |||
328 | classifieds[cid] = name; | ||
329 | |||
330 | if(!classifiedCache.ContainsKey(cid)) | ||
331 | { | ||
332 | classifiedCache.Add(cid,creatorId); | ||
333 | classifiedInterest.Add(cid, 0); | ||
334 | } | ||
335 | |||
336 | classifiedInterest[cid] ++; | ||
337 | } | ||
338 | |||
339 | remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); | ||
340 | } | ||
341 | |||
342 | public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient) | ||
343 | { | ||
344 | UUID target = remoteClient.AgentId; | ||
345 | UserClassifiedAdd ad = new UserClassifiedAdd(); | ||
346 | ad.ClassifiedId = queryClassifiedID; | ||
347 | |||
348 | if(classifiedCache.ContainsKey(queryClassifiedID)) | ||
349 | { | ||
350 | target = classifiedCache[queryClassifiedID]; | ||
351 | |||
352 | if(classifiedInterest[queryClassifiedID] -- == 0) | ||
353 | { | ||
354 | lock(classifiedCache) | ||
355 | { | ||
356 | lock(classifiedInterest) | ||
357 | { | ||
358 | classifiedInterest.Remove(queryClassifiedID); | ||
359 | } | ||
360 | classifiedCache.Remove(queryClassifiedID); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | |||
366 | string serverURI = string.Empty; | ||
367 | bool foreign = GetUserProfileServerURI(target, out serverURI); | ||
368 | |||
369 | object Ad = (object)ad; | ||
370 | if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) | ||
371 | { | ||
372 | remoteClient.SendAgentAlertMessage( | ||
373 | "Error getting classified info", false); | ||
374 | return; | ||
375 | } | ||
376 | ad = (UserClassifiedAdd) Ad; | ||
377 | |||
378 | if(ad.CreatorId == UUID.Zero) | ||
379 | return; | ||
380 | |||
381 | Vector3 globalPos = new Vector3(); | ||
382 | Vector3.TryParse(ad.GlobalPos, out globalPos); | ||
383 | |||
384 | remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate, | ||
385 | (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate, | ||
386 | ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price); | ||
387 | |||
388 | } | ||
389 | |||
390 | /// <summary> | ||
391 | /// Classifieds info update. | ||
392 | /// </summary> | ||
393 | /// <param name='queryclassifiedID'> | ||
394 | /// Queryclassified I. | ||
395 | /// </param> | ||
396 | /// <param name='queryCategory'> | ||
397 | /// Query category. | ||
398 | /// </param> | ||
399 | /// <param name='queryName'> | ||
400 | /// Query name. | ||
401 | /// </param> | ||
402 | /// <param name='queryDescription'> | ||
403 | /// Query description. | ||
404 | /// </param> | ||
405 | /// <param name='queryParcelID'> | ||
406 | /// Query parcel I. | ||
407 | /// </param> | ||
408 | /// <param name='queryParentEstate'> | ||
409 | /// Query parent estate. | ||
410 | /// </param> | ||
411 | /// <param name='querySnapshotID'> | ||
412 | /// Query snapshot I. | ||
413 | /// </param> | ||
414 | /// <param name='queryGlobalPos'> | ||
415 | /// Query global position. | ||
416 | /// </param> | ||
417 | /// <param name='queryclassifiedFlags'> | ||
418 | /// Queryclassified flags. | ||
419 | /// </param> | ||
420 | /// <param name='queryclassifiedPrice'> | ||
421 | /// Queryclassified price. | ||
422 | /// </param> | ||
423 | /// <param name='remoteClient'> | ||
424 | /// Remote client. | ||
425 | /// </param> | ||
426 | public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID, | ||
427 | uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags, | ||
428 | int queryclassifiedPrice, IClientAPI remoteClient) | ||
429 | { | ||
430 | UserClassifiedAdd ad = new UserClassifiedAdd(); | ||
431 | |||
432 | Scene s = (Scene) remoteClient.Scene; | ||
433 | Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; | ||
434 | ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); | ||
435 | ScenePresence p = FindPresence(remoteClient.AgentId); | ||
436 | Vector3 avaPos = p.AbsolutePosition; | ||
437 | |||
438 | string serverURI = string.Empty; | ||
439 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
440 | |||
441 | if (land == null) | ||
442 | { | ||
443 | ad.ParcelName = string.Empty; | ||
444 | } | ||
445 | else | ||
446 | { | ||
447 | ad.ParcelName = land.LandData.Name; | ||
448 | } | ||
449 | |||
450 | ad.CreatorId = remoteClient.AgentId; | ||
451 | ad.ClassifiedId = queryclassifiedID; | ||
452 | ad.Category = Convert.ToInt32(queryCategory); | ||
453 | ad.Name = queryName; | ||
454 | ad.Description = queryDescription; | ||
455 | ad.ParentEstate = Convert.ToInt32(queryParentEstate); | ||
456 | ad.SnapshotId = querySnapshotID; | ||
457 | ad.SimName = remoteClient.Scene.RegionInfo.RegionName; | ||
458 | ad.GlobalPos = queryGlobalPos.ToString (); | ||
459 | ad.Flags = queryclassifiedFlags; | ||
460 | ad.Price = queryclassifiedPrice; | ||
461 | ad.ParcelId = p.currentParcelUUID; | ||
462 | |||
463 | object Ad = ad; | ||
464 | |||
465 | OSD X = OSD.SerializeMembers(Ad); | ||
466 | |||
467 | if(!JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString())) | ||
468 | { | ||
469 | remoteClient.SendAgentAlertMessage( | ||
470 | "Error updating classified", false); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | /// <summary> | ||
475 | /// Classifieds delete. | ||
476 | /// </summary> | ||
477 | /// <param name='queryClassifiedID'> | ||
478 | /// Query classified I. | ||
479 | /// </param> | ||
480 | /// <param name='remoteClient'> | ||
481 | /// Remote client. | ||
482 | /// </param> | ||
483 | public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) | ||
484 | { | ||
485 | string serverURI = string.Empty; | ||
486 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
487 | |||
488 | UUID classifiedId; | ||
489 | OSDMap parameters= new OSDMap(); | ||
490 | UUID.TryParse(queryClassifiedID.ToString(), out classifiedId); | ||
491 | parameters.Add("classifiedId", OSD.FromUUID(classifiedId)); | ||
492 | OSD Params = (OSD)parameters; | ||
493 | if(!JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString())) | ||
494 | { | ||
495 | remoteClient.SendAgentAlertMessage( | ||
496 | "Error classified delete", false); | ||
497 | } | ||
498 | |||
499 | parameters = (OSDMap)Params; | ||
500 | } | ||
501 | #endregion Classified | ||
502 | |||
503 | #region Picks | ||
504 | /// <summary> | ||
505 | /// Handles the avatar picks request. | ||
506 | /// </summary> | ||
507 | /// <param name='sender'> | ||
508 | /// Sender. | ||
509 | /// </param> | ||
510 | /// <param name='method'> | ||
511 | /// Method. | ||
512 | /// </param> | ||
513 | /// <param name='args'> | ||
514 | /// Arguments. | ||
515 | /// </param> | ||
516 | public void PicksRequest(Object sender, string method, List<String> args) | ||
517 | { | ||
518 | if (!(sender is IClientAPI)) | ||
519 | return; | ||
520 | |||
521 | IClientAPI remoteClient = (IClientAPI)sender; | ||
522 | |||
523 | UUID targetId; | ||
524 | UUID.TryParse(args[0], out targetId); | ||
525 | |||
526 | // Can't handle NPC yet... | ||
527 | ScenePresence p = FindPresence(targetId); | ||
528 | |||
529 | if (null != p) | ||
530 | { | ||
531 | if (p.PresenceType == PresenceType.Npc) | ||
532 | return; | ||
533 | } | ||
534 | |||
535 | string serverURI = string.Empty; | ||
536 | bool foreign = GetUserProfileServerURI(targetId, out serverURI); | ||
537 | |||
538 | OSDMap parameters= new OSDMap(); | ||
539 | parameters.Add("creatorId", OSD.FromUUID(targetId)); | ||
540 | OSD Params = (OSD)parameters; | ||
541 | if(!JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString())) | ||
542 | { | ||
543 | remoteClient.SendAgentAlertMessage( | ||
544 | "Error requesting picks", false); | ||
545 | return; | ||
546 | } | ||
547 | |||
548 | parameters = (OSDMap)Params; | ||
549 | |||
550 | OSDArray list = (OSDArray)parameters["result"]; | ||
551 | |||
552 | Dictionary<UUID, string> picks = new Dictionary<UUID, string>(); | ||
553 | |||
554 | foreach(OSD map in list) | ||
555 | { | ||
556 | OSDMap m = (OSDMap)map; | ||
557 | UUID cid = m["pickuuid"].AsUUID(); | ||
558 | string name = m["name"].AsString(); | ||
559 | |||
560 | m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name); | ||
561 | |||
562 | picks[cid] = name; | ||
563 | } | ||
564 | remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); | ||
565 | } | ||
566 | |||
567 | /// <summary> | ||
568 | /// Handles the pick info request. | ||
569 | /// </summary> | ||
570 | /// <param name='sender'> | ||
571 | /// Sender. | ||
572 | /// </param> | ||
573 | /// <param name='method'> | ||
574 | /// Method. | ||
575 | /// </param> | ||
576 | /// <param name='args'> | ||
577 | /// Arguments. | ||
578 | /// </param> | ||
579 | public void PickInfoRequest(Object sender, string method, List<String> args) | ||
580 | { | ||
581 | if (!(sender is IClientAPI)) | ||
582 | return; | ||
583 | |||
584 | UUID targetID; | ||
585 | UUID.TryParse(args[0], out targetID); | ||
586 | string serverURI = string.Empty; | ||
587 | bool foreign = GetUserProfileServerURI(targetID, out serverURI); | ||
588 | IClientAPI remoteClient = (IClientAPI)sender; | ||
589 | |||
590 | UserProfilePick pick = new UserProfilePick(); | ||
591 | UUID.TryParse(args[0], out pick.CreatorId); | ||
592 | UUID.TryParse(args[1], out pick.PickId); | ||
593 | |||
594 | |||
595 | object Pick = (object)pick; | ||
596 | if(!JsonRpcRequest(ref Pick, "pickinforequest", serverURI, UUID.Random().ToString())) | ||
597 | { | ||
598 | remoteClient.SendAgentAlertMessage( | ||
599 | "Error selecting pick", false); | ||
600 | } | ||
601 | pick = (UserProfilePick) Pick; | ||
602 | if(pick.SnapshotId == UUID.Zero) | ||
603 | { | ||
604 | // In case of a new UserPick, the data may not be ready and we would send wrong data, skip it... | ||
605 | m_log.DebugFormat("[PROFILES]: PickInfoRequest: SnapshotID is {0}", UUID.Zero.ToString()); | ||
606 | return; | ||
607 | } | ||
608 | |||
609 | Vector3 globalPos; | ||
610 | Vector3.TryParse(pick.GlobalPos,out globalPos); | ||
611 | |||
612 | m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); | ||
613 | |||
614 | remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, | ||
615 | pick.Desc,pick.SnapshotId,pick.User,pick.OriginalName,pick.SimName, | ||
616 | globalPos,pick.SortOrder,pick.Enabled); | ||
617 | } | ||
618 | |||
619 | /// <summary> | ||
620 | /// Updates the userpicks | ||
621 | /// </summary> | ||
622 | /// <param name='remoteClient'> | ||
623 | /// Remote client. | ||
624 | /// </param> | ||
625 | /// <param name='pickID'> | ||
626 | /// Pick I. | ||
627 | /// </param> | ||
628 | /// <param name='creatorID'> | ||
629 | /// the creator of the pick | ||
630 | /// </param> | ||
631 | /// <param name='topPick'> | ||
632 | /// Top pick. | ||
633 | /// </param> | ||
634 | /// <param name='name'> | ||
635 | /// Name. | ||
636 | /// </param> | ||
637 | /// <param name='desc'> | ||
638 | /// Desc. | ||
639 | /// </param> | ||
640 | /// <param name='snapshotID'> | ||
641 | /// Snapshot I. | ||
642 | /// </param> | ||
643 | /// <param name='sortOrder'> | ||
644 | /// Sort order. | ||
645 | /// </param> | ||
646 | /// <param name='enabled'> | ||
647 | /// Enabled. | ||
648 | /// </param> | ||
649 | public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled) | ||
650 | { | ||
651 | |||
652 | m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); | ||
653 | UserProfilePick pick = new UserProfilePick(); | ||
654 | string serverURI = string.Empty; | ||
655 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
656 | ScenePresence p = FindPresence(remoteClient.AgentId); | ||
657 | |||
658 | Vector3 avaPos = p.AbsolutePosition; | ||
659 | // Getting the global position for the Avatar | ||
660 | Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X, | ||
661 | remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y, | ||
662 | avaPos.Z); | ||
663 | |||
664 | string landOwnerName = string.Empty; | ||
665 | ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y); | ||
666 | if(land.LandData.IsGroupOwned) | ||
667 | { | ||
668 | IGroupsModule groupMod = p.Scene.RequestModuleInterface<IGroupsModule>(); | ||
669 | UUID groupId = land.LandData.GroupID; | ||
670 | GroupRecord groupRecord = groupMod.GetGroupRecord(groupId); | ||
671 | landOwnerName = groupRecord.GroupName; | ||
672 | } | ||
673 | else | ||
674 | { | ||
675 | IUserAccountService accounts = p.Scene.RequestModuleInterface<IUserAccountService>(); | ||
676 | UserAccount user = accounts.GetUserAccount(p.Scene.RegionInfo.ScopeID, land.LandData.OwnerID); | ||
677 | landOwnerName = user.Name; | ||
678 | } | ||
679 | |||
680 | pick.PickId = pickID; | ||
681 | pick.CreatorId = creatorID; | ||
682 | pick.TopPick = topPick; | ||
683 | pick.Name = name; | ||
684 | pick.Desc = desc; | ||
685 | pick.ParcelId = p.currentParcelUUID; | ||
686 | pick.SnapshotId = snapshotID; | ||
687 | pick.User = landOwnerName; | ||
688 | pick.SimName = remoteClient.Scene.RegionInfo.RegionName; | ||
689 | pick.GlobalPos = posGlobal.ToString(); | ||
690 | pick.SortOrder = sortOrder; | ||
691 | pick.Enabled = enabled; | ||
692 | |||
693 | object Pick = (object)pick; | ||
694 | if(!JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString())) | ||
695 | { | ||
696 | remoteClient.SendAgentAlertMessage( | ||
697 | "Error updating pick", false); | ||
698 | } | ||
699 | |||
700 | m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString()); | ||
701 | } | ||
702 | |||
703 | /// <summary> | ||
704 | /// Delete a Pick | ||
705 | /// </summary> | ||
706 | /// <param name='remoteClient'> | ||
707 | /// Remote client. | ||
708 | /// </param> | ||
709 | /// <param name='queryPickID'> | ||
710 | /// Query pick I. | ||
711 | /// </param> | ||
712 | public void PickDelete(IClientAPI remoteClient, UUID queryPickID) | ||
713 | { | ||
714 | string serverURI = string.Empty; | ||
715 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
716 | |||
717 | OSDMap parameters= new OSDMap(); | ||
718 | parameters.Add("pickId", OSD.FromUUID(queryPickID)); | ||
719 | OSD Params = (OSD)parameters; | ||
720 | if(!JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString())) | ||
721 | { | ||
722 | remoteClient.SendAgentAlertMessage( | ||
723 | "Error picks delete", false); | ||
724 | } | ||
725 | } | ||
726 | #endregion Picks | ||
727 | |||
728 | #region Notes | ||
729 | /// <summary> | ||
730 | /// Handles the avatar notes request. | ||
731 | /// </summary> | ||
732 | /// <param name='sender'> | ||
733 | /// Sender. | ||
734 | /// </param> | ||
735 | /// <param name='method'> | ||
736 | /// Method. | ||
737 | /// </param> | ||
738 | /// <param name='args'> | ||
739 | /// Arguments. | ||
740 | /// </param> | ||
741 | public void NotesRequest(Object sender, string method, List<String> args) | ||
742 | { | ||
743 | UserProfileNotes note = new UserProfileNotes(); | ||
744 | |||
745 | if (!(sender is IClientAPI)) | ||
746 | return; | ||
747 | |||
748 | IClientAPI remoteClient = (IClientAPI)sender; | ||
749 | string serverURI = string.Empty; | ||
750 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
751 | note.TargetId = remoteClient.AgentId; | ||
752 | UUID.TryParse(args[0], out note.UserId); | ||
753 | |||
754 | object Note = (object)note; | ||
755 | if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) | ||
756 | { | ||
757 | remoteClient.SendAgentAlertMessage( | ||
758 | "Error requesting note", false); | ||
759 | } | ||
760 | note = (UserProfileNotes) Note; | ||
761 | |||
762 | remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); | ||
763 | } | ||
764 | |||
765 | /// <summary> | ||
766 | /// Avatars the notes update. | ||
767 | /// </summary> | ||
768 | /// <param name='remoteClient'> | ||
769 | /// Remote client. | ||
770 | /// </param> | ||
771 | /// <param name='queryTargetID'> | ||
772 | /// Query target I. | ||
773 | /// </param> | ||
774 | /// <param name='queryNotes'> | ||
775 | /// Query notes. | ||
776 | /// </param> | ||
777 | public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes) | ||
778 | { | ||
779 | UserProfileNotes note = new UserProfileNotes(); | ||
780 | |||
781 | note.UserId = remoteClient.AgentId; | ||
782 | note.TargetId = queryTargetID; | ||
783 | note.Notes = queryNotes; | ||
784 | |||
785 | string serverURI = string.Empty; | ||
786 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
787 | |||
788 | object Note = note; | ||
789 | if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) | ||
790 | { | ||
791 | remoteClient.SendAgentAlertMessage( | ||
792 | "Error updating note", false); | ||
793 | } | ||
794 | } | ||
795 | #endregion Notes | ||
796 | |||
797 | #region Avatar Properties | ||
798 | /// <summary> | ||
799 | /// Update the avatars interests . | ||
800 | /// </summary> | ||
801 | /// <param name='remoteClient'> | ||
802 | /// Remote client. | ||
803 | /// </param> | ||
804 | /// <param name='wantmask'> | ||
805 | /// Wantmask. | ||
806 | /// </param> | ||
807 | /// <param name='wanttext'> | ||
808 | /// Wanttext. | ||
809 | /// </param> | ||
810 | /// <param name='skillsmask'> | ||
811 | /// Skillsmask. | ||
812 | /// </param> | ||
813 | /// <param name='skillstext'> | ||
814 | /// Skillstext. | ||
815 | /// </param> | ||
816 | /// <param name='languages'> | ||
817 | /// Languages. | ||
818 | /// </param> | ||
819 | public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages) | ||
820 | { | ||
821 | UserProfileProperties prop = new UserProfileProperties(); | ||
822 | |||
823 | prop.UserId = remoteClient.AgentId; | ||
824 | prop.WantToMask = (int)wantmask; | ||
825 | prop.WantToText = wanttext; | ||
826 | prop.SkillsMask = (int)skillsmask; | ||
827 | prop.SkillsText = skillstext; | ||
828 | prop.Language = languages; | ||
829 | |||
830 | string serverURI = string.Empty; | ||
831 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
832 | |||
833 | object Param = prop; | ||
834 | if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) | ||
835 | { | ||
836 | remoteClient.SendAgentAlertMessage( | ||
837 | "Error updating interests", false); | ||
838 | } | ||
839 | } | ||
840 | |||
841 | public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) | ||
842 | { | ||
843 | if ( String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString())) | ||
844 | { | ||
845 | // Looking for a reason that some viewers are sending null Id's | ||
846 | m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID); | ||
847 | return; | ||
848 | } | ||
849 | |||
850 | // Can't handle NPC yet... | ||
851 | ScenePresence p = FindPresence(avatarID); | ||
852 | |||
853 | if (null != p) | ||
854 | { | ||
855 | if (p.PresenceType == PresenceType.Npc) | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | string serverURI = string.Empty; | ||
860 | bool foreign = GetUserProfileServerURI(avatarID, out serverURI); | ||
861 | |||
862 | UserAccount account = null; | ||
863 | Dictionary<string,object> userInfo; | ||
864 | |||
865 | if (!foreign) | ||
866 | { | ||
867 | account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID); | ||
868 | } | ||
869 | else | ||
870 | { | ||
871 | userInfo = new Dictionary<string, object>(); | ||
872 | } | ||
873 | |||
874 | Byte[] charterMember = new Byte[1]; | ||
875 | string born = String.Empty; | ||
876 | uint flags = 0x00; | ||
877 | |||
878 | if (null != account) | ||
879 | { | ||
880 | if (account.UserTitle == "") | ||
881 | { | ||
882 | charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8); | ||
883 | } | ||
884 | else | ||
885 | { | ||
886 | charterMember = Utils.StringToBytes(account.UserTitle); | ||
887 | } | ||
888 | |||
889 | born = Util.ToDateTime(account.Created).ToString( | ||
890 | "M/d/yyyy", CultureInfo.InvariantCulture); | ||
891 | flags = (uint)(account.UserFlags & 0xff); | ||
892 | } | ||
893 | else | ||
894 | { | ||
895 | if (GetUserAccountData(avatarID, out userInfo) == true) | ||
896 | { | ||
897 | if ((string)userInfo["user_title"] == "") | ||
898 | { | ||
899 | charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | charterMember = Utils.StringToBytes((string)userInfo["user_title"]); | ||
904 | } | ||
905 | |||
906 | int val_born = (int)userInfo["user_created"]; | ||
907 | born = Util.ToDateTime(val_born).ToString( | ||
908 | "M/d/yyyy", CultureInfo.InvariantCulture); | ||
909 | |||
910 | // picky, picky | ||
911 | int val_flags = (int)userInfo["user_flags"]; | ||
912 | flags = (uint)(val_flags & 0xff); | ||
913 | } | ||
914 | } | ||
915 | |||
916 | UserProfileProperties props = new UserProfileProperties(); | ||
917 | string result = string.Empty; | ||
918 | |||
919 | props.UserId = avatarID; | ||
920 | GetProfileData(ref props, out result); | ||
921 | |||
922 | remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags, | ||
923 | props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); | ||
924 | |||
925 | |||
926 | remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, | ||
927 | props.SkillsText, props.Language); | ||
928 | } | ||
929 | |||
930 | /// <summary> | ||
931 | /// Updates the avatar properties. | ||
932 | /// </summary> | ||
933 | /// <param name='remoteClient'> | ||
934 | /// Remote client. | ||
935 | /// </param> | ||
936 | /// <param name='newProfile'> | ||
937 | /// New profile. | ||
938 | /// </param> | ||
939 | public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile) | ||
940 | { | ||
941 | if (remoteClient.AgentId == newProfile.ID) | ||
942 | { | ||
943 | UserProfileProperties prop = new UserProfileProperties(); | ||
944 | |||
945 | prop.UserId = remoteClient.AgentId; | ||
946 | prop.WebUrl = newProfile.ProfileUrl; | ||
947 | prop.ImageId = newProfile.Image; | ||
948 | prop.AboutText = newProfile.AboutText; | ||
949 | prop.FirstLifeImageId = newProfile.FirstLifeImage; | ||
950 | prop.FirstLifeText = newProfile.FirstLifeAboutText; | ||
951 | |||
952 | string serverURI = string.Empty; | ||
953 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
954 | |||
955 | object Prop = prop; | ||
956 | |||
957 | if(!JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString())) | ||
958 | { | ||
959 | remoteClient.SendAgentAlertMessage( | ||
960 | "Error updating properties", false); | ||
961 | } | ||
962 | |||
963 | RequestAvatarProperties(remoteClient, newProfile.ID); | ||
964 | } | ||
965 | } | ||
966 | |||
967 | |||
968 | /// <summary> | ||
969 | /// Gets the profile data. | ||
970 | /// </summary> | ||
971 | /// <returns> | ||
972 | /// The profile data. | ||
973 | /// </returns> | ||
974 | /// <param name='userID'> | ||
975 | /// User I. | ||
976 | /// </param> | ||
977 | bool GetProfileData(ref UserProfileProperties properties, out string message) | ||
978 | { | ||
979 | // Can't handle NPC yet... | ||
980 | ScenePresence p = FindPresence(properties.UserId); | ||
981 | |||
982 | if (null != p) | ||
983 | { | ||
984 | if (p.PresenceType == PresenceType.Npc) | ||
985 | { | ||
986 | message = "Id points to NPC"; | ||
987 | return false; | ||
988 | } | ||
989 | } | ||
990 | |||
991 | string serverURI = string.Empty; | ||
992 | bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); | ||
993 | |||
994 | // This is checking a friend on the home grid | ||
995 | // Not HG friend | ||
996 | if ( String.IsNullOrEmpty(serverURI)) | ||
997 | { | ||
998 | message = "No Presence - foreign friend"; | ||
999 | return false; | ||
1000 | } | ||
1001 | |||
1002 | object Prop = (object)properties; | ||
1003 | JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()); | ||
1004 | properties = (UserProfileProperties)Prop; | ||
1005 | |||
1006 | message = "Success"; | ||
1007 | return true; | ||
1008 | } | ||
1009 | #endregion Avatar Properties | ||
1010 | |||
1011 | #region Utils | ||
1012 | bool GetImageAssets(UUID avatarId) | ||
1013 | { | ||
1014 | string profileServerURI = string.Empty; | ||
1015 | string assetServerURI = string.Empty; | ||
1016 | |||
1017 | bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI); | ||
1018 | |||
1019 | if(!foreign) | ||
1020 | return true; | ||
1021 | |||
1022 | assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI"); | ||
1023 | |||
1024 | OSDMap parameters= new OSDMap(); | ||
1025 | parameters.Add("avatarId", OSD.FromUUID(avatarId)); | ||
1026 | OSD Params = (OSD)parameters; | ||
1027 | if(!JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString())) | ||
1028 | { | ||
1029 | // Error Handling here! | ||
1030 | // if(parameters.ContainsKey("message") | ||
1031 | return false; | ||
1032 | } | ||
1033 | |||
1034 | parameters = (OSDMap)Params; | ||
1035 | |||
1036 | OSDArray list = (OSDArray)parameters["result"]; | ||
1037 | |||
1038 | foreach(OSD asset in list) | ||
1039 | { | ||
1040 | OSDString assetId = (OSDString)asset; | ||
1041 | |||
1042 | Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString()), this, | ||
1043 | delegate (string assetID, Object s, AssetBase a) | ||
1044 | { | ||
1045 | // m_log.DebugFormat("[PROFILES]: Getting Image Assets {0}", assetID); | ||
1046 | return; | ||
1047 | }); | ||
1048 | } | ||
1049 | return true; | ||
1050 | } | ||
1051 | |||
1052 | /// <summary> | ||
1053 | /// Gets the user account data. | ||
1054 | /// </summary> | ||
1055 | /// <returns> | ||
1056 | /// The user profile data. | ||
1057 | /// </returns> | ||
1058 | /// <param name='userID'> | ||
1059 | /// If set to <c>true</c> user I. | ||
1060 | /// </param> | ||
1061 | /// <param name='userInfo'> | ||
1062 | /// If set to <c>true</c> user info. | ||
1063 | /// </param> | ||
1064 | bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo) | ||
1065 | { | ||
1066 | Dictionary<string,object> info = new Dictionary<string, object>(); | ||
1067 | |||
1068 | if (UserManagementModule.IsLocalGridUser(userID)) | ||
1069 | { | ||
1070 | // Is local | ||
1071 | IUserAccountService uas = Scene.UserAccountService; | ||
1072 | UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID); | ||
1073 | |||
1074 | info["user_flags"] = account.UserFlags; | ||
1075 | info["user_created"] = account.Created; | ||
1076 | |||
1077 | if (!String.IsNullOrEmpty(account.UserTitle)) | ||
1078 | info["user_title"] = account.UserTitle; | ||
1079 | else | ||
1080 | info["user_title"] = ""; | ||
1081 | |||
1082 | userInfo = info; | ||
1083 | |||
1084 | return false; | ||
1085 | } | ||
1086 | else | ||
1087 | { | ||
1088 | // Is Foreign | ||
1089 | string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI"); | ||
1090 | |||
1091 | if (String.IsNullOrEmpty(home_url)) | ||
1092 | { | ||
1093 | info["user_flags"] = 0; | ||
1094 | info["user_created"] = 0; | ||
1095 | info["user_title"] = "Unavailable"; | ||
1096 | |||
1097 | userInfo = info; | ||
1098 | return true; | ||
1099 | } | ||
1100 | |||
1101 | UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url); | ||
1102 | |||
1103 | Dictionary<string, object> account = uConn.GetUserInfo(userID); | ||
1104 | |||
1105 | if (account.Count > 0) | ||
1106 | { | ||
1107 | if (account.ContainsKey("user_flags")) | ||
1108 | info["user_flags"] = account["user_flags"]; | ||
1109 | else | ||
1110 | info["user_flags"] = ""; | ||
1111 | |||
1112 | if (account.ContainsKey("user_created")) | ||
1113 | info["user_created"] = account["user_created"]; | ||
1114 | else | ||
1115 | info["user_created"] = ""; | ||
1116 | |||
1117 | info["user_title"] = "HG Visitor"; | ||
1118 | } | ||
1119 | else | ||
1120 | { | ||
1121 | info["user_flags"] = 0; | ||
1122 | info["user_created"] = 0; | ||
1123 | info["user_title"] = "HG Visitor"; | ||
1124 | } | ||
1125 | userInfo = info; | ||
1126 | return true; | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | /// <summary> | ||
1131 | /// Gets the user profile server UR. | ||
1132 | /// </summary> | ||
1133 | /// <returns> | ||
1134 | /// The user profile server UR. | ||
1135 | /// </returns> | ||
1136 | /// <param name='userID'> | ||
1137 | /// If set to <c>true</c> user I. | ||
1138 | /// </param> | ||
1139 | /// <param name='serverURI'> | ||
1140 | /// If set to <c>true</c> server UR. | ||
1141 | /// </param> | ||
1142 | bool GetUserProfileServerURI(UUID userID, out string serverURI) | ||
1143 | { | ||
1144 | bool local; | ||
1145 | local = UserManagementModule.IsLocalGridUser(userID); | ||
1146 | |||
1147 | if (!local) | ||
1148 | { | ||
1149 | serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI"); | ||
1150 | // Is Foreign | ||
1151 | return true; | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | serverURI = ProfileServerUri; | ||
1156 | // Is local | ||
1157 | return false; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | /// <summary> | ||
1162 | /// Finds the presence. | ||
1163 | /// </summary> | ||
1164 | /// <returns> | ||
1165 | /// The presence. | ||
1166 | /// </returns> | ||
1167 | /// <param name='clientID'> | ||
1168 | /// Client I. | ||
1169 | /// </param> | ||
1170 | ScenePresence FindPresence(UUID clientID) | ||
1171 | { | ||
1172 | ScenePresence p; | ||
1173 | |||
1174 | p = Scene.GetScenePresence(clientID); | ||
1175 | if (p != null && !p.IsChildAgent) | ||
1176 | return p; | ||
1177 | |||
1178 | return null; | ||
1179 | } | ||
1180 | #endregion Util | ||
1181 | |||
1182 | #region Web Util | ||
1183 | /// <summary> | ||
1184 | /// Sends json-rpc request with a serializable type. | ||
1185 | /// </summary> | ||
1186 | /// <returns> | ||
1187 | /// OSD Map. | ||
1188 | /// </returns> | ||
1189 | /// <param name='parameters'> | ||
1190 | /// Serializable type . | ||
1191 | /// </param> | ||
1192 | /// <param name='method'> | ||
1193 | /// Json-rpc method to call. | ||
1194 | /// </param> | ||
1195 | /// <param name='uri'> | ||
1196 | /// URI of json-rpc service. | ||
1197 | /// </param> | ||
1198 | /// <param name='jsonId'> | ||
1199 | /// Id for our call. | ||
1200 | /// </param> | ||
1201 | bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId) | ||
1202 | { | ||
1203 | if (jsonId == null) | ||
1204 | throw new ArgumentNullException ("jsonId"); | ||
1205 | if (uri == null) | ||
1206 | throw new ArgumentNullException ("uri"); | ||
1207 | if (method == null) | ||
1208 | throw new ArgumentNullException ("method"); | ||
1209 | if (parameters == null) | ||
1210 | throw new ArgumentNullException ("parameters"); | ||
1211 | |||
1212 | // Prep our payload | ||
1213 | OSDMap json = new OSDMap(); | ||
1214 | |||
1215 | json.Add("jsonrpc", OSD.FromString("2.0")); | ||
1216 | json.Add("id", OSD.FromString(jsonId)); | ||
1217 | json.Add("method", OSD.FromString(method)); | ||
1218 | // Experiment | ||
1219 | json.Add("params", OSD.SerializeMembers(parameters)); | ||
1220 | |||
1221 | string jsonRequestData = OSDParser.SerializeJsonString(json); | ||
1222 | byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); | ||
1223 | |||
1224 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
1225 | // webRequest.Credentials = new NetworkCredential(rpcUser, rpcPass); | ||
1226 | webRequest.ContentType = "application/json-rpc"; | ||
1227 | webRequest.Method = "POST"; | ||
1228 | |||
1229 | Stream dataStream = webRequest.GetRequestStream(); | ||
1230 | dataStream.Write(content, 0, content.Length); | ||
1231 | dataStream.Close(); | ||
1232 | |||
1233 | WebResponse webResponse = null; | ||
1234 | try | ||
1235 | { | ||
1236 | webResponse = webRequest.GetResponse(); | ||
1237 | } | ||
1238 | catch (WebException e) | ||
1239 | { | ||
1240 | Console.WriteLine("Web Error" + e.Message); | ||
1241 | Console.WriteLine ("Please check input"); | ||
1242 | return false; | ||
1243 | } | ||
1244 | |||
1245 | byte[] buf = new byte[8192]; | ||
1246 | Stream rstream = webResponse.GetResponseStream(); | ||
1247 | OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); | ||
1248 | |||
1249 | if(mret.ContainsKey("error")) | ||
1250 | return false; | ||
1251 | |||
1252 | // get params... | ||
1253 | OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]); | ||
1254 | return true; | ||
1255 | } | ||
1256 | |||
1257 | /// <summary> | ||
1258 | /// Sends json-rpc request with OSD parameter. | ||
1259 | /// </summary> | ||
1260 | /// <returns> | ||
1261 | /// The rpc request. | ||
1262 | /// </returns> | ||
1263 | /// <param name='data'> | ||
1264 | /// data - incoming as parameters, outgong as result/error | ||
1265 | /// </param> | ||
1266 | /// <param name='method'> | ||
1267 | /// Json-rpc method to call. | ||
1268 | /// </param> | ||
1269 | /// <param name='uri'> | ||
1270 | /// URI of json-rpc service. | ||
1271 | /// </param> | ||
1272 | /// <param name='jsonId'> | ||
1273 | /// If set to <c>true</c> json identifier. | ||
1274 | /// </param> | ||
1275 | bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId) | ||
1276 | { | ||
1277 | OSDMap map = new OSDMap(); | ||
1278 | |||
1279 | map["jsonrpc"] = "2.0"; | ||
1280 | if(string.IsNullOrEmpty(jsonId)) | ||
1281 | map["id"] = UUID.Random().ToString(); | ||
1282 | else | ||
1283 | map["id"] = jsonId; | ||
1284 | |||
1285 | map["method"] = method; | ||
1286 | map["params"] = data; | ||
1287 | |||
1288 | string jsonRequestData = OSDParser.SerializeJsonString(map); | ||
1289 | byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); | ||
1290 | |||
1291 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
1292 | webRequest.ContentType = "application/json-rpc"; | ||
1293 | webRequest.Method = "POST"; | ||
1294 | |||
1295 | Stream dataStream = webRequest.GetRequestStream(); | ||
1296 | dataStream.Write(content, 0, content.Length); | ||
1297 | dataStream.Close(); | ||
1298 | |||
1299 | WebResponse webResponse = null; | ||
1300 | try | ||
1301 | { | ||
1302 | webResponse = webRequest.GetResponse(); | ||
1303 | } | ||
1304 | catch (WebException e) | ||
1305 | { | ||
1306 | Console.WriteLine("Web Error" + e.Message); | ||
1307 | Console.WriteLine ("Please check input"); | ||
1308 | return false; | ||
1309 | } | ||
1310 | |||
1311 | byte[] buf = new byte[8192]; | ||
1312 | Stream rstream = webResponse.GetResponseStream(); | ||
1313 | |||
1314 | OSDMap response = new OSDMap(); | ||
1315 | response = (OSDMap)OSDParser.DeserializeJson(rstream); | ||
1316 | if(response.ContainsKey("error")) | ||
1317 | { | ||
1318 | data = response["error"]; | ||
1319 | return false; | ||
1320 | } | ||
1321 | |||
1322 | data = response; | ||
1323 | |||
1324 | return true; | ||
1325 | } | ||
1326 | #endregion Web Util | ||
1327 | } | ||
1328 | } | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs new file mode 100644 index 0000000..323535a --- /dev/null +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs | |||
@@ -0,0 +1,226 @@ | |||
1 | |||
2 | /* | ||
3 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
4 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of the OpenSimulator Project nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
20 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
27 | */ | ||
28 | |||
29 | using log4net; | ||
30 | using Mono.Addins; | ||
31 | using Nini.Config; | ||
32 | using System; | ||
33 | using System.Collections.Generic; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Console; | ||
37 | using OpenSim.Server.Base; | ||
38 | using OpenSim.Server.Handlers; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenSim.Services.Interfaces; | ||
44 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
45 | using OpenMetaverse; | ||
46 | |||
47 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile | ||
48 | { | ||
49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalUserProfilesServicesConnector")] | ||
50 | public class LocalUserProfilesServicesConnector : ISharedRegionModule | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private Dictionary<UUID, Scene> regions = new Dictionary<UUID, Scene>(); | ||
57 | |||
58 | public IUserProfilesService ServiceModule | ||
59 | { | ||
60 | get; private set; | ||
61 | } | ||
62 | |||
63 | public bool Enabled | ||
64 | { | ||
65 | get; private set; | ||
66 | } | ||
67 | |||
68 | public string Name | ||
69 | { | ||
70 | get | ||
71 | { | ||
72 | return "LocalUserProfilesServicesConnector"; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public string ConfigName | ||
77 | { | ||
78 | get; private set; | ||
79 | } | ||
80 | |||
81 | public Type ReplaceableInterface | ||
82 | { | ||
83 | get { return null; } | ||
84 | } | ||
85 | |||
86 | public LocalUserProfilesServicesConnector() | ||
87 | { | ||
88 | m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params"); | ||
89 | } | ||
90 | |||
91 | public LocalUserProfilesServicesConnector(IConfigSource source) | ||
92 | { | ||
93 | m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly."); | ||
94 | InitialiseService(source); | ||
95 | } | ||
96 | |||
97 | public void InitialiseService(IConfigSource source) | ||
98 | { | ||
99 | ConfigName = "UserProfilesService"; | ||
100 | |||
101 | // Instantiate the request handler | ||
102 | IHttpServer Server = MainServer.Instance; | ||
103 | |||
104 | IConfig config = source.Configs[ConfigName]; | ||
105 | if (config == null) | ||
106 | { | ||
107 | m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini"); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | if(!config.GetBoolean("Enabled",false)) | ||
112 | { | ||
113 | Enabled = false; | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | Enabled = true; | ||
118 | |||
119 | string serviceDll = config.GetString("LocalServiceModule", | ||
120 | String.Empty); | ||
121 | |||
122 | if (serviceDll == String.Empty) | ||
123 | { | ||
124 | m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService"); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | Object[] args = new Object[] { source, ConfigName }; | ||
129 | ServiceModule = | ||
130 | ServerUtils.LoadPlugin<IUserProfilesService>(serviceDll, | ||
131 | args); | ||
132 | |||
133 | if (ServiceModule == null) | ||
134 | { | ||
135 | m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service"); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | Enabled = true; | ||
140 | |||
141 | JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule); | ||
142 | |||
143 | Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest); | ||
144 | Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate); | ||
145 | Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest); | ||
146 | Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete); | ||
147 | Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest); | ||
148 | Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest); | ||
149 | Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate); | ||
150 | Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete); | ||
151 | Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest); | ||
152 | Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate); | ||
153 | Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); | ||
154 | Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); | ||
155 | Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); | ||
156 | Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); | ||
157 | Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); | ||
158 | Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); | ||
159 | |||
160 | } | ||
161 | |||
162 | #region ISharedRegionModule implementation | ||
163 | |||
164 | void ISharedRegionModule.PostInitialise() | ||
165 | { | ||
166 | if(!Enabled) | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | #endregion | ||
171 | |||
172 | #region IRegionModuleBase implementation | ||
173 | |||
174 | void IRegionModuleBase.Initialise(IConfigSource source) | ||
175 | { | ||
176 | IConfig moduleConfig = source.Configs["Modules"]; | ||
177 | if (moduleConfig != null) | ||
178 | { | ||
179 | string name = moduleConfig.GetString("UserProfilesServices", ""); | ||
180 | if (name == Name) | ||
181 | { | ||
182 | InitialiseService(source); | ||
183 | m_log.Info("[LOCAL USERPROFILES SERVICE CONNECTOR]: Local user profiles connector enabled"); | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | void IRegionModuleBase.Close() | ||
189 | { | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | void IRegionModuleBase.AddRegion(Scene scene) | ||
194 | { | ||
195 | if (!Enabled) | ||
196 | return; | ||
197 | |||
198 | lock (regions) | ||
199 | { | ||
200 | if (regions.ContainsKey(scene.RegionInfo.RegionID)) | ||
201 | m_log.ErrorFormat("[LOCAL USERPROFILES SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); | ||
202 | else | ||
203 | regions.Add(scene.RegionInfo.RegionID, scene); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | void IRegionModuleBase.RemoveRegion(Scene scene) | ||
208 | { | ||
209 | if (!Enabled) | ||
210 | return; | ||
211 | |||
212 | lock (regions) | ||
213 | { | ||
214 | if (regions.ContainsKey(scene.RegionInfo.RegionID)) | ||
215 | regions.Remove(scene.RegionInfo.RegionID); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void IRegionModuleBase.RegionLoaded(Scene scene) | ||
220 | { | ||
221 | if (!Enabled) | ||
222 | return; | ||
223 | } | ||
224 | #endregion | ||
225 | } | ||
226 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index c32820e..3849a3f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs | |||
@@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
56 | 56 | ||
57 | public LocalGridServicesConnector() | 57 | public LocalGridServicesConnector() |
58 | { | 58 | { |
59 | m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms."); | ||
59 | } | 60 | } |
60 | 61 | ||
61 | public LocalGridServicesConnector(IConfigSource source) | 62 | public LocalGridServicesConnector(IConfigSource source) |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index 66edfed..5dee64d 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs | |||
@@ -28,8 +28,11 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Text; | ||
31 | using log4net; | 32 | using log4net; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.StructuredData; | ||
35 | |||
33 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
34 | 37 | ||
35 | using Animation = OpenSim.Framework.Animation; | 38 | using Animation = OpenSim.Framework.Animation; |
@@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
60 | ResetDefaultAnimation(); | 63 | ResetDefaultAnimation(); |
61 | } | 64 | } |
62 | 65 | ||
66 | public AnimationSet(OSDArray pArray) | ||
67 | { | ||
68 | ResetDefaultAnimation(); | ||
69 | FromOSDArray(pArray); | ||
70 | } | ||
71 | |||
63 | public bool HasAnimation(UUID animID) | 72 | public bool HasAnimation(UUID animID) |
64 | { | 73 | { |
65 | if (m_defaultAnimation.AnimID == animID) | 74 | if (m_defaultAnimation.AnimID == animID) |
@@ -218,5 +227,106 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
218 | foreach (OpenSim.Framework.Animation anim in theArray) | 227 | foreach (OpenSim.Framework.Animation anim in theArray) |
219 | m_animations.Add(anim); | 228 | m_animations.Add(anim); |
220 | } | 229 | } |
230 | |||
231 | // Create representation of this AnimationSet as an OSDArray. | ||
232 | // First two entries in the array are the default and implicitDefault animations | ||
233 | // followed by the other animations. | ||
234 | public OSDArray ToOSDArray() | ||
235 | { | ||
236 | OSDArray ret = new OSDArray(); | ||
237 | ret.Add(DefaultAnimation.PackUpdateMessage()); | ||
238 | ret.Add(ImplicitDefaultAnimation.PackUpdateMessage()); | ||
239 | |||
240 | foreach (OpenSim.Framework.Animation anim in m_animations) | ||
241 | ret.Add(anim.PackUpdateMessage()); | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | public void FromOSDArray(OSDArray pArray) | ||
247 | { | ||
248 | this.Clear(); | ||
249 | |||
250 | if (pArray.Count >= 1) | ||
251 | { | ||
252 | m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]); | ||
253 | } | ||
254 | if (pArray.Count >= 2) | ||
255 | { | ||
256 | m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]); | ||
257 | } | ||
258 | for (int ii = 2; ii < pArray.Count; ii++) | ||
259 | { | ||
260 | m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii])); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | // Compare two AnimationSets and return 'true' if the default animations are the same | ||
265 | // and all of the animations in the list are equal. | ||
266 | public override bool Equals(object obj) | ||
267 | { | ||
268 | AnimationSet other = obj as AnimationSet; | ||
269 | if (other != null) | ||
270 | { | ||
271 | if (this.DefaultAnimation.Equals(other.DefaultAnimation) | ||
272 | && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation)) | ||
273 | { | ||
274 | // The defaults are the same. Is the list of animations the same? | ||
275 | OpenSim.Framework.Animation[] thisAnims = this.ToArray(); | ||
276 | OpenSim.Framework.Animation[] otherAnims = other.ToArray(); | ||
277 | if (thisAnims.Length == 0 && otherAnims.Length == 0) | ||
278 | return true; // the common case | ||
279 | if (thisAnims.Length == otherAnims.Length) | ||
280 | { | ||
281 | // Do this the hard way but since the list is usually short this won't take long. | ||
282 | foreach (OpenSim.Framework.Animation thisAnim in thisAnims) | ||
283 | { | ||
284 | bool found = false; | ||
285 | foreach (OpenSim.Framework.Animation otherAnim in otherAnims) | ||
286 | { | ||
287 | if (thisAnim.Equals(otherAnim)) | ||
288 | { | ||
289 | found = true; | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | if (!found) | ||
294 | { | ||
295 | // If anything is not in the other list, these are not equal | ||
296 | return false; | ||
297 | } | ||
298 | } | ||
299 | // Found everything in the other list. Since lists are equal length, they must be equal. | ||
300 | return true; | ||
301 | } | ||
302 | } | ||
303 | return false; | ||
304 | } | ||
305 | // Don't know what was passed, but the base system will figure it out for me. | ||
306 | return base.Equals(obj); | ||
307 | } | ||
308 | |||
309 | public override string ToString() | ||
310 | { | ||
311 | StringBuilder buff = new StringBuilder(); | ||
312 | buff.Append("dflt="); | ||
313 | buff.Append(DefaultAnimation.ToString()); | ||
314 | buff.Append(",iDflt="); | ||
315 | if (DefaultAnimation == ImplicitDefaultAnimation) | ||
316 | buff.Append("same"); | ||
317 | else | ||
318 | buff.Append(ImplicitDefaultAnimation.ToString()); | ||
319 | if (m_animations.Count > 0) | ||
320 | { | ||
321 | buff.Append(",anims="); | ||
322 | foreach (OpenSim.Framework.Animation anim in m_animations) | ||
323 | { | ||
324 | buff.Append("<"); | ||
325 | buff.Append(anim.ToString()); | ||
326 | buff.Append(">,"); | ||
327 | } | ||
328 | } | ||
329 | return buff.ToString(); | ||
330 | } | ||
221 | } | 331 | } |
222 | } | 332 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs index c2b0468..b79dd8f 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs | |||
@@ -104,5 +104,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
104 | 104 | ||
105 | return UUID.Zero; | 105 | return UUID.Zero; |
106 | } | 106 | } |
107 | |||
108 | /// <summary> | ||
109 | /// Get the name of the animation given a UUID. If there is no matching animation | ||
110 | /// return the UUID as a string. | ||
111 | /// </summary> | ||
112 | public static string GetDefaultAnimationName(UUID uuid) | ||
113 | { | ||
114 | string ret = "unknown"; | ||
115 | if (AnimsUUID.ContainsValue(uuid)) | ||
116 | { | ||
117 | foreach (KeyValuePair<string, UUID> kvp in AnimsUUID) | ||
118 | { | ||
119 | if (kvp.Value == uuid) | ||
120 | { | ||
121 | ret = kvp.Key; | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | ret = uuid.ToString(); | ||
129 | } | ||
130 | |||
131 | return ret; | ||
132 | } | ||
107 | } | 133 | } |
108 | } \ No newline at end of file | 134 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 65c279e..eb70eee 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -93,7 +93,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
93 | GetAnimName(animID), animID, m_scenePresence.Name); | 93 | GetAnimName(animID), animID, m_scenePresence.Name); |
94 | 94 | ||
95 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) | 95 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) |
96 | { | ||
96 | SendAnimPack(); | 97 | SendAnimPack(); |
98 | } | ||
97 | } | 99 | } |
98 | 100 | ||
99 | // Called from scripts | 101 | // Called from scripts |
@@ -132,7 +134,9 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
132 | GetAnimName(animID), animID, m_scenePresence.Name); | 134 | GetAnimName(animID), animID, m_scenePresence.Name); |
133 | 135 | ||
134 | if (m_animations.Remove(animID, allowNoDefault)) | 136 | if (m_animations.Remove(animID, allowNoDefault)) |
137 | { | ||
135 | SendAnimPack(); | 138 | SendAnimPack(); |
139 | } | ||
136 | } | 140 | } |
137 | 141 | ||
138 | public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) | 142 | public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) |
@@ -180,8 +184,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
180 | /// The movement animation is reserved for "main" animations | 184 | /// The movement animation is reserved for "main" animations |
181 | /// that are mutually exclusive, e.g. flying and sitting. | 185 | /// that are mutually exclusive, e.g. flying and sitting. |
182 | /// </summary> | 186 | /// </summary> |
183 | public void TrySetMovementAnimation(string anim) | 187 | /// <returns>'true' if the animation was updated</returns> |
188 | public bool TrySetMovementAnimation(string anim) | ||
184 | { | 189 | { |
190 | bool ret = false; | ||
185 | if (!m_scenePresence.IsChildAgent) | 191 | if (!m_scenePresence.IsChildAgent) |
186 | { | 192 | { |
187 | // m_log.DebugFormat( | 193 | // m_log.DebugFormat( |
@@ -198,6 +204,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
198 | // 16384 is CHANGED_ANIMATION | 204 | // 16384 is CHANGED_ANIMATION |
199 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); | 205 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); |
200 | SendAnimPack(); | 206 | SendAnimPack(); |
207 | ret = true; | ||
201 | } | 208 | } |
202 | } | 209 | } |
203 | else | 210 | else |
@@ -206,6 +213,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
206 | "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", | 213 | "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", |
207 | anim, m_scenePresence.Name); | 214 | anim, m_scenePresence.Name); |
208 | } | 215 | } |
216 | return ret; | ||
209 | } | 217 | } |
210 | 218 | ||
211 | /// <summary> | 219 | /// <summary> |
@@ -439,8 +447,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
439 | /// <summary> | 447 | /// <summary> |
440 | /// Update the movement animation of this avatar according to its current state | 448 | /// Update the movement animation of this avatar according to its current state |
441 | /// </summary> | 449 | /// </summary> |
442 | public void UpdateMovementAnimations() | 450 | /// <returns>'true' if the animation was changed</returns> |
451 | public bool UpdateMovementAnimations() | ||
443 | { | 452 | { |
453 | bool ret = false; | ||
444 | lock (m_animations) | 454 | lock (m_animations) |
445 | { | 455 | { |
446 | string newMovementAnimation = DetermineMovementAnimation(); | 456 | string newMovementAnimation = DetermineMovementAnimation(); |
@@ -454,9 +464,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
454 | 464 | ||
455 | // Only set it if it's actually changed, give a script | 465 | // Only set it if it's actually changed, give a script |
456 | // a chance to stop a default animation | 466 | // a chance to stop a default animation |
457 | TrySetMovementAnimation(CurrentMovementAnimation); | 467 | ret = TrySetMovementAnimation(CurrentMovementAnimation); |
458 | } | 468 | } |
459 | } | 469 | } |
470 | return ret; | ||
460 | } | 471 | } |
461 | 472 | ||
462 | public UUID[] GetAnimationArray() | 473 | public UUID[] GetAnimationArray() |
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 4733547..4fec44f 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs | |||
@@ -974,6 +974,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
974 | public delegate void RegionStarted(Scene scene); | 974 | public delegate void RegionStarted(Scene scene); |
975 | public event RegionStarted OnRegionStarted; | 975 | public event RegionStarted OnRegionStarted; |
976 | 976 | ||
977 | public delegate void RegionHeartbeatStart(Scene scene); | ||
978 | public event RegionHeartbeatStart OnRegionHeartbeatStart; | ||
977 | public delegate void RegionHeartbeatEnd(Scene scene); | 979 | public delegate void RegionHeartbeatEnd(Scene scene); |
978 | public event RegionHeartbeatEnd OnRegionHeartbeatEnd; | 980 | public event RegionHeartbeatEnd OnRegionHeartbeatEnd; |
979 | 981 | ||
@@ -3096,6 +3098,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
3096 | } | 3098 | } |
3097 | } | 3099 | } |
3098 | 3100 | ||
3101 | public void TriggerRegionHeartbeatStart(Scene scene) | ||
3102 | { | ||
3103 | RegionHeartbeatStart handler = OnRegionHeartbeatStart; | ||
3104 | |||
3105 | if (handler != null) | ||
3106 | { | ||
3107 | foreach (RegionHeartbeatStart d in handler.GetInvocationList()) | ||
3108 | { | ||
3109 | try | ||
3110 | { | ||
3111 | d(scene); | ||
3112 | } | ||
3113 | catch (Exception e) | ||
3114 | { | ||
3115 | m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}", | ||
3116 | e.Message, e.StackTrace); | ||
3117 | } | ||
3118 | } | ||
3119 | } | ||
3120 | } | ||
3121 | |||
3099 | public void TriggerRegionHeartbeatEnd(Scene scene) | 3122 | public void TriggerRegionHeartbeatEnd(Scene scene) |
3100 | { | 3123 | { |
3101 | RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; | 3124 | RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 6bac468..6ef83fb 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -1569,6 +1569,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1569 | 1569 | ||
1570 | try | 1570 | try |
1571 | { | 1571 | { |
1572 | EventManager.TriggerRegionHeartbeatStart(this); | ||
1573 | |||
1572 | // Apply taints in terrain module to terrain in physics scene | 1574 | // Apply taints in terrain module to terrain in physics scene |
1573 | if (Frame % m_update_terrain == 0) | 1575 | if (Frame % m_update_terrain == 0) |
1574 | { | 1576 | { |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 83bd3fb..1859cb1 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -2310,6 +2310,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2310 | AddToPhysicalScene(false); | 2310 | AddToPhysicalScene(false); |
2311 | 2311 | ||
2312 | Animator.TrySetMovementAnimation("STAND"); | 2312 | Animator.TrySetMovementAnimation("STAND"); |
2313 | TriggerScenePresenceUpdated(); | ||
2313 | } | 2314 | } |
2314 | 2315 | ||
2315 | private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) | 2316 | private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) |
@@ -2408,7 +2409,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2408 | ControllingClient.SendSitResponse( | 2409 | ControllingClient.SendSitResponse( |
2409 | part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); | 2410 | part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); |
2410 | 2411 | ||
2411 | m_requestedSitTargetUUID = targetID; | 2412 | m_requestedSitTargetUUID = part.UUID; |
2412 | 2413 | ||
2413 | HandleAgentSit(ControllingClient, UUID); | 2414 | HandleAgentSit(ControllingClient, UUID); |
2414 | 2415 | ||
@@ -2436,7 +2437,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2436 | if (part != null) | 2437 | if (part != null) |
2437 | { | 2438 | { |
2438 | m_requestedSitTargetID = part.LocalId; | 2439 | m_requestedSitTargetID = part.LocalId; |
2439 | m_requestedSitTargetUUID = targetID; | 2440 | m_requestedSitTargetUUID = part.UUID; |
2440 | 2441 | ||
2441 | } | 2442 | } |
2442 | else | 2443 | else |
@@ -2635,6 +2636,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2635 | } | 2636 | } |
2636 | Animator.TrySetMovementAnimation(sitAnimation); | 2637 | Animator.TrySetMovementAnimation(sitAnimation); |
2637 | SendAvatarDataToAllAgents(); | 2638 | SendAvatarDataToAllAgents(); |
2639 | TriggerScenePresenceUpdated(); | ||
2638 | } | 2640 | } |
2639 | } | 2641 | } |
2640 | 2642 | ||
@@ -2643,6 +2645,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2643 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. | 2645 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. |
2644 | m_AngularVelocity = Vector3.Zero; | 2646 | m_AngularVelocity = Vector3.Zero; |
2645 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | 2647 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); |
2648 | TriggerScenePresenceUpdated(); | ||
2646 | SitGround = true; | 2649 | SitGround = true; |
2647 | RemoveFromPhysicalScene(); | 2650 | RemoveFromPhysicalScene(); |
2648 | } | 2651 | } |
@@ -2659,11 +2662,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2659 | public void HandleStartAnim(IClientAPI remoteClient, UUID animID) | 2662 | public void HandleStartAnim(IClientAPI remoteClient, UUID animID) |
2660 | { | 2663 | { |
2661 | Animator.AddAnimation(animID, UUID.Zero); | 2664 | Animator.AddAnimation(animID, UUID.Zero); |
2665 | TriggerScenePresenceUpdated(); | ||
2662 | } | 2666 | } |
2663 | 2667 | ||
2664 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) | 2668 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) |
2665 | { | 2669 | { |
2666 | Animator.RemoveAnimation(animID, false); | 2670 | Animator.RemoveAnimation(animID, false); |
2671 | TriggerScenePresenceUpdated(); | ||
2667 | } | 2672 | } |
2668 | 2673 | ||
2669 | public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) | 2674 | public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) |
@@ -3693,7 +3698,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3693 | 3698 | ||
3694 | // if (m_updateCount > 0) | 3699 | // if (m_updateCount > 0) |
3695 | // { | 3700 | // { |
3696 | Animator.UpdateMovementAnimations(); | 3701 | if (Animator.UpdateMovementAnimations()) |
3702 | TriggerScenePresenceUpdated(); | ||
3697 | // m_updateCount--; | 3703 | // m_updateCount--; |
3698 | // } | 3704 | // } |
3699 | 3705 | ||
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs index 20affa6..2f07c42 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | |||
@@ -841,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice | |||
841 | requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); | 841 | requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); |
842 | requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); | 842 | requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); |
843 | requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); | 843 | requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); |
844 | requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); | 844 | requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance); |
845 | 845 | ||
846 | XmlElement resp = VivoxCall(requrl, true); | 846 | XmlElement resp = VivoxCall(requrl, true); |
847 | if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) | 847 | if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 2651e3b..afd547a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -54,6 +54,9 @@ public static class BSParam | |||
54 | // =================== | 54 | // =================== |
55 | // From: | 55 | // From: |
56 | 56 | ||
57 | public static bool UseSeparatePhysicsThread { get; private set; } | ||
58 | public static float PhysicsTimeStep { get; private set; } | ||
59 | |||
57 | // Level of Detail values kept as float because that's what the Meshmerizer wants | 60 | // Level of Detail values kept as float because that's what the Meshmerizer wants |
58 | public static float MeshLOD { get; private set; } | 61 | public static float MeshLOD { get; private set; } |
59 | public static float MeshCircularLOD { get; private set; } | 62 | public static float MeshCircularLOD { get; private set; } |
@@ -354,6 +357,11 @@ public static class BSParam | |||
354 | // v = value (appropriate type) | 357 | // v = value (appropriate type) |
355 | private static ParameterDefnBase[] ParameterDefinitions = | 358 | private static ParameterDefnBase[] ParameterDefinitions = |
356 | { | 359 | { |
360 | new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", | ||
361 | false ), | ||
362 | new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", | ||
363 | 0.1f ), | ||
364 | |||
357 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | 365 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", |
358 | true, | 366 | true, |
359 | (s) => { return ShouldMeshSculptedPrim; }, | 367 | (s) => { return ShouldMeshSculptedPrim; }, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e11e365..95bdc7b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -1513,7 +1513,8 @@ public class BSPrim : BSPhysObject | |||
1513 | CurrentEntityProperties = entprop; | 1513 | CurrentEntityProperties = entprop; |
1514 | 1514 | ||
1515 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. | 1515 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. |
1516 | base.RequestPhysicsterseUpdate(); | 1516 | |
1517 | PhysScene.PostUpdate(this); | ||
1517 | } | 1518 | } |
1518 | } | 1519 | } |
1519 | } | 1520 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 39f5b0a..423c389 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
56 | public string BulletEngineName { get; private set; } | 56 | public string BulletEngineName { get; private set; } |
57 | public BSAPITemplate PE; | 57 | public BSAPITemplate PE; |
58 | 58 | ||
59 | // If the physics engine is running on a separate thread | ||
60 | public Thread m_physicsThread; | ||
61 | |||
59 | public Dictionary<uint, BSPhysObject> PhysObjects; | 62 | public Dictionary<uint, BSPhysObject> PhysObjects; |
60 | public BSShapeCollection Shapes; | 63 | public BSShapeCollection Shapes; |
61 | 64 | ||
62 | // Keeping track of the objects with collisions so we can report begin and end of a collision | 65 | // Keeping track of the objects with collisions so we can report begin and end of a collision |
63 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | 66 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); |
64 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | 67 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); |
68 | |||
69 | // All the collision processing is protected with this lock object | ||
70 | public Object CollisionLock = new Object(); | ||
71 | |||
72 | // Properties are updated here | ||
73 | public Object UpdateLock = new Object(); | ||
74 | public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
75 | |||
65 | // Keep track of all the avatars so we can send them a collision event | 76 | // Keep track of all the avatars so we can send them a collision event |
66 | // every tick so OpenSim will update its animation. | 77 | // every tick so OpenSim will update its animation. |
67 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 78 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |
@@ -77,12 +88,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
77 | public BSConstraintCollection Constraints { get; private set; } | 88 | public BSConstraintCollection Constraints { get; private set; } |
78 | 89 | ||
79 | // Simulation parameters | 90 | // Simulation parameters |
91 | internal float m_physicsStepTime; // if running independently, the interval simulated by default | ||
92 | |||
80 | internal int m_maxSubSteps; | 93 | internal int m_maxSubSteps; |
81 | internal float m_fixedTimeStep; | 94 | internal float m_fixedTimeStep; |
82 | internal long m_simulationStep = 0; | 95 | |
83 | internal float NominalFrameRate { get; set; } | 96 | internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc. |
97 | |||
98 | internal long m_simulationStep = 0; // The current simulation step. | ||
84 | public long SimulationStep { get { return m_simulationStep; } } | 99 | public long SimulationStep { get { return m_simulationStep; } } |
85 | internal float LastTimeStep { get; private set; } | 100 | |
101 | internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() | ||
102 | |||
103 | internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to | ||
86 | 104 | ||
87 | // Physical objects can register for prestep or poststep events | 105 | // Physical objects can register for prestep or poststep events |
88 | public delegate void PreStepAction(float timeStep); | 106 | public delegate void PreStepAction(float timeStep); |
@@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | public event PreStepAction BeforeStep; | 108 | public event PreStepAction BeforeStep; |
91 | public event PostStepAction AfterStep; | 109 | public event PostStepAction AfterStep; |
92 | 110 | ||
93 | // A value of the time now so all the collision and update routines do not have to get their own | 111 | // A value of the time 'now' so all the collision and update routines do not have to get their own |
94 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 112 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
95 | public int SimulationNowTime { get; private set; } | 113 | public int SimulationNowTime { get; private set; } |
96 | 114 | ||
@@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
188 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | 206 | PhysObjects = new Dictionary<uint, BSPhysObject>(); |
189 | Shapes = new BSShapeCollection(this); | 207 | Shapes = new BSShapeCollection(this); |
190 | 208 | ||
209 | m_simulatedTime = 0f; | ||
210 | LastTimeStep = 0.1f; | ||
211 | |||
191 | // Allocate pinned memory to pass parameters. | 212 | // Allocate pinned memory to pass parameters. |
192 | UnmanagedParams = new ConfigurationParameters[1]; | 213 | UnmanagedParams = new ConfigurationParameters[1]; |
193 | 214 | ||
@@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
227 | TerrainManager = new BSTerrainManager(this); | 248 | TerrainManager = new BSTerrainManager(this); |
228 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 249 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
229 | 250 | ||
251 | // Put some informational messages into the log file. | ||
230 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | 252 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); |
231 | 253 | ||
232 | InTaintTime = false; | 254 | InTaintTime = false; |
233 | m_initialized = true; | 255 | m_initialized = true; |
256 | |||
257 | // If the physics engine runs on its own thread, start same. | ||
258 | if (BSParam.UseSeparatePhysicsThread) | ||
259 | { | ||
260 | // The physics simulation should happen independently of the heartbeat loop | ||
261 | m_physicsThread = new Thread(BulletSPluginPhysicsThread); | ||
262 | m_physicsThread.Name = BulletEngineName; | ||
263 | m_physicsThread.Start(); | ||
264 | } | ||
234 | } | 265 | } |
235 | 266 | ||
236 | // All default parameter values are set here. There should be no values set in the | 267 | // All default parameter values are set here. There should be no values set in the |
@@ -270,6 +301,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
270 | } | 301 | } |
271 | else | 302 | else |
272 | { | 303 | { |
304 | // Nothing in the configuration INI file so assume unmanaged and other defaults. | ||
273 | BulletEngineName = "BulletUnmanaged"; | 305 | BulletEngineName = "BulletUnmanaged"; |
274 | m_physicsLoggingEnabled = false; | 306 | m_physicsLoggingEnabled = false; |
275 | VehicleLoggingEnabled = false; | 307 | VehicleLoggingEnabled = false; |
@@ -317,6 +349,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
317 | 349 | ||
318 | switch (selectionName) | 350 | switch (selectionName) |
319 | { | 351 | { |
352 | case "bullet": | ||
320 | case "bulletunmanaged": | 353 | case "bulletunmanaged": |
321 | ret = new BSAPIUnman(engineName, this); | 354 | ret = new BSAPIUnman(engineName, this); |
322 | break; | 355 | break; |
@@ -494,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
494 | #endregion // Prim and Avatar addition and removal | 527 | #endregion // Prim and Avatar addition and removal |
495 | 528 | ||
496 | #region Simulation | 529 | #region Simulation |
497 | // Simulate one timestep | 530 | |
531 | // Call from the simulator to send physics information to the simulator objects. | ||
532 | // This pushes all the collision and property update events into the objects in | ||
533 | // the simulator and, since it is on the heartbeat thread, there is an implicit | ||
534 | // locking of those data structures from other heartbeat events. | ||
535 | // If the physics engine is running on a separate thread, the update information | ||
536 | // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. | ||
498 | public override float Simulate(float timeStep) | 537 | public override float Simulate(float timeStep) |
499 | { | 538 | { |
539 | if (!BSParam.UseSeparatePhysicsThread) | ||
540 | { | ||
541 | DoPhysicsStep(timeStep); | ||
542 | } | ||
543 | return SendUpdatesToSimulator(timeStep); | ||
544 | } | ||
545 | |||
546 | // Call the physics engine to do one 'timeStep' and collect collisions and updates | ||
547 | // into ObjectsWithCollisions and ObjectsWithUpdates data structures. | ||
548 | private void DoPhysicsStep(float timeStep) | ||
549 | { | ||
500 | // prevent simulation until we've been initialized | 550 | // prevent simulation until we've been initialized |
501 | if (!m_initialized) return 5.0f; | 551 | if (!m_initialized) return; |
502 | 552 | ||
503 | LastTimeStep = timeStep; | 553 | LastTimeStep = timeStep; |
504 | 554 | ||
505 | int updatedEntityCount = 0; | 555 | int updatedEntityCount = 0; |
506 | int collidersCount = 0; | 556 | int collidersCount = 0; |
507 | 557 | ||
508 | int beforeTime = 0; | 558 | int beforeTime = Util.EnvironmentTickCount(); |
509 | int simTime = 0; | 559 | int simTime = 0; |
510 | 560 | ||
511 | // update the prim states while we know the physics engine is not busy | ||
512 | int numTaints = _taintOperations.Count; | 561 | int numTaints = _taintOperations.Count; |
513 | |||
514 | InTaintTime = true; // Only used for debugging so locking is not necessary. | 562 | InTaintTime = true; // Only used for debugging so locking is not necessary. |
515 | 563 | ||
564 | // update the prim states while we know the physics engine is not busy | ||
516 | ProcessTaints(); | 565 | ProcessTaints(); |
517 | 566 | ||
518 | // Some of the physical objects requre individual, pre-step calls | 567 | // Some of the physical objects requre individual, pre-step calls |
@@ -535,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
535 | int numSubSteps = 0; | 584 | int numSubSteps = 0; |
536 | try | 585 | try |
537 | { | 586 | { |
538 | if (PhysicsLogging.Enabled) | ||
539 | beforeTime = Util.EnvironmentTickCount(); | ||
540 | |||
541 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); | 587 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
542 | 588 | ||
543 | if (PhysicsLogging.Enabled) | ||
544 | { | ||
545 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
546 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
547 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
548 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
549 | } | ||
550 | } | 589 | } |
551 | catch (Exception e) | 590 | catch (Exception e) |
552 | { | 591 | { |
@@ -558,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
558 | collidersCount = 0; | 597 | collidersCount = 0; |
559 | } | 598 | } |
560 | 599 | ||
600 | // Make the physics engine dump useful statistics periodically | ||
561 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) | 601 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
562 | PE.DumpPhysicsStatistics(World); | 602 | PE.DumpPhysicsStatistics(World); |
563 | 603 | ||
564 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 604 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
565 | SimulationNowTime = Util.EnvironmentTickCount(); | 605 | SimulationNowTime = Util.EnvironmentTickCount(); |
566 | 606 | ||
567 | // If there were collisions, process them by sending the event to the prim. | 607 | // Send collision information to the colliding objects. The objects decide if the collision |
568 | // Collisions must be processed before updates. | 608 | // is 'real' (like linksets don't collide with themselves) and the individual objects |
569 | if (collidersCount > 0) | 609 | // know if the simulator has subscribed to collisions. |
610 | lock (CollisionLock) | ||
570 | { | 611 | { |
571 | for (int ii = 0; ii < collidersCount; ii++) | 612 | if (collidersCount > 0) |
572 | { | 613 | { |
573 | uint cA = m_collisionArray[ii].aID; | 614 | for (int ii = 0; ii < collidersCount; ii++) |
574 | uint cB = m_collisionArray[ii].bID; | ||
575 | Vector3 point = m_collisionArray[ii].point; | ||
576 | Vector3 normal = m_collisionArray[ii].normal; | ||
577 | float penetration = m_collisionArray[ii].penetration; | ||
578 | SendCollision(cA, cB, point, normal, penetration); | ||
579 | SendCollision(cB, cA, point, -normal, penetration); | ||
580 | } | ||
581 | } | ||
582 | |||
583 | // The above SendCollision's batch up the collisions on the objects. | ||
584 | // Now push the collisions into the simulator. | ||
585 | if (ObjectsWithCollisions.Count > 0) | ||
586 | { | ||
587 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
588 | if (!bsp.SendCollisions()) | ||
589 | { | 615 | { |
590 | // If the object is done colliding, see that it's removed from the colliding list | 616 | uint cA = m_collisionArray[ii].aID; |
591 | ObjectsWithNoMoreCollisions.Add(bsp); | 617 | uint cB = m_collisionArray[ii].bID; |
618 | Vector3 point = m_collisionArray[ii].point; | ||
619 | Vector3 normal = m_collisionArray[ii].normal; | ||
620 | float penetration = m_collisionArray[ii].penetration; | ||
621 | SendCollision(cA, cB, point, normal, penetration); | ||
622 | SendCollision(cB, cA, point, -normal, penetration); | ||
592 | } | 623 | } |
624 | } | ||
593 | } | 625 | } |
594 | 626 | ||
595 | // This is a kludge to get avatar movement updates. | 627 | // If any of the objects had updated properties, tell the managed objects about the update |
596 | // The simulator expects collisions for avatars even if there are have been no collisions. | 628 | // and remember that there was a change so it will be passed to the simulator. |
597 | // The event updates avatar animations and stuff. | 629 | lock (UpdateLock) |
598 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
599 | foreach (BSPhysObject bsp in m_avatars) | ||
600 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
601 | bsp.SendCollisions(); | ||
602 | |||
603 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
604 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
605 | // This complex collision processing is required to create an empty collision | ||
606 | // event call after all real collisions have happened on an object. This enables | ||
607 | // the simulator to generate the 'collision end' event. | ||
608 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
609 | { | ||
610 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
611 | ObjectsWithCollisions.Remove(po); | ||
612 | ObjectsWithNoMoreCollisions.Clear(); | ||
613 | } | ||
614 | // Done with collisions. | ||
615 | |||
616 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | ||
617 | if (updatedEntityCount > 0) | ||
618 | { | 630 | { |
619 | for (int ii = 0; ii < updatedEntityCount; ii++) | 631 | if (updatedEntityCount > 0) |
620 | { | 632 | { |
621 | EntityProperties entprop = m_updateArray[ii]; | 633 | for (int ii = 0; ii < updatedEntityCount; ii++) |
622 | BSPhysObject pobj; | ||
623 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
624 | { | 634 | { |
625 | pobj.UpdateProperties(entprop); | 635 | EntityProperties entprop = m_updateArray[ii]; |
636 | BSPhysObject pobj; | ||
637 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
638 | { | ||
639 | pobj.UpdateProperties(entprop); | ||
640 | } | ||
626 | } | 641 | } |
627 | } | 642 | } |
628 | } | 643 | } |
629 | 644 | ||
645 | // Some actors want to know when the simulation step is complete. | ||
630 | TriggerPostStepEvent(timeStep); | 646 | TriggerPostStepEvent(timeStep); |
631 | 647 | ||
648 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
649 | if (PhysicsLogging.Enabled) | ||
650 | { | ||
651 | DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
652 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
653 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
654 | } | ||
655 | |||
632 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 656 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
633 | // Only enable this in a limited test world with few objects. | 657 | // Only enable this in a limited test world with few objects. |
634 | if (m_physicsPhysicalDumpEnabled) | 658 | if (m_physicsPhysicalDumpEnabled) |
@@ -637,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
637 | // The physics engine returns the number of milliseconds it simulated this call. | 661 | // The physics engine returns the number of milliseconds it simulated this call. |
638 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 662 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
639 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). | 663 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). |
640 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; | 664 | m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
665 | } | ||
666 | |||
667 | // Called by a BSPhysObject to note that it has changed properties and this information | ||
668 | // should be passed up to the simulator at the proper time. | ||
669 | // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so | ||
670 | // this is is under UpdateLock. | ||
671 | public void PostUpdate(BSPhysObject updatee) | ||
672 | { | ||
673 | ObjectsWithUpdates.Add(updatee); | ||
674 | } | ||
675 | |||
676 | // The simulator thinks it is physics time so return all the collisions and position | ||
677 | // updates that were collected in actual physics simulation. | ||
678 | private float SendUpdatesToSimulator(float timeStep) | ||
679 | { | ||
680 | if (!m_initialized) return 5.0f; | ||
681 | |||
682 | DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", | ||
683 | BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); | ||
684 | // Push the collisions into the simulator. | ||
685 | lock (CollisionLock) | ||
686 | { | ||
687 | if (ObjectsWithCollisions.Count > 0) | ||
688 | { | ||
689 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
690 | if (!bsp.SendCollisions()) | ||
691 | { | ||
692 | // If the object is done colliding, see that it's removed from the colliding list | ||
693 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | // This is a kludge to get avatar movement updates. | ||
698 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
699 | // The event updates avatar animations and stuff. | ||
700 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
701 | foreach (BSPhysObject bsp in m_avatars) | ||
702 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
703 | bsp.SendCollisions(); | ||
704 | |||
705 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
706 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
707 | // This complex collision processing is required to create an empty collision | ||
708 | // event call after all real collisions have happened on an object. This allows | ||
709 | // the simulator to generate the 'collision end' event. | ||
710 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
711 | { | ||
712 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
713 | ObjectsWithCollisions.Remove(po); | ||
714 | ObjectsWithNoMoreCollisions.Clear(); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | // Call the simulator for each object that has physics property updates. | ||
719 | HashSet<BSPhysObject> updatedObjects = null; | ||
720 | lock (UpdateLock) | ||
721 | { | ||
722 | if (ObjectsWithUpdates.Count > 0) | ||
723 | { | ||
724 | updatedObjects = ObjectsWithUpdates; | ||
725 | ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
726 | } | ||
727 | } | ||
728 | if (updatedObjects != null) | ||
729 | { | ||
730 | foreach (BSPhysObject obj in updatedObjects) | ||
731 | { | ||
732 | obj.RequestPhysicsterseUpdate(); | ||
733 | } | ||
734 | updatedObjects.Clear(); | ||
735 | } | ||
736 | |||
737 | // Return the framerate simulated to give the above returned results. | ||
738 | // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). | ||
739 | float simTime = m_simulatedTime; | ||
740 | m_simulatedTime = 0f; | ||
741 | return simTime; | ||
641 | } | 742 | } |
642 | 743 | ||
643 | // Something has collided | 744 | // Something has collided |
@@ -656,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
656 | return; | 757 | return; |
657 | } | 758 | } |
658 | 759 | ||
659 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 760 | // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. |
660 | BSPhysObject collidee = null; | 761 | BSPhysObject collidee = null; |
661 | PhysObjects.TryGetValue(collidingWith, out collidee); | 762 | PhysObjects.TryGetValue(collidingWith, out collidee); |
662 | 763 | ||
@@ -664,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
664 | 765 | ||
665 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 766 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
666 | { | 767 | { |
667 | // If a collision was posted, remember to send it to the simulator | 768 | // If a collision was 'good', remember to send it to the simulator |
668 | ObjectsWithCollisions.Add(collider); | 769 | ObjectsWithCollisions.Add(collider); |
669 | } | 770 | } |
670 | 771 | ||
671 | return; | 772 | return; |
672 | } | 773 | } |
673 | 774 | ||
775 | public void BulletSPluginPhysicsThread() | ||
776 | { | ||
777 | while (m_initialized) | ||
778 | { | ||
779 | int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); | ||
780 | DoPhysicsStep(BSParam.PhysicsTimeStep); | ||
781 | int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); | ||
782 | int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; | ||
783 | |||
784 | if (simulationTimeVsRealtimeDifferenceMS > 0) | ||
785 | { | ||
786 | // The simulation of the time interval took less than realtime. | ||
787 | // Do a sleep for the rest of realtime. | ||
788 | DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
789 | Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | // The simulation took longer than realtime. | ||
794 | // Do some scaling of simulation time. | ||
795 | // TODO. | ||
796 | DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
674 | #endregion // Simulation | 801 | #endregion // Simulation |
675 | 802 | ||
676 | public override void GetResults() { } | 803 | public override void GetResults() { } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 6879ebb..1e19032 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs | |||
@@ -37,6 +37,8 @@ using OpenSim.Region.ScriptEngine.Interfaces; | |||
37 | using OpenSim.Region.ScriptEngine.Shared; | 37 | using OpenSim.Region.ScriptEngine.Shared; |
38 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | 38 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; |
39 | using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; | 39 | using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; |
40 | using System.Reflection; | ||
41 | using log4net; | ||
40 | 42 | ||
41 | namespace OpenSim.Region.ScriptEngine.Shared.Api | 43 | namespace OpenSim.Region.ScriptEngine.Shared.Api |
42 | { | 44 | { |
@@ -45,15 +47,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
45 | /// </summary> | 47 | /// </summary> |
46 | public class AsyncCommandManager | 48 | public class AsyncCommandManager |
47 | { | 49 | { |
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
48 | private static Thread cmdHandlerThread; | 52 | private static Thread cmdHandlerThread; |
49 | private static int cmdHandlerThreadCycleSleepms; | 53 | private static int cmdHandlerThreadCycleSleepms; |
50 | 54 | ||
51 | private static List<IScene> m_Scenes = new List<IScene>(); | 55 | /// <summary> |
56 | /// Lock for reading/writing static components of AsyncCommandManager. | ||
57 | /// </summary> | ||
58 | /// <remarks> | ||
59 | /// This lock exists so that multiple threads from different engines and/or different copies of the same engine | ||
60 | /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently. | ||
61 | /// </remarks> | ||
62 | private static object staticLock = new object(); | ||
63 | |||
52 | private static List<IScriptEngine> m_ScriptEngines = | 64 | private static List<IScriptEngine> m_ScriptEngines = |
53 | new List<IScriptEngine>(); | 65 | new List<IScriptEngine>(); |
54 | 66 | ||
55 | public IScriptEngine m_ScriptEngine; | 67 | public IScriptEngine m_ScriptEngine; |
56 | private IScene m_Scene; | ||
57 | 68 | ||
58 | private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = | 69 | private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = |
59 | new Dictionary<IScriptEngine, Dataserver>(); | 70 | new Dictionary<IScriptEngine, Dataserver>(); |
@@ -70,67 +81,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
70 | 81 | ||
71 | public Dataserver DataserverPlugin | 82 | public Dataserver DataserverPlugin |
72 | { | 83 | { |
73 | get { return m_Dataserver[m_ScriptEngine]; } | 84 | get |
85 | { | ||
86 | lock (staticLock) | ||
87 | return m_Dataserver[m_ScriptEngine]; | ||
88 | } | ||
74 | } | 89 | } |
75 | 90 | ||
76 | public Timer TimerPlugin | 91 | public Timer TimerPlugin |
77 | { | 92 | { |
78 | get { return m_Timer[m_ScriptEngine]; } | 93 | get |
94 | { | ||
95 | lock (staticLock) | ||
96 | return m_Timer[m_ScriptEngine]; | ||
97 | } | ||
79 | } | 98 | } |
80 | 99 | ||
81 | public HttpRequest HttpRequestPlugin | 100 | public HttpRequest HttpRequestPlugin |
82 | { | 101 | { |
83 | get { return m_HttpRequest[m_ScriptEngine]; } | 102 | get |
103 | { | ||
104 | lock (staticLock) | ||
105 | return m_HttpRequest[m_ScriptEngine]; | ||
106 | } | ||
84 | } | 107 | } |
85 | 108 | ||
86 | public Listener ListenerPlugin | 109 | public Listener ListenerPlugin |
87 | { | 110 | { |
88 | get { return m_Listener[m_ScriptEngine]; } | 111 | get |
112 | { | ||
113 | lock (staticLock) | ||
114 | return m_Listener[m_ScriptEngine]; | ||
115 | } | ||
89 | } | 116 | } |
90 | 117 | ||
91 | public SensorRepeat SensorRepeatPlugin | 118 | public SensorRepeat SensorRepeatPlugin |
92 | { | 119 | { |
93 | get { return m_SensorRepeat[m_ScriptEngine]; } | 120 | get |
121 | { | ||
122 | lock (staticLock) | ||
123 | return m_SensorRepeat[m_ScriptEngine]; | ||
124 | } | ||
94 | } | 125 | } |
95 | 126 | ||
96 | public XmlRequest XmlRequestPlugin | 127 | public XmlRequest XmlRequestPlugin |
97 | { | 128 | { |
98 | get { return m_XmlRequest[m_ScriptEngine]; } | 129 | get |
130 | { | ||
131 | lock (staticLock) | ||
132 | return m_XmlRequest[m_ScriptEngine]; | ||
133 | } | ||
99 | } | 134 | } |
100 | 135 | ||
101 | public IScriptEngine[] ScriptEngines | 136 | public IScriptEngine[] ScriptEngines |
102 | { | 137 | { |
103 | get { return m_ScriptEngines.ToArray(); } | 138 | get |
139 | { | ||
140 | lock (staticLock) | ||
141 | return m_ScriptEngines.ToArray(); | ||
142 | } | ||
104 | } | 143 | } |
105 | 144 | ||
106 | public AsyncCommandManager(IScriptEngine _ScriptEngine) | 145 | public AsyncCommandManager(IScriptEngine _ScriptEngine) |
107 | { | 146 | { |
108 | m_ScriptEngine = _ScriptEngine; | 147 | m_ScriptEngine = _ScriptEngine; |
109 | m_Scene = m_ScriptEngine.World; | 148 | |
110 | 149 | // If there is more than one scene in the simulator or multiple script engines are used on the same region | |
111 | if (m_Scenes.Count == 0) | 150 | // then more than one thread could arrive at this block of code simultaneously. However, it cannot be |
112 | ReadConfig(); | 151 | // executed concurrently both because concurrent list operations are not thread-safe and because of other |
113 | 152 | // race conditions such as the later check of cmdHandlerThread == null. | |
114 | if (!m_Scenes.Contains(m_Scene)) | 153 | lock (staticLock) |
115 | m_Scenes.Add(m_Scene); | 154 | { |
116 | if (!m_ScriptEngines.Contains(m_ScriptEngine)) | 155 | if (m_ScriptEngines.Count == 0) |
117 | m_ScriptEngines.Add(m_ScriptEngine); | 156 | ReadConfig(); |
118 | 157 | ||
119 | // Create instances of all plugins | 158 | if (!m_ScriptEngines.Contains(m_ScriptEngine)) |
120 | if (!m_Dataserver.ContainsKey(m_ScriptEngine)) | 159 | m_ScriptEngines.Add(m_ScriptEngine); |
121 | m_Dataserver[m_ScriptEngine] = new Dataserver(this); | 160 | |
122 | if (!m_Timer.ContainsKey(m_ScriptEngine)) | 161 | // Create instances of all plugins |
123 | m_Timer[m_ScriptEngine] = new Timer(this); | 162 | if (!m_Dataserver.ContainsKey(m_ScriptEngine)) |
124 | if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) | 163 | m_Dataserver[m_ScriptEngine] = new Dataserver(this); |
125 | m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); | 164 | if (!m_Timer.ContainsKey(m_ScriptEngine)) |
126 | if (!m_Listener.ContainsKey(m_ScriptEngine)) | 165 | m_Timer[m_ScriptEngine] = new Timer(this); |
127 | m_Listener[m_ScriptEngine] = new Listener(this); | 166 | if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) |
128 | if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) | 167 | m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); |
129 | m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); | 168 | if (!m_Listener.ContainsKey(m_ScriptEngine)) |
130 | if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) | 169 | m_Listener[m_ScriptEngine] = new Listener(this); |
131 | m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); | 170 | if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) |
132 | 171 | m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); | |
133 | StartThread(); | 172 | if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) |
173 | m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); | ||
174 | |||
175 | StartThread(); | ||
176 | } | ||
134 | } | 177 | } |
135 | 178 | ||
136 | private static void StartThread() | 179 | private static void StartThread() |
@@ -179,42 +222,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
179 | { | 222 | { |
180 | try | 223 | try |
181 | { | 224 | { |
182 | while (true) | 225 | Thread.Sleep(cmdHandlerThreadCycleSleepms); |
183 | { | ||
184 | Thread.Sleep(cmdHandlerThreadCycleSleepms); | ||
185 | 226 | ||
186 | DoOneCmdHandlerPass(); | 227 | DoOneCmdHandlerPass(); |
187 | 228 | ||
188 | Watchdog.UpdateThread(); | 229 | Watchdog.UpdateThread(); |
189 | } | ||
190 | } | 230 | } |
191 | catch | 231 | catch (Exception e) |
192 | { | 232 | { |
233 | m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e); | ||
193 | } | 234 | } |
194 | } | 235 | } |
195 | } | 236 | } |
196 | 237 | ||
197 | private static void DoOneCmdHandlerPass() | 238 | private static void DoOneCmdHandlerPass() |
198 | { | 239 | { |
199 | // Check HttpRequests | 240 | lock (staticLock) |
200 | m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); | 241 | { |
242 | // Check HttpRequests | ||
243 | m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); | ||
201 | 244 | ||
202 | // Check XMLRPCRequests | 245 | // Check XMLRPCRequests |
203 | m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); | 246 | m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); |
204 | 247 | ||
205 | foreach (IScriptEngine s in m_ScriptEngines) | 248 | foreach (IScriptEngine s in m_ScriptEngines) |
206 | { | 249 | { |
207 | // Check Listeners | 250 | // Check Listeners |
208 | m_Listener[s].CheckListeners(); | 251 | m_Listener[s].CheckListeners(); |
209 | 252 | ||
210 | // Check timers | 253 | // Check timers |
211 | m_Timer[s].CheckTimerEvents(); | 254 | m_Timer[s].CheckTimerEvents(); |
212 | 255 | ||
213 | // Check Sensors | 256 | // Check Sensors |
214 | m_SensorRepeat[s].CheckSenseRepeaterEvents(); | 257 | m_SensorRepeat[s].CheckSenseRepeaterEvents(); |
215 | 258 | ||
216 | // Check dataserver | 259 | // Check dataserver |
217 | m_Dataserver[s].ExpireRequests(); | 260 | m_Dataserver[s].ExpireRequests(); |
261 | } | ||
218 | } | 262 | } |
219 | } | 263 | } |
220 | 264 | ||
@@ -226,31 +270,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
226 | public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) | 270 | public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) |
227 | { | 271 | { |
228 | // Remove a specific script | 272 | // Remove a specific script |
273 | // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); | ||
229 | 274 | ||
230 | // Remove dataserver events | 275 | lock (staticLock) |
231 | m_Dataserver[engine].RemoveEvents(localID, itemID); | 276 | { |
277 | // Remove dataserver events | ||
278 | m_Dataserver[engine].RemoveEvents(localID, itemID); | ||
232 | 279 | ||
233 | // Remove from: Timers | 280 | // Remove from: Timers |
234 | m_Timer[engine].UnSetTimerEvents(localID, itemID); | 281 | m_Timer[engine].UnSetTimerEvents(localID, itemID); |
235 | 282 | ||
236 | // Remove from: HttpRequest | 283 | // Remove from: HttpRequest |
237 | IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); | 284 | IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); |
238 | if (iHttpReq != null) | 285 | if (iHttpReq != null) |
239 | iHttpReq.StopHttpRequest(localID, itemID); | 286 | iHttpReq.StopHttpRequest(localID, itemID); |
240 | 287 | ||
241 | IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); | 288 | IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); |
242 | if (comms != null) | 289 | if (comms != null) |
243 | comms.DeleteListener(itemID); | 290 | comms.DeleteListener(itemID); |
244 | 291 | ||
245 | IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); | 292 | IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); |
246 | if (xmlrpc != null) | 293 | if (xmlrpc != null) |
247 | { | 294 | { |
248 | xmlrpc.DeleteChannels(itemID); | 295 | xmlrpc.DeleteChannels(itemID); |
249 | xmlrpc.CancelSRDRequests(itemID); | 296 | xmlrpc.CancelSRDRequests(itemID); |
250 | } | 297 | } |
251 | 298 | ||
252 | // Remove Sensors | 299 | // Remove Sensors |
253 | m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); | 300 | m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); |
301 | } | ||
254 | } | 302 | } |
255 | 303 | ||
256 | /// <summary> | 304 | /// <summary> |
@@ -260,10 +308,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
260 | /// <returns></returns> | 308 | /// <returns></returns> |
261 | public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) | 309 | public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) |
262 | { | 310 | { |
263 | if (m_SensorRepeat.ContainsKey(engine)) | 311 | lock (staticLock) |
264 | return m_SensorRepeat[engine]; | 312 | { |
265 | else | 313 | if (m_SensorRepeat.ContainsKey(engine)) |
266 | return null; | 314 | return m_SensorRepeat[engine]; |
315 | else | ||
316 | return null; | ||
317 | } | ||
267 | } | 318 | } |
268 | 319 | ||
269 | /// <summary> | 320 | /// <summary> |
@@ -273,10 +324,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
273 | /// <returns></returns> | 324 | /// <returns></returns> |
274 | public static Dataserver GetDataserverPlugin(IScriptEngine engine) | 325 | public static Dataserver GetDataserverPlugin(IScriptEngine engine) |
275 | { | 326 | { |
276 | if (m_Dataserver.ContainsKey(engine)) | 327 | lock (staticLock) |
277 | return m_Dataserver[engine]; | 328 | { |
278 | else | 329 | if (m_Dataserver.ContainsKey(engine)) |
279 | return null; | 330 | return m_Dataserver[engine]; |
331 | else | ||
332 | return null; | ||
333 | } | ||
280 | } | 334 | } |
281 | 335 | ||
282 | /// <summary> | 336 | /// <summary> |
@@ -286,10 +340,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
286 | /// <returns></returns> | 340 | /// <returns></returns> |
287 | public static Timer GetTimerPlugin(IScriptEngine engine) | 341 | public static Timer GetTimerPlugin(IScriptEngine engine) |
288 | { | 342 | { |
289 | if (m_Timer.ContainsKey(engine)) | 343 | lock (staticLock) |
290 | return m_Timer[engine]; | 344 | { |
291 | else | 345 | if (m_Timer.ContainsKey(engine)) |
292 | return null; | 346 | return m_Timer[engine]; |
347 | else | ||
348 | return null; | ||
349 | } | ||
293 | } | 350 | } |
294 | 351 | ||
295 | /// <summary> | 352 | /// <summary> |
@@ -299,10 +356,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
299 | /// <returns></returns> | 356 | /// <returns></returns> |
300 | public static Listener GetListenerPlugin(IScriptEngine engine) | 357 | public static Listener GetListenerPlugin(IScriptEngine engine) |
301 | { | 358 | { |
302 | if (m_Listener.ContainsKey(engine)) | 359 | lock (staticLock) |
303 | return m_Listener[engine]; | 360 | { |
304 | else | 361 | if (m_Listener.ContainsKey(engine)) |
305 | return null; | 362 | return m_Listener[engine]; |
363 | else | ||
364 | return null; | ||
365 | } | ||
306 | } | 366 | } |
307 | 367 | ||
308 | public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) | 368 | public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) |
@@ -332,28 +392,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
332 | { | 392 | { |
333 | List<Object> data = new List<Object>(); | 393 | List<Object> data = new List<Object>(); |
334 | 394 | ||
335 | Object[] listeners = m_Listener[engine].GetSerializationData(itemID); | 395 | lock (staticLock) |
336 | if (listeners.Length > 0) | ||
337 | { | 396 | { |
338 | data.Add("listener"); | 397 | Object[] listeners = m_Listener[engine].GetSerializationData(itemID); |
339 | data.Add(listeners.Length); | 398 | if (listeners.Length > 0) |
340 | data.AddRange(listeners); | 399 | { |
341 | } | 400 | data.Add("listener"); |
401 | data.Add(listeners.Length); | ||
402 | data.AddRange(listeners); | ||
403 | } | ||
342 | 404 | ||
343 | Object[] timers=m_Timer[engine].GetSerializationData(itemID); | 405 | Object[] timers=m_Timer[engine].GetSerializationData(itemID); |
344 | if (timers.Length > 0) | 406 | if (timers.Length > 0) |
345 | { | 407 | { |
346 | data.Add("timer"); | 408 | data.Add("timer"); |
347 | data.Add(timers.Length); | 409 | data.Add(timers.Length); |
348 | data.AddRange(timers); | 410 | data.AddRange(timers); |
349 | } | 411 | } |
350 | 412 | ||
351 | Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); | 413 | Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); |
352 | if (sensors.Length > 0) | 414 | if (sensors.Length > 0) |
353 | { | 415 | { |
354 | data.Add("sensor"); | 416 | data.Add("sensor"); |
355 | data.Add(sensors.Length); | 417 | data.Add(sensors.Length); |
356 | data.AddRange(sensors); | 418 | data.AddRange(sensors); |
419 | } | ||
357 | } | 420 | } |
358 | 421 | ||
359 | return data.ToArray(); | 422 | return data.ToArray(); |
@@ -378,41 +441,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
378 | 441 | ||
379 | idx+=len; | 442 | idx+=len; |
380 | 443 | ||
444 | lock (staticLock) | ||
445 | { | ||
381 | switch (type) | 446 | switch (type) |
382 | { | 447 | { |
383 | case "listener": | 448 | case "listener": |
384 | m_Listener[engine].CreateFromData(localID, itemID, | 449 | m_Listener[engine].CreateFromData(localID, itemID, |
385 | hostID, item); | 450 | hostID, item); |
386 | break; | 451 | break; |
387 | case "timer": | 452 | case "timer": |
388 | m_Timer[engine].CreateFromData(localID, itemID, | 453 | m_Timer[engine].CreateFromData(localID, itemID, |
389 | hostID, item); | 454 | hostID, item); |
390 | break; | 455 | break; |
391 | case "sensor": | 456 | case "sensor": |
392 | m_SensorRepeat[engine].CreateFromData(localID, | 457 | m_SensorRepeat[engine].CreateFromData(localID, |
393 | itemID, hostID, item); | 458 | itemID, hostID, item); |
394 | break; | 459 | break; |
460 | } | ||
395 | } | 461 | } |
396 | } | 462 | } |
397 | } | 463 | } |
398 | } | 464 | } |
399 | |||
400 | #region Check llRemoteData channels | ||
401 | |||
402 | #endregion | ||
403 | |||
404 | #region Check llListeners | ||
405 | |||
406 | #endregion | ||
407 | |||
408 | /// <summary> | ||
409 | /// If set to true then threads and stuff should try to make a graceful exit | ||
410 | /// </summary> | ||
411 | public bool PleaseShutdown | ||
412 | { | ||
413 | get { return _PleaseShutdown; } | ||
414 | set { _PleaseShutdown = value; } | ||
415 | } | ||
416 | private bool _PleaseShutdown = false; | ||
417 | } | 465 | } |
418 | } | 466 | } |