/// <summary> /// Add an object to the scene. This will both update the scene, and send information about the /// new object to all clients interested in the scene. /// </summary> /// <param name="sceneObject"></param> /// <param name="attachToBackup"> /// If true, the object is made persistent into the scene. /// If false, the object will not persist over server restarts /// </param> /// <returns>true if the object was added, false if an object with the same uuid was already in the scene /// </returns> public bool AddGroupToSceneGraph(SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool fromStorage, bool fromCrossing) { if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero) { m_log.ErrorFormat("[SceneGraph]: {0} AddGroupToSceneGraph failed, invalid or null object.", m_parentScene.RegionInfo.RegionName); return false; } foreach (SceneObjectPart part in sceneObject.Children.Values) { Vector3 scale = part.Shape.Scale; if (scale.X < SceneObjectPart.MIN_PART_SCALE) { scale.X = SceneObjectPart.MIN_PART_SCALE; sceneObject.HasGroupChanged = true; } if (scale.Y < SceneObjectPart.MIN_PART_SCALE) { scale.Y = SceneObjectPart.MIN_PART_SCALE; sceneObject.HasGroupChanged = true; } if (scale.Z < SceneObjectPart.MIN_PART_SCALE) { scale.Z = SceneObjectPart.MIN_PART_SCALE; sceneObject.HasGroupChanged = true; } if (m_parentScene.m_clampPrimSize) { if (scale.X > m_parentScene.m_maxNonphys) scale.X = m_parentScene.m_maxNonphys; if (scale.Y > m_parentScene.m_maxNonphys) scale.Y = m_parentScene.m_maxNonphys; if (scale.Z > m_parentScene.m_maxNonphys) scale.Z = m_parentScene.m_maxNonphys; } part.Shape.Scale = scale; } // if physical, make sure we're above the ground by at least 10 cm if ((sceneObject.RootPart.Flags & PrimFlags.Physics) != 0) { OpenSim.Framework.Geom.Box bbox = sceneObject.BoundingBox(); float groundHeight = m_parentScene.Heightmap.CalculateHeightAt(sceneObject.AbsolutePosition.X, sceneObject.AbsolutePosition.Y); if (sceneObject.AbsolutePosition.Z + bbox.Size.Z <= groundHeight) { Vector3 newPos = sceneObject.AbsolutePosition; newPos.Z = (bbox.Size.Z / 2.0f) + groundHeight + 0.1f; sceneObject.RootPart.SetGroupPositionDirect(newPos); } AddPhysicalObject(); } // rationalize the group: fix any inconsistency in locked bits, and // clear the default touch action of BUY for any objects not actually for sale, etc sceneObject.Rationalize(sceneObject.OwnerID, fromCrossing); sceneObject.AttachToScene(m_parentScene, fromStorage); // allocates the localIds for the prims if (!alreadyPersisted) { sceneObject.HasGroupChanged = true; } sceneObject.IsPersisted = alreadyPersisted; lock (sceneObject) { bool entityAdded = false; lock (m_dictionary_lock) { if (!Entities.ContainsKey(sceneObject.LocalId)) { Entities.Add(sceneObject); foreach (SceneObjectPart part in sceneObject.Children.Values) { SceneObjectPartsByFullID[part.UUID] = part; SceneObjectPartsByLocalID[part.LocalId] = part; } entityAdded = true; } } if (entityAdded) { m_numPrim += sceneObject.Children.Count; m_parentScene.EventManager.TriggerParcelPrimCountTainted(); if (attachToBackup) { sceneObject.AttachToBackup(); //this gets the new object on the taint list if (!alreadyPersisted) { sceneObject.HasGroupChanged = true; } m_parentScene.InspectForAutoReturn(sceneObject); } //This property doesn't work on rezzing, only on crossings or restarts if ((fromStorage || fromCrossing) && sceneObject.RootPart.KeyframeAnimation != null) { if (sceneObject.RootPart.KeyframeAnimation.CurrentCommand == KeyframeAnimation.Commands.Play) { if (!fromStorage) { //Offset the initial position so that it is in the new region's coordinates // (only if we are actually crossing from a different region) Vector3 regionOffset = sceneObject.AbsolutePosition - sceneObject.OriginalEnteringScenePosition; sceneObject.RootPart.KeyframeAnimation.InitialPosition += regionOffset; } sceneObject.AddKeyframedMotion(null, KeyframeAnimation.Commands.Play); } } if (OnObjectCreate != null) OnObjectCreate(sceneObject); return true; } } return false; }