aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs16
-rw-r--r--OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs1328
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs226
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs1
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs110
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs26
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs23
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs12
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs8
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs3
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs271
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs326
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
28using System; 28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Scenes;
34using OpenSim.Region.Framework.Interfaces;
35using System;
36using System.Reflection;
37using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
38using System.Collections.Specialized; 31using System.Collections.Specialized;
39using System.Reflection;
40using System.IO; 32using System.IO;
33using System.Reflection;
41using System.Web; 34using System.Web;
42using System.Xml; 35using System.Xml;
43using log4net; 36using log4net;
44using Mono.Addins; 37using Mono.Addins;
38using Nini.Config;
39using OpenMetaverse;
45using OpenMetaverse.Messages.Linden; 40using OpenMetaverse.Messages.Linden;
46using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
42using OpenSim.Framework;
47using OpenSim.Framework.Capabilities; 43using OpenSim.Framework.Capabilities;
48using OpenSim.Framework.Servers; 44using OpenSim.Framework.Servers;
49using OpenSim.Framework.Servers.HttpServer; 45using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Scenes;
47using OpenSim.Region.Framework.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 48using Caps = OpenSim.Framework.Capabilities.Caps;
51using OSDArray = OpenMetaverse.StructuredData.OSDArray; 49using OSDArray = OpenMetaverse.StructuredData.OSDArray;
52using OSDMap = OpenMetaverse.StructuredData.OSDMap; 50using 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
28using System;
29using System.IO;
30using System.Text;
31using System.Collections;
32using System.Collections.Generic;
33using System.Globalization;
34using System.Net;
35using System.Net.Sockets;
36using System.Reflection;
37using System.Xml;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40using log4net;
41using Nini.Config;
42using Nwc.XmlRpc;
43using OpenSim.Framework;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Services.Interfaces;
47using Mono.Addins;
48using OpenSim.Services.Connectors.Hypergrid;
49
50namespace 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
29using log4net;
30using Mono.Addins;
31using Nini.Config;
32using System;
33using System.Collections.Generic;
34using System.Reflection;
35using OpenSim.Framework;
36using OpenSim.Framework.Console;
37using OpenSim.Server.Base;
38using OpenSim.Server.Handlers;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Framework.Servers.HttpServer;
41using OpenSim.Framework.Servers;
42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Services.Interfaces;
44using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45using OpenMetaverse;
46
47namespace 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 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31using System.Text;
31using log4net; 32using log4net;
32using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35
33using OpenSim.Framework; 36using OpenSim.Framework;
34 37
35using Animation = OpenSim.Framework.Animation; 38using 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;
37using OpenSim.Region.ScriptEngine.Shared; 37using OpenSim.Region.ScriptEngine.Shared;
38using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; 38using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
39using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; 39using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer;
40using System.Reflection;
41using log4net;
40 42
41namespace OpenSim.Region.ScriptEngine.Shared.Api 43namespace 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}