/// <summary>
        ///     Parses ad request
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <param name="AgentId"></param>
        /// <returns></returns>
        public byte[] ProcessAdd(Stream request, OSHttpResponse response, UUID AgentId)
        {
            IScenePresence avatar;

            if (!m_scene.TryGetScenePresence(AgentId, out avatar))
                return MainServer.BlankResponse;

            OSDMap r = (OSDMap) OSDParser.Deserialize(HttpServerHandlerHelpers.ReadFully(request));
            UploadObjectAssetMessage message = new UploadObjectAssetMessage();
            try
            {
                message.Deserialize(r);
            }
            catch (Exception ex)
            {
                MainConsole.Instance.Error("[UploadObjectAssetModule]: Error deserializing message " + ex);
                message = null;
            }

            if (message == null)
            {
                response.StatusCode = 400; //501; //410; //404;
                return
                    Encoding.UTF8.GetBytes(
                        "<llsd><map><key>error</key><string>Error parsing Object</string></map></llsd>");
            }

            Vector3 pos = avatar.AbsolutePosition + (Vector3.UnitX*avatar.Rotation);
            Quaternion rot = Quaternion.Identity;
            Vector3 rootpos = Vector3.Zero;

            SceneObjectGroup rootGroup = null;
            SceneObjectGroup[] allparts = new SceneObjectGroup[message.Objects.Length];
            for (int i = 0; i < message.Objects.Length; i++)
            {
                UploadObjectAssetMessage.Object obj = message.Objects[i];
                PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();

                if (i == 0)
                {
                    rootpos = obj.Position;
                }

                // Combine the extraparams data into it's ugly blob again....
                //int bytelength = 0;
                //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
                //{
                //    bytelength += obj.ExtraParams[extparams].ExtraParamData.Length;
                //}
                //byte[] extraparams = new byte[bytelength];
                //int position = 0;

                //for (int extparams = 0; extparams < obj.ExtraParams.Length; extparams++)
                //{
                //    Buffer.BlockCopy(obj.ExtraParams[extparams].ExtraParamData, 0, extraparams, position,
                //                     obj.ExtraParams[extparams].ExtraParamData.Length);
                //
                //    position += obj.ExtraParams[extparams].ExtraParamData.Length;
                // }

                //pbs.ExtraParams = extraparams;
                foreach (UploadObjectAssetMessage.Object.ExtraParam extraParam in obj.ExtraParams)
                {
                    switch ((ushort) extraParam.Type)
                    {
                        case (ushort) ExtraParamType.Sculpt:
                            Primitive.SculptData sculpt = new Primitive.SculptData(extraParam.ExtraParamData, 0);

                            pbs.SculptEntry = true;

                            pbs.SculptTexture = obj.SculptID;
                            pbs.SculptType = (byte) sculpt.Type;

                            break;
                        case (ushort) ExtraParamType.Flexible:
                            Primitive.FlexibleData flex = new Primitive.FlexibleData(extraParam.ExtraParamData, 0);
                            pbs.FlexiEntry = true;
                            pbs.FlexiDrag = flex.Drag;
                            pbs.FlexiForceX = flex.Force.X;
                            pbs.FlexiForceY = flex.Force.Y;
                            pbs.FlexiForceZ = flex.Force.Z;
                            pbs.FlexiGravity = flex.Gravity;
                            pbs.FlexiSoftness = flex.Softness;
                            pbs.FlexiTension = flex.Tension;
                            pbs.FlexiWind = flex.Wind;
                            break;
                        case (ushort) ExtraParamType.Light:
                            Primitive.LightData light = new Primitive.LightData(extraParam.ExtraParamData, 0);
                            pbs.LightColorA = light.Color.A;
                            pbs.LightColorB = light.Color.B;
                            pbs.LightColorG = light.Color.G;
                            pbs.LightColorR = light.Color.R;
                            pbs.LightCutoff = light.Cutoff;
                            pbs.LightEntry = true;
                            pbs.LightFalloff = light.Falloff;
                            pbs.LightIntensity = light.Intensity;
                            pbs.LightRadius = light.Radius;
                            break;
                        case 0x40:
                            pbs.ReadProjectionData(extraParam.ExtraParamData, 0);
                            break;
                    }
                }
                pbs.PathBegin = (ushort) obj.PathBegin;
                pbs.PathCurve = (byte) obj.PathCurve;
                pbs.PathEnd = (ushort) obj.PathEnd;
                pbs.PathRadiusOffset = (sbyte) obj.RadiusOffset;
                pbs.PathRevolutions = (byte) obj.Revolutions;
                pbs.PathScaleX = (byte) obj.ScaleX;
                pbs.PathScaleY = (byte) obj.ScaleY;
                pbs.PathShearX = (byte) obj.ShearX;
                pbs.PathShearY = (byte) obj.ShearY;
                pbs.PathSkew = (sbyte) obj.Skew;
                pbs.PathTaperX = (sbyte) obj.TaperX;
                pbs.PathTaperY = (sbyte) obj.TaperY;
                pbs.PathTwist = (sbyte) obj.Twist;
                pbs.PathTwistBegin = (sbyte) obj.TwistBegin;
                pbs.HollowShape = (HollowShape) obj.ProfileHollow;
                pbs.PCode = (byte) PCode.Prim;
                pbs.ProfileBegin = (ushort) obj.ProfileBegin;
                pbs.ProfileCurve = (byte) obj.ProfileCurve;
                pbs.ProfileEnd = (ushort) obj.ProfileEnd;
                pbs.Scale = obj.Scale;
                pbs.State = 0;
                SceneObjectPart prim = new SceneObjectPart(AgentId, pbs, obj.Position, obj.Rotation,
                                                           Vector3.Zero, obj.Name)
                                           {
                                               UUID = UUID.Random(),
                                               CreatorID = AgentId,
                                               OwnerID = AgentId,
                                               GroupID = obj.GroupID
                                           };
                prim.LastOwnerID = prim.OwnerID;
                prim.CreationDate = Util.UnixTimeSinceEpoch();
                prim.Name = obj.Name;
                prim.Description = "";

                prim.PayPrice[0] = -2;
                prim.PayPrice[1] = -2;
                prim.PayPrice[2] = -2;
                prim.PayPrice[3] = -2;
                prim.PayPrice[4] = -2;
                Primitive.TextureEntry tmp =
                    new Primitive.TextureEntry(UUID.Parse("89556747-24cb-43ed-920b-47caed15465f"));

                for (int j = 0; j < obj.Faces.Length; j++)
                {
                    UploadObjectAssetMessage.Object.Face face = obj.Faces[j];

                    Primitive.TextureEntryFace primFace = tmp.CreateFace((uint) j);

                    primFace.Bump = face.Bump;
                    primFace.RGBA = face.Color;
                    primFace.Fullbright = face.Fullbright;
                    primFace.Glow = face.Glow;
                    primFace.TextureID = face.ImageID;
                    primFace.Rotation = face.ImageRot;
                    primFace.MediaFlags = ((face.MediaFlags & 1) != 0);

                    primFace.OffsetU = face.OffsetS;
                    primFace.OffsetV = face.OffsetT;
                    primFace.RepeatU = face.ScaleS;
                    primFace.RepeatV = face.ScaleT;
                    primFace.TexMapType = (MappingType) (face.MediaFlags & 6);
                }
                pbs.TextureEntry = tmp.GetBytes();
                prim.Shape = pbs;
                prim.Scale = obj.Scale;

                SceneObjectGroup grp = new SceneObjectGroup(prim, m_scene);

                prim.ParentID = 0;
                if (i == 0)
                    rootGroup = grp;

                grp.AbsolutePosition = obj.Position;
                prim.SetRotationOffset(true, obj.Rotation, true);

                grp.RootPart.IsAttachment = false;

                string reason;
                if (m_scene.Permissions.CanRezObject(1, avatar.UUID, pos, out reason))
                {
                    m_scene.SceneGraph.AddPrimToScene(grp);
                    grp.AbsolutePosition = obj.Position;
                }
                else
                {
                    //Stop now then
                    avatar.ControllingClient.SendAlertMessage("You do not have permission to rez objects here: " +
                                                              reason);
                    return MainServer.BlankResponse;
                }
                allparts[i] = grp;
            }

            for (int j = 1; j < allparts.Length; j++)
            {
                rootGroup.LinkToGroup(allparts[j]);
            }

            rootGroup.ScheduleGroupUpdate(PrimUpdateFlags.ForcedFullUpdate);
            pos = m_scene.SceneGraph.GetNewRezLocation(Vector3.Zero, rootpos, UUID.Zero, rot, 1, 1, true,
                                                       allparts[0].GroupScale(), false);

            OSDMap map = new OSDMap();
            map["local_id"] = allparts[0].LocalId;
            return OSDParser.SerializeLLSDXmlBytes(map);
        }
        /// <summary>
        /// </summary>
        /// <param name="assetName"></param>
        /// <param name="assetDescription"></param>
        /// <param name="assetID"></param>
        /// <param name="inventoryItem"></param>
        /// <param name="parentFolder"></param>
        /// <param name="data"></param>
        /// <param name="inventoryType"></param>
        /// <param name="assetType"></param>
        /// <param name="everyone_mask"></param>
        /// <param name="group_mask"></param>
        /// <param name="next_owner_mask"></param>
        public UUID UploadCompleteHandler(string assetName, string assetDescription, UUID assetID,
                                          UUID inventoryItem, UUID parentFolder, byte[] data, string inventoryType,
                                          string assetType, uint everyone_mask, uint group_mask, uint next_owner_mask)
        {
            sbyte assType = 0;
            sbyte inType = 0;

            switch (inventoryType)
            {
                case "sound":
                    inType = 1;
                    assType = 1;
                    break;
                case "animation":
                    inType = 19;
                    assType = 20;
                    break;
                case "snapshot":
                    inType = 15;
                    assType = 0;
                    break;
                case "wearable":
                    inType = 18;
                    switch (assetType)
                    {
                        case "bodypart":
                            assType = 13;
                            break;
                        case "clothing":
                            assType = 5;
                            break;
                    }
                    break;
                case "object":
                    {
                        inType = (sbyte) InventoryType.Object;
                        assType = (sbyte) AssetType.Object;

                        List<Vector3> positions = new List<Vector3>();
                        List<Quaternion> rotations = new List<Quaternion>();
                        OSDMap request = (OSDMap) OSDParser.DeserializeLLSDXml(data);
                        OSDArray instance_list = (OSDArray) request["instance_list"];
                        OSDArray mesh_list = (OSDArray) request["mesh_list"];
                        OSDArray texture_list = (OSDArray) request["texture_list"];
                        SceneObjectGroup grp = null;

                        List<UUID> textures = new List<UUID>();
                        foreach (
                            AssetBase textureAsset in
                                texture_list.Select(t => new AssetBase(UUID.Random(), assetName, AssetType.Texture,
                                                                       m_agentID) { Data = t.AsBinary() }))
                        {
                            textureAsset.ID = m_assetService.Store(textureAsset);
                            textures.Add(textureAsset.ID);
                        }

                        InventoryFolderBase meshFolder = m_inventoryService.GetFolderForType(m_agentID,
                                                                                             InventoryType.Mesh,
                                                                                             AssetType.Mesh);
                        for (int i = 0; i < mesh_list.Count; i++)
                        {
                            PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateBox();

                            Primitive.TextureEntry textureEntry =
                                new Primitive.TextureEntry(Primitive.TextureEntry.WHITE_TEXTURE);
                            OSDMap inner_instance_list = (OSDMap) instance_list[i];

                            OSDArray face_list = (OSDArray) inner_instance_list["face_list"];
                            for (uint face = 0; face < face_list.Count; face++)
                            {
                                OSDMap faceMap = (OSDMap) face_list[(int) face];
                                Primitive.TextureEntryFace f = pbs.Textures.CreateFace(face);
                                if (faceMap.ContainsKey("fullbright"))
                                    f.Fullbright = faceMap["fullbright"].AsBoolean();
                                if (faceMap.ContainsKey("diffuse_color"))
                                    f.RGBA = faceMap["diffuse_color"].AsColor4();

                                int textureNum = faceMap["image"].AsInteger();
                                float imagerot = faceMap["imagerot"].AsInteger();
                                float offsets = (float) faceMap["offsets"].AsReal();
                                float offsett = (float) faceMap["offsett"].AsReal();
                                float scales = (float) faceMap["scales"].AsReal();
                                float scalet = (float) faceMap["scalet"].AsReal();

                                if (imagerot != 0)
                                    f.Rotation = imagerot;
                                if (offsets != 0)
                                    f.OffsetU = offsets;
                                if (offsett != 0)
                                    f.OffsetV = offsett;
                                if (scales != 0)
                                    f.RepeatU = scales;
                                if (scalet != 0)
                                    f.RepeatV = scalet;
                                f.TextureID = textures.Count > textureNum
                                                  ? textures[textureNum]
                                                  : Primitive.TextureEntry.WHITE_TEXTURE;
                                textureEntry.FaceTextures[face] = f;
                            }
                            pbs.TextureEntry = textureEntry.GetBytes();

                            AssetBase meshAsset = new AssetBase(UUID.Random(), assetName, AssetType.Mesh, m_agentID)
                                                      {Data = mesh_list[i].AsBinary()};
                            meshAsset.ID = m_assetService.Store(meshAsset);

                            if (meshFolder == null)
                            {
                                m_inventoryService.CreateUserInventory(m_agentID, false);
                                meshFolder = m_inventoryService.GetFolderForType(m_agentID, InventoryType.Mesh,
                                                                                 AssetType.Mesh);
                            }

                            InventoryItemBase itemBase = new InventoryItemBase(UUID.Random(), m_agentID)
                                                             {
                                                                 AssetType = (sbyte) AssetType.Mesh,
                                                                 AssetID = meshAsset.ID,
                                                                 CreatorId = m_agentID.ToString(),
                                                                 Folder = meshFolder.ID,
                                                                 InvType = (int) InventoryType.Texture,
                                                                 Name = "(Mesh) - " + assetName,
                                                                 CurrentPermissions = (uint) PermissionMask.All,
                                                                 BasePermissions = (uint) PermissionMask.All,
                                                                 EveryOnePermissions = everyone_mask,
                                                                 GroupPermissions = group_mask,
                                                                 NextPermissions = next_owner_mask
                                                             };
                            //Bad... but whatever
                            m_inventoryService.AddItem(itemBase);

                            pbs.SculptEntry = true;
                            pbs.SculptTexture = meshAsset.ID;
                            pbs.SculptType = (byte) SculptType.Mesh;
                            pbs.SculptData = meshAsset.Data;

                            Vector3 position = inner_instance_list["position"].AsVector3();
                            Vector3 scale = inner_instance_list["scale"].AsVector3();
                            Quaternion rotation = inner_instance_list["rotation"].AsQuaternion();

                            int physicsShapeType = inner_instance_list["physics_shape_type"].AsInteger();
                            int material = inner_instance_list["material"].AsInteger();
                            int mesh = inner_instance_list["mesh"].AsInteger();

                            SceneObjectPart prim = new SceneObjectPart(m_agentID, pbs, position, Quaternion.Identity,
                                                                       Vector3.Zero, assetName)
                                                       {Scale = scale, AbsolutePosition = position};

                            rotations.Add(rotation);
                            positions.Add(position);
                            prim.UUID = UUID.Random();
                            prim.CreatorID = m_agentID;
                            prim.OwnerID = m_agentID;
                            prim.GroupID = UUID.Zero;
                            prim.LastOwnerID = m_agentID;
                            prim.CreationDate = Util.UnixTimeSinceEpoch();
                            prim.Name = assetName;
                            prim.Description = "";
                            prim.PhysicsType = (byte) physicsShapeType;

                            prim.BaseMask = (uint) PermissionMask.All;
                            prim.EveryoneMask = everyone_mask;
                            prim.NextOwnerMask = next_owner_mask;
                            prim.GroupMask = group_mask;
                            prim.OwnerMask = (uint) PermissionMask.All;

                            if (grp == null)
                                grp = new SceneObjectGroup(prim, null);
                            else
                                grp.AddChild(prim, i + 1);
                            grp.RootPart.IsAttachment = false;
                        }
                        if (grp.ChildrenList.Count > 1) //Fix first link #
                            grp.RootPart.LinkNum++;

                        Vector3 rootPos = positions[0];
                        grp.SetAbsolutePosition(false, rootPos);
                        for (int i = 0; i < positions.Count; i++)
                        {
                            Vector3 offset = positions[i] - rootPos;
                            grp.ChildrenList[i].SetOffsetPosition(offset);
                        }
                        //grp.Rotation = rotations[0];
                        for (int i = 0; i < rotations.Count; i++)
                        {
                            if (i != 0)
                                grp.ChildrenList[i].SetRotationOffset(false, rotations[i], false);
                        }
                        grp.UpdateGroupRotationR(rotations[0]);
                        data = Encoding.ASCII.GetBytes(grp.ToXml2());
                    }
                    break;
            }
            AssetBase asset = new AssetBase(assetID, assetName, (AssetType)assType, m_agentID) { Data = data };
            asset.ID = m_assetService.Store(asset);
            assetID = asset.ID;

            InventoryItemBase item = new InventoryItemBase
                                         {
                                             Owner = m_agentID,
                                             CreatorId = m_agentID.ToString(),
                                             ID = inventoryItem,
                                             AssetID = asset.ID,
                                             Description = assetDescription,
                                             Name = assetName,
                                             AssetType = assType,
                                             InvType = inType,
                                             Folder = parentFolder,
                                             CurrentPermissions = (uint) PermissionMask.All,
                                             BasePermissions = (uint) PermissionMask.All,
                                             EveryOnePermissions = everyone_mask,
                                             NextPermissions = next_owner_mask,
                                             GroupPermissions = group_mask,
                                             CreationDate = Util.UnixTimeSinceEpoch()
                                         };

            m_inventoryService.AddItem(item);

            return assetID;
        }
 /// <summary>
 ///     Constructor
 /// </summary>
 /// <param name="part">
 ///     A <see cref="SceneObjectPart" />
 /// </param>
 public SceneObjectPartInventory(SceneObjectPart part)
 {
     m_part = part;
 }
        private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation,
            int linkNum)
        {
            Quaternion WorldRot = oldGroupRotation*part.GetRotationOffset();

            // first fix from old local to world
            // position
            Vector3 axPos = part.OffsetPosition;
            axPos *= oldGroupRotation;
            part.SetGroupPosition(oldGroupPosition + axPos);
            //offset
            part.SetRotationOffset(false, WorldRot, false);

            // have it in world coords lets fix other things
            m_scene.SceneGraph.LinkPartToSOG(this, part, linkNum);
            part.CreateSelected = true;

            // now lets move to the new parent frame
            Quaternion rootRotation = m_rootPart.GetRotationOffset();

            Vector3 pos = part.GroupPosition - AbsolutePosition;
            pos *= Quaternion.Inverse(rootRotation);
            part.SetOffsetPosition(pos);

            Quaternion newRot = Quaternion.Inverse(rootRotation)*WorldRot;
            part.SetRotationOffset(false, newRot, false);
            // caller will tell the rest about this position changes..
        }
        /// <summary>
        ///     Add a child to the group, set the parent id's and then set the link number
        /// </summary>
        /// <param name="child"></param>
        /// <param name="linkNum"></param>
        /// <returns></returns>
        public bool AddChild(ISceneChildEntity child, int linkNum)
        {
            lock (m_partsLock)
            {
                if (child is SceneObjectPart)
                {
                    SceneObjectPart part = (SceneObjectPart) child;
                    //Root part is first
                    if (m_partsList.Count == 0)
                    {
                        m_rootPart = part;
                    }
                    //Set the parent prim
                    part.SetParent(this);
                    if (m_rootPart.LocalId != 0 && !part.IsRoot)
                        part.SetParentLocalId(m_rootPart.LocalId);
                    else
                        part.SetParentLocalId(0);

                    //Fix the link num
                    part.LinkNum = linkNum;

                    if (!m_parts.ContainsKey(child.UUID))
                    {
                        m_parts.Add(child.UUID, part);
                        m_partsList.Add(part);
                        m_ValidgrpOOB = false;
                    }
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        ///     Set a part to act as the root part for this scene object
        /// </summary>
        /// <param name="part"></param>
        public void SetRootPart(SceneObjectPart part)
        {
            if (part == null)
                throw new ArgumentNullException("part");

            m_rootPart = part;
            if (!IsAttachment)
                part.SetParentLocalId(0);
            AddChild(part, part.LinkNum);
        }
        /// <summary>
        ///     Fix all the vehicle params after rebuilding the representation
        /// </summary>
        /// <param name="part"></param>
        private void FixVehicleParams(SceneObjectPart part)
        {
            part.PhysActor.VehicleType = part.VehicleType;

            // OSD o = part.GetComponentState("VehicleParameters");
            foreach (OSD param in part.VehicleFlags)
            {
                part.PhysActor.VehicleFlags(param.AsInteger(), false);
            }

            foreach (KeyValuePair<string, OSD> param in part.VehicleParameters)
            {
                if (param.Value.Type == OSDType.Real)
                    part.PhysActor.VehicleFloatParam(int.Parse(param.Key), (float) param.Value.AsReal());
                else if (param.Value.Type == OSDType.Array)
                {
                    OSDArray a = (OSDArray) param.Value;
                    if (a.Count == 3)
                        part.PhysActor.VehicleVectorParam(int.Parse(param.Key), param.Value.AsVector3());
                    else
                        part.PhysActor.VehicleRotationParam(int.Parse(param.Key), param.Value.AsQuaternion());
                }
            }
        }
 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
 {
     part.StoreUndoState();
     part.OnGrab(offsetPos, remoteClient);
 }
 public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
 {
     part.OwnerID = cAgentID;
     part.GroupID = cGroupID;
 }
        /// <summary>
        ///     Link the prims in a given group to this group
        /// </summary>
        /// <param name="grp">The group of prims which should be linked to this group</param>
        public void LinkToGroup(ISceneEntity grp)
        {
            //MainConsole.Instance.DebugFormat(
            //    "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
            //    objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);

            if (!(grp is SceneObjectGroup))
                return;
            SceneObjectGroup objectGroup = (SceneObjectGroup) grp;

            if (m_rootPart.PhysActor != null)
                m_rootPart.PhysActor.BlockPhysicalReconstruction = true;

            SceneObjectPart linkPart = objectGroup.m_rootPart;

            Vector3 oldGroupPosition = linkPart.GroupPosition;
            Quaternion oldRootRotation = linkPart.GetRotationOffset();
            Quaternion parentRot = m_rootPart.GetRotationOffset();

            linkPart.SetGroupPosition(AbsolutePosition); // just change it without doing anything else

            Vector3 axPos = oldGroupPosition - AbsolutePosition;
            axPos *= Quaternion.Inverse(parentRot);
            linkPart.SetOffsetPosition(axPos);

            Quaternion newRot = Quaternion.Inverse(parentRot)*oldRootRotation;
            linkPart.SetRotationOffset(false, newRot, false);

            //Fix the link number for the root
            if (m_rootPart.LinkNum == 0)
                m_rootPart.LinkNum = 1;

            SceneObjectPart[] objectGroupChildren = new SceneObjectPart[objectGroup.ChildrenList.Count];
            objectGroup.ChildrenList.CopyTo(objectGroupChildren, 0);

            //Destroy the old group
            m_scene.SceneGraph.DeleteEntity(objectGroup);
            objectGroup.IsDeleted = true;
            objectGroup.ClearChildren();

            lock (m_partsLock)
            {
                int linkNum = 2;
                //Add the root part to our group!
                m_scene.SceneGraph.LinkPartToSOG(this, linkPart, linkNum++);
                linkPart.CreateSelected = true;
                linkPart.FixOffsetPosition(linkPart.OffsetPosition, true); // nasty let all know about where this is
                // let physics link it
                if (linkPart.PhysActor != null && m_rootPart.PhysActor != null)
                {
                    if (linkPart.PhysicsType != (byte) PhysicsShapeType.None)
                        linkPart.PhysActor.link(m_rootPart.PhysActor);
                }
                //rest of parts
                foreach (
                    SceneObjectPart part in objectGroupChildren.Where(part => part.UUID != objectGroup.m_rootPart.UUID))
                {
                    LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
                    part.FixOffsetPosition(part.OffsetPosition, true);
                    if (part.PhysActor != null && m_rootPart.PhysActor != null)
                        part.PhysActor.link(m_rootPart.PhysActor);
                }
            }
            // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
            // position of linkset prims.  IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
            // unmoved prims!
            m_ValidgrpOOB = false;
            ResetChildPrimPhysicsPositions();

            if (m_rootPart.PhysActor != null)
                m_rootPart.PhysActor.BlockPhysicalReconstruction = false;
        }
        /// <summary>
        ///     Add this child to the group and set the parent ID's,
        ///     but do NOT set the link number,
        ///     the caller wants to deal with it if they call this
        /// </summary>
        /// <param name="child"></param>
        /// <returns></returns>
        public bool LinkChild(ISceneChildEntity child)
        {
            lock (m_partsLock)
            {
                if (child is SceneObjectPart)
                {
                    SceneObjectPart part = (SceneObjectPart) child;
                    //Root part is first
                    if (m_partsList.Count == 0)
                    {
                        m_rootPart = part;
                    }
                    //Set the parent prim
                    part.SetParent(this);
                    part.SetParentLocalId(m_rootPart.LocalId);

                    if (!m_parts.ContainsKey(child.UUID))
                    {
                        m_parts.Add(child.UUID, part);
                        m_partsList.Add(part);
                        m_ValidgrpOOB = false;
                    }
                    m_partsList.Sort(m_scene.SceneGraph.LinkSetSorter);
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        ///     Constructor.  This object is added to the scene later via AttachToScene()
        /// </summary>
        public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape, string name,
            IScene scene)
            : this(scene)
        {
            SceneObjectPart part = new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero, name);
            SetRootPart(part);

            //This has to be set, otherwise it will break things like rezzing objects in an area where crossing is disabled, but rez isn't
            m_lastSignificantPosition = pos;

            m_ValidgrpOOB = false;
        }
        public SceneObjectGroup(SceneObjectPart part, IScene scene, bool AddToScene)
            : this(scene)
        {
            if (!AddToScene)
                m_isDeleted = true;

            SetRootPart(part);
            part.Scale = part.Shape.Scale; // temporary hack to update oobb
            m_ValidgrpOOB = false;
        }
 /// <summary>
 ///     This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
 ///     The original SceneObjectPart will be used rather than a copy, preserving
 ///     its existing localID and UUID.
 /// </summary>
 public SceneObjectGroup(SceneObjectPart part, IScene scene)
     : this(scene)
 {
     SetRootPart(part);
     part.Scale = part.Shape.Scale; // temporary hack to update oobb
     m_ValidgrpOOB = false;
 }