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