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