clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Threading;
30 using System.Collections.Generic;
31 using System.Reflection;
32 using OpenMetaverse;
33 using OpenMetaverse.Packets;
34 using log4net;
35 using OpenSim.Framework;
36 using OpenSim.Region.Framework.Scenes.Types;
37 using OpenSim.Region.Physics.Manager;
38 using OpenSim.Region.Framework.Interfaces;
39  
40 namespace OpenSim.Region.Framework.Scenes
41 {
42 public delegate void PhysicsCrash();
43  
44 /// <summary>
45 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
46 /// should be migrated out over time.
47 /// </summary>
48 public class SceneGraph
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51  
52 #region Events
53  
54 protected internal event PhysicsCrash UnRecoverableError;
55 private PhysicsCrash handlerPhysicsCrash = null;
56  
57 #endregion
58  
59 #region Fields
60  
61 protected object m_presenceLock = new object();
62 protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
63 protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
64  
65 protected internal EntityManager Entities = new EntityManager();
66  
67 protected Scene m_parentScene;
68 protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>();
69 protected int m_numRootAgents = 0;
70 protected int m_numPrim = 0;
71 protected int m_numChildAgents = 0;
72 protected int m_physicalPrim = 0;
73  
74 protected int m_activeScripts = 0;
75 protected int m_scriptLPS = 0;
76  
77 protected internal PhysicsScene _PhyScene;
78  
79 /// <summary>
80 /// Index the SceneObjectGroup for each part by the root part's UUID.
81 /// </summary>
82 protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
83  
84 /// <summary>
85 /// Index the SceneObjectGroup for each part by that part's UUID.
86 /// </summary>
87 protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullPartID = new Dictionary<UUID, SceneObjectGroup>();
88  
89 /// <summary>
90 /// Index the SceneObjectGroup for each part by that part's local ID.
91 /// </summary>
92 protected internal Dictionary<uint, SceneObjectGroup> SceneObjectGroupsByLocalPartID = new Dictionary<uint, SceneObjectGroup>();
93  
94 /// <summary>
95 /// Lock to prevent object group update, linking, delinking and duplication operations from running concurrently.
96 /// </summary>
97 /// <remarks>
98 /// These operations rely on the parts composition of the object. If allowed to run concurrently then race
99 /// conditions can occur.
100 /// </remarks>
101 private Object m_updateLock = new Object();
102  
103 #endregion
104  
105 protected internal SceneGraph(Scene parent)
106 {
107 m_parentScene = parent;
108 }
109  
110 public PhysicsScene PhysicsScene
111 {
112 get { return _PhyScene; }
113 set
114 {
115 // If we're not doing the initial set
116 // Then we've got to remove the previous
117 // event handler
118 if (_PhyScene != null)
119 _PhyScene.OnPhysicsCrash -= physicsBasedCrash;
120  
121 _PhyScene = value;
122  
123 if (_PhyScene != null)
124 _PhyScene.OnPhysicsCrash += physicsBasedCrash;
125 }
126 }
127  
128 protected internal void Close()
129 {
130 lock (m_presenceLock)
131 {
132 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
133 List<ScenePresence> newlist = new List<ScenePresence>();
134 m_scenePresenceMap = newmap;
135 m_scenePresenceArray = newlist;
136 }
137  
138 lock (SceneObjectGroupsByFullID)
139 SceneObjectGroupsByFullID.Clear();
140 lock (SceneObjectGroupsByFullPartID)
141 SceneObjectGroupsByFullPartID.Clear();
142 lock (SceneObjectGroupsByLocalPartID)
143 SceneObjectGroupsByLocalPartID.Clear();
144  
145 Entities.Clear();
146 }
147  
148 #region Update Methods
149  
150 protected internal void UpdatePreparePhysics()
151 {
152 // If we are using a threaded physics engine
153 // grab the latest scene from the engine before
154 // trying to process it.
155  
156 // PhysX does this (runs in the background).
157  
158 if (_PhyScene.IsThreaded)
159 {
160 _PhyScene.GetResults();
161 }
162 }
163  
164 /// <summary>
165 /// Update the position of all the scene presences.
166 /// </summary>
167 /// <remarks>
168 /// Called only from the main scene loop.
169 /// </remarks>
170 protected internal void UpdatePresences()
171 {
172 ForEachScenePresence(delegate(ScenePresence presence)
173 {
174 presence.Update();
175 });
176 }
177  
178 /// <summary>
179 /// Perform a physics frame update.
180 /// </summary>
181 /// <param name="elapsed"></param>
182 /// <returns></returns>
183 protected internal float UpdatePhysics(double elapsed)
184 {
185 // Here is where the Scene calls the PhysicsScene. This is a one-way
186 // interaction; the PhysicsScene cannot access the calling Scene directly.
187 // But with joints, we want a PhysicsActor to be able to influence a
188 // non-physics SceneObjectPart. In particular, a PhysicsActor that is connected
189 // with a joint should be able to move the SceneObjectPart which is the visual
190 // representation of that joint (for editing and serialization purposes).
191 // However the PhysicsActor normally cannot directly influence anything outside
192 // of the PhysicsScene, and the non-physical SceneObjectPart which represents
193 // the joint in the Scene does not exist in the PhysicsScene.
194 //
195 // To solve this, we have an event in the PhysicsScene that is fired when a joint
196 // has changed position (because one of its associated PhysicsActors has changed
197 // position).
198 //
199 // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate().
200 return _PhyScene.Simulate((float)elapsed);
201 }
202  
203 protected internal void UpdateScenePresenceMovement()
204 {
205 ForEachScenePresence(delegate(ScenePresence presence)
206 {
207 presence.UpdateMovement();
208 });
209 }
210  
211 public void GetCoarseLocations(out List<Vector3> coarseLocations, out List<UUID> avatarUUIDs, uint maxLocations)
212 {
213 coarseLocations = new List<Vector3>();
214 avatarUUIDs = new List<UUID>();
215  
216 List<ScenePresence> presences = GetScenePresences();
217 for (int i = 0; i < Math.Min(presences.Count, maxLocations); ++i)
218 {
219 ScenePresence sp = presences[i];
220  
221 // If this presence is a child agent, we don't want its coarse locations
222 if (sp.IsChildAgent)
223 continue;
224  
225 coarseLocations.Add(sp.AbsolutePosition);
226  
227 avatarUUIDs.Add(sp.UUID);
228 }
229 }
230  
231 #endregion
232  
233 #region Entity Methods
234  
235 /// <summary>
236 /// Add an object into the scene that has come from storage
237 /// </summary>
238 /// <param name="sceneObject"></param>
239 /// <param name="attachToBackup">
240 /// If true, changes to the object will be reflected in its persisted data
241 /// If false, the persisted data will not be changed even if the object in the scene is changed
242 /// </param>
243 /// <param name="alreadyPersisted">
244 /// If true, we won't persist this object until it changes
245 /// If false, we'll persist this object immediately
246 /// </param>
247 /// <param name="sendClientUpdates">
248 /// If true, we send updates to the client to tell it about this object
249 /// If false, we leave it up to the caller to do this
250 /// </param>
251 /// <returns>
252 /// true if the object was added, false if an object with the same uuid was already in the scene
253 /// </returns>
254 protected internal bool AddRestoredSceneObject(
255 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
256 {
257 if (attachToBackup && (!alreadyPersisted))
258 {
259 sceneObject.ForceInventoryPersistence();
260 sceneObject.HasGroupChanged = true;
261 }
262  
263 return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
264 }
265  
266 /// <summary>
267 /// Add a newly created object to the scene. This will both update the scene, and send information about the
268 /// new object to all clients interested in the scene.
269 /// </summary>
270 /// <param name="sceneObject"></param>
271 /// <param name="attachToBackup">
272 /// If true, the object is made persistent into the scene.
273 /// If false, the object will not persist over server restarts
274 /// </param>
275 /// <returns>
276 /// true if the object was added, false if an object with the same uuid was already in the scene
277 /// </returns>
278 protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
279 {
280 // Ensure that we persist this new scene object if it's not an
281 // attachment
282 if (attachToBackup)
283 sceneObject.HasGroupChanged = true;
284  
285 return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
286 }
287  
288 /// <summary>
289 /// Add a newly created object to the scene.
290 /// </summary>
291 ///
292 /// This method does not send updates to the client - callers need to handle this themselves.
293 /// Caller should also trigger EventManager.TriggerObjectAddedToScene
294 /// <param name="sceneObject"></param>
295 /// <param name="attachToBackup"></param>
296 /// <param name="pos">Position of the object. If null then the position stored in the object is used.</param>
297 /// <param name="rot">Rotation of the object. If null then the rotation stored in the object is used.</param>
298 /// <param name="vel">Velocity of the object. This parameter only has an effect if the object is physical</param>
299 /// <returns></returns>
300 public bool AddNewSceneObject(
301 SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
302 {
303 AddNewSceneObject(sceneObject, attachToBackup, false);
304  
305 if (pos != null)
306 sceneObject.AbsolutePosition = (Vector3)pos;
307  
308 if (sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim)
309 {
310 sceneObject.ClearPartAttachmentData();
311 }
312  
313 if (rot != null)
314 sceneObject.UpdateGroupRotationR((Quaternion)rot);
315  
316 PhysicsActor pa = sceneObject.RootPart.PhysActor;
317 if (pa != null && pa.IsPhysical && vel != Vector3.Zero)
318 {
319 sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false);
320 sceneObject.Velocity = vel;
321 }
322  
323 return true;
324 }
325  
326 /// <summary>
327 /// Add an object to the scene. This will both update the scene, and send information about the
328 /// new object to all clients interested in the scene.
329 /// </summary>
330 /// <remarks>
331 /// The object's stored position, rotation and velocity are used.
332 /// </remarks>
333 /// <param name="sceneObject"></param>
334 /// <param name="attachToBackup">
335 /// If true, the object is made persistent into the scene.
336 /// If false, the object will not persist over server restarts
337 /// </param>
338 /// <param name="sendClientUpdates">
339 /// If true, updates for the new scene object are sent to all viewers in range.
340 /// If false, it is left to the caller to schedule the update
341 /// </param>
342 /// <returns>
343 /// true if the object was added, false if an object with the same uuid was already in the scene
344 /// </returns>
345 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
346 {
347 if (sceneObject.UUID == UUID.Zero)
348 {
349 m_log.ErrorFormat(
350 "[SCENEGRAPH]: Tried to add scene object {0} to {1} with illegal UUID of {2}",
351 sceneObject.Name, m_parentScene.RegionInfo.RegionName, UUID.Zero);
352  
353 return false;
354 }
355  
356 if (Entities.ContainsKey(sceneObject.UUID))
357 {
358 m_log.DebugFormat(
359 "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()",
360 m_parentScene.RegionInfo.RegionName, sceneObject.UUID);
361  
362 return false;
363 }
364  
365 // m_log.DebugFormat(
366 // "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}",
367 // sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName);
368  
369 SceneObjectPart[] parts = sceneObject.Parts;
370  
371 // Clamp child prim sizes and add child prims to the m_numPrim count
372 if (m_parentScene.m_clampPrimSize)
373 {
374 foreach (SceneObjectPart part in parts)
375 {
376 Vector3 scale = part.Shape.Scale;
377  
378 scale.X = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.X));
379 scale.Y = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Y));
380 scale.Z = Math.Max(m_parentScene.m_minNonphys, Math.Min(m_parentScene.m_maxNonphys, scale.Z));
381  
382 part.Shape.Scale = scale;
383 }
384 }
385 m_numPrim += parts.Length;
386  
387 sceneObject.AttachToScene(m_parentScene);
388  
389 if (sendClientUpdates)
390 sceneObject.ScheduleGroupForFullUpdate();
391  
392 Entities.Add(sceneObject);
393  
394 if (attachToBackup)
395 sceneObject.AttachToBackup();
396  
397 lock (SceneObjectGroupsByFullID)
398 SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
399  
400 lock (SceneObjectGroupsByFullPartID)
401 {
402 foreach (SceneObjectPart part in parts)
403 SceneObjectGroupsByFullPartID[part.UUID] = sceneObject;
404 }
405  
406 lock (SceneObjectGroupsByLocalPartID)
407 {
408 // m_log.DebugFormat(
409 // "[SCENE GRAPH]: Adding scene object {0} {1} {2} to SceneObjectGroupsByLocalPartID in {3}",
410 // sceneObject.Name, sceneObject.UUID, sceneObject.LocalId, m_parentScene.RegionInfo.RegionName);
411  
412 foreach (SceneObjectPart part in parts)
413 SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject;
414 }
415  
416 return true;
417 }
418  
419 /// <summary>
420 /// Delete an object from the scene
421 /// </summary>
422 /// <returns>true if the object was deleted, false if there was no object to delete</returns>
423 public bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked)
424 {
425 // m_log.DebugFormat(
426 // "[SCENE GRAPH]: Deleting scene object with uuid {0}, resultOfObjectLinked = {1}",
427 // uuid, resultOfObjectLinked);
428  
429 EntityBase entity;
430 if (!Entities.TryGetValue(uuid, out entity) || (!(entity is SceneObjectGroup)))
431 return false;
432  
433 SceneObjectGroup grp = (SceneObjectGroup)entity;
434  
435 if (entity == null)
436 return false;
437  
438 if (!resultOfObjectLinked)
439 {
440 m_numPrim -= grp.PrimCount;
441  
442 if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
443 RemovePhysicalPrim(grp.PrimCount);
444 }
445  
446 lock (SceneObjectGroupsByFullID)
447 SceneObjectGroupsByFullID.Remove(grp.UUID);
448  
449 lock (SceneObjectGroupsByFullPartID)
450 {
451 SceneObjectPart[] parts = grp.Parts;
452 for (int i = 0; i < parts.Length; i++)
453 SceneObjectGroupsByFullPartID.Remove(parts[i].UUID);
454 }
455  
456 lock (SceneObjectGroupsByLocalPartID)
457 {
458 SceneObjectPart[] parts = grp.Parts;
459 for (int i = 0; i < parts.Length; i++)
460 SceneObjectGroupsByLocalPartID.Remove(parts[i].LocalId);
461 }
462  
463 return Entities.Remove(uuid);
464 }
465  
466 /// <summary>
467 /// Add an object to the list of prims to process on the next update
468 /// </summary>
469 /// <param name="obj">
470 /// A <see cref="SceneObjectGroup"/>
471 /// </param>
472 protected internal void AddToUpdateList(SceneObjectGroup obj)
473 {
474 lock (m_updateList)
475 m_updateList[obj.UUID] = obj;
476 }
477  
478 /// <summary>
479 /// Process all pending updates
480 /// </summary>
481 protected internal void UpdateObjectGroups()
482 {
483 if (!Monitor.TryEnter(m_updateLock))
484 return;
485 try
486 {
487 List<SceneObjectGroup> updates;
488  
489 // Some updates add more updates to the updateList.
490 // Get the current list of updates and clear the list before iterating
491 lock (m_updateList)
492 {
493 updates = new List<SceneObjectGroup>(m_updateList.Values);
494 m_updateList.Clear();
495 }
496  
497 // Go through all updates
498 for (int i = 0; i < updates.Count; i++)
499 {
500 SceneObjectGroup sog = updates[i];
501  
502 // Don't abort the whole update if one entity happens to give us an exception.
503 try
504 {
505 sog.Update();
506 }
507 catch (Exception e)
508 {
509 m_log.ErrorFormat(
510 "[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e);
511 }
512 }
513 }
514 finally
515 {
516 Monitor.Exit(m_updateLock);
517 }
518 }
519  
520 protected internal void AddPhysicalPrim(int number)
521 {
522 m_physicalPrim += number;
523 }
524  
525 protected internal void RemovePhysicalPrim(int number)
526 {
527 m_physicalPrim -= number;
528 }
529  
530 protected internal void AddToScriptLPS(int number)
531 {
532 m_scriptLPS += number;
533 }
534  
535 protected internal void AddActiveScripts(int number)
536 {
537 m_activeScripts += number;
538 }
539  
540 protected internal void HandleUndo(IClientAPI remoteClient, UUID primId)
541 {
542 if (primId != UUID.Zero)
543 {
544 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
545 if (part != null)
546 part.Undo();
547 }
548 }
549  
550 protected internal void HandleRedo(IClientAPI remoteClient, UUID primId)
551 {
552 if (primId != UUID.Zero)
553 {
554 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
555  
556 if (part != null)
557 part.Redo();
558 }
559 }
560  
561 protected internal ScenePresence CreateAndAddChildScenePresence(
562 IClientAPI client, AvatarAppearance appearance, PresenceType type)
563 {
564 // ScenePresence always defaults to child agent
565 ScenePresence presence = new ScenePresence(client, m_parentScene, appearance, type);
566  
567 Entities[presence.UUID] = presence;
568  
569 lock (m_presenceLock)
570 {
571 m_numChildAgents++;
572  
573 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
574 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
575  
576 if (!newmap.ContainsKey(presence.UUID))
577 {
578 newmap.Add(presence.UUID, presence);
579 newlist.Add(presence);
580 }
581 else
582 {
583 // Remember the old presence reference from the dictionary
584 ScenePresence oldref = newmap[presence.UUID];
585 // Replace the presence reference in the dictionary with the new value
586 newmap[presence.UUID] = presence;
587 // Find the index in the list where the old ref was stored and update the reference
588 newlist[newlist.IndexOf(oldref)] = presence;
589 }
590  
591 // Swap out the dictionary and list with new references
592 m_scenePresenceMap = newmap;
593 m_scenePresenceArray = newlist;
594 }
595  
596 return presence;
597 }
598  
599 /// <summary>
600 /// Remove a presence from the scene
601 /// </summary>
602 protected internal void RemoveScenePresence(UUID agentID)
603 {
604 if (!Entities.Remove(agentID))
605 {
606 m_log.WarnFormat(
607 "[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene Entities list",
608 agentID);
609 }
610  
611 lock (m_presenceLock)
612 {
613 Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
614 List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
615  
616 // Remove the presence reference from the dictionary
617 if (newmap.ContainsKey(agentID))
618 {
619 ScenePresence oldref = newmap[agentID];
620 newmap.Remove(agentID);
621  
622 // Find the index in the list where the old ref was stored and remove the reference
623 newlist.RemoveAt(newlist.IndexOf(oldref));
624 // Swap out the dictionary and list with new references
625 m_scenePresenceMap = newmap;
626 m_scenePresenceArray = newlist;
627 }
628 else
629 {
630 m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
631 }
632 }
633 }
634  
635 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
636 {
637 if (direction_RC_CR_T_F)
638 {
639 m_numRootAgents--;
640 m_numChildAgents++;
641 }
642 else
643 {
644 m_numChildAgents--;
645 m_numRootAgents++;
646 }
647 }
648  
649 public void removeUserCount(bool TypeRCTF)
650 {
651 if (TypeRCTF)
652 {
653 m_numRootAgents--;
654 }
655 else
656 {
657 m_numChildAgents--;
658 }
659 }
660  
661 public void RecalculateStats()
662 {
663 int rootcount = 0;
664 int childcount = 0;
665  
666 ForEachScenePresence(delegate(ScenePresence presence)
667 {
668 if (presence.IsChildAgent)
669 ++childcount;
670 else
671 ++rootcount;
672 });
673  
674 m_numRootAgents = rootcount;
675 m_numChildAgents = childcount;
676 }
677  
678 public int GetChildAgentCount()
679 {
680 return m_numChildAgents;
681 }
682  
683 public int GetRootAgentCount()
684 {
685 return m_numRootAgents;
686 }
687  
688 public int GetTotalObjectsCount()
689 {
690 return m_numPrim;
691 }
692  
693 public int GetActiveObjectsCount()
694 {
695 return m_physicalPrim;
696 }
697  
698 public int GetActiveScriptsCount()
699 {
700 return m_activeScripts;
701 }
702  
703 public int GetScriptLPS()
704 {
705 int returnval = m_scriptLPS;
706 m_scriptLPS = 0;
707 return returnval;
708 }
709  
710 #endregion
711  
712 #region Get Methods
713  
714 /// <summary>
715 /// Get the controlling client for the given avatar, if there is one.
716 ///
717 /// FIXME: The only user of the method right now is Caps.cs, in order to resolve a client API since it can't
718 /// use the ScenePresence. This could be better solved in a number of ways - we could establish an
719 /// OpenSim.Framework.IScenePresence, or move the caps code into a region package (which might be the more
720 /// suitable solution).
721 /// </summary>
722 /// <param name="agentId"></param>
723 /// <returns>null if either the avatar wasn't in the scene, or
724 /// they do not have a controlling client</returns>
725 /// <remarks>this used to be protected internal, but that
726 /// prevents CapabilitiesModule from accessing it</remarks>
727 public IClientAPI GetControllingClient(UUID agentId)
728 {
729 ScenePresence presence = GetScenePresence(agentId);
730  
731 if (presence != null)
732 {
733 return presence.ControllingClient;
734 }
735  
736 return null;
737 }
738  
739 /// <summary>
740 /// Get a reference to the scene presence list. Changes to the list will be done in a copy
741 /// There is no guarantee that presences will remain in the scene after the list is returned.
742 /// This list should remain private to SceneGraph. Callers wishing to iterate should instead
743 /// pass a delegate to ForEachScenePresence.
744 /// </summary>
745 /// <returns></returns>
746 protected internal List<ScenePresence> GetScenePresences()
747 {
748 return m_scenePresenceArray;
749 }
750  
751 /// <summary>
752 /// Request a scene presence by UUID. Fast, indexed lookup.
753 /// </summary>
754 /// <param name="agentID"></param>
755 /// <returns>null if the presence was not found</returns>
756 protected internal ScenePresence GetScenePresence(UUID agentID)
757 {
758 Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
759 ScenePresence presence;
760 presences.TryGetValue(agentID, out presence);
761 return presence;
762 }
763  
764 /// <summary>
765 /// Request the scene presence by name.
766 /// </summary>
767 /// <param name="firstName"></param>
768 /// <param name="lastName"></param>
769 /// <returns>null if the presence was not found</returns>
770 protected internal ScenePresence GetScenePresence(string firstName, string lastName)
771 {
772 List<ScenePresence> presences = GetScenePresences();
773 foreach (ScenePresence presence in presences)
774 {
775 if (string.Equals(presence.Firstname, firstName, StringComparison.CurrentCultureIgnoreCase)
776 && string.Equals(presence.Lastname, lastName, StringComparison.CurrentCultureIgnoreCase))
777 return presence;
778 }
779 return null;
780 }
781  
782 /// <summary>
783 /// Request the scene presence by localID.
784 /// </summary>
785 /// <param name="localID"></param>
786 /// <returns>null if the presence was not found</returns>
787 protected internal ScenePresence GetScenePresence(uint localID)
788 {
789 List<ScenePresence> presences = GetScenePresences();
790 foreach (ScenePresence presence in presences)
791 if (presence.LocalId == localID)
792 return presence;
793 return null;
794 }
795  
796 protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar)
797 {
798 Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
799 presences.TryGetValue(agentID, out avatar);
800 return (avatar != null);
801 }
802  
803 protected internal bool TryGetAvatarByName(string name, out ScenePresence avatar)
804 {
805 avatar = null;
806 foreach (ScenePresence presence in GetScenePresences())
807 {
808 if (String.Compare(name, presence.ControllingClient.Name, true) == 0)
809 {
810 avatar = presence;
811 break;
812 }
813 }
814 return (avatar != null);
815 }
816  
817 /// <summary>
818 /// Get a scene object group that contains the prim with the given local id
819 /// </summary>
820 /// <param name="localID"></param>
821 /// <returns>null if no scene object group containing that prim is found</returns>
822 public SceneObjectGroup GetGroupByPrim(uint localID)
823 {
824 EntityBase entity;
825 if (Entities.TryGetValue(localID, out entity))
826 return entity as SceneObjectGroup;
827  
828 // m_log.DebugFormat("[SCENE GRAPH]: Entered GetGroupByPrim with localID {0}", localID);
829  
830 SceneObjectGroup sog;
831 lock (SceneObjectGroupsByLocalPartID)
832 SceneObjectGroupsByLocalPartID.TryGetValue(localID, out sog);
833  
834 if (sog != null)
835 {
836 if (sog.ContainsPart(localID))
837 {
838 // m_log.DebugFormat(
839 // "[SCENE GRAPH]: Found scene object {0} {1} {2} containing part with local id {3} in {4}. Returning.",
840 // sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName);
841  
842 return sog;
843 }
844 else
845 {
846 lock (SceneObjectGroupsByLocalPartID)
847 {
848 m_log.WarnFormat(
849 "[SCENE GRAPH]: Found scene object {0} {1} {2} via SceneObjectGroupsByLocalPartID index but it doesn't contain part with local id {3}. Removing from entry from index in {4}.",
850 sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName);
851  
852 SceneObjectGroupsByLocalPartID.Remove(localID);
853 }
854 }
855 }
856  
857 EntityBase[] entityList = GetEntities();
858 foreach (EntityBase ent in entityList)
859 {
860 //m_log.DebugFormat("Looking at entity {0}", ent.UUID);
861 if (ent is SceneObjectGroup)
862 {
863 sog = (SceneObjectGroup)ent;
864 if (sog.ContainsPart(localID))
865 {
866 lock (SceneObjectGroupsByLocalPartID)
867 SceneObjectGroupsByLocalPartID[localID] = sog;
868 return sog;
869 }
870 }
871 }
872  
873 return null;
874 }
875  
876 /// <summary>
877 /// Get a scene object group that contains the prim with the given uuid
878 /// </summary>
879 /// <param name="fullID"></param>
880 /// <returns>null if no scene object group containing that prim is found</returns>
881 public SceneObjectGroup GetGroupByPrim(UUID fullID)
882 {
883 SceneObjectGroup sog;
884 lock (SceneObjectGroupsByFullPartID)
885 SceneObjectGroupsByFullPartID.TryGetValue(fullID, out sog);
886  
887 if (sog != null)
888 {
889 if (sog.ContainsPart(fullID))
890 return sog;
891  
892 lock (SceneObjectGroupsByFullPartID)
893 SceneObjectGroupsByFullPartID.Remove(fullID);
894 }
895  
896 EntityBase[] entityList = GetEntities();
897 foreach (EntityBase ent in entityList)
898 {
899 if (ent is SceneObjectGroup)
900 {
901 sog = (SceneObjectGroup)ent;
902 if (sog.ContainsPart(fullID))
903 {
904 lock (SceneObjectGroupsByFullPartID)
905 SceneObjectGroupsByFullPartID[fullID] = sog;
906 return sog;
907 }
908 }
909 }
910  
911 return null;
912 }
913  
914 protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
915 {
916 // Primitive Ray Tracing
917 float closestDistance = 280f;
918 EntityIntersection result = new EntityIntersection();
919 EntityBase[] EntityList = GetEntities();
920 foreach (EntityBase ent in EntityList)
921 {
922 if (ent is SceneObjectGroup)
923 {
924 SceneObjectGroup reportingG = (SceneObjectGroup)ent;
925 EntityIntersection inter = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
926 if (inter.HitTF && inter.distance < closestDistance)
927 {
928 closestDistance = inter.distance;
929 result = inter;
930 }
931 }
932 }
933 return result;
934 }
935  
936 /// <summary>
937 /// Get all the scene object groups.
938 /// </summary>
939 /// <returns>
940 /// The scene object groups. If the scene is empty then an empty list is returned.
941 /// </returns>
942 protected internal List<SceneObjectGroup> GetSceneObjectGroups()
943 {
944 lock (SceneObjectGroupsByFullID)
945 return new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
946 }
947  
948 /// <summary>
949 /// Get a group in the scene
950 /// </summary>
951 /// <param name="fullID">UUID of the group</param>
952 /// <returns>null if no such group was found</returns>
953 protected internal SceneObjectGroup GetSceneObjectGroup(UUID fullID)
954 {
955 lock (SceneObjectGroupsByFullID)
956 {
957 if (SceneObjectGroupsByFullID.ContainsKey(fullID))
958 return SceneObjectGroupsByFullID[fullID];
959 }
960  
961 return null;
962 }
963  
964 /// <summary>
965 /// Get a group in the scene
966 /// </summary>
967 /// <remarks>
968 /// This will only return a group if the local ID matches the root part, not other parts.
969 /// </remarks>
970 /// <param name="localID">Local id of the root part of the group</param>
971 /// <returns>null if no such group was found</returns>
972 protected internal SceneObjectGroup GetSceneObjectGroup(uint localID)
973 {
974 lock (SceneObjectGroupsByLocalPartID)
975 {
976 if (SceneObjectGroupsByLocalPartID.ContainsKey(localID))
977 {
978 SceneObjectGroup so = SceneObjectGroupsByLocalPartID[localID];
979  
980 if (so.LocalId == localID)
981 return so;
982 }
983 }
984  
985 return null;
986 }
987  
988 /// <summary>
989 /// Get a group by name from the scene (will return the first
990 /// found, if there are more than one prim with the same name)
991 /// </summary>
992 /// <param name="name"></param>
993 /// <returns>null if the part was not found</returns>
994 protected internal SceneObjectGroup GetSceneObjectGroup(string name)
995 {
996 SceneObjectGroup so = null;
997  
998 Entities.Find(
999 delegate(EntityBase entity)
1000 {
1001 if (entity is SceneObjectGroup)
1002 {
1003 if (entity.Name == name)
1004 {
1005 so = (SceneObjectGroup)entity;
1006 return true;
1007 }
1008 }
1009  
1010 return false;
1011 }
1012 );
1013  
1014 return so;
1015 }
1016  
1017 /// <summary>
1018 /// Get a part contained in this scene.
1019 /// </summary>
1020 /// <param name="localID"></param>
1021 /// <returns>null if the part was not found</returns>
1022 protected internal SceneObjectPart GetSceneObjectPart(uint localID)
1023 {
1024 SceneObjectGroup group = GetGroupByPrim(localID);
1025 if (group == null)
1026 return null;
1027 return group.GetPart(localID);
1028 }
1029  
1030 /// <summary>
1031 /// Get a prim by name from the scene (will return the first
1032 /// found, if there are more than one prim with the same name)
1033 /// </summary>
1034 /// <param name="name"></param>
1035 /// <returns>null if the part was not found</returns>
1036 protected internal SceneObjectPart GetSceneObjectPart(string name)
1037 {
1038 SceneObjectPart sop = null;
1039  
1040 Entities.Find(
1041 delegate(EntityBase entity)
1042 {
1043 if (entity is SceneObjectGroup)
1044 {
1045 foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts)
1046 {
1047 // m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name);
1048  
1049 if (p.Name == name)
1050 {
1051 sop = p;
1052 return true;
1053 }
1054 }
1055 }
1056  
1057 return false;
1058 }
1059 );
1060  
1061 return sop;
1062 }
1063  
1064 /// <summary>
1065 /// Get a part contained in this scene.
1066 /// </summary>
1067 /// <param name="fullID"></param>
1068 /// <returns>null if the part was not found</returns>
1069 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
1070 {
1071 SceneObjectGroup group = GetGroupByPrim(fullID);
1072 if (group == null)
1073 return null;
1074 return group.GetPart(fullID);
1075 }
1076  
1077 /// <summary>
1078 /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
1079 /// it
1080 /// </summary>
1081 /// <returns></returns>
1082 protected internal EntityBase[] GetEntities()
1083 {
1084 return Entities.GetEntities();
1085 }
1086  
1087 #endregion
1088  
1089 #region Other Methods
1090  
1091 protected internal void physicsBasedCrash()
1092 {
1093 handlerPhysicsCrash = UnRecoverableError;
1094 if (handlerPhysicsCrash != null)
1095 {
1096 handlerPhysicsCrash();
1097 }
1098 }
1099  
1100 protected internal UUID ConvertLocalIDToFullID(uint localID)
1101 {
1102 SceneObjectGroup group = GetGroupByPrim(localID);
1103 if (group != null)
1104 return group.GetPartsFullID(localID);
1105 else
1106 return UUID.Zero;
1107 }
1108  
1109 /// <summary>
1110 /// Performs action once on all scene object groups.
1111 /// </summary>
1112 /// <param name="action"></param>
1113 protected internal void ForEachSOG(Action<SceneObjectGroup> action)
1114 {
1115 foreach (SceneObjectGroup obj in GetSceneObjectGroups())
1116 {
1117 try
1118 {
1119 action(obj);
1120 }
1121 catch (Exception e)
1122 {
1123 // Catch it and move on. This includes situations where objlist has inconsistent info
1124 m_log.WarnFormat(
1125 "[SCENEGRAPH]: Problem processing action in ForEachSOG: {0} {1}", e.Message, e.StackTrace);
1126 }
1127 }
1128 }
1129  
1130 /// <summary>
1131 /// Performs action on all ROOT (not child) scene presences.
1132 /// This is just a shortcut function since frequently actions only appy to root SPs
1133 /// </summary>
1134 /// <param name="action"></param>
1135 public void ForEachAvatar(Action<ScenePresence> action)
1136 {
1137 ForEachScenePresence(delegate(ScenePresence sp)
1138 {
1139 if (!sp.IsChildAgent)
1140 action(sp);
1141 });
1142 }
1143  
1144 /// <summary>
1145 /// Performs action on all scene presences. This can ultimately run the actions in parallel but
1146 /// any delegates passed in will need to implement their own locking on data they reference and
1147 /// modify outside of the scope of the delegate.
1148 /// </summary>
1149 /// <param name="action"></param>
1150 public void ForEachScenePresence(Action<ScenePresence> action)
1151 {
1152 // Once all callers have their delegates configured for parallelism, we can unleash this
1153 /*
1154 Action<ScenePresence> protectedAction = new Action<ScenePresence>(delegate(ScenePresence sp)
1155 {
1156 try
1157 {
1158 action(sp);
1159 }
1160 catch (Exception e)
1161 {
1162 m_log.Info("[SCENEGRAPH]: Error in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1163 m_log.Info("[SCENEGRAPH]: Stack Trace: " + e.StackTrace);
1164 }
1165 });
1166 Parallel.ForEach<ScenePresence>(GetScenePresences(), protectedAction);
1167 */
1168 // For now, perform actions serially
1169 List<ScenePresence> presences = GetScenePresences();
1170 foreach (ScenePresence sp in presences)
1171 {
1172 try
1173 {
1174 action(sp);
1175 }
1176 catch (Exception e)
1177 {
1178 m_log.Error("[SCENEGRAPH]: Error in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1179 }
1180 }
1181 }
1182  
1183 #endregion
1184  
1185 #region Client Event handlers
1186  
1187 /// <summary>
1188 /// Update the scale of an individual prim.
1189 /// </summary>
1190 /// <param name="localID"></param>
1191 /// <param name="scale"></param>
1192 /// <param name="remoteClient"></param>
1193 protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1194 {
1195 SceneObjectPart part = GetSceneObjectPart(localID);
1196  
1197 if (part != null)
1198 {
1199 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1200 {
1201 part.Resize(scale);
1202 }
1203 }
1204 }
1205  
1206 protected internal void UpdatePrimGroupScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1207 {
1208 SceneObjectGroup group = GetGroupByPrim(localID);
1209 if (group != null)
1210 {
1211 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1212 {
1213 group.GroupResize(scale);
1214 }
1215 }
1216 }
1217  
1218 /// <summary>
1219 /// This handles the nifty little tool tip that you get when you drag your mouse over an object
1220 /// Send to the Object Group to process. We don't know enough to service the request
1221 /// </summary>
1222 /// <param name="remoteClient"></param>
1223 /// <param name="AgentID"></param>
1224 /// <param name="RequestFlags"></param>
1225 /// <param name="ObjectID"></param>
1226 protected internal void RequestObjectPropertiesFamily(
1227 IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
1228 {
1229 SceneObjectGroup group = GetGroupByPrim(ObjectID);
1230 if (group != null)
1231 {
1232 group.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
1233 }
1234 }
1235  
1236 /// <summary>
1237 ///
1238 /// </summary>
1239 /// <param name="localID"></param>
1240 /// <param name="rot"></param>
1241 /// <param name="remoteClient"></param>
1242 protected internal void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1243 {
1244 SceneObjectGroup group = GetGroupByPrim(localID);
1245 if (group != null)
1246 {
1247 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1248 {
1249 group.UpdateSingleRotation(rot, localID);
1250 }
1251 }
1252 }
1253  
1254 /// <summary>
1255 ///
1256 /// </summary>
1257 /// <param name="localID"></param>
1258 /// <param name="rot"></param>
1259 /// <param name="remoteClient"></param>
1260 protected internal void UpdatePrimSingleRotationPosition(uint localID, Quaternion rot, Vector3 pos, IClientAPI remoteClient)
1261 {
1262 SceneObjectGroup group = GetGroupByPrim(localID);
1263 if (group != null)
1264 {
1265 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1266 {
1267 group.UpdateSingleRotation(rot, pos, localID);
1268 }
1269 }
1270 }
1271  
1272 /// <summary>
1273 /// Update the rotation of a whole group.
1274 /// </summary>
1275 /// <param name="localID"></param>
1276 /// <param name="rot"></param>
1277 /// <param name="remoteClient"></param>
1278 protected internal void UpdatePrimGroupRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1279 {
1280 SceneObjectGroup group = GetGroupByPrim(localID);
1281 if (group != null)
1282 {
1283 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1284 {
1285 group.UpdateGroupRotationR(rot);
1286 }
1287 }
1288 }
1289  
1290 /// <summary>
1291 ///
1292 /// </summary>
1293 /// <param name="localID"></param>
1294 /// <param name="pos"></param>
1295 /// <param name="rot"></param>
1296 /// <param name="remoteClient"></param>
1297 protected internal void UpdatePrimGroupRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
1298 {
1299 SceneObjectGroup group = GetGroupByPrim(localID);
1300 if (group != null)
1301 {
1302 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1303 {
1304 group.UpdateGroupRotationPR(pos, rot);
1305 }
1306 }
1307 }
1308  
1309 /// <summary>
1310 /// Update the position of the given part
1311 /// </summary>
1312 /// <param name="localID"></param>
1313 /// <param name="pos"></param>
1314 /// <param name="remoteClient"></param>
1315 protected internal void UpdatePrimSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1316 {
1317 SceneObjectGroup group = GetGroupByPrim(localID);
1318 if (group != null)
1319 {
1320 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment)
1321 {
1322 group.UpdateSinglePosition(pos, localID);
1323 }
1324 }
1325 }
1326  
1327 /// <summary>
1328 /// Update the position of the given group.
1329 /// </summary>
1330 /// <param name="localId"></param>
1331 /// <param name="pos"></param>
1332 /// <param name="remoteClient"></param>
1333 public void UpdatePrimGroupPosition(uint localId, Vector3 pos, IClientAPI remoteClient)
1334 {
1335 UpdatePrimGroupPosition(localId, pos, remoteClient.AgentId);
1336 }
1337  
1338 /// <summary>
1339 /// Update the position of the given group.
1340 /// </summary>
1341 /// <param name="localId"></param>
1342 /// <param name="pos"></param>
1343 /// <param name="updatingAgentId"></param>
1344 public void UpdatePrimGroupPosition(uint localId, Vector3 pos, UUID updatingAgentId)
1345 {
1346 SceneObjectGroup group = GetGroupByPrim(localId);
1347  
1348 if (group != null)
1349 {
1350 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1351 {
1352 if (m_parentScene.AttachmentsModule != null)
1353 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos);
1354 }
1355 else
1356 {
1357 if (m_parentScene.Permissions.CanMoveObject(group.UUID, updatingAgentId)
1358 && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1359 {
1360 group.UpdateGroupPosition(pos);
1361 }
1362 }
1363 }
1364 }
1365  
1366 /// <summary>
1367 /// Update the texture entry of the given prim.
1368 /// </summary>
1369 /// <remarks>
1370 /// A texture entry is an object that contains details of all the textures of the prim's face. In this case,
1371 /// the texture is given in its byte serialized form.
1372 /// </remarks>
1373 /// <param name="localID"></param>
1374 /// <param name="texture"></param>
1375 /// <param name="remoteClient"></param>
1376 protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
1377 {
1378 SceneObjectGroup group = GetGroupByPrim(localID);
1379  
1380 if (group != null)
1381 {
1382 if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId))
1383 {
1384 group.UpdateTextureEntry(localID, texture);
1385 }
1386 }
1387 }
1388  
1389 /// <summary>
1390 /// Update the flags on a scene object. This covers properties such as phantom, physics and temporary.
1391 /// </summary>
1392 /// <remarks>
1393 /// This is currently handling the incoming call from the client stack (e.g. LLClientView).
1394 /// </remarks>
1395 /// <param name="localID"></param>
1396 /// <param name="UsePhysics"></param>
1397 /// <param name="SetTemporary"></param>
1398 /// <param name="SetPhantom"></param>
1399 /// <param name="remoteClient"></param>
1400 protected internal void UpdatePrimFlags(
1401 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1402 {
1403 SceneObjectGroup group = GetGroupByPrim(localID);
1404 if (group != null)
1405 {
1406 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1407 {
1408 // VolumeDetect can't be set via UI and will always be off when a change is made there
1409 // now only change volume dtc if phantom off
1410  
1411 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1412 {
1413 bool vdtc;
1414 if (SetPhantom) // if phantom keep volumedtc
1415 vdtc = group.RootPart.VolumeDetectActive;
1416 else // else turn it off
1417 vdtc = false;
1418  
1419 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1420 }
1421 else
1422 {
1423 SceneObjectPart part = GetSceneObjectPart(localID);
1424 if (part != null)
1425 {
1426 part.UpdateExtraPhysics(PhysData);
1427 if (part.UpdatePhysRequired)
1428 remoteClient.SendPartPhysicsProprieties(part);
1429 }
1430 }
1431 }
1432 }
1433 }
1434  
1435 /// <summary>
1436 /// Move the given object
1437 /// </summary>
1438 /// <param name="objectID"></param>
1439 /// <param name="offset"></param>
1440 /// <param name="pos"></param>
1441 /// <param name="remoteClient"></param>
1442 protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
1443 {
1444 SceneObjectGroup group = GetGroupByPrim(objectID);
1445 if (group != null)
1446 {
1447 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1448 {
1449 group.GrabMovement(objectID, offset, pos, remoteClient);
1450 }
1451  
1452 // This is outside the above permissions condition
1453 // so that if the object is locked the client moving the object
1454 // get's it's position on the simulator even if it was the same as before
1455 // This keeps the moving user's client in sync with the rest of the world.
1456 group.SendGroupTerseUpdate();
1457 }
1458 }
1459  
1460 /// <summary>
1461 /// Start spinning the given object
1462 /// </summary>
1463 /// <param name="objectID"></param>
1464 /// <param name="rotation"></param>
1465 /// <param name="remoteClient"></param>
1466 protected internal void SpinStart(UUID objectID, IClientAPI remoteClient)
1467 {
1468 SceneObjectGroup group = GetGroupByPrim(objectID);
1469 if (group != null)
1470 {
1471 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1472 {
1473 group.SpinStart(remoteClient);
1474 }
1475 }
1476 }
1477  
1478 /// <summary>
1479 /// Spin the given object
1480 /// </summary>
1481 /// <param name="objectID"></param>
1482 /// <param name="rotation"></param>
1483 /// <param name="remoteClient"></param>
1484 protected internal void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient)
1485 {
1486 SceneObjectGroup group = GetGroupByPrim(objectID);
1487 if (group != null)
1488 {
1489 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1490 {
1491 group.SpinMovement(rotation, remoteClient);
1492 }
1493 // This is outside the above permissions condition
1494 // so that if the object is locked the client moving the object
1495 // get's it's position on the simulator even if it was the same as before
1496 // This keeps the moving user's client in sync with the rest of the world.
1497 group.SendGroupTerseUpdate();
1498 }
1499 }
1500  
1501 /// <summary>
1502 ///
1503 /// </summary>
1504 /// <param name="primLocalID"></param>
1505 /// <param name="description"></param>
1506 protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
1507 {
1508 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1509 if (group != null)
1510 {
1511 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1512 {
1513 group.SetPartName(Util.CleanString(name), primLocalID);
1514 group.HasGroupChanged = true;
1515 }
1516 }
1517 }
1518  
1519 /// <summary>
1520 /// Handle a prim description set request from a viewer.
1521 /// </summary>
1522 /// <param name="primLocalID"></param>
1523 /// <param name="description"></param>
1524 protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
1525 {
1526 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1527 if (group != null)
1528 {
1529 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1530 {
1531 group.SetPartDescription(Util.CleanString(description), primLocalID);
1532 group.HasGroupChanged = true;
1533 }
1534 }
1535 }
1536  
1537 /// <summary>
1538 /// Set a click action for the prim.
1539 /// </summary>
1540 /// <param name="remoteClient"></param>
1541 /// <param name="primLocalID"></param>
1542 /// <param name="clickAction"></param>
1543 protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
1544 {
1545 // m_log.DebugFormat(
1546 // "[SCENEGRAPH]: User {0} set click action for {1} to {2}", remoteClient.Name, primLocalID, clickAction);
1547  
1548 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1549 if (group != null)
1550 {
1551 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1552 {
1553 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1554 if (part != null)
1555 {
1556 part.ClickAction = Convert.ToByte(clickAction);
1557 group.HasGroupChanged = true;
1558 }
1559 }
1560 }
1561 }
1562  
1563 protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
1564 {
1565 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1566 if (group != null)
1567 {
1568 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1569 {
1570 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1571 if (part != null)
1572 {
1573 part.Material = Convert.ToByte(material);
1574 group.HasGroupChanged = true;
1575 }
1576 }
1577 }
1578 }
1579  
1580 protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
1581 {
1582 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1583  
1584 if (group != null)
1585 {
1586 if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
1587 {
1588 group.UpdateExtraParam(primLocalID, type, inUse, data);
1589 }
1590 }
1591 }
1592  
1593 /// <summary>
1594 ///
1595 /// </summary>
1596 /// <param name="primLocalID"></param>
1597 /// <param name="shapeBlock"></param>
1598 protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
1599 {
1600 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1601 if (group != null)
1602 {
1603 if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
1604 {
1605 ObjectShapePacket.ObjectDataBlock shapeData = new ObjectShapePacket.ObjectDataBlock();
1606 shapeData.ObjectLocalID = shapeBlock.ObjectLocalID;
1607 shapeData.PathBegin = shapeBlock.PathBegin;
1608 shapeData.PathCurve = shapeBlock.PathCurve;
1609 shapeData.PathEnd = shapeBlock.PathEnd;
1610 shapeData.PathRadiusOffset = shapeBlock.PathRadiusOffset;
1611 shapeData.PathRevolutions = shapeBlock.PathRevolutions;
1612 shapeData.PathScaleX = shapeBlock.PathScaleX;
1613 shapeData.PathScaleY = shapeBlock.PathScaleY;
1614 shapeData.PathShearX = shapeBlock.PathShearX;
1615 shapeData.PathShearY = shapeBlock.PathShearY;
1616 shapeData.PathSkew = shapeBlock.PathSkew;
1617 shapeData.PathTaperX = shapeBlock.PathTaperX;
1618 shapeData.PathTaperY = shapeBlock.PathTaperY;
1619 shapeData.PathTwist = shapeBlock.PathTwist;
1620 shapeData.PathTwistBegin = shapeBlock.PathTwistBegin;
1621 shapeData.ProfileBegin = shapeBlock.ProfileBegin;
1622 shapeData.ProfileCurve = shapeBlock.ProfileCurve;
1623 shapeData.ProfileEnd = shapeBlock.ProfileEnd;
1624 shapeData.ProfileHollow = shapeBlock.ProfileHollow;
1625  
1626 group.UpdateShape(shapeData, primLocalID);
1627 }
1628 }
1629 }
1630  
1631 /// <summary>
1632 /// Initial method invoked when we receive a link objects request from the client.
1633 /// </summary>
1634 /// <param name="client"></param>
1635 /// <param name="parentPrim"></param>
1636 /// <param name="childPrims"></param>
1637 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1638 {
1639 if (root.KeyframeMotion != null)
1640 {
1641 root.KeyframeMotion.Stop();
1642 root.KeyframeMotion = null;
1643 }
1644  
1645 SceneObjectGroup parentGroup = root.ParentGroup;
1646 if (parentGroup == null) return;
1647  
1648 // Cowardly refuse to link to a group owned root
1649 if (parentGroup.OwnerID == parentGroup.GroupID)
1650 return;
1651  
1652 Monitor.Enter(m_updateLock);
1653 try
1654 {
1655 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1656  
1657 // We do this in reverse to get the link order of the prims correct
1658 for (int i = 0 ; i < children.Count ; i++)
1659 {
1660 SceneObjectGroup child = children[i].ParentGroup;
1661  
1662 // Don't try and add a group to itself - this will only cause severe problems later on.
1663 if (child == parentGroup)
1664 continue;
1665  
1666 // Make sure no child prim is set for sale
1667 // So that, on delink, no prims are unwittingly
1668 // left for sale and sold off
1669 child.RootPart.ObjectSaleType = 0;
1670 child.RootPart.SalePrice = 10;
1671 childGroups.Add(child);
1672 }
1673  
1674 foreach (SceneObjectGroup child in childGroups)
1675 {
1676 if (parentGroup.OwnerID == child.OwnerID)
1677 {
1678 parentGroup.LinkToGroup(child);
1679  
1680 child.DetachFromBackup();
1681  
1682 // this is here so physics gets updated!
1683 // Don't remove! Bad juju! Stay away! or fix physics!
1684 child.AbsolutePosition = child.AbsolutePosition;
1685 }
1686 }
1687  
1688 // We need to explicitly resend the newly link prim's object properties since no other actions
1689 // occur on link to invoke this elsewhere (such as object selection)
1690 if (childGroups.Count > 0)
1691 {
1692 parentGroup.RootPart.CreateSelected = true;
1693 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1694 parentGroup.HasGroupChanged = true;
1695 parentGroup.ScheduleGroupForFullUpdate();
1696 }
1697 }
1698 finally
1699 {
1700 Monitor.Exit(m_updateLock);
1701 }
1702 }
1703  
1704 /// <summary>
1705 /// Delink a linkset
1706 /// </summary>
1707 /// <param name="prims"></param>
1708 protected internal void DelinkObjects(List<SceneObjectPart> prims)
1709 {
1710 Monitor.Enter(m_updateLock);
1711 try
1712 {
1713 List<SceneObjectPart> childParts = new List<SceneObjectPart>();
1714 List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
1715 List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
1716 // Look them all up in one go, since that is comparatively expensive
1717 //
1718 foreach (SceneObjectPart part in prims)
1719 {
1720 if (part != null)
1721 {
1722 if (part.KeyframeMotion != null)
1723 {
1724 part.KeyframeMotion.Stop();
1725 part.KeyframeMotion = null;
1726 }
1727 if (part.ParentGroup.PrimCount != 1) // Skip single
1728 {
1729 if (part.LinkNum < 2) // Root
1730 {
1731 rootParts.Add(part);
1732 }
1733 else
1734 {
1735 part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID;
1736 childParts.Add(part);
1737 }
1738  
1739 SceneObjectGroup group = part.ParentGroup;
1740 if (!affectedGroups.Contains(group))
1741 affectedGroups.Add(group);
1742 }
1743 }
1744 }
1745  
1746 foreach (SceneObjectPart child in childParts)
1747 {
1748 // Unlink all child parts from their groups
1749 //
1750 child.ParentGroup.DelinkFromGroup(child, true);
1751  
1752 // These are not in affected groups and will not be
1753 // handled further. Do the honors here.
1754 child.ParentGroup.HasGroupChanged = true;
1755 child.ParentGroup.ScheduleGroupForFullUpdate();
1756 }
1757  
1758 foreach (SceneObjectPart root in rootParts)
1759 {
1760 // In most cases, this will run only one time, and the prim
1761 // will be a solo prim
1762 // However, editing linked parts and unlinking may be different
1763 //
1764 SceneObjectGroup group = root.ParentGroup;
1765  
1766 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1767 int numChildren = newSet.Count;
1768  
1769 // If there are prims left in a link set, but the root is
1770 // slated for unlink, we need to do this
1771 //
1772 if (numChildren != 1)
1773 {
1774 // Unlink the remaining set
1775 //
1776 bool sendEventsToRemainder = true;
1777 if (numChildren > 1)
1778 sendEventsToRemainder = false;
1779  
1780 foreach (SceneObjectPart p in newSet)
1781 {
1782 if (p != group.RootPart)
1783 group.DelinkFromGroup(p, sendEventsToRemainder);
1784 }
1785  
1786 // If there is more than one prim remaining, we
1787 // need to re-link
1788 //
1789 if (numChildren > 2)
1790 {
1791 // Remove old root
1792 //
1793 if (newSet.Contains(root))
1794 newSet.Remove(root);
1795  
1796 // Preserve link ordering
1797 //
1798 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1799 {
1800 return a.LinkNum.CompareTo(b.LinkNum);
1801 });
1802  
1803 // Determine new root
1804 //
1805 SceneObjectPart newRoot = newSet[0];
1806 newSet.RemoveAt(0);
1807  
1808 foreach (SceneObjectPart newChild in newSet)
1809 newChild.ClearUpdateSchedule();
1810  
1811 LinkObjects(newRoot, newSet);
1812 if (!affectedGroups.Contains(newRoot.ParentGroup))
1813 affectedGroups.Add(newRoot.ParentGroup);
1814 }
1815 }
1816 }
1817  
1818 // Finally, trigger events in the roots
1819 //
1820 foreach (SceneObjectGroup g in affectedGroups)
1821 {
1822 g.TriggerScriptChangedEvent(Changed.LINK);
1823 g.HasGroupChanged = true; // Persist
1824 g.ScheduleGroupForFullUpdate();
1825 }
1826 }
1827 finally
1828 {
1829 Monitor.Exit(m_updateLock);
1830 }
1831 }
1832  
1833 protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
1834 {
1835 UUID user = remoteClient.AgentId;
1836 UUID objid = UUID.Zero;
1837 SceneObjectPart obj = null;
1838  
1839 EntityBase[] entityList = GetEntities();
1840 foreach (EntityBase ent in entityList)
1841 {
1842 if (ent is SceneObjectGroup)
1843 {
1844 SceneObjectGroup sog = ent as SceneObjectGroup;
1845  
1846 foreach (SceneObjectPart part in sog.Parts)
1847 {
1848 if (part.LocalId == localID)
1849 {
1850 objid = part.UUID;
1851 obj = part;
1852 }
1853 }
1854 }
1855 }
1856  
1857 //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
1858 //aka ObjectFlags.JointWheel = IncludeInSearch
1859  
1860 //Permissions model: Object can be REMOVED from search IFF:
1861 // * User owns object
1862 //use CanEditObject
1863  
1864 //Object can be ADDED to search IFF:
1865 // * User owns object
1866 // * Asset/DRM permission bit "modify" is enabled
1867 //use CanEditObjectPosition
1868  
1869 // libomv will complain about PrimFlags.JointWheel being
1870 // deprecated, so we
1871 #pragma warning disable 0612
1872 if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user))
1873 {
1874 obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel);
1875 obj.ParentGroup.HasGroupChanged = true;
1876 }
1877 else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user))
1878 {
1879 obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel);
1880 obj.ParentGroup.HasGroupChanged = true;
1881 }
1882 #pragma warning restore 0612
1883 }
1884  
1885 /// <summary>
1886 /// Duplicate the given object.
1887 /// </summary>
1888 /// <param name="originalPrim"></param>
1889 /// <param name="offset"></param>
1890 /// <param name="flags"></param>
1891 /// <param name="AgentID"></param>
1892 /// <param name="GroupID"></param>
1893 /// <param name="rot"></param>
1894 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1895 public SceneObjectGroup DuplicateObject(
1896 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1897 {
1898 Monitor.Enter(m_updateLock);
1899  
1900 try
1901 {
1902 // m_log.DebugFormat(
1903 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
1904 // originalPrimID, offset, AgentID);
1905  
1906 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1907 if (original == null)
1908 {
1909 m_log.WarnFormat(
1910 "[SCENEGRAPH]: Attempt to duplicate nonexistent prim id {0} by {1}", originalPrimID, AgentID);
1911  
1912 return null;
1913 }
1914  
1915 if (!m_parentScene.Permissions.CanDuplicateObject(
1916 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1917 return null;
1918  
1919 SceneObjectGroup copy = original.Copy(true);
1920 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1921  
1922 if (original.OwnerID != AgentID)
1923 {
1924 copy.SetOwnerId(AgentID);
1925 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1926  
1927 SceneObjectPart[] partList = copy.Parts;
1928  
1929 if (m_parentScene.Permissions.PropagatePermissions())
1930 {
1931 foreach (SceneObjectPart child in partList)
1932 {
1933 child.Inventory.ChangeInventoryOwner(AgentID);
1934 child.TriggerScriptChangedEvent(Changed.OWNER);
1935 child.ApplyNextOwnerPermissions();
1936 }
1937 }
1938  
1939 copy.RootPart.ObjectSaleType = 0;
1940 copy.RootPart.SalePrice = 10;
1941 }
1942  
1943 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1944 Entities.Add(copy);
1945  
1946 lock (SceneObjectGroupsByFullID)
1947 SceneObjectGroupsByFullID[copy.UUID] = copy;
1948  
1949 SceneObjectPart[] children = copy.Parts;
1950  
1951 lock (SceneObjectGroupsByFullPartID)
1952 {
1953 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1954 foreach (SceneObjectPart part in children)
1955 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1956 }
1957  
1958 lock (SceneObjectGroupsByLocalPartID)
1959 {
1960 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
1961 foreach (SceneObjectPart part in children)
1962 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
1963 }
1964 // PROBABLE END OF FIXME
1965  
1966 // Since we copy from a source group that is in selected
1967 // state, but the copy is shown deselected in the viewer,
1968 // We need to clear the selection flag here, else that
1969 // prim never gets persisted at all. The client doesn't
1970 // think it's selected, so it will never send a deselect...
1971 copy.IsSelected = false;
1972  
1973 m_numPrim += copy.Parts.Length;
1974  
1975 if (rot != Quaternion.Identity)
1976 {
1977 copy.UpdateGroupRotationR(rot);
1978 }
1979  
1980 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1981 copy.HasGroupChanged = true;
1982 copy.ScheduleGroupForFullUpdate();
1983 copy.ResumeScripts();
1984  
1985 // required for physics to update it's position
1986 copy.AbsolutePosition = copy.AbsolutePosition;
1987  
1988 return copy;
1989 }
1990 finally
1991 {
1992 Monitor.Exit(m_updateLock);
1993 }
1994 }
1995  
1996 /// <summary>
1997 /// Calculates the distance between two Vector3s
1998 /// </summary>
1999 /// <param name="v1"></param>
2000 /// <param name="v2"></param>
2001 /// <returns></returns>
2002 protected internal float Vector3Distance(Vector3 v1, Vector3 v2)
2003 {
2004 // We don't really need the double floating point precision...
2005 // so casting it to a single
2006  
2007 return
2008 (float)
2009 Math.Sqrt((v1.X - v2.X) * (v1.X - v2.X) + (v1.Y - v2.Y) * (v1.Y - v2.Y) + (v1.Z - v2.Z) * (v1.Z - v2.Z));
2010 }
2011  
2012 #endregion
2013  
2014  
2015 }
2016 }