/// <summary> /// This function should only be triggered when an update update is received (i.e. /// triggered by remote update instead of local update). /// </summary> /// <param name="sp"></param> /// <param name="property"></param> private void SetPropertyValue(ScenePresence sp, SyncedProperty syncedProperty) { if (sp == null) { return; } SyncableProperties.Type property = syncedProperty.Property; if (syncedProperty == null) { DebugLog.ErrorFormat("{0}: SetPropertyValue: property {1} not in sync cache for uuid {2}. ", LogHeader, property, UUID); return; } SetPropertyValue(sp, property, syncedProperty); }
// Constructor used for initializing SyncInfo from remote (OSDMap) data before syncing it locally /// <param name="id">UUID of the scene presence</param> /// <param name="syncInfoData">Initial sync data</param> /// <param name="scene">The local scene</param> public SyncInfoPresence(UUID id, OSDArray properties, Scene scene) { // DebugLog.WarnFormat("[SYNC INFO PRESENCE] Constructing SyncInfoPresence (from map) for uuid {0}", id); UUID = id; Scene = scene; lock (m_syncLock) { // Decode syncInfoData into CurrentlySyncedProperties CurrentlySyncedProperties = new Dictionary <SyncableProperties.Type, SyncedProperty>(); foreach (OSD property in properties) { // Parse each property from the key in the map we received SyncedProperty syncedProperty = new SyncedProperty((OSDArray)property); CurrentlySyncedProperties.Add(syncedProperty.Property, syncedProperty); } } }
/// <summary> /// Compare the local timestamp with that in pSyncInfo. If the one in /// pSyncInfo is newer, copy its members to the local record. /// </summary> /// <param name="pSyncInfo"></param> /// <returns>'true' if the received sync value was accepted and the sync cache was updated with the received value</returns> public bool CompareAndUpdateSyncInfoBySync(SyncedProperty pSyncInfo, long recvTS) { // KLUDGE!!! THIS TRIES TO FORCE THE SCRIPT SETTING OF ANIMATIONS VS DEFAULT ANIMATIONS. // Unconditionally accept an animation update if the received update has extended animations // and the existing animation is a default animation. This case is most often // from a script setting a sit or animation override. if (RegionSyncModule.ShouldUnconditionallyAcceptAnimationOverrides && Property == SyncableProperties.Type.Animations) { OSDArray receivedAnimations = pSyncInfo.LastUpdateValue as OSDArray; OSDArray existingAnimations = LastUpdateValue as OSDArray; if (receivedAnimations != null && existingAnimations != null) { /* * // If going from default animation to something better, always accept it * if (receivedAnimations.Count > 2 && existingAnimations.Count <= 2) * { * // The new animation has more info than the existing so accept it. * // DebugLog.DebugFormat("{0} SyncedProperty.CompareAndUpdateSyncInfoBySync: forcing. receivedCnt={1}, existingCnt={2}", // DEBUG DEBUG * // "[DSG SYNCED PROPERTY]", receivedAnimations.Count, existingAnimations.Count); // DEBUG DEBUG * UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, pSyncInfo.LastUpdateValue, recvTS); * return true; * } */ // For the moment, just accept received animations UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, pSyncInfo.LastUpdateValue, recvTS); return(true); } } // If update timestamp is later, or we do some tie breaking, then update if ((pSyncInfo.LastUpdateTimeStamp > LastUpdateTimeStamp) || ((pSyncInfo.LastUpdateTimeStamp == LastUpdateTimeStamp) && (!LastUpdateSyncID.Equals(pSyncInfo.LastUpdateSyncID)) && (SyncIDTieBreak(LastUpdateSyncID, pSyncInfo.LastUpdateSyncID).Equals(pSyncInfo.LastUpdateSyncID)))) { UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, pSyncInfo.LastUpdateValue, recvTS); return(true); } return(false); }
//In SOP's implementation, GroupPosition and SOP.PhysActor.Position are //correlated. We need to make sure that they are both properly synced. private bool CompareAndUpdateSOPGroupPositionByLocal(SceneObjectPart part, long lastUpdateByLocalTS, string syncID) { if (part.ParentGroup.IsAttachment) return false; SyncedProperty groupPositionProperty; SyncedProperty positionProperty; CurrentlySyncedProperties.TryGetValue(SyncableProperties.Type.GroupPosition, out groupPositionProperty); if (groupPositionProperty == null) { DebugLog.WarnFormat("{0}: CompareAndUpdateSOPGroupPosition for uuid {1}. GroupPosition is not in CurrentlySyncedProperties!", LogHeader, part.UUID); return false; } // DebugLog.WarnFormat("[SYNC INFO PRIM] CompareAndUpdateSOPGroupPositionByLocal"); if (!part.GroupPosition.ApproxEquals((Vector3)groupPositionProperty.LastUpdateValue, (float)0.001)) { CurrentlySyncedProperties.TryGetValue(SyncableProperties.Type.Position, out positionProperty); if (lastUpdateByLocalTS >= groupPositionProperty.LastUpdateTimeStamp) { //Update cached value with SOP.GroupPosition groupPositionProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.GroupPosition); //Also may need to cached PhysActor.Position if (part.PhysActor != null) { if (positionProperty == null) { Object initValue = GetPropertyValue(part, SyncableProperties.Type.Position); positionProperty = new SyncedProperty(SyncableProperties.Type.Position, initValue, lastUpdateByLocalTS, syncID); CurrentlySyncedProperties.Add(SyncableProperties.Type.Position, positionProperty); } else { if (!part.PhysActor.Position.Equals(positionProperty.LastUpdateValue)) { positionProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Position); } } } return true; } else if (lastUpdateByLocalTS < groupPositionProperty.LastUpdateTimeStamp) { //overwrite SOP's data, set function of GroupPosition updates PhysActor.Position as well part.GroupPosition = (Vector3)groupPositionProperty.LastUpdateValue; //PhysActor.Position is just updated by setting GroupPosition //above, so need to update the cached value of Position here. if (part.PhysActor != null) { //Set the timestamp and syncID to be the same with GroupPosition long lastUpdateTimestamp = groupPositionProperty.LastUpdateTimeStamp; string lastUpdateSyncID = groupPositionProperty.LastUpdateSyncID; if (positionProperty == null) { Object initValue = GetPropertyValue(part, SyncableProperties.Type.Position); positionProperty = new SyncedProperty(SyncableProperties.Type.Position, initValue, lastUpdateTimestamp, lastUpdateSyncID); CurrentlySyncedProperties.Add(SyncableProperties.Type.Position, positionProperty); } else { if (!part.PhysActor.Position.Equals(positionProperty.LastUpdateValue)) { //Set the timestamp and syncID to be the same with GroupPosition //long lastUpdateTimestamp = CurrentlySyncedProperties[SyncableProperties.Type.GroupPosition].LastUpdateTimeStamp; //string lastUpdateSyncID = CurrentlySyncedProperties[SyncableProperties.Type.GroupPosition].LastUpdateSyncID; positionProperty.UpdateSyncInfoByLocal(lastUpdateTimestamp, lastUpdateSyncID, (Object)part.PhysActor.Position); } } } } } return false; }
public override void SetPropertyValue(SyncedProperty pSyncInfo) { SceneObjectPart part = (SceneObjectPart)SceneThing; // DebugLog.WarnFormat("[SYNC INFO PRIM] SetPropertyValue(property={0})", property.ToString()); SetPropertyValue(part, pSyncInfo); part.ParentGroup.HasGroupChanged = true; }
private void SetSOPAbsolutePosition(SceneObjectPart part, SyncedProperty pSyncInfo) { // DebugLog.WarnFormat("[SYNC INFO PRIM] SetSOPAbsolutePosition"); if (part.ParentGroup != null) { part.ParentGroup.AbsolutePosition = (Vector3)pSyncInfo.LastUpdateValue; if (part.ParentGroup.IsAttachment) return; SyncedProperty syncedProperty; CurrentlySyncedProperties.TryGetValue(SyncableProperties.Type.GroupPosition, out syncedProperty); if (syncedProperty == null) { CurrentlySyncedProperties.Add(SyncableProperties.Type.GroupPosition, new SyncedProperty(SyncableProperties.Type.GroupPosition, part.GroupPosition, pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID)); } else { syncedProperty.UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, part.GroupPosition, pSyncInfo.LastSyncUpdateRecvTime); } if (part.PhysActor != null) { CurrentlySyncedProperties.TryGetValue(SyncableProperties.Type.Position, out syncedProperty); if(syncedProperty == null) { CurrentlySyncedProperties.Add(SyncableProperties.Type.Position, new SyncedProperty(SyncableProperties.Type.Position, part.PhysActor.Position, pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID)); } else { syncedProperty.UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, part.PhysActor.Position, pSyncInfo.LastSyncUpdateRecvTime); } } //the above operation may change GroupPosition and PhysActor.Postiion //as well. so update their values } }
// Constructor used for initializing SyncInfo from remote (OSDMap) data before syncing it locally public SyncInfoPrim(UUID id, OSDArray properties, Scene scene) { UUID = id; Scene = scene; // Create an SOP based on the set of decoded properties // The SOP will be stored internally and someone will add it to the scene later SceneThing = new SceneObjectPart(); ((SceneObjectPart)SceneThing).UUID = UUID; //DebugLog.WarnFormat("{0}: Constructing SyncInfoPrim (from map) for uuid {1}", LogHeader, UUID); lock (m_syncLock) { // Decode syncInfoData into CurrentlySyncedProperties CurrentlySyncedProperties = new Dictionary<SyncableProperties.Type, SyncedProperty>(); foreach(OSDArray property in properties) { // Parse each property from the key in the map we received SyncedProperty syncedProperty = new SyncedProperty(property); CurrentlySyncedProperties.Add(syncedProperty.Property, syncedProperty); try { SetPropertyValue((SceneObjectPart)SceneThing, syncedProperty); } catch (Exception e) { DebugLog.ErrorFormat("{0}: Error setting SOP property {1}: {2}", LogHeader, property, e.Message); } } } }
// When this is called, the SyncInfo should already have a reference to the scene object it will be updating public abstract void SetPropertyValue(SyncedProperty syncedProperty);
/// <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 }); }
public override void SetPropertyValue(SyncedProperty syncedPropertyValue) { ScenePresence sp = (ScenePresence)SceneThing; SetPropertyValue(sp, syncedPropertyValue); }
// Constructor used for initializing SyncInfo from remote (OSDMap) data before syncing it locally /// <param name="id">UUID of the scene presence</param> /// <param name="syncInfoData">Initial sync data</param> /// <param name="scene">The local scene</param> public SyncInfoPresence(UUID id, OSDArray properties, Scene scene) { // DebugLog.WarnFormat("[SYNC INFO PRESENCE] Constructing SyncInfoPresence (from map) for uuid {0}", id); UUID = id; Scene = scene; lock (m_syncLock) { // Decode syncInfoData into CurrentlySyncedProperties CurrentlySyncedProperties = new Dictionary<SyncableProperties.Type, SyncedProperty>(); foreach (OSD property in properties) { // Parse each property from the key in the map we received SyncedProperty syncedProperty = new SyncedProperty((OSDArray)property); CurrentlySyncedProperties.Add(syncedProperty.Property, syncedProperty); } } }
/// <summary> /// Compare the local timestamp with that in pSyncInfo. If the one in /// pSyncInfo is newer, copy its members to the local record. /// </summary> /// <param name="pSyncInfo"></param> /// <returns>'true' if the received sync value was accepted and the sync cache was updated with the received value</returns> public bool CompareAndUpdateSyncInfoBySync(SyncedProperty pSyncInfo, long recvTS) { // KLUDGE!!! THIS TRIES TO FORCE THE SCRIPT SETTING OF ANIMATIONS VS DEFAULT ANIMATIONS. // Unconditionally accept an animation update if the received update has extended animations // and the existing animation is a default animation. This case is most often // from a script setting a sit or animation override. if (RegionSyncModule.ShouldUnconditionallyAcceptAnimationOverrides && Property == SyncableProperties.Type.Animations) { OSDArray receivedAnimations = pSyncInfo.LastUpdateValue as OSDArray; OSDArray existingAnimations = LastUpdateValue as OSDArray; if (receivedAnimations != null && existingAnimations != null) { /* // If going from default animation to something better, always accept it if (receivedAnimations.Count > 2 && existingAnimations.Count <= 2) { // The new animation has more info than the existing so accept it. // DebugLog.DebugFormat("{0} SyncedProperty.CompareAndUpdateSyncInfoBySync: forcing. receivedCnt={1}, existingCnt={2}", // DEBUG DEBUG // "[DSG SYNCED PROPERTY]", receivedAnimations.Count, existingAnimations.Count); // DEBUG DEBUG UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, pSyncInfo.LastUpdateValue, recvTS); return true; } */ // For the moment, just accept received animations UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, pSyncInfo.LastUpdateValue, recvTS); return true; } } // If update timestamp is later, or we do some tie breaking, then update if ((pSyncInfo.LastUpdateTimeStamp > LastUpdateTimeStamp) || ((pSyncInfo.LastUpdateTimeStamp == LastUpdateTimeStamp) && (!LastUpdateSyncID.Equals(pSyncInfo.LastUpdateSyncID)) && (SyncIDTieBreak(LastUpdateSyncID, pSyncInfo.LastUpdateSyncID).Equals(pSyncInfo.LastUpdateSyncID)))) { UpdateSyncInfoBySync(pSyncInfo.LastUpdateTimeStamp, pSyncInfo.LastUpdateSyncID, pSyncInfo.LastUpdateValue, recvTS); return true; } return false; }
private void SetPropertyValue(ScenePresence sp, SyncableProperties.Type property, SyncedProperty pSyncInfo) { if (sp == null || pSyncInfo == null) { return; } Object pValue = pSyncInfo.LastUpdateValue; switch (property) { case SyncableProperties.Type.LocalId: sp.LocalId = (uint)pValue; break; case SyncableProperties.Type.AbsolutePosition: sp.AbsolutePosition = (Vector3)pValue; break; case SyncableProperties.Type.AgentCircuitData: DebugLog.WarnFormat("{0}: Received updated AgentCircuitData. Not implemented", LogHeader); break; case SyncableProperties.Type.ParentId: uint localID = (uint)pValue; if (localID == 0) { // DebugLog.DebugFormat("{0}: SetPropertyValue:ParentID. Standup. Input={1}", LogHeader, localID); // DEBUG DEBUG sp.StandUp(); } else { SceneObjectPart parentPart = Scene.GetSceneObjectPart(localID); if (parentPart != null) // TODO ?? { sp.HandleAgentRequestSit(sp.ControllingClient, sp.ControllingClient.AgentId, parentPart.UUID, Vector3.Zero); // DebugLog.DebugFormat("{0}: SetPropertyValue:ParentID. SitRequest. Input={1},sp={2},newParentID={3}", // LogHeader, localID, (string)(sp == null ? "NULL" : sp.Name), sp.ParentID); // DEBUG DEBUG } } //sp.ParentID = (uint)pValue; break; case SyncableProperties.Type.AgentControlFlags: sp.AgentControlFlags = (uint)pValue; break; case SyncableProperties.Type.AllowMovement: sp.AllowMovement = (bool)pValue; break; case SyncableProperties.Type.AvatarAppearance: sp.Appearance.Unpack((OSDMap)pValue); sp.SendAppearanceToAllOtherAgents(); DebugLog.DebugFormat("{0} Received updated AvatarAppearance for uuid {1}.", LogHeader, sp.UUID); break; case SyncableProperties.Type.Animations: UpdateAvatarAnimations(sp, (OSDArray)pValue); break; case SyncableProperties.Type.Rotation: sp.Rotation = (Quaternion)pValue; break; case SyncableProperties.Type.PA_Velocity: if (sp.PhysicsActor != null) { sp.PhysicsActor.Velocity = (Vector3)pValue; } break; case SyncableProperties.Type.RealRegion: ////// NOP ////// break; case SyncableProperties.Type.PA_TargetVelocity: if (sp.PhysicsActor != null) { sp.PhysicsActor.TargetVelocity = (Vector3)pValue; } break; case SyncableProperties.Type.Flying: sp.Flying = (bool)pValue; break; case SyncableProperties.Type.PresenceType: DebugLog.WarnFormat("{0} Received updated PresenceType for uuid {1}. Not implemented", LogHeader, sp.UUID); break; case SyncableProperties.Type.IsColliding: if (sp.PhysicsActor != null) { sp.IsColliding = (bool)pValue; } break; } // When presence values are changed, we tell the simulator with an event GenerateAgentUpdated(sp); }
/// <summary> /// Compare the value (not "reference") of the given property. /// Assumption: the caller has already checked if PhysActor exists /// if there are physics properties updated. /// If the value maintained here is different from that in SOP data, /// synchronize the two: /// (1) if the value here has a timestamp newer than lastUpdateByLocalTS /// (e.g. due to clock drifts among different sync nodes, a remote /// write might have a newer timestamp than the local write), /// overwrite the SOP's property with the value here (effectively /// disvalidate the local write operation that just happened). /// (2) otherwise, copy SOP's data and update timestamp and syncID /// as indicated by "lastUpdateByLocalTS" and "syncID". /// </summary> /// <param name="part"></param> /// <param name="property"></param> /// <param name="lastUpdateByLocalTS"></param> /// <param name="syncID"></param> /// <returns>Return true if the property's value maintained in this SyncInfoPrim is replaced by SOP's data.</returns> private bool CompareValue_UpdateByLocal(SceneObjectPart part, SyncableProperties.Type property, long lastUpdateByLocalTS, string syncID, out bool resetSceneValue) { resetSceneValue = false; //DebugLog.WarnFormat("[SYNC INFO PRIM] CompareValue_UpdateByLocal: Updating property {0} on part {1}", property.ToString(), part.UUID); SyncedProperty syncedProperty; CurrentlySyncedProperties.TryGetValue(property, out syncedProperty); // If the property does not exist yet then add it. if (syncedProperty == null) { Object initValue = GetPropertyValue(part, property); SyncedProperty syncInfo = new SyncedProperty(property, initValue, lastUpdateByLocalTS, syncID); CurrentlySyncedProperties.Add(property, syncInfo); return true; } // First, check if the value maintained here is different from that in SOP's. // If different, next check if the timestamp in SyncInfo is newer than lastUpdateByLocalTS; // if so (although ideally should not happen, but due to things likc clock not so perfectly // sync'ed, it might happen), overwrite SOP's value with what's maintained // in SyncInfo; otherwise, copy SOP's data to SyncInfo. switch (property) { case SyncableProperties.Type.GroupPosition: return CompareAndUpdateSOPGroupPositionByLocal(part, lastUpdateByLocalTS, syncID); default: Object value = GetPropertyValue(part, property); // If both null, no update needed if (syncedProperty.LastUpdateValue == null && value == null) return false; // If one is null and the other is not, or if they are not equal, the property was changed. if ((value == null && syncedProperty.LastUpdateValue != null) || (value != null && syncedProperty.LastUpdateValue == null) || (!value.Equals(syncedProperty.LastUpdateValue))) { if (value != null) { switch (property) { case SyncableProperties.Type.Velocity: case SyncableProperties.Type.PA_Velocity: case SyncableProperties.Type.PA_TargetVelocity: case SyncableProperties.Type.RotationalVelocity: case SyncableProperties.Type.AngularVelocity: { Vector3 partVal = (Vector3)value; Vector3 lastVal = (Vector3)syncedProperty.LastUpdateValue; // If velocity difference is small but not zero, don't update if (partVal.ApproxEquals(lastVal, VELOCITY_TOLERANCE) && !partVal.Equals(Vector3.Zero)) return false; break; } case SyncableProperties.Type.RotationOffset: case SyncableProperties.Type.Orientation: { Quaternion partVal = (Quaternion)value; Quaternion lastVal = (Quaternion)syncedProperty.LastUpdateValue; if (partVal.ApproxEquals(lastVal, ROTATION_TOLERANCE)) return false; break; } case SyncableProperties.Type.OffsetPosition: case SyncableProperties.Type.AbsolutePosition: case SyncableProperties.Type.Position: case SyncableProperties.Type.GroupPosition: { Vector3 partVal = (Vector3)value; Vector3 lastVal = (Vector3)syncedProperty.LastUpdateValue; if (partVal.ApproxEquals(lastVal, POSITION_TOLERANCE)) return false; break; } } } if (property == SyncableProperties.Type.Shape) { //DebugLog.WarnFormat("[SYNC INFO PRIM]: SHAPES DIFFER {0} {1}", (string)value, (string)syncedProperty.LastUpdateValue); } // DebugLog.WarnFormat("[SYNC INFO PRIM] CompareValue_UpdateByLocal (property={0}): value != syncedProperty.LastUpdateValue", property.ToString()); if (lastUpdateByLocalTS >= syncedProperty.LastUpdateTimeStamp) { // DebugLog.WarnFormat("[SYNC INFO PRIM] CompareValue_UpdateByLocal (property={0}): TS >= lastTS (updating SyncInfo)", property.ToString()); syncedProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, value); // Updating either absolute position or position also requires checking for updates to group position if (property == SyncableProperties.Type.AbsolutePosition || property == SyncableProperties.Type.Position) { CompareValue_UpdateByLocal(part, SyncableProperties.Type.GroupPosition, lastUpdateByLocalTS, syncID, out resetSceneValue); resetSceneValue = false; } return true; } // DebugLog.WarnFormat("[SYNC INFO PRIM] CompareValue_UpdateByLocal (property={0}): TS < lastTS (updating SOP)", property.ToString()); //We'll reset the property value outside of CompareValue_UpdateByLocal //SetPropertyValue(property); resetSceneValue = true; } break; } return false; }
/// <summary> /// This function should only be triggered when an update update is received (i.e. /// triggered by remote update instead of local update). /// </summary> /// <param name="sp"></param> /// <param name="property"></param> private void SetPropertyValue(ScenePresence sp, SyncedProperty syncedProperty) { if (sp == null) return; SyncableProperties.Type property = syncedProperty.Property; if (syncedProperty == null) { DebugLog.ErrorFormat("{0}: SetPropertyValue: property {1} not in sync cache for uuid {2}. ", LogHeader, property, UUID); return; } SetPropertyValue(sp, property, syncedProperty); }
// Constructor used for initializing SyncInfo from local (SceneObjectPart) data before syncing it out /// <param name="sop">Part to use for initial synced property values</param> /// <param name="initUpdateTimestamp">Initial update timestamp</param> /// <param name="syncID"></param> /// <param name="scene"></param> public SyncInfoPrim(SceneObjectPart sop, long initUpdateTimestamp, string syncID, Scene scene) { UUID = sop.UUID; Scene = scene; SceneThing = sop; //DebugLog.WarnFormat("{0}: Constructing SyncInfoPrim (from scene) for uuid {1}", LogHeader, UUID); // If the part does not have a PhysActor then don't store physical property initial values HashSet<SyncableProperties.Type> initialProperties = sop.PhysActor == null ? new HashSet<SyncableProperties.Type>(SyncableProperties.NonPhysActorProperties) : new HashSet<SyncableProperties.Type>(SyncableProperties.FullUpdateProperties); lock (m_syncLock) { CurrentlySyncedProperties = new Dictionary<SyncableProperties.Type, SyncedProperty>(); foreach (SyncableProperties.Type property in initialProperties) { Object initValue = GetPropertyValue(sop, property); SyncedProperty syncInfo = new SyncedProperty(property, initValue, initUpdateTimestamp, syncID); CurrentlySyncedProperties.Add(property, syncInfo); } } }
private void SetPropertyValue(ScenePresence sp, SyncableProperties.Type property, SyncedProperty pSyncInfo) { if (sp == null || pSyncInfo == null) return; Object pValue = pSyncInfo.LastUpdateValue; switch (property) { case SyncableProperties.Type.LocalId: sp.LocalId = (uint)pValue; break; case SyncableProperties.Type.AbsolutePosition: sp.AbsolutePosition = (Vector3)pValue; break; case SyncableProperties.Type.AgentCircuitData: DebugLog.WarnFormat("{0}: Received updated AgentCircuitData. Not implemented", LogHeader); break; case SyncableProperties.Type.ParentId: uint localID = (uint)pValue; if (localID == 0) { // DebugLog.DebugFormat("{0}: SetPropertyValue:ParentID. Standup. Input={1}", LogHeader, localID); // DEBUG DEBUG sp.StandUp(); } else { SceneObjectPart parentPart = Scene.GetSceneObjectPart(localID); if (parentPart != null) // TODO ?? { sp.HandleAgentRequestSit(sp.ControllingClient, sp.ControllingClient.AgentId, parentPart.UUID, Vector3.Zero); // DebugLog.DebugFormat("{0}: SetPropertyValue:ParentID. SitRequest. Input={1},sp={2},newParentID={3}", // LogHeader, localID, (string)(sp == null ? "NULL" : sp.Name), sp.ParentID); // DEBUG DEBUG } } //sp.ParentID = (uint)pValue; break; case SyncableProperties.Type.AgentControlFlags: sp.AgentControlFlags = (uint)pValue; break; case SyncableProperties.Type.AllowMovement: sp.AllowMovement = (bool)pValue; break; case SyncableProperties.Type.AvatarAppearance: sp.Appearance.Unpack((OSDMap)pValue); sp.SendAppearanceToAllOtherAgents(); DebugLog.DebugFormat("{0} Received updated AvatarAppearance for uuid {1}.", LogHeader, sp.UUID); break; case SyncableProperties.Type.Animations: UpdateAvatarAnimations(sp, (OSDArray)pValue); break; case SyncableProperties.Type.Rotation: sp.Rotation = (Quaternion)pValue; break; case SyncableProperties.Type.PA_Velocity: if (sp.PhysicsActor != null) sp.PhysicsActor.Velocity = (Vector3)pValue; break; case SyncableProperties.Type.RealRegion: ////// NOP ////// break; case SyncableProperties.Type.PA_TargetVelocity: if(sp.PhysicsActor != null) sp.PhysicsActor.TargetVelocity = (Vector3)pValue; break; case SyncableProperties.Type.Flying: sp.Flying = (bool)pValue; break; case SyncableProperties.Type.PresenceType: DebugLog.WarnFormat("{0} Received updated PresenceType for uuid {1}. Not implemented", LogHeader, sp.UUID); break; case SyncableProperties.Type.IsColliding: if(sp.PhysicsActor != null) sp.IsColliding = (bool)pValue; break; } // When presence values are changed, we tell the simulator with an event GenerateAgentUpdated(sp); }