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