diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs
index 1db8ac6379..6d458a6733 100644
--- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs
+++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs
@@ -404,7 +404,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
}
//include the property values of each object after delinking, for synchronizing the values
- data["afterGroupsCount"] = OSD.FromInteger(beforeDelinkGroups.Count);
+ data["afterGroupsCount"] = OSD.FromInteger(afterDelinkGroups.Count);
groupNum = 0;
foreach (SceneObjectGroup afterGroup in afterDelinkGroups)
{
@@ -1031,8 +1031,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
/// The handler for processing incoming sync messages.
///
///
+ /// ActorID of the sender
public void HandleIncomingMessage(SymmetricSyncMessage msg, string senderActorID)
{
+ //Added senderActorID, so that we don't have to include actorID in sync messages -- TODO
switch (msg.Type)
{
case SymmetricSyncMessage.MsgType.GetTerrain:
@@ -1084,6 +1086,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
HandleLinkObject(msg, senderActorID);
return;
}
+ case SymmetricSyncMessage.MsgType.DelinkObject:
+ {
+ HandleDelinkObject(msg, senderActorID);
+ return;
+ }
//EVENTS PROCESSING
case SymmetricSyncMessage.MsgType.NewScript:
case SymmetricSyncMessage.MsgType.UpdateScript:
@@ -1254,7 +1261,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
return;
}
- string init_actorID = data["actorID"].AsString();
+ //string init_actorID = data["actorID"].AsString();
string sogxml = data["linkedGroup"].AsString();
SceneObjectGroup linkedGroup = SceneObjectSerializer.FromXml2Format(sogxml);
UUID rootID = data["rootID"].AsUUID();
@@ -1277,6 +1284,57 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
}
}
+ private void HandleDelinkObject(SymmetricSyncMessage msg, string senderActorID)
+ {
+ OSDMap data = DeserializeMessage(msg);
+ if (data == null)
+ {
+ SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data.");
+ return;
+ }
+
+ //List localPrims = new List();
+ List delinkPrimIDs = new List();
+ List beforeDelinkGroupIDs = new List();
+ List incomingAfterDelinkGroups = new List();
+
+ int partCount = data["partCount"].AsInteger();
+ for (int i = 0; i < partCount; i++)
+ {
+ string partTempID = "part" + i;
+ UUID primID = data[partTempID].AsUUID();
+ //SceneObjectPart localPart = m_scene.GetSceneObjectPart(primID);
+ //localPrims.Add(localPart);
+ delinkPrimIDs.Add(primID);
+ }
+
+ int beforeGroupCount = data["beforeGroupsCount"].AsInteger();
+ for (int i = 0; i < beforeGroupCount; i++)
+ {
+ string groupTempID = "beforeGroup" + i;
+ UUID beforeGroupID = data[groupTempID].AsUUID();
+ beforeDelinkGroupIDs.Add(beforeGroupID);
+ }
+
+ int afterGroupsCount = data["afterGroupsCount"].AsInteger();
+ for (int i = 0; i < afterGroupsCount; i++)
+ {
+ string groupTempID = "afterGroup" + i;
+ string sogxml = data[groupTempID].AsString();
+ SceneObjectGroup afterGroup = SceneObjectSerializer.FromXml2Format(sogxml);
+ incomingAfterDelinkGroups.Add(afterGroup);
+ }
+
+ m_scene.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups);
+
+ //if this is a relay node, forwards the event
+ if (m_isSyncRelay)
+ {
+ //SendSceneEventToRelevantSyncConnectors(init_actorID, msg);
+ SendSceneEventToRelevantSyncConnectors(senderActorID, msg);
+ }
+ }
+
///
/// The common actions for handling remote events (event initiated at other actors and propogated here)
///
@@ -1284,6 +1342,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
private void HandleRemoteEvent(SymmetricSyncMessage msg, string senderActorID)
{
OSDMap data = DeserializeMessage(msg);
+ if (data == null)
+ {
+ SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data.");
+ return;
+ }
+
string init_actorID = data["actorID"].AsString();
ulong evSeqNum = data["seqNum"].AsULong();
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 40c37f3e1e..1914e1abee 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -808,6 +808,11 @@ namespace OpenSim.Region.Framework.Scenes
* */
}
+ public void DelinkObjectsBySync(List delinkPrimIDs, List beforeDelinkGroupIDs, List incomingAfterDelinkGroups)
+ {
+ m_sceneGraph.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups);
+ }
+
#endregion //SYMMETRIC SYNC
public ICapabilitiesModule CapsModule
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 16358c731c..c35b0b440e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -2177,6 +2177,371 @@ namespace OpenSim.Region.Framework.Scenes
}
+ ///
+ /// Delink the prims as indicated in localPrimIDs, and regroup them as the object-groups indicated in incomingAfterDelinkGroups.
+ ///
+ ///
+ ///
+ ///
+ public void DelinkObjectsBySync(List delinkPrimIDs, List beforeDelinkGroupIDs, List incomingAfterDelinkGroups)
+ {
+ Dictionary localBeforeDelinkGroups = new Dictionary();
+ Dictionary delinkPrims = new Dictionary();
+ bool beforeStateConsistent = true;
+ bool afterStateConsistent = true;
+
+ Monitor.Enter(m_updateLock);
+ try
+ {
+ //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!!!");
+ beforeStateConsistent = false;
+ //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!!!");
+ beforeStateConsistent = false;
+ break;
+ }
+ }
+ //TODO: further actions
+ }
+
+ if(beforeStateConsistent){
+ //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!!!");
+ beforeStateConsistent = false;
+ //TODO: further action
+ }else{
+ 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!!!");
+ beforeStateConsistent = false;
+ break;
+ //TODO: further action
+ }
+ }
+ }
+ }
+ //end of sanity checking
+
+ if(!beforeStateConsistent){
+ m_log.Warn("DelinkObjectsBySync: before-delink state not consistent in local copy and the incoming copy. Return without further operations.");
+ }else{
+ //Next, apply the delink operation locally.
+ List localAfterDelinkGroups = DelinkObjectsBySync(new List(delinkPrims.Values));
+
+
+ //Check if local after-state agrees with that in the remote copy, and update the groups' properties
+ if (localAfterDelinkGroups.Count != incomingAfterDelinkGroups.Count)
+ {
+ m_log.Warn("DelinkObjectsBySync: local state after delink does not agree with the incoming delink message (# of groups are different). NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
+ afterStateConsistent = false;
+ }
+ else
+ {
+ Dictionary incomingAfterDelinkGroupsDictionary = new Dictionary();
+ foreach (SceneObjectGroup incomingGroup in incomingAfterDelinkGroups){
+ incomingAfterDelinkGroupsDictionary.Add(incomingGroup.UUID, incomingGroup);
+ }
+ foreach (SceneObjectGroup localAfterGroup in localAfterDelinkGroups)
+ {
+ if (!incomingAfterDelinkGroupsDictionary.ContainsKey(localAfterGroup.UUID))
+ {
+ m_log.Warn("DelinkObjectsBySync: local state after delink does not agree with the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
+ afterStateConsistent = false;
+ }
+ else
+ {
+ localAfterGroup.UpdateObjectProperties(incomingAfterDelinkGroupsDictionary[localAfterGroup.UUID]);
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ Monitor.Exit(m_updateLock);
+ }
+
+ if(beforeStateConsistent && afterStateConsistent){
+ m_log.Debug("DelinkObjectsBySync successful");
+ }
+ }
+
+ //Similar to DelinkObjects(), w/o triggering any ScheduleFullUpdate(),
+ private List DelinkObjectsBySync(List prims)
+ {
+ //!!!Caller of this function should already lock on m_updateLock, so no locking here !!!
+
+ List afterDelinkGroups = new List();
+
+ List childParts = new List();
+ List rootParts = new List();
+ List affectedGroups = new List();
+
+ foreach (SceneObjectPart part in prims)
+ {
+ if (part != null)
+ {
+ if (part.ParentGroup.PrimCount != 1) // Skip single
+ {
+ if (part.LinkNum < 2) // Root
+ rootParts.Add(part);
+ else
+ childParts.Add(part);
+
+ SceneObjectGroup group = part.ParentGroup;
+ if (!affectedGroups.Contains(group))
+ {
+ affectedGroups.Add(group);
+ }
+ }
+ }
+ }
+
+ foreach (SceneObjectPart child in childParts)
+ {
+ // Unlink all child parts from their groups, w/o triggering unwanted events or syncinfo updates
+ child.ParentGroup.DelinkFromGroupBySync(child, true);
+
+ // These are not in affected groups and will not be
+ // handled further. Do the honors here.
+ child.ParentGroup.HasGroupChanged = true;
+
+ //record the after-delink-groups
+ afterDelinkGroups.Add(child.ParentGroup);
+ }
+
+ foreach (SceneObjectPart root in rootParts)
+ {
+ // In most cases, this will run only one time, and the prim
+ // will be a solo prim
+ // However, editing linked parts and unlinking may be different
+ //
+ SceneObjectGroup group = root.ParentGroup;
+
+ List newSet = new List(group.Parts);
+ int numChildren = newSet.Count;
+
+ // If there are prims left in a link set, but the root is
+ // slated for unlink, we need to do this
+ //
+ if (numChildren != 1)
+ {
+ // Unlink the remaining set
+ //
+ bool sendEventsToRemainder = true;
+ if (numChildren > 1)
+ sendEventsToRemainder = false;
+
+ foreach (SceneObjectPart p in newSet)
+ {
+ if (p != group.RootPart)
+ group.DelinkFromGroupBySync(p, sendEventsToRemainder);
+ }
+
+ // If there is more than one prim remaining, we
+ // need to re-link
+ //
+ if (numChildren > 2)
+ {
+ // Remove old root
+ //
+ if (newSet.Contains(root))
+ newSet.Remove(root);
+
+ // Preserve link ordering
+ //
+ newSet.Sort(delegate(SceneObjectPart a, SceneObjectPart b)
+ {
+ return a.LinkNum.CompareTo(b.LinkNum);
+ });
+
+ // Determine new root
+ //
+ SceneObjectPart newRoot = newSet[0];
+ newSet.RemoveAt(0);
+
+ foreach (SceneObjectPart newChild in newSet)
+ newChild.UpdateFlag = 0;
+
+ LinkObjectsBySync(newRoot, newSet);
+ if (!affectedGroups.Contains(newRoot.ParentGroup))
+ affectedGroups.Add(newRoot.ParentGroup);
+ }
+ }
+ }
+
+ foreach (SceneObjectGroup g in affectedGroups)
+ {
+ g.TriggerScriptChangedEvent(Changed.LINK);
+ g.HasGroupChanged = true; // Persist
+
+ afterDelinkGroups.Add(g);
+ }
+
+ 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)
+ {
+ Monitor.Enter(m_updateLock);
+ try
+ {
+ 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);
+ }
+ }
+
+ //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/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 0b03d2c242..605e591bf8 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -3685,7 +3685,7 @@ namespace OpenSim.Region.Framework.Scenes
}
//Similar actions with DelinkFromGroup, except that m_scene.AddNewSceneObjectBySync is called
- private SceneObjectGroup DelinkFromGroupBySync(SceneObjectPart linkPart, bool sendEvents)
+ public SceneObjectGroup DelinkFromGroupBySync(SceneObjectPart linkPart, bool sendEvents)
{
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 8aa4ca4516..61583160ef 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -5093,7 +5093,7 @@ namespace OpenSim.Region.Framework.Scenes
m_parentGroup.Scene.EventManager.TriggerAggregateScriptEvents(this);
}
- m_log.Debug("SceneObjectPart Name-" +Name+", localID-" + m_localId + " updated");
+ m_log.Debug("SceneObjectPart Name-" +Name+", UUID-"+UUID+" localID-" + m_localId + " updated");
return partUpdateResult;
}