aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneGraph.cs
diff options
context:
space:
mode:
authorDr Scofield2009-02-06 16:55:34 +0000
committerDr Scofield2009-02-06 16:55:34 +0000
commit9b66108081a8c8cf79faaa6c541554091c40850e (patch)
tree095a232ae5a9de3a9244bcd34da08294f61eeea5 /OpenSim/Region/Framework/Scenes/SceneGraph.cs
parent* removed superfluous constants class (diff)
downloadopensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.zip
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.gz
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.bz2
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.xz
This changeset is the step 1 of 2 in refactoring
OpenSim.Region.Environment into a "framework" part and a modules only part. This first changeset refactors OpenSim.Region.Environment.Scenes, OpenSim.Region.Environment.Interfaces, and OpenSim.Region.Interfaces into OpenSim.Region.Framework.{Interfaces,Scenes} leaving only region modules in OpenSim.Region.Environment. The next step will be to move region modules up from OpenSim.Region.Environment.Modules to OpenSim.Region.CoreModules and then sort out which modules are really core modules and which should move out to forge. I've been very careful to NOT BREAK anything. i hope i've succeeded. as this is the work of a whole week i hope i managed to keep track with the applied patches of the last week --- could any of you that did check in stuff have a look at whether it survived? thx!
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs1814
1 files changed, 1814 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
new file mode 100644
index 0000000..2877dcd
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -0,0 +1,1814 @@
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.Framework.Scenes.Types;
36using OpenSim.Region.Physics.Manager;
37
38namespace OpenSim.Region.Framework.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 public 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
801 /// they do not have a controlling client</returns>
802 /// <remarks>this used to be protected internal, but that
803 /// prevents CapabilitiesModule from accessing it</remarks>
804 public IClientAPI GetControllingClient(UUID agentId)
805 {
806 ScenePresence presence = GetScenePresence(agentId);
807
808 if (presence != null)
809 {
810 return presence.ControllingClient;
811 }
812
813 return null;
814 }
815
816 /// <summary>
817 /// Request a filtered list of m_scenePresences in this World
818 /// </summary>
819 /// <returns></returns>
820 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter)
821 {
822 // No locking of scene presences here since we're passing back a list...
823
824 List<ScenePresence> result = new List<ScenePresence>();
825 List<ScenePresence> ScenePresencesList = GetScenePresences();
826
827 foreach (ScenePresence avatar in ScenePresencesList)
828 {
829 if (filter(avatar))
830 {
831 result.Add(avatar);
832 }
833 }
834
835 return result;
836 }
837
838 /// <summary>
839 /// Request a scene presence by UUID
840 /// </summary>
841 /// <param name="avatarID"></param>
842 /// <returns>null if the agent was not found</returns>
843 protected internal ScenePresence GetScenePresence(UUID agentID)
844 {
845 ScenePresence sp;
846
847 lock (ScenePresences)
848 {
849 ScenePresences.TryGetValue(agentID, out sp);
850 }
851
852 return sp;
853 }
854
855 /// <summary>
856 /// Get a scene object group that contains the prim with the given local id
857 /// </summary>
858 /// <param name="localID"></param>
859 /// <returns>null if no scene object group containing that prim is found</returns>
860 private SceneObjectGroup GetGroupByPrim(uint localID)
861 {
862 //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID);
863 List<EntityBase> EntityList = GetEntities();
864 foreach (EntityBase ent in EntityList)
865 {
866 //m_log.DebugFormat("Looking at entity {0}", ent.UUID);
867 if (ent is SceneObjectGroup)
868 {
869 if (((SceneObjectGroup)ent).HasChildPrim(localID))
870 return (SceneObjectGroup)ent;
871 }
872 }
873 return null;
874 }
875
876 /// <summary>
877 /// Get a scene object group that contains the prim with the given uuid
878 /// </summary>
879 /// <param name="fullID"></param>
880 /// <returns>null if no scene object group containing that prim is found</returns>
881 private SceneObjectGroup GetGroupByPrim(UUID fullID)
882 {
883 List<EntityBase> EntityList = GetEntities();
884
885 foreach (EntityBase ent in EntityList)
886 {
887 if (ent is SceneObjectGroup)
888 {
889 if (((SceneObjectGroup)ent).HasChildPrim(fullID))
890 return (SceneObjectGroup)ent;
891 }
892 }
893 return null;
894 }
895
896 protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
897 {
898 // Primitive Ray Tracing
899 float closestDistance = 280f;
900 EntityIntersection returnResult = new EntityIntersection();
901 List<EntityBase> EntityList = GetEntities();
902 foreach (EntityBase ent in EntityList)
903 {
904 if (ent is SceneObjectGroup)
905 {
906 SceneObjectGroup reportingG = (SceneObjectGroup)ent;
907 EntityIntersection result = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
908 if (result.HitTF)
909 {
910 if (result.distance < closestDistance)
911 {
912 closestDistance = result.distance;
913 returnResult = result;
914 }
915 }
916 }
917 }
918 return returnResult;
919 }
920
921 /// <summary>
922 /// Get a part contained in this scene.
923 /// </summary>
924 /// <param name="localID"></param>
925 /// <returns>null if the part was not found</returns>
926 protected internal SceneObjectPart GetSceneObjectPart(uint localID)
927 {
928 SceneObjectGroup group = GetGroupByPrim(localID);
929
930 if (group != null)
931 return group.GetChildPart(localID);
932 else
933 return null;
934 }
935
936 /// <summary>
937 /// Get a named prim contained in this scene (will return the first
938 /// found, if there are more than one prim with the same name)
939 /// </summary>
940 /// <param name="name"></param>
941 /// <returns>null if the part was not found</returns>
942 protected internal SceneObjectPart GetSceneObjectPart(string name)
943 {
944 List<EntityBase> EntityList = GetEntities();
945
946 // FIXME: use a dictionary here
947 foreach (EntityBase ent in EntityList)
948 {
949 if (ent is SceneObjectGroup)
950 {
951 foreach (SceneObjectPart p in ((SceneObjectGroup) ent).GetParts())
952 {
953 if (p.Name==name)
954 {
955 return p;
956 }
957 }
958 }
959 }
960 return null;
961 }
962
963 /// <summary>
964 /// Get a part contained in this scene.
965 /// </summary>
966 /// <param name="fullID"></param>
967 /// <returns>null if the part was not found</returns>
968 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
969 {
970 SceneObjectGroup group = GetGroupByPrim(fullID);
971
972 if (group != null)
973 return group.GetChildPart(fullID);
974 else
975 return null;
976 }
977
978 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
979 {
980 ScenePresence presence;
981
982 lock (ScenePresences)
983 {
984 if (ScenePresences.TryGetValue(avatarId, out presence))
985 {
986 avatar = presence;
987 return true;
988
989 //if (!presence.IsChildAgent)
990 //{
991 // avatar = presence;
992 // return true;
993 //}
994 //else
995 //{
996 // m_log.WarnFormat(
997 // "[INNER SCENE]: Requested avatar {0} could not be found in scene {1} since it is only registered as a child agent!",
998 // avatarId, m_parentScene.RegionInfo.RegionName);
999 //}
1000 }
1001 }
1002
1003 avatar = null;
1004 return false;
1005 }
1006
1007 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
1008 {
1009 lock (ScenePresences)
1010 {
1011 foreach (ScenePresence presence in ScenePresences.Values)
1012 {
1013 if (!presence.IsChildAgent)
1014 {
1015 string name = presence.ControllingClient.Name;
1016
1017 if (String.Compare(avatarName, name, true) == 0)
1018 {
1019 avatar = presence;
1020 return true;
1021 }
1022 }
1023 }
1024 }
1025
1026 avatar = null;
1027 return false;
1028 }
1029
1030 /// <summary>
1031 /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
1032 /// it
1033 /// </summary>
1034 /// <returns></returns>
1035 protected internal List<EntityBase> GetEntities()
1036 {
1037 return Entities.GetEntities();
1038 }
1039
1040 public Dictionary<uint, float> GetTopScripts()
1041 {
1042 Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
1043
1044 List<EntityBase> EntityList = GetEntities();
1045 int limit = 0;
1046 foreach (EntityBase ent in EntityList)
1047 {
1048 if (ent is SceneObjectGroup)
1049 {
1050 SceneObjectGroup grp = (SceneObjectGroup)ent;
1051 if ((grp.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
1052 {
1053 if (grp.scriptScore >= 0.01)
1054 {
1055 topScripts.Add(grp.LocalId, grp.scriptScore);
1056 limit++;
1057 if (limit >= 100)
1058 {
1059 break;
1060 }
1061 }
1062 grp.scriptScore = 0;
1063 }
1064 }
1065 }
1066
1067 return topScripts;
1068 }
1069
1070 #endregion
1071
1072 #region Other Methods
1073
1074 protected internal void physicsBasedCrash()
1075 {
1076 handlerPhysicsCrash = UnRecoverableError;
1077 if (handlerPhysicsCrash != null)
1078 {
1079 handlerPhysicsCrash();
1080 }
1081 }
1082
1083 protected internal UUID ConvertLocalIDToFullID(uint localID)
1084 {
1085 SceneObjectGroup group = GetGroupByPrim(localID);
1086 if (group != null)
1087 return group.GetPartsFullID(localID);
1088 else
1089 return UUID.Zero;
1090 }
1091
1092 protected internal void ForEachClient(Action<IClientAPI> action)
1093 {
1094 List<ScenePresence> splist = GetScenePresences();
1095 foreach (ScenePresence presence in splist)
1096 {
1097 try
1098 {
1099 action(presence.ControllingClient);
1100 }
1101 catch (Exception e)
1102 {
1103 // Catch it and move on. This includes situations where splist has inconsistent info
1104 m_log.WarnFormat("[SCENE]: Problem processing action in ForEachClient: ", e.Message);
1105 }
1106 }
1107 }
1108
1109 #endregion
1110
1111 #region Client Event handlers
1112
1113 /// <summary>
1114 ///
1115 /// </summary>
1116 /// <param name="localID"></param>
1117 /// <param name="scale"></param>
1118 /// <param name="remoteClient"></param>
1119 protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1120 {
1121 SceneObjectGroup group = GetGroupByPrim(localID);
1122 if (group != null)
1123 {
1124 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1125 {
1126 group.Resize(scale, localID);
1127 }
1128 }
1129 }
1130
1131 protected internal void UpdatePrimGroupScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1132 {
1133 SceneObjectGroup group = GetGroupByPrim(localID);
1134 if (group != null)
1135 {
1136 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1137 {
1138 group.GroupResize(scale, localID);
1139 }
1140 }
1141 }
1142
1143 /// <summary>
1144 /// This handles the nifty little tool tip that you get when you drag your mouse over an object
1145 /// Send to the Object Group to process. We don't know enough to service the request
1146 /// </summary>
1147 /// <param name="remoteClient"></param>
1148 /// <param name="AgentID"></param>
1149 /// <param name="RequestFlags"></param>
1150 /// <param name="ObjectID"></param>
1151 protected internal void RequestObjectPropertiesFamily(
1152 IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
1153 {
1154 SceneObjectGroup group = GetGroupByPrim(ObjectID);
1155 if (group != null)
1156 {
1157 group.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
1158 }
1159 }
1160
1161 /// <summary>
1162 ///
1163 /// </summary>
1164 /// <param name="localID"></param>
1165 /// <param name="rot"></param>
1166 /// <param name="remoteClient"></param>
1167 protected internal void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1168 {
1169 SceneObjectGroup group = GetGroupByPrim(localID);
1170 if (group != null)
1171 {
1172 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1173 {
1174 group.UpdateSingleRotation(rot, localID);
1175 }
1176 }
1177 }
1178
1179 /// <summary>
1180 ///
1181 /// </summary>
1182 /// <param name="localID"></param>
1183 /// <param name="rot"></param>
1184 /// <param name="remoteClient"></param>
1185 protected internal void UpdatePrimRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1186 {
1187 SceneObjectGroup group = GetGroupByPrim(localID);
1188 if (group != null)
1189 {
1190 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1191 {
1192 group.UpdateGroupRotation(rot);
1193 }
1194 }
1195 }
1196
1197 /// <summary>
1198 ///
1199 /// </summary>
1200 /// <param name="localID"></param>
1201 /// <param name="pos"></param>
1202 /// <param name="rot"></param>
1203 /// <param name="remoteClient"></param>
1204 protected internal void UpdatePrimRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
1205 {
1206 SceneObjectGroup group = GetGroupByPrim(localID);
1207 if (group != null)
1208 {
1209 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1210 {
1211 group.UpdateGroupRotation(pos, rot);
1212 }
1213 }
1214 }
1215
1216 /// <summary>
1217 /// Update the position of the given part
1218 /// </summary>
1219 /// <param name="localID"></param>
1220 /// <param name="pos"></param>
1221 /// <param name="remoteClient"></param>
1222 protected internal void UpdatePrimSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1223 {
1224 SceneObjectGroup group = GetGroupByPrim(localID);
1225 if (group != null)
1226 {
1227 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment)
1228 {
1229 group.UpdateSinglePosition(pos, localID);
1230 }
1231 }
1232 }
1233
1234 /// <summary>
1235 /// Update the position of the given part
1236 /// </summary>
1237 /// <param name="localID"></param>
1238 /// <param name="pos"></param>
1239 /// <param name="remoteClient"></param>
1240 protected internal void UpdatePrimPosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1241 {
1242 SceneObjectGroup group = GetGroupByPrim(localID);
1243 if (group != null)
1244 {
1245
1246 // Vector3 oldPos = group.AbsolutePosition;
1247 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1248 {
1249 group.UpdateGroupPosition(pos);
1250 }
1251 else
1252 {
1253 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1254 {
1255 group.UpdateGroupPosition(pos);
1256 }
1257 }
1258 }
1259 }
1260
1261 /// <summary>
1262 ///
1263 /// </summary>
1264 /// <param name="localID"></param>
1265 /// <param name="texture"></param>
1266 /// <param name="remoteClient"></param>
1267 protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
1268 {
1269 SceneObjectGroup group = GetGroupByPrim(localID);
1270 if (group != null)
1271 {
1272 if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId))
1273 {
1274 group.UpdateTextureEntry(localID, texture);
1275 }
1276 }
1277 }
1278
1279 /// <summary>
1280 ///
1281 /// </summary>
1282 /// <param name="localID"></param>
1283 /// <param name="packet"></param>
1284 /// <param name="remoteClient"></param>
1285 /// This routine seems to get called when a user changes object settings in the viewer.
1286 /// If some one can confirm that, please change the comment according.
1287 protected internal void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient)
1288 {
1289 SceneObjectGroup group = GetGroupByPrim(localID);
1290 if (group != null)
1291 {
1292 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1293 {
1294 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
1295 }
1296 }
1297 }
1298
1299 /// <summary>
1300 /// Move the given object
1301 /// </summary>
1302 /// <param name="objectID"></param>
1303 /// <param name="offset"></param>
1304 /// <param name="pos"></param>
1305 /// <param name="remoteClient"></param>
1306 protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
1307 {
1308 SceneObjectGroup group = GetGroupByPrim(objectID);
1309 if (group != null)
1310 {
1311 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1312 {
1313 group.GrabMovement(offset, pos, remoteClient);
1314 }
1315 // This is outside the above permissions condition
1316 // so that if the object is locked the client moving the object
1317 // get's it's position on the simulator even if it was the same as before
1318 // This keeps the moving user's client in sync with the rest of the world.
1319 group.SendGroupTerseUpdate();
1320 }
1321 }
1322
1323 /// <summary>
1324 ///
1325 /// </summary>
1326 /// <param name="primLocalID"></param>
1327 /// <param name="description"></param>
1328 protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
1329 {
1330 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1331 if (group != null)
1332 {
1333 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1334 {
1335 group.SetPartName(Util.CleanString(name), primLocalID);
1336 group.HasGroupChanged = true;
1337 }
1338 }
1339 }
1340
1341 /// <summary>
1342 ///
1343 /// </summary>
1344 /// <param name="primLocalID"></param>
1345 /// <param name="description"></param>
1346 protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
1347 {
1348 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1349 if (group != null)
1350 {
1351 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1352 {
1353 group.SetPartDescription(Util.CleanString(description), primLocalID);
1354 group.HasGroupChanged = true;
1355 }
1356 }
1357 }
1358
1359 protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
1360 {
1361 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1362 if (group != null)
1363 {
1364 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1365 {
1366 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1367 part.ClickAction = Convert.ToByte(clickAction);
1368 group.HasGroupChanged = true;
1369 }
1370 }
1371 }
1372
1373 protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
1374 {
1375 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1376 if (group != null)
1377 {
1378 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1379 {
1380 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1381 part.Material = Convert.ToByte(material);
1382 group.HasGroupChanged = true;
1383 }
1384 }
1385 }
1386
1387 protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
1388 {
1389 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1390
1391 if (group != null)
1392 {
1393 if (m_parentScene.Permissions.CanEditObject(group.UUID,agentID))
1394 {
1395 group.UpdateExtraParam(primLocalID, type, inUse, data);
1396 }
1397 }
1398 }
1399
1400 /// <summary>
1401 ///
1402 /// </summary>
1403 /// <param name="primLocalID"></param>
1404 /// <param name="shapeBlock"></param>
1405 protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
1406 {
1407 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1408 if (group != null)
1409 {
1410 if (m_parentScene.Permissions.CanEditObject(group.GetPartsFullID(primLocalID), agentID))
1411 {
1412 ObjectShapePacket.ObjectDataBlock shapeData = new ObjectShapePacket.ObjectDataBlock();
1413 shapeData.ObjectLocalID = shapeBlock.ObjectLocalID;
1414 shapeData.PathBegin = shapeBlock.PathBegin;
1415 shapeData.PathCurve = shapeBlock.PathCurve;
1416 shapeData.PathEnd = shapeBlock.PathEnd;
1417 shapeData.PathRadiusOffset = shapeBlock.PathRadiusOffset;
1418 shapeData.PathRevolutions = shapeBlock.PathRevolutions;
1419 shapeData.PathScaleX = shapeBlock.PathScaleX;
1420 shapeData.PathScaleY = shapeBlock.PathScaleY;
1421 shapeData.PathShearX = shapeBlock.PathShearX;
1422 shapeData.PathShearY = shapeBlock.PathShearY;
1423 shapeData.PathSkew = shapeBlock.PathSkew;
1424 shapeData.PathTaperX = shapeBlock.PathTaperX;
1425 shapeData.PathTaperY = shapeBlock.PathTaperY;
1426 shapeData.PathTwist = shapeBlock.PathTwist;
1427 shapeData.PathTwistBegin = shapeBlock.PathTwistBegin;
1428 shapeData.ProfileBegin = shapeBlock.ProfileBegin;
1429 shapeData.ProfileCurve = shapeBlock.ProfileCurve;
1430 shapeData.ProfileEnd = shapeBlock.ProfileEnd;
1431 shapeData.ProfileHollow = shapeBlock.ProfileHollow;
1432
1433 group.UpdateShape(shapeData, primLocalID);
1434 }
1435 }
1436 }
1437
1438 /// <summary>
1439 /// Initial method invoked when we receive a link objects request from the client.
1440 /// </summary>
1441 /// <param name="client"></param>
1442 /// <param name="parentPrim"></param>
1443 /// <param name="childPrims"></param>
1444 protected internal void LinkObjects(IClientAPI client, uint parentPrim, List<uint> childPrims)
1445 {
1446 List<EntityBase> EntityList = GetEntities();
1447
1448 SceneObjectGroup parenPrim = null;
1449 foreach (EntityBase ent in EntityList)
1450 {
1451 if (ent is SceneObjectGroup)
1452 {
1453 if (((SceneObjectGroup)ent).LocalId == parentPrim)
1454 {
1455 parenPrim = (SceneObjectGroup)ent;
1456 break;
1457 }
1458 }
1459 }
1460
1461 List<SceneObjectGroup> children = new List<SceneObjectGroup>();
1462 if (parenPrim != null)
1463 {
1464 // We do this in reverse to get the link order of the prims correct
1465 for (int i = childPrims.Count - 1; i >= 0; i--)
1466 {
1467 foreach (EntityBase ent in EntityList)
1468 {
1469 if (ent is SceneObjectGroup)
1470 {
1471 if (((SceneObjectGroup)ent).LocalId == childPrims[i])
1472 {
1473 // Make sure no child prim is set for sale
1474 // So that, on delink, no prims are unwittingly
1475 // left for sale and sold off
1476 ((SceneObjectGroup)ent).RootPart.ObjectSaleType = 0;
1477 ((SceneObjectGroup)ent).RootPart.SalePrice = 10;
1478 children.Add((SceneObjectGroup)ent);
1479 }
1480 }
1481 }
1482 }
1483 }
1484 else
1485 {
1486 return; // parent is null so not in this region
1487 }
1488
1489 foreach (SceneObjectGroup sceneObj in children)
1490 {
1491 parenPrim.LinkToGroup(sceneObj);
1492
1493 // this is here so physics gets updated!
1494 // Don't remove! Bad juju! Stay away! or fix physics!
1495 sceneObj.AbsolutePosition = sceneObj.AbsolutePosition;
1496 }
1497
1498 // We need to explicitly resend the newly link prim's object properties since no other actions
1499 // occur on link to invoke this elsewhere (such as object selection)
1500 parenPrim.RootPart.AddFlag(PrimFlags.CreateSelected);
1501 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1502
1503 if (client != null)
1504 {
1505 parenPrim.GetProperties(client);
1506 }
1507 else
1508 {
1509 foreach (ScenePresence p in GetScenePresences())
1510 {
1511 parenPrim.GetProperties(p.ControllingClient);
1512 }
1513 }
1514 }
1515
1516 /// <summary>
1517 /// Delink a linkset
1518 /// </summary>
1519 /// <param name="prims"></param>
1520 protected internal void DelinkObjects(List<uint> primIds)
1521 {
1522 DelinkObjects(primIds, true);
1523 }
1524
1525 protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
1526 {
1527 SceneObjectGroup parenPrim = null;
1528
1529 // Need a list of the SceneObjectGroup local ids
1530 // XXX I'm anticipating that building this dictionary once is more efficient than
1531 // repeated scanning of the Entity.Values for a large number of primIds. However, it might
1532 // be more efficient yet to keep this dictionary permanently on hand.
1533
1534 Dictionary<uint, SceneObjectGroup> sceneObjects = new Dictionary<uint, SceneObjectGroup>();
1535
1536 List<EntityBase> EntityList = GetEntities();
1537 foreach (EntityBase ent in EntityList)
1538 {
1539 if (ent is SceneObjectGroup)
1540 {
1541 SceneObjectGroup obj = (SceneObjectGroup)ent;
1542 // Nasty one. Can't unlink anything in the sim
1543 // If a duplicate local ID sneaks in
1544 // So, check it here!
1545 //
1546 if (!sceneObjects.ContainsKey(obj.LocalId))
1547 sceneObjects.Add(obj.LocalId, obj);
1548
1549 }
1550 }
1551
1552 // Find the root prim among the prim ids we've been given
1553 for (int i = 0; i < primIds.Count; i++)
1554 {
1555
1556 if (sceneObjects.ContainsKey(primIds[i]))
1557 {
1558 parenPrim = sceneObjects[primIds[i]];
1559 primIds.RemoveAt(i);
1560 break;
1561 }
1562 }
1563
1564 if (parenPrim != null)
1565 {
1566 foreach (uint childPrimId in primIds)
1567 {
1568 parenPrim.DelinkFromGroup(childPrimId, sendEvents);
1569 }
1570
1571 if (parenPrim.Children.Count == 1)
1572 {
1573 // The link set has been completely torn down
1574 // This is the case if you select a link set and delink
1575 //
1576 parenPrim.RootPart.LinkNum = 0;
1577 if (sendEvents)
1578 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1579 }
1580 else
1581 {
1582 // The link set has prims remaining. This path is taken
1583 // when a subset of a link set's prims are selected
1584 // and the root prim is part of that selection
1585 //
1586 List<SceneObjectPart> parts = new List<SceneObjectPart>(parenPrim.Children.Values);
1587
1588 List<uint> unlink_ids = new List<uint>();
1589 foreach (SceneObjectPart unlink_part in parts)
1590 unlink_ids.Add(unlink_part.LocalId);
1591
1592 // Tear down the remaining link set
1593 //
1594 if (unlink_ids.Count == 2)
1595 {
1596 DelinkObjects(unlink_ids, true);
1597 return;
1598 }
1599
1600 DelinkObjects(unlink_ids, false);
1601
1602 // Send event to root prim, then we're done with it
1603 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1604
1605 unlink_ids.Remove(parenPrim.RootPart.LocalId);
1606
1607 foreach (uint localId in unlink_ids)
1608 {
1609 SceneObjectPart nr = GetSceneObjectPart(localId);
1610 nr.UpdateFlag = 0;
1611 }
1612
1613 uint newRoot = unlink_ids[0];
1614 unlink_ids.Remove(newRoot);
1615
1616 LinkObjects(null, newRoot, unlink_ids);
1617 }
1618 }
1619 else
1620 {
1621 // The selected prims were all child prims. Edit linked parts
1622 // without the root prim selected will get us here
1623 //
1624 List<SceneObjectGroup> parents = new List<SceneObjectGroup>();
1625
1626 // If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow
1627 // We know that this is not the root prim now essentially, so we don't have to worry about remapping
1628 // which one is the root prim
1629 bool delinkedSomething = false;
1630 for (int i = 0; i < primIds.Count; i++)
1631 {
1632 foreach (SceneObjectGroup grp in sceneObjects.Values)
1633 {
1634 SceneObjectPart gPart = grp.GetChildPart(primIds[i]);
1635 if (gPart != null)
1636 {
1637 grp.DelinkFromGroup(primIds[i]);
1638 delinkedSomething = true;
1639 if (!parents.Contains(grp))
1640 parents.Add(grp);
1641 }
1642
1643 }
1644 }
1645 if (!delinkedSomething)
1646 {
1647 m_log.InfoFormat("[SCENE]: " +
1648 "DelinkObjects(): Could not find a root prim out of {0} as given to a delink request!",
1649 primIds);
1650 }
1651 else
1652 {
1653 foreach (SceneObjectGroup g in parents)
1654 {
1655 g.TriggerScriptChangedEvent(Changed.LINK);
1656 }
1657 }
1658 }
1659 }
1660
1661 protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
1662 {
1663 UUID user = remoteClient.AgentId;
1664 UUID objid = UUID.Zero;
1665 SceneObjectPart obj = null;
1666
1667 List<EntityBase> EntityList = GetEntities();
1668 foreach (EntityBase ent in EntityList)
1669 {
1670 if (ent is SceneObjectGroup)
1671 {
1672 foreach (KeyValuePair<UUID, SceneObjectPart> subent in ((SceneObjectGroup)ent).Children)
1673 {
1674 if (subent.Value.LocalId == localID)
1675 {
1676 objid = subent.Key;
1677 obj = subent.Value;
1678 }
1679 }
1680 }
1681 }
1682
1683 //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
1684 //aka ObjectFlags.JointWheel = IncludeInSearch
1685
1686 //Permissions model: Object can be REMOVED from search IFF:
1687 // * User owns object
1688 //use CanEditObject
1689
1690 //Object can be ADDED to search IFF:
1691 // * User owns object
1692 // * Asset/DRM permission bit "modify" is enabled
1693 //use CanEditObjectPosition
1694
1695 // libomv will complain about PrimFlags.JointWheel being
1696 // deprecated, so we
1697 #pragma warning disable 0612
1698 if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user))
1699 {
1700 obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel);
1701 obj.ParentGroup.HasGroupChanged = true;
1702 }
1703 else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user))
1704 {
1705 obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel);
1706 obj.ParentGroup.HasGroupChanged = true;
1707 }
1708 #pragma warning restore 0612
1709 }
1710
1711 /// <summary>
1712 /// Duplicate the given object, Fire and Forget, No rotation, no return wrapper
1713 /// </summary>
1714 /// <param name="originalPrim"></param>
1715 /// <param name="offset"></param>
1716 /// <param name="flags"></param>
1717 protected internal void DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID)
1718 {
1719 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1720
1721 // SceneObjectGroup dupe = DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Zero);
1722 DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Identity);
1723 }
1724
1725 /// <summary>
1726 /// Duplicate the given object.
1727 /// </summary>
1728 /// <param name="originalPrim"></param>
1729 /// <param name="offset"></param>
1730 /// <param name="flags"></param>
1731 protected internal SceneObjectGroup DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1732 {
1733 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1734
1735 List<EntityBase> EntityList = GetEntities();
1736
1737 SceneObjectGroup originPrim = null;
1738 foreach (EntityBase ent in EntityList)
1739 {
1740 if (ent is SceneObjectGroup)
1741 {
1742 if (((SceneObjectGroup)ent).LocalId == originalPrim)
1743 {
1744 originPrim = (SceneObjectGroup)ent;
1745 break;
1746 }
1747 }
1748 }
1749
1750 if (originPrim != null)
1751 {
1752 if (m_parentScene.Permissions.CanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition))
1753 {
1754 SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID, true);
1755 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1756
1757 Entities.Add(copy);
1758
1759 // Since we copy from a source group that is in selected
1760 // state, but the copy is shown deselected in the viewer,
1761 // We need to clear the selection flag here, else that
1762 // prim never gets persisted at all. The client doesn't
1763 // think it's selected, so it will never send a deselect...
1764 copy.IsSelected = false;
1765
1766 m_numPrim += copy.Children.Count;
1767
1768 if (rot != Quaternion.Identity)
1769 {
1770 copy.UpdateGroupRotation(rot);
1771 }
1772
1773 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 0);
1774 copy.HasGroupChanged = true;
1775 copy.ScheduleGroupForFullUpdate();
1776
1777 // required for physics to update it's position
1778 copy.AbsolutePosition = copy.AbsolutePosition;
1779
1780 if (OnObjectDuplicate != null)
1781 OnObjectDuplicate(originPrim, copy);
1782
1783 return copy;
1784 }
1785 }
1786 else
1787 {
1788 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1789 }
1790
1791 return null;
1792 }
1793
1794 /// <summary>
1795 /// Calculates the distance between two Vector3s
1796 /// </summary>
1797 /// <param name="v1"></param>
1798 /// <param name="v2"></param>
1799 /// <returns></returns>
1800 protected internal float Vector3Distance(Vector3 v1, Vector3 v2)
1801 {
1802 // We don't really need the double floating point precision...
1803 // so casting it to a single
1804
1805 return
1806 (float)
1807 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));
1808 }
1809
1810 #endregion
1811
1812
1813 }
1814}