Пример #1
0
 // Constructor
 public SyncedProperty(SyncableProperties.Type property, Object initValue, long initTS, string syncID)
 {
     Property            = property;
     LastUpdateValue     = initValue;
     LastUpdateTimeStamp = initTS;
     LastUpdateSyncID    = syncID;
 }
Пример #2
0
        /// <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);
        }
Пример #3
0
 public abstract Object GetPropertyValue(SyncableProperties.Type property);
Пример #4
0
        //TODO: might return status such as Updated, Unchanged, etc to caller
        public HashSet <SyncableProperties.Type> UpdatePropertiesBySync(UUID uuid, HashSet <SyncedProperty> syncedProperties)
        {
            long recvTS = RegionSyncModule.NowTicks();
            HashSet <SyncableProperties.Type> propertiesUpdated       = new HashSet <SyncableProperties.Type>();
            List <SyncedProperty>             updatedSyncedProperties = new List <SyncedProperty>();

            lock (m_syncLock)
            {
                foreach (SyncedProperty syncedProperty in syncedProperties)
                {
                    bool updated = false;

                    SyncableProperties.Type property = syncedProperty.Property;
                    //Compare if the value of the property in this SyncInfo is different than the value in local scene

                    SyncedProperty currentlySyncedProperty;
                    CurrentlySyncedProperties.TryGetValue(property, out currentlySyncedProperty);

                    // If synced property is not in cache, add it now.
                    if (currentlySyncedProperty == null)
                    {
                        //could happen if PhysActor is just created (object stops being phantom)
                        if (SyncableProperties.PhysActorProperties.Contains(property))
                        {
                            CurrentlySyncedProperties.Add(property, syncedProperty);
                        }
                        else
                        {
                            DebugLog.WarnFormat("{0}: UpdatePropertiesBySync: No record of property {1} for uuid {2}", LogHeader, property, uuid);
                        }
                    }
                    else
                    {
                        try
                        {
                            //Compare timestamp and update SyncInfo if necessary
                            updated = currentlySyncedProperty.CompareAndUpdateSyncInfoBySync(syncedProperty, recvTS);
                            //If updated, update the property value in scene object/presence
                            if (updated)
                            {
                                //SetPropertyValue(property);
                                updatedSyncedProperties.Add(currentlySyncedProperty);
                                propertiesUpdated.Add(property);
                            }
                        }
                        catch (Exception e)
                        {
                            DebugLog.ErrorFormat("{0}: UpdatePropertiesBySync: Error in updating property {1}: {2}", LogHeader, property, e.Message);
                        }
                    }
                }
            }

            //Now we only need to read from the SyncInfo, so moving the SetPropertyValue out of lock, to avoid potential deadlocks
            //which might happen due to side effects of "set" functions of a SOp or SP property
            foreach (SyncedProperty updatedProperty in updatedSyncedProperties)
            {
                SetPropertyValue(updatedProperty);
            }

            PostUpdateBySync(propertiesUpdated);

            return(propertiesUpdated);
        }
