/// <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("Cannot give SceneObjectGroup a null root SceneObjectPart"); m_rootPart = part; if (!IsAttachment) part.SetParentLocalId(0); AddChild(part, part.LinkNum); }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object m_scene.SceneGraph.DeLinkPartFromEntity(this, linkPart); /* this is already done in DeLinkPartFromEntity if (m_partsList.Count == 1 && RootPart != null) //Single prim is left RootPart.LinkNum = 0; else { lock (m_partsLock) { foreach (SceneObjectPart p in m_partsList) { if (p.LinkNum > linkPart.LinkNum) p.LinkNum--; } } } */ linkPart.SetParentLocalId(0); linkPart.LinkNum = 0; if (linkPart.PhysActor != null) { m_scene.SceneGraph.PhysicsScene.RemovePrim(linkPart.PhysActor); // linkPart.PhysActor.delink(); } // We need to reset the child part's position // ready for life as a separate object after being a part of another object Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.SetOffsetPosition(axPos); linkPart.FixGroupPosition(AbsolutePosition + linkPart.OffsetPosition,false); linkPart.FixOffsetPosition(Vector3.Zero, false); linkPart.RotationOffset = worldRot; SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart, Scene); m_scene.SceneGraph.DelinkPartToScene(objectGroup); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; //This is already set multiple places, no need to do it again //HasGroupChanged = true; //We need to send this so that we don't have issues with the client not realizing that the prims were unlinked ScheduleGroupUpdate(PrimUpdateFlags.FullUpdate); return objectGroup; }
/// <summary> /// Set the property's value based on the value maintained in SyncInfoManager. /// Assumption: caller will call ScheduleFullUpdate to enqueue updates properly to /// update viewers. /// This function should only be triggered when a prim update is received (i.e. /// triggered by remote update instead of local update). /// </summary> /// <param name="part"></param> /// <param name="property"></param> /// /* private void SetPropertyValue(SceneObjectPart part, SyncedProperty syncedProperty) { //DebugLog.WarnFormat("[SYNC INFO PRIM] SetPropertyValue(part={0}, property={1})", part.UUID, property.ToString()); if (part == null) return; SyncableProperties.Type property = syncedProperty.Property; // If this is a physical property but the part's PhysActor is null, then we can't set it. if (SyncableProperties.PhysActorProperties.Contains(property) && syncedProperty == null && part.PhysActor == null) { // DebugLog.WarnFormat("{0}: SetPropertyValue: property {1} not in record.", LogHeader, property.ToString()); //For phantom prims, they don't have physActor properties, so for those properties, simply return return; } if (syncedProperty == null) { DebugLog.ErrorFormat("{0}: SetPropertyValue: property {1} not in sync cache for uuid {2}. CSP.Count={3} ", LogHeader, property, UUID, CurrentlySyncedProperties.Count); return; } SetPropertyValue(part, property, syncedProperty); } */ private void SetPropertyValue(SceneObjectPart part, SyncedProperty pSyncInfo) { if (part == null || pSyncInfo == null) return; SyncableProperties.Type property = pSyncInfo.Property; Object LastUpdateValue = pSyncInfo.LastUpdateValue; // Do not generate undo information for this update part.IgnoreUndoUpdate = true; switch (property) { /////////////////////// //SOP properties /////////////////////// case SyncableProperties.Type.AggregateScriptEvents: part.AggregateScriptEvents = (scriptEvents)(int)LastUpdateValue; //DebugLog.DebugFormat("set {0} value to be {1}", property.ToString(), part.AggregateScriptEvents); // Have the part process the new values for collision events. part.SubscribeForCollisionEvents(); break; case SyncableProperties.Type.AllowedDrop: part.AllowedDrop = (bool)LastUpdateValue; break; case SyncableProperties.Type.AngularVelocity: part.AngularVelocity = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.AttachedAvatar: //part.AttachedAvatar = (UUID)LastUpdateValue; UUID attachedAvatar = (UUID)LastUpdateValue; if (part.ParentGroup != null && !part.ParentGroup.AttachedAvatar.Equals(attachedAvatar)) { part.ParentGroup.AttachedAvatar = attachedAvatar; if (attachedAvatar != UUID.Zero) { ScenePresence avatar = Scene.GetScenePresence(attachedAvatar); //It is possible that the avatar has not been fully //created locally when attachment objects are sync'ed. //So we need to check if the avatar already exists. //If not, handling of NewPresence will evetually trigger //calling of SetParentLocalId. if (avatar != null) { if (part.ParentGroup != null) { part.ParentGroup.RootPart.SetParentLocalId(avatar.LocalId); } else { //If this SOP is not a part of group yet, record the //avatar's localID for now. If this SOP is rootpart of //the group, then the localID is the right setting; //otherwise, this SOP will be linked to the SOG it belongs //to later, and that will rewrite the parent localID. part.SetParentLocalId(avatar.LocalId); } } } else { part.SetParentLocalId(0); } } break; case SyncableProperties.Type.AttachedPos: part.AttachedPos = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.AttachmentPoint: //part.AttachmentPoint = (uint)LastUpdateValue; //part.SetAttachmentPoint((uint)LastUpdateValue); if (part.ParentGroup != null) part.ParentGroup.AttachmentPoint = ((uint)LastUpdateValue); break; case SyncableProperties.Type.BaseMask: part.BaseMask = (uint)LastUpdateValue; break; case SyncableProperties.Type.Category: part.Category = (uint)LastUpdateValue; break; case SyncableProperties.Type.ClickAction: part.ClickAction = (byte)LastUpdateValue; break; case SyncableProperties.Type.CollisionSound: SetSOPCollisionSound(part, (UUID)LastUpdateValue); break; case SyncableProperties.Type.CollisionSoundVolume: part.CollisionSoundVolume = (float)LastUpdateValue; break; case SyncableProperties.Type.Color: part.Color = PropertySerializer.DeSerializeColor((string)LastUpdateValue); break; case SyncableProperties.Type.CreationDate: part.CreationDate = (int)LastUpdateValue; break; case SyncableProperties.Type.CreatorData: part.CreatorData = (string)LastUpdateValue; break; case SyncableProperties.Type.CreatorID: part.CreatorID = (UUID)LastUpdateValue; break; case SyncableProperties.Type.Description: part.Description = (string)LastUpdateValue; break; case SyncableProperties.Type.EveryoneMask: part.EveryoneMask = (uint)LastUpdateValue; break; case SyncableProperties.Type.Flags: SetSOPFlags(part, (PrimFlags)(int)LastUpdateValue); break; case SyncableProperties.Type.FolderID: part.FolderID = (UUID)LastUpdateValue; break; //Skip SyncableProperties.FullUpdate, which should be handled seperatedly case SyncableProperties.Type.GroupID: part.GroupID = (UUID)LastUpdateValue; break; case SyncableProperties.Type.GroupMask: part.GroupMask = (uint)LastUpdateValue; break; case SyncableProperties.Type.GroupPosition: part.GroupPosition = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.InventorySerial: part.InventorySerial = (uint)LastUpdateValue; break; case SyncableProperties.Type.IsAttachment: if (part.ParentGroup != null) part.ParentGroup.IsAttachment = (bool)LastUpdateValue; break; case SyncableProperties.Type.LastOwnerID: part.LastOwnerID = (UUID)LastUpdateValue; break; case SyncableProperties.Type.LinkNum: part.LinkNum = (int)LastUpdateValue; break; case SyncableProperties.Type.LocalFlags: part.LocalFlags = (PrimFlags)(int)LastUpdateValue; break; case SyncableProperties.Type.LocalId: part.LocalId = (uint)LastUpdateValue; break; case SyncableProperties.Type.Material: part.Material = (byte)LastUpdateValue; break; case SyncableProperties.Type.MediaUrl: part.MediaUrl = (string)LastUpdateValue; break; case SyncableProperties.Type.Name: part.Name = (string)LastUpdateValue; break; case SyncableProperties.Type.NextOwnerMask: part.NextOwnerMask = (uint)LastUpdateValue; break; case SyncableProperties.Type.ObjectSaleType: part.ObjectSaleType = (byte)LastUpdateValue; break; case SyncableProperties.Type.OffsetPosition: part.OffsetPosition = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.OwnerID: part.OwnerID = (UUID)LastUpdateValue; break; case SyncableProperties.Type.OwnerMask: part.OwnerMask = (uint)LastUpdateValue; break; case SyncableProperties.Type.OwnershipCost: part.OwnershipCost = (int)LastUpdateValue; break; case SyncableProperties.Type.ParticleSystem: //byte[], return a cloned copy //byte[] pValue = (byte[])LastUpdateValue; //part.ParticleSystem = (byte[])pValue.Clone(); part.ParticleSystem = (byte[])LastUpdateValue; break; case SyncableProperties.Type.PassTouches: part.PassTouches = (bool)LastUpdateValue; break; case SyncableProperties.Type.RotationOffset: part.RotationOffset = (Quaternion)LastUpdateValue; break; case SyncableProperties.Type.SalePrice: part.SalePrice = (int)LastUpdateValue; break; case SyncableProperties.Type.Scale: part.Scale = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.ScriptAccessPin: part.ScriptAccessPin = (int)LastUpdateValue; break; case SyncableProperties.Type.Shape: PrimitiveBaseShape shapeVal = PropertySerializer.DeSerializeShape((string)LastUpdateValue); // Scale and State are actually synchronized as part properties so existing values // should be preserved when updating a shape if (part.Shape != null) { shapeVal.Scale = part.Shape.Scale; shapeVal.State = part.Shape.State; } part.Shape = shapeVal; break; case SyncableProperties.Type.SitName: part.SitName = (string)LastUpdateValue; break; case SyncableProperties.Type.SitTargetOrientation: part.SitTargetOrientation = (Quaternion)LastUpdateValue; break; case SyncableProperties.Type.SitTargetOrientationLL: part.SitTargetOrientationLL = (Quaternion)LastUpdateValue; break; case SyncableProperties.Type.SitTargetPosition: part.SitTargetPosition = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.SitTargetPositionLL: part.SitTargetPositionLL = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.SOP_Acceleration: part.Acceleration = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.Sound: part.Sound = (UUID)LastUpdateValue; break; case SyncableProperties.Type.TaskInventory: TaskInventoryDictionary taskVal = PropertySerializer.DeSerializeTaskInventory((string)LastUpdateValue); if (taskVal != null) { part.TaskInventory = taskVal; //Mark the inventory as has changed, for proper backup part.Inventory.ForceInventoryPersistence(); } break; case SyncableProperties.Type.Text: part.Text = (string)LastUpdateValue; break; case SyncableProperties.Type.TextureAnimation: //byte[], return a cloned copy //byte[] tValue = (byte[])LastUpdateValue; //part.TextureAnimation = (byte[])tValue.Clone(); part.TextureAnimation = (byte[])LastUpdateValue; break; case SyncableProperties.Type.TouchName: part.TouchName = (string)LastUpdateValue; break; /* case SyncableProperties.Type.UpdateFlag: part.UpdateFlag = (UpdateRequired)LastUpdateValue; break; */ case SyncableProperties.Type.Velocity: part.Velocity = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.VolumeDetectActive: //part.ParentGroup.UpdatePrimFlagsBySync(part.LocalId, part., IsTemporary, IsPhantom, part.VolumeDetectActive); bool isVD = (bool)LastUpdateValue; //VD DEBUG //DebugLog.DebugFormat("VolumeDetectActive updated on SOP {0}, to {1}", part.Name, isVD); if (part.ParentGroup != null) { //VD DEBUG //DebugLog.DebugFormat("calling ScriptSetVolumeDetectBySync"); //DSL part.ParentGroup.ScriptSetVolumeDetectBySync(isVD); } part.VolumeDetectActive = isVD; //DSL part.aggregateScriptEventSubscriptions(); break; /////////////////////// //PhysActor properties /////////////////////// case SyncableProperties.Type.Buoyancy: if (part.PhysActor != null) part.PhysActor.Buoyancy = (float)LastUpdateValue; break; case SyncableProperties.Type.Flying: if (part.PhysActor != null) part.PhysActor.Flying = (bool)LastUpdateValue; break; case SyncableProperties.Type.Force: if (part.PhysActor != null) part.PhysActor.Force = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.IsColliding: if (part.PhysActor != null) part.PhysActor.IsColliding = (bool)LastUpdateValue; break; case SyncableProperties.Type.CollidingGround: if (part.PhysActor != null) part.PhysActor.CollidingGround = (bool)LastUpdateValue; break; case SyncableProperties.Type.Kinematic: if (part.PhysActor != null) part.PhysActor.Kinematic = (bool)LastUpdateValue; break; case SyncableProperties.Type.Orientation: if (part.PhysActor != null) part.PhysActor.Orientation = (Quaternion)LastUpdateValue; break; case SyncableProperties.Type.PA_Acceleration: if (part.PhysActor != null) part.PhysActor.Acceleration = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.PA_Velocity: if (part.PhysActor != null) part.PhysActor.Velocity = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.PA_TargetVelocity: if (part.PhysActor != null) part.PhysActor.TargetVelocity = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.Position: if (part.PhysActor != null) part.PhysActor.Position = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.RotationalVelocity: if (part.PhysActor != null) part.PhysActor.RotationalVelocity = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.Size: if (part.PhysActor != null) part.PhysActor.Size = (Vector3)LastUpdateValue; break; case SyncableProperties.Type.Torque: if (part.PhysActor != null) part.PhysActor.Torque = (Vector3)LastUpdateValue; break; /////////////////////// //SOG properties /////////////////////// case SyncableProperties.Type.AbsolutePosition: SetSOPAbsolutePosition(part, pSyncInfo); break; case SyncableProperties.Type.IsSelected: if (part.ParentGroup != null) part.ParentGroup.IsSelected = (bool)LastUpdateValue; break; } // Do not generate undo information for this update part.IgnoreUndoUpdate = false; //Calling ScheduleFullUpdate to trigger enqueuing updates for sync'ing (relay sync nodes need to do so) //part.ScheduleFullUpdate(new List<SyncableProperties.Type>() { property }); }
private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) { Quaternion parentRot = oldGroupRotation; Quaternion oldRot = part.RotationOffset; Quaternion worldRot = parentRot * oldRot; parentRot = oldGroupRotation; Vector3 axPos = part.OffsetPosition; axPos *= parentRot; part.OffsetPosition = axPos; part.GroupPosition = oldGroupPosition + part.OffsetPosition; part.OffsetPosition = Vector3.Zero; part.RotationOffset = worldRot; part.SetParent(this); part.SetParentLocalId(m_rootPart.LocalId); UpdatePartList(part); part.LinkNum = linkNum; part.OffsetPosition = part.GroupPosition - AbsolutePosition; Quaternion rootRotation = m_rootPart.RotationOffset; Vector3 pos = part.OffsetPosition; pos *= Quaternion.Inverse(rootRotation); part.OffsetPosition = pos; parentRot = m_rootPart.RotationOffset; oldRot = part.RotationOffset; Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; part.RotationOffset = newRot; }
/// <summary> /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// </summary> /// <param name="partID"></param> /// <param name="sendEvents"></param> /// <returns>The object group of the newly delinked prim.</returns> public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents) { // m_log.DebugFormat( // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); linkPart.ClearUndoState(); foreach (SceneObjectPart child in ChildrenList) { child.ClearUndoState(); } Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object RemovePartList(linkPart); if (m_parts.Count == 1 && RootPart != null) //Single prim is left RootPart.LinkNum = 0; else { lock (m_partsLock) { foreach (SceneObjectPart p in m_partsList) { if (p.LinkNum > linkPart.LinkNum) p.LinkNum--; } } } linkPart.SetParentLocalId(0); linkPart.LinkNum = 0; if (linkPart.PhysActor != null) { m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); } // We need to reset the child part's position // ready for life as a separate object after being a part of another object Quaternion parentRot = m_rootPart.RotationOffset; Vector3 axPos = linkPart.OffsetPosition; axPos *= parentRot; linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); linkPart.RotationOffset = worldRot; SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart, Scene); m_scene.AddNewSceneObject(objectGroup, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); linkPart.Rezzed = RootPart.Rezzed; //HasGroupChanged = true; //ScheduleGroupForFullUpdate(); return objectGroup; }
/// <summary> /// /// </summary> /// <param name="part"></param> private void SetPartAsNonRoot(SceneObjectPart part) { part.SetParentLocalId(m_rootPart.LocalId); part.ClearUndoState(); }
public bool LinkPartToSOG(SceneObjectGroup grp, SceneObjectPart part, int linkNum) { part.SetParentLocalId(grp.RootPart.LocalId); part.SetParent(grp); // Insert in terms of link numbers, the new links // before the current ones (with the exception of // the root prim. Shuffle the old ones up foreach (ISceneEntity otherPart in grp.ChildrenEntities()) { if (otherPart.LinkNum >= linkNum) { // Don't update root prim link number otherPart.LinkNum += 1; } } part.LinkNum = linkNum; return LinkPartToEntity(grp, part); }