clockwerk-opensim-stable – 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++;
523 }
524  
525 protected internal void RemovePhysicalPrim(int number)
526 {
527 m_physicalPrim--;
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 (presence.Firstname == firstName && presence.Lastname == lastName)
776 return presence;
777 }
778 return null;
779 }
780  
781 /// <summary>
782 /// Request the scene presence by localID.
783 /// </summary>
784 /// <param name="localID"></param>
785 /// <returns>null if the presence was not found</returns>
786 protected internal ScenePresence GetScenePresence(uint localID)
787 {
788 List<ScenePresence> presences = GetScenePresences();
789 foreach (ScenePresence presence in presences)
790 if (presence.LocalId == localID)
791 return presence;
792 return null;
793 }
794  
795 protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar)
796 {
797 Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
798 presences.TryGetValue(agentID, out avatar);
799 return (avatar != null);
800 }
801  
802 protected internal bool TryGetAvatarByName(string name, out ScenePresence avatar)
803 {
804 avatar = null;
805 foreach (ScenePresence presence in GetScenePresences())
806 {
807 if (String.Compare(name, presence.ControllingClient.Name, true) == 0)
808 {
809 avatar = presence;
810 break;
811 }
812 }
813 return (avatar != null);
814 }
815  
816 /// <summary>
817 /// Get a scene object group that contains the prim with the given local id
818 /// </summary>
819 /// <param name="localID"></param>
820 /// <returns>null if no scene object group containing that prim is found</returns>
821 public SceneObjectGroup GetGroupByPrim(uint localID)
822 {
823 EntityBase entity;
824 if (Entities.TryGetValue(localID, out entity))
825 return entity as SceneObjectGroup;
826  
827 // m_log.DebugFormat("[SCENE GRAPH]: Entered GetGroupByPrim with localID {0}", localID);
828  
829 SceneObjectGroup sog;
830 lock (SceneObjectGroupsByLocalPartID)
831 SceneObjectGroupsByLocalPartID.TryGetValue(localID, out sog);
832  
833 if (sog != null)
834 {
835 if (sog.ContainsPart(localID))
836 {
837 // m_log.DebugFormat(
838 // "[SCENE GRAPH]: Found scene object {0} {1} {2} containing part with local id {3} in {4}. Returning.",
839 // sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName);
840  
841 return sog;
842 }
843 else
844 {
845 lock (SceneObjectGroupsByLocalPartID)
846 {
847 m_log.WarnFormat(
848 "[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}.",
849 sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName);
850  
851 SceneObjectGroupsByLocalPartID.Remove(localID);
852 }
853 }
854 }
855  
856 EntityBase[] entityList = GetEntities();
857 foreach (EntityBase ent in entityList)
858 {
859 //m_log.DebugFormat("Looking at entity {0}", ent.UUID);
860 if (ent is SceneObjectGroup)
861 {
862 sog = (SceneObjectGroup)ent;
863 if (sog.ContainsPart(localID))
864 {
865 lock (SceneObjectGroupsByLocalPartID)
866 SceneObjectGroupsByLocalPartID[localID] = sog;
867 return sog;
868 }
869 }
870 }
871  
872 return null;
873 }
874  
875 /// <summary>
876 /// Get a scene object group that contains the prim with the given uuid
877 /// </summary>
878 /// <param name="fullID"></param>
879 /// <returns>null if no scene object group containing that prim is found</returns>
880 public SceneObjectGroup GetGroupByPrim(UUID fullID)
881 {
882 SceneObjectGroup sog;
883 lock (SceneObjectGroupsByFullPartID)
884 SceneObjectGroupsByFullPartID.TryGetValue(fullID, out sog);
885  
886 if (sog != null)
887 {
888 if (sog.ContainsPart(fullID))
889 return sog;
890  
891 lock (SceneObjectGroupsByFullPartID)
892 SceneObjectGroupsByFullPartID.Remove(fullID);
893 }
894  
895 EntityBase[] entityList = GetEntities();
896 foreach (EntityBase ent in entityList)
897 {
898 if (ent is SceneObjectGroup)
899 {
900 sog = (SceneObjectGroup)ent;
901 if (sog.ContainsPart(fullID))
902 {
903 lock (SceneObjectGroupsByFullPartID)
904 SceneObjectGroupsByFullPartID[fullID] = sog;
905 return sog;
906 }
907 }
908 }
909  
910 return null;
911 }
912  
913 protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
914 {
915 // Primitive Ray Tracing
916 float closestDistance = 280f;
917 EntityIntersection result = new EntityIntersection();
918 EntityBase[] EntityList = GetEntities();
919 foreach (EntityBase ent in EntityList)
920 {
921 if (ent is SceneObjectGroup)
922 {
923 SceneObjectGroup reportingG = (SceneObjectGroup)ent;
924 EntityIntersection inter = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
925 if (inter.HitTF && inter.distance < closestDistance)
926 {
927 closestDistance = inter.distance;
928 result = inter;
929 }
930 }
931 }
932 return result;
933 }
934  
935 /// <summary>
936 /// Get all the scene object groups.
937 /// </summary>
938 /// <returns>
939 /// The scene object groups. If the scene is empty then an empty list is returned.
940 /// </returns>
941 protected internal List<SceneObjectGroup> GetSceneObjectGroups()
942 {
943 lock (SceneObjectGroupsByFullID)
944 return new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
945 }
946  
947 /// <summary>
948 /// Get a group in the scene
949 /// </summary>
950 /// <param name="fullID">UUID of the group</param>
951 /// <returns>null if no such group was found</returns>
952 protected internal SceneObjectGroup GetSceneObjectGroup(UUID fullID)
953 {
954 lock (SceneObjectGroupsByFullID)
955 {
956 if (SceneObjectGroupsByFullID.ContainsKey(fullID))
957 return SceneObjectGroupsByFullID[fullID];
958 }
959  
960 return null;
961 }
962  
963 /// <summary>
964 /// Get a group in the scene
965 /// </summary>
966 /// <remarks>
967 /// This will only return a group if the local ID matches the root part, not other parts.
968 /// </remarks>
969 /// <param name="localID">Local id of the root part of the group</param>
970 /// <returns>null if no such group was found</returns>
971 protected internal SceneObjectGroup GetSceneObjectGroup(uint localID)
972 {
973 lock (SceneObjectGroupsByLocalPartID)
974 {
975 if (SceneObjectGroupsByLocalPartID.ContainsKey(localID))
976 {
977 SceneObjectGroup so = SceneObjectGroupsByLocalPartID[localID];
978  
979 if (so.LocalId == localID)
980 return so;
981 }
982 }
983  
984 return null;
985 }
986  
987 /// <summary>
988 /// Get a group by name from the scene (will return the first
989 /// found, if there are more than one prim with the same name)
990 /// </summary>
991 /// <param name="name"></param>
992 /// <returns>null if the part was not found</returns>
993 protected internal SceneObjectGroup GetSceneObjectGroup(string name)
994 {
995 SceneObjectGroup so = null;
996  
997 Entities.Find(
998 delegate(EntityBase entity)
999 {
1000 if (entity is SceneObjectGroup)
1001 {
1002 if (entity.Name == name)
1003 {
1004 so = (SceneObjectGroup)entity;
1005 return true;
1006 }
1007 }
1008  
1009 return false;
1010 }
1011 );
1012  
1013 return so;
1014 }
1015  
1016 /// <summary>
1017 /// Get a part contained in this scene.
1018 /// </summary>
1019 /// <param name="localID"></param>
1020 /// <returns>null if the part was not found</returns>
1021 protected internal SceneObjectPart GetSceneObjectPart(uint localID)
1022 {
1023 SceneObjectGroup group = GetGroupByPrim(localID);
1024 if (group == null)
1025 return null;
1026 return group.GetPart(localID);
1027 }
1028  
1029 /// <summary>
1030 /// Get a prim by name from the scene (will return the first
1031 /// found, if there are more than one prim with the same name)
1032 /// </summary>
1033 /// <param name="name"></param>
1034 /// <returns>null if the part was not found</returns>
1035 protected internal SceneObjectPart GetSceneObjectPart(string name)
1036 {
1037 SceneObjectPart sop = null;
1038  
1039 Entities.Find(
1040 delegate(EntityBase entity)
1041 {
1042 if (entity is SceneObjectGroup)
1043 {
1044 foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts)
1045 {
1046 // m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name);
1047  
1048 if (p.Name == name)
1049 {
1050 sop = p;
1051 return true;
1052 }
1053 }
1054 }
1055  
1056 return false;
1057 }
1058 );
1059  
1060 return sop;
1061 }
1062  
1063 /// <summary>
1064 /// Get a part contained in this scene.
1065 /// </summary>
1066 /// <param name="fullID"></param>
1067 /// <returns>null if the part was not found</returns>
1068 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
1069 {
1070 SceneObjectGroup group = GetGroupByPrim(fullID);
1071 if (group == null)
1072 return null;
1073 return group.GetPart(fullID);
1074 }
1075  
1076 /// <summary>
1077 /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
1078 /// it
1079 /// </summary>
1080 /// <returns></returns>
1081 protected internal EntityBase[] GetEntities()
1082 {
1083 return Entities.GetEntities();
1084 }
1085  
1086 #endregion
1087  
1088 #region Other Methods
1089  
1090 protected internal void physicsBasedCrash()
1091 {
1092 handlerPhysicsCrash = UnRecoverableError;
1093 if (handlerPhysicsCrash != null)
1094 {
1095 handlerPhysicsCrash();
1096 }
1097 }
1098  
1099 protected internal UUID ConvertLocalIDToFullID(uint localID)
1100 {
1101 SceneObjectGroup group = GetGroupByPrim(localID);
1102 if (group != null)
1103 return group.GetPartsFullID(localID);
1104 else
1105 return UUID.Zero;
1106 }
1107  
1108 /// <summary>
1109 /// Performs action once on all scene object groups.
1110 /// </summary>
1111 /// <param name="action"></param>
1112 protected internal void ForEachSOG(Action<SceneObjectGroup> action)
1113 {
1114 foreach (SceneObjectGroup obj in GetSceneObjectGroups())
1115 {
1116 try
1117 {
1118 action(obj);
1119 }
1120 catch (Exception e)
1121 {
1122 // Catch it and move on. This includes situations where objlist has inconsistent info
1123 m_log.WarnFormat(
1124 "[SCENEGRAPH]: Problem processing action in ForEachSOG: {0} {1}", e.Message, e.StackTrace);
1125 }
1126 }
1127 }
1128  
1129 /// <summary>
1130 /// Performs action on all ROOT (not child) scene presences.
1131 /// This is just a shortcut function since frequently actions only appy to root SPs
1132 /// </summary>
1133 /// <param name="action"></param>
1134 public void ForEachAvatar(Action<ScenePresence> action)
1135 {
1136 ForEachScenePresence(delegate(ScenePresence sp)
1137 {
1138 if (!sp.IsChildAgent)
1139 action(sp);
1140 });
1141 }
1142  
1143 /// <summary>
1144 /// Performs action on all scene presences. This can ultimately run the actions in parallel but
1145 /// any delegates passed in will need to implement their own locking on data they reference and
1146 /// modify outside of the scope of the delegate.
1147 /// </summary>
1148 /// <param name="action"></param>
1149 public void ForEachScenePresence(Action<ScenePresence> action)
1150 {
1151 // Once all callers have their delegates configured for parallelism, we can unleash this
1152 /*
1153 Action<ScenePresence> protectedAction = new Action<ScenePresence>(delegate(ScenePresence sp)
1154 {
1155 try
1156 {
1157 action(sp);
1158 }
1159 catch (Exception e)
1160 {
1161 m_log.Info("[SCENEGRAPH]: Error in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1162 m_log.Info("[SCENEGRAPH]: Stack Trace: " + e.StackTrace);
1163 }
1164 });
1165 Parallel.ForEach<ScenePresence>(GetScenePresences(), protectedAction);
1166 */
1167 // For now, perform actions serially
1168 List<ScenePresence> presences = GetScenePresences();
1169 foreach (ScenePresence sp in presences)
1170 {
1171 try
1172 {
1173 action(sp);
1174 }
1175 catch (Exception e)
1176 {
1177 m_log.Error("[SCENEGRAPH]: Error in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1178 }
1179 }
1180 }
1181  
1182 #endregion
1183  
1184 #region Client Event handlers
1185  
1186 /// <summary>
1187 /// Update the scale of an individual prim.
1188 /// </summary>
1189 /// <param name="localID"></param>
1190 /// <param name="scale"></param>
1191 /// <param name="remoteClient"></param>
1192 protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1193 {
1194 SceneObjectPart part = GetSceneObjectPart(localID);
1195  
1196 if (part != null)
1197 {
1198 if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1199 {
1200 part.Resize(scale);
1201 }
1202 }
1203 }
1204  
1205 protected internal void UpdatePrimGroupScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1206 {
1207 SceneObjectGroup group = GetGroupByPrim(localID);
1208 if (group != null)
1209 {
1210 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1211 {
1212 group.GroupResize(scale);
1213 }
1214 }
1215 }
1216  
1217 /// <summary>
1218 /// This handles the nifty little tool tip that you get when you drag your mouse over an object
1219 /// Send to the Object Group to process. We don't know enough to service the request
1220 /// </summary>
1221 /// <param name="remoteClient"></param>
1222 /// <param name="AgentID"></param>
1223 /// <param name="RequestFlags"></param>
1224 /// <param name="ObjectID"></param>
1225 protected internal void RequestObjectPropertiesFamily(
1226 IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
1227 {
1228 SceneObjectGroup group = GetGroupByPrim(ObjectID);
1229 if (group != null)
1230 {
1231 group.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
1232 }
1233 }
1234  
1235 /// <summary>
1236 ///
1237 /// </summary>
1238 /// <param name="localID"></param>
1239 /// <param name="rot"></param>
1240 /// <param name="remoteClient"></param>
1241 protected internal void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1242 {
1243 SceneObjectGroup group = GetGroupByPrim(localID);
1244 if (group != null)
1245 {
1246 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1247 {
1248 group.UpdateSingleRotation(rot, localID);
1249 }
1250 }
1251 }
1252  
1253 /// <summary>
1254 ///
1255 /// </summary>
1256 /// <param name="localID"></param>
1257 /// <param name="rot"></param>
1258 /// <param name="remoteClient"></param>
1259 protected internal void UpdatePrimSingleRotationPosition(uint localID, Quaternion rot, Vector3 pos, IClientAPI remoteClient)
1260 {
1261 SceneObjectGroup group = GetGroupByPrim(localID);
1262 if (group != null)
1263 {
1264 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1265 {
1266 group.UpdateSingleRotation(rot, pos, localID);
1267 }
1268 }
1269 }
1270  
1271 /// <summary>
1272 /// Update the rotation of a whole group.
1273 /// </summary>
1274 /// <param name="localID"></param>
1275 /// <param name="rot"></param>
1276 /// <param name="remoteClient"></param>
1277 protected internal void UpdatePrimGroupRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1278 {
1279 SceneObjectGroup group = GetGroupByPrim(localID);
1280 if (group != null)
1281 {
1282 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1283 {
1284 group.UpdateGroupRotationR(rot);
1285 }
1286 }
1287 }
1288  
1289 /// <summary>
1290 ///
1291 /// </summary>
1292 /// <param name="localID"></param>
1293 /// <param name="pos"></param>
1294 /// <param name="rot"></param>
1295 /// <param name="remoteClient"></param>
1296 protected internal void UpdatePrimGroupRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
1297 {
1298 SceneObjectGroup group = GetGroupByPrim(localID);
1299 if (group != null)
1300 {
1301 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1302 {
1303 group.UpdateGroupRotationPR(pos, rot);
1304 }
1305 }
1306 }
1307  
1308 /// <summary>
1309 /// Update the position of the given part
1310 /// </summary>
1311 /// <param name="localID"></param>
1312 /// <param name="pos"></param>
1313 /// <param name="remoteClient"></param>
1314 protected internal void UpdatePrimSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1315 {
1316 SceneObjectGroup group = GetGroupByPrim(localID);
1317 if (group != null)
1318 {
1319 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment)
1320 {
1321 group.UpdateSinglePosition(pos, localID);
1322 }
1323 }
1324 }
1325  
1326 /// <summary>
1327 /// Update the position of the given group.
1328 /// </summary>
1329 /// <param name="localID"></param>
1330 /// <param name="pos"></param>
1331 /// <param name="remoteClient"></param>
1332 public void UpdatePrimGroupPosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1333 {
1334 SceneObjectGroup group = GetGroupByPrim(localID);
1335  
1336 if (group != null)
1337 {
1338 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1339 {
1340 if (m_parentScene.AttachmentsModule != null)
1341 m_parentScene.AttachmentsModule.UpdateAttachmentPosition(group, pos);
1342 }
1343 else
1344 {
1345 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId)
1346 && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1347 {
1348 group.UpdateGroupPosition(pos);
1349 }
1350 }
1351 }
1352 }
1353  
1354 /// <summary>
1355 /// Update the texture entry of the given prim.
1356 /// </summary>
1357 /// <remarks>
1358 /// A texture entry is an object that contains details of all the textures of the prim's face. In this case,
1359 /// the texture is given in its byte serialized form.
1360 /// </remarks>
1361 /// <param name="localID"></param>
1362 /// <param name="texture"></param>
1363 /// <param name="remoteClient"></param>
1364 protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
1365 {
1366 SceneObjectGroup group = GetGroupByPrim(localID);
1367  
1368 if (group != null)
1369 {
1370 if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId))
1371 {
1372 group.UpdateTextureEntry(localID, texture);
1373 }
1374 }
1375 }
1376  
1377 /// <summary>
1378 /// Update the flags on a scene object. This covers properties such as phantom, physics and temporary.
1379 /// </summary>
1380 /// <remarks>
1381 /// This is currently handling the incoming call from the client stack (e.g. LLClientView).
1382 /// </remarks>
1383 /// <param name="localID"></param>
1384 /// <param name="UsePhysics"></param>
1385 /// <param name="SetTemporary"></param>
1386 /// <param name="SetPhantom"></param>
1387 /// <param name="remoteClient"></param>
1388 protected internal void UpdatePrimFlags(
1389 uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1390 {
1391 SceneObjectGroup group = GetGroupByPrim(localID);
1392 if (group != null)
1393 {
1394 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1395 {
1396 // VolumeDetect can't be set via UI and will always be off when a change is made there
1397 // now only change volume dtc if phantom off
1398  
1399 if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1400 {
1401 bool vdtc;
1402 if (SetPhantom) // if phantom keep volumedtc
1403 vdtc = group.RootPart.VolumeDetectActive;
1404 else // else turn it off
1405 vdtc = false;
1406  
1407 group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1408 }
1409 else
1410 {
1411 SceneObjectPart part = GetSceneObjectPart(localID);
1412 if (part != null)
1413 {
1414 part.UpdateExtraPhysics(PhysData);
1415 if (part.UpdatePhysRequired)
1416 remoteClient.SendPartPhysicsProprieties(part);
1417 }
1418 }
1419 }
1420 }
1421 }
1422  
1423 /// <summary>
1424 /// Move the given object
1425 /// </summary>
1426 /// <param name="objectID"></param>
1427 /// <param name="offset"></param>
1428 /// <param name="pos"></param>
1429 /// <param name="remoteClient"></param>
1430 protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
1431 {
1432 SceneObjectGroup group = GetGroupByPrim(objectID);
1433 if (group != null)
1434 {
1435 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1436 {
1437 group.GrabMovement(offset, pos, remoteClient);
1438 }
1439 // This is outside the above permissions condition
1440 // so that if the object is locked the client moving the object
1441 // get's it's position on the simulator even if it was the same as before
1442 // This keeps the moving user's client in sync with the rest of the world.
1443 group.SendGroupTerseUpdate();
1444 }
1445 }
1446  
1447 /// <summary>
1448 /// Start spinning the given object
1449 /// </summary>
1450 /// <param name="objectID"></param>
1451 /// <param name="rotation"></param>
1452 /// <param name="remoteClient"></param>
1453 protected internal void SpinStart(UUID objectID, IClientAPI remoteClient)
1454 {
1455 SceneObjectGroup group = GetGroupByPrim(objectID);
1456 if (group != null)
1457 {
1458 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1459 {
1460 group.SpinStart(remoteClient);
1461 }
1462 }
1463 }
1464  
1465 /// <summary>
1466 /// Spin the given object
1467 /// </summary>
1468 /// <param name="objectID"></param>
1469 /// <param name="rotation"></param>
1470 /// <param name="remoteClient"></param>
1471 protected internal void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient)
1472 {
1473 SceneObjectGroup group = GetGroupByPrim(objectID);
1474 if (group != null)
1475 {
1476 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1477 {
1478 group.SpinMovement(rotation, remoteClient);
1479 }
1480 // This is outside the above permissions condition
1481 // so that if the object is locked the client moving the object
1482 // get's it's position on the simulator even if it was the same as before
1483 // This keeps the moving user's client in sync with the rest of the world.
1484 group.SendGroupTerseUpdate();
1485 }
1486 }
1487  
1488 /// <summary>
1489 ///
1490 /// </summary>
1491 /// <param name="primLocalID"></param>
1492 /// <param name="description"></param>
1493 protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
1494 {
1495 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1496 if (group != null)
1497 {
1498 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1499 {
1500 group.SetPartName(Util.CleanString(name), primLocalID);
1501 group.HasGroupChanged = true;
1502 }
1503 }
1504 }
1505  
1506 /// <summary>
1507 /// Handle a prim description set request from a viewer.
1508 /// </summary>
1509 /// <param name="primLocalID"></param>
1510 /// <param name="description"></param>
1511 protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
1512 {
1513 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1514 if (group != null)
1515 {
1516 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1517 {
1518 group.SetPartDescription(Util.CleanString(description), primLocalID);
1519 group.HasGroupChanged = true;
1520 }
1521 }
1522 }
1523  
1524 /// <summary>
1525 /// Set a click action for the prim.
1526 /// </summary>
1527 /// <param name="remoteClient"></param>
1528 /// <param name="primLocalID"></param>
1529 /// <param name="clickAction"></param>
1530 protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
1531 {
1532 // m_log.DebugFormat(
1533 // "[SCENEGRAPH]: User {0} set click action for {1} to {2}", remoteClient.Name, primLocalID, clickAction);
1534  
1535 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1536 if (group != null)
1537 {
1538 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1539 {
1540 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1541 if (part != null)
1542 {
1543 part.ClickAction = Convert.ToByte(clickAction);
1544 group.HasGroupChanged = true;
1545 }
1546 }
1547 }
1548 }
1549  
1550 protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
1551 {
1552 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1553 if (group != null)
1554 {
1555 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1556 {
1557 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1558 if (part != null)
1559 {
1560 part.Material = Convert.ToByte(material);
1561 group.HasGroupChanged = true;
1562 }
1563 }
1564 }
1565 }
1566  
1567 protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
1568 {
1569 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1570  
1571 if (group != null)
1572 {
1573 if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
1574 {
1575 group.UpdateExtraParam(primLocalID, type, inUse, data);
1576 }
1577 }
1578 }
1579  
1580 /// <summary>
1581 ///
1582 /// </summary>
1583 /// <param name="primLocalID"></param>
1584 /// <param name="shapeBlock"></param>
1585 protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
1586 {
1587 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1588 if (group != null)
1589 {
1590 if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
1591 {
1592 ObjectShapePacket.ObjectDataBlock shapeData = new ObjectShapePacket.ObjectDataBlock();
1593 shapeData.ObjectLocalID = shapeBlock.ObjectLocalID;
1594 shapeData.PathBegin = shapeBlock.PathBegin;
1595 shapeData.PathCurve = shapeBlock.PathCurve;
1596 shapeData.PathEnd = shapeBlock.PathEnd;
1597 shapeData.PathRadiusOffset = shapeBlock.PathRadiusOffset;
1598 shapeData.PathRevolutions = shapeBlock.PathRevolutions;
1599 shapeData.PathScaleX = shapeBlock.PathScaleX;
1600 shapeData.PathScaleY = shapeBlock.PathScaleY;
1601 shapeData.PathShearX = shapeBlock.PathShearX;
1602 shapeData.PathShearY = shapeBlock.PathShearY;
1603 shapeData.PathSkew = shapeBlock.PathSkew;
1604 shapeData.PathTaperX = shapeBlock.PathTaperX;
1605 shapeData.PathTaperY = shapeBlock.PathTaperY;
1606 shapeData.PathTwist = shapeBlock.PathTwist;
1607 shapeData.PathTwistBegin = shapeBlock.PathTwistBegin;
1608 shapeData.ProfileBegin = shapeBlock.ProfileBegin;
1609 shapeData.ProfileCurve = shapeBlock.ProfileCurve;
1610 shapeData.ProfileEnd = shapeBlock.ProfileEnd;
1611 shapeData.ProfileHollow = shapeBlock.ProfileHollow;
1612  
1613 group.UpdateShape(shapeData, primLocalID);
1614 }
1615 }
1616 }
1617  
1618 /// <summary>
1619 /// Initial method invoked when we receive a link objects request from the client.
1620 /// </summary>
1621 /// <param name="client"></param>
1622 /// <param name="parentPrim"></param>
1623 /// <param name="childPrims"></param>
1624 protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1625 {
1626 if (root.KeyframeMotion != null)
1627 {
1628 root.KeyframeMotion.Stop();
1629 root.KeyframeMotion = null;
1630 }
1631  
1632 SceneObjectGroup parentGroup = root.ParentGroup;
1633 if (parentGroup == null) return;
1634  
1635 // Cowardly refuse to link to a group owned root
1636 if (parentGroup.OwnerID == parentGroup.GroupID)
1637 return;
1638  
1639 Monitor.Enter(m_updateLock);
1640 try
1641 {
1642 List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1643  
1644 // We do this in reverse to get the link order of the prims correct
1645 for (int i = 0 ; i < children.Count ; i++)
1646 {
1647 SceneObjectGroup child = children[i].ParentGroup;
1648  
1649 // Don't try and add a group to itself - this will only cause severe problems later on.
1650 if (child == parentGroup)
1651 continue;
1652  
1653 // Make sure no child prim is set for sale
1654 // So that, on delink, no prims are unwittingly
1655 // left for sale and sold off
1656 child.RootPart.ObjectSaleType = 0;
1657 child.RootPart.SalePrice = 10;
1658 childGroups.Add(child);
1659 }
1660  
1661 foreach (SceneObjectGroup child in childGroups)
1662 {
1663 if (parentGroup.OwnerID == child.OwnerID)
1664 {
1665 parentGroup.LinkToGroup(child);
1666  
1667 child.DetachFromBackup();
1668  
1669 // this is here so physics gets updated!
1670 // Don't remove! Bad juju! Stay away! or fix physics!
1671 child.AbsolutePosition = child.AbsolutePosition;
1672 }
1673 }
1674  
1675 // We need to explicitly resend the newly link prim's object properties since no other actions
1676 // occur on link to invoke this elsewhere (such as object selection)
1677 if (childGroups.Count > 0)
1678 {
1679 parentGroup.RootPart.CreateSelected = true;
1680 parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1681 parentGroup.HasGroupChanged = true;
1682 parentGroup.ScheduleGroupForFullUpdate();
1683 }
1684 }
1685 finally
1686 {
1687 Monitor.Exit(m_updateLock);
1688 }
1689 }
1690  
1691 /// <summary>
1692 /// Delink a linkset
1693 /// </summary>
1694 /// <param name="prims"></param>
1695 protected internal void DelinkObjects(List<SceneObjectPart> prims)
1696 {
1697 Monitor.Enter(m_updateLock);
1698 try
1699 {
1700 List<SceneObjectPart> childParts = new List<SceneObjectPart>();
1701 List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
1702 List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
1703 // Look them all up in one go, since that is comparatively expensive
1704 //
1705 foreach (SceneObjectPart part in prims)
1706 {
1707 if (part != null)
1708 {
1709 if (part.KeyframeMotion != null)
1710 {
1711 part.KeyframeMotion.Stop();
1712 part.KeyframeMotion = null;
1713 }
1714 if (part.ParentGroup.PrimCount != 1) // Skip single
1715 {
1716 if (part.LinkNum < 2) // Root
1717 {
1718 rootParts.Add(part);
1719 }
1720 else
1721 {
1722 part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID;
1723 childParts.Add(part);
1724 }
1725  
1726 SceneObjectGroup group = part.ParentGroup;
1727 if (!affectedGroups.Contains(group))
1728 affectedGroups.Add(group);
1729 }
1730 }
1731 }
1732  
1733 foreach (SceneObjectPart child in childParts)
1734 {
1735 // Unlink all child parts from their groups
1736 //
1737 child.ParentGroup.DelinkFromGroup(child, true);
1738  
1739 // These are not in affected groups and will not be
1740 // handled further. Do the honors here.
1741 child.ParentGroup.HasGroupChanged = true;
1742 child.ParentGroup.ScheduleGroupForFullUpdate();
1743 }
1744  
1745 foreach (SceneObjectPart root in rootParts)
1746 {
1747 // In most cases, this will run only one time, and the prim
1748 // will be a solo prim
1749 // However, editing linked parts and unlinking may be different
1750 //
1751 SceneObjectGroup group = root.ParentGroup;
1752  
1753 List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
1754 int numChildren = newSet.Count;
1755  
1756 // If there are prims left in a link set, but the root is
1757 // slated for unlink, we need to do this
1758 //
1759 if (numChildren != 1)
1760 {
1761 // Unlink the remaining set
1762 //
1763 bool sendEventsToRemainder = true;
1764 if (numChildren > 1)
1765 sendEventsToRemainder = false;
1766  
1767 foreach (SceneObjectPart p in newSet)
1768 {
1769 if (p != group.RootPart)
1770 group.DelinkFromGroup(p, sendEventsToRemainder);
1771 }
1772  
1773 // If there is more than one prim remaining, we
1774 // need to re-link
1775 //
1776 if (numChildren > 2)
1777 {
1778 // Remove old root
1779 //
1780 if (newSet.Contains(root))
1781 newSet.Remove(root);
1782  
1783 // Preserve link ordering
1784 //
1785 newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
1786 {
1787 return a.LinkNum.CompareTo(b.LinkNum);
1788 });
1789  
1790 // Determine new root
1791 //
1792 SceneObjectPart newRoot = newSet[0];
1793 newSet.RemoveAt(0);
1794  
1795 foreach (SceneObjectPart newChild in newSet)
1796 newChild.ClearUpdateSchedule();
1797  
1798 LinkObjects(newRoot, newSet);
1799 if (!affectedGroups.Contains(newRoot.ParentGroup))
1800 affectedGroups.Add(newRoot.ParentGroup);
1801 }
1802 }
1803 }
1804  
1805 // Finally, trigger events in the roots
1806 //
1807 foreach (SceneObjectGroup g in affectedGroups)
1808 {
1809 g.TriggerScriptChangedEvent(Changed.LINK);
1810 g.HasGroupChanged = true; // Persist
1811 g.ScheduleGroupForFullUpdate();
1812 }
1813 }
1814 finally
1815 {
1816 Monitor.Exit(m_updateLock);
1817 }
1818 }
1819  
1820 protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
1821 {
1822 UUID user = remoteClient.AgentId;
1823 UUID objid = UUID.Zero;
1824 SceneObjectPart obj = null;
1825  
1826 EntityBase[] entityList = GetEntities();
1827 foreach (EntityBase ent in entityList)
1828 {
1829 if (ent is SceneObjectGroup)
1830 {
1831 SceneObjectGroup sog = ent as SceneObjectGroup;
1832  
1833 foreach (SceneObjectPart part in sog.Parts)
1834 {
1835 if (part.LocalId == localID)
1836 {
1837 objid = part.UUID;
1838 obj = part;
1839 }
1840 }
1841 }
1842 }
1843  
1844 //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
1845 //aka ObjectFlags.JointWheel = IncludeInSearch
1846  
1847 //Permissions model: Object can be REMOVED from search IFF:
1848 // * User owns object
1849 //use CanEditObject
1850  
1851 //Object can be ADDED to search IFF:
1852 // * User owns object
1853 // * Asset/DRM permission bit "modify" is enabled
1854 //use CanEditObjectPosition
1855  
1856 // libomv will complain about PrimFlags.JointWheel being
1857 // deprecated, so we
1858 #pragma warning disable 0612
1859 if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user))
1860 {
1861 obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel);
1862 obj.ParentGroup.HasGroupChanged = true;
1863 }
1864 else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user))
1865 {
1866 obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel);
1867 obj.ParentGroup.HasGroupChanged = true;
1868 }
1869 #pragma warning restore 0612
1870 }
1871  
1872 /// <summary>
1873 /// Duplicate the given object.
1874 /// </summary>
1875 /// <param name="originalPrim"></param>
1876 /// <param name="offset"></param>
1877 /// <param name="flags"></param>
1878 /// <param name="AgentID"></param>
1879 /// <param name="GroupID"></param>
1880 /// <param name="rot"></param>
1881 /// <returns>null if duplication fails, otherwise the duplicated object</returns>
1882 public SceneObjectGroup DuplicateObject(
1883 uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1884 {
1885 Monitor.Enter(m_updateLock);
1886  
1887 try
1888 {
1889 // m_log.DebugFormat(
1890 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
1891 // originalPrimID, offset, AgentID);
1892  
1893 SceneObjectGroup original = GetGroupByPrim(originalPrimID);
1894 if (original == null)
1895 {
1896 m_log.WarnFormat(
1897 "[SCENEGRAPH]: Attempt to duplicate nonexistant prim id {0} by {1}", originalPrimID, AgentID);
1898  
1899 return null;
1900 }
1901  
1902 if (!m_parentScene.Permissions.CanDuplicateObject(
1903 original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
1904 return null;
1905  
1906 SceneObjectGroup copy = original.Copy(true);
1907 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1908  
1909 if (original.OwnerID != AgentID)
1910 {
1911 copy.SetOwnerId(AgentID);
1912 copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
1913  
1914 SceneObjectPart[] partList = copy.Parts;
1915  
1916 if (m_parentScene.Permissions.PropagatePermissions())
1917 {
1918 foreach (SceneObjectPart child in partList)
1919 {
1920 child.Inventory.ChangeInventoryOwner(AgentID);
1921 child.TriggerScriptChangedEvent(Changed.OWNER);
1922 child.ApplyNextOwnerPermissions();
1923 }
1924 }
1925  
1926 copy.RootPart.ObjectSaleType = 0;
1927 copy.RootPart.SalePrice = 10;
1928 }
1929  
1930 // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
1931 Entities.Add(copy);
1932  
1933 lock (SceneObjectGroupsByFullID)
1934 SceneObjectGroupsByFullID[copy.UUID] = copy;
1935  
1936 SceneObjectPart[] children = copy.Parts;
1937  
1938 lock (SceneObjectGroupsByFullPartID)
1939 {
1940 SceneObjectGroupsByFullPartID[copy.UUID] = copy;
1941 foreach (SceneObjectPart part in children)
1942 SceneObjectGroupsByFullPartID[part.UUID] = copy;
1943 }
1944  
1945 lock (SceneObjectGroupsByLocalPartID)
1946 {
1947 SceneObjectGroupsByLocalPartID[copy.LocalId] = copy;
1948 foreach (SceneObjectPart part in children)
1949 SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
1950 }
1951 // PROBABLE END OF FIXME
1952  
1953 // Since we copy from a source group that is in selected
1954 // state, but the copy is shown deselected in the viewer,
1955 // We need to clear the selection flag here, else that
1956 // prim never gets persisted at all. The client doesn't
1957 // think it's selected, so it will never send a deselect...
1958 copy.IsSelected = false;
1959  
1960 m_numPrim += copy.Parts.Length;
1961  
1962 if (rot != Quaternion.Identity)
1963 {
1964 copy.UpdateGroupRotationR(rot);
1965 }
1966  
1967 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
1968 copy.HasGroupChanged = true;
1969 copy.ScheduleGroupForFullUpdate();
1970 copy.ResumeScripts();
1971  
1972 // required for physics to update it's position
1973 copy.AbsolutePosition = copy.AbsolutePosition;
1974  
1975 return copy;
1976 }
1977 finally
1978 {
1979 Monitor.Exit(m_updateLock);
1980 }
1981 }
1982  
1983 /// <summary>
1984 /// Calculates the distance between two Vector3s
1985 /// </summary>
1986 /// <param name="v1"></param>
1987 /// <param name="v2"></param>
1988 /// <returns></returns>
1989 protected internal float Vector3Distance(Vector3 v1, Vector3 v2)
1990 {
1991 // We don't really need the double floating point precision...
1992 // so casting it to a single
1993  
1994 return
1995 (float)
1996 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));
1997 }
1998  
1999 #endregion
2000  
2001  
2002 }
2003 }