aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Scenes/SceneGraph.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Scenes/SceneGraph.cs')
-rw-r--r--OpenSim/Region/Environment/Scenes/SceneGraph.cs1811
1 files changed, 0 insertions, 1811 deletions
diff --git a/OpenSim/Region/Environment/Scenes/SceneGraph.cs b/OpenSim/Region/Environment/Scenes/SceneGraph.cs
deleted file mode 100644
index 24eaad1..0000000
--- a/OpenSim/Region/Environment/Scenes/SceneGraph.cs
+++ /dev/null
@@ -1,1811 +0,0 @@
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 OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Region.Environment.Types;
36using OpenSim.Region.Physics.Manager;
37
38namespace OpenSim.Region.Environment.Scenes
39{
40 public delegate void PhysicsCrash();
41
42 public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone);
43
44 public delegate void ObjectCreateDelegate(EntityBase obj);
45
46 public delegate void ObjectDeleteDelegate(EntityBase obj);
47
48 /// <summary>
49 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
50 /// should be migrated out over time.
51 /// </summary>
52 public class SceneGraph
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 #region Events
57
58 protected internal event PhysicsCrash UnRecoverableError;
59 private PhysicsCrash handlerPhysicsCrash = null;
60
61 public event ObjectDuplicateDelegate OnObjectDuplicate;
62 public event ObjectCreateDelegate OnObjectCreate;
63 public event ObjectDeleteDelegate OnObjectRemove;
64
65 #endregion
66
67 #region Fields
68
69 protected internal Dictionary<UUID, ScenePresence> ScenePresences = new Dictionary<UUID, ScenePresence>();
70 // SceneObjects is not currently populated or used.
71 //public Dictionary<UUID, SceneObjectGroup> SceneObjects;
72 protected internal EntityManager Entities = new EntityManager();
73// protected internal Dictionary<UUID, EntityBase> Entities = new Dictionary<UUID, EntityBase>();
74 protected internal Dictionary<UUID, ScenePresence> RestorePresences = new Dictionary<UUID, ScenePresence>();
75
76 protected internal BasicQuadTreeNode QuadTree;
77
78 protected RegionInfo m_regInfo;
79 protected Scene m_parentScene;
80 protected List<EntityBase> m_updateList = new List<EntityBase>();
81 protected int m_numRootAgents = 0;
82 protected int m_numPrim = 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 object m_syncRoot = new object();
90
91 protected internal PhysicsScene _PhyScene;
92
93 #endregion
94
95 protected internal SceneGraph(Scene parent, RegionInfo regInfo)
96 {
97 m_parentScene = parent;
98 m_regInfo = regInfo;
99 QuadTree = new BasicQuadTreeNode(null, "/0/", 0, 0, (short)Constants.RegionSize, (short)Constants.RegionSize);
100 QuadTree.Subdivide();
101 QuadTree.Subdivide();
102 }
103
104 public PhysicsScene PhysicsScene
105 {
106 get { return _PhyScene; }
107 set
108 {
109 // If we're not doing the initial set
110 // Then we've got to remove the previous
111 // event handler
112
113 if (_PhyScene != null)
114 _PhyScene.OnPhysicsCrash -= physicsBasedCrash;
115
116 _PhyScene = value;
117
118 if (_PhyScene != null)
119 _PhyScene.OnPhysicsCrash += physicsBasedCrash;
120 }
121 }
122
123 protected internal void Close()
124 {
125 lock (ScenePresences)
126 {
127 ScenePresences.Clear();
128 }
129
130 Entities.Clear();
131 }
132
133 #region Update Methods
134
135 protected internal void UpdatePreparePhysics()
136 {
137 // If we are using a threaded physics engine
138 // grab the latest scene from the engine before
139 // trying to process it.
140
141 // PhysX does this (runs in the background).
142
143 if (_PhyScene.IsThreaded)
144 {
145 _PhyScene.GetResults();
146 }
147 }
148
149 protected internal void UpdateEntities()
150 {
151 List<EntityBase> updateEntities = GetEntities();
152
153 foreach (EntityBase entity in updateEntities)
154 {
155 entity.Update();
156 }
157 }
158
159 protected internal void UpdatePresences()
160 {
161 List<ScenePresence> updateScenePresences = GetScenePresences();
162 foreach (ScenePresence pres in updateScenePresences)
163 {
164 pres.Update();
165 }
166 }
167
168 protected internal float UpdatePhysics(double elapsed)
169 {
170 lock (m_syncRoot)
171 {
172 // Here is where the Scene calls the PhysicsScene. This is a one-way
173 // interaction; the PhysicsScene cannot access the calling Scene directly.
174 // But with joints, we want a PhysicsActor to be able to influence a
175 // non-physics SceneObjectPart. In particular, a PhysicsActor that is connected
176 // with a joint should be able to move the SceneObjectPart which is the visual
177 // representation of that joint (for editing and serialization purposes).
178 // However the PhysicsActor normally cannot directly influence anything outside
179 // of the PhysicsScene, and the non-physical SceneObjectPart which represents
180 // the joint in the Scene does not exist in the PhysicsScene.
181 //
182 // To solve this, we have an event in the PhysicsScene that is fired when a joint
183 // has changed position (because one of its associated PhysicsActors has changed
184 // position).
185 //
186 // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate().
187
188 return _PhyScene.Simulate((float)elapsed);
189 }
190 }
191
192 protected internal void UpdateEntityMovement()
193 {
194 List<EntityBase> moveEntities = GetEntities();
195
196 foreach (EntityBase entity in moveEntities)
197 {
198 //cfk. This throws occaisional exceptions on a heavily used region
199 //and I added this null check to try to preclude the exception.
200 if (entity != null)
201 entity.UpdateMovement();
202 }
203 }
204
205 #endregion
206
207 #region Entity Methods
208
209 /// <summary>
210 /// Add an object into the scene that has come from storage
211 /// </summary>
212 /// <param name="sceneObject"></param>
213 /// <param name="attachToBackup">
214 /// If true, changes to the object will be reflected in its persisted data
215 /// If false, the persisted data will not be changed even if the object in the scene is changed
216 /// </param>
217 /// <param name="alreadyPersisted">
218 /// If true, we won't persist this object until it changes
219 /// If false, we'll persist this object immediately
220 /// </param>
221 /// <returns>
222 /// true if the object was added, false if an object with the same uuid was already in the scene
223 /// </returns>
224 protected internal bool AddRestoredSceneObject(
225 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted)
226 {
227 if (!alreadyPersisted)
228 {
229 sceneObject.ForceInventoryPersistence();
230 sceneObject.HasGroupChanged = true;
231 }
232
233 return AddSceneObject(sceneObject, attachToBackup);
234 }
235
236 /// <summary>
237 /// Add a newly created object to the scene. This will both update the scene, and send information about the
238 /// new object to all clients interested in the scene.
239 /// </summary>
240 /// <param name="sceneObject"></param>
241 /// <param name="attachToBackup">
242 /// If true, the object is made persistent into the scene.
243 /// If false, the object will not persist over server restarts
244 /// </param>
245 /// <returns>
246 /// true if the object was added, false if an object with the same uuid was already in the scene
247 /// </returns>
248 protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
249 {
250 // Ensure that we persist this new scene object
251 sceneObject.HasGroupChanged = true;
252
253 return AddSceneObject(sceneObject, attachToBackup);
254 }
255
256 /// <summary>
257 /// Add an object to the scene. This will both update the scene, and send information about the
258 /// new object to all clients interested in the scene.
259 /// </summary>
260 /// <param name="sceneObject"></param>
261 /// <param name="attachToBackup">
262 /// If true, the object is made persistent into the scene.
263 /// If false, the object will not persist over server restarts
264 /// </param>
265 /// <returns>true if the object was added, false if an object with the same uuid was already in the scene
266 /// </returns>
267 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
268 {
269 if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero)
270 return false;
271
272 if (m_parentScene.m_clampPrimSize)
273 {
274 foreach (SceneObjectPart part in sceneObject.Children.Values)
275 {
276 Vector3 scale = part.Shape.Scale;
277
278 if (scale.X > m_parentScene.m_maxNonphys)
279 scale.X = m_parentScene.m_maxNonphys;
280 if (scale.Y > m_parentScene.m_maxNonphys)
281 scale.Y = m_parentScene.m_maxNonphys;
282 if (scale.Z > m_parentScene.m_maxNonphys)
283 scale.Z = m_parentScene.m_maxNonphys;
284
285 part.Shape.Scale = scale;
286 }
287 }
288
289 sceneObject.AttachToScene(m_parentScene);
290
291 lock (sceneObject)
292 {
293 if (!Entities.ContainsKey(sceneObject.UUID))
294 {
295 Entities.Add(sceneObject);
296 m_numPrim += sceneObject.Children.Count;
297
298 if (attachToBackup)
299 sceneObject.AttachToBackup();
300
301 if (OnObjectCreate != null)
302 OnObjectCreate(sceneObject);
303
304 return true;
305 }
306 }
307
308 return false;
309 }
310
311 /// <summary>
312 /// Delete an object from the scene
313 /// </summary>
314 /// <returns>true if the object was deleted, false if there was no object to delete</returns>
315 protected internal bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked)
316 {
317 if (Entities.ContainsKey(uuid))
318 {
319 if (!resultOfObjectLinked)
320 {
321 m_numPrim -= ((SceneObjectGroup) Entities[uuid]).Children.Count;
322
323 if ((((SceneObjectGroup)Entities[uuid]).RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
324 {
325 RemovePhysicalPrim(((SceneObjectGroup)Entities[uuid]).Children.Count);
326 }
327 }
328
329 if (OnObjectRemove != null)
330 OnObjectRemove(Entities[uuid]);
331
332 Entities.Remove(uuid);
333 //SceneObjectGroup part;
334 //((part.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
335
336 return true;
337 }
338
339 return false;
340 }
341
342 /// <summary>
343 /// Add an entity to the list of prims to process on the next update
344 /// </summary>
345 /// <param name="obj">
346 /// A <see cref="EntityBase"/>
347 /// </param>
348 protected internal void AddToUpdateList(EntityBase obj)
349 {
350 lock (m_updateList)
351 {
352 if (!m_updateList.Contains(obj))
353 {
354 m_updateList.Add(obj);
355 }
356 }
357 }
358
359 /// <summary>
360 /// Process all pending updates
361 /// </summary>
362 protected internal void ProcessUpdates()
363 {
364 lock (m_updateList)
365 {
366 for (int i = 0; i < m_updateList.Count; i++)
367 {
368 EntityBase entity = m_updateList[i];
369
370 // Don't abort the whole update if one entity happens to give us an exception.
371 try
372 {
373 m_updateList[i].Update();
374 }
375 catch (Exception e)
376 {
377 m_log.ErrorFormat(
378 "[INNER SCENE]: Failed to update {0}, {1} - {2}", entity.Name, entity.UUID, e);
379 }
380 }
381
382 m_updateList.Clear();
383 }
384 }
385
386 protected internal void AddPhysicalPrim(int number)
387 {
388 m_physicalPrim++;
389 }
390
391 protected internal void RemovePhysicalPrim(int number)
392 {
393 m_physicalPrim--;
394 }
395
396 protected internal void AddToScriptLPS(int number)
397 {
398 m_scriptLPS += number;
399 }
400
401 protected internal void AddActiveScripts(int number)
402 {
403 m_activeScripts += number;
404 }
405
406 protected internal void DropObject(uint objectLocalID, IClientAPI remoteClient)
407 {
408 List<EntityBase> EntityList = GetEntities();
409
410 foreach (EntityBase obj in EntityList)
411 {
412 if (obj is SceneObjectGroup)
413 {
414 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
415 {
416 SceneObjectGroup group = (SceneObjectGroup)obj;
417
418 m_parentScene.DetachSingleAttachmentToGround(group.UUID,remoteClient);
419 }
420 }
421 }
422 }
423
424 protected internal void DetachObject(uint objectLocalID, IClientAPI remoteClient)
425 {
426 List<EntityBase> EntityList = GetEntities();
427
428 foreach (EntityBase obj in EntityList)
429 {
430 if (obj is SceneObjectGroup)
431 {
432 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
433 {
434 SceneObjectGroup group = (SceneObjectGroup)obj;
435
436 //group.DetachToGround();
437 m_parentScene.DetachSingleAttachmentToInv(group.GetFromAssetID(),remoteClient);
438 }
439 }
440 }
441 }
442
443 protected internal void HandleUndo(IClientAPI remoteClient, UUID primId)
444 {
445 if (primId != UUID.Zero)
446 {
447 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
448 if (part != null)
449 part.Undo();
450 }
451 }
452
453 protected internal void HandleObjectGroupUpdate(
454 IClientAPI remoteClient, UUID GroupID, uint objectLocalID, UUID Garbage)
455 {
456 List<EntityBase> EntityList = GetEntities();
457
458 foreach (EntityBase obj in EntityList)
459 {
460 if (obj is SceneObjectGroup)
461 {
462 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
463 {
464 SceneObjectGroup group = (SceneObjectGroup)obj;
465
466 if (group.OwnerID == remoteClient.AgentId)
467 group.SetGroup(GroupID, remoteClient);
468 }
469 }
470 }
471 }
472
473 /// <summary>
474 /// Event Handling routine for Attach Object
475 /// </summary>
476 /// <param name="remoteClient"></param>
477 /// <param name="objectLocalID"></param>
478 /// <param name="AttachmentPt"></param>
479 /// <param name="rot"></param>
480 protected internal void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent)
481 {
482 // If we can't take it, we can't attach it!
483 //
484 SceneObjectPart part = m_parentScene.GetSceneObjectPart(objectLocalID);
485 if (part == null)
486 return;
487
488 if (!m_parentScene.Permissions.CanTakeObject(
489 part.UUID, remoteClient.AgentId))
490 return;
491
492 // Calls attach with a Zero position
493 //
494 AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false);
495 }
496
497 public SceneObjectGroup RezSingleAttachment(
498 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
499 {
500 SceneObjectGroup objatt = m_parentScene.RezObject(remoteClient,
501 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
502 false, false, remoteClient.AgentId, true);
503
504
505 if (objatt != null)
506 {
507 bool tainted = false;
508 if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint())
509 tainted = true;
510
511 AttachObject(remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false);
512 objatt.ScheduleGroupForFullUpdate();
513 if (tainted)
514 objatt.HasGroupChanged = true;
515
516 // Fire after attach, so we don't get messy perms dialogs
517 //
518 objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 0);
519 }
520 return objatt;
521 }
522
523 // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards.
524 // To LocalId or UUID, *THAT* is the question. How now Brown UUID??
525 public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient)
526 {
527 if (itemID == UUID.Zero) // If this happened, someone made a mistake....
528 return;
529
530 List<EntityBase> EntityList = GetEntities();
531
532 foreach (EntityBase obj in EntityList)
533 {
534 if (obj is SceneObjectGroup)
535 {
536 if (((SceneObjectGroup)obj).GetFromAssetID() == itemID)
537 {
538 SceneObjectGroup group = (SceneObjectGroup)obj;
539 group.DetachToInventoryPrep();
540 m_log.Debug("[DETACH]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
541 m_parentScene.updateKnownAsset(remoteClient, group, group.GetFromAssetID(), group.OwnerID);
542 m_parentScene.DeleteSceneObject(group, false);
543 }
544 }
545 }
546 }
547
548 protected internal void AttachObject(
549 IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent)
550 {
551 List<EntityBase> EntityList = GetEntities();
552 foreach (EntityBase obj in EntityList)
553 {
554 if (obj is SceneObjectGroup)
555 {
556 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
557 {
558 SceneObjectGroup group = (SceneObjectGroup)obj;
559 if (m_parentScene.Permissions.CanTakeObject(obj.UUID, remoteClient.AgentId))
560 {
561 // If the attachment point isn't the same as the one previously used
562 // set it's offset position = 0 so that it appears on the attachment point
563 // and not in a weird location somewhere unknown.
564 if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
565 {
566
567 attachPos = Vector3.Zero;
568 }
569
570 // AttachmentPt 0 means the client chose to 'wear' the attachment.
571 if (AttachmentPt == 0)
572 {
573
574 // Check object for stored attachment point
575 AttachmentPt = (uint)group.GetAttachmentPoint();
576
577
578 }
579
580 // if we still didn't find a suitable attachment point.......
581 if (AttachmentPt == 0)
582 {
583 // Stick it on left hand with Zero Offset from the attachment point.
584 AttachmentPt = (uint)AttachmentPoint.LeftHand;
585 attachPos = Vector3.Zero;
586 }
587
588 group.SetAttachmentPoint(Convert.ToByte(AttachmentPt));
589 group.AbsolutePosition = attachPos;
590
591 // Saves and gets assetID
592 UUID itemId;
593 if (group.GetFromAssetID() == UUID.Zero)
594 {
595 m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId);
596 }
597 else
598 {
599 itemId = group.GetFromAssetID();
600 }
601
602 m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group);
603
604 group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent);
605 // In case it is later dropped again, don't let
606 // it get cleaned up
607 //
608 group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
609 group.HasGroupChanged = false;
610 }
611 else
612 {
613 remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false);
614 }
615
616 }
617 }
618 }
619 }
620
621 protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance)
622 {
623 ScenePresence newAvatar = null;
624
625 newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance);
626 newAvatar.IsChildAgent = true;
627
628 AddScenePresence(newAvatar);
629
630 return newAvatar;
631 }
632
633 /// <summary>
634 /// Add a presence to the scene
635 /// </summary>
636 /// <param name="presence"></param>
637 protected internal void AddScenePresence(ScenePresence presence)
638 {
639 bool child = presence.IsChildAgent;
640
641 if (child)
642 {
643 m_numChildAgents++;
644 }
645 else
646 {
647 m_numRootAgents++;
648 presence.AddToPhysicalScene();
649 }
650
651 Entities[presence.UUID] = presence;
652
653 lock (ScenePresences)
654 {
655 ScenePresences[presence.UUID] = presence;
656 }
657 }
658
659 /// <summary>
660 /// Remove a presence from the scene
661 /// </summary>
662 protected internal void RemoveScenePresence(UUID agentID)
663 {
664 if (!Entities.Remove(agentID))
665 {
666 m_log.WarnFormat(
667 "[SCENE] Tried to remove non-existent scene presence with agent ID {0} from scene Entities list",
668 agentID);
669 }
670
671 lock (ScenePresences)
672 {
673 if (!ScenePresences.Remove(agentID))
674 {
675 m_log.WarnFormat("[SCENE] Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
676 }
677// else
678// {
679// m_log.InfoFormat("[SCENE] Removed scene presence {0} from scene presences list", agentID);
680// }
681 }
682 }
683
684 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
685 {
686 if (direction_RC_CR_T_F)
687 {
688 m_numRootAgents--;
689 m_numChildAgents++;
690 }
691 else
692 {
693 m_numChildAgents--;
694 m_numRootAgents++;
695 }
696 }
697
698 protected internal void removeUserCount(bool TypeRCTF)
699 {
700 if (TypeRCTF)
701 {
702 m_numRootAgents--;
703 }
704 else
705 {
706 m_numChildAgents--;
707 }
708 }
709
710 public void RecalculateStats()
711 {
712 List<ScenePresence> SPList = GetScenePresences();
713 int rootcount = 0;
714 int childcount = 0;
715
716 foreach (ScenePresence user in SPList)
717 {
718 if (user.IsChildAgent)
719 childcount++;
720 else
721 rootcount++;
722 }
723 m_numRootAgents = rootcount;
724 m_numChildAgents = childcount;
725
726 }
727
728 public int GetChildAgentCount()
729 {
730 // some network situations come in where child agents get closed twice.
731 if (m_numChildAgents < 0)
732 {
733 m_numChildAgents = 0;
734 }
735
736 return m_numChildAgents;
737 }
738
739 public int GetRootAgentCount()
740 {
741 return m_numRootAgents;
742 }
743
744 public int GetTotalObjectsCount()
745 {
746 return m_numPrim;
747 }
748
749 public int GetActiveObjectsCount()
750 {
751 return m_physicalPrim;
752 }
753
754 public int GetActiveScriptsCount()
755 {
756 return m_activeScripts;
757 }
758
759 public int GetScriptLPS()
760 {
761 int returnval = m_scriptLPS;
762 m_scriptLPS = 0;
763 return returnval;
764 }
765
766 #endregion
767
768 #region Get Methods
769
770 /// <summary>
771 /// Request a List of all scene presences in this scene. This is a new list, so no
772 /// locking is required to iterate over it.
773 /// </summary>
774 /// <returns></returns>
775 protected internal List<ScenePresence> GetScenePresences()
776 {
777 lock (ScenePresences)
778 {
779 return new List<ScenePresence>(ScenePresences.Values);
780 }
781 }
782
783 protected internal List<ScenePresence> GetAvatars()
784 {
785 List<ScenePresence> result =
786 GetScenePresences(delegate(ScenePresence scenePresence) { return !scenePresence.IsChildAgent; });
787
788 return result;
789 }
790
791 /// <summary>
792 /// Get the controlling client for the given avatar, if there is one.
793 ///
794 /// FIXME: The only user of the method right now is Caps.cs, in order to resolve a client API since it can't
795 /// use the ScenePresence. This could be better solved in a number of ways - we could establish an
796 /// OpenSim.Framework.IScenePresence, or move the caps code into a region package (which might be the more
797 /// suitable solution).
798 /// </summary>
799 /// <param name="agentId"></param>
800 /// <returns>null if either the avatar wasn't in the scene, or they do not have a controlling client</returns>
801 protected internal IClientAPI GetControllingClient(UUID agentId)
802 {
803 ScenePresence presence = GetScenePresence(agentId);
804
805 if (presence != null)
806 {
807 return presence.ControllingClient;
808 }
809
810 return null;
811 }
812
813 /// <summary>
814 /// Request a filtered list of m_scenePresences in this World
815 /// </summary>
816 /// <returns></returns>
817 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter)
818 {
819 // No locking of scene presences here since we're passing back a list...
820
821 List<ScenePresence> result = new List<ScenePresence>();
822 List<ScenePresence> ScenePresencesList = GetScenePresences();
823
824 foreach (ScenePresence avatar in ScenePresencesList)
825 {
826 if (filter(avatar))
827 {
828 result.Add(avatar);
829 }
830 }
831
832 return result;
833 }
834
835 /// <summary>
836 /// Request a scene presence by UUID
837 /// </summary>
838 /// <param name="avatarID"></param>
839 /// <returns>null if the agent was not found</returns>
840 protected internal ScenePresence GetScenePresence(UUID agentID)
841 {
842 ScenePresence sp;
843
844 lock (ScenePresences)
845 {
846 ScenePresences.TryGetValue(agentID, out sp);
847 }
848
849 return sp;
850 }
851
852 /// <summary>
853 /// Get a scene object group that contains the prim with the given local id
854 /// </summary>
855 /// <param name="localID"></param>
856 /// <returns>null if no scene object group containing that prim is found</returns>
857 private SceneObjectGroup GetGroupByPrim(uint localID)
858 {
859 //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID);
860 List<EntityBase> EntityList = GetEntities();
861 foreach (EntityBase ent in EntityList)
862 {
863 //m_log.DebugFormat("Looking at entity {0}", ent.UUID);
864 if (ent is SceneObjectGroup)
865 {
866 if (((SceneObjectGroup)ent).HasChildPrim(localID))
867 return (SceneObjectGroup)ent;
868 }
869 }
870 return null;
871 }
872
873 /// <summary>
874 /// Get a scene object group that contains the prim with the given uuid
875 /// </summary>
876 /// <param name="fullID"></param>
877 /// <returns>null if no scene object group containing that prim is found</returns>
878 private SceneObjectGroup GetGroupByPrim(UUID fullID)
879 {
880 List<EntityBase> EntityList = GetEntities();
881
882 foreach (EntityBase ent in EntityList)
883 {
884 if (ent is SceneObjectGroup)
885 {
886 if (((SceneObjectGroup)ent).HasChildPrim(fullID))
887 return (SceneObjectGroup)ent;
888 }
889 }
890 return null;
891 }
892
893 protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
894 {
895 // Primitive Ray Tracing
896 float closestDistance = 280f;
897 EntityIntersection returnResult = new EntityIntersection();
898 List<EntityBase> EntityList = GetEntities();
899 foreach (EntityBase ent in EntityList)
900 {
901 if (ent is SceneObjectGroup)
902 {
903 SceneObjectGroup reportingG = (SceneObjectGroup)ent;
904 EntityIntersection result = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
905 if (result.HitTF)
906 {
907 if (result.distance < closestDistance)
908 {
909 closestDistance = result.distance;
910 returnResult = result;
911 }
912 }
913 }
914 }
915 return returnResult;
916 }
917
918 /// <summary>
919 /// Get a part contained in this scene.
920 /// </summary>
921 /// <param name="localID"></param>
922 /// <returns>null if the part was not found</returns>
923 protected internal SceneObjectPart GetSceneObjectPart(uint localID)
924 {
925 SceneObjectGroup group = GetGroupByPrim(localID);
926
927 if (group != null)
928 return group.GetChildPart(localID);
929 else
930 return null;
931 }
932
933 /// <summary>
934 /// Get a named prim contained in this scene (will return the first
935 /// found, if there are more than one prim with the same name)
936 /// </summary>
937 /// <param name="name"></param>
938 /// <returns>null if the part was not found</returns>
939 protected internal SceneObjectPart GetSceneObjectPart(string name)
940 {
941 List<EntityBase> EntityList = GetEntities();
942
943 // FIXME: use a dictionary here
944 foreach (EntityBase ent in EntityList)
945 {
946 if (ent is SceneObjectGroup)
947 {
948 foreach (SceneObjectPart p in ((SceneObjectGroup) ent).GetParts())
949 {
950 if (p.Name==name)
951 {
952 return p;
953 }
954 }
955 }
956 }
957 return null;
958 }
959
960 /// <summary>
961 /// Get a part contained in this scene.
962 /// </summary>
963 /// <param name="fullID"></param>
964 /// <returns>null if the part was not found</returns>
965 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
966 {
967 SceneObjectGroup group = GetGroupByPrim(fullID);
968
969 if (group != null)
970 return group.GetChildPart(fullID);
971 else
972 return null;
973 }
974
975 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
976 {
977 ScenePresence presence;
978
979 lock (ScenePresences)
980 {
981 if (ScenePresences.TryGetValue(avatarId, out presence))
982 {
983 avatar = presence;
984 return true;
985
986 //if (!presence.IsChildAgent)
987 //{
988 // avatar = presence;
989 // return true;
990 //}
991 //else
992 //{
993 // m_log.WarnFormat(
994 // "[INNER SCENE]: Requested avatar {0} could not be found in scene {1} since it is only registered as a child agent!",
995 // avatarId, m_parentScene.RegionInfo.RegionName);
996 //}
997 }
998 }
999
1000 avatar = null;
1001 return false;
1002 }
1003
1004 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
1005 {
1006 lock (ScenePresences)
1007 {
1008 foreach (ScenePresence presence in ScenePresences.Values)
1009 {
1010 if (!presence.IsChildAgent)
1011 {
1012 string name = presence.ControllingClient.Name;
1013
1014 if (String.Compare(avatarName, name, true) == 0)
1015 {
1016 avatar = presence;
1017 return true;
1018 }
1019 }
1020 }
1021 }
1022
1023 avatar = null;
1024 return false;
1025 }
1026
1027 /// <summary>
1028 /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
1029 /// it
1030 /// </summary>
1031 /// <returns></returns>
1032 protected internal List<EntityBase> GetEntities()
1033 {
1034 return Entities.GetEntities();
1035 }
1036
1037 protected internal Dictionary<uint, float> GetTopScripts()
1038 {
1039 Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
1040
1041 List<EntityBase> EntityList = GetEntities();
1042 int limit = 0;
1043 foreach (EntityBase ent in EntityList)
1044 {
1045 if (ent is SceneObjectGroup)
1046 {
1047 SceneObjectGroup grp = (SceneObjectGroup)ent;
1048 if ((grp.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
1049 {
1050 if (grp.scriptScore >= 0.01)
1051 {
1052 topScripts.Add(grp.LocalId, grp.scriptScore);
1053 limit++;
1054 if (limit >= 100)
1055 {
1056 break;
1057 }
1058 }
1059 grp.scriptScore = 0;
1060 }
1061 }
1062 }
1063
1064 return topScripts;
1065 }
1066
1067 #endregion
1068
1069 #region Other Methods
1070
1071 protected internal void physicsBasedCrash()
1072 {
1073 handlerPhysicsCrash = UnRecoverableError;
1074 if (handlerPhysicsCrash != null)
1075 {
1076 handlerPhysicsCrash();
1077 }
1078 }
1079
1080 protected internal UUID ConvertLocalIDToFullID(uint localID)
1081 {
1082 SceneObjectGroup group = GetGroupByPrim(localID);
1083 if (group != null)
1084 return group.GetPartsFullID(localID);
1085 else
1086 return UUID.Zero;
1087 }
1088
1089 protected internal void ForEachClient(Action<IClientAPI> action)
1090 {
1091 List<ScenePresence> splist = GetScenePresences();
1092 foreach (ScenePresence presence in splist)
1093 {
1094 try
1095 {
1096 action(presence.ControllingClient);
1097 }
1098 catch (Exception e)
1099 {
1100 // Catch it and move on. This includes situations where splist has inconsistent info
1101 m_log.WarnFormat("[SCENE]: Problem processing action in ForEachClient: ", e.Message);
1102 }
1103 }
1104 }
1105
1106 #endregion
1107
1108 #region Client Event handlers
1109
1110 /// <summary>
1111 ///
1112 /// </summary>
1113 /// <param name="localID"></param>
1114 /// <param name="scale"></param>
1115 /// <param name="remoteClient"></param>
1116 protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1117 {
1118 SceneObjectGroup group = GetGroupByPrim(localID);
1119 if (group != null)
1120 {
1121 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1122 {
1123 group.Resize(scale, localID);
1124 }
1125 }
1126 }
1127
1128 protected internal void UpdatePrimGroupScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1129 {
1130 SceneObjectGroup group = GetGroupByPrim(localID);
1131 if (group != null)
1132 {
1133 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1134 {
1135 group.GroupResize(scale, localID);
1136 }
1137 }
1138 }
1139
1140 /// <summary>
1141 /// This handles the nifty little tool tip that you get when you drag your mouse over an object
1142 /// Send to the Object Group to process. We don't know enough to service the request
1143 /// </summary>
1144 /// <param name="remoteClient"></param>
1145 /// <param name="AgentID"></param>
1146 /// <param name="RequestFlags"></param>
1147 /// <param name="ObjectID"></param>
1148 protected internal void RequestObjectPropertiesFamily(
1149 IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
1150 {
1151 SceneObjectGroup group = GetGroupByPrim(ObjectID);
1152 if (group != null)
1153 {
1154 group.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
1155 }
1156 }
1157
1158 /// <summary>
1159 ///
1160 /// </summary>
1161 /// <param name="localID"></param>
1162 /// <param name="rot"></param>
1163 /// <param name="remoteClient"></param>
1164 protected internal void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1165 {
1166 SceneObjectGroup group = GetGroupByPrim(localID);
1167 if (group != null)
1168 {
1169 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1170 {
1171 group.UpdateSingleRotation(rot, localID);
1172 }
1173 }
1174 }
1175
1176 /// <summary>
1177 ///
1178 /// </summary>
1179 /// <param name="localID"></param>
1180 /// <param name="rot"></param>
1181 /// <param name="remoteClient"></param>
1182 protected internal void UpdatePrimRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1183 {
1184 SceneObjectGroup group = GetGroupByPrim(localID);
1185 if (group != null)
1186 {
1187 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1188 {
1189 group.UpdateGroupRotation(rot);
1190 }
1191 }
1192 }
1193
1194 /// <summary>
1195 ///
1196 /// </summary>
1197 /// <param name="localID"></param>
1198 /// <param name="pos"></param>
1199 /// <param name="rot"></param>
1200 /// <param name="remoteClient"></param>
1201 protected internal void UpdatePrimRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
1202 {
1203 SceneObjectGroup group = GetGroupByPrim(localID);
1204 if (group != null)
1205 {
1206 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1207 {
1208 group.UpdateGroupRotation(pos, rot);
1209 }
1210 }
1211 }
1212
1213 /// <summary>
1214 /// Update the position of the given part
1215 /// </summary>
1216 /// <param name="localID"></param>
1217 /// <param name="pos"></param>
1218 /// <param name="remoteClient"></param>
1219 protected internal void UpdatePrimSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1220 {
1221 SceneObjectGroup group = GetGroupByPrim(localID);
1222 if (group != null)
1223 {
1224 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment)
1225 {
1226 group.UpdateSinglePosition(pos, localID);
1227 }
1228 }
1229 }
1230
1231 /// <summary>
1232 /// Update the position of the given part
1233 /// </summary>
1234 /// <param name="localID"></param>
1235 /// <param name="pos"></param>
1236 /// <param name="remoteClient"></param>
1237 protected internal void UpdatePrimPosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1238 {
1239 SceneObjectGroup group = GetGroupByPrim(localID);
1240 if (group != null)
1241 {
1242
1243 // Vector3 oldPos = group.AbsolutePosition;
1244 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1245 {
1246 group.UpdateGroupPosition(pos);
1247 }
1248 else
1249 {
1250 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1251 {
1252 group.UpdateGroupPosition(pos);
1253 }
1254 }
1255 }
1256 }
1257
1258 /// <summary>
1259 ///
1260 /// </summary>
1261 /// <param name="localID"></param>
1262 /// <param name="texture"></param>
1263 /// <param name="remoteClient"></param>
1264 protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
1265 {
1266 SceneObjectGroup group = GetGroupByPrim(localID);
1267 if (group != null)
1268 {
1269 if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId))
1270 {
1271 group.UpdateTextureEntry(localID, texture);
1272 }
1273 }
1274 }
1275
1276 /// <summary>
1277 ///
1278 /// </summary>
1279 /// <param name="localID"></param>
1280 /// <param name="packet"></param>
1281 /// <param name="remoteClient"></param>
1282 /// This routine seems to get called when a user changes object settings in the viewer.
1283 /// If some one can confirm that, please change the comment according.
1284 protected internal void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient)
1285 {
1286 SceneObjectGroup group = GetGroupByPrim(localID);
1287 if (group != null)
1288 {
1289 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1290 {
1291 group.UpdatePrimFlags(localID, UsePhysics, IsTemporary, IsPhantom, false); // VolumeDetect can't be set via UI and will always be off when a change is made there
1292 }
1293 }
1294 }
1295
1296 /// <summary>
1297 /// Move the given object
1298 /// </summary>
1299 /// <param name="objectID"></param>
1300 /// <param name="offset"></param>
1301 /// <param name="pos"></param>
1302 /// <param name="remoteClient"></param>
1303 protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
1304 {
1305 SceneObjectGroup group = GetGroupByPrim(objectID);
1306 if (group != null)
1307 {
1308 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1309 {
1310 group.GrabMovement(offset, pos, remoteClient);
1311 }
1312 // This is outside the above permissions condition
1313 // so that if the object is locked the client moving the object
1314 // get's it's position on the simulator even if it was the same as before
1315 // This keeps the moving user's client in sync with the rest of the world.
1316 group.SendGroupTerseUpdate();
1317 }
1318 }
1319
1320 /// <summary>
1321 ///
1322 /// </summary>
1323 /// <param name="primLocalID"></param>
1324 /// <param name="description"></param>
1325 protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
1326 {
1327 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1328 if (group != null)
1329 {
1330 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1331 {
1332 group.SetPartName(Util.CleanString(name), primLocalID);
1333 group.HasGroupChanged = true;
1334 }
1335 }
1336 }
1337
1338 /// <summary>
1339 ///
1340 /// </summary>
1341 /// <param name="primLocalID"></param>
1342 /// <param name="description"></param>
1343 protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
1344 {
1345 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1346 if (group != null)
1347 {
1348 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1349 {
1350 group.SetPartDescription(Util.CleanString(description), primLocalID);
1351 group.HasGroupChanged = true;
1352 }
1353 }
1354 }
1355
1356 protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
1357 {
1358 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1359 if (group != null)
1360 {
1361 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1362 {
1363 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1364 part.ClickAction = Convert.ToByte(clickAction);
1365 group.HasGroupChanged = true;
1366 }
1367 }
1368 }
1369
1370 protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
1371 {
1372 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1373 if (group != null)
1374 {
1375 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1376 {
1377 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1378 part.Material = Convert.ToByte(material);
1379 group.HasGroupChanged = true;
1380 }
1381 }
1382 }
1383
1384 protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
1385 {
1386 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1387
1388 if (group != null)
1389 {
1390 if (m_parentScene.Permissions.CanEditObject(group.UUID,agentID))
1391 {
1392 group.UpdateExtraParam(primLocalID, type, inUse, data);
1393 }
1394 }
1395 }
1396
1397 /// <summary>
1398 ///
1399 /// </summary>
1400 /// <param name="primLocalID"></param>
1401 /// <param name="shapeBlock"></param>
1402 protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
1403 {
1404 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1405 if (group != null)
1406 {
1407 if (m_parentScene.Permissions.CanEditObject(group.GetPartsFullID(primLocalID), agentID))
1408 {
1409 ObjectShapePacket.ObjectDataBlock shapeData = new ObjectShapePacket.ObjectDataBlock();
1410 shapeData.ObjectLocalID = shapeBlock.ObjectLocalID;
1411 shapeData.PathBegin = shapeBlock.PathBegin;
1412 shapeData.PathCurve = shapeBlock.PathCurve;
1413 shapeData.PathEnd = shapeBlock.PathEnd;
1414 shapeData.PathRadiusOffset = shapeBlock.PathRadiusOffset;
1415 shapeData.PathRevolutions = shapeBlock.PathRevolutions;
1416 shapeData.PathScaleX = shapeBlock.PathScaleX;
1417 shapeData.PathScaleY = shapeBlock.PathScaleY;
1418 shapeData.PathShearX = shapeBlock.PathShearX;
1419 shapeData.PathShearY = shapeBlock.PathShearY;
1420 shapeData.PathSkew = shapeBlock.PathSkew;
1421 shapeData.PathTaperX = shapeBlock.PathTaperX;
1422 shapeData.PathTaperY = shapeBlock.PathTaperY;
1423 shapeData.PathTwist = shapeBlock.PathTwist;
1424 shapeData.PathTwistBegin = shapeBlock.PathTwistBegin;
1425 shapeData.ProfileBegin = shapeBlock.ProfileBegin;
1426 shapeData.ProfileCurve = shapeBlock.ProfileCurve;
1427 shapeData.ProfileEnd = shapeBlock.ProfileEnd;
1428 shapeData.ProfileHollow = shapeBlock.ProfileHollow;
1429
1430 group.UpdateShape(shapeData, primLocalID);
1431 }
1432 }
1433 }
1434
1435 /// <summary>
1436 /// Initial method invoked when we receive a link objects request from the client.
1437 /// </summary>
1438 /// <param name="client"></param>
1439 /// <param name="parentPrim"></param>
1440 /// <param name="childPrims"></param>
1441 protected internal void LinkObjects(IClientAPI client, uint parentPrim, List<uint> childPrims)
1442 {
1443 List<EntityBase> EntityList = GetEntities();
1444
1445 SceneObjectGroup parenPrim = null;
1446 foreach (EntityBase ent in EntityList)
1447 {
1448 if (ent is SceneObjectGroup)
1449 {
1450 if (((SceneObjectGroup)ent).LocalId == parentPrim)
1451 {
1452 parenPrim = (SceneObjectGroup)ent;
1453 break;
1454 }
1455 }
1456 }
1457
1458 List<SceneObjectGroup> children = new List<SceneObjectGroup>();
1459 if (parenPrim != null)
1460 {
1461 // We do this in reverse to get the link order of the prims correct
1462 for (int i = childPrims.Count - 1; i >= 0; i--)
1463 {
1464 foreach (EntityBase ent in EntityList)
1465 {
1466 if (ent is SceneObjectGroup)
1467 {
1468 if (((SceneObjectGroup)ent).LocalId == childPrims[i])
1469 {
1470 // Make sure no child prim is set for sale
1471 // So that, on delink, no prims are unwittingly
1472 // left for sale and sold off
1473 ((SceneObjectGroup)ent).RootPart.ObjectSaleType = 0;
1474 ((SceneObjectGroup)ent).RootPart.SalePrice = 10;
1475 children.Add((SceneObjectGroup)ent);
1476 }
1477 }
1478 }
1479 }
1480 }
1481 else
1482 {
1483 return; // parent is null so not in this region
1484 }
1485
1486 foreach (SceneObjectGroup sceneObj in children)
1487 {
1488 parenPrim.LinkToGroup(sceneObj);
1489
1490 // this is here so physics gets updated!
1491 // Don't remove! Bad juju! Stay away! or fix physics!
1492 sceneObj.AbsolutePosition = sceneObj.AbsolutePosition;
1493 }
1494
1495 // We need to explicitly resend the newly link prim's object properties since no other actions
1496 // occur on link to invoke this elsewhere (such as object selection)
1497 parenPrim.RootPart.AddFlag(PrimFlags.CreateSelected);
1498 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1499
1500 if (client != null)
1501 {
1502 parenPrim.GetProperties(client);
1503 }
1504 else
1505 {
1506 foreach (ScenePresence p in GetScenePresences())
1507 {
1508 parenPrim.GetProperties(p.ControllingClient);
1509 }
1510 }
1511 }
1512
1513 /// <summary>
1514 /// Delink a linkset
1515 /// </summary>
1516 /// <param name="prims"></param>
1517 protected internal void DelinkObjects(List<uint> primIds)
1518 {
1519 DelinkObjects(primIds, true);
1520 }
1521
1522 protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
1523 {
1524 SceneObjectGroup parenPrim = null;
1525
1526 // Need a list of the SceneObjectGroup local ids
1527 // XXX I'm anticipating that building this dictionary once is more efficient than
1528 // repeated scanning of the Entity.Values for a large number of primIds. However, it might
1529 // be more efficient yet to keep this dictionary permanently on hand.
1530
1531 Dictionary<uint, SceneObjectGroup> sceneObjects = new Dictionary<uint, SceneObjectGroup>();
1532
1533 List<EntityBase> EntityList = GetEntities();
1534 foreach (EntityBase ent in EntityList)
1535 {
1536 if (ent is SceneObjectGroup)
1537 {
1538 SceneObjectGroup obj = (SceneObjectGroup)ent;
1539 // Nasty one. Can't unlink anything in the sim
1540 // If a duplicate local ID sneaks in
1541 // So, check it here!
1542 //
1543 if (!sceneObjects.ContainsKey(obj.LocalId))
1544 sceneObjects.Add(obj.LocalId, obj);
1545
1546 }
1547 }
1548
1549 // Find the root prim among the prim ids we've been given
1550 for (int i = 0; i < primIds.Count; i++)
1551 {
1552
1553 if (sceneObjects.ContainsKey(primIds[i]))
1554 {
1555 parenPrim = sceneObjects[primIds[i]];
1556 primIds.RemoveAt(i);
1557 break;
1558 }
1559 }
1560
1561 if (parenPrim != null)
1562 {
1563 foreach (uint childPrimId in primIds)
1564 {
1565 parenPrim.DelinkFromGroup(childPrimId, sendEvents);
1566 }
1567
1568 if (parenPrim.Children.Count == 1)
1569 {
1570 // The link set has been completely torn down
1571 // This is the case if you select a link set and delink
1572 //
1573 parenPrim.RootPart.LinkNum = 0;
1574 if (sendEvents)
1575 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1576 }
1577 else
1578 {
1579 // The link set has prims remaining. This path is taken
1580 // when a subset of a link set's prims are selected
1581 // and the root prim is part of that selection
1582 //
1583 List<SceneObjectPart> parts = new List<SceneObjectPart>(parenPrim.Children.Values);
1584
1585 List<uint> unlink_ids = new List<uint>();
1586 foreach (SceneObjectPart unlink_part in parts)
1587 unlink_ids.Add(unlink_part.LocalId);
1588
1589 // Tear down the remaining link set
1590 //
1591 if (unlink_ids.Count == 2)
1592 {
1593 DelinkObjects(unlink_ids, true);
1594 return;
1595 }
1596
1597 DelinkObjects(unlink_ids, false);
1598
1599 // Send event to root prim, then we're done with it
1600 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1601
1602 unlink_ids.Remove(parenPrim.RootPart.LocalId);
1603
1604 foreach (uint localId in unlink_ids)
1605 {
1606 SceneObjectPart nr = GetSceneObjectPart(localId);
1607 nr.UpdateFlag = 0;
1608 }
1609
1610 uint newRoot = unlink_ids[0];
1611 unlink_ids.Remove(newRoot);
1612
1613 LinkObjects(null, newRoot, unlink_ids);
1614 }
1615 }
1616 else
1617 {
1618 // The selected prims were all child prims. Edit linked parts
1619 // without the root prim selected will get us here
1620 //
1621 List<SceneObjectGroup> parents = new List<SceneObjectGroup>();
1622
1623 // If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow
1624 // We know that this is not the root prim now essentially, so we don't have to worry about remapping
1625 // which one is the root prim
1626 bool delinkedSomething = false;
1627 for (int i = 0; i < primIds.Count; i++)
1628 {
1629 foreach (SceneObjectGroup grp in sceneObjects.Values)
1630 {
1631 SceneObjectPart gPart = grp.GetChildPart(primIds[i]);
1632 if (gPart != null)
1633 {
1634 grp.DelinkFromGroup(primIds[i]);
1635 delinkedSomething = true;
1636 if (!parents.Contains(grp))
1637 parents.Add(grp);
1638 }
1639
1640 }
1641 }
1642 if (!delinkedSomething)
1643 {
1644 m_log.InfoFormat("[SCENE]: " +
1645 "DelinkObjects(): Could not find a root prim out of {0} as given to a delink request!",
1646 primIds);
1647 }
1648 else
1649 {
1650 foreach (SceneObjectGroup g in parents)
1651 {
1652 g.TriggerScriptChangedEvent(Changed.LINK);
1653 }
1654 }
1655 }
1656 }
1657
1658 protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
1659 {
1660 UUID user = remoteClient.AgentId;
1661 UUID objid = UUID.Zero;
1662 SceneObjectPart obj = null;
1663
1664 List<EntityBase> EntityList = GetEntities();
1665 foreach (EntityBase ent in EntityList)
1666 {
1667 if (ent is SceneObjectGroup)
1668 {
1669 foreach (KeyValuePair<UUID, SceneObjectPart> subent in ((SceneObjectGroup)ent).Children)
1670 {
1671 if (subent.Value.LocalId == localID)
1672 {
1673 objid = subent.Key;
1674 obj = subent.Value;
1675 }
1676 }
1677 }
1678 }
1679
1680 //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
1681 //aka ObjectFlags.JointWheel = IncludeInSearch
1682
1683 //Permissions model: Object can be REMOVED from search IFF:
1684 // * User owns object
1685 //use CanEditObject
1686
1687 //Object can be ADDED to search IFF:
1688 // * User owns object
1689 // * Asset/DRM permission bit "modify" is enabled
1690 //use CanEditObjectPosition
1691
1692 // libomv will complain about PrimFlags.JointWheel being
1693 // deprecated, so we
1694 #pragma warning disable 0612
1695 if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user))
1696 {
1697 obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel);
1698 obj.ParentGroup.HasGroupChanged = true;
1699 }
1700 else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user))
1701 {
1702 obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel);
1703 obj.ParentGroup.HasGroupChanged = true;
1704 }
1705 #pragma warning restore 0612
1706 }
1707
1708 /// <summary>
1709 /// Duplicate the given object, Fire and Forget, No rotation, no return wrapper
1710 /// </summary>
1711 /// <param name="originalPrim"></param>
1712 /// <param name="offset"></param>
1713 /// <param name="flags"></param>
1714 protected internal void DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID)
1715 {
1716 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1717
1718 // SceneObjectGroup dupe = DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Zero);
1719 DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Identity);
1720 }
1721
1722 /// <summary>
1723 /// Duplicate the given object.
1724 /// </summary>
1725 /// <param name="originalPrim"></param>
1726 /// <param name="offset"></param>
1727 /// <param name="flags"></param>
1728 protected internal SceneObjectGroup DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1729 {
1730 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1731
1732 List<EntityBase> EntityList = GetEntities();
1733
1734 SceneObjectGroup originPrim = null;
1735 foreach (EntityBase ent in EntityList)
1736 {
1737 if (ent is SceneObjectGroup)
1738 {
1739 if (((SceneObjectGroup)ent).LocalId == originalPrim)
1740 {
1741 originPrim = (SceneObjectGroup)ent;
1742 break;
1743 }
1744 }
1745 }
1746
1747 if (originPrim != null)
1748 {
1749 if (m_parentScene.Permissions.CanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition))
1750 {
1751 SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID, true);
1752 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1753
1754 Entities.Add(copy);
1755
1756 // Since we copy from a source group that is in selected
1757 // state, but the copy is shown deselected in the viewer,
1758 // We need to clear the selection flag here, else that
1759 // prim never gets persisted at all. The client doesn't
1760 // think it's selected, so it will never send a deselect...
1761 copy.IsSelected = false;
1762
1763 m_numPrim += copy.Children.Count;
1764
1765 if (rot != Quaternion.Identity)
1766 {
1767 copy.UpdateGroupRotation(rot);
1768 }
1769
1770 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 0);
1771 copy.HasGroupChanged = true;
1772 copy.ScheduleGroupForFullUpdate();
1773
1774 // required for physics to update it's position
1775 copy.AbsolutePosition = copy.AbsolutePosition;
1776
1777 if (OnObjectDuplicate != null)
1778 OnObjectDuplicate(originPrim, copy);
1779
1780 return copy;
1781 }
1782 }
1783 else
1784 {
1785 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1786 }
1787
1788 return null;
1789 }
1790
1791 /// <summary>
1792 /// Calculates the distance between two Vector3s
1793 /// </summary>
1794 /// <param name="v1"></param>
1795 /// <param name="v2"></param>
1796 /// <returns></returns>
1797 protected internal float Vector3Distance(Vector3 v1, Vector3 v2)
1798 {
1799 // We don't really need the double floating point precision...
1800 // so casting it to a single
1801
1802 return
1803 (float)
1804 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));
1805 }
1806
1807 #endregion
1808
1809
1810 }
1811}