diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 5f543ddf01..8813e437da 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -206,6 +206,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + //SendSceneUpdates put each update into an outgoing queue of each SyncConnector public void SendSceneUpdates() { // Existing value of 1 indicates that updates are currently being sent so skip updates this pass @@ -310,6 +311,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule }); } + //The following Sendxxx calls,send out a message immediately, w/o putting it in the SyncConnector's outgoing queue. + //May need some optimization there on the priorities. + public void SendTerrainUpdates(string lastUpdateActorID) { if(m_isSyncRelay || m_actorID.Equals(lastUpdateActorID)) @@ -320,6 +324,114 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + /// + /// Send a sync message to remove the given objects in all connected actors. + /// UUID is used for identified a removed object. This function now should + /// only be triggered by an object removal that is initiated locally. + /// + /// + //private void RegionSyncModule_OnObjectBeingRemovedFromScene(SceneObjectGroup sog) + public void SendDeleteObject(SceneObjectGroup sog, bool softDelete) + { + //m_log.DebugFormat("RegionSyncModule_OnObjectBeingRemovedFromScene called at time {0}:{1}:{2}", DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond); + + //Only send the message out if this is a relay node for sync messages, or this actor caused deleting the object + //if (m_isSyncRelay || CheckObjectForSendingUpdate(sog)) + + + OSDMap data = new OSDMap(); + //data["regionHandle"] = OSD.FromULong(regionHandle); + //data["localID"] = OSD.FromUInteger(sog.LocalId); + data["UUID"] = OSD.FromUUID(sog.UUID); + data["actorID"] = OSD.FromString(m_actorID); + data["softDelete"] = OSD.FromBoolean(softDelete); + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); + SendObjectUpdateToRelevantSyncConnectors(sog, rsm); + } + + + public void SendLinkObject(SceneObjectPart root, List children) + { + if(children.Count==0) return; + + OSDMap data = new OSDMap(); + //string sogxml = SceneObjectSerializer.ToXml2Format(linkedGroup); + //data["linkedGroup"]=OSD.FromString(sogxml); + data["root"] = OSD.FromUUID(root.UUID); + data["partCount"] = OSD.FromInteger(children.Count); + data["actorID"] = OSD.FromString(m_actorID); + int partNum = 0; + foreach(SceneObjectPart part in children){ + string partTempID = "part"+partNum; + data[partTempID] = OSD.FromUUID(part.UUID); + partNum++; + } + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.LinkObject, OSDParser.SerializeJsonString(data)); + SendObjectUpdateToRelevantSyncConnectors(root.ParentGroup, rsm); + } + + + public void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs) + { + switch (ev) + { + case EventManager.EventNames.NewScript: + if (evArgs.Length < 3) + { + m_log.Error(LogHeader + " not enough event args for NewScript"); + return; + } + OnLocalNewScript((UUID)evArgs[0], (SceneObjectPart)evArgs[1], (UUID)evArgs[2]); + return; + case EventManager.EventNames.UpdateScript: + if (evArgs.Length < 5) + { + m_log.Error(LogHeader + " not enough event args for UpdateScript"); + return; + } + OnLocalUpdateScript((UUID)evArgs[0], (UUID)evArgs[1], (UUID)evArgs[2], (bool)evArgs[3], (UUID)evArgs[4]); + return; + case EventManager.EventNames.ScriptReset: + if (evArgs.Length < 2) + { + m_log.Error(LogHeader + " not enough event args for ScriptReset"); + return; + } + OnLocalScriptReset((uint)evArgs[0], (UUID)evArgs[1]); + return; + case EventManager.EventNames.ChatFromClient: + if (evArgs.Length < 2) + { + m_log.Error(LogHeader + " not enough event args for ChatFromClient"); + return; + } + OnLocalChatFromClient(evArgs[0], (OSChatMessage)evArgs[1]); + return; + case EventManager.EventNames.ChatFromWorld: + if (evArgs.Length < 2) + { + m_log.Error(LogHeader + " not enough event args for ChatFromWorld"); + return; + } + OnLocalChatFromWorld(evArgs[0], (OSChatMessage)evArgs[1]); + return; + case EventManager.EventNames.ObjectGrab: + OnLocalGrabObject((uint)evArgs[0], (uint)evArgs[1], (Vector3)evArgs[2], (IClientAPI)evArgs[3], (SurfaceTouchEventArgs)evArgs[4]); + return; + case EventManager.EventNames.ObjectGrabbing: + OnLocalObjectGrabbing((uint)evArgs[0], (uint)evArgs[1], (Vector3)evArgs[2], (IClientAPI)evArgs[3], (SurfaceTouchEventArgs)evArgs[4]); + return; + case EventManager.EventNames.ObjectDeGrab: + OnLocalDeGrabObject((uint)evArgs[0], (uint)evArgs[1], (IClientAPI)evArgs[2], (SurfaceTouchEventArgs)evArgs[3]); + return; + default: + return; + } + } + + #endregion //IRegionSyncModule #region ICommandableModule Members @@ -855,7 +967,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule /// The handler for processing incoming sync messages. /// /// - public void HandleIncomingMessage(SymmetricSyncMessage msg) + public void HandleIncomingMessage(SymmetricSyncMessage msg, string senderActorID) { switch (msg.Type) { @@ -903,6 +1015,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule HandleRemovedObject(msg); return; } + case SymmetricSyncMessage.MsgType.LinkObject: + { + HandleLinkObject(msg); + return; + } //EVENTS PROCESSING case SymmetricSyncMessage.MsgType.NewScript: case SymmetricSyncMessage.MsgType.UpdateScript: @@ -1059,6 +1176,38 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + private void HandleLinkObject(SymmetricSyncMessage msg) + { + // 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; + } + + string init_actorID = data["actorID"].AsString(); + //string sogxml = data["linkedGroup"].AsString(); + //SceneObjectGroup linkedGroup = SceneObjectSerializer.FromXml2Format(sogxml); + UUID rootID = data["root"].AsUUID(); + int partCount = data["partCount"].AsInteger(); + List childrenIDs = new List(); + + for (int i = 0; i < partCount; i++) + { + string partTempID = "part" + i; + childrenIDs.Add(data[partTempID].AsUUID()); + } + + m_scene.LinkObjectBySync(rootID, childrenIDs); + + //if this is a relay node, forwards the event + if (m_isSyncRelay) + { + SendSceneEventToRelevantSyncConnectors(init_actorID, msg); + } + } + /// /// The common actions for handling remote events (event initiated at other actors and propogated here) /// @@ -1346,89 +1495,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_scene.EventManager.TriggerObjectDeGrabLocally(part.LocalId, originalID, remoteClinet, surfaceArgs); } - /// - /// Send a sync message to remove the given objects in all connected actors. - /// UUID is used for identified a removed object. This function now should - /// only be triggered by an object removal that is initiated locally. - /// - /// - //private void RegionSyncModule_OnObjectBeingRemovedFromScene(SceneObjectGroup sog) - public void SendDeleteObject(SceneObjectGroup sog, bool softDelete) - { - //m_log.DebugFormat("RegionSyncModule_OnObjectBeingRemovedFromScene called at time {0}:{1}:{2}", DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond); - - //Only send the message out if this is a relay node for sync messages, or this actor caused deleting the object - //if (m_isSyncRelay || CheckObjectForSendingUpdate(sog)) - - - OSDMap data = new OSDMap(1); - //data["regionHandle"] = OSD.FromULong(regionHandle); - //data["localID"] = OSD.FromUInteger(sog.LocalId); - data["UUID"] = OSD.FromUUID(sog.UUID); - data["actorID"] = OSD.FromString(m_actorID); - data["softDelete"] = OSD.FromBoolean(softDelete); - - SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); - SendObjectUpdateToRelevantSyncConnectors(sog, rsm); - } - - public void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs) - { - switch (ev) - { - case EventManager.EventNames.NewScript: - if (evArgs.Length < 3) - { - m_log.Error(LogHeader + " not enough event args for NewScript"); - return; - } - OnLocalNewScript((UUID)evArgs[0], (SceneObjectPart)evArgs[1], (UUID)evArgs[2]); - return; - case EventManager.EventNames.UpdateScript: - if (evArgs.Length < 5) - { - m_log.Error(LogHeader + " not enough event args for UpdateScript"); - return; - } - OnLocalUpdateScript((UUID)evArgs[0], (UUID)evArgs[1], (UUID)evArgs[2], (bool)evArgs[3], (UUID)evArgs[4]); - return; - case EventManager.EventNames.ScriptReset: - if (evArgs.Length < 2) - { - m_log.Error(LogHeader + " not enough event args for ScriptReset"); - return; - } - OnLocalScriptReset((uint)evArgs[0], (UUID)evArgs[1]); - return; - case EventManager.EventNames.ChatFromClient: - if (evArgs.Length < 2) - { - m_log.Error(LogHeader + " not enough event args for ChatFromClient"); - return; - } - OnLocalChatFromClient(evArgs[0], (OSChatMessage)evArgs[1]); - return; - case EventManager.EventNames.ChatFromWorld: - if (evArgs.Length < 2) - { - m_log.Error(LogHeader + " not enough event args for ChatFromWorld"); - return; - } - OnLocalChatFromWorld(evArgs[0], (OSChatMessage)evArgs[1]); - return; - case EventManager.EventNames.ObjectGrab: - OnLocalGrabObject((uint)evArgs[0], (uint)evArgs[1], (Vector3) evArgs[2], (IClientAPI) evArgs[3], (SurfaceTouchEventArgs)evArgs[4]); - return; - case EventManager.EventNames.ObjectGrabbing: - OnLocalObjectGrabbing((uint)evArgs[0], (uint)evArgs[1], (Vector3)evArgs[2], (IClientAPI)evArgs[3], (SurfaceTouchEventArgs)evArgs[4]); - return; - case EventManager.EventNames.ObjectDeGrab: - OnLocalDeGrabObject((uint)evArgs[0], (uint)evArgs[1], (IClientAPI)evArgs[2], (SurfaceTouchEventArgs)evArgs[3]); - return; - default: - return; - } - } /// /// The handler for (locally initiated) event OnNewScript: triggered by client's RezSript packet, publish it to other actors. diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs index 8e5f09bb8f..381216f132 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs @@ -30,6 +30,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule NewObject, // objects UpdatedObject, // objects RemovedObject, // objects + LinkObject, RegionName, //RegionStatus, ActorID, diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index 6f2e915b36..105ce77559 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -292,7 +292,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //For any other messages, we simply deliver the message to RegionSyncModule for now. //Later on, we may deliver messages to different modules, say sync message to RegionSyncModule and event message to ActorSyncModule. - m_regionSyncModule.HandleIncomingMessage(msg); + m_regionSyncModule.HandleIncomingMessage(msg, m_syncOtherSideActorID); } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs index 5048434859..41629c20d6 100755 --- a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs @@ -60,10 +60,15 @@ namespace OpenSim.Region.Framework.Interfaces void QueueSceneObjectPartForUpdate(SceneObjectPart part); void QueueScenePresenceForTerseUpdate(ScenePresence presence); - //void SendUpdatesToSynchronizeState(List sog); + //SendSceneUpdates put each update into an outgoing queue of each SyncConnector void SendSceneUpdates(); + + //In RegionSyncModule's implementation, + //The following calls send out a message immediately, w/o putting it in the SyncConnector's outgoing queue. + //May need some optimization there on the priorities. void SendTerrainUpdates(string lastUpdateActorID); void SendDeleteObject(SceneObjectGroup sog, bool softDelete); + void SendLinkObject(SceneObjectPart root, List children); //For propogating scene events to other actors void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 9b0340879e..e810d502e1 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -725,6 +725,74 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGraph.AddSceneObjectByStateSynch(group); } + public void DebugSceneObjectGroups() + { + EntityBase[] entities = Entities.GetEntities(); + List groups = new List(); + + foreach (EntityBase ent in entities) + { + if (ent is SceneObjectGroup) + { + SceneObjectGroup sog = (SceneObjectGroup)ent; + groups.Add(sog); + } + } + + m_log.Debug("Scene " + m_regInfo.RegionName + " has " + groups.Count + " SOGs"); + foreach (SceneObjectGroup sog in groups) + { + string sogDebug = sog.DebugObjectUpdateResult(); + m_log.Debug(sogDebug); + } + } + + //Assuming that the permission and owner checking is done at the actor that initiates the link operation, so + //no checking of permissions here. + /// + /// Update the grouping relations of the SceneObjectParts as identified by the rootID and childrenIDs, and update the properties of all the parts in the new object group. + /// + /// + /// + /// + public void LinkObjectBySync(UUID rootID, List childrenIDs) + { + m_log.Debug("Start to LinkObjectBySync"); + DebugSceneObjectGroups(); + + List children = new List(); + SceneObjectPart root = GetSceneObjectPart(rootID); + + if (root == null) + { + m_log.Warn("LinkObjectBySync: root part " + rootID + " not found at local Scene copy"); + return; + } + + foreach (UUID childID in childrenIDs) + { + SceneObjectPart part = GetSceneObjectPart(childID); + + if (part == null) + { + m_log.Warn("LinkObjectBySync: child part " + rootID + " not found at local Scene copy"); + continue; + } + + children.Add(part); + } + + //Leverage the LinkObject implementation to get the book keeping of Group and Parts relations right + m_sceneGraph.LinkObjectsBySync(root, children); + + //The properties of the newly linked object should be updated later with another UpdatedObject message. + + //Set the property values as in the incoming copy of the object group + //SceneObjectGroup localGroup = root.ParentGroup; + //localGroup.UpdateObjectProperties(linkedGroup); + + } + #endregion //SYMMETRIC SYNC public ICapabilitiesModule CapsModule diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 99c150ff3c..987468f1c5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1576,6 +1576,24 @@ namespace OpenSim.Region.Framework.Scenes return; // parent is null so not in this region } + + //SYMMETRIC SYNC + //Send out a LinkObject message for synchronization purpose, before other object-update sync messages are sent out. + //We need to do this before the calling to parentGroup.LinkToGroup() below, as LinkToGroup will trigger + //SendDeleteObject message to be sent out. + + // ------------- NOTE: This needs further optimization, as we don't want to block on sending messages while inside the lock. ------------- + // However, we also want to make sure that the LinkObject message is sent out with high priority and sent + // earlier than the object update message triggered by the ScheduleGroupForFullUpdate() function below + if (m_parentScene.RegionSyncModule != null) + { + //Tell other actors to link the SceneObjectParts together as a new group. But not updating the properties yet. + //The properties will be updated later when parentGroup.ScheduleGroupForFullUpdate() is called below. + m_parentScene.RegionSyncModule.SendLinkObject(root, children); + } + + //end of SYMMETRIC SYNC + foreach (SceneObjectGroup child in childGroups) { parentGroup.LinkToGroup(child); @@ -1585,6 +1603,7 @@ namespace OpenSim.Region.Framework.Scenes child.AbsolutePosition = child.AbsolutePosition; } + // We need to explicitly resend the newly link prim's object properties since no other actions // occur on link to invoke this elsewhere (such as object selection) parentGroup.RootPart.CreateSelected = true; @@ -1946,6 +1965,7 @@ namespace OpenSim.Region.Framework.Scenes public Scene.ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup updatedSog) { UUID sogID = updatedSog.UUID; + Scene.ObjectUpdateResult updateResult = Scene.ObjectUpdateResult.Unchanged; if (Entities.ContainsKey(sogID)) { @@ -1954,22 +1974,27 @@ namespace OpenSim.Region.Framework.Scenes if (entity is SceneObjectGroup) { SceneObjectGroup localSog = (SceneObjectGroup)entity; - Scene.ObjectUpdateResult updateResult = localSog.UpdateObjectGroupBySync(updatedSog); - return updateResult; + updateResult = localSog.UpdateObjectGroupBySync(updatedSog); } else { m_log.Warn("Entity with " + sogID + " is not of type SceneObjectGroup"); //return false; - return Scene.ObjectUpdateResult.Error; + updateResult = Scene.ObjectUpdateResult.Error; } } else { m_log.Debug("AddSceneObjectByStateSynch to be called"); AddSceneObjectByStateSynch(updatedSog); - return Scene.ObjectUpdateResult.New; + updateResult = Scene.ObjectUpdateResult.New; } + + //Debug + m_log.Debug("after AddOrUpdateObjectBySynchronization"); + m_parentScene.DebugSceneObjectGroups(); + + return updateResult; } //This is called when an object is added due to receiving a state synchronization message from Scene or an actor. Do similar things as the original AddSceneObject(), @@ -2058,6 +2083,62 @@ namespace OpenSim.Region.Framework.Scenes } } + public void LinkObjectsBySync(SceneObjectPart root, List children) + { + Monitor.Enter(m_updateLock); + try + { + SceneObjectGroup parentGroup = root.ParentGroup; + + List childGroups = new List(); + if (parentGroup != null) + { + // We do this in reverse to get the link order of the prims correct + for (int i = children.Count - 1; i >= 0; i--) + { + SceneObjectGroup child = children[i].ParentGroup; + + if (child != null) + { + // Make sure no child prim is set for sale + // So that, on delink, no prims are unwittingly + // left for sale and sold off + child.RootPart.ObjectSaleType = 0; + child.RootPart.SalePrice = 10; + childGroups.Add(child); + } + } + } + else + { + return; // parent is null so not in this region + } + + foreach (SceneObjectGroup child in childGroups) + { + parentGroup.LinkToGroupBySync(child); + + // this is here so physics gets updated! + // Don't remove! Bad juju! Stay away! or fix physics! + child.AbsolutePosition = child.AbsolutePosition; + } + + + // We need to explicitly resend the newly link prim's object properties since no other actions + // occur on link to invoke this elsewhere (such as object selection) + parentGroup.RootPart.CreateSelected = true; + parentGroup.TriggerScriptChangedEvent(Changed.LINK); + parentGroup.HasGroupChanged = true; + //Do not change the timestamp and actorID values + parentGroup.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + + } + finally + { + Monitor.Exit(m_updateLock); + } + } + #endregion //SYMMETRIC SYNC } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 32e79517fd..625f6d6217 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2127,6 +2127,7 @@ namespace OpenSim.Region.Framework.Scenes //ScheduleGroupForFullUpdate(); //SYMMETRIC SYNC + //The DeleteObject message will be enqueued to be sent out by another thread, and the call will return quickly. if (m_scene.RegionSyncModule != null) m_scene.RegionSyncModule.SendDeleteObject(objectGroup, true); //end of SYMMETRIC SYNC @@ -3648,9 +3649,33 @@ namespace OpenSim.Region.Framework.Scenes ScheduleGroupForFullUpdate_SyncInfoUnchanged(); } + //debug the update result + if (groupUpdateResult == Scene.ObjectUpdateResult.Updated) + { + DebugObjectUpdateResult(); + } + return groupUpdateResult; } + public string DebugObjectUpdateResult() + { + //m_log.Debug("ObjectGroup " + UUID + " updated. Rootpart: " +m_rootPart.DebugObjectPartProperties()); + string sogDebug = "ObjectGroup " + UUID + ".\n Rootpart: " + m_rootPart.DebugObjectPartProperties(); + + int partNum = 1; + foreach (SceneObjectPart part in Parts) + { + if (part.UUID != m_rootPart.UUID) + { + //m_log.Debug("part " + partNum + ", " + part.DebugObjectPartProperties()); + sogDebug += "\n"+part.DebugObjectPartProperties(); + partNum++; + } + } + return sogDebug; + } + private void AddNewPart(SceneObjectPart newPart) { //set the parent relationship @@ -3750,6 +3775,91 @@ namespace OpenSim.Region.Framework.Scenes } } + //Similar to LinkToGroup(), except that not calling RegionSyncModule.SendDeleteObject + public void LinkToGroupBySync(SceneObjectGroup objectGroup) + { + + SceneObjectPart linkPart = objectGroup.m_rootPart; + + Vector3 oldGroupPosition = linkPart.GroupPosition; + Quaternion oldRootRotation = linkPart.RotationOffset; + + linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; + linkPart.GroupPosition = AbsolutePosition; + Vector3 axPos = linkPart.OffsetPosition; + + Quaternion parentRot = m_rootPart.RotationOffset; + axPos *= Quaternion.Inverse(parentRot); + + linkPart.OffsetPosition = axPos; + Quaternion oldRot = linkPart.RotationOffset; + Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; + linkPart.RotationOffset = newRot; + + linkPart.ParentID = m_rootPart.LocalId; + if (m_rootPart.LinkNum == 0) + m_rootPart.LinkNum = 1; + + lock (m_parts.SyncRoot) + { + m_parts.Add(linkPart.UUID, linkPart); + + // Insert in terms of link numbers, the new links + // before the current ones (with the exception of + // the root prim. Shuffle the old ones up + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part.LinkNum != 1) + { + // Don't update root prim link number + part.LinkNum += objectGroup.PrimCount; + } + } + + linkPart.LinkNum = 2; + + linkPart.SetParent(this); + linkPart.CreateSelected = true; + + //if (linkPart.PhysActor != null) + //{ + // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); + + //linkPart.PhysActor = null; + //} + + //TODO: rest of parts + int linkNum = 3; + SceneObjectPart[] ogParts = objectGroup.Parts; + for (int i = 0; i < ogParts.Length; i++) + { + SceneObjectPart part = ogParts[i]; + if (part.UUID != objectGroup.m_rootPart.UUID) + LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); + part.ClearUndoState(); + } + } + + m_scene.UnlinkSceneObject(objectGroup, true); + objectGroup.m_isDeleted = true; + + objectGroup.m_parts.Clear(); + + // Can't do this yet since backup still makes use of the root part without any synchronization + // objectGroup.m_rootPart = null; + + AttachToBackup(); + + // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the + // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and + // unmoved prims! + ResetChildPrimPhysicsPositions(); + + } + + #endregion } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index fb6e231885..97745aac02 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -5084,6 +5084,8 @@ namespace OpenSim.Region.Framework.Scenes m_parentGroup.Scene.EventManager.TriggerAggregateScriptEvents(this); } + m_log.Debug("SceneObjectPart Name-" +Name+", localID-" + m_localId + " updated"); + return partUpdateResult; } @@ -5097,6 +5099,12 @@ namespace OpenSim.Region.Framework.Scenes return false; } + public string DebugObjectPartProperties() + { + string debugMsg = "UUID " + UUID + ", Name " + Name + ", localID " + LocalId + ", lastUpdateActorID " + LastUpdateActorID + ", lastUpdateTimeStamp " + LastUpdateTimeStamp; + return debugMsg; + } + /// /// Schedules this prim for a full update, without changing the timestamp or actorID (info on when and who modified any property). /// NOTE: this is the same as the original SceneObjectPart.ScheduleFullUpdate(). diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index a22e3f174c..536c0145c5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -654,6 +654,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance if (m_Suspended) return 0; + lock (m_Script) { EventParams data = null; @@ -674,6 +675,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance return 0; } + m_log.DebugFormat("[Script] processing event {2} in state {3} to {0}.{1}, localID -{4}", m_PrimName, m_ScriptName, data.EventName, m_State, m_LocalID); + + if (data.EventName == "timer") m_TimerQueued = false; if (data.EventName == "control") @@ -712,8 +716,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { SceneObjectPart part = m_Engine.World.GetSceneObjectPart( m_LocalID); - // m_log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", - // m_PrimName, m_ScriptName, data.EventName, m_State); try { @@ -786,6 +788,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } } + m_log.DebugFormat("[Script] processing event {2} in state {3} to {0}.{1}, localID -{4}; to trigger QueueEventHandler", m_PrimName, m_ScriptName, data.EventName, m_State, m_LocalID); + lock (m_EventQueue) { if ((m_EventQueue.Count > 0) && m_RunEvents && (!m_ShuttingDown))