diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index ff262648e5..0c815d284d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -591,7 +591,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } so.AbsolutePosition = AttachOffset; - so.RootPart.AttachedPos = AttachOffset; + so.RootPart.AttachedPos = AttachOffset; so.RootPart.IsAttachment = true; so.RootPart.SetParentLocalId(avatar.LocalId); @@ -611,7 +611,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } so.IsSelected = false; // fudge.... - so.ScheduleGroupForFullUpdate(); + //so.ScheduleGroupForFullUpdate(); + so.ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //just force it to sychronize all properties } // In case it is later dropped again, don't let diff --git a/OpenSim/Region/CoreModules/Avatar/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/CoreModules/Avatar/ObjectCaps/UploadObjectAssetModule.cs index 3114d7ff59..f366b421ee 100644 --- a/OpenSim/Region/CoreModules/Avatar/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/ObjectCaps/UploadObjectAssetModule.cs @@ -352,7 +352,8 @@ namespace OpenSim.Region.CoreModules.Avatar.ObjectCaps rootGroup.LinkToGroup(allparts[j]); } - rootGroup.ScheduleGroupForFullUpdate(); + //rootGroup.ScheduleGroupForFullUpdate(); + rootGroup.ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //seems like new object pos = m_scene.GetNewRezLocation(Vector3.Zero, rootpos, UUID.Zero, rot, (byte)1, 1, true, allparts[0].GroupScale(), false); responsedata["int_response_code"] = 200; //501; //410; //404; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index d87f91602f..b7e68d06d3 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1581,7 +1581,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (destination != null && !CrossPrimGroupIntoNewRegion(destination, grp, silent)) { grp.OffsetForNewRegion(oldGroupPosition); - grp.ScheduleGroupForFullUpdate(); + //grp.ScheduleGroupForFullUpdate(); + grp.ScheduleGroupForFullUpdate(SceneObjectPartProperties.Position); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 7bb8789f16..91d8edc24e 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -600,7 +600,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // if not, we set it's position in world. if (!attachment) { - group.ScheduleGroupForFullUpdate(); + //group.ScheduleGroupForFullUpdate(); + group.ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //new object float offsetHeight = 0; pos = m_Scene.GetNewRezLocation( @@ -698,7 +699,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); rootPart.ParentGroup.ResumeScripts(); - rootPart.ScheduleFullUpdate(); + //rootPart.ScheduleFullUpdate(); + rootPart.ScheduleFullUpdate(SceneObjectPartProperties.FullUpdate); } if (!m_Scene.Permissions.BypassPermissions()) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs index 3040866e46..bc8e4bac76 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs @@ -321,7 +321,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //RegionSyncMessage.HandleSuccess(LogHeader(), msg, String.Format("Object \"{0}\" ({1}) ({1}) updated.", sog.Name, sog.UUID.ToString(), sog.LocalId.ToString())); //else //RegionSyncMessage.HandleSuccess(LogHeader(), msg, String.Format("Object \"{0}\" ({1}) ({1}) added.", sog.Name, sog.UUID.ToString(), sog.LocalId.ToString())); - sog.ScheduleGroupForFullUpdate(); + //sog.ScheduleGroupForFullUpdate(); } return; } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs index 3167d901c4..8024edee2f 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs @@ -550,7 +550,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //the prim is not the root-part, set the offset position primToUpdate.OffsetPosition = pos; parent.HasGroupChanged = true; - parent.ScheduleGroupForTerseUpdate(); + //parent.ScheduleGroupForTerseUpdate(); + parent.ScheduleGroupForTerseUpdate(SceneObjectPartProperties.OffsetPosition); } } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 247af727da..b0e81c3863 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -182,8 +182,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_isSyncRelay; } } - private Dictionary m_primPropertyBucketMap = new Dictionary(); - public Dictionary PrimPropertyBucketMap + private Dictionary m_primPropertyBucketMap = new Dictionary(); + public Dictionary PrimPropertyBucketMap { get { return m_primPropertyBucketMap; } } @@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule PupolatePropertyBuketMapByDefault(); //Pass the bucket information to SceneObjectPart. - SceneObjectPart.InitializeBucketInfo(m_primPropertyBucketMap, m_propertyBucketDescription, m_actorID); + SceneObjectPart.InitializePropertyBucketInfo(m_primPropertyBucketMap, m_propertyBucketDescription, m_actorID); } @@ -226,6 +226,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_propertyBucketDescription.Add(physicsBucketName); m_maxNumOfPropertyBuckets = 2; + /* foreach (string pName in SceneObjectPart.PropertyList) { switch (pName){ @@ -253,6 +254,36 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule break; } } + * */ + + foreach (SceneObjectPartProperties property in Enum.GetValues(typeof(SceneObjectPartProperties))) + { + switch (property) + { + case SceneObjectPartProperties.GroupPosition: + case SceneObjectPartProperties.OffsetPosition: + case SceneObjectPartProperties.Scale: + case SceneObjectPartProperties.Velocity: + case SceneObjectPartProperties.AngularVelocity: + case SceneObjectPartProperties.RotationOffset: + case SceneObjectPartProperties.Position: + case SceneObjectPartProperties.Size: + case SceneObjectPartProperties.Force: + case SceneObjectPartProperties.RotationalVelocity: + case SceneObjectPartProperties.PA_Acceleration: + case SceneObjectPartProperties.Torque: + case SceneObjectPartProperties.Orientation: + case SceneObjectPartProperties.IsPhysical: + case SceneObjectPartProperties.Flying: + case SceneObjectPartProperties.Buoyancy: + m_primPropertyBucketMap.Add(property, physicsBucketName); + break; + default: + //all other properties belong to the "General" bucket. + m_primPropertyBucketMap.Add(property, generalBucketName); + break; + } + } } private bool IsSyncingWithOtherActors() @@ -263,7 +294,28 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule public void QueueSceneObjectPartForUpdate(SceneObjectPart part) { //if the last update of the prim is caused by this actor itself, or if the actor is a relay node, then enqueue the update - if (part.LastUpdateActorID.Equals(m_actorID) || m_isSyncRelay) + //if (part.LastUpdateActorID.Equals(m_actorID) || m_isSyncRelay) + bool updated = m_isSyncRelay; + + if (!updated) + { + /* + foreach (KeyValuePair pair in part.BucketSyncInfoList) + { + if (pair.Value.LastUpdateActorID.Equals(m_actorID)) + { + updated = true; + break; + } + } + * */ + if (part.HasPropertyUpdatedLocally()) + { + updated = true; + } + } + + if(updated) { lock (m_updateSceneObjectPartLock) { @@ -274,10 +326,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule public void QueueScenePresenceForTerseUpdate(ScenePresence presence) { + /* lock (m_updateScenePresenceLock) { m_presenceUpdates[presence.UUID] = presence; } + * */ } //SendSceneUpdates put each update into an outgoing queue of each SyncConnector @@ -321,6 +375,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule if (primUpdates != null || presenceUpdates != null) { + long timeStamp = DateTime.Now.Ticks; + // This could be another thread for sending outgoing messages or just have the Queue functions // create and queue the messages directly into the outgoing server thread. System.Threading.ThreadPool.QueueUserWorkItem(delegate @@ -333,6 +389,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule foreach (SceneObjectGroup sog in primUpdates) { //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))) { //send @@ -459,6 +516,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } + //First, make sure the linked group has updated timestamp info for synchronization + linkedGroup.BucketSyncInfoUpdate(); + OSDMap data = new OSDMap(); string sogxml = SceneObjectSerializer.ToXml2Format(linkedGroup); data["linkedGroup"]=OSD.FromString(sogxml); @@ -517,6 +577,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule groupNum++; } + //make sure the newly delinked objects have the updated timestamp information + foreach (SceneObjectGroup sog in afterDelinkGroups) + { + sog.BucketSyncInfoUpdate(); + } + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.DelinkObject, OSDParser.SerializeJsonString(data)); SendDelinkObjectToRelevantSyncConnectors(beforeDelinkGroups, rsm); } @@ -741,7 +807,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } /// - /// Check if we need to send out an update message for the given object. + /// Check if we need to send out an update message for the given object. For now, we have a very inefficient solution: + /// If any synchronization bucket in any part shows a property in that bucket has changed, we'll serialize and ship the whole object. /// /// /// @@ -750,10 +817,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //If any part in the object has the last update caused by this actor itself, then send the update foreach (SceneObjectPart part in sog.Parts) { + /* if (part.LastUpdateActorID.Equals(m_actorID)) { return true; } + * */ + + foreach (KeyValuePair pair in part.BucketSyncInfoList) + { + if (pair.Value.LastUpdateActorID.Equals(m_actorID)) + { + return true; + } + } } return false; @@ -991,6 +1068,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //save script state and stop script instances m_scene.EventManager.TriggerOnSymmetricSyncStop(); } + m_synced = true; } else { @@ -1072,11 +1150,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { syncConnector.StartCommThreads(); AddSyncConnector(syncConnector); + m_synced = true; } } - m_synced = true; - return true; } diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index 7c5d044347..c909c195de 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs @@ -236,7 +236,8 @@ namespace OpenSim.Region.CoreModules.Media.Moap part.Shape.Media[face] = me; UpdateMediaUrl(part, UUID.Zero); - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.MediaUrl); part.TriggerScriptChangedEvent(Changed.MEDIA); } @@ -421,7 +422,9 @@ namespace OpenSim.Region.CoreModules.Media.Moap UpdateMediaUrl(part, agentId); // Arguably, we could avoid sending a full update to the avatar that just changed the texture. - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.Shape); + part.ScheduleFullUpdate(SceneObjectPartProperties.MediaUrl); //not an efficient way to taint two properties, but should not have bad side effects part.TriggerScriptChangedEvent(Changed.MEDIA); @@ -499,7 +502,8 @@ namespace OpenSim.Region.CoreModules.Media.Moap UpdateMediaUrl(part, agentId); - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.MediaUrl); part.TriggerScriptChangedEvent(Changed.MEDIA); diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs index be399ff65b..efa58ef710 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs @@ -148,7 +148,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell part.GetProperties(remoteClient); part.TriggerScriptChangedEvent(Changed.OWNER); group.ResumeScripts(); - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.FullUpdate); //quite some properties changed, let's just force all to be synchronized break; diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs index 5bd5957706..db3fd98e7a 100755 --- a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs @@ -56,6 +56,15 @@ namespace OpenSim.Region.Framework.Interfaces DSGActorTypes DSGActorType { get; set; } bool IsSyncRelay { get; } + /// + /// The mapping of a property (identified by its name) to the index of a bucket. + /// + Dictionary PrimPropertyBucketMap { get; } + /// + /// The text description of the properties in each bucket, e.g. "General", "Physics" + /// + List PropertyBucketDescription { get; } + //Enqueue updates for scene-objects and scene-presences void QueueSceneObjectPartForUpdate(SceneObjectPart part); void QueueScenePresenceForTerseUpdate(ScenePresence presence); diff --git a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs index 7251d57f69..bf80a32a47 100644 --- a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs +++ b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs @@ -34,7 +34,8 @@ namespace OpenSim.Region.Framework.Interfaces { void Reset(); void Close(); - void QueuePartForUpdate(SceneObjectPart part); + //void QueuePartForUpdate(SceneObjectPart part); + void QueuePartForUpdate(SceneObjectPartBase part); void SendPrimUpdates(); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index cb3de01774..510831d0b1 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1720,7 +1720,7 @@ namespace OpenSim.Region.Framework.Scenes * */ if (RegionSyncModule != null) { - part.SyncInfoUpdate(); + //part.SyncInfoUpdate(); EventManager.TriggerNewScript(remoteClient.AgentId, part, copyID); } else @@ -1798,7 +1798,7 @@ namespace OpenSim.Region.Framework.Scenes //part.ParentGroup.ResumeScripts(); if (RegionSyncModule != null) { - part.SyncInfoUpdate(); + //part.SyncInfoUpdate(); EventManager.TriggerNewScript(remoteClient.AgentId, part, taskItem.ItemID); } else @@ -2197,7 +2197,8 @@ namespace OpenSim.Region.Framework.Scenes // to find out if scripts should be activated at all. group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); - group.ScheduleGroupForFullUpdate(); + //group.ScheduleGroupForFullUpdate(); + group.ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //new object, all properties have new value return group; } @@ -2262,7 +2263,8 @@ namespace OpenSim.Region.Framework.Scenes { sog.SetOwnerId(ownerID); sog.SetGroup(groupID, remoteClient); - sog.ScheduleGroupForFullUpdate(); + //sog.ScheduleGroupForFullUpdate(); + sog.ScheduleGroupForFullUpdate(SceneObjectPartProperties.OwnerID); SceneObjectPart[] partList = sog.Parts; diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index ab567fbcb0..db8c75f1ca 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -208,11 +208,12 @@ namespace OpenSim.Region.Framework.Scenes // TODO: Make selection flagging per prim! // part.ParentGroup.IsSelected = false; - + if (part.ParentGroup.IsAttachment) isAttachment = true; else - part.ParentGroup.ScheduleGroupForFullUpdate(); + //part.ParentGroup.ScheduleGroupForFullUpdate(); + part.ParentGroup.ScheduleGroupForFullUpdate(SceneObjectPartProperties.IsSelected); // If it's not an attachment, and we are allowed to move it, // then we might have done so. If we moved across a parcel diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index cf6428c8a6..af08e7bd9c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -795,7 +795,7 @@ namespace OpenSim.Region.Framework.Scenes //Set the property values as in the incoming copy of the object group SceneObjectGroup localGroup = root.ParentGroup; - localGroup.UpdateObjectProperties(linkedGroup); + localGroup.UpdateObjectGroupBySync(linkedGroup); //debug /* @@ -2391,7 +2391,8 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.SetGroup(groupID, null); } - sceneObject.ScheduleGroupForFullUpdate(); + //sceneObject.ScheduleGroupForFullUpdate(); + sceneObject.ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //new object, all properties have new value return sceneObject; } @@ -2560,16 +2561,6 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); - //SYMMETRIC SYNC - //Set the ActorID and TimeStamp info for this latest update - /* - foreach (SceneObjectPart part in group.Parts) - { - part.SyncInfoUpdate(); - } - * - * */ - //Propagate the RemovedObject message if (RegionSyncModule != null) { @@ -4500,7 +4491,8 @@ namespace OpenSim.Region.Framework.Scenes { if (ent is SceneObjectGroup) { - ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(); + //((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(); + ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); //This is not due to property being updated, hence passing "None" property. } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index c3bace8447..96a7075942 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -374,7 +374,8 @@ namespace OpenSim.Region.Framework.Scenes if (scale.Z > m_parentScene.m_maxNonphys) scale.Z = m_parentScene.m_maxNonphys; - part.Shape.Scale = scale; + //part.Shape.Scale = scale; + part.Scale = scale; } } m_numPrim += children.Length; @@ -382,7 +383,8 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.AttachToScene(m_parentScene); if (sendClientUpdates) - sceneObject.ScheduleGroupForFullUpdate(); + //sceneObject.ScheduleGroupForFullUpdate(); + sceneObject.ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); Entities.Add(sceneObject); @@ -1599,7 +1601,6 @@ namespace OpenSim.Region.Framework.Scenes if (m_parentScene.RegionSyncModule != null) { //Tell other actors to link the SceneObjectParts together as a new group. - parentGroup.SyncInfoUpdate(); m_parentScene.RegionSyncModule.SendLinkObject(parentGroup, root, children); } @@ -1746,20 +1747,11 @@ namespace OpenSim.Region.Framework.Scenes } //SYMMETRIC SYNC - //set timestamp - long timeStamp = DateTime.Now.Ticks; - string actorID = m_parentScene.GetSyncActorID(); - foreach (SceneObjectGroup sog in afterDelinkGroups) - { - if (m_parentScene.RegionSyncModule != null) - { - sog.SyncInfoUpdate(timeStamp, actorID); ; - } - } //Send out DelinkObject message to other actors to sychronize their object list - m_parentScene.RegionSyncModule.SendDeLinkObject(prims, beforeDelinkGroups, afterDelinkGroups); - - + if (m_parentScene.RegionSyncModule != null) + { + m_parentScene.RegionSyncModule.SendDeLinkObject(prims, beforeDelinkGroups, afterDelinkGroups); + } //Schedule updates as in legacy OpenSim code, to send updates to viewers connected to this actor (at least needed for client managers). //But timestamp won't be changed, so that when other actors get the update, they's simple ignore the updates since they already get them foreach (SceneObjectGroup sog in afterDelinkGroups) @@ -1902,7 +1894,8 @@ namespace OpenSim.Region.Framework.Scenes copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); copy.HasGroupChanged = true; - copy.ScheduleGroupForFullUpdate(); + //copy.ScheduleGroupForFullUpdate(); + copy.ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //new object, all property values are new copy.ResumeScripts(); // required for physics to update it's position @@ -1971,7 +1964,7 @@ namespace OpenSim.Region.Framework.Scenes { //if we need to debug the script engine with a viewer attaching to it, //we need to schedule updates to be sent to the viewer - oldSog.ScheduleGroupForFullUpdate(); + oldSog.ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); } } else @@ -2051,7 +2044,8 @@ namespace OpenSim.Region.Framework.Scenes { foreach (SceneObjectPart part in children) { - Vector3 scale = part.Shape.Scale; + SceneObjectPartBase partBase = (SceneObjectPartBase)part; + Vector3 scale = partBase.Scale; if (scale.X > m_parentScene.m_maxNonphys) scale.X = m_parentScene.m_maxNonphys; @@ -2060,12 +2054,15 @@ namespace OpenSim.Region.Framework.Scenes if (scale.Z > m_parentScene.m_maxNonphys) scale.Z = m_parentScene.m_maxNonphys; - part.Shape.Scale = scale; + part.Scale = scale; } } m_numPrim += children.Length; + //SYMMETRIC SYNC, sceneObject.AttachToScene(m_parentScene); + //sceneObject.AttachToSceneBySync(m_parentScene); + //end of SYMMETRIC SYNC, //SYMMETRIC SYNC, sceneObject.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); @@ -2140,8 +2137,18 @@ namespace OpenSim.Region.Framework.Scenes // 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; + //SYMMETRIC SYNC: need to copy value w/o trigger UpdateBucketSyncInfo + //child.RootPart.ObjectSaleType = 0; + //child.RootPart.SalePrice = 10; + //child.RootPart.SetObjectSaleType(0); + //child.RootPart.SetSalePrice(10); + //child.RootPart.SetProperty("ObjectSaleType", 0); + //child.RootPart.SetProperty("SalePrice", 10); + + //casting SOP to SOPBase to make sure we call SOPBase.Property set function, not the SOP.Property set function + SceneObjectPartBase rootPart = (SceneObjectPartBase)child.RootPart; + rootPart.ObjectSaleType = 0; + rootPart.SalePrice = 10; childGroups.Add(child); } } @@ -2291,7 +2298,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - localAfterGroup.UpdateObjectProperties(incomingAfterDelinkGroupsDictionary[localAfterGroup.UUID]); + localAfterGroup.UpdateObjectGroupBySync(incomingAfterDelinkGroupsDictionary[localAfterGroup.UUID]); } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 8a951f1df8..d4a7d1099e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -294,6 +294,12 @@ namespace OpenSim.Region.Framework.Scenes get { return m_rootPart.GroupPosition; } set { + /* + SetAbsolutePosition(value); + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + parts[i].UpdateBucketSyncInfo("GroupPosition"); + */ Vector3 val = value; //REGION SYNC touched @@ -328,6 +334,39 @@ namespace OpenSim.Region.Framework.Scenes //m_rootPart.GroupPosition.Z); //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); //} + + } + } + public void SetAbsolutePosition(Vector3 value) + { + Vector3 val = value; + + //REGION SYNC touched + + //if ((m_scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || m_scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) + // || m_scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || m_scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) + // && !IsAttachmentCheckFull()) + if (m_scene.IsBorderCrossing(LocX, LocY, val) && !IsAttachmentCheckFull() && (!m_scene.LoadingPrims)) + { + m_scene.CrossPrimGroupIntoNewRegion(val, this, true); + } + //end REGION SYNC touched + if (RootPart.GetStatusSandbox()) + { + if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) + { + RootPart.ScriptSetPhysicsStatus(false); + Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), + ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); + return; + } + } + + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + parts[i].GroupPosition = val; + //parts[i].SetGroupPosition(val); } } @@ -465,6 +504,20 @@ namespace OpenSim.Region.Framework.Scenes #region Constructors + //SYMMETRIC SYNC + public SceneObjectGroup(SceneObjectPart part, bool newGroupBySync) + { + if (!newGroupBySync) + { + SetRootPart(part); + } + else + { + SetRootPartBySync(part); + } + + } + /// /// Constructor /// @@ -969,7 +1022,8 @@ namespace OpenSim.Region.Framework.Scenes RootPart.RemFlag(PrimFlags.TemporaryOnRez); AttachToBackup(); m_scene.EventManager.TriggerParcelPrimCountTainted(); - m_rootPart.ScheduleFullUpdate(); + //m_rootPart.ScheduleFullUpdate(); + m_rootPart.ScheduleFullUpdate(SceneObjectPartProperties.AttachmentPoint); //Physics properties, such as Position, OffsetPosition, etc, should be tainted in ApplyPhysics() m_rootPart.ClearUndoState(); } @@ -1242,7 +1296,8 @@ namespace OpenSim.Region.Framework.Scenes m_scene.RemoveGroupTarget(this); } - ScheduleGroupForFullUpdate(); + //ScheduleGroupForFullUpdate(); + ScheduleGroupForFullUpdate(SceneObjectPartProperties.Flags); } public void SetText(string text, Vector3 color, double alpha) @@ -1254,7 +1309,8 @@ namespace OpenSim.Region.Framework.Scenes Text = text; HasGroupChanged = true; - m_rootPart.ScheduleFullUpdate(); + //m_rootPart.ScheduleFullUpdate(); + m_rootPart.ScheduleFullUpdate(SceneObjectPartProperties.Text); } /// @@ -1488,7 +1544,8 @@ namespace OpenSim.Region.Framework.Scenes dupe.HasGroupChanged = true; dupe.AttachToBackup(); - ScheduleGroupForFullUpdate(); + //ScheduleGroupForFullUpdate(); + ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); //This full-update is triggered by copying, no property changed } return dupe; @@ -1741,7 +1798,8 @@ namespace OpenSim.Region.Framework.Scenes ApplyNextOwnerPermissions(); } - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.OwnerID); } /// @@ -1866,33 +1924,38 @@ namespace OpenSim.Region.Framework.Scenes /// /// Schedule a full update for this scene object /// - public void ScheduleGroupForFullUpdate() + //public void ScheduleGroupForFullUpdate() + public void ScheduleGroupForFullUpdate(SceneObjectPartProperties property) { // if (IsAttachment) // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); checkAtTargets(); - RootPart.ScheduleFullUpdate(); + //RootPart.ScheduleFullUpdate(); + RootPart.ScheduleFullUpdate(property); SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part != RootPart) - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(property); } } /// /// Schedule a terse update for this scene object /// - public void ScheduleGroupForTerseUpdate() + //public void ScheduleGroupForTerseUpdate() + public void ScheduleGroupForTerseUpdate(SceneObjectPartProperties property) { // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) - parts[i].ScheduleTerseUpdate(); + //parts[i].ScheduleTerseUpdate(); + parts[i].ScheduleTerseUpdate(property); } /// @@ -2650,7 +2713,8 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; part.TriggerScriptChangedEvent(Changed.SCALE); - ScheduleGroupForFullUpdate(); + //ScheduleGroupForFullUpdate(); + ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); //above actions only update Scale for the given part, and part.Resize() will taint Scale as updated //if (part.UUID == m_rootPart.UUID) //{ @@ -2802,7 +2866,8 @@ namespace OpenSim.Region.Framework.Scenes part.StoreUndoState(); HasGroupChanged = true; m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); - ScheduleGroupForTerseUpdate(); + //ScheduleGroupForTerseUpdate(); + ScheduleGroupForTerseUpdate(SceneObjectPartProperties.Scale); } } @@ -2843,7 +2908,8 @@ namespace OpenSim.Region.Framework.Scenes //we need to do a terse update even if the move wasn't allowed // so that the position is reset in the client (the object snaps back) - ScheduleGroupForTerseUpdate(); + //ScheduleGroupForTerseUpdate(); + ScheduleGroupForTerseUpdate(SceneObjectPartProperties.GroupPosition); } /// @@ -2906,7 +2972,8 @@ namespace OpenSim.Region.Framework.Scenes AbsolutePosition = newPos; HasGroupChanged = true; - ScheduleGroupForTerseUpdate(); + //ScheduleGroupForTerseUpdate(); + ScheduleGroupForTerseUpdate(SceneObjectPartProperties.Position); } public void OffsetForNewRegion(Vector3 offset) @@ -2938,7 +3005,8 @@ namespace OpenSim.Region.Framework.Scenes } HasGroupChanged = true; - ScheduleGroupForTerseUpdate(); + //ScheduleGroupForTerseUpdate(); + ScheduleGroupForTerseUpdate(SceneObjectPartProperties.None); //Above actions only update m_rootPart's RotationOffset, and m_rootPart.UpdateRotation will taint RotationOffset as updated } /// @@ -2964,7 +3032,8 @@ namespace OpenSim.Region.Framework.Scenes AbsolutePosition = pos; HasGroupChanged = true; - ScheduleGroupForTerseUpdate(); + //ScheduleGroupForTerseUpdate(); + ScheduleGroupForTerseUpdate(SceneObjectPartProperties.Position); //RotationOffset is only updated for m_rootPart, and m_rootPart.UpdateRotation should already taint RotationOffset as updated } /// @@ -3051,7 +3120,8 @@ namespace OpenSim.Region.Framework.Scenes Quaternion newRot = primsRot * oldParentRot; newRot *= Quaternion.Inverse(axRot); prim.RotationOffset = newRot; - prim.ScheduleTerseUpdate(); + //prim.ScheduleTerseUpdate(); + prim.ScheduleTerseUpdate(SceneObjectPartProperties.RotationOffset | SceneObjectPartProperties.OffsetPosition); } } @@ -3065,7 +3135,8 @@ namespace OpenSim.Region.Framework.Scenes } } - m_rootPart.ScheduleTerseUpdate(); + //m_rootPart.ScheduleTerseUpdate(); + m_rootPart.ScheduleTerseUpdate(SceneObjectPartProperties.RotationOffset); } #endregion @@ -3694,12 +3765,16 @@ namespace OpenSim.Region.Framework.Scenes } //Similar actions with DelinkFromGroup, except that m_scene.AddNewSceneObjectBySync is called - public SceneObjectGroup DelinkFromGroupBySync(SceneObjectPart linkPart, bool sendEvents) + //!!!!!!!!!!!!!!!!!!NOTE!!!!!!!!!!!!!!! + //All SOP properties below is set through calling SetXXX(value) instead of by "XXX=value", as such a value is being changed due to sync ( + //i.e. triggered by remote operation instead of by local operation + public SceneObjectGroup DelinkFromGroupBySync(SceneObjectPart delinkPart, bool sendEvents) { -// m_log.DebugFormat( -// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", -// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); - + // m_log.DebugFormat( + // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", + // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); + + SceneObjectPartBase linkPart = (SceneObjectPartBase)delinkPart; linkPart.ClearUndoState(); Quaternion worldRot = linkPart.GetWorldRotation(); @@ -3714,21 +3789,28 @@ namespace OpenSim.Region.Framework.Scenes if (parts.Length == 1 && RootPart != null) { // Single prim left - RootPart.LinkNum = 0; + //RootPart.LinkNum = 0; + //RootPart.SetProperty("LinkNum", 0); + ((SceneObjectPartBase)RootPart).LinkNum = 0; } else { for (int i = 0; i < parts.Length; i++) { - SceneObjectPart part = parts[i]; + SceneObjectPartBase part = (SceneObjectPartBase)parts[i]; if (part.LinkNum > linkPart.LinkNum) + { part.LinkNum--; + //int linkNum = part.LinkNum - 1; + //part.SetProperty("LinkNum", linkNum); + } } } } - linkPart.ParentID = 0; + linkPart.ParentID = 0; //ParentID is a value set only locally and ignored in synchronization, so no need to call SetProperty to set its value linkPart.LinkNum = 0; + //linkPart.SetParentID(0); if (linkPart.PhysActor != null) { @@ -3745,10 +3827,20 @@ namespace OpenSim.Region.Framework.Scenes linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); - linkPart.RotationOffset = worldRot; - SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); + //linkPart.SetOffsetPosition(new Vector3(axPos.X, axPos.Y, axPos.Z)); + //linkPart.SetGroupPosition(AbsolutePosition + linkPart.OffsetPosition); + //linkPart.SetOffsetPosition(new Vector3(0, 0, 0)); + //linkPart.SetRotationOffset(worldRot); + //linkPart.SetProperty("OffsetPosition", new Vector3(axPos.X, axPos.Y, axPos.Z)); + //linkPart.SetProperty("GroupPosition", AbsolutePosition + linkPart.OffsetPosition); + //linkPart.SetProperty("OffsetPosition", new Vector3(0, 0, 0)); + //linkPart.SetProperty("RotationOffset", worldRot); + + //SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); + bool newGroupBySync = true; + SceneObjectGroup objectGroup = new SceneObjectGroup(delinkPart, newGroupBySync); m_scene.AddNewSceneObjectBySync(objectGroup, true); @@ -3764,7 +3856,24 @@ namespace OpenSim.Region.Framework.Scenes return objectGroup; } + /// + /// Set a part to act as the root part for this scene object, in which SetProperty("LinkNum",) is called instead of "LinkNum=". + /// + /// + public void SetRootPartBySync(SceneObjectPart part) + { + if (part == null) + throw new ArgumentNullException("Cannot give SceneObjectGroup a null root SceneObjectPart"); + part.SetParent(this); + m_rootPart = part; + if (!IsAttachment) + part.ParentID = 0; +// part.SetProperty("LinkNum", 0); + ((SceneObjectPartBase)part).LinkNum = 0; + + m_parts.Add(m_rootPart.UUID, m_rootPart); + } public void ScheduleGroupForFullUpdate_SyncInfoUnchanged() { @@ -3788,30 +3897,40 @@ namespace OpenSim.Region.Framework.Scenes public void LinkToGroupBySync(SceneObjectGroup objectGroup) { - SceneObjectPart linkPart = objectGroup.m_rootPart; - + SceneObjectPartBase linkPart = (SceneObjectPartBase)objectGroup.m_rootPart; + Vector3 oldGroupPosition = linkPart.GroupPosition; Quaternion oldRootRotation = linkPart.RotationOffset; linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; linkPart.GroupPosition = AbsolutePosition; + //linkPart.SetOffsetPosition(linkPart.GroupPosition - AbsolutePosition); + //linkPart.SetGroupPosition(AbsolutePosition); + //linkPart.SetProperty("OffsetPosition", linkPart.GroupPosition - AbsolutePosition); + //linkPart.SetProperty("GroupPosition", AbsolutePosition); Vector3 axPos = linkPart.OffsetPosition; Quaternion parentRot = m_rootPart.RotationOffset; axPos *= Quaternion.Inverse(parentRot); linkPart.OffsetPosition = axPos; + //linkPart.SetOffsetPosition(axPos); + //linkPart.SetProperty("OffsetPosition", axPos); Quaternion oldRot = linkPart.RotationOffset; Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; linkPart.RotationOffset = newRot; + //linkPart.SetRotationOffset(newRot); + //linkPart.SetProperty("RotationOffset", newRot); + //ParentID is only valid locally, so remote value is ignored and no syncinfo will be modified linkPart.ParentID = m_rootPart.LocalId; if (m_rootPart.LinkNum == 0) - m_rootPart.LinkNum = 1; + ((SceneObjectPartBase)m_rootPart).LinkNum = 1; + //m_rootPart.SetProperty("LinkNum",1); lock (m_parts.SyncRoot) { - m_parts.Add(linkPart.UUID, linkPart); + m_parts.Add(linkPart.UUID, (SceneObjectPart) linkPart); // Insert in terms of link numbers, the new links // before the current ones (with the exception of @@ -3819,15 +3938,17 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { - SceneObjectPart part = parts[i]; + SceneObjectPartBase part = (SceneObjectPartBase)parts[i]; if (part.LinkNum != 1) { // Don't update root prim link number part.LinkNum += objectGroup.PrimCount; + //part.SetProperty("LinkNum",objectGroup.PrimCount); } } linkPart.LinkNum = 2; + //linkPart.SetProperty("LinkNum",2); linkPart.SetParent(this); linkPart.CreateSelected = true; @@ -3846,7 +3967,7 @@ namespace OpenSim.Region.Framework.Scenes { SceneObjectPart part = ogParts[i]; if (part.UUID != objectGroup.m_rootPart.UUID) - LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); + LinkNonRootPartBySync(part, oldGroupPosition, oldRootRotation, linkNum++); part.ClearUndoState(); } } @@ -3864,20 +3985,80 @@ namespace OpenSim.Region.Framework.Scenes // 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(); + //ResetChildPrimPhysicsPositions(); + //EntityBase sogBase = (EntityBase)this; + //sogBase.AbsolutePosition = AbsolutePosition; + SetAbsolutePosition(AbsolutePosition); } - public void SyncInfoUpdate() + private void LinkNonRootPartBySync(SceneObjectPart linkPart, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) + { + Quaternion parentRot = oldGroupRotation; + Quaternion oldRot = linkPart.RotationOffset; + Quaternion worldRot = parentRot * oldRot; + + parentRot = oldGroupRotation; + + Vector3 axPos = linkPart.OffsetPosition; + + SceneObjectPartBase part = (SceneObjectPartBase)linkPart; + axPos *= parentRot; + part.OffsetPosition = axPos; + part.GroupPosition = oldGroupPosition + part.OffsetPosition; + part.OffsetPosition = Vector3.Zero; + part.RotationOffset = worldRot; + //part.SetOffsetPosition(axPos); + //part.SetGroupPosition(oldGroupPosition + part.OffsetPosition); + //part.SetOffsetPosition(Vector3.Zero); + //part.SetRotationOffset(worldRot); + //part.SetProperty("OffsetPosition", axPos); + //part.SetProperty("GroupPosition", oldGroupPosition + part.OffsetPosition); + //part.SetProperty("OffsetPosition", Vector3.Zero); + //part.SetProperty("RotationOffset", worldRot); + + part.SetParent(this); + part.ParentID = m_rootPart.LocalId; + + m_parts.Add(part.UUID, linkPart); + + part.LinkNum = linkNum; + //part.SetProperty("LinkNum",linkNum); + + part.OffsetPosition = part.GroupPosition - AbsolutePosition; + //part.SetOffsetPosition(part.GroupPosition - AbsolutePosition); + //part.SetProperty("OffsetPosition", part.GroupPosition - AbsolutePosition); + + Quaternion rootRotation = m_rootPart.RotationOffset; + + Vector3 pos = part.OffsetPosition; + pos *= Quaternion.Inverse(rootRotation); + part.OffsetPosition = pos; + //part.SetOffsetPosition(pos); + //part.SetProperty("OffsetPosition", pos); + + parentRot = m_rootPart.RotationOffset; + oldRot = part.RotationOffset; + Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; + part.RotationOffset = newRot; + //part.SetRotationOffset(newRot); + //part.SetProperty("RotationOffset", newRot); + } + + + + public void BucketSyncInfoUpdate() { long timeStamp = DateTime.Now.Ticks; string actorID = m_scene.GetSyncActorID(); foreach (SceneObjectPart part in Parts) { - part.SyncInfoUpdate(timeStamp, actorID); + //part.SyncInfoUpdate(timeStamp, actorID); + part.UpdateAllBucketSyncInfo(timeStamp); } } + /* public void SyncInfoUpdate(long timeStamp, string actorID) { foreach (SceneObjectPart part in Parts) @@ -3885,6 +4066,53 @@ namespace OpenSim.Region.Framework.Scenes part.SyncInfoUpdate(timeStamp, actorID); } } + * */ + + /// + /// Attach this object to a scene after a new object is created due to receiving a sync message. + /// Code similar to AttachToScene, except that this does not invoke InitializeBucketSyncInfo of each part, + /// as that information is included in the incoming message. + /// + /// + public void AttachToSceneBySync(Scene scene) + { + m_scene = scene; + RegionHandle = m_scene.RegionInfo.RegionHandle; + + if (m_rootPart.Shape.PCode != 9 || m_rootPart.Shape.State == 0) + m_rootPart.ParentID = 0; + if (m_rootPart.LocalId == 0) + m_rootPart.LocalId = m_scene.AllocateLocalId(); + + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (Object.ReferenceEquals(part, m_rootPart)) + continue; + + if (part.LocalId == 0) + part.LocalId = m_scene.AllocateLocalId(); + + part.ParentID = m_rootPart.LocalId; + //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID); + } + + ApplyPhysics(m_scene.m_physicalPrim); + + // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled + // for the same object with very different properties. The caller must schedule the update. + //ScheduleGroupForFullUpdate(); + + } + + public void UpdateTaintedBucketSyncInfo(long timeStamp) + { + foreach (SceneObjectPart part in Parts) + { + part.UpdateTaintedBucketSyncInfo(timeStamp); + } + } #endregion } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index dbde8f202c..89f68b6058 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -107,64 +107,15 @@ namespace OpenSim.Region.Framework.Scenes #endregion Enumerations - //SYMMETRIC SYNC - - //Information for concurrency control of one bucket of prim proproperties. - public class BucketSyncInfo - { - private long m_lastUpdateTimeStamp; - private string m_lastUpdateActorID; - //lock for concurrent updates of the timestamp and actorID. - private Object m_updateLock = new Object(); - private string m_bucketName; - - public long LastUpdateTimeStamp - { - get { return m_lastUpdateTimeStamp; } - } - - public string LastUpdateActorID - { - get { return m_lastUpdateActorID; } - } - - public string BucketName - { - get { return m_bucketName; } - } - - public BucketSyncInfo(string bucketName) - { - m_bucketName = bucketName; - } - - public BucketSyncInfo(long timeStamp, string actorID, string bucketName) - { - m_lastUpdateTimeStamp = timeStamp; - m_lastUpdateActorID = actorID; - m_bucketName = bucketName; - } - - public void UpdateSyncInfo(long timeStamp, string actorID) - { - lock (m_updateLock) - { - m_lastUpdateTimeStamp = timeStamp; - m_lastUpdateActorID = actorID; - } - } - - } - //end of SYMMETRIC SYNC - - public class SceneObjectPart : IScriptHost, ISceneEntity + //public class SceneObjectPart : IScriptHost, ISceneEntity + public abstract class SceneObjectPartBase : IScriptHost, ISceneEntity { /// /// Denote all sides of the prim /// public const int ALL_SIDES = -1; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Is this sop a root part? @@ -185,15 +136,9 @@ namespace OpenSim.Region.Framework.Scenes get { return m_allowedDrop; } set { - //m_allowedDrop = value; - SetAllowedDrop(value); - UpdateBucketSyncInfo("AllowedDrop"); + m_allowedDrop = value; } } - public void SetAllowedDrop(bool value) - { - m_allowedDrop = value; - } public bool DIE_AT_EDGE; @@ -325,7 +270,8 @@ namespace OpenSim.Region.Framework.Scenes { get { return m_inventory; } } - protected SceneObjectPartInventory m_inventory; + //protected SceneObjectPartInventory m_inventory; + protected SceneObjectPartInventoryBase m_inventory; public bool Undoing; @@ -365,7 +311,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// TODO - This should be an enumeration /// - private byte m_updateFlag; + //private byte m_updateFlag; + protected byte m_updateFlag; private PhysicsActor m_physActor; protected Vector3 m_acceleration; @@ -406,7 +353,8 @@ namespace OpenSim.Region.Framework.Scenes private bool m_forceMouselook; // TODO: Collision sound should have default. - private UUID m_collisionSound; + //private UUID m_collisionSound; + protected UUID m_collisionSound; private float m_collisionSoundVolume; #endregion Fields @@ -416,14 +364,16 @@ namespace OpenSim.Region.Framework.Scenes /// /// No arg constructor called by region restore db code /// - public SceneObjectPart() + //public SceneObjectPart() + public SceneObjectPartBase() { // It's not necessary to persist this m_TextureAnimation = Utils.EmptyBytes; m_particleSystem = Utils.EmptyBytes; Rezzed = DateTime.UtcNow; - m_inventory = new SceneObjectPartInventory(this); + //m_inventory = new SceneObjectPartInventory(this); + m_inventory = new SceneObjectPartInventoryBase(this); } /// @@ -434,7 +384,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public SceneObjectPart( + //public SceneObjectPart( + public SceneObjectPartBase( UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, Quaternion rotationOffset, Vector3 offsetPosition) { @@ -473,7 +424,8 @@ namespace OpenSim.Region.Framework.Scenes TrimPermissions(); //m_undo = new UndoStack(ParentGroup.GetSceneMaxUndo()); - m_inventory = new SceneObjectPartInventory(this); + //m_inventory = new SceneObjectPartInventory(this); + m_inventory = new SceneObjectPartInventoryBase(this); } #endregion Constructors @@ -798,11 +750,6 @@ namespace OpenSim.Region.Framework.Scenes } set { - SetGroupPosition(value); - UpdateBucketSyncInfo("GroupPosition"); - - /* - //Legacy Opensim code m_groupPosition = value; PhysicsActor actor = PhysActor; @@ -843,63 +790,14 @@ namespace OpenSim.Region.Framework.Scenes } } } - */ } } - //SYMMETRIC SYNC - public void SetGroupPosition(Vector3 value) - { - m_groupPosition = value; - - PhysicsActor actor = PhysActor; - if (actor != null) - { - try - { - // Root prim actually goes at Position - if (_parentID == 0) - { - actor.Position = value; - } - else - { - // To move the child prim in respect to the group position and rotation we have to calculate - actor.Position = GetWorldPosition(); - actor.Orientation = GetWorldRotation(); - } - - // Tell the physics engines that this prim changed. - m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); - } - catch (Exception e) - { - m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); - } - } - - // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too - if (m_sitTargetAvatar != UUID.Zero) - { - if (m_parentGroup != null) // TODO can there be a SOP without a SOG? - { - ScenePresence avatar; - if (m_parentGroup.Scene.TryGetScenePresence(m_sitTargetAvatar, out avatar)) - { - avatar.ParentPosition = GetWorldPosition(); - } - } - } - } - public Vector3 OffsetPosition { get { return m_offsetPosition; } set { - SetOffsetPosition(value); - UpdateBucketSyncInfo("OffsetPosition"); - /* StoreUndoState(); m_offsetPosition = value; @@ -915,26 +813,6 @@ namespace OpenSim.Region.Framework.Scenes m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); } } - * */ - } - } - //SYMMETRIC SYNC - public void SetOffsetPosition(Vector3 value) - { - StoreUndoState(); - m_offsetPosition = value; - - if (ParentGroup != null && !ParentGroup.IsDeleted) - { - PhysicsActor actor = PhysActor; - if (_parentID != 0 && actor != null) - { - actor.Position = GetWorldPosition(); - actor.Orientation = GetWorldRotation(); - - // Tell the physics engines that this prim changed. - m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); - } } } @@ -976,9 +854,6 @@ namespace OpenSim.Region.Framework.Scenes set { - SetRotationOffset(value); - UpdateBucketSyncInfo("RotationOffset"); - /* StoreUndoState(); m_rotationOffset = value; @@ -1008,43 +883,9 @@ namespace OpenSim.Region.Framework.Scenes m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message); } } - * */ } } - //SYMMETRIC SYNC - public void SetRotationOffset(Quaternion value) - { - StoreUndoState(); - m_rotationOffset = value; - - PhysicsActor actor = PhysActor; - if (actor != null) - { - try - { - // Root prim gets value directly - if (_parentID == 0) - { - actor.Orientation = value; - //m_log.Info("[PART]: RO1:" + actor.Orientation.ToString()); - } - else - { - // Child prim we have to calculate it's world rotationwel - Quaternion resultingrotation = GetWorldRotation(); - actor.Orientation = resultingrotation; - //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); - } - m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); - //} - } - catch (Exception ex) - { - m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message); - } - } - } /// public Vector3 Velocity @@ -1065,9 +906,6 @@ namespace OpenSim.Region.Framework.Scenes set { - SetVelocity(value); - UpdateBucketSyncInfo("Velocity"); - /* m_velocity = value; PhysicsActor actor = PhysActor; @@ -1079,22 +917,6 @@ namespace OpenSim.Region.Framework.Scenes m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); } } - * */ - } - } - //SYMMETRIC SYNC - public void SetVelocity(Vector3 value) - { - m_velocity = value; - - PhysicsActor actor = PhysActor; - if (actor != null) - { - if (actor.IsPhysical) - { - actor.Velocity = value; - m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); - } } } @@ -1110,17 +932,7 @@ namespace OpenSim.Region.Framework.Scenes } return m_angularVelocity; } - set - { - SetAngularVelocity(value); - UpdateBucketSyncInfo("AngularVelocity"); - //m_angularVelocity = value; - } - } - //SYMMETRIC SYNC - public void SetAngularVelocity(Vector3 value) - { - m_angularVelocity = value; + set { m_angularVelocity = value; } } /// @@ -1217,9 +1029,6 @@ namespace OpenSim.Region.Framework.Scenes get { return m_shape.Scale; } set { - SetScale(value); - UpdateBucketSyncInfo("Scale"); - /* StoreUndoState(); if (m_shape != null) { @@ -1239,33 +1048,8 @@ namespace OpenSim.Region.Framework.Scenes } } TriggerScriptChangedEvent(Changed.SCALE); - * */ } } - //SYMMETRIC SYNC - public void SetScale(Vector3 value) - { - StoreUndoState(); - if (m_shape != null) - { - m_shape.Scale = value; - - PhysicsActor actor = PhysActor; - if (actor != null && m_parentGroup != null) - { - if (m_parentGroup.Scene != null) - { - if (m_parentGroup.Scene.PhysicsScene != null) - { - actor.Size = m_shape.Scale; - m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); - } - } - } - } - TriggerScriptChangedEvent(Changed.SCALE); - } - public byte UpdateFlag { @@ -1627,7 +1411,7 @@ namespace OpenSim.Region.Framework.Scenes }); // REGION SYNC if (m_parentGroup.Scene.IsSyncedServer()) - m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate(this); + m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate((SceneObjectPart)this); } /// @@ -1635,7 +1419,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void AddFullUpdateToAvatar(ScenePresence presence) { - presence.SceneViewer.QueuePartForUpdate(this); + presence.SceneViewer.QueuePartForUpdate((SceneObjectPart)this); } public void AddNewParticleSystem(Primitive.ParticleSystem pSystem) @@ -1657,12 +1441,12 @@ namespace OpenSim.Region.Framework.Scenes }); // REGION SYNC if (m_parentGroup.Scene.IsSyncedServer()) - m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate(this); + m_parentGroup.Scene.RegionSyncServerModule.QueuePartForUpdate((SceneObjectPart)this); } public void AddTerseUpdateToAvatar(ScenePresence presence) { - presence.SceneViewer.QueuePartForUpdate(this); + presence.SceneViewer.QueuePartForUpdate((SceneObjectPart)this); } public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim) @@ -1936,7 +1720,7 @@ namespace OpenSim.Region.Framework.Scenes dupe.DoPhysicsPropertyUpdate(UsePhysics, true); } - ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, this, userExposed); + ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, (SceneObjectPart) this, userExposed); // m_log.DebugFormat("[SCENE OBJECT PART]: Clone of {0} {1} finished", Name, UUID); @@ -2967,7 +2751,8 @@ namespace OpenSim.Region.Framework.Scenes } //m_parentGroup.RootPart.m_groupPosition = newpos; } - ScheduleTerseUpdate(); + //ScheduleTerseUpdate(); + ScheduleTerseUpdate(SceneObjectPartProperties.Position); //SendTerseUpdateToAllClients(); } @@ -3057,7 +2842,8 @@ namespace OpenSim.Region.Framework.Scenes m_shape.Scale = scale; ParentGroup.HasGroupChanged = true; - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Scale); } public void RotLookAt(Quaternion target, float strength, float damping) @@ -3099,7 +2885,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// Schedules this prim for a full update /// - public void ScheduleFullUpdate() + //public void ScheduleFullUpdate() :: SYMMETRIC SYNC: changed the interface so that we can identify which property triggers calling this function + public virtual void ScheduleFullUpdate(SceneObjectPartProperties sopProperty) { // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId); @@ -3127,20 +2914,14 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", // UUID, Name, TimeStampFull); - - //SYMMETRIC SYNC - - //update information (timestamp, actorID, etc) needed for synchronization across copies of Scene - SyncInfoUpdate(); - - //end of SYMMETRIC SYNC } /// /// Schedule a terse update for this prim. Terse updates only send position, /// rotation, velocity, rotational velocity and shape information. /// - public void ScheduleTerseUpdate() + //public void ScheduleTerseUpdate() + public virtual void ScheduleTerseUpdate(SceneObjectPartProperties sopProperty) { if (m_updateFlag < 1) { @@ -3155,13 +2936,6 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}", // UUID, Name, TimeStampTerse); - - //SYMMETRIC SYNC - - //update information (timestamp, actorID, etc) needed for synchronization across copies of Scene - SyncInfoUpdate(); - - //end of SYMMETRIC SYNC } } @@ -3381,10 +3155,10 @@ namespace OpenSim.Region.Framework.Scenes ClearUpdateSchedule(); //SYMMETRIC SYNC - if (m_parentGroup.Scene.RegionSyncModule == null) - return; - m_parentGroup.Scene.RegionSyncModule.QueueSceneObjectPartForUpdate(this); - + if (m_parentGroup.Scene.RegionSyncModule != null) + { + m_parentGroup.Scene.RegionSyncModule.QueueSceneObjectPartForUpdate((SceneObjectPart)this); + } //end of SYMMETRIC SYNC } @@ -3440,7 +3214,7 @@ namespace OpenSim.Region.Framework.Scenes soundModule.TriggerSound(soundID, ownerID, objectID, parentID, volume, position, regionHandle, radius); else soundModule.PlayAttachedSound(soundID, ownerID, objectID, volume, position, flags, radius); - ParentGroup.PlaySoundMasterPrim = this; + ParentGroup.PlaySoundMasterPrim = (SceneObjectPart)this; ownerID = _ownerID; objectID = ParentGroup.RootPart.UUID; parentID = GetRootPartUUID(); @@ -3467,7 +3241,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - ParentGroup.PlaySoundSlavePrims.Add(this); + ParentGroup.PlaySoundSlavePrims.Add((SceneObjectPart)this); } } else @@ -3848,14 +3622,16 @@ namespace OpenSim.Region.Framework.Scenes Text = text; ParentGroup.HasGroupChanged = true; - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Text); } public void StopLookAt() { m_parentGroup.stopLookAt(); - m_parentGroup.ScheduleGroupForTerseUpdate(); + //m_parentGroup.ScheduleGroupForTerseUpdate(); + m_parentGroup.ScheduleGroupForTerseUpdate(SceneObjectPartProperties.None);//in stopLookAt(), PhysicsActor shall already take care of tainting which properties have been updated } /// @@ -3877,7 +3653,8 @@ namespace OpenSim.Region.Framework.Scenes { m_parentGroup.stopMoveToTarget(); - m_parentGroup.ScheduleGroupForTerseUpdate(); + //m_parentGroup.ScheduleGroupForTerseUpdate(); + m_parentGroup.ScheduleGroupForTerseUpdate(SceneObjectPartProperties.None); //in stopMoveToTarget(), PhysicsActor shall already take care of tainting which properties have been updated //m_parentGroup.ScheduleGroupForFullUpdate(); } @@ -3896,14 +3673,14 @@ namespace OpenSim.Region.Framework.Scenes UndoState last = m_undo.Peek(); if (last != null) { - if (last.Compare(this)) + if (last.Compare((SceneObjectPart)this)) return; } } if (m_parentGroup.GetSceneMaxUndo() > 0) { - UndoState nUndo = new UndoState(this); + UndoState nUndo = new UndoState((SceneObjectPart)this); m_undo.Push(nUndo); } @@ -4356,7 +4133,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void ToXml(XmlTextWriter xmlWriter) { - SceneObjectSerializer.SOPToXml2(xmlWriter, this, new Dictionary()); + SceneObjectSerializer.SOPToXml2(xmlWriter, (SceneObjectPart)this, new Dictionary()); } public void TriggerScriptChangedEvent(Changed val) @@ -4383,12 +4160,12 @@ namespace OpenSim.Region.Framework.Scenes UndoState nUndo = null; if (m_parentGroup.GetSceneMaxUndo() > 0) { - nUndo = new UndoState(this); + nUndo = new UndoState((SceneObjectPart)this); } UndoState goback = m_undo.Pop(); if (goback != null) { - goback.PlaybackState(this); + goback.PlaybackState((SceneObjectPart)this); if (nUndo != null) m_redo.Push(nUndo); } @@ -4402,13 +4179,13 @@ namespace OpenSim.Region.Framework.Scenes { if (m_parentGroup.GetSceneMaxUndo() > 0) { - UndoState nUndo = new UndoState(this); + UndoState nUndo = new UndoState((SceneObjectPart)this); m_undo.Push(nUndo); } UndoState gofwd = m_redo.Pop(); if (gofwd != null) - gofwd.PlayfwdState(this); + gofwd.PlayfwdState((SceneObjectPart)this); } } @@ -4425,7 +4202,8 @@ namespace OpenSim.Region.Framework.Scenes } ParentGroup.HasGroupChanged = true; - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Shape); } public void UpdateGroupPosition(Vector3 pos) @@ -4436,7 +4214,8 @@ namespace OpenSim.Region.Framework.Scenes { Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); GroupPosition = newPos; - ScheduleTerseUpdate(); + //ScheduleTerseUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.GroupPosition); } } @@ -4468,7 +4247,8 @@ namespace OpenSim.Region.Framework.Scenes } OffsetPosition = newPos; - ScheduleTerseUpdate(); + //ScheduleTerseUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.OffsetPosition); } } @@ -4757,7 +4537,8 @@ namespace OpenSim.Region.Framework.Scenes // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); ParentGroup.HasGroupChanged = true; - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Flags); } public void UpdateRotation(Quaternion rot) @@ -4769,7 +4550,8 @@ namespace OpenSim.Region.Framework.Scenes { RotationOffset = rot; ParentGroup.HasGroupChanged = true; - ScheduleTerseUpdate(); + //ScheduleTerseUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.RotationOffset); } } @@ -4814,7 +4596,8 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; TriggerScriptChangedEvent(Changed.SHAPE); - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Shape); } /// @@ -4861,7 +4644,8 @@ namespace OpenSim.Region.Framework.Scenes //This is madness.. //ParentGroup.ScheduleGroupForFullUpdate(); //This is sparta - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Shape); } public void aggregateScriptEvents() @@ -4929,7 +4713,8 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling part {0} {1} for full update in aggregateScriptEvents() since m_parentGroup == null", Name, LocalId); - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Flags); return; } @@ -4952,7 +4737,8 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling part {0} {1} for full update in aggregateScriptEvents()", Name, LocalId); - ScheduleFullUpdate(); + //ScheduleFullUpdate(); + ScheduleFullUpdate(SceneObjectPartProperties.Flags); } } @@ -5156,58 +4942,267 @@ namespace OpenSim.Region.Framework.Scenes set { m_lastUpdateTimeStamp = value; } } - //The ID the identifies which actor has caused the most recent update to the prim. - //We use type "string" for the ID only to make it human-readable. - private string m_lastUpdateActorID=""; + #endregion + + } + + //SYMMETRIC SYNC + + //Information for concurrency control of one bucket of prim proproperties. + public class BucketSyncInfo + { + private long m_lastUpdateTimeStamp; + private string m_lastUpdateActorID; + //lock for concurrent updates of the timestamp and actorID. + private Object m_updateLock = new Object(); + private string m_bucketName; + + public long LastUpdateTimeStamp + { + get { return m_lastUpdateTimeStamp; } + set { m_lastUpdateTimeStamp = value; } + } + public string LastUpdateActorID { get { return m_lastUpdateActorID; } set { m_lastUpdateActorID = value; } } - public void UpdateTimestamp(long time) + public string BucketName { - m_lastUpdateTimeStamp = time; + get { return m_bucketName; } } - public void SetLastUpdateActorID() + public BucketSyncInfo(string bucketName) { - if (m_parentGroup != null) - { - m_lastUpdateActorID = m_parentGroup.Scene.GetSyncActorID(); - } - else - { - m_log.Error("Prim " + UUID + " is not in a SceneObjectGroup yet"); - } + m_bucketName = bucketName; } - private Object m_SyncInfoLock = new Object(); - public void SyncInfoUpdate(long timeStamp, string actorID) + public BucketSyncInfo(long timeStamp, string actorID, string bucketName) { - //update timestamp and actorID atomically - lock (m_SyncInfoLock) + m_lastUpdateTimeStamp = timeStamp; + m_lastUpdateActorID = actorID; + m_bucketName = bucketName; + } + + public void UpdateSyncInfo(long timeStamp, string actorID) + { + lock (m_updateLock) { - UpdateTimestamp(timeStamp); + m_lastUpdateTimeStamp = timeStamp; m_lastUpdateActorID = actorID; } } - - public void SyncInfoUpdate() + } + + /* + public enum SceneObjectPartProperties:ulong + { + //Following properties copied from SceneObjectSerializer(), + AllowedDrop = (ulong) 1<<0, + CreatorID = (ulong) 1<<1, + CreatorData = (ulong) 1 <<2, + FolderID = (ulong) 1 << 3, + InventorySerial = (ulong) 1 << 4, + TaskInventory = (ulong) 1 << 5, + //UUID", + //LocalId", + Name = (ulong) 1 << 6, + Material = (ulong) 1 <<7, + PassTouches = (ulong) 1 << 8, + RegionHandle = (ulong) 1 << 9, + ScriptAccessPin = (ulong) 1 << 10, + GroupPosition = (ulong) 1 << 11, + OffsetPosition = (ulong) 1 << 12, + RotationOffset = (ulong) 1 << 13, + Velocity = (ulong) 1 << 14, + AngularVelocity = (ulong) 1 << 15, + //"Acceleration", + SOP_Acceleration = (ulong) 1 << 16, //SOP and PA read/write their own local copies of acceleration, so we distinguish the copies + Description = (ulong) 1 << 17, + Color = (ulong) 1 << 18, + Text = (ulong) 1 << 19, + SitName = (ulong) 1 << 20, + TouchName = (ulong) 1 << 21, + LinkNum = (ulong) 1 << 22, + ClickAction = (ulong) 1 << 23, + Shape = (ulong) 1 << 24, + Scale = (ulong) 1 << 25, + UpdateFlag = (ulong) 1 << 26, + SitTargetOrientation = (ulong) 1 << 27, + SitTargetPosition = (ulong) 1 << 28, + SitTargetPositionLL = (ulong) 1 << 29, + SitTargetOrientationLL = (ulong) 1 << 30, + ParentID = (ulong)1 << 31, + CreationDate = (ulong) 1 << 32, + Category = (ulong) 1 << 33, + SalePrice = (ulong) 1 << 34, + ObjectSaleType = (ulong) 1 << 35, + OwnershipCost = (ulong) 1 << 36, + GroupID = (ulong) 1 << 37, + OwnerID = (ulong) 1 << 38, + LastOwnerID = (ulong) 1 << 39, + BaseMask = (ulong) 1 << 40, + OwnerMask = (ulong) 1 << 41, + GroupMask = (ulong) 1 << 42, + EveryoneMask = (ulong) 1 << 43, + NextOwnerMask = (ulong) 1 << 44, + Flags = (ulong) 1 << 45, + CollisionSound = (ulong) 1 << 46, + CollisionSoundVolume = (ulong) 1 << 47, + MediaUrl = (ulong) 1 << 48, + TextureAnimation = (ulong) 1 << 49, + ParticleSystem = (ulong) 1 << 50, + //Property names below copied from PhysicsActor, they are necessary in synchronization, but not covered the above properties + //Physics properties "Velocity" is covered above + Position = (ulong) 1 << 51, + Size = (ulong) 1 << 52, + Force = (ulong) 1 << 53, + RotationalVelocity = (ulong) 1 << 54, + PA_Acceleration = (ulong) 1 << 55, + Torque = (ulong) 1 << 56, + Orientation = (ulong) 1 << 57, + IsPhysical = (ulong) 1 << 58, + Flying = (ulong) 1 << 59, + Buoyancy = (ulong) 1 << 60, + //To be handled + AttachmentPoint = (ulong)1 << 61, + FullUpdate = UInt64.MaxValue + } + */ + + public enum SceneObjectPartProperties + { + None, + //Following properties copied from SceneObjectSerializer(), + AllowedDrop , + CreatorID , + CreatorData , + FolderID , + InventorySerial, + TaskInventory, + //UUID", + //LocalId", + Name, + Material, + PassTouches, + RegionHandle, + ScriptAccessPin, + GroupPosition, + OffsetPosition, + RotationOffset, + Velocity, + AngularVelocity, + //"Acceleration", + SOP_Acceleration, //SOP and PA read/write their own local copies of acceleration, so we distinguish the copies + Description, + Color, + Text, + SitName, + TouchName, + LinkNum, + ClickAction, + Shape, + Scale, + UpdateFlag, + SitTargetOrientation, + SitTargetPosition, + SitTargetPositionLL, + SitTargetOrientationLL, + ParentID, + CreationDate, + Category, + SalePrice, + ObjectSaleType, + OwnershipCost, + GroupID, + OwnerID, + LastOwnerID, + BaseMask, + OwnerMask, + GroupMask, + EveryoneMask, + NextOwnerMask, + Flags, + CollisionSound, + CollisionSoundVolume, + MediaUrl, + TextureAnimation, + ParticleSystem, + //Property names below copied from PhysicsActor, they are necessary in synchronization, but not covered the above properties + //Physics properties "Velocity" is covered above + Position, + Size, + Force, + RotationalVelocity, + PA_Acceleration, + Torque, + Orientation, + IsPhysical, + Flying, + Buoyancy, + //To be handled in serialization/deserizaltion for synchronization + IsSelected, + AttachmentPoint, + AttachedPos, + Sound, //This indicates any Sound related property has changed: Sound, SoundGain, SoundFlags,SoundRadius, + //Addition properties to be added here + + //Client Manager may want to add some property here that viewers care about and should be synchronized across actors + + FullUpdate, + } + + + public class SceneObjectPart : SceneObjectPartBase + { + public SceneObjectPart() + : base() { - //Trick: calling UpdateTimestamp here makes sure that when an object was received and de-serialized, before - // its parts are linked together, neither TimeStamp or ActorID will be modified. This is because during de-serialization, - // ScheduleFullUpdate() is called when m_parentGroup == null - if (m_parentGroup != null && m_parentGroup.Scene != null && m_parentGroup.Scene.ActorSyncModule != null) - { - SyncInfoUpdate(DateTime.Now.Ticks, m_parentGroup.Scene.GetSyncActorID()); - } } + public SceneObjectPart( + UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, + Quaternion rotationOffset, Vector3 offsetPosition) + : base(ownerID, shape, groupPosition, rotationOffset, offsetPosition) + { + } + + //The following variables should be initialized when this SceneObjectPart is added into the local Scene. + //private List SynchronizeUpdatesToScene = null; + //public List BucketSyncInfoList + private Dictionary m_bucketSyncInfoList = new Dictionary(); + public Dictionary BucketSyncInfoList + { + get { return m_bucketSyncInfoList; } + set { m_bucketSyncInfoList = value; } + } + //TODO: serialization and deserialization processors to be added in SceneObjectSerializer + + //The following variables are initialized when RegionSyncModule reads the config file for mapping of properties and buckets + private static Dictionary m_primPropertyBucketMap = null; + private static List m_propertyBucketNames = null; + + private static string m_localActorID = ""; + //private static int m_bucketCount = 0; + //private delegate void BucketUpdateProcessor(int bucketIndex); + private delegate void BucketUpdateProcessor(SceneObjectPart updatedPart, string bucketName); + + //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(); + + //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. + private bool m_syncEnabled = false; + //The list of each prim's properties. This is the list of properties that matter in synchronizing prim copies on different actors. //This list is created based on properties included in the serialization/deserialization process (see SceneObjectSerializer()) and the //properties Physics Engine needs to synchronize to other actors. + /* public static List PropertyList = new List() { //Following properties copied from SceneObjectSerializer() @@ -5278,20 +5273,326 @@ namespace OpenSim.Region.Framework.Scenes "Flying", "Buoyancy", }; - + * */ + + + public static void InitializePropertyBucketInfo(Dictionary propertyBucketMap, List bucketNames, string actorID) + { + m_primPropertyBucketMap = propertyBucketMap; + m_propertyBucketNames = bucketNames; + m_localActorID = actorID; + //m_bucketCount = bucketNames.Count; + + //RegisterBucketUpdateProcessor(); + } + + public string DebugObjectPartProperties() + { + string debugMsg = "UUID " + UUID + ", Name " + Name + ", localID " + LocalId; + debugMsg += ", parentID " + ParentID + ", parentUUID " + ParentUUID; + foreach (KeyValuePair pair in m_bucketSyncInfoList) + { + debugMsg += ", Bucket " + pair.Key + ": TimeStamp - " + pair.Value.LastUpdateTimeStamp + ", ActorID - " + pair.Value.LastUpdateActorID; + } + return debugMsg; + } + + /// + /// Link each bucket with the function that applies updates to properties in the bucket upon receiving sync messages. + /// This is the "hard-coded" part in the property-buckets implementation. When new buckets are implemented, + /// the processing functions need to be modified accordingly. + /// + //private static void RegisterBucketUpdateProcessor() + private void RegisterBucketUpdateProcessor() + { + foreach (string bucketName in m_propertyBucketNames) + { + switch (bucketName) + { + case "General": + m_bucketUpdateProcessors.Add(bucketName, GeneralBucketUpdateProcessor); + break; + case "Physics": + m_bucketUpdateProcessors.Add(bucketName, PhysicsBucketUpdateProcessor); + break; + default: + m_log.Warn("Bucket " + bucketName + "'s update processing function not defined yet"); + break; + } + } + } + + private void GeneralBucketUpdateProcessor(SceneObjectPart updatedPart, string bucketName) + { + //If needed, we could define new set functions for these properties, and cast this SOP to SOPBase to + //invoke the set functions in SOPBase + //SceneObjectPartBase localPart = (SceneObjectPartBase)this; + SceneObjectPart localPart = this; + bool collisionSoundUpdated = false; + + lock (m_bucketUpdateLocks[bucketName]) + { + //See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart. + localPart.AllowedDrop = updatedPart.AllowedDrop; + localPart.CreatorID = updatedPart.CreatorID; + localPart.CreatorData = updatedPart.CreatorData; + localPart.FolderID = updatedPart.FolderID; + localPart.InventorySerial = updatedPart.InventorySerial; + localPart.TaskInventory = updatedPart.TaskInventory; + //Following two properties, UUID and LocalId, shall not be updated. + //localPart.UUID + //localPart.LocalId + localPart.Name = updatedPart.Name; + localPart.Material = updatedPart.Material; + localPart.PassTouches = updatedPart.PassTouches; + //RegionHandle shall not be copied, since updatedSog is sent by a different actor, which has a different local region + //localPart.RegionHandle + localPart.ScriptAccessPin = updatedPart.ScriptAccessPin; + + localPart.Description = updatedPart.Description; + localPart.Color = updatedPart.Color; + localPart.Text = updatedPart.Text; + localPart.SitName = updatedPart.SitName; + localPart.TouchName = updatedPart.TouchName; + localPart.LinkNum = updatedPart.LinkNum; + localPart.ClickAction = updatedPart.ClickAction; + localPart.Shape = updatedPart.Shape; + localPart.Scale = updatedPart.Scale; + localPart.UpdateFlag = updatedPart.UpdateFlag; + localPart.SitTargetOrientation = updatedPart.SitTargetOrientation; + localPart.SitTargetPosition = updatedPart.SitTargetPosition; + localPart.SitTargetPositionLL = updatedPart.SitTargetPositionLL; + localPart.SitTargetOrientationLL = updatedPart.SitTargetOrientationLL; + //ParentID should still point to the rootpart in the local sog, do not update. If the root part changed, we will update it in SceneObjectGroup.UpdateObjectProperties() + //localPart.ParentID; + localPart.CreationDate = updatedPart.CreationDate; + localPart.Category = updatedPart.Category; + localPart.SalePrice = updatedPart.SalePrice; + localPart.ObjectSaleType = updatedPart.ObjectSaleType; + localPart.OwnershipCost = updatedPart.OwnershipCost; + localPart.GroupID = updatedPart.GroupID; + localPart.OwnerID = updatedPart.OwnerID; + localPart.LastOwnerID = updatedPart.LastOwnerID; + localPart.BaseMask = updatedPart.BaseMask; + localPart.OwnerMask = updatedPart.OwnerMask; + localPart.GroupMask = updatedPart.GroupMask; + localPart.EveryoneMask = updatedPart.EveryoneMask; + localPart.NextOwnerMask = updatedPart.NextOwnerMask; + localPart.Flags = updatedPart.Flags; + + //We will update CollisionSound with special care so that it does not lead to ScheduleFullUpdate of this part, to make the actor think it just made an update and + //need to propogate that update to other actors. + //localPart.CollisionSound = updatedPart.CollisionSound; + collisionSoundUpdated = UpdateCollisionSound(updatedPart.CollisionSound); + + localPart.CollisionSoundVolume = updatedPart.CollisionSoundVolume; + localPart.MediaUrl = updatedPart.MediaUrl; + localPart.TextureAnimation = updatedPart.TextureAnimation; + localPart.ParticleSystem = updatedPart.ParticleSystem; + + m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp = updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp; + m_bucketSyncInfoList[bucketName].LastUpdateActorID = updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID; + + if (collisionSoundUpdated) + { + //If the local actor is Script Engine, it will catch this evnet and trigger aggregateScriptEvents() + m_parentGroup.Scene.EventManager.TriggerAggregateScriptEvents(this); + } + } + } + + private void PhysicsBucketUpdateProcessor(SceneObjectPart updatedPart, string bucketName) + { + //If needed, we could define new set functions for these properties, and cast this SOP to SOPBase to + //invoke the set functions in SOPBase + //SceneObjectPartBase localPart = (SceneObjectPartBase)this; + SceneObjectPart localPart = this; + + lock (m_bucketUpdateLocks[bucketName]) + { + localPart.GroupPosition = updatedPart.GroupPosition; + localPart.OffsetPosition = updatedPart.OffsetPosition; + localPart.Scale = updatedPart.Scale; + localPart.Velocity = updatedPart.Velocity; + localPart.AngularVelocity = updatedPart.AngularVelocity; + localPart.RotationOffset = updatedPart.RotationOffset; + //properties in Physics bucket whose update processors are in PhysicsActor + /* + "Position": + "Size": + "Force": + "RotationalVelocity": + "PA_Acceleration": + "Torque": + "Orientation": + "IsPhysical": + "Flying": + "Buoyancy": + * */ + + m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp = updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp; + m_bucketSyncInfoList[bucketName].LastUpdateActorID = updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID; + + } + } + + //Initialize and set the values of timestamp and actorID for each synchronization bucket. + //Should be called when the SceneObjectGroup this part is in is added to scene, see SceneObjectGroup.AttachToScene. + private bool m_BucketUpdateProcessorRegistered = false; + public void InitializeBucketSyncInfo() + { + if (m_primPropertyBucketMap == null) + { + m_log.Error("Bucket Information has not been initilized. Return."); + return; + } + long timeStamp = DateTime.Now.Ticks; + + m_log.Debug("InitializeBucketSyncInfo called at " + timeStamp); + + for (int i = 0; i < m_propertyBucketNames.Count; i++) + { + string bucketName = m_propertyBucketNames[i]; + + //If the object is created by de-serialization, then it may already have m_bucketSyncInfoList populated with the right number of buckets. + //If the deserilaization is due to receiving a sync message, then m_bucketSyncInfoList should already be filled with sync info. + if (!m_bucketSyncInfoList.ContainsKey(bucketName)) + { + BucketSyncInfo syncInfo = new BucketSyncInfo(timeStamp, m_localActorID, bucketName); + m_bucketSyncInfoList.Add(bucketName, syncInfo); + } + if (!m_bucketUpdateLocks.ContainsKey(bucketName)) + { + m_bucketUpdateLocks.Add(bucketName, new Object()); + } + if (!m_bucketSyncTainted.ContainsKey(bucketName)) + { + m_bucketSyncTainted.Add(bucketName, false); + } + } + + if (!m_BucketUpdateProcessorRegistered) + { + RegisterBucketUpdateProcessor(); + m_BucketUpdateProcessorRegistered = true; + } + + m_syncEnabled = true; + } + + //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) + { + string bucketName = m_primPropertyBucketMap[property]; + m_bucketSyncTainted[bucketName] = true; + } + } + + public bool HasPropertyUpdatedLocally() + { + bool updatedLocally = false; + foreach (KeyValuePair pair in m_bucketSyncTainted) + { + updatedLocally = pair.Value; + if (updatedLocally) + break; + } + return updatedLocally; + } + + /* + 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. + /// + public void UpdateTaintedBucketSyncInfo() + { + if (m_syncEnabled) + { + long timeStamp = DateTime.Now.Ticks; + foreach (KeyValuePair pair in m_bucketSyncInfoList) + { + string bucketName = pair.Key; + if (m_bucketSyncTainted[bucketName]) + { + m_bucketSyncInfoList[bucketName].UpdateSyncInfo(timeStamp, m_localActorID); + m_bucketSyncTainted[bucketName] = false; + } + } + } + } + + /// + /// Update the timestamp information of each property bucket, and clear out the taint on each bucket. + /// + public void UpdateTaintedBucketSyncInfo(long timeStamp) + { + if (m_syncEnabled) + { + foreach (KeyValuePair pair in m_bucketSyncInfoList) + { + string bucketName = pair.Key; + if (m_bucketSyncTainted[bucketName]) + { + m_bucketSyncInfoList[bucketName].UpdateSyncInfo(timeStamp, m_localActorID); + m_bucketSyncTainted[bucketName] = false; + } + } + } + } + + /// + /// Update the timestamp and actorID information of the bucket the given property belongs to. + /// + /// Name of the property. Make sure the spelling is consistent with what are defined in PropertyList + public void UpdateBucketSyncInfo(SceneObjectPartProperties property) + { + if (m_syncEnabled && m_bucketSyncInfoList != null && m_bucketSyncInfoList.Count > 0) + { + //int bucketIndex = m_primPropertyBucketMap[propertyName]; + string bucketName = m_primPropertyBucketMap[property]; + long timeStamp = DateTime.Now.Ticks; + if (m_bucketSyncInfoList.ContainsKey(bucketName)) + { + m_bucketSyncInfoList[bucketName].UpdateSyncInfo(timeStamp, m_localActorID); + } + else + { + m_log.Warn("No SyncInfo of bucket (name: " + bucketName + ") found"); + } + } + } + + public void UpdateAllBucketSyncInfo(long timeStamp) + { + if (m_syncEnabled) + { + foreach (KeyValuePair pair in m_bucketSyncInfoList) + { + string bucketName = pair.Key; + BucketSyncInfo syncInfo= pair.Value; + syncInfo.UpdateSyncInfo(timeStamp, m_localActorID); + m_bucketSyncTainted[bucketName] = false; + } + } + } - - - private Object propertyUpdateLock = new Object(); - //!!!!!! -- TODO: - //!!!!!! -- We should call UpdateXXX functions to update each property, cause some of such updates involves sanity checking. - public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart) { - //////////////////////////////////////////////////////////////////////////////////////////////////// - //NOTE!!!: So far this function is written with Script Engine updating local Scene cache in mind. - //////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////Assumptions: //////////////////// //(1) prim's UUID and LocalID shall not change (UUID is the unique identifies, LocalID is used to refer to the prim by, say scripts) @@ -5299,134 +5600,64 @@ namespace OpenSim.Region.Framework.Scenes //(3) ParentID won't be updated -- if the rootpart of the SceneObjectGroup changed, that will be updated in SceneObjectGroup.UpdateObjectProperties ////////////////////Furture enhancements://////////////////// - //For now, we only update the set of properties that are included in serialization. - //See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart. - //Later on, we may implement update functions that allow updating certain properties or certain buckets of properties. + //For now, we only update the set of properties that are included in serialization, and some PhysicsActor properties + //See RegionSyncModule.PupolatePropertyBuketMapByDefault for the properties that are handled. if (updatedPart == null) return Scene.ObjectUpdateResult.Error; - if (m_lastUpdateTimeStamp > updatedPart.LastUpdateTimeStamp) - { - //Our timestamp is more update to date, keep our values of the properties. Do not update anything. - return Scene.ObjectUpdateResult.Unchanged; - } + //Compate the timestamp of each bucket and update the properties if needed - if (m_lastUpdateTimeStamp == updatedPart.LastUpdateTimeStamp) + Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged; + + for (int i = 0; i < m_propertyBucketNames.Count; i++) { - //if (m_parentGroup.Scene.GetActorID() != updatedPart.LastUpdatedByActorID) - if (m_lastUpdateActorID != updatedPart.LastUpdateActorID) + string bucketName = m_propertyBucketNames[i]; + //First, compare the bucket's timestamp and actorID + if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp > updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp) { - m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp, CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!"); - return Scene.ObjectUpdateResult.Unchanged; + //Our timestamp is more update to date, keep our values of the properties. Do not update anything. + continue; } - //My own update was relayed back. Don't relay it. - return Scene.ObjectUpdateResult.Unchanged; + if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp == updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp) + { + 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!!!!"); + } + continue; + } + + //Second, if need to update local properties, call each bucket's update process + if (m_bucketUpdateProcessors.ContainsKey(bucketName)) + { + m_bucketUpdateProcessors[bucketName](updatedPart, bucketName); + partUpdateResult = Scene.ObjectUpdateResult.Updated; + } + else + { + m_log.Warn("No update processor for property bucket " + bucketName); + } + + } - //Otherwise, our timestamp is less up to date, update the prim with the received copy - - Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Updated; - bool collisionSoundUpdated = false; - lock (propertyUpdateLock) - { - - //See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart. - this.AllowedDrop = updatedPart.AllowedDrop; - this.CreatorID = updatedPart.CreatorID; - this.CreatorData = updatedPart.CreatorData; - this.FolderID = updatedPart.FolderID; - this.InventorySerial = updatedPart.InventorySerial; - this.TaskInventory = updatedPart.TaskInventory; - //Following two properties, UUID and LocalId, shall not be updated. - //this.UUID - //this.LocalId - this.Name = updatedPart.Name; - this.Material = updatedPart.Material; - this.PassTouches = updatedPart.PassTouches; - //RegionHandle shall not be copied, since updatedSog is sent by a different actor, which has a different local region - //this.RegionHandle - this.ScriptAccessPin = updatedPart.ScriptAccessPin; - this.GroupPosition = updatedPart.GroupPosition; - this.OffsetPosition = updatedPart.OffsetPosition; - this.RotationOffset = updatedPart.RotationOffset; - this.Velocity = updatedPart.Velocity; - this.AngularVelocity = updatedPart.AngularVelocity; - this.Acceleration = updatedPart.Acceleration; - this.Description = updatedPart.Description; - this.Color = updatedPart.Color; - this.Text = updatedPart.Text; - this.SitName = updatedPart.SitName; - this.TouchName = updatedPart.TouchName; - this.LinkNum = updatedPart.LinkNum; - this.ClickAction = updatedPart.ClickAction; - this.Shape = updatedPart.Shape; - this.Scale = updatedPart.Scale; - this.UpdateFlag = updatedPart.UpdateFlag; - this.SitTargetOrientation = updatedPart.SitTargetOrientation; - this.SitTargetPosition = updatedPart.SitTargetPosition; - this.SitTargetPositionLL = updatedPart.SitTargetPositionLL; - this.SitTargetOrientationLL = updatedPart.SitTargetOrientationLL; - //ParentID should still point to the rootpart in the local sog, do not update. If the root part changed, we will update it in SceneObjectGroup.UpdateObjectProperties() - //this.ParentID; - this.CreationDate = updatedPart.CreationDate; - this.Category = updatedPart.Category; - this.SalePrice = updatedPart.SalePrice; - this.ObjectSaleType = updatedPart.ObjectSaleType; - this.OwnershipCost = updatedPart.OwnershipCost; - this.GroupID = updatedPart.GroupID; - this.OwnerID = updatedPart.OwnerID; - this.LastOwnerID = updatedPart.LastOwnerID; - this.BaseMask = updatedPart.BaseMask; - this.OwnerMask = updatedPart.OwnerMask; - this.GroupMask = updatedPart.GroupMask; - this.EveryoneMask = updatedPart.EveryoneMask; - this.NextOwnerMask = updatedPart.NextOwnerMask; - this.Flags = updatedPart.Flags; - - //We will update CollisionSound with special care so that it does not lead to ScheduleFullUpdate of this part, to make the actor think it just made an update and - //need to propogate that update to other actors. - //this.CollisionSound = updatedPart.CollisionSound; - collisionSoundUpdated = UpdateCollisionSound(updatedPart.CollisionSound); - - this.CollisionSoundVolume = updatedPart.CollisionSoundVolume; - this.MediaUrl = updatedPart.MediaUrl; - this.TextureAnimation = updatedPart.TextureAnimation; - this.ParticleSystem = updatedPart.ParticleSystem; - - //Update the timestamp and LastUpdatedByActorID first. - this.m_lastUpdateActorID = updatedPart.LastUpdateActorID; - this.m_lastUpdateTimeStamp = updatedPart.LastUpdateTimeStamp; - } - - if (collisionSoundUpdated) - { - m_parentGroup.Scene.EventManager.TriggerAggregateScriptEvents(this); - } - - //m_log.Debug("SceneObjectPart Name-" +Name+", UUID-"+UUID+" localID-" + m_localId + " updated"); - return partUpdateResult; - } - - - private bool UpdateCollisionSound(UUID updatedCollisionSound) - { - if (this.CollisionSound != updatedCollisionSound) - { - m_collisionSound = updatedCollisionSound; - return true; - } - return false; } - public string DebugObjectPartProperties() + public override void ScheduleFullUpdate(SceneObjectPartProperties property) { - string debugMsg = "UUID " + UUID + ", Name " + Name + ", localID " + LocalId + ", lastUpdateActorID " + LastUpdateActorID + ", lastUpdateTimeStamp " + LastUpdateTimeStamp; - debugMsg += ", parentID " + ParentID + ", parentUUID " + ParentUUID; - return debugMsg; + base.ScheduleFullUpdate(property); + TaintBucketSyncInfo(property); + } + + public override void ScheduleTerseUpdate(SceneObjectPartProperties property) + { + base.ScheduleTerseUpdate(property); + TaintBucketSyncInfo(property); } /// @@ -5464,198 +5695,16 @@ namespace OpenSim.Region.Framework.Scenes } - //The following variables should be initialized when this SceneObjectPart is added into the local Scene. - //private List SynchronizeUpdatesToScene = null; - //public List BucketSyncInfoList - private Dictionary m_bucketSyncInfoList = new Dictionary(); - public Dictionary BucketSyncInfoList + private bool UpdateCollisionSound(UUID updatedCollisionSound) { - get { return m_bucketSyncInfoList; } - set { m_bucketSyncInfoList = value; } - } - //TODO: serialization and deserialization processors to be added in SceneObjectSerializer - - //The following variables are initialized when RegionSyncModule reads the config file for mapping of properties and buckets - private static Dictionary m_primPropertyBucketMap = null; - private static List m_propertyBucketNames = null; - //private static List m_bucketUpdateLocks = null; - private static Dictionary m_bucketUpdateLocks = new Dictionary(); - - private static string m_localActorID = ""; - //private static int m_bucketCount = 0; - //private delegate void BucketUpdateProcessor(int bucketIndex); - private delegate void BucketUpdateProcessor(string bucketName); - - private static Dictionary m_bucketUpdateProcessors = new Dictionary(); - - public static void InitializeBucketInfo(Dictionary propertyBucketMap, List bucketNames, string actorID) - { - m_primPropertyBucketMap = propertyBucketMap; - m_propertyBucketNames = bucketNames; - m_localActorID = actorID; - //m_bucketCount = bucketNames.Count; - - RegisterBucketUpdateProcessor(); - } - - /// - /// Link each bucket with the function that applies updates to properties in the bucket. This is the "hard-coded" part - /// in the property-buckets implementation. When new buckets are implemented, the processing functions need to be modified accordingly. - /// - private static void RegisterBucketUpdateProcessor() - { - foreach (string bucketName in m_propertyBucketNames) + if (this.CollisionSound != updatedCollisionSound) { - switch (bucketName) - { - case "General": - m_bucketUpdateProcessors.Add(bucketName, GeneralBucketUpdateProcessor); - break; - case "Physics": - m_bucketUpdateProcessors.Add(bucketName, PhysicsBucketUpdateProcessor); - break; - default: - m_log.Warn("Bucket " + bucketName + "'s update processing function not defined yet"); - break; - } + m_collisionSound = updatedCollisionSound; + return true; } + return false; } - - private static void GeneralBucketUpdateProcessor(string bucketName) - { - lock (m_bucketUpdateLocks[bucketName]) - { - - } - } - - private static void PhysicsBucketUpdateProcessor(string bucketName) - { - lock (m_bucketUpdateLocks[bucketName]) - { - - } - } - - //Initialize and set the values of timestamp and actorID for each synchronization bucket. - //Should be called when the SceneObjectGroup this part is in is added to scene, see SceneObjectGroup.AttachToScene. - public void InitializeBucketSyncInfo() - { - if (m_primPropertyBucketMap == null) - { - m_log.Error("Bucket Information has not been initilized. Return."); - return; - } - long timeStamp = DateTime.Now.Ticks; - - m_log.Debug("InitializeBucketSyncInfo called at " + timeStamp); - - for (int i = 0; i < m_propertyBucketNames.Count; i++) - { - string bucketName = m_propertyBucketNames[i]; - BucketSyncInfo syncInfo = new BucketSyncInfo(timeStamp, m_localActorID, bucketName); - - //If the object is created by de-serialization, then it already has m_bucketSyncInfoList populated with the right number of buckets - if (m_bucketSyncInfoList.ContainsKey(bucketName)) - { - m_bucketSyncInfoList[bucketName] = syncInfo; - } - else - { - m_bucketSyncInfoList.Add(bucketName, syncInfo); - } - if (!m_bucketSyncInfoList.ContainsKey(bucketName)) - { - m_bucketUpdateLocks.Add(bucketName, new Object()); - } - } - } - - /// - /// Update the timestamp and actorID information of the bucket the given property belongs to. - /// - /// Name of the property. Make sure the spelling is consistent with what are defined in PropertyList - private void UpdateBucketSyncInfo(string propertyName) - { - if (m_bucketSyncInfoList != null && m_bucketSyncInfoList.Count>0) - { - //int bucketIndex = m_primPropertyBucketMap[propertyName]; - string bucketName = m_primPropertyBucketMap[propertyName]; - long timeStamp = DateTime.Now.Ticks; - if (m_bucketSyncInfoList.ContainsKey(bucketName)) - { - m_bucketSyncInfoList[bucketName].UpdateSyncInfo(timeStamp, m_localActorID); - } - else - { - m_log.Warn("No SyncInfo of bucket (name: " + bucketName + ") found"); - } - } - } - - - - /* - - public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart) - { - - ////////////////////Assumptions: //////////////////// - //(1) prim's UUID and LocalID shall not change (UUID is the unique identifies, LocalID is used to refer to the prim by, say scripts) - //(2) RegionHandle won't be updated -- each copy of Scene is hosted on a region with different region handle - //(3) ParentID won't be updated -- if the rootpart of the SceneObjectGroup changed, that will be updated in SceneObjectGroup.UpdateObjectProperties - - ////////////////////Furture enhancements://////////////////// - //For now, we only update the set of properties that are included in serialization, and some PhysicsActor properties - //See RegionSyncModule.PupolatePropertyBuketMapByDefault for the properties that are handled. - - if (updatedPart == null) - return Scene.ObjectUpdateResult.Error; - - //Compate the timestamp of each bucket and update the properties if needed - - Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged; - - for (int i=0; i updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp) - { - //Our timestamp is more update to date, keep our values of the properties. Do not update anything. - continue; - } - - if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp == updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp) - { - 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!!!!"); - } - continue; - } - - //Second, if need to update local properties, call each bucket's update process - if (m_bucketUpdateProcessors.ContainsKey(bucketName)) - { - m_bucketUpdateProcessors[bucketName](bucketName); - partUpdateResult = Scene.ObjectUpdateResult.Updated; - } - else - { - m_log.Warn("No update processor for property bucket " + bucketName); - } - - - } - - return partUpdateResult; - - } - */ - //private void UpdateBucketProperties(string bucketDescription, - - #endregion - } + + //end of SYMMETRIC SYNC } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 67de34e1b0..f8509dd017 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -41,7 +41,8 @@ using OpenSim.Region.Framework.Scenes.Serialization; namespace OpenSim.Region.Framework.Scenes { - public class SceneObjectPartInventory : IEntityInventory + //public class SceneObjectPartInventory : IEntityInventory + public class SceneObjectPartInventoryBase : IEntityInventory { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -52,7 +53,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// The part to which the inventory belongs. /// - private SceneObjectPart m_part; + //private SceneObjectPart m_part; + private SceneObjectPartBase m_part; /// /// Serial count for inventory file , used to tell if inventory has changed @@ -98,7 +100,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// A /// - public SceneObjectPartInventory(SceneObjectPart part) + //public SceneObjectPartInventory(SceneObjectPart part) + public SceneObjectPartInventoryBase(SceneObjectPartBase part) { m_part = part; } @@ -291,7 +294,7 @@ namespace OpenSim.Region.Framework.Scenes m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); m_part.ParentGroup.AddActiveScriptCount(1); - m_part.ScheduleFullUpdate(); + m_part.ScheduleFullUpdate(SceneObjectPartProperties.Flags | SceneObjectPartProperties.TaskInventory); return; } @@ -319,7 +322,7 @@ namespace OpenSim.Region.Framework.Scenes m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); m_part.ParentGroup.AddActiveScriptCount(1); - m_part.ScheduleFullUpdate(); + m_part.ScheduleFullUpdate(SceneObjectPartProperties.Flags | SceneObjectPartProperties.TaskInventory); } } } @@ -543,7 +546,7 @@ namespace OpenSim.Region.Framework.Scenes m_part.ParentGroup.HasGroupChanged = true; //SYMMETRIC SYNC: add ScheduleFullUpdate to enable synchronization across actors - m_part.ScheduleFullUpdate(); + m_part.ScheduleFullUpdate(SceneObjectPartProperties.TaskInventory | SceneObjectPartProperties.InventorySerial); } /// @@ -763,7 +766,7 @@ namespace OpenSim.Region.Framework.Scenes if (!ContainsScripts()) m_part.RemFlag(PrimFlags.Scripted); - m_part.ScheduleFullUpdate(); + m_part.ScheduleFullUpdate(SceneObjectPartProperties.TaskInventory); return type; @@ -1172,4 +1175,25 @@ namespace OpenSim.Region.Framework.Scenes } #endregion REGION SYNC } + + #region SYMMETRIC SYNC + public class SceneObjectPartInventory : SceneObjectPartInventoryBase + { + private SceneObjectPart m_part; + public SceneObjectPartInventory(SceneObjectPart part):base((SceneObjectPartBase) part) + { + m_part = part; + } + + new protected internal uint Serial + { + get { return base.Serial; } + set + { + base.Serial = value; + //m_part.UpdateBucketSyncInfo("InventorySerial"); + } + } + } + #endregion } diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index b44a0100a4..d3b4f94bfa 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs @@ -57,11 +57,12 @@ namespace OpenSim.Region.Framework.Scenes /// Add the part to the queue of parts for which we need to send an update to the client /// /// - public void QueuePartForUpdate(SceneObjectPart part) + //public void QueuePartForUpdate(SceneObjectPart part) + public void QueuePartForUpdate(SceneObjectPartBase part) { lock (m_partsUpdateQueue) { - m_partsUpdateQueue.Enqueue(part); + m_partsUpdateQueue.Enqueue((SceneObjectPart)part); } } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index b2f891078c..9659845567 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -330,8 +330,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); //SYMMETRIC SYNC - m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp); - m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID); + m_SOPXmlProcessors.Add("LocalFlags", ProcessLocalFlags); + //m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp); + //m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID); m_SOPXmlProcessors.Add("BucketSyncInfoList", ProcessBucketSyncInfo); //end of SYMMETRIC SYNC @@ -422,8 +423,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization //That is, calling SetXXX(value) instead of using "XXX = value". private static void ProcessAllowedDrop(SceneObjectPart obj, XmlTextReader reader) { - //obj.AllowedDrop = Util.ReadBoolean(reader); - obj.SetAllowedDrop(Util.ReadBoolean(reader)); + obj.AllowedDrop = Util.ReadBoolean(reader); + //obj.SetAllowedDrop(Util.ReadBoolean(reader)); } private static void ProcessCreatorID(SceneObjectPart obj, XmlTextReader reader) @@ -488,32 +489,32 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessGroupPosition(SceneObjectPart obj, XmlTextReader reader) { - //obj.GroupPosition = Util.ReadVector(reader, "GroupPosition"); - obj.SetGroupPosition(Util.ReadVector(reader, "GroupPosition")); + obj.GroupPosition = Util.ReadVector(reader, "GroupPosition"); + //obj.SetGroupPosition(Util.ReadVector(reader, "GroupPosition")); } private static void ProcessOffsetPosition(SceneObjectPart obj, XmlTextReader reader) { - //obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ; - obj.SetOffsetPosition(Util.ReadVector(reader, "OffsetPosition")); + obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ; + //obj.SetOffsetPosition(Util.ReadVector(reader, "OffsetPosition")); } private static void ProcessRotationOffset(SceneObjectPart obj, XmlTextReader reader) { - //obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset"); - obj.SetRotationOffset(Util.ReadQuaternion(reader, "RotationOffset")); + obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset"); + //obj.SetRotationOffset(Util.ReadQuaternion(reader, "RotationOffset")); } private static void ProcessVelocity(SceneObjectPart obj, XmlTextReader reader) { - //obj.Velocity = Util.ReadVector(reader, "Velocity"); - obj.SetVelocity(Util.ReadVector(reader, "Velocity")); + obj.Velocity = Util.ReadVector(reader, "Velocity"); + //obj.SetVelocity(Util.ReadVector(reader, "Velocity")); } private static void ProcessAngularVelocity(SceneObjectPart obj, XmlTextReader reader) { - //obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity"); - obj.SetVelocity(Util.ReadVector(reader, "AngularVelocity")); + obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity"); + //obj.SetVelocity(Util.ReadVector(reader, "AngularVelocity")); } private static void ProcessAcceleration(SceneObjectPart obj, XmlTextReader reader) @@ -572,8 +573,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization private static void ProcessScale(SceneObjectPart obj, XmlTextReader reader) { - //obj.Scale = Util.ReadVector(reader, "Scale"); - obj.SetScale(Util.ReadVector(reader, "Scale")); + obj.Scale = Util.ReadVector(reader, "Scale"); + //obj.SetScale(Util.ReadVector(reader, "Scale")); } private static void ProcessUpdateFlag(SceneObjectPart obj, XmlTextReader reader) @@ -703,6 +704,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } //SYMMETRIC SYNC + /* private static void ProcessUpdateTimeStamp(SceneObjectPart obj, XmlTextReader reader) { obj.LastUpdateTimeStamp = reader.ReadElementContentAsLong("LastUpdateTimeStamp", string.Empty); @@ -712,6 +714,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization { obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty); } + * */ + + private static void ProcessLocalFlags(SceneObjectPart obj, XmlTextReader reader) + { + obj.LocalFlags = Util.ReadEnum(reader, "LocalFlags"); + } public static void ProcessBucketSyncInfo(SceneObjectPart obj, XmlTextReader reader) { @@ -1234,8 +1242,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("EveryoneMask", sop.EveryoneMask.ToString()); writer.WriteElementString("NextOwnerMask", sop.NextOwnerMask.ToString()); //SYMMETRIC SYNC: also serialize SceneObjectPart:LocalFlags, so that it can be propogated across actors - //WriteFlags(writer, "Flags", sop.Flags.ToString(), options); - WriteFlags(writer, "Flags", sop.GetEffectiveObjectFlags().ToString(), options); + WriteFlags(writer, "Flags", sop.Flags.ToString(), options); + WriteFlags(writer, "LocalFlags", sop.LocalFlags.ToString(), options); + //writer.WriteElementString("Flags", sop.Flags.ToString()); + //writer.WriteElementString("LocalFlags", sop.Flags.ToString()); //end SYMMETRIC SYNC WriteUUID(writer, "CollisionSound", sop.CollisionSound, options); writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); @@ -1245,8 +1255,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); //SYMMETRIC SYNC - writer.WriteElementString("LastUpdateTimeStamp", sop.LastUpdateTimeStamp.ToString()); - writer.WriteElementString("LastUpdateActorID", sop.LastUpdateActorID); + //writer.WriteElementString("LastUpdateTimeStamp", sop.LastUpdateTimeStamp.ToString()); + //writer.WriteElementString("LastUpdateActorID", sop.LastUpdateActorID); WriteBucketSyncInfo(writer, sop.BucketSyncInfoList); //end of SYMMETRIC SYNC diff --git a/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs b/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs index 213e954c1f..ad26e8159f 100644 --- a/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs +++ b/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs @@ -62,7 +62,7 @@ namespace OpenSim.Region.Framework.Scenes.Types } } - public void Enqueue(SceneObjectPart part) + public void Enqueue(SceneObjectPart part) { lock (m_syncObject) { diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index 55e407ec5f..f325699d7c 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs @@ -91,7 +91,8 @@ namespace OpenSim.Region.Framework.Scenes part.RotationOffset = Rotation; if (Scale != Vector3.Zero) part.Resize(Scale); - part.ParentGroup.ScheduleGroupForTerseUpdate(); + //part.ParentGroup.ScheduleGroupForTerseUpdate(); + part.ParentGroup.ScheduleGroupForTerseUpdate(SceneObjectPartProperties.Scale); } else { @@ -99,7 +100,8 @@ namespace OpenSim.Region.Framework.Scenes part.OffsetPosition = Position; part.UpdateRotation(Rotation); if (Scale != Vector3.Zero) - part.Resize(Scale); part.ScheduleTerseUpdate(); + part.Resize(Scale); //part.ScheduleTerseUpdate(); + part.ScheduleTerseUpdate(SceneObjectPartProperties.Scale); } part.Undoing = false; @@ -119,7 +121,8 @@ namespace OpenSim.Region.Framework.Scenes part.UpdateRotation(Rotation); if (Scale != Vector3.Zero) part.Resize(Scale); - part.ParentGroup.ScheduleGroupForTerseUpdate(); + //part.ParentGroup.ScheduleGroupForTerseUpdate(); + part.ParentGroup.ScheduleGroupForTerseUpdate(SceneObjectPartProperties.Scale); } else { @@ -129,7 +132,9 @@ namespace OpenSim.Region.Framework.Scenes part.UpdateRotation(Rotation); if (Scale != Vector3.Zero) part.Resize(Scale); - part.ScheduleTerseUpdate(); + //part.ScheduleTerseUpdate(); + part.ScheduleTerseUpdate(SceneObjectPartProperties.Scale); + } part.Undoing = false; diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs index 3a6996ef9b..f3847c2bd7 100644 --- a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs +++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs @@ -290,7 +290,8 @@ namespace OpenSim.Region.OptionalModules.ContentManagement ((SceneObjectGroup)ent).ApplyPhysics(true); ((SceneObjectGroup)ent).AttachToBackup(); ((SceneObjectGroup)ent).HasGroupChanged = true; // If not true, then attaching to backup does nothing because no change is detected. - ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(); + //((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(); + ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(SceneObjectPartProperties.FullUpdate); //don't know what properties to taint, so just taint all } catch(Exception e) { diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs index 421da3664a..5baf903d6e 100644 --- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs +++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs @@ -640,7 +640,8 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator { s_tree.Scale += copse.m_rate; s_tree.ParentGroup.HasGroupChanged = true; - s_tree.ScheduleFullUpdate(); + //s_tree.ScheduleFullUpdate(); + s_tree.ScheduleFullUpdate(SceneObjectPartProperties.Scale); } } else diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index f713cfa5f4..664813b20d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1411,7 +1411,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); m_host.ClickAction = (byte)action; if (m_host.ParentGroup != null) m_host.ParentGroup.HasGroupChanged = true; - m_host.ScheduleFullUpdate(); + //m_host.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.ClickAction); return; } @@ -1679,7 +1680,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } part.ParentGroup.HasGroupChanged = true; - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.Shape); } /// @@ -1714,7 +1716,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } part.ParentGroup.HasGroupChanged = true; - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + part.ScheduleFullUpdate(SceneObjectPartProperties.Shape); } public LSL_Vector llGetColor(int face) @@ -1982,40 +1985,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api targetPos.z = ground; SceneObjectGroup parent = part.ParentGroup; LSL_Vector real_vec = SetPosAdjust(currentPos, targetPos); - //KittyL: edited below - if ((World.ScriptEngineToSceneConnectorModule == null)) - { - parent.UpdateGroupPosition(new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z)); - } - else - { - object[] valParams = new object[1]; - Vector3 pos = new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z); - valParams[0] = (Vector3)pos; - World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(m_host.ParentGroup.LocX, m_host.ParentGroup.LocY, m_host.UUID, "pos", (object)valParams); - } + parent.UpdateGroupPosition(new Vector3((float)real_vec.x, (float)real_vec.y, (float)real_vec.z)); } else { LSL_Vector rel_vec = SetPosAdjust(currentPos, targetPos); - - //KittyL: edited below - if ((World.ScriptEngineToSceneConnectorModule == null)) - { - part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z); - SceneObjectGroup parent = part.ParentGroup; - parent.HasGroupChanged = true; - parent.ScheduleGroupForTerseUpdate(); - } - else - { - object[] valParams = new object[3]; - valParams[0] = (object)rel_vec.x; - valParams[1] = (object)rel_vec.y; - valParams[2] = (object)rel_vec.z; - World.ScriptEngineToSceneConnectorModule.SendSetPrimProperties(m_host.ParentGroup.LocX, m_host.ParentGroup.LocY, m_host.UUID, "pos", (object)valParams); - } - + part.OffsetPosition = new Vector3((float)rel_vec.x, (float)rel_vec.y, (float)rel_vec.z); + SceneObjectGroup parent = part.ParentGroup; + parent.HasGroupChanged = true; + //parent.ScheduleGroupForTerseUpdate(); + parent.ScheduleGroupForTerseUpdate(SceneObjectPartProperties.OffsetPosition); } } @@ -2361,7 +2340,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundFlags = 1; // looping m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable? - m_host.ScheduleFullUpdate(); + //m_host.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.Sound); m_host.SendFullUpdateToAllClients(); } @@ -2381,7 +2361,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api prim.SoundFlags = 1; // looping prim.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable? - prim.ScheduleFullUpdate(); + //prim.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.Sound); prim.SendFullUpdateToAllClients(); } } @@ -2393,7 +2374,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundFlags = 1; // looping m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable? - m_host.ScheduleFullUpdate(); + //m_host.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.Sound); m_host.SendFullUpdateToAllClients(); } @@ -2435,7 +2417,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.SoundGain = 0; part.SoundFlags = 0; part.SoundRadius = 0; - part.ScheduleFullUpdate(); + //part.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.Sound); part.SendFullUpdateToAllClients(); } m_host.ParentGroup.LoopSoundMasterPrim = null; @@ -2447,7 +2430,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundGain = 0; m_host.SoundFlags = 0; m_host.SoundRadius = 0; - m_host.ScheduleFullUpdate(); + //m_host.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.Sound); m_host.SendFullUpdateToAllClients(); } } @@ -2457,7 +2441,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundGain = 0; m_host.SoundFlags = 0; m_host.SoundRadius = 0; - m_host.ScheduleFullUpdate(); + //m_host.ScheduleFullUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.Sound); m_host.SendFullUpdateToAllClients(); } } @@ -3384,7 +3369,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.AngularVelocity = new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate)); - m_host.ScheduleTerseUpdate(); + //m_host.ScheduleTerseUpdate(); + m_host.ScheduleFullUpdate(SceneObjectPartProperties.AngularVelocity); m_host.SendTerseUpdateToAllClients(); m_host.ParentGroup.HasGroupChanged = true; } @@ -3664,7 +3650,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parentPrim.TriggerScriptChangedEvent(Changed.LINK); parentPrim.RootPart.CreateSelected = true; parentPrim.HasGroupChanged = true; - parentPrim.ScheduleGroupForFullUpdate(); + //parentPrim.ScheduleGroupForFullUpdate(); + //SYMMETRIC SYNC + //Schedule a LinkObject message for synchronization purpose. This will lead to enqueue a LinkObject message in SyncConnector's outgoingQueue, + //so should return quickly. + if (World.RegionSyncModule != null) + { + //Tell other actors to link the SceneObjectParts together as a new group. + //parentGroup.SyncInfoUpdate(); + World.RegionSyncModule.SendLinkObject(parentPrim, parentPrim.RootPart, new List(childPrim.Parts)); + } + m_host.ScheduleFullUpdate(SceneObjectPartProperties.None); //SendLinkObject above will synchronize the link operation, no need to taint updates here + //end of SYMMETRIC SYNC if (client != null) parentPrim.GetProperties(client); @@ -3722,15 +3719,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (linknum == ScriptBaseClass.LINK_ROOT) { + //SYMMETRIC SYNC + List beforeDelinkGroups = new List(); + beforeDelinkGroups.Add(parentPrim); + List afterDelinkGroups = new List(); + //end of SYMMETRIC SYNC + // Restructuring Multiple Prims. List parts = new List(parentPrim.Parts); parts.Remove(parentPrim.RootPart); foreach (SceneObjectPart part in parts) { parentPrim.DelinkFromGroup(part.LocalId, true); + //SYMMETRIC SYNC + afterDelinkGroups.Add(part.ParentGroup); } parentPrim.HasGroupChanged = true; - parentPrim.ScheduleGroupForFullUpdate(); + //parentPrim.ScheduleGroupForFullUpdate(); + //SYMMETRIC SYNC + //Send out DelinkObject message to other actors to sychronize their object list + if (World.RegionSyncModule != null) + { + World.RegionSyncModule.SendDeLinkObject(parts, beforeDelinkGroups, afterDelinkGroups); + } + parentPrim.ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); + //end of SYMMETRIC SYNC parentPrim.TriggerScriptChangedEvent(Changed.LINK); if (parts.Count > 0) @@ -3743,7 +3756,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api newRoot.ParentGroup.LinkToGroup(part.ParentGroup); } newRoot.ParentGroup.HasGroupChanged = true; - newRoot.ParentGroup.ScheduleGroupForFullUpdate(); + //newRoot.ParentGroup.ScheduleGroupForFullUpdate(); + //SYMMETRIC SYNC + if (World.RegionSyncModule != null) + { + World.RegionSyncModule.SendLinkObject(newRoot.ParentGroup, newRoot, new List(newRoot.ParentGroup.Parts)); + } + newRoot.ParentGroup.ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); + //end of SYMMETRIC SYNC + } } else @@ -3753,7 +3774,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parentPrim.DelinkFromGroup(childPrim.LocalId, true); parentPrim.HasGroupChanged = true; - parentPrim.ScheduleGroupForFullUpdate(); + //parentPrim.ScheduleGroupForFullUpdate(); + //SYMMETRIC SYNC + //Send out DelinkObject message to other actors to sychronize their object list + if (World.RegionSyncModule != null) + { + List beforeDelinkGroups = new List(); + beforeDelinkGroups.Add(parentPrim); + List afterDelinkGroups = new List(); + afterDelinkGroups.Add(childPrim.ParentGroup); + World.RegionSyncModule.SendDeLinkObject(new List(parentPrim.Parts), beforeDelinkGroups, afterDelinkGroups); + } + //end of SYMMETRIC SYNC + parentPrim.TriggerScriptChangedEvent(Changed.LINK); } } @@ -3765,6 +3798,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (parentPrim.RootPart.AttachmentPoint != 0) return; // Fail silently if attached + //SYMMETRIC SYNC + List beforeDelinkGroups = new List(); + beforeDelinkGroups.Add(parentPrim); + List afterDelinkGroups = new List(); + SceneObjectPart rootPart = parentPrim.RootPart; + //end of SYMMETRIC SYNC + List parts = new List(parentPrim.Parts); parts.Remove(parentPrim.RootPart); @@ -3772,9 +3812,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { parentPrim.DelinkFromGroup(part.LocalId, true); parentPrim.TriggerScriptChangedEvent(Changed.LINK); + //SYMMETRIC SYNC + afterDelinkGroups.Add(part.ParentGroup); } parentPrim.HasGroupChanged = true; - parentPrim.ScheduleGroupForFullUpdate(); + //parentPrim.ScheduleGroupForFullUpdate(); + //SYMMETRIC SYNCF + if (World.RegionSyncModule != null) + { + parts.Add(rootPart); + afterDelinkGroups.Add(rootPart.ParentGroup); + World.RegionSyncModule.SendDeLinkObject(parts, beforeDelinkGroups, afterDelinkGroups); + } + parentPrim.ScheduleGroupForFullUpdate(SceneObjectPartProperties.None); + //end of SYMMETRIC SYNC } public LSL_String llGetLinkKey(int linknum) @@ -4012,7 +4063,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api Util.Clip((float)color.z, 0.0f, 1.0f)); m_host.SetText(text, av3, Util.Clip((float)alpha, 0.0f, 1.0f)); m_host.ParentGroup.HasGroupChanged = true; - m_host.ParentGroup.ScheduleGroupForFullUpdate(); + //m_host.ParentGroup.ScheduleGroupForFullUpdate(); + m_host.ParentGroup.ScheduleGroupForFullUpdate(SceneObjectPartProperties.Text); } public LSL_Float llWater(LSL_Vector offset) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index c0c790dd28..6bf95bf1e5 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2349,7 +2349,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api obj.ParentGroup.HasGroupChanged = true; - obj.ScheduleFullUpdate(); + //obj.ScheduleFullUpdate(); + obj.ScheduleFullUpdate(SceneObjectPartProperties.Shape); }