diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index aeaa4cb2f0..658410e1c3 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -200,9 +200,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //private object m_updateSceneObjectPartLock = new object(); //private Dictionary m_primUpdates = new Dictionary(); private Dictionary m_primUpdateLocks = new Dictionary(); - private Dictionary> m_primUpdates = new Dictionary>(); + private Dictionary> m_primUpdates = new Dictionary>(); - private delegate void PrimUpdatePerBucketSender(SceneObjectGroup sog, string bucketName); + private delegate void PrimUpdatePerBucketSender(string bucketName, List primUpdates); private Dictionary m_primUpdatesPerBucketSender = new Dictionary(); private object m_updateScenePresenceLock = new object(); @@ -222,18 +222,60 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } - private void PrimUpdatesGeneralBucketSender(SceneObjectGroup sog, string bucketName) + //As of current version, we still use the xml serialization as most of SOP's properties are in the General bucket. + //Going forward, we may serialize the properties differently, e.g. using OSDMap + private void PrimUpdatesGeneralBucketSender(string bucketName, List primUpdates) { - sog.UpdateTaintedBucketSyncInfo(bucketName, DateTime.Now.Ticks); //this update the timestamp and clear the taint info of the bucket - string sogxml = SceneObjectSerializer.ToXml2Format(sog); - SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); - SendObjectUpdateToRelevantSyncConnectors(sog, syncMsg); + Dictionary updatedObjects = new Dictionary(); + foreach (SceneObjectPart part in primUpdates) + { + updatedObjects[part.ParentGroup.UUID] = part.ParentGroup; + } + foreach (SceneObjectGroup sog in updatedObjects.Values) + { + sog.UpdateTaintedBucketSyncInfo(bucketName, DateTime.Now.Ticks); //this update the timestamp and clear the taint info of the bucket + string sogxml = SceneObjectSerializer.ToXml2Format(sog); + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); + SendObjectUpdateToRelevantSyncConnectors(sog, syncMsg); + } } - private void PrimUpdatesPhysicsBucketSender(SceneObjectGroup sog, string bucketName) + private void PrimUpdatesPhysicsBucketSender(string bucketName, List primUpdates) { + foreach (SceneObjectPart updatedPart in primUpdates) + { + updatedPart.UpdateTaintedBucketSyncInfo(bucketName, DateTime.Now.Ticks); + OSDMap data = new OSDMap(); + data["UUID"] = OSD.FromUUID(updatedPart.UUID); + data["Bucket"] = OSD.FromString(bucketName); + + data["GroupPosition"] = OSD.FromVector3(updatedPart.GroupPosition); + data["OffsetPosition"] = OSD.FromVector3(updatedPart.OffsetPosition); + data["RotationOffset"] = OSD.FromQuaternion(updatedPart.RotationOffset); + data["Velocity"] = OSD.FromVector3(updatedPart.Velocity); + data["Scale"] = OSD.FromVector3(updatedPart.Scale); + //Other properties to be included + /* + "Position": + "Size": + "Force": + "RotationalVelocity": + "PA_Acceleration": + "Torque": + "Orientation": + "IsPhysical": + "Flying": + "Buoyancy": + * */ + + data["LastUpdateTimeStamp"] = OSD.FromLong(updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp); + data["LastUpdateActorID"] = OSD.FromString(updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID); + + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedBucketProperties, OSDParser.SerializeJsonString(data)); + SendObjectUpdateToRelevantSyncConnectors(updatedPart, syncMsg); + } } //If nothing configured in the config file, this is the default settings for grouping properties into different bucket @@ -283,7 +325,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //create different lists to keep track which SOP has what properties updated (which bucket of properties) foreach (string bucketName in m_propertyBucketNames) { - m_primUpdates.Add(bucketName, new Dictionary()); + m_primUpdates.Add(bucketName, new Dictionary()); m_primUpdateLocks.Add(bucketName, new Object()); } } @@ -302,7 +344,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { lock (m_primUpdateLocks[bucketName]) { - m_primUpdates[bucketName][part.UUID] = part.ParentGroup; + m_primUpdates[bucketName][part.UUID] = part; } } } @@ -339,7 +381,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } //List primUpdates=null; - Dictionary> primUpdates = new Dictionary>(); + Dictionary> primUpdates = new Dictionary>(); bool updated = false; //copy the updated SOG list and clear m_primUpdates for immediately future usage @@ -350,7 +392,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule lock (m_primUpdateLocks[bucketName]) { updated = true; - primUpdates.Add(bucketName, new List(m_primUpdates[bucketName].Values)); + primUpdates.Add(bucketName, new List(m_primUpdates[bucketName].Values)); m_primUpdates[bucketName].Clear(); @@ -383,11 +425,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule foreach (string bucketName in m_propertyBucketNames) { - if (primUpdates[bucketName].Count>0) + if (primUpdates.ContainsKey(bucketName) && primUpdates[bucketName].Count > 0) { + /* foreach (SceneObjectGroup sog in primUpdates[bucketName]) { - /* + //If this is a relay node, or at least one part of the object has the last update caused by this actor, then send the update sog.UpdateTaintedBucketSyncInfo(timeStamp); if (m_isSyncRelay || (!sog.IsDeleted && CheckObjectForSendingUpdate(sog))) @@ -397,9 +440,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); SendObjectUpdateToRelevantSyncConnectors(sog, syncMsg); } - * */ - m_primUpdatesPerBucketSender[bucketName](sog, bucketName); } + * */ + m_primUpdatesPerBucketSender[bucketName](bucketName, primUpdates[bucketName]); } } /* @@ -778,6 +821,19 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + //Object updates are sent by enqueuing into each connector's outQueue. + private void SendObjectUpdateToRelevantSyncConnectors(SceneObjectPart updatedPart, SymmetricSyncMessage syncMsg) + { + List syncConnectors = GetSyncConnectorsForObjectUpdates(updatedPart); + + foreach (SyncConnector connector in syncConnectors) + { + //string sogxml = SceneObjectSerializer.ToXml2Format(sog); + //SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); + connector.EnqueueOutgoingUpdate(updatedPart.UUID, syncMsg.ToBytes()); + } + } + private void SendDelinkObjectToRelevantSyncConnectors(List beforeDelinkGroups, SymmetricSyncMessage syncMsg) { HashSet syncConnectorsSent = new HashSet(); @@ -871,6 +927,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return syncConnectors; } + private List GetSyncConnectorsForObjectUpdates(SceneObjectPart updatedPart) + { + return GetSyncConnectorsForObjectUpdates(updatedPart.ParentGroup); + } + /// /// Get the set of SyncConnectors to send certain scene events. /// @@ -1341,6 +1402,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //HandleAddNewObject(sog); return; } + case SymmetricSyncMessage.MsgType.UpdatedBucketProperties: + { + HandleUpdatedBucketProperties(msg, senderActorID); + return; + } case SymmetricSyncMessage.MsgType.RemovedObject: { HandleRemovedObject(msg, senderActorID); @@ -1428,6 +1494,64 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + private void HandleUpdatedBucketProperties(SymmetricSyncMessage msg, string senderActorID) + { + // Get the data from message and error check + OSDMap data = DeserializeMessage(msg); + + if (data == null) + { + SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data."); + return; + } + + UUID partUUID = data["UUID"].AsUUID(); + string bucketName = data["Bucket"].AsString(); + + + SceneObjectPart updatedPart = new SceneObjectPart(); + updatedPart.GroupPosition = data["GroupPosition"].AsVector3(); + updatedPart.OffsetPosition = data["OffsetPosition"].AsVector3(); + updatedPart.RotationOffset = data["RotationOffset"].AsQuaternion(); + updatedPart.Velocity = data["Velocity"].AsVector3(); + updatedPart.AngularVelocity = data["AngularVelocity"].AsVector3(); + //Scale is a bit complex, we need to have Shape first -- not a good solution, but leave it as is so that we can move on, + updatedPart.Shape = new PrimitiveBaseShape(); + updatedPart.Scale = data["Scale"].AsVector3(); + + + /* + Dictionary updatedProperties = new Dictionary(); + updatedProperties.Add("GroupPosition", (Object)data["GroupPosition"].AsVector3()); + updatedProperties.Add("OffsetPosition", (Object)data["OffsetPosition"].AsVector3()); + updatedProperties.Add("RotationOffset", (Object)data["RotationOffset"].AsQuaternion()); + updatedProperties.Add("Velocity", (Object)data["Velocity"].AsVector3()); + updatedProperties.Add("AngularVelocity", (Object)data["AngularVelocity"].AsVector3()); + updatedProperties.Add("Scale", (Object)data["Scale"].AsVector3()); + * */ + + + //Other properties to be included + /* + "Position": + "Size": + "Force": + "RotationalVelocity": + "PA_Acceleration": + "Torque": + "Orientation": + "IsPhysical": + "Flying": + "Buoyancy": + * */ + BucketSyncInfo rBucketSyncInfo = new BucketSyncInfo(bucketName); + rBucketSyncInfo.LastUpdateTimeStamp = data["LastUpdateTimeStamp"].AsLong(); + rBucketSyncInfo.LastUpdateActorID = data["LastUpdateActorID"].AsString(); + updatedPart.BucketSyncInfoList.Add(bucketName, rBucketSyncInfo); + + m_scene.UpdateObjectPartBucketProperties(bucketName, partUUID, updatedPart); + } + private void SendTerrainUpdateMessage() { string msgData = m_scene.Heightmap.SaveToXmlString(); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index b1b9932274..b9bc9c5ed5 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -815,6 +815,12 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGraph.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups); } + //public ObjectUpdateResult UpdateObjectPartBucketProperties(string bucketName, UUID partUUID, Dictionary updatedProperties, BucketSyncInfo rBucketSyncInfo) + public ObjectUpdateResult UpdateObjectPartBucketProperties(string bucketName, UUID partUUID, SceneObjectPart updatePart) + { + return m_sceneGraph.UpdateObjectPartBucketProperties(bucketName, partUUID, updatePart); + } + #endregion //SYMMETRIC SYNC public ICapabilitiesModule CapsModule diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index c5110440f1..564461d315 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -2429,126 +2429,18 @@ namespace OpenSim.Region.Framework.Scenes return afterDelinkGroups; } - - /* - * //Initial effort to delink objects by copying from the linksets from remote copy. Too much book-keeping updating work to make sure all details are right. - * //So we switched to letting local actor to apply the same "delink" operation as the remote actor did, and check if the "before-state" and "after-state" - * //agrees. - public void DelinkObjectsBySync(List delinkPrimIDs, List beforeDelinkGroupIDs, List incomingAfterDelinkGroups) + //public Scene.ObjectUpdateResult UpdateObjectPartBucketProperties(string bucketName, UUID partUUID, Dictionary updatedProperties, BucketSyncInfo rBucketSyncInfo) + public Scene.ObjectUpdateResult UpdateObjectPartBucketProperties(string bucketName, UUID partUUID, SceneObjectPart updatedPart) { - Monitor.Enter(m_updateLock); - try + SceneObjectPart localPart = GetSceneObjectPart(partUUID); + if (localPart == null) { - Dictionary localBeforeDelinkGroups = new Dictionary(); - Dictionary delinkPrims = new Dictionary(); - - //get the before-delink-groups, and all the prims to delink - foreach (UUID primID in delinkPrimIDs) - { - SceneObjectPart localPart = GetSceneObjectPart(primID); - if (!delinkPrims.ContainsKey(primID)) - { - delinkPrims.Add(primID, localPart); - } - SceneObjectGroup localGroup = localPart.ParentGroup; - if (!localBeforeDelinkGroups.ContainsKey(localGroup.UUID)) - { - localBeforeDelinkGroups.Add(localGroup.UUID, localGroup); - } - } - - //Next, do some sanity check to see if the local copy agrees with remote copy on the before-link state. - //TODO:: Actions to be taken after detecting conflicts. For now, we just assume the chance that conflict will happen is almost 0. - - //First, check if the groups match - if (beforeDelinkGroupIDs.Count != localBeforeDelinkGroups.Count) - { - //detected conflict on editing object groups - m_log.Warn("DelinkObjectsBySync: the # of groups in before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!"); - //TODO: further actions - } - else - { - foreach (UUID beforeGroupID in beforeDelinkGroupIDs) - { - if (!localBeforeDelinkGroups.ContainsKey(beforeGroupID)) - { - m_log.Warn("DelinkObjectsBySync: the local state of before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!"); - } - } - //TODO: further actions - } - //Second, check if the prims match - List allPrimsInLocalGroups = new List(); - foreach (KeyValuePair pair in localBeforeDelinkGroups) - { - foreach (SceneObjectPart part in pair.Value.Parts) - { - allPrimsInLocalGroups.Add(part); - } - } - if (allPrimsInLocalGroups.Count != delinkPrims.Count) - { - m_log.Warn("DelinkObjectsBySync: the # of prims of before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!"); - //TODO: further action - } - foreach (SceneObjectPart part in allPrimsInLocalGroups) - { - if (!delinkPrims.ContainsKey(part.UUID)) - { - m_log.Warn("DelinkObjectsBySync: some local prims in before-delink-groups not exist in the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!"); - //TODO: further action - } - } - //end of sanity checking - - //now work with localBeforeDelinkGroups, delinkPrims, and incomingAfterDelinkGroups - List localAfterDelinkGroups = new List(); - List remoteOldGroups = new List(); - List remoteNewGroups = new List(); - - foreach (SceneObjectGroup remoteGroup in incomingAfterDelinkGroups) - { - if (localBeforeDelinkGroups.ContainsKey(remoteGroup.UUID)) - { - remoteOldGroups.Add(remoteGroup); - } - else - { - remoteNewGroups.Add(remoteGroup); - } - } - - //update parts in old groups - foreach (SceneObjectGroup remoteGroupCopy in remoteOldGroups) - { - SceneObjectGroup localGroupCopy = localBeforeDelinkGroups[remoteGroupCopy.UUID]; - //update the parts in local copy with those in the remote copy - - - } - - //add new groups - - - } - finally - { - Monitor.Exit(m_updateLock); + m_log.Warn("No SOP found: UUID -- " + partUUID); + return Scene.ObjectUpdateResult.Unchanged; } + return localPart.UpdateBucketProperties(bucketName, updatedPart); } - //update the parts in local copy with those in the updated copy - private void UpdatePartsInGroup(SceneObjectGroup localGroup, SceneObjectGroup updatedGroup) - { - //caller of this function should already lock on m_updateLock, hence no locking here - foreach (SceneObjectPart part in localGroup.Parts){ - - } - } - * */ - - #endregion //SYMMETRIC SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 9e1adae4bb..290b6ef5e1 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -5209,7 +5209,7 @@ namespace OpenSim.Region.Framework.Scenes //private static Dictionary m_bucketUpdateProcessors = new Dictionary(); private Dictionary m_bucketUpdateProcessors = new Dictionary(); private Dictionary m_bucketUpdateLocks = new Dictionary(); - private Dictionary m_bucketSyncTainted = new Dictionary(); + //private Dictionary m_bucketSyncTainted = new Dictionary(); //Define this as a guard to not to fill in any sync info when not desired, i.e. while de-serializing and building SOP and SOG, where //property set functions will be called and might trigger UpdateBucketSyncInfo() if not guarded carefully. @@ -5481,12 +5481,6 @@ namespace OpenSim.Region.Framework.Scenes { m_bucketUpdateLocks.Add(bucketName, new Object()); } - /* - if (!m_bucketSyncTainted.ContainsKey(bucketName)) - { - m_bucketSyncTainted.Add(bucketName, false); - } - * */ } if (!m_BucketUpdateProcessorRegistered) @@ -5501,11 +5495,24 @@ namespace OpenSim.Region.Framework.Scenes //For tainitng and clearing taints, do i need to lock on m_bucketSyncTaint? public void TaintBucketSyncInfo(SceneObjectPartProperties property) { - if (m_syncEnabled && m_bucketSyncTainted.Count > 0) + if (m_syncEnabled) { - string bucketName = m_primPropertyBucketMap[property]; - //m_bucketSyncTainted[bucketName] = true; - m_bucketSyncInfoList[bucketName].TaintBucket(); + if (property == SceneObjectPartProperties.None) + return; + + if (property == SceneObjectPartProperties.FullUpdate) + { + foreach (BucketSyncInfo bucketSynInfo in m_bucketSyncInfoList.Values) + { + bucketSynInfo.TaintBucket(); + } + } + else + { + string bucketName = m_primPropertyBucketMap[property]; + //m_bucketSyncTainted[bucketName] = true; + m_bucketSyncInfoList[bucketName].TaintBucket(); + } } } @@ -5516,19 +5523,6 @@ namespace OpenSim.Region.Framework.Scenes } - /* - public void ClearBucketTaint() - { - if (m_syncEnabled && m_bucketSyncTainted.Count > 0) - { - foreach (KeyValuePair pair in m_bucketSyncTainted) - { - pair.Value = false; - } - } - } - * */ - /// /// Update the timestamp information of each property bucket, and clear out the taint on each bucket. /// @@ -5540,10 +5534,9 @@ namespace OpenSim.Region.Framework.Scenes foreach (KeyValuePair pair in m_bucketSyncInfoList) { string bucketName = pair.Key; - if (m_bucketSyncTainted[bucketName]) + if (m_bucketSyncInfoList[bucketName].Tainted) { m_bucketSyncInfoList[bucketName].UpdateSyncInfoAndClearTaint(timeStamp, m_localActorID); - //m_bucketSyncTainted[bucketName] = false; } } } @@ -5562,7 +5555,7 @@ namespace OpenSim.Region.Framework.Scenes foreach (KeyValuePair pair in m_bucketSyncInfoList) { string bucketName = pair.Key; - if (m_bucketSyncTainted[bucketName]) + if (m_bucketSyncInfoList[bucketName].Tainted) { m_bucketSyncInfoList[bucketName].UpdateSyncInfoAndClearTaint(timeStamp, m_localActorID); } @@ -5574,10 +5567,9 @@ namespace OpenSim.Region.Framework.Scenes { if (m_syncEnabled) { - if (m_bucketSyncTainted[bucketName]) + if (m_bucketSyncInfoList[bucketName].Tainted) { m_bucketSyncInfoList[bucketName].UpdateSyncInfoAndClearTaint(timeStamp, m_localActorID); - //m_bucketSyncTainted[bucketName] = false; } } } @@ -5613,12 +5605,10 @@ namespace OpenSim.Region.Framework.Scenes string bucketName = pair.Key; BucketSyncInfo syncInfo= pair.Value; syncInfo.UpdateSyncInfoAndClearTaint(timeStamp, m_localActorID); - m_bucketSyncTainted[bucketName] = false; } } } - public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart) { @@ -5653,8 +5643,9 @@ namespace OpenSim.Region.Framework.Scenes if (!m_bucketSyncInfoList[bucketName].LastUpdateActorID.Equals(updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID)) { m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp (" + m_bucketSyncInfoList[bucketName].LastUpdateActorID - + "," + updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID + ", CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!"); + + "," + updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID + ", CONFLICT RESOLUTION TO BE IMPLEMENTED, PICK A WINNER!!!!"); } + //TODO: conflict resolution to be implemented -- pick a winner continue; } @@ -5676,6 +5667,55 @@ namespace OpenSim.Region.Framework.Scenes } + /// + /// Update values of property in the given bucket. + /// + /// The bucket that the properties belong to. + /// A container of the updated properties. Only the values of the updated properties are set. + /// A copy of the sync info of the bucket on the sender's (who sends out the syn message) side. + /// + public Scene.ObjectUpdateResult UpdateBucketProperties(string bucketName, SceneObjectPart updatedPart) + { + Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged; + + if (updatedPart.BucketSyncInfoList.ContainsKey(bucketName)) + { + m_log.Warn("No bucket named " + bucketName + " found in the copy of updatedPart in UpdateBucketProperties"); + return partUpdateResult; + } + + BucketSyncInfo rBucketSyncInfo = updatedPart.BucketSyncInfoList[bucketName]; + + if (!m_bucketSyncInfoList.ContainsKey(bucketName)) + { + m_log.Error("SceneObjectPart.UpdateBucketProperties: no bucket name " + bucketName + " defined"); + return partUpdateResult; + } + + if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp > rBucketSyncInfo.LastUpdateTimeStamp) + { + //Our timestamp is more update to date, keep our values of the properties. Do not update anything. + return partUpdateResult; + } + + if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp == rBucketSyncInfo.LastUpdateTimeStamp) + { + if (!m_bucketSyncInfoList[bucketName].LastUpdateActorID.Equals(rBucketSyncInfo.LastUpdateActorID)) + { + m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp (" + m_bucketSyncInfoList[bucketName].LastUpdateActorID + + "," + rBucketSyncInfo.LastUpdateActorID + ", CONFLICT RESOLUTION TO BE IMPLEMENTED, PICK A WINNER!!!!"); + } + //TODO: conflict resolution to be implemented -- pick a winner + return partUpdateResult; + } + + + m_bucketUpdateProcessors[bucketName](updatedPart, bucketName); + partUpdateResult = Scene.ObjectUpdateResult.Updated; + + return partUpdateResult; + } + public override void ScheduleFullUpdate(List updatedProperties) { foreach (SceneObjectPartProperties property in updatedProperties)