OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SceneGraph.cs
Go to the documentation of this file.
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.PhysicsModules.SharedBase;
38 using OpenSim.Region.Framework.Interfaces;
39 
40 namespace OpenSim.Region.Framework.Scenes
41 {
42  public delegate void PhysicsCrash();
43 
44  public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
45 
46  public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
47 
48  public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
49 
54  public class SceneGraph
55  {
56  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 
58  #region Events
59 
60  protected internal event PhysicsCrash UnRecoverableError;
61  private PhysicsCrash handlerPhysicsCrash = null;
62 
66 
67  #endregion
68 
69  #region Fields
70 
71  protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
72  protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
73  protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
74 
75  protected internal EntityManager Entities = new EntityManager();
76 
77  protected Scene m_parentScene;
78  protected Dictionary<UUID, SceneObjectGroup> m_updateList = new Dictionary<UUID, SceneObjectGroup>();
79  protected int m_numRootAgents = 0;
80  protected int m_numTotalPrim = 0;
81  protected int m_numPrim = 0;
82  protected int m_numMesh = 0;
83  protected int m_numChildAgents = 0;
84  protected int m_physicalPrim = 0;
85 
86  protected int m_activeScripts = 0;
87  protected int m_scriptLPS = 0;
88 
89  protected internal PhysicsScene _PhyScene;
90 
94  protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
95 
99  protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullPartID = new Dictionary<UUID, SceneObjectGroup>();
100 
104  protected internal Dictionary<uint, SceneObjectGroup> SceneObjectGroupsByLocalPartID = new Dictionary<uint, SceneObjectGroup>();
105 
113  private Object m_updateLock = new Object();
114 
115  #endregion
116 
117  protected internal SceneGraph(Scene parent)
118  {
119  m_parentScene = parent;
120  }
121 
123  {
124  get
125  {
126  if (_PhyScene == null)
127  _PhyScene = m_parentScene.RequestModuleInterface<PhysicsScene>();
128  return _PhyScene;
129  }
130  set
131  {
132  // If we're not doing the initial set
133  // Then we've got to remove the previous
134  // event handler
135  if (_PhyScene != null)
136  _PhyScene.OnPhysicsCrash -= physicsBasedCrash;
137 
138  _PhyScene = value;
139 
140  if (_PhyScene != null)
141  _PhyScene.OnPhysicsCrash += physicsBasedCrash;
142  }
143  }
144 
145  protected internal void Close()
146  {
147  m_scenePresencesLock.EnterWriteLock();
148  try
149  {
150  Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
151  List<ScenePresence> newlist = new List<ScenePresence>();
152  m_scenePresenceMap = newmap;
153  m_scenePresenceArray = newlist;
154  }
155  finally
156  {
157  m_scenePresencesLock.ExitWriteLock();
158  }
159 
160  lock (SceneObjectGroupsByFullID)
161  SceneObjectGroupsByFullID.Clear();
162  lock (SceneObjectGroupsByFullPartID)
163  SceneObjectGroupsByFullPartID.Clear();
164  lock (SceneObjectGroupsByLocalPartID)
165  SceneObjectGroupsByLocalPartID.Clear();
166 
167  Entities.Clear();
168  }
169 
170  #region Update Methods
171 
172  protected internal void UpdatePreparePhysics()
173  {
174  // If we are using a threaded physics engine
175  // grab the latest scene from the engine before
176  // trying to process it.
177 
178  // PhysX does this (runs in the background).
179 
181  {
182  PhysicsScene.GetResults();
183  }
184  }
185 
192  protected internal void UpdatePresences()
193  {
194  ForEachScenePresence(delegate(ScenePresence presence)
195  {
196  presence.Update();
197  });
198  }
199 
205  protected internal float UpdatePhysics(double elapsed)
206  {
207  // Here is where the Scene calls the PhysicsScene. This is a one-way
208  // interaction; the PhysicsScene cannot access the calling Scene directly.
209  // But with joints, we want a PhysicsActor to be able to influence a
210  // non-physics SceneObjectPart. In particular, a PhysicsActor that is connected
211  // with a joint should be able to move the SceneObjectPart which is the visual
212  // representation of that joint (for editing and serialization purposes).
213  // However the PhysicsActor normally cannot directly influence anything outside
214  // of the PhysicsScene, and the non-physical SceneObjectPart which represents
215  // the joint in the Scene does not exist in the PhysicsScene.
216  //
217  // To solve this, we have an event in the PhysicsScene that is fired when a joint
218  // has changed position (because one of its associated PhysicsActors has changed
219  // position).
220  //
221  // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate().
222  return PhysicsScene.Simulate((float)elapsed);
223  }
224 
225  protected internal void ProcessPhysicsPreSimulation()
226  {
227  if(PhysicsScene != null)
228  PhysicsScene.ProcessPreSimulation();
229  }
230 
231  protected internal void UpdateScenePresenceMovement()
232  {
233  ForEachScenePresence(delegate(ScenePresence presence)
234  {
235  presence.UpdateMovement();
236  });
237  }
238 
239  public void GetCoarseLocations(out List<Vector3> coarseLocations, out List<UUID> avatarUUIDs, uint maxLocations)
240  {
241  coarseLocations = new List<Vector3>();
242  avatarUUIDs = new List<UUID>();
243 
244  List<ScenePresence> presences = GetScenePresences();
245  for (int i = 0; i < Math.Min(presences.Count, maxLocations); ++i)
246  {
247  ScenePresence sp = presences[i];
248 
249  // If this presence is a child agent, we don't want its coarse locations
250  if (sp.IsChildAgent)
251  continue;
252 
253  coarseLocations.Add(sp.AbsolutePosition);
254 
255  avatarUUIDs.Add(sp.UUID);
256  }
257  }
258 
259  #endregion
260 
261  #region Entity Methods
262 
282  protected internal bool AddRestoredSceneObject(
283  SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
284  {
285  if (!m_parentScene.CombineRegions)
286  {
287  // temporary checks to remove after varsize suport
288  float regionSizeX = m_parentScene.RegionInfo.RegionSizeX;
289  if (regionSizeX == 0)
290  regionSizeX = Constants.RegionSize;
291  float regionSizeY = m_parentScene.RegionInfo.RegionSizeY;
292  if (regionSizeY == 0)
293  regionSizeY = Constants.RegionSize;
294 
295  // KF: Check for out-of-region, move inside and make static.
296  Vector3 npos = new Vector3(sceneObject.RootPart.GroupPosition.X,
297  sceneObject.RootPart.GroupPosition.Y,
298  sceneObject.RootPart.GroupPosition.Z);
299  bool clampZ = m_parentScene.ClampNegativeZ;
300 
301  if (!(((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0))) && (npos.X < 0.0 || npos.Y < 0.0 || (npos.Z < 0.0 && clampZ) ||
302  npos.X > regionSizeX ||
303  npos.Y > regionSizeY))
304  {
305  if (npos.X < 0.0) npos.X = 1.0f;
306  if (npos.Y < 0.0) npos.Y = 1.0f;
307  if (npos.Z < 0.0 && clampZ) npos.Z = 0.0f;
308  if (npos.X > regionSizeX) npos.X = regionSizeX - 1.0f;
309  if (npos.Y > regionSizeY) npos.Y = regionSizeY - 1.0f;
310 
311  SceneObjectPart rootpart = sceneObject.RootPart;
312  rootpart.GroupPosition = npos;
313 
314  foreach (SceneObjectPart part in sceneObject.Parts)
315  {
316  if (part == rootpart)
317  continue;
318  part.GroupPosition = npos;
319  }
320  rootpart.Velocity = Vector3.Zero;
321  rootpart.AngularVelocity = Vector3.Zero;
322  rootpart.Acceleration = Vector3.Zero;
323  }
324  }
325 
326  bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
327 
328  if (attachToBackup && (!alreadyPersisted))
329  {
330  sceneObject.ForceInventoryPersistence();
331  sceneObject.HasGroupChanged = true;
332  }
333 
334  return ret;
335  }
336 
349  protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
350  {
351 
352  bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
353 
354  // Ensure that we persist this new scene object if it's not an
355  // attachment
356 
357  if (attachToBackup)
358  sceneObject.HasGroupChanged = true;
359 
360  return ret;
361  }
362 
375  public bool AddNewSceneObject(
376  SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
377  {
378  AddNewSceneObject(sceneObject, attachToBackup, false);
379 
380  if (pos != null)
381  sceneObject.AbsolutePosition = (Vector3)pos;
382 
383  if (sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim)
384  {
385  sceneObject.ClearPartAttachmentData();
386  }
387 
388  if (rot != null)
389  sceneObject.UpdateGroupRotationR((Quaternion)rot);
390 
391  PhysicsActor pa = sceneObject.RootPart.PhysActor;
392  if (pa != null && pa.IsPhysical && vel != Vector3.Zero)
393  {
394  sceneObject.RootPart.ApplyImpulse((vel * sceneObject.GetMass()), false);
395  }
396 
397  return true;
398  }
399 
419  protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
420  {
421  if (sceneObject == null)
422  {
423  m_log.ErrorFormat("[SCENEGRAPH]: Tried to add null scene object");
424  return false;
425  }
426  if (sceneObject.UUID == UUID.Zero)
427  {
428  m_log.ErrorFormat(
429  "[SCENEGRAPH]: Tried to add scene object {0} to {1} with illegal UUID of {2}",
430  sceneObject.Name, m_parentScene.RegionInfo.RegionName, UUID.Zero);
431 
432  return false;
433  }
434 
435  if (Entities.ContainsKey(sceneObject.UUID))
436  {
437  m_log.DebugFormat(
438  "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()",
439  m_parentScene.RegionInfo.RegionName, sceneObject.UUID);
440 
441  return false;
442  }
443 
444 // m_log.DebugFormat(
445 // "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}",
446 // sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName);
447 
448  SceneObjectPart[] parts = sceneObject.Parts;
449 
450  // Clamp the sizes (scales) of the child prims and add the child prims to the count of all primitives
451  // (meshes and geometric primitives) in the scene; add child prims to m_numTotalPrim count
452  if (m_parentScene.m_clampPrimSize)
453  {
454  foreach (SceneObjectPart part in parts)
455  {
456  Vector3 scale = part.Shape.Scale;
457 
458  scale.X = Util.Clamp(scale.X, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys);
459  scale.Y = Util.Clamp(scale.Y, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys);
460  scale.Z = Util.Clamp(scale.Z, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys);
461 
462  part.Shape.Scale = scale;
463  }
464  }
465  m_numTotalPrim += parts.Length;
466 
467  // Go through all parts (geometric primitives and meshes) of this Scene Object
468  foreach (SceneObjectPart part in parts)
469  {
470  // Keep track of the total number of meshes or geometric primitives now in the scene;
471  // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
472  // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
473  if (part.GetPrimType() == PrimType.SCULPT)
474  m_numMesh++;
475  else
476  m_numPrim++;
477  }
478 
479  sceneObject.AttachToScene(m_parentScene);
480 
481  Entities.Add(sceneObject);
482 
483  lock (SceneObjectGroupsByFullID)
484  SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
485 
486  foreach (SceneObjectPart part in parts)
487  {
488  lock (SceneObjectGroupsByFullPartID)
489  SceneObjectGroupsByFullPartID[part.UUID] = sceneObject;
490 
491  lock (SceneObjectGroupsByLocalPartID)
492  SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject;
493  }
494 
495  if (sendClientUpdates)
496  sceneObject.ScheduleGroupForFullUpdate();
497 
498  if (attachToBackup)
499  sceneObject.AttachToBackup();
500 
501  return true;
502  }
503 
505  {
506  // no tests, caller has responsability...
507  lock (SceneObjectGroupsByFullPartID)
508  SceneObjectGroupsByFullPartID[part.UUID] = grp;
509 
510  lock (SceneObjectGroupsByLocalPartID)
511  SceneObjectGroupsByLocalPartID[part.LocalId] = grp;
512  }
513 
518  public bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked)
519  {
520 // m_log.DebugFormat(
521 // "[SCENE GRAPH]: Deleting scene object with uuid {0}, resultOfObjectLinked = {1}",
522 // uuid, resultOfObjectLinked);
523 
524  EntityBase entity;
525  if (!Entities.TryGetValue(uuid, out entity) || (!(entity is SceneObjectGroup)))
526  return false;
527 
528  SceneObjectGroup grp = (SceneObjectGroup)entity;
529 
530  if (entity == null)
531  return false;
532 
533  if (!resultOfObjectLinked)
534  {
535  // Decrement the total number of primitives (meshes and geometric primitives)
536  // that are part of the Scene Object being removed
537  m_numTotalPrim -= grp.PrimCount;
538 
539  // Go through all parts (primitives and meshes) of this Scene Object
540  foreach (SceneObjectPart part in grp.Parts)
541  {
542  // Keep track of the total number of meshes or geometric primitives left in the scene;
543  // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
544  // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
545  if (part.GetPrimType() == PrimType.SCULPT)
546  m_numMesh--;
547  else
548  m_numPrim--;
549  }
550 
551  if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
552  RemovePhysicalPrim(grp.PrimCount);
553  }
554 
555  bool ret = Entities.Remove(uuid);
556 
557  lock (SceneObjectGroupsByFullID)
558  SceneObjectGroupsByFullID.Remove(grp.UUID);
559 
560  SceneObjectPart[] parts = grp.Parts;
561  for (int i = 0; i < parts.Length; i++)
562  {
563  lock (SceneObjectGroupsByFullPartID)
564  SceneObjectGroupsByFullPartID.Remove(parts[i].UUID);
565 
566  lock (SceneObjectGroupsByLocalPartID)
567  SceneObjectGroupsByLocalPartID.Remove(parts[i].LocalId);
568  }
569 
570  return ret;
571  }
572 
579  protected internal void AddToUpdateList(SceneObjectGroup obj)
580  {
581  lock (m_updateList)
582  m_updateList[obj.UUID] = obj;
583  }
584 
585  public void FireAttachToBackup(SceneObjectGroup obj)
586  {
587  if (OnAttachToBackup != null)
588  {
589  OnAttachToBackup(obj);
590  }
591  }
592 
594  {
595  if (OnDetachFromBackup != null)
596  {
597  OnDetachFromBackup(obj);
598  }
599  }
600 
602  {
603  if (OnChangeBackup != null)
604  {
605  OnChangeBackup(obj);
606  }
607  }
608 
612  protected internal void UpdateObjectGroups()
613  {
614  if (!Monitor.TryEnter(m_updateLock))
615  return;
616  try
617  {
618  List<SceneObjectGroup> updates;
619 
620  // Some updates add more updates to the updateList.
621  // Get the current list of updates and clear the list before iterating
622  lock (m_updateList)
623  {
624  updates = new List<SceneObjectGroup>(m_updateList.Values);
625  m_updateList.Clear();
626  }
627 
628  // Go through all updates
629  for (int i = 0; i < updates.Count; i++)
630  {
631  SceneObjectGroup sog = updates[i];
632 
633  // Don't abort the whole update if one entity happens to give us an exception.
634  try
635  {
636  sog.Update();
637  }
638  catch (Exception e)
639  {
640  m_log.ErrorFormat(
641  "[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e);
642  }
643  }
644  }
645  finally
646  {
647  Monitor.Exit(m_updateLock);
648  }
649  }
650 
651  protected internal void AddPhysicalPrim(int number)
652  {
653  m_physicalPrim += number;
654  }
655 
656  protected internal void RemovePhysicalPrim(int number)
657  {
658  m_physicalPrim -= number;
659  }
660 
661  protected internal void AddToScriptLPS(int number)
662  {
663  m_scriptLPS += number;
664  }
665 
666  protected internal void AddActiveScripts(int number)
667  {
668  m_activeScripts += number;
669  }
670 
671  protected internal void HandleUndo(IClientAPI remoteClient, UUID primId)
672  {
673  if (primId != UUID.Zero)
674  {
675  SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
676  if (part != null)
677  part.Undo();
678  }
679  }
680 
681  protected internal void HandleRedo(IClientAPI remoteClient, UUID primId)
682  {
683  if (primId != UUID.Zero)
684  {
685  SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
686 
687  if (part != null)
688  part.Redo();
689  }
690  }
691 
692  protected internal ScenePresence CreateAndAddChildScenePresence(
693  IClientAPI client, AvatarAppearance appearance, PresenceType type)
694  {
695  // ScenePresence always defaults to child agent
696  ScenePresence presence = new ScenePresence(client, m_parentScene, appearance, type);
697 
698  Entities[presence.UUID] = presence;
699 
700  m_scenePresencesLock.EnterWriteLock();
701  try
702  {
703  m_numChildAgents++;
704 
705  Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
706  List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
707 
708  if (!newmap.ContainsKey(presence.UUID))
709  {
710  newmap.Add(presence.UUID, presence);
711  newlist.Add(presence);
712  }
713  else
714  {
715  // Remember the old presence reference from the dictionary
716  ScenePresence oldref = newmap[presence.UUID];
717  // Replace the presence reference in the dictionary with the new value
718  newmap[presence.UUID] = presence;
719  // Find the index in the list where the old ref was stored and update the reference
720  newlist[newlist.IndexOf(oldref)] = presence;
721  }
722 
723  // Swap out the dictionary and list with new references
724  m_scenePresenceMap = newmap;
725  m_scenePresenceArray = newlist;
726  }
727  finally
728  {
729  m_scenePresencesLock.ExitWriteLock();
730  }
731 
732  return presence;
733  }
734 
738  protected internal void RemoveScenePresence(UUID agentID)
739  {
740  if (!Entities.Remove(agentID))
741  {
742  m_log.WarnFormat(
743  "[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene Entities list",
744  agentID);
745  }
746 
747  m_scenePresencesLock.EnterWriteLock();
748  try
749  {
750  Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
751  List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
752 
753  // Remove the presence reference from the dictionary
754  if (newmap.ContainsKey(agentID))
755  {
756  ScenePresence oldref = newmap[agentID];
757  newmap.Remove(agentID);
758 
759  // Find the index in the list where the old ref was stored and remove the reference
760  newlist.RemoveAt(newlist.IndexOf(oldref));
761  // Swap out the dictionary and list with new references
762  m_scenePresenceMap = newmap;
763  m_scenePresenceArray = newlist;
764  }
765  else
766  {
767  m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
768  }
769  }
770  finally
771  {
772  m_scenePresencesLock.ExitWriteLock();
773  }
774  }
775 
776  protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
777  {
778  if (direction_RC_CR_T_F)
779  {
780  m_numRootAgents--;
781  m_numChildAgents++;
782  }
783  else
784  {
785  m_numChildAgents--;
786  m_numRootAgents++;
787  }
788  }
789 
790  public void removeUserCount(bool TypeRCTF)
791  {
792  if (TypeRCTF)
793  {
794  m_numRootAgents--;
795  }
796  else
797  {
798  m_numChildAgents--;
799  }
800  }
801 
802  public void RecalculateStats()
803  {
804  int rootcount = 0;
805  int childcount = 0;
806 
807  ForEachScenePresence(delegate(ScenePresence presence)
808  {
809  if (presence.IsChildAgent)
810  ++childcount;
811  else
812  ++rootcount;
813  });
814 
815  m_numRootAgents = rootcount;
816  m_numChildAgents = childcount;
817  }
818 
819  public int GetChildAgentCount()
820  {
821  return m_numChildAgents;
822  }
823 
824  public int GetRootAgentCount()
825  {
826  return m_numRootAgents;
827  }
828 
829  public int GetTotalObjectsCount()
830  {
831  return m_numTotalPrim;
832  }
833 
835  {
836  return m_numPrim;
837  }
838 
840  {
841  return m_numMesh;
842  }
843 
845  {
846  return m_physicalPrim;
847  }
848 
850  {
851  return m_activeScripts;
852  }
853 
854  public int GetScriptLPS()
855  {
856  int returnval = m_scriptLPS;
857  m_scriptLPS = 0;
858  return returnval;
859  }
860 
861  #endregion
862 
863  #region Get Methods
864 
878  public IClientAPI GetControllingClient(UUID agentId)
879  {
880  ScenePresence presence = GetScenePresence(agentId);
881 
882  if (presence != null)
883  {
884  return presence.ControllingClient;
885  }
886 
887  return null;
888  }
889 
897  protected internal List<ScenePresence> GetScenePresences()
898  {
899  return m_scenePresenceArray;
900  }
901 
907  protected internal ScenePresence GetScenePresence(UUID agentID)
908  {
909  Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
910  ScenePresence presence;
911  presences.TryGetValue(agentID, out presence);
912  return presence;
913  }
914 
921  protected internal ScenePresence GetScenePresence(string firstName, string lastName)
922  {
923  List<ScenePresence> presences = GetScenePresences();
924  foreach (ScenePresence presence in presences)
925  {
926  if (string.Equals(presence.Firstname, firstName, StringComparison.CurrentCultureIgnoreCase)
927  && string.Equals(presence.Lastname, lastName, StringComparison.CurrentCultureIgnoreCase))
928  return presence;
929  }
930  return null;
931  }
932 
938  protected internal ScenePresence GetScenePresence(uint localID)
939  {
940  List<ScenePresence> presences = GetScenePresences();
941  foreach (ScenePresence presence in presences)
942  if (presence.LocalId == localID)
943  return presence;
944  return null;
945  }
946 
947  protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar)
948  {
949  Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
950  presences.TryGetValue(agentID, out avatar);
951  return (avatar != null);
952  }
953 
954  protected internal bool TryGetAvatarByName(string name, out ScenePresence avatar)
955  {
956  avatar = null;
957  foreach (ScenePresence presence in GetScenePresences())
958  {
959  if (String.Compare(name, presence.ControllingClient.Name, true) == 0)
960  {
961  avatar = presence;
962  break;
963  }
964  }
965  return (avatar != null);
966  }
967 
973  public SceneObjectGroup GetGroupByPrim(uint localID)
974  {
975  EntityBase entity;
976  if (Entities.TryGetValue(localID, out entity))
977  return entity as SceneObjectGroup;
978 
979 // m_log.DebugFormat("[SCENE GRAPH]: Entered GetGroupByPrim with localID {0}", localID);
980 
981  SceneObjectGroup sog;
982  lock (SceneObjectGroupsByLocalPartID)
983  SceneObjectGroupsByLocalPartID.TryGetValue(localID, out sog);
984 
985  if (sog != null)
986  {
987  if (sog.ContainsPart(localID))
988  {
989 // m_log.DebugFormat(
990 // "[SCENE GRAPH]: Found scene object {0} {1} {2} containing part with local id {3} in {4}. Returning.",
991 // sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName);
992 
993  return sog;
994  }
995  else
996  {
997  lock (SceneObjectGroupsByLocalPartID)
998  {
999  m_log.WarnFormat(
1000  "[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}.",
1001  sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName);
1002  m_log.WarnFormat("stack: {0}", Environment.StackTrace);
1003  SceneObjectGroupsByLocalPartID.Remove(localID);
1004  }
1005  }
1006  }
1007 
1008  EntityBase[] entityList = GetEntities();
1009  foreach (EntityBase ent in entityList)
1010  {
1011  //m_log.DebugFormat("Looking at entity {0}", ent.UUID);
1012  if (ent is SceneObjectGroup)
1013  {
1014  sog = (SceneObjectGroup)ent;
1015  if (sog.ContainsPart(localID))
1016  {
1017  lock (SceneObjectGroupsByLocalPartID)
1018  SceneObjectGroupsByLocalPartID[localID] = sog;
1019  return sog;
1020  }
1021  }
1022  }
1023 
1024  return null;
1025  }
1026 
1032  public SceneObjectGroup GetGroupByPrim(UUID fullID)
1033  {
1034  SceneObjectGroup sog;
1035  lock (SceneObjectGroupsByFullPartID)
1036  SceneObjectGroupsByFullPartID.TryGetValue(fullID, out sog);
1037 
1038  if (sog != null)
1039  {
1040  if (sog.ContainsPart(fullID))
1041  return sog;
1042 
1043  lock (SceneObjectGroupsByFullPartID)
1044  SceneObjectGroupsByFullPartID.Remove(fullID);
1045  }
1046 
1047  EntityBase[] entityList = GetEntities();
1048  foreach (EntityBase ent in entityList)
1049  {
1050  if (ent is SceneObjectGroup)
1051  {
1052  sog = (SceneObjectGroup)ent;
1053  if (sog.ContainsPart(fullID))
1054  {
1055  lock (SceneObjectGroupsByFullPartID)
1056  SceneObjectGroupsByFullPartID[fullID] = sog;
1057  return sog;
1058  }
1059  }
1060  }
1061 
1062  return null;
1063  }
1064 
1065  protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
1066  {
1067  // Primitive Ray Tracing
1068  float closestDistance = 280f;
1069  EntityIntersection result = new EntityIntersection();
1070  EntityBase[] EntityList = GetEntities();
1071  foreach (EntityBase ent in EntityList)
1072  {
1073  if (ent is SceneObjectGroup)
1074  {
1075  SceneObjectGroup reportingG = (SceneObjectGroup)ent;
1076  EntityIntersection inter = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
1077  if (inter.HitTF && inter.distance < closestDistance)
1078  {
1079  closestDistance = inter.distance;
1080  result = inter;
1081  }
1082  }
1083  }
1084  return result;
1085  }
1086 
1093  protected internal List<SceneObjectGroup> GetSceneObjectGroups()
1094  {
1095  lock (SceneObjectGroupsByFullID)
1096  return new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
1097  }
1098 
1104  protected internal SceneObjectGroup GetSceneObjectGroup(UUID fullID)
1105  {
1106  lock (SceneObjectGroupsByFullID)
1107  {
1108  if (SceneObjectGroupsByFullID.ContainsKey(fullID))
1109  return SceneObjectGroupsByFullID[fullID];
1110  }
1111 
1112  return null;
1113  }
1114 
1123  protected internal SceneObjectGroup GetSceneObjectGroup(uint localID)
1124  {
1125  lock (SceneObjectGroupsByLocalPartID)
1126  {
1127  if (SceneObjectGroupsByLocalPartID.ContainsKey(localID))
1128  {
1129  SceneObjectGroup so = SceneObjectGroupsByLocalPartID[localID];
1130 
1131  if (so.LocalId == localID)
1132  return so;
1133  }
1134  }
1135 
1136  return null;
1137  }
1138 
1145  protected internal SceneObjectGroup GetSceneObjectGroup(string name)
1146  {
1147  SceneObjectGroup so = null;
1148 
1149  Entities.Find(
1150  delegate(EntityBase entity)
1151  {
1152  if (entity is SceneObjectGroup)
1153  {
1154  if (entity.Name == name)
1155  {
1156  so = (SceneObjectGroup)entity;
1157  return true;
1158  }
1159  }
1160 
1161  return false;
1162  }
1163  );
1164 
1165  return so;
1166  }
1167 
1173  protected internal SceneObjectPart GetSceneObjectPart(uint localID)
1174  {
1175  SceneObjectGroup group = GetGroupByPrim(localID);
1176  if (group == null || group.IsDeleted)
1177  return null;
1178  return group.GetPart(localID);
1179  }
1180 
1187  protected internal SceneObjectPart GetSceneObjectPart(string name)
1188  {
1189  SceneObjectPart sop = null;
1190 
1191  Entities.Find(
1192  delegate(EntityBase entity)
1193  {
1194  if (entity is SceneObjectGroup)
1195  {
1196  foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts)
1197  {
1198 // m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name);
1199 
1200  if (p.Name == name)
1201  {
1202  sop = p;
1203  return true;
1204  }
1205  }
1206  }
1207 
1208  return false;
1209  }
1210  );
1211 
1212  return sop;
1213  }
1214 
1220  protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
1221  {
1222  SceneObjectGroup group = GetGroupByPrim(fullID);
1223  if (group == null)
1224  return null;
1225  return group.GetPart(fullID);
1226  }
1227 
1233  protected internal EntityBase[] GetEntities()
1234  {
1235  return Entities.GetEntities();
1236  }
1237 
1238  #endregion
1239 
1240  #region Other Methods
1241 
1242  protected internal void physicsBasedCrash()
1243  {
1244  handlerPhysicsCrash = UnRecoverableError;
1245  if (handlerPhysicsCrash != null)
1246  {
1247  handlerPhysicsCrash();
1248  }
1249  }
1250 
1251  protected internal UUID ConvertLocalIDToFullID(uint localID)
1252  {
1253  SceneObjectGroup group = GetGroupByPrim(localID);
1254  if (group != null)
1255  return group.GetPartsFullID(localID);
1256  else
1257  return UUID.Zero;
1258  }
1259 
1264  protected internal void ForEachSOG(Action<SceneObjectGroup> action)
1265  {
1266  foreach (SceneObjectGroup obj in GetSceneObjectGroups())
1267  {
1268  try
1269  {
1270  action(obj);
1271  }
1272  catch (Exception e)
1273  {
1274  // Catch it and move on. This includes situations where objlist has inconsistent info
1275  m_log.WarnFormat(
1276  "[SCENEGRAPH]: Problem processing action in ForEachSOG: {0} {1}", e.Message, e.StackTrace);
1277  }
1278  }
1279  }
1280 
1286  public void ForEachAvatar(Action<ScenePresence> action)
1287  {
1288  ForEachScenePresence(delegate(ScenePresence sp)
1289  {
1290  if (!sp.IsChildAgent)
1291  action(sp);
1292  });
1293  }
1294 
1301  public void ForEachScenePresence(Action<ScenePresence> action)
1302  {
1303  // Once all callers have their delegates configured for parallelism, we can unleash this
1304  /*
1305  Action<ScenePresence> protectedAction = new Action<ScenePresence>(delegate(ScenePresence sp)
1306  {
1307  try
1308  {
1309  action(sp);
1310  }
1311  catch (Exception e)
1312  {
1313  m_log.Info("[SCENEGRAPH]: Error in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1314  m_log.Info("[SCENEGRAPH]: Stack Trace: " + e.StackTrace);
1315  }
1316  });
1317  Parallel.ForEach<ScenePresence>(GetScenePresences(), protectedAction);
1318  */
1319  // For now, perform actions serially
1320  List<ScenePresence> presences = GetScenePresences();
1321  foreach (ScenePresence sp in presences)
1322  {
1323  try
1324  {
1325  action(sp);
1326  }
1327  catch (Exception e)
1328  {
1329  m_log.Error("[SCENEGRAPH]: Error in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1330  }
1331  }
1332  }
1333 
1334  #endregion
1335 
1336  #region Client Event handlers
1337 
1338  protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient)
1339  {
1340  SceneObjectPart part = GetSceneObjectPart(localID);
1341  ObjectChangeData data = (ObjectChangeData)odata;
1342 
1343  if (part != null)
1344  {
1345  SceneObjectGroup grp = part.ParentGroup;
1346  if (grp != null)
1347  {
1348  if (m_parentScene.Permissions.CanEditObject(grp.UUID, remoteClient.AgentId))
1349  {
1350  // These two are exceptions SL makes in the interpretation
1351  // of the change flags. Must check them here because otherwise
1352  // the group flag (see below) would be lost
1353  if (data.change == ObjectChangeType.groupS)
1354  data.change = ObjectChangeType.primS;
1355  if (data.change == ObjectChangeType.groupPS)
1356  data.change = ObjectChangeType.primPS;
1357  part.StoreUndoState(data.change); // lets test only saving what we changed
1358  grp.doChangeObject(part, (ObjectChangeData)data);
1359  }
1360  else
1361  {
1362  // Is this any kind of group operation?
1363  if ((data.change & ObjectChangeType.Group) != 0)
1364  {
1365  // Is a move and/or rotation requested?
1366  if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0)
1367  {
1368  // Are we allowed to move it?
1369  if (m_parentScene.Permissions.CanMoveObject(grp.UUID, remoteClient.AgentId))
1370  {
1371  // Strip all but move and rotation from request
1372  data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation);
1373 
1374  part.StoreUndoState(data.change);
1375  grp.doChangeObject(part, (ObjectChangeData)data);
1376  }
1377  }
1378  }
1379  }
1380  }
1381  }
1382  }
1383 
1390  protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1391  {
1392  SceneObjectPart part = GetSceneObjectPart(localID);
1393 
1394  if (part != null)
1395  {
1396  if (m_parentScene.Permissions.CanEditObject(part.ParentGroup.UUID, remoteClient.AgentId))
1397  {
1398  bool physbuild = false;
1399  if (part.ParentGroup.RootPart.PhysActor != null)
1400  {
1401  part.ParentGroup.RootPart.PhysActor.Building = true;
1402  physbuild = true;
1403  }
1404 
1405  part.Resize(scale);
1406 
1407  if (physbuild)
1408  part.ParentGroup.RootPart.PhysActor.Building = false;
1409  }
1410  }
1411  }
1412 
1413  protected internal void UpdatePrimGroupScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1414  {
1415  SceneObjectGroup group = GetGroupByPrim(localID);
1416  if (group != null)
1417  {
1418  if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1419  {
1420  bool physbuild = false;
1421  if (group.RootPart.PhysActor != null)
1422  {
1423  group.RootPart.PhysActor.Building = true;
1424  physbuild = true;
1425  }
1426 
1427  group.GroupResize(scale);
1428 
1429  if (physbuild)
1430  group.RootPart.PhysActor.Building = false;
1431  }
1432  }
1433  }
1434 
1443  protected internal void RequestObjectPropertiesFamily(
1444  IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
1445  {
1446  SceneObjectGroup group = GetGroupByPrim(ObjectID);
1447  if (group != null)
1448  {
1449  group.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
1450  }
1451  }
1452 
1459  protected internal void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1460  {
1461  SceneObjectGroup group = GetGroupByPrim(localID);
1462  if (group != null)
1463  {
1464  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1465  {
1466  group.UpdateSingleRotation(rot, localID);
1467  }
1468  }
1469  }
1470 
1477  protected internal void UpdatePrimSingleRotationPosition(uint localID, Quaternion rot, Vector3 pos, IClientAPI remoteClient)
1478  {
1479  SceneObjectGroup group = GetGroupByPrim(localID);
1480  if (group != null)
1481  {
1482  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1483  {
1484  group.UpdateSingleRotation(rot, pos, localID);
1485  }
1486  }
1487  }
1488 
1495  protected internal void UpdatePrimGroupRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1496  {
1497  SceneObjectGroup group = GetGroupByPrim(localID);
1498  if (group != null)
1499  {
1500  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1501  {
1502  group.UpdateGroupRotationR(rot);
1503  }
1504  }
1505  }
1506 
1514  protected internal void UpdatePrimGroupRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
1515  {
1516  SceneObjectGroup group = GetGroupByPrim(localID);
1517  if (group != null)
1518  {
1519  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1520  {
1521  group.UpdateGroupRotationPR(pos, rot);
1522  }
1523  }
1524  }
1525 
1532  protected internal void UpdatePrimSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1533  {
1534  SceneObjectGroup group = GetGroupByPrim(localID);
1535  if (group != null)
1536  {
1537  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment)
1538  {
1539  group.UpdateSinglePosition(pos, localID);
1540  }
1541  }
1542  }
1543 
1550  public void UpdatePrimGroupPosition(uint localId, Vector3 pos, IClientAPI remoteClient)
1551  {
1552  UpdatePrimGroupPosition(localId, pos, remoteClient.AgentId);
1553  }
1554 
1561  public void UpdatePrimGroupPosition(uint localId, Vector3 pos, UUID updatingAgentId)
1562  {
1563  SceneObjectGroup group = GetGroupByPrim(localId);
1564 
1565  if (group != null)
1566  {
1567  if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1568  {
1569  // Set the new attachment point data in the object
1570  byte attachmentPoint = group.GetAttachmentPoint();
1571  group.UpdateGroupPosition(pos);
1572  group.IsAttachment = false;
1573  group.AbsolutePosition = group.RootPart.AttachedPos;
1574  group.AttachmentPoint = attachmentPoint;
1575  group.HasGroupChanged = true;
1576  }
1577  else
1578  {
1579  if (m_parentScene.Permissions.CanMoveObject(group.UUID, updatingAgentId)
1580  && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1581  {
1582  group.UpdateGroupPosition(pos);
1583  }
1584  }
1585  }
1586  }
1587 
1598  protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
1599  {
1600  SceneObjectGroup group = GetGroupByPrim(localID);
1601 
1602  if (group != null)
1603  {
1604  if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId))
1605  {
1606  group.UpdateTextureEntry(localID, texture);
1607  }
1608  }
1609  }
1610 
1622  protected internal void UpdatePrimFlags(
1623  uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
1624  {
1625  SceneObjectGroup group = GetGroupByPrim(localID);
1626  if (group != null)
1627  {
1628  if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1629  {
1630  // VolumeDetect can't be set via UI and will always be off when a change is made there
1631  // now only change volume dtc if phantom off
1632 
1633  bool wantedPhys = UsePhysics;
1634  if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
1635  {
1636  bool vdtc;
1637  if (SetPhantom) // if phantom keep volumedtc
1638  vdtc = group.RootPart.VolumeDetectActive;
1639  else // else turn it off
1640  vdtc = false;
1641 
1642  group.UpdatePrimFlags(localID, UsePhysics, SetTemporary, SetPhantom, vdtc);
1643  }
1644  else
1645  {
1646  SceneObjectPart part = GetSceneObjectPart(localID);
1647  if (part != null)
1648  {
1649  part.UpdateExtraPhysics(PhysData);
1650  if (part.UpdatePhysRequired && remoteClient != null)
1651  remoteClient.SendPartPhysicsProprieties(part);
1652  }
1653  }
1654 
1655  if (wantedPhys != group.UsesPhysics && remoteClient != null)
1656  {
1657  remoteClient.SendAlertMessage("Object physics canceled because exceeds the limit of " +
1658  m_parentScene.m_linksetPhysCapacity + " physical prims with shape type not set to None");
1659  group.RootPart.ScheduleFullUpdate();
1660  }
1661  }
1662  }
1663  }
1664 
1672  protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
1673  {
1674  SceneObjectGroup group = GetGroupByPrim(objectID);
1675  if (group != null)
1676  {
1677  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1678  {
1679  group.GrabMovement(objectID, offset, pos, remoteClient);
1680  }
1681 
1682  // This is outside the above permissions condition
1683  // so that if the object is locked the client moving the object
1684  // get's it's position on the simulator even if it was the same as before
1685  // This keeps the moving user's client in sync with the rest of the world.
1686  group.SendGroupTerseUpdate();
1687  }
1688  }
1689 
1696  protected internal void SpinStart(UUID objectID, IClientAPI remoteClient)
1697  {
1698  SceneObjectGroup group = GetGroupByPrim(objectID);
1699  if (group != null)
1700  {
1701  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1702  {
1703  group.SpinStart(remoteClient);
1704  }
1705  }
1706  }
1707 
1714  protected internal void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient)
1715  {
1716  SceneObjectGroup group = GetGroupByPrim(objectID);
1717  if (group != null)
1718  {
1719  if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1720  {
1721  group.SpinMovement(rotation, remoteClient);
1722  }
1723  // This is outside the above permissions condition
1724  // so that if the object is locked the client moving the object
1725  // get's it's position on the simulator even if it was the same as before
1726  // This keeps the moving user's client in sync with the rest of the world.
1727  group.SendGroupTerseUpdate();
1728  }
1729  }
1730 
1736  protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
1737  {
1738  SceneObjectGroup group = GetGroupByPrim(primLocalID);
1739  if (group != null)
1740  {
1741  if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1742  {
1743  group.SetPartName(Util.CleanString(name), primLocalID);
1744  group.HasGroupChanged = true;
1745  }
1746  }
1747  }
1748 
1754  protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
1755  {
1756  SceneObjectGroup group = GetGroupByPrim(primLocalID);
1757  if (group != null)
1758  {
1759  if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1760  {
1761  group.SetPartDescription(Util.CleanString(description), primLocalID);
1762  group.HasGroupChanged = true;
1763  }
1764  }
1765  }
1766 
1773  protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
1774  {
1775 // m_log.DebugFormat(
1776 // "[SCENEGRAPH]: User {0} set click action for {1} to {2}", remoteClient.Name, primLocalID, clickAction);
1777 
1778  SceneObjectGroup group = GetGroupByPrim(primLocalID);
1779  if (group != null)
1780  {
1781  if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1782  {
1783  SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1784  if (part != null)
1785  {
1786  part.ClickAction = Convert.ToByte(clickAction);
1787  group.HasGroupChanged = true;
1788  }
1789  }
1790  }
1791  }
1792 
1793  protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
1794  {
1795  SceneObjectGroup group = GetGroupByPrim(primLocalID);
1796  if (group != null)
1797  {
1798  if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1799  {
1800  SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1801  if (part != null)
1802  {
1803  part.Material = Convert.ToByte(material);
1804  group.HasGroupChanged = true;
1805  remoteClient.SendPartPhysicsProprieties(part);
1806  }
1807  }
1808  }
1809  }
1810 
1811  protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
1812  {
1813  SceneObjectGroup group = GetGroupByPrim(primLocalID);
1814 
1815  if (group != null)
1816  {
1817  if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
1818  {
1819  group.UpdateExtraParam(primLocalID, type, inUse, data);
1820  }
1821  }
1822  }
1823 
1829  protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
1830  {
1831  SceneObjectGroup group = GetGroupByPrim(primLocalID);
1832  if (group != null)
1833  {
1834  if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
1835  {
1836  ObjectShapePacket.ObjectDataBlock shapeData = new ObjectShapePacket.ObjectDataBlock();
1837  shapeData.ObjectLocalID = shapeBlock.ObjectLocalID;
1838  shapeData.PathBegin = shapeBlock.PathBegin;
1839  shapeData.PathCurve = shapeBlock.PathCurve;
1840  shapeData.PathEnd = shapeBlock.PathEnd;
1841  shapeData.PathRadiusOffset = shapeBlock.PathRadiusOffset;
1842  shapeData.PathRevolutions = shapeBlock.PathRevolutions;
1843  shapeData.PathScaleX = shapeBlock.PathScaleX;
1844  shapeData.PathScaleY = shapeBlock.PathScaleY;
1845  shapeData.PathShearX = shapeBlock.PathShearX;
1846  shapeData.PathShearY = shapeBlock.PathShearY;
1847  shapeData.PathSkew = shapeBlock.PathSkew;
1848  shapeData.PathTaperX = shapeBlock.PathTaperX;
1849  shapeData.PathTaperY = shapeBlock.PathTaperY;
1850  shapeData.PathTwist = shapeBlock.PathTwist;
1851  shapeData.PathTwistBegin = shapeBlock.PathTwistBegin;
1852  shapeData.ProfileBegin = shapeBlock.ProfileBegin;
1853  shapeData.ProfileCurve = shapeBlock.ProfileCurve;
1854  shapeData.ProfileEnd = shapeBlock.ProfileEnd;
1855  shapeData.ProfileHollow = shapeBlock.ProfileHollow;
1856 
1857  group.UpdateShape(shapeData, primLocalID);
1858  }
1859  }
1860  }
1861 
1868  protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
1869  {
1870  if (root.KeyframeMotion != null)
1871  {
1872  root.KeyframeMotion.Stop();
1873  root.KeyframeMotion = null;
1874  }
1875 
1876  SceneObjectGroup parentGroup = root.ParentGroup;
1877  if (parentGroup == null) return;
1878 
1879  // Cowardly refuse to link to a group owned root
1880  if (parentGroup.OwnerID == parentGroup.GroupID)
1881  return;
1882 
1883  Monitor.Enter(m_updateLock);
1884 
1885  try
1886  {
1887 
1888  List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
1889 
1890  // We do this in reverse to get the link order of the prims correct
1891  for (int i = 0; i < children.Count; i++)
1892  {
1893  SceneObjectGroup child = children[i].ParentGroup;
1894 
1895  // Don't try and add a group to itself - this will only cause severe problems later on.
1896  if (child == parentGroup)
1897  continue;
1898 
1899  // Make sure no child prim is set for sale
1900  // So that, on delink, no prims are unwittingly
1901  // left for sale and sold off
1902 
1903  if (child != null)
1904  {
1905  child.RootPart.ObjectSaleType = 0;
1906  child.RootPart.SalePrice = 10;
1907  childGroups.Add(child);
1908  }
1909  }
1910 
1911  foreach (SceneObjectGroup child in childGroups)
1912  {
1913  if (parentGroup.OwnerID == child.OwnerID)
1914  {
1915  parentGroup.LinkToGroup(child);
1916 
1917  child.DetachFromBackup();
1918 
1919  // this is here so physics gets updated!
1920  // Don't remove! Bad juju! Stay away! or fix physics!
1921  child.AbsolutePosition = child.AbsolutePosition;
1922  }
1923  }
1924 
1925  // We need to explicitly resend the newly link prim's object properties since no other actions
1926  // occur on link to invoke this elsewhere (such as object selection)
1927  if (childGroups.Count > 0)
1928  {
1929  parentGroup.RootPart.CreateSelected = true;
1930  parentGroup.TriggerScriptChangedEvent(Changed.LINK);
1931  parentGroup.HasGroupChanged = true;
1932  parentGroup.ScheduleGroupForFullUpdate();
1933  }
1934  }
1935  finally
1936  {
1937 /*
1938  lock (SceneObjectGroupsByLocalPartID)
1939  {
1940  foreach (SceneObjectPart part in parentGroup.Parts)
1941  SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
1942  }
1943 */
1944  parentGroup.AdjustChildPrimPermissions(false);
1945  parentGroup.HasGroupChanged = true;
1946  parentGroup.ProcessBackup(m_parentScene.SimulationDataService, true);
1947  parentGroup.ScheduleGroupForFullUpdate();
1948  Monitor.Exit(m_updateLock);
1949  }
1950  }
1951 
1956  protected internal void DelinkObjects(List<SceneObjectPart> prims)
1957  {
1958  Monitor.Enter(m_updateLock);
1959  try
1960  {
1961  List<SceneObjectPart> childParts = new List<SceneObjectPart>();
1962  List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
1963  List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
1964  // Look them all up in one go, since that is comparatively expensive
1965  //
1966  foreach (SceneObjectPart part in prims)
1967  {
1968  if (part != null)
1969  {
1970  if (part.KeyframeMotion != null)
1971  {
1972  part.KeyframeMotion.Stop();
1973  part.KeyframeMotion = null;
1974  }
1975  if (part.ParentGroup.PrimCount != 1) // Skip single
1976  {
1977  if (part.LinkNum < 2) // Root
1978  {
1979  rootParts.Add(part);
1980  }
1981  else
1982  {
1983  part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID;
1984  childParts.Add(part);
1985  }
1986 
1987  SceneObjectGroup group = part.ParentGroup;
1988  if (!affectedGroups.Contains(group))
1989  {
1990  affectedGroups.Add(group);
1991  }
1992  }
1993  }
1994  }
1995 
1996  if (childParts.Count > 0)
1997  {
1998  foreach (SceneObjectPart child in childParts)
1999  {
2000  // Unlink all child parts from their groups
2001  //
2002  child.ParentGroup.DelinkFromGroup(child, true);
2003  child.ParentGroup.HasGroupChanged = true;
2004  child.ParentGroup.ScheduleGroupForFullUpdate();
2005  }
2006  }
2007 
2008  foreach (SceneObjectPart root in rootParts)
2009  {
2010  // In most cases, this will run only one time, and the prim
2011  // will be a solo prim
2012  // However, editing linked parts and unlinking may be different
2013  //
2014  SceneObjectGroup group = root.ParentGroup;
2015 
2016  List<SceneObjectPart> newSet = new List<SceneObjectPart>(group.Parts);
2017  int numChildren = newSet.Count;
2018 
2019  if (numChildren == 1)
2020  break;
2021 
2022  // If there are prims left in a link set, but the root is
2023  // slated for unlink, we need to do this
2024  // Unlink the remaining set
2025  //
2026  bool sendEventsToRemainder = false;
2027  if (numChildren == 2) // only one child prim no re-link needed
2028  sendEventsToRemainder = true;
2029 
2030  foreach (SceneObjectPart p in newSet)
2031  {
2032  if (p != group.RootPart)
2033  {
2034  group.DelinkFromGroup(p, sendEventsToRemainder);
2035  if (sendEventsToRemainder) // finish single child prim now
2036  {
2037  p.ParentGroup.HasGroupChanged = true;
2038  p.ParentGroup.ScheduleGroupForFullUpdate();
2039  }
2040  }
2041  }
2042 
2043  // If there is more than one prim remaining, we
2044  // need to re-link
2045  //
2046  if (numChildren > 2)
2047  {
2048  // Remove old root
2049  //
2050  if (newSet.Contains(root))
2051  newSet.Remove(root);
2052 
2053  // Preserve link ordering
2054  //
2055  newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b)
2056  {
2057  return a.LinkNum.CompareTo(b.LinkNum);
2058  });
2059 
2060  // Determine new root
2061  //
2062  SceneObjectPart newRoot = newSet[0];
2063  newSet.RemoveAt(0);
2064 
2065  foreach (SceneObjectPart newChild in newSet)
2066  newChild.ClearUpdateSchedule();
2067 
2068  LinkObjects(newRoot, newSet);
2069 // if (!affectedGroups.Contains(newRoot.ParentGroup))
2070 // affectedGroups.Add(newRoot.ParentGroup);
2071  }
2072  }
2073 
2074  // Finally, trigger events in the roots
2075  //
2076  foreach (SceneObjectGroup g in affectedGroups)
2077  {
2078  // Child prims that have been unlinked and deleted will
2079  // return unless the root is deleted. This will remove them
2080  // from the database. They will be rewritten immediately,
2081  // minus the rows for the unlinked child prims.
2082  g.AdjustChildPrimPermissions(false);
2083  m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
2084  g.TriggerScriptChangedEvent(Changed.LINK);
2085  g.HasGroupChanged = true; // Persist
2086  g.ScheduleGroupForFullUpdate();
2087  }
2088  }
2089  finally
2090  {
2091  Monitor.Exit(m_updateLock);
2092  }
2093  }
2094 
2095  protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
2096  {
2097  UUID user = remoteClient.AgentId;
2098  UUID objid = UUID.Zero;
2099  SceneObjectPart obj = null;
2100 
2101  EntityBase[] entityList = GetEntities();
2102  foreach (EntityBase ent in entityList)
2103  {
2104  if (ent is SceneObjectGroup)
2105  {
2106  SceneObjectGroup sog = ent as SceneObjectGroup;
2107 
2108  foreach (SceneObjectPart part in sog.Parts)
2109  {
2110  if (part.LocalId == localID)
2111  {
2112  objid = part.UUID;
2113  obj = part;
2114  }
2115  }
2116  }
2117  }
2118 
2119  //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
2120  //aka ObjectFlags.JointWheel = IncludeInSearch
2121 
2122  //Permissions model: Object can be REMOVED from search IFF:
2123  // * User owns object
2124  //use CanEditObject
2125 
2126  //Object can be ADDED to search IFF:
2127  // * User owns object
2128  // * Asset/DRM permission bit "modify" is enabled
2129  //use CanEditObjectPosition
2130 
2131  // libomv will complain about PrimFlags.JointWheel being
2132  // deprecated, so we
2133  #pragma warning disable 0612
2134  if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user))
2135  {
2136  obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel);
2137  obj.ParentGroup.HasGroupChanged = true;
2138  }
2139  else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user))
2140  {
2141  obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel);
2142  obj.ParentGroup.HasGroupChanged = true;
2143  }
2144  #pragma warning restore 0612
2145  }
2146 
2158  public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
2159  {
2160 // m_log.DebugFormat(
2161 // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2162 // originalPrimID, offset, AgentID);
2163 
2164  SceneObjectGroup original = GetGroupByPrim(originalPrimID);
2165  if (original != null)
2166  {
2167  if (m_parentScene.Permissions.CanDuplicateObject(
2168  original.PrimCount, original.UUID, AgentID, original.AbsolutePosition))
2169  {
2170  SceneObjectGroup copy = original.Copy(true);
2171  copy.AbsolutePosition = copy.AbsolutePosition + offset;
2172 
2173  if (original.OwnerID != AgentID)
2174  {
2175  copy.SetOwnerId(AgentID);
2176  copy.SetRootPartOwner(copy.RootPart, AgentID, GroupID);
2177 
2178  SceneObjectPart[] partList = copy.Parts;
2179 
2180  if (m_parentScene.Permissions.PropagatePermissions())
2181  {
2182  foreach (SceneObjectPart child in partList)
2183  {
2184  child.Inventory.ChangeInventoryOwner(AgentID);
2185  child.TriggerScriptChangedEvent(Changed.OWNER);
2186  child.ApplyNextOwnerPermissions();
2187  }
2188  }
2189  }
2190 
2191  // FIXME: This section needs to be refactored so that it just calls AddSceneObject()
2192  Entities.Add(copy);
2193 
2194  lock (SceneObjectGroupsByFullID)
2195  SceneObjectGroupsByFullID[copy.UUID] = copy;
2196 
2197  SceneObjectPart[] parts = copy.Parts;
2198  foreach (SceneObjectPart part in parts)
2199  {
2200  lock (SceneObjectGroupsByFullPartID)
2201  SceneObjectGroupsByFullPartID[part.UUID] = copy;
2202  lock (SceneObjectGroupsByLocalPartID)
2203  SceneObjectGroupsByLocalPartID[part.LocalId] = copy;
2204  }
2205 
2206  // PROBABLE END OF FIXME
2207 
2208  // Since we copy from a source group that is in selected
2209  // state, but the copy is shown deselected in the viewer,
2210  // We need to clear the selection flag here, else that
2211  // prim never gets persisted at all. The client doesn't
2212  // think it's selected, so it will never send a deselect...
2213  copy.IsSelected = false;
2214 
2215  m_numPrim += copy.Parts.Length;
2216 
2217  if (rot != Quaternion.Identity)
2218  {
2219  copy.UpdateGroupRotationR(rot);
2220  }
2221 
2222  copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
2223  copy.HasGroupChanged = true;
2224  copy.ScheduleGroupForFullUpdate();
2225  copy.ResumeScripts();
2226 
2227  // required for physics to update it's position
2228  copy.AbsolutePosition = copy.AbsolutePosition;
2229 
2230  return copy;
2231  }
2232  }
2233  else
2234  {
2235  m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
2236  }
2237 
2238  return null;
2239  }
2240 
2246  protected internal float Vector3Distance(Vector3 v1, Vector3 v2)
2247  {
2248  // We don't really need the double floating point precision...
2249  // so casting it to a single
2250 
2251  return
2252  (float)
2253  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));
2254  }
2255 
2256  #endregion
2257 
2258 
2259  }
2260 }
void updateScenePartGroup(SceneObjectPart part, SceneObjectGroup grp)
Definition: SceneGraph.cs:504
Vector3 GroupPosition
The position of the entire group that this prim belongs to.
delegate void UpdatePrimSingleRotationPosition(uint localID, Quaternion rot, Vector3 pos, IClientAPI remoteClient)
delegate void UpdatePrimGroupRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
delegate void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
PrimType GetPrimType()
Tell us what type this prim is
delegate void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
Contains the Avatar's Appearance and methods to manipulate the appearance.
delegate void ClientChangeObject(uint localID, object data, IClientAPI remoteClient)
delegate void DelinkObjects(List< uint > primIds, IClientAPI client)
SceneObjectGroup GetGroupByPrim(uint localID)
Get a scene object group that contains the prim with the given local id
Definition: SceneGraph.cs:973
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
Add an object to the scene. This will both update the scene, and send information about the new objec...
Definition: SceneGraph.cs:419
PrimFlags Flags
Property flags. See OpenMetaverse.PrimFlags
bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked)
Delete an object from the scene
Definition: SceneGraph.cs:518
delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
void GetCoarseLocations(out List< Vector3 > coarseLocations, out List< UUID > avatarUUIDs, uint maxLocations)
Definition: SceneGraph.cs:239
AttachToBackupDelegate OnAttachToBackup
Definition: SceneGraph.cs:63
PresenceType
Indicate the type of ScenePresence.
Definition: PresenceType.cs:34
SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
Duplicate the given object.
Definition: SceneGraph.cs:2158
int PrimCount
Number of prims in this group
IClientAPI GetControllingClient(UUID agentId)
Get the controlling client for the given avatar, if there is one.
Definition: SceneGraph.cs:878
delegate void AttachToBackupDelegate(SceneObjectGroup sog)
void FireDetachFromBackup(SceneObjectGroup obj)
Definition: SceneGraph.cs:593
delegate void MoveObject(UUID objectID, Vector3 offset, Vector3 grapPos, IClientAPI remoteClient, List< SurfaceTouchEventArgs > surfaceArgs)
void FireChangeBackup(SceneObjectGroup obj)
Definition: SceneGraph.cs:601
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
void UpdatePrimGroupPosition(uint localId, Vector3 pos, UUID updatingAgentId)
Update the position of the given group.
Definition: SceneGraph.cs:1561
delegate void LinkObjects(IClientAPI remoteClient, uint parent, List< uint > children)
delegate void ChangedBackupDelegate(SceneObjectGroup sog)
delegate void SpinStart(UUID objectID, IClientAPI remoteClient)
delegate void SpinObject(UUID objectID, Quaternion rotation, IClientAPI remoteClient)
DetachFromBackupDelegate OnDetachFromBackup
Definition: SceneGraph.cs:64
void ForEachAvatar(Action< ScenePresence > action)
Performs action on all ROOT (not child) scene presences. This is just a shortcut function since frequ...
Definition: SceneGraph.cs:1286
override Vector3 AbsolutePosition
The absolute position of this scene object in the scene
void UpdatePrimGroupPosition(uint localId, Vector3 pos, IClientAPI remoteClient)
Update the position of the given group.
Definition: SceneGraph.cs:1550
void ForEachScenePresence(Action< ScenePresence > action)
Performs action on all scene presences. This can ultimately run the actions in parallel but any deleg...
Definition: SceneGraph.cs:1301
delegate void RequestObjectPropertiesFamily(IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID TaskID)
bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, Vector3?pos, Quaternion?rot, Vector3 vel)
Add a newly created object to the scene.
Definition: SceneGraph.cs:375
This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph co...
Definition: SceneGraph.cs:54
delegate void DetachFromBackupDelegate(SceneObjectGroup sog)
SceneObjectGroup GetGroupByPrim(UUID fullID)
Get a scene object group that contains the prim with the given uuid
Definition: SceneGraph.cs:1032
bool IsAttachment
Is this scene object acting as an attachment?