Пример #5
0
        /// <summary>
        /// Set member values by decoding out of propertyData. Should only
        /// be called in initialization time (e.g. from constructor).
        /// </summary>
        /// <param name="propertyData"></param>
        private void FromOSDArray(OSDArray propertyData)
        {
            Property            = (SyncableProperties.Type)(propertyData[0].AsInteger());
            LastUpdateTimeStamp = propertyData[1].AsLong();
            LastUpdateSyncID    = propertyData[2].AsString();

            OSD value = propertyData[3];

            switch (Property)
            {
            ///////////////////////////////////////
            // Complex structure properties
            ///////////////////////////////////////
            case SyncableProperties.Type.AgentCircuitData:
            case SyncableProperties.Type.AvatarAppearance:
                LastUpdateValue = (OSDMap)value;
                break;

            case SyncableProperties.Type.Animations:
                LastUpdateValue = (OSDArray)value;
                break;

            ////////////////////////////
            // Integer/enum type properties
            ////////////////////////////
            case SyncableProperties.Type.CreationDate:              // int
            case SyncableProperties.Type.LinkNum:                   // int
            case SyncableProperties.Type.OwnershipCost:             // int
            case SyncableProperties.Type.SalePrice:                 // int
            case SyncableProperties.Type.ScriptAccessPin:           // int
            case SyncableProperties.Type.AggregateScriptEvents:     // enum
            case SyncableProperties.Type.Flags:                     // enum
            case SyncableProperties.Type.LocalFlags:                // enum
            case SyncableProperties.Type.PresenceType:              // enum
                LastUpdateValue = value.AsInteger();
                break;

            case SyncableProperties.Type.ClickAction:
            case SyncableProperties.Type.Material:
            case SyncableProperties.Type.ObjectSaleType:
                LastUpdateValue = (byte)value.AsInteger();
                break;

            ////////////////////////////
            // Boolean type properties
            ////////////////////////////
            case SyncableProperties.Type.AllowedDrop:
            case SyncableProperties.Type.IsAttachment:
            case SyncableProperties.Type.PassTouches:
            case SyncableProperties.Type.VolumeDetectActive:
            case SyncableProperties.Type.Flying:
            case SyncableProperties.Type.IsColliding:
            case SyncableProperties.Type.CollidingGround:
            case SyncableProperties.Type.Kinematic:
            case SyncableProperties.Type.IsSelected:
            case SyncableProperties.Type.AllowMovement:
                LastUpdateValue = value.AsBoolean();
                break;

            ////////////////////////////
            // Vector3 type properties
            ////////////////////////////
            case SyncableProperties.Type.AngularVelocity:
            case SyncableProperties.Type.AttachedPos:
            case SyncableProperties.Type.GroupPosition:
            case SyncableProperties.Type.OffsetPosition:
            case SyncableProperties.Type.Scale:
            case SyncableProperties.Type.SitTargetPosition:
            case SyncableProperties.Type.SitTargetPositionLL:
            case SyncableProperties.Type.SOP_Acceleration:
            case SyncableProperties.Type.Velocity:
            case SyncableProperties.Type.Force:
            case SyncableProperties.Type.PA_Acceleration:
            case SyncableProperties.Type.PA_Velocity:
            case SyncableProperties.Type.PA_TargetVelocity:
            case SyncableProperties.Type.Position:
            case SyncableProperties.Type.RotationalVelocity:
            case SyncableProperties.Type.Size:
            case SyncableProperties.Type.Torque:
            case SyncableProperties.Type.AbsolutePosition:
                LastUpdateValue = value.AsVector3();
                break;

            ////////////////////////////
            // UUID type properties
            ////////////////////////////
            case SyncableProperties.Type.AttachedAvatar:
            case SyncableProperties.Type.CollisionSound:
            case SyncableProperties.Type.CreatorID:
            case SyncableProperties.Type.FolderID:
            case SyncableProperties.Type.GroupID:
            case SyncableProperties.Type.LastOwnerID:
            case SyncableProperties.Type.OwnerID:
            case SyncableProperties.Type.Sound:
                LastUpdateValue = value.AsUUID();
                break;

            ////////////////////////////
            // UInt type properties
            ////////////////////////////
            case SyncableProperties.Type.LocalId:
            case SyncableProperties.Type.AttachmentPoint:
            case SyncableProperties.Type.BaseMask:
            case SyncableProperties.Type.Category:
            case SyncableProperties.Type.EveryoneMask:
            case SyncableProperties.Type.GroupMask:
            case SyncableProperties.Type.InventorySerial:
            case SyncableProperties.Type.NextOwnerMask:
            case SyncableProperties.Type.OwnerMask:
            case SyncableProperties.Type.AgentControlFlags:
            case SyncableProperties.Type.ParentId:
                LastUpdateValue = value.AsUInteger();
                break;

            ////////////////////////////
            // Float type properties
            ////////////////////////////
            case SyncableProperties.Type.CollisionSoundVolume:
            case SyncableProperties.Type.Buoyancy:
                LastUpdateValue = (float)value.AsReal();
                break;

            ////////////////////////////
            // String type properties
            ////////////////////////////
            case SyncableProperties.Type.Color:
            case SyncableProperties.Type.CreatorData:
            case SyncableProperties.Type.Description:
            case SyncableProperties.Type.MediaUrl:
            case SyncableProperties.Type.Name:
            case SyncableProperties.Type.RealRegion:
            case SyncableProperties.Type.Shape:
            case SyncableProperties.Type.SitName:
            case SyncableProperties.Type.TaskInventory:
            case SyncableProperties.Type.Text:
            case SyncableProperties.Type.TouchName:
                LastUpdateValue = value.AsString();
                break;

            ////////////////////////////
            // byte[] (binary data) type properties
            ////////////////////////////
            case SyncableProperties.Type.ParticleSystem:
            case SyncableProperties.Type.TextureAnimation:
                LastUpdateValue = value.AsBinary();
                break;

            ////////////////////////////
            // Quaternion type properties
            ////////////////////////////
            case SyncableProperties.Type.RotationOffset:
            case SyncableProperties.Type.SitTargetOrientation:
            case SyncableProperties.Type.SitTargetOrientationLL:
            case SyncableProperties.Type.Orientation:
            case SyncableProperties.Type.Rotation:
                LastUpdateValue = value.AsQuaternion();
                break;

            default:
                DebugLog.WarnFormat("[SYNCED PROPERTY] FromOSDArray: No handler for property {0} ", Property);
                break;
            }
        }
Пример #6
0
        /// <summary>
        /// Set member values by decoding out of propertyData. Should only
        /// be called in initialization time (e.g. from constructor).
        /// </summary>
        /// <param name="propertyData"></param>
        private void FromOSDArray(OSDArray propertyData)
        {
            Property = (SyncableProperties.Type)(propertyData[0].AsInteger());
            LastUpdateTimeStamp = propertyData[1].AsLong();
            LastUpdateSyncID = propertyData[2].AsString();

            OSD value = propertyData[3];
            switch (Property)
            {
                ///////////////////////////////////////
                // Complex structure properties
                ///////////////////////////////////////
                case SyncableProperties.Type.AgentCircuitData:
                case SyncableProperties.Type.AvatarAppearance:
                    LastUpdateValue = (OSDMap)value;
                    break;

                case SyncableProperties.Type.Animations:
                    LastUpdateValue = (OSDArray)value;
                    break;

                ////////////////////////////
                // Integer/enum type properties
                ////////////////////////////
                case SyncableProperties.Type.CreationDate:          // int
                case SyncableProperties.Type.LinkNum:               // int
                case SyncableProperties.Type.OwnershipCost:         // int
                case SyncableProperties.Type.SalePrice:             // int
                case SyncableProperties.Type.ScriptAccessPin:       // int
                case SyncableProperties.Type.AggregateScriptEvents: // enum
                case SyncableProperties.Type.Flags:                 // enum
                case SyncableProperties.Type.LocalFlags:            // enum
                case SyncableProperties.Type.PresenceType:          // enum
                    LastUpdateValue = value.AsInteger();
                    break;

                case SyncableProperties.Type.ClickAction:
                case SyncableProperties.Type.Material:
                case SyncableProperties.Type.ObjectSaleType:
                    LastUpdateValue = (byte)value.AsInteger();
                    break;

                ////////////////////////////
                // Boolean type properties
                ////////////////////////////
                case SyncableProperties.Type.AllowedDrop:
                case SyncableProperties.Type.IsAttachment:
                case SyncableProperties.Type.PassTouches:
                case SyncableProperties.Type.VolumeDetectActive:
                case SyncableProperties.Type.Flying:
                case SyncableProperties.Type.IsColliding:
                case SyncableProperties.Type.CollidingGround:
                case SyncableProperties.Type.Kinematic:
                case SyncableProperties.Type.IsSelected:
                case SyncableProperties.Type.AllowMovement:
                    LastUpdateValue = value.AsBoolean();
                    break;

                ////////////////////////////
                // Vector3 type properties
                ////////////////////////////
                case SyncableProperties.Type.AngularVelocity:
                case SyncableProperties.Type.AttachedPos:
                case SyncableProperties.Type.GroupPosition:
                case SyncableProperties.Type.OffsetPosition:
                case SyncableProperties.Type.Scale:
                case SyncableProperties.Type.SitTargetPosition:
                case SyncableProperties.Type.SitTargetPositionLL:
                case SyncableProperties.Type.SOP_Acceleration:
                case SyncableProperties.Type.Velocity:
                case SyncableProperties.Type.Force:
                case SyncableProperties.Type.PA_Acceleration:
                case SyncableProperties.Type.PA_Velocity:
                case SyncableProperties.Type.PA_TargetVelocity:
                case SyncableProperties.Type.Position:
                case SyncableProperties.Type.RotationalVelocity:
                case SyncableProperties.Type.Size:
                case SyncableProperties.Type.Torque:
                case SyncableProperties.Type.AbsolutePosition:
                    LastUpdateValue = value.AsVector3();
                    break;

                ////////////////////////////
                // UUID type properties
                ////////////////////////////
                case SyncableProperties.Type.AttachedAvatar:
                case SyncableProperties.Type.CollisionSound:
                case SyncableProperties.Type.CreatorID:
                case SyncableProperties.Type.FolderID:
                case SyncableProperties.Type.GroupID:
                case SyncableProperties.Type.LastOwnerID:
                case SyncableProperties.Type.OwnerID:
                case SyncableProperties.Type.Sound:
                    LastUpdateValue = value.AsUUID();
                    break;

                ////////////////////////////
                // UInt type properties
                ////////////////////////////
                case SyncableProperties.Type.LocalId:
                case SyncableProperties.Type.AttachmentPoint:
                case SyncableProperties.Type.BaseMask:
                case SyncableProperties.Type.Category:
                case SyncableProperties.Type.EveryoneMask:
                case SyncableProperties.Type.GroupMask:
                case SyncableProperties.Type.InventorySerial:
                case SyncableProperties.Type.NextOwnerMask:
                case SyncableProperties.Type.OwnerMask:
                case SyncableProperties.Type.AgentControlFlags:
                case SyncableProperties.Type.ParentId:
                    LastUpdateValue = value.AsUInteger();
                    break;

                ////////////////////////////
                // Float type properties
                ////////////////////////////
                case SyncableProperties.Type.CollisionSoundVolume:
                case SyncableProperties.Type.Buoyancy:
                    LastUpdateValue = (float)value.AsReal();
                    break;

                ////////////////////////////
                // String type properties
                ////////////////////////////
                case SyncableProperties.Type.Color:
                case SyncableProperties.Type.CreatorData:
                case SyncableProperties.Type.Description:
                case SyncableProperties.Type.MediaUrl:
                case SyncableProperties.Type.Name:
                case SyncableProperties.Type.RealRegion:
                case SyncableProperties.Type.Shape:
                case SyncableProperties.Type.SitName:
                case SyncableProperties.Type.TaskInventory:
                case SyncableProperties.Type.Text:
                case SyncableProperties.Type.TouchName:
                    LastUpdateValue = value.AsString();
                    break;

                ////////////////////////////
                // byte[] (binary data) type properties
                ////////////////////////////
                case SyncableProperties.Type.ParticleSystem:
                case SyncableProperties.Type.TextureAnimation:
                    LastUpdateValue = value.AsBinary();
                    break;

                ////////////////////////////
                // Quaternion type properties
                ////////////////////////////
                case SyncableProperties.Type.RotationOffset:
                case SyncableProperties.Type.SitTargetOrientation:
                case SyncableProperties.Type.SitTargetOrientationLL:
                case SyncableProperties.Type.Orientation:
                case SyncableProperties.Type.Rotation:
                    LastUpdateValue = value.AsQuaternion();
                    break;

                default:
                    DebugLog.WarnFormat("[SYNCED PROPERTY] FromOSDArray: No handler for property {0} ", Property);
                    break;
            }
        }
Пример #7
0
        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);
        }
Пример #8
0
        // Gets the value out of the SP in local scene and returns it as an object
        private Object GetPropertyValue(ScenePresence sp, SyncableProperties.Type property)
        {
            if (sp == null)
            {
                return(null);
            }

            switch (property)
            {
            case SyncableProperties.Type.LocalId:
                return(sp.LocalId);

            case SyncableProperties.Type.AbsolutePosition:
                return(sp.AbsolutePosition);

            case SyncableProperties.Type.AgentCircuitData:
                return(Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode).PackAgentCircuitData());

            case SyncableProperties.Type.ParentId:
                return(sp.ParentID);

            case SyncableProperties.Type.AgentControlFlags:
                return(sp.AgentControlFlags);

            case SyncableProperties.Type.AllowMovement:
                return(sp.AllowMovement);

            case SyncableProperties.Type.Animations:
                return(sp.Animator.Animations.ToOSDArray());

            case SyncableProperties.Type.AvatarAppearance:
                return(sp.Appearance.Pack());

            case SyncableProperties.Type.Rotation:
                return(sp.Rotation);

            case SyncableProperties.Type.PA_Velocity:
                if (sp.PhysicsActor == null)
                {
                    return(Vector3.Zero);
                }
                return(sp.PhysicsActor.Velocity);

            case SyncableProperties.Type.RealRegion:
                // Always just the local scene name the avatar is in when requested locally.
                return(sp.Scene.Name);

            case SyncableProperties.Type.PA_TargetVelocity:
                if (sp.PhysicsActor == null)
                {
                    return(Vector3.Zero);
                }
                return(sp.PhysicsActor.TargetVelocity);

            case SyncableProperties.Type.Flying:
                return(sp.Flying);

            case SyncableProperties.Type.PresenceType:
                return((int)sp.PresenceType);

            case SyncableProperties.Type.IsColliding:
                return(sp.IsColliding);
            }

            //DebugLog.ErrorFormat("{0}: GetPropertyValue could not get property {1} from {2}", LogHeader, property.ToString(), sp.UUID);
            return(null);
        }
Пример #9
0
 public override Object GetPropertyValue(SyncableProperties.Type property)
 {
     return(GetPropertyValue((ScenePresence)SceneThing, property));
 }
Пример #10
0
        /// <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 SP data,
        /// synchronize the two:
        /// (1) if the cached value has a timestamp newer than lastUpdateByLocalTS
        /// overwrite the SP's property with the cached value (effectively
        /// undoing the local write operation that just happened).
        /// (2) otherwise, copy SP's data and update timestamp and syncID
        /// as indicated by "lastUpdateByLocalTS" and "syncID".
        /// </summary>
        /// <param name="sp"></param>
        /// <param name="property"></param>
        /// <param name="lastUpdateByLocalTS"></param>
        /// <param name="syncID"></param>
        /// <returns>Return true if the property's value maintained in this
        /// RegionSyncModule is replaced by SP's data.</returns>
        private bool CompareValue_UpdateByLocal(ScenePresence sp, SyncableProperties.Type property, long lastUpdateByLocalTS, string syncID)
        {
            //DebugLog.WarnFormat("[SYNC INFO PRESENCE] CompareValue_UpdateByLocal: Updating property {0} on sp {1}", property.ToString(), sp.UUID);
            // Check to see if this property is in the sync cache for this object.
            // If not, add it and initialize value to value in ScenePresence.
            bool ret = false;

            SyncedProperty syncedProperty;

            CurrentlySyncedProperties.TryGetValue(property, out syncedProperty);

            // If synced property is not in cache, add it now
            if (syncedProperty == null)
            {
                Object initValue = GetPropertyValue(sp, property);
                if (initValue != null)
                {
                    CurrentlySyncedProperties.Add(property, new SyncedProperty(property, initValue, lastUpdateByLocalTS, syncID));
                    ret = true;
                }
                return(ret);
            }

            // First, check if the value maintained here is different from that in SP'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 SP's value with what's maintained
            // in SyncInfo; otherwise, copy SP's data to SyncInfo.
            Object value = GetPropertyValue(sp, property);

            // If both null, no update needed
            if (syncedProperty.LastUpdateValue == null && value == null)
            {
                return(false);
            }

            switch (property)
            {
            default:
                // If one is null and the other is not, or if the references are different, the property was changed.
                // This will perform a value comparison for strings in C#. We could use String.Clone instead for string properties.
                if ((value == null && syncedProperty.LastUpdateValue != null) ||
                    (value != null && syncedProperty.LastUpdateValue == null) ||
                    (!value.Equals(syncedProperty.LastUpdateValue)))
                {
                    if (value != null)
                    {
                        // Some values, even if they are not 'equal', might be close enough to be equal.
                        // Note that the 'Equals()' above will most always return 'false' for lists and OSDMaps
                        //     since they are probably not the same object.
                        // Returning a 'false' here means the values don't need any updating (they are equal enough).
                        switch (property)
                        {
                        case SyncableProperties.Type.AvatarAppearance:
                            String stringValue     = OSDParser.SerializeJsonString((OSDMap)value);
                            String lastStringValue = OSDParser.SerializeJsonString((OSDMap)syncedProperty.LastUpdateValue);
                            if (stringValue == lastStringValue)
                            {
                                return(false);
                            }
                            break;

                        case SyncableProperties.Type.Animations:
                            if (syncedProperty.LastUpdateValue != null)
                            {
                                AnimationSet lastAnimations = new AnimationSet((OSDArray)syncedProperty.LastUpdateValue);

                                // Get the home region for this presence (the client manager the presence is connected to).
                                string cachedRealRegionName = (string)(CurrentlySyncedProperties[SyncableProperties.Type.RealRegion].LastUpdateValue);
                                if (cachedRealRegionName != Scene.Name && sp.Animator.Animations.ToArray().Length == 0)
                                {
                                    // If this is not the originating region for this presence and there is no additional
                                    //   animations being added, this simulator does not change the animation.
                                    // THIS IS A HORRIBLE KLUDGE. FIGURE OUT THE REAL SOLUTION!!
                                    // The problem is that animations are changed by every simulator (setting default
                                    //   sit and stand when parentID changes) and the updates conflict/override the real
                                    //   settings (like a scripted sit animation).
                                    // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal. Not home sim or no anim change. spID={1}, homeSim={2}, thisSim={3}, anims={4}",
                                    //                     LogHeader, sp.LocalId, cachedRealRegionName, Scene.Name, sp.Animator.Animations.ToArray().Length); // DEBUG DEBUG

                                    return(false);
                                }

                                if (lastAnimations.Equals(sp.Animator.Animations))
                                {
                                    // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal. Equal anims. spID={1}, sp.Anim={2}, lastAnim={3}",
                                    //                     LogHeader, sp.LocalId, sp.Animator.Animations, lastAnimations); // DEBUG DEBUG
                                    return(false);
                                }
                                else
                                {
                                    // If locally storing a new value of the animation, don't check for the time.
                                    // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal. Not equal anims. spID={1}, sp.Anim={2}, lastAnim={3}",
                                    //                     LogHeader, sp.LocalId, sp.Animator.Animations, lastAnimations); // DEBUG DEBUG
                                    syncedProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, value);
                                    return(true);
                                }
                            }
                            break;

                        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 we get here, the values are not equal and we need to update the cached value if the
                    //     new value is timestamp newer.
                    if (lastUpdateByLocalTS >= syncedProperty.LastUpdateTimeStamp)
                    {
                        // DebugLog.DebugFormat("{0} CompareValue_UpdateByLocal (property={1}): TS >= lastTS (updating SyncInfo)", LogHeader, property);
                        syncedProperty.UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, value);
                        return(true);
                    }
                }
                break;
            }
            return(false);
        }