diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 70619e0643..db0f888a0a 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -386,7 +386,7 @@ namespace OpenSim.Framework public string RemotingAddress; public UUID ScopeID = UUID.Zero; - //SYMMETRIC SYNC + //DSG SYNC //IP:port for the symmetric sync listener this actor is configured to connect to private string m_syncServerAddr = String.Empty; private int m_syncServerPort; @@ -398,7 +398,7 @@ namespace OpenSim.Framework private int m_physicsSyncServerPort; private uint m_quarkLocX; private uint m_quarkLocY; - //end of SYMMETRIC SYNC + //end of DSG SYNC // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. @@ -694,7 +694,7 @@ namespace OpenSim.Framework get { return Util.UIntsToLong((RegionLocX * (uint) Constants.RegionSize), (RegionLocY * (uint) Constants.RegionSize)); } } - //SYMMETRIC SYNC + //DSG SYNC public string SyncServerAddress { get { return m_syncServerAddr; } @@ -731,7 +731,7 @@ namespace OpenSim.Framework get { return m_quarkLocY; } set { m_quarkLocY = value; } } - //end of SYMMETRIC SYNC + //end of DSG SYNC public void SetEndPoint(string ipaddr, int port) { @@ -886,7 +886,7 @@ namespace OpenSim.Framework // ScopeID = new UUID(config.GetString("ScopeID", UUID.Zero.ToString())); - // SYMMETRIC SYNC + // DSG SYNC m_syncServerAddr = config.GetString("SyncServerAddress", String.Empty); m_syncServerPort = config.GetInt("SyncServerPort", -1); //if either IP or port is not configured, we set IP to empty to raise warning later @@ -911,7 +911,7 @@ namespace OpenSim.Framework m_quarkLocY = Convert.ToUInt32(quarkLocElements[1]); - // end of SYMMETRIC SYNC + // end of DSG SYNC } diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index d784267353..14d8543714 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -411,11 +411,11 @@ namespace OpenSim scene.StartTimer(); - //SYMMETRIC SYNC + //DSG SYNC //For INonSharedRegionModule, there is no more PostInitialise(). So we trigger OnPostSceneCreation event here //to let the Sync modules to do their work once all modules are loaded and scene has interfaces to all of them. scene.EventManager.TriggerOnPostSceneCreation(scene); - //end of SYMMETRIC SYNC + //end of DSG SYNC return clientServer; } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 3e00c3ee8b..5e2b473ae0 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -612,7 +612,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments so.IsSelected = false; // fudge.... //so.ScheduleGroupForFullUpdate(); - so.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.FullUpdate}); //just force it to sychronize all properties + so.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.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 ac5df368ca..fcac692969 100644 --- a/OpenSim/Region/CoreModules/Avatar/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/ObjectCaps/UploadObjectAssetModule.cs @@ -355,7 +355,7 @@ namespace OpenSim.Region.CoreModules.Avatar.ObjectCaps } //rootGroup.ScheduleGroupForFullUpdate(); - rootGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.FullUpdate}); //seems like new object + rootGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.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 048f6f7086..5803cc4828 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1603,7 +1603,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { grp.OffsetForNewRegion(oldGroupPosition); //grp.ScheduleGroupForFullUpdate(); - grp.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.Position}); + grp.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.Position}); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 5ab9ec2cfd..898c55eba4 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -609,8 +609,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { -// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); - + // m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); + byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); Vector3 pos = m_Scene.GetNewRezLocation( @@ -696,15 +696,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess itemId, n.OuterXml); objlist.Add(g); XmlElement el = (XmlElement)n; - + string rawX = el.GetAttribute("offsetx"); string rawY = el.GetAttribute("offsety"); string rawZ = el.GetAttribute("offsetz"); -// -// m_log.DebugFormat( -// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", -// g.Name, rawX, rawY, rawZ); - + // + // m_log.DebugFormat( + // "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", + // g.Name, rawX, rawY, rawZ); + float x = Convert.ToSingle(rawX); float y = Convert.ToSingle(rawY); float z = Convert.ToSingle(rawZ); @@ -730,7 +730,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return null; } - for (int i = 0 ; i < objlist.Count ; i++ ) + for (int i = 0; i < objlist.Count; i++) { group = objlist[i]; @@ -770,8 +770,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // can reflect that, if not, we set it's position in world. if (!attachment) { - group.ScheduleGroupForFullUpdate(null); - + group.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.FullUpdate}); + group.AbsolutePosition = pos + veclist[i]; } else @@ -828,7 +828,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } part.GroupMask = 0; // DO NOT propagate here } - + group.ApplyNextOwnerPermissions(); } } @@ -853,12 +853,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { if (group.RootPart.Shape.PCode == (byte)PCode.Prim) group.ClearPartAttachmentData(); - + // Fire on_rez group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); rootPart.ParentGroup.ResumeScripts(); - - rootPart.ScheduleFullUpdate(null); + rootPart.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.FullUpdate }); } } @@ -884,6 +883,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return null; } + protected void AddUserData(SceneObjectGroup sog) { UserManagementModule.AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData); diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs index 6d3192dbb8..4b649b3082 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClient.cs @@ -318,7 +318,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule RegionSyncMessage.HandleSuccess(LogHeader(), msg, String.Format("Syncing to region \"{0}\"", m_regionName)); return; } - //SYMMETRIC SYNC: do not handle terrian and object updates + //DSG SYNC: do not handle terrian and object updates case RegionSyncMessage.MsgType.Terrain: { if(!m_symSync) @@ -378,7 +378,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } return; } - //end of SYMMETRIC SYNC + //end of DSG SYNC case RegionSyncMessage.MsgType.NewAvatar: { // Get the data from message and error check @@ -854,13 +854,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule Send(new RegionSyncMessage(RegionSyncMessage.MsgType.RegionName, m_scene.RegionInfo.RegionName)); m_log.WarnFormat("Sending region name: \"{0}\"", m_scene.RegionInfo.RegionName); - //SYMMETRIC SYNC: commenting out terrian and object updates + //DSG SYNC: commenting out terrian and object updates if (!m_symSync) { Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetTerrain)); Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetObjects)); } - //end of SYMMETRIC SYNC + //end of DSG SYNC Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetAvatars)); // Register for events which will be forwarded to authoritative scene @@ -910,11 +910,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Register for interesting client events which will be forwarded to auth sim // These are the raw packet data blocks from the client, intercepted and sent up to the sim client.OnAgentUpdateRaw += HandleAgentUpdateRaw; - //SYMMETRIC SYNC: do not subscribe to OnChatFromClientRaw: RegionSyncModule + Scene.EventManager will handle this. + //DSG SYNC: do not subscribe to OnChatFromClientRaw: RegionSyncModule + Scene.EventManager will handle this. //client.OnChatFromClientRaw += HandleChatFromClientRaw; client.OnAgentRequestSit += HandleAgentRequestSit; client.OnAgentSit += HandleAgentSit; - //SYMMETRIC SYNC: do not subscribe to OnGrabObject, OnGrabUpdate, and OnDeGrabObject: RegionSyncModule + Scene.EventManager will handle this. + //DSG SYNC: do not subscribe to OnGrabObject, OnGrabUpdate, and OnDeGrabObject: RegionSyncModule + Scene.EventManager will handle this. //client.OnGrabObject += HandleGrabObject; //client.OnGrabUpdate += HandleGrabUpdate; //client.OnDeGrabObject += HandleDeGrabObject; diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClientView.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClientView.cs index 05b6848a0b..b605723144 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClientView.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncClientView.cs @@ -202,10 +202,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // *** This is the main receive loop thread for each connected client private void ReceiveLoop() { - //SYMMETRIC SYNC: commenting out the code for handling chats + //DSG SYNC: commenting out the code for handling chats // m_scene.EventManager.OnChatFromClient += new EventManager.ChatFromClientEvent(EventManager_OnChatFromClient); // m_scene.EventManager.OnChatFromWorld += new EventManager.ChatFromWorldEvent(EventManager_OnChatFromClient); - //end of SYMMETRIC SYNC + //end of DSG SYNC // Reset stats and time @@ -327,7 +327,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule RegionSyncMessage.HandleSuccess(LogHeader, msg, String.Format("Syncing to region \"{0}\"", m_regionName)); return; } - //SYMMETRIC SYNC: do not handle terrian and object updates + //DSG SYNC: do not handle terrian and object updates case RegionSyncMessage.MsgType.GetTerrain: { /* @@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule * */ return; } - //end of SYMMETRIC SYNC + //end of DSG SYNC case RegionSyncMessage.MsgType.GetAvatars: { m_scene.ForEachScenePresence(delegate(ScenePresence presence) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs index 4e53703a21..0652dc9291 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs @@ -151,7 +151,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //m_scene.EventManager.OnNewPresence += new EventManager.OnNewPresenceDelegate(EventManager_OnNewPresence); m_scene.EventManager.OnRemovePresence += new EventManager.OnRemovePresenceDelegate(EventManager_OnRemovePresence); - //SYMMETRIC SYNC: do not handle object updates + //DSG SYNC: do not handle object updates /* if (!m_symsync) { @@ -162,7 +162,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_scene.EventManager.OnOarFileLoaded += new EventManager.OarFileLoaded(EventManager_OnOarFileLoaded); } * */ - //end of SYMMETRIC SYNC + //end of DSG SYNC // Start the server and listen for RegionSyncClients m_serveraddr = m_scene.RegionInfo.AvatarSyncServerAddress; m_serverport = m_scene.RegionInfo.AvatarSyncServerPort; @@ -300,7 +300,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Sending the message when it's first queued would yield lower latency but much higher load on the simulator // as parts may be updated many many times very quickly. Need to implement a higher resolution send in heartbeat - //SYMMETRIC SYNC: do not handle object updates + //DSG SYNC: do not handle object updates /* if (!m_symsync) { @@ -317,7 +317,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } * */ - //end of SYMMETRIC SYNC + //end of DSG SYNC foreach (ScenePresence presence in presenceUpdates) { try diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs index b961362720..7880ae4df5 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SceneToScriptEngineConnector.cs @@ -574,7 +574,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule primToUpdate.OffsetPosition = pos; parent.HasGroupChanged = true; //parent.ScheduleGroupForTerseUpdate(); - parent.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.OffsetPosition}); + parent.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.OffsetPosition}); } } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 10a510d96a..a504bc6e91 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -100,6 +100,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule SyncStatisticCollector.LogInterval = m_sysConfig.GetInt("SyncLogInterval", 5000); SyncStatisticCollector.LogMaxFileTimeMin = m_sysConfig.GetInt("SyncLogMaxFileTimeMin", 5); SyncStatisticCollector.LogFileHeader = m_sysConfig.GetString("SyncLogFileHeader", "sync-"); + + //initialize PrimSyncInfoManager + PrimSyncInfoManager.DebugLog = m_log; + PrimSyncInfo.DebugLog = m_log; + PropertySyncInfo.DebugLog = m_log; + int syncInfoAgeOutSeconds = m_sysConfig.GetInt("PrimSyncInfoAgeOutSeconds", 300); //unit of seconds + TimeSpan tSpan = new TimeSpan(0, 0, syncInfoAgeOutSeconds); + m_primSyncInfoManager = new PrimSyncInfoManager(this, tSpan.Ticks); } //Called after Initialise() @@ -125,32 +133,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //m_scene.EventManager.OnObjectBeingRemovedFromScene += new EventManager.ObjectBeingRemovedFromScene(RegionSyncModule_OnObjectBeingRemovedFromScene); LogHeader += "-LocalRegion " + scene.RegionInfo.RegionName; + + m_syncID = GetSyncID(); } //Called after AddRegion() has been called for all region modules of the scene public void RegionLoaded(Scene scene) { - //m_log.Warn(LogHeader + " RegionLoaded() called"); - - /* - //If this one is configured to start a listener so that other actors can connect to form a overlay, start the listener. - //For now, we use the star topology, and ScenePersistence actor is always the one to start the listener. - if (m_isSyncListenerLocal) - { - StartLocalSyncListener(); - } - else - { - //Start connecting to the remote listener. TO BE IMPLEMENTED. - //For now, the connection will be started by manually typing in "sync start". - - } - * */ - - //Start symmetric synchronization initialization automatically - //SyncStart(null); - - // connect to statistics system SyncStatisticCollector.Register(this); } @@ -182,24 +171,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Synchronization related members and functions, exposed through IRegionSyncModule interface /////////////////////////////////////////////////////////////////////////////////////////////////// - private DSGActorTypes m_actorType = DSGActorTypes.Unknown; - /// - /// The type of the actor running locally. This value will be set by an ActorSyncModule, so that - /// no hard code needed in RegionSyncModule to recoganize the actor's type, thus make it easier - /// to add new ActorSyncModules w/o chaning the code in RegionSyncModule. - /// - public DSGActorTypes DSGActorType - { - get { return m_actorType; } - set { m_actorType = value; } - } - + //ActorID might not be in use anymore. Rather, SyncID should be used. + //(Synchronization is sync node centric, not actor centric.) private string m_actorID; public string ActorID { get { return m_actorID; } } + private string m_syncID; + public string SyncID + { + get { return m_syncID; } + } + private bool m_active = false; public bool Active { @@ -212,8 +197,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; } } @@ -228,12 +213,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule foreach (string bucketName in m_propertyBucketNames) { - //if (m_isSyncRelay || part.HasPropertyUpdatedLocallyInGivenBucket(bucketName)) if(!part.ParentGroup.IsDeleted && HaveUpdatesToSendoutForSync(part, bucketName)) { lock (m_primUpdateLocks[bucketName]) { - //m_log.Debug("Queueing to bucket " + bucketName + " with part " + part.Name + ", " + part.UUID+" at pos "+part.GroupPosition.ToString()); m_primUpdates[bucketName][part.UUID] = part; } } @@ -250,8 +233,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } - + //SendSceneUpdates put each update into an outgoing queue of each SyncConnector + /// + /// Send updates to other sync nodes. So far we only handle object updates. + /// public void SendSceneUpdates() { if (!IsSyncingWithOtherSyncNodes()) @@ -271,7 +257,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } - //List primUpdates=null; Dictionary> primUpdates = new Dictionary>(); bool updated = false; @@ -304,18 +289,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } - List presenceUpdates = new List(); - /* - if (m_presenceUpdates.Count > 0) - { - lock (m_updateScenePresenceLock) - { - updated = true; - presenceUpdates = new List(m_presenceUpdates.Values); - m_presenceUpdates.Clear(); - } - } - */ if (updated) { @@ -337,48 +310,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule primUpdates[bucketName].Clear(); } } - foreach (ScenePresence presence in presenceUpdates) - { - try - { - if (!presence.IsDeleted) - { - /* - OSDMap data = new OSDMap(10); - data["id"] = OSD.FromUUID(presence.UUID); - // Do not include offset for appearance height. That will be handled by RegionSyncClient before sending to viewers - if(presence.AbsolutePosition.IsFinite()) - data["pos"] = OSD.FromVector3(presence.AbsolutePosition); - else - data["pos"] = OSD.FromVector3(Vector3.Zero); - if(presence.Velocity.IsFinite()) - data["vel"] = OSD.FromVector3(presence.Velocity); - else - data["vel"] = OSD.FromVector3(Vector3.Zero); - data["rot"] = OSD.FromQuaternion(presence.Rotation); - data["fly"] = OSD.FromBoolean(presence.Flying); - data["flags"] = OSD.FromUInteger((uint)presence.AgentControlFlags); - data["anim"] = OSD.FromString(presence.Animator.CurrentMovementAnimation); - // needed for a full update - if (presence.ParentID != presence.lastSentParentID) - { - data["coll"] = OSD.FromVector4(presence.CollisionPlane); - data["off"] = OSD.FromVector3(presence.OffsetPosition); - data["pID"] = OSD.FromUInteger(presence.ParentID); - presence.lastSentParentID = presence.ParentID; - } - - RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.UpdatedAvatar, OSDParser.SerializeJsonString(data)); - m_server.EnqueuePresenceUpdate(presence.UUID, rsm.ToBytes()); - */ - - } - } - catch (Exception e) - { - m_log.ErrorFormat("[REGION SYNC MODULE] Caught exception sending presence updates for {0}: {1}", presence.Name, e); - } - } // Indicate that the current batch of updates has been completed Interlocked.Exchange(ref m_sendingUpdates, 0); @@ -408,6 +339,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + //Legacy SendNewObject and SendDeleteObject for Bucket based sync protocol + /// /// Send a sync message to add the given object to other sync nodes. /// @@ -461,7 +394,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule SendSpecialObjectUpdateToRelevantSyncConnectors(m_actorID, sog, rsm); //SendSceneEventToRelevantSyncConnectors(m_actorID, rsm, sog); } - + public void SendLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children) { @@ -583,21 +516,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule OnLocalScriptReset((uint)evArgs[0], (UUID)evArgs[1]); return; case EventManager.EventNames.ChatFromClient: - /*if (evArgs.Length < 2) - { - m_log.Error(LogHeader + " not enough event args for ChatFromClient"); - return; - } - OnLocalChatFromClient(evArgs[0], (OSChatMessage)evArgs[1]); - return;*/ - case EventManager.EventNames.ChatFromWorld: - /*if (evArgs.Length < 2) - { - m_log.Error(LogHeader + " not enough event args for ChatFromWorld"); - return; - } - OnLocalChatFromWorld(evArgs[0], (OSChatMessage)evArgs[1]); - return;*/ + case EventManager.EventNames.ChatFromWorld: case EventManager.EventNames.ChatBroadcast: if (evArgs.Length < 2) { @@ -627,6 +546,163 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + ///////////////////////////////////////////////////////////// + //New IRegionSyncModule functions for per property sync'ing + ///////////////////////////////////////////////////////////// + + /// + /// Called when new object is created in local SceneGraph. (Add new object + /// by receiving sync message should not trigger calling this function.) + /// + /// + public void SyncNewObject(SceneObjectGroup sog) + { + //First, add PrimSyncInfoManager's record. + foreach (SceneObjectPart part in sog.Parts) + { + m_primSyncInfoManager.InsertPrimSyncInfo(part, DateTime.Now.Ticks, m_syncID); + } + + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. No need to send out sync messages. + return; + } + + OSDMap encodedSOG = SceneObjectEncoder(sog); + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.NewObject, OSDParser.SerializeJsonString(encodedSOG)); + + m_log.DebugFormat("{0}: Send NewObject out for {1},{2}", LogHeader, sog.Name, sog.UUID); + + SendSpecialObjectUpdateToRelevantSyncConnectors(m_actorID, sog, syncMsg); + } + + public void SyncDeleteObject(SceneObjectGroup sog, bool softDelete) + { + //First, remove from PrimSyncInfoManager's record. + foreach (SceneObjectPart part in sog.Parts) + { + m_primSyncInfoManager.RemovePrimSyncInfo(part); + } + + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. Do nothing. + return; + } + + OSDMap data = new OSDMap(); + data["UUID"] = OSD.FromUUID(sog.UUID); + //TODO: need to put in SyncID instead of ActorID here. + //For now, keep it the same for simple debugging + data["actorID"] = OSD.FromString(m_actorID); + data["softDelete"] = OSD.FromBoolean(softDelete); + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); + SendSpecialObjectUpdateToRelevantSyncConnectors(m_actorID, sog, rsm); + } + + public void SyncLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children) + { + if (children.Count == 0) return; + + //the group is just linked, each part has quite some properties changed + //(OffsetPosition, etc). Need to sync the property values in PrimSyncInfoManager + //first + foreach (SceneObjectPart part in linkedGroup.Parts) + { + m_primSyncInfoManager.UpdatePrimSyncInfoByLocal(part, new List { SceneObjectPartSyncProperties.FullUpdate }); + } + + + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. Do nothing. + return; + } + + //Now encode the linkedGroup for sync + OSDMap data = new OSDMap(); + OSDMap encodedSOG = SceneObjectEncoder(linkedGroup); + data["linkedGroup"] = encodedSOG; + data["rootID"] = OSD.FromUUID(root.UUID); + data["partCount"] = OSD.FromInteger(children.Count); + data["actorID"] = OSD.FromString(m_actorID); + int partNum = 0; + foreach (SceneObjectPart part in children) + { + string partTempID = "part" + partNum; + data[partTempID] = OSD.FromUUID(part.UUID); + partNum++; + + //m_log.DebugFormat("{0}: SendLinkObject to link {1},{2} with {3}, {4}", part.Name, part.UUID, root.Name, root.UUID); + } + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.LinkObject, OSDParser.SerializeJsonString(data)); + SendSpecialObjectUpdateToRelevantSyncConnectors(m_actorID, linkedGroup, rsm); + //SendSceneEventToRelevantSyncConnectors(m_actorID, rsm, linkedGroup); + } + + public void SyncDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups) + { + if (prims.Count == 0 || beforeDelinkGroups.Count == 0) return; + + //the prims are just delinked, each part has quite some properties changed + //(OffsetPosition, etc). Need to sync the property values in PrimSyncInfoManager + //first + foreach (SceneObjectPart part in prims) + { + m_primSyncInfoManager.UpdatePrimSyncInfoByLocal(part, new List { SceneObjectPartSyncProperties.FullUpdate }); + } + + + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. Do nothing. + return; + } + + OSDMap data = new OSDMap(); + data["partCount"] = OSD.FromInteger(prims.Count); + int partNum = 0; + foreach (SceneObjectPart part in prims) + { + string partTempID = "part" + partNum; + data[partTempID] = OSD.FromUUID(part.UUID); + partNum++; + } + //We also include the IDs of beforeDelinkGroups, for now it is more for sanity checking at the receiving end, so that the receiver + //could make sure its delink starts with the same linking state of the groups/prims. + data["beforeGroupsCount"] = OSD.FromInteger(beforeDelinkGroups.Count); + int groupNum = 0; + foreach (SceneObjectGroup affectedGroup in beforeDelinkGroups) + { + string groupTempID = "beforeGroup" + groupNum; + data[groupTempID] = OSD.FromUUID(affectedGroup.UUID); + groupNum++; + } + + //include the property values of each object after delinking, for synchronizing the values + data["afterGroupsCount"] = OSD.FromInteger(afterDelinkGroups.Count); + groupNum = 0; + foreach (SceneObjectGroup afterGroup in afterDelinkGroups) + { + string groupTempID = "afterGroup" + groupNum; + //string sogxml = SceneObjectSerializer.ToXml2Format(afterGroup); + //data[groupTempID] = OSD.FromString(sogxml); + OSDMap encodedSOG = SceneObjectEncoder(afterGroup); + data[groupTempID] = encodedSOG; + groupNum++; + } + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.DelinkObject, OSDParser.SerializeJsonString(data)); + SendDelinkObjectToRelevantSyncConnectors(m_actorID, beforeDelinkGroups, rsm); + } + + public void Debug(String debugMsg) + { + m_log.DebugFormat("{0}", debugMsg); + } #endregion //IRegionSyncModule @@ -651,12 +727,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule Command cmdSyncStatus = new Command("status", CommandIntentions.COMMAND_HAZARDOUS, SyncStatus, "Displays synchronization status."); - //for debugging purpose + //for test and debugging purpose Command cmdSyncDebug = new Command("debug", CommandIntentions.COMMAND_HAZARDOUS, SyncDebug, "Trigger some debugging functions"); //for sync state comparison, Command cmdSyncStateReport = new Command("state", CommandIntentions.COMMAND_HAZARDOUS, SyncStateReport, "Trigger synchronization state comparision functions"); + m_commander.RegisterCommand("start", cmdSyncStart); m_commander.RegisterCommand("stop", cmdSyncStop); m_commander.RegisterCommand("status", cmdSyncStatus); @@ -697,11 +774,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule #endregion Console Command Interface - #region RegionSyncModule members and functions - - ///////////////////////////////////////////////////////////////////////////////////////// - // Synchronization related functions, NOT exposed through IRegionSyncModule interface - ///////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////// + // Memeber variables + /////////////////////////////////////////////////////////////////////// private static int PortUnknown = -1; private static string IPAddrUnknown = String.Empty; @@ -740,9 +815,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private RegionSyncListener m_localSyncListener = null; private bool m_synced = false; - // Lock is used to synchronize access to the update status and update queues - //private object m_updateSceneObjectPartLock = new object(); - //private Dictionary m_primUpdates = new Dictionary(); + /////////////////////////////////////////////////////////////////////// + // Memeber variables for per-property timestamp + /////////////////////////////////////////////////////////////////////// + + private Object m_primPropertyUpdateLock = new Object(); + private Dictionary> m_primPropertyUpdates = new Dictionary>(); + private int m_sendingPrimPropertyUpdates = 0; + + /////////////////////////////////////////////////////////////////////// + // Legacy members for bucket-based sync, + /////////////////////////////////////////////////////////////////////// + private Dictionary m_primUpdateLocks = new Dictionary(); private Dictionary> m_primUpdates = new Dictionary>(); @@ -771,6 +855,22 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private int m_maxNumOfPropertyBuckets; + ///////////////////////////////////////////////////////////////////////////////////////// + // Synchronization related functions, NOT exposed through IRegionSyncModule interface + ///////////////////////////////////////////////////////////////////////////////////////// + + private string GetSyncID() + { + if (m_scene != null) + { + return m_scene.RegionInfo.RegionID.ToString(); + } + else + { + return String.Empty; + } + } + private void StatsTimerElapsed(object source, System.Timers.ElapsedEventArgs e) { //TO BE IMPLEMENTED @@ -824,10 +924,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //if (connector.IsPositionInSyncQuarks(sog.AbsolutePosition)) //{ - SymmetricSyncMessage syncMsg = NewObjectMessageEncoder(sog); - //SendToSyncConnector(connector, sog, syncMsg); - connector.EnqueueOutgoingUpdate(sog.UUID, syncMsg.ToBytes()); + //SymmetricSyncMessage syncMsg = NewObjectMessageEncoder(sog); + OSDMap encodedSOG = SceneObjectEncoder(sog); + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.NewObject, OSDParser.SerializeJsonString(encodedSOG)); + + //SendToSyncConnector(connector, sog, syncMsg); + connector.EnqueueOutgoingUpdate(sog.UUID, syncMsg.ToBytes()); //} } } @@ -880,6 +983,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return sog; } + /////////////////////////////////////////////////////////////////////// + //Legacy implementation of NewObject encoder/decoder for bucket-based + //sync protocol. + /////////////////////////////////////////////////////////////////////// + /// /// Encode all properties of an object. Assumption: no matter how many /// buckets are designed, there is always a "General" bucket that contains @@ -898,13 +1006,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //convert the coordinates if necessary Vector3 globalPos = sog.AbsolutePosition; - /* - if (CoordinatesConversionHandler != null) - { - bool inComingMsg = false; - globalPos = CoordinatesConversionHandler(globalPos, inComingMsg); - } - * */ data["GroupPosition"] = OSDMap.FromVector3(globalPos); foreach (string bucketName in m_propertyBucketNames) @@ -940,13 +1041,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Convert the coordinates if necessary Vector3 localPos = globalPos; - /* - if (CoordinatesConversionHandler != null) - { - bool inComingMsg = true; - localPos = CoordinatesConversionHandler(globalPos, inComingMsg); - } - * */ + sog.AbsolutePosition = localPos; //TEMP DEBUG @@ -1345,21 +1440,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { return part.HasPropertyUpdatedLocally(bucketName); } - - //return (m_isSyncRelay || part.HasPropertyUpdatedLocallyInGivenBucket(bucketName)); - - /* - if (!m_isSyncRelay) - { - return part.HasPropertyUpdatedLocallyInGivenBucket(bucketName); - } - - //if this is a relay node, forward out the updates that have not been sent out since lastUpdateSentTime - if (m_lastUpdateSentTime[bucketName] <= part.BucketSyncInfoList[bucketName].LastUpdateTimeStamp) - return true; - else - return false; - * */ } //by default, there are two property buckets: the "General" bucket and the "Physics" bucket. @@ -1392,29 +1472,29 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //m_lastUpdateSentTime.Add("Physics", 0); //Mapping properties to buckets. - foreach (SceneObjectPartProperties property in Enum.GetValues(typeof(SceneObjectPartProperties))) + foreach (SceneObjectPartSyncProperties property in Enum.GetValues(typeof(SceneObjectPartSyncProperties))) { switch (property) { - case SceneObjectPartProperties.GroupPosition: - case SceneObjectPartProperties.OffsetPosition: - case SceneObjectPartProperties.Scale: - case SceneObjectPartProperties.AngularVelocity: - case SceneObjectPartProperties.RotationOffset: - case SceneObjectPartProperties.Size: - case SceneObjectPartProperties.Position: - case SceneObjectPartProperties.Force: - case SceneObjectPartProperties.Velocity: - case SceneObjectPartProperties.RotationalVelocity: - case SceneObjectPartProperties.PA_Acceleration: - case SceneObjectPartProperties.Torque: - case SceneObjectPartProperties.Orientation: - case SceneObjectPartProperties.IsPhysical: - case SceneObjectPartProperties.Flying: - case SceneObjectPartProperties.Kinematic: - case SceneObjectPartProperties.Buoyancy: - case SceneObjectPartProperties.IsCollidingGround: - case SceneObjectPartProperties.IsColliding: + case SceneObjectPartSyncProperties.GroupPosition: + case SceneObjectPartSyncProperties.OffsetPosition: + case SceneObjectPartSyncProperties.Scale: + case SceneObjectPartSyncProperties.AngularVelocity: + case SceneObjectPartSyncProperties.RotationOffset: + case SceneObjectPartSyncProperties.Size: + case SceneObjectPartSyncProperties.Position: + case SceneObjectPartSyncProperties.Force: + case SceneObjectPartSyncProperties.Velocity: + case SceneObjectPartSyncProperties.RotationalVelocity: + case SceneObjectPartSyncProperties.PA_Acceleration: + case SceneObjectPartSyncProperties.Torque: + case SceneObjectPartSyncProperties.Orientation: + case SceneObjectPartSyncProperties.IsPhysical: + case SceneObjectPartSyncProperties.Flying: + case SceneObjectPartSyncProperties.Kinematic: + case SceneObjectPartSyncProperties.Buoyancy: + case SceneObjectPartSyncProperties.CollidingGround: + case SceneObjectPartSyncProperties.IsColliding: m_primPropertyBucketMap.Add(property, m_physicsBucketName); break; default: @@ -1556,7 +1636,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule foreach (SceneObjectPart part in sog.Parts) { /* - if (part.LastUpdateActorID.Equals(m_actorID)) + if (!part.LastUpdateActorID.Equals(m_actorID)) { return true; } @@ -1690,7 +1770,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Error(LogHeader + "interface Scene.ActorSyncModule has not been set yet"); return; } - m_actorType = m_scene.ActorSyncModule.ActorType; + //m_actorType = m_scene.ActorSyncModule.ActorType; } //Start symmetric synchronization initialization automatically @@ -1800,12 +1880,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Start SyncListener if a listener is supposed to run on this actor; Otherwise, initiate connections to remote listeners. private void SyncStart(Object[] args) { - if (m_actorType == DSGActorTypes.Unknown) - { - m_log.Error(LogHeader + ": SyncStart -- ActorType not set yet. Either it's not defined in config file (DSGActorType), or the ActorSyncModule (ScenePersistenceSyncModule, ScriptEngineSyncModule etc) has not defined it."); - return; - } - if (m_isSyncListenerLocal) { if (m_localSyncListener!=null && m_localSyncListener.IsListening) @@ -1896,6 +1970,17 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule foreach (SceneObjectGroup sog in sogList) { m_log.WarnFormat("SyncStateReport -- SOG: name {0}, UUID {1}, position {2}", sog.Name, sog.UUID, sog.AbsolutePosition); + foreach (SceneObjectPart part in sog.Parts) + { + Vector3 pos = Vector3.Zero; + if (part.PhysActor != null) + { + pos = part.PhysActor.Position; + } + m_log.WarnFormat(" -- part {0}, UUID {1}, LocalID {2}, GroupPos {3}, offset-position {4}, Position {5}, AggregateScriptEvents ={6}, Flags = {7}, LocalFlags {8}", + part.Name, part.UUID, part.LocalId, part.GroupPosition, part.OffsetPosition, + pos, part.AggregateScriptEvents, part.Flags, part.LocalFlags); + } } if (m_isSyncRelay) @@ -1918,6 +2003,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { if (entity is SceneObjectGroup) { + //Legacy serialization/deserialization for bucket based sync + /* //first test serialization StringWriter sw = new StringWriter(); XmlTextWriter writer = new XmlTextWriter(sw); @@ -1935,6 +2022,48 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule XmlTextReader reader = new XmlTextReader(new StringReader(xmlString)); SceneObjectPart part = new SceneObjectPart(); SceneObjectSerializer.ProcessBucketSyncInfo(part, reader); + * */ + + SceneObjectGroup sog = (SceneObjectGroup)entity; + + //First, create PrimSyncInfo for each part in SOG and insert + //into the local record + foreach (SceneObjectPart part in sog.Parts) + { + m_primSyncInfoManager.InsertPrimSyncInfo(part, DateTime.Now.Ticks, m_syncID); + } + + //Next test serialization + OSDMap sogData = SceneObjectEncoder(sog); + + //Next, test de-serialization + SceneObjectGroup group; + Dictionary primsSyncInfo; + SceneObjectDecoder(sogData, out group, out primsSyncInfo); + + //Add the list of PrimSyncInfo to PrimSyncInfoManager's record. + m_primSyncInfoManager.InsertMultiPrimSyncInfo(primsSyncInfo); + + //Change each part's UUID so that we can add them to Scene and test the steps in AddNewSceneObjectByDecoding + foreach (SceneObjectPart part in group.Parts) + { + UUID oldUUID = part.UUID; + part.UUID = UUID.Random(); + + PrimSyncInfo syncInfo = primsSyncInfo[oldUUID]; + primsSyncInfo.Add(part.UUID, syncInfo); + } + + //Add the decoded object to Scene + Scene.ObjectUpdateResult updateResult = m_scene.AddNewSceneObjectBySync(group); + + //Now the PhysActor of each part in sog have been created, let's + //set the PhysActor's properties + foreach (SceneObjectPart part in group.Parts) + { + primsSyncInfo[part.UUID].SetSOPPhyscActorProperties(part); + } + break; } } @@ -2108,6 +2237,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + #region Sync message handlers /// @@ -2130,35 +2260,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } case SymmetricSyncMessage.MsgType.Terrain: { - /* - m_scene.Heightmap.LoadFromXmlString(Encoding.ASCII.GetString(msg.Data, 0, msg.Length)); - //Inform the terrain module that terrain has been updated - m_scene.RequestModuleInterface().TaintTerrain(); - m_log.Debug(LogHeader+": Synchronized terrain"); - * */ HandleTerrainUpdateMessage(msg, senderActorID); return; } case SymmetricSyncMessage.MsgType.GetObjects: { - /* - EntityBase[] entities = m_scene.GetEntities(); - foreach (EntityBase e in entities) - { - if (e is SceneObjectGroup) - { - //string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)e); - //SendSyncMessage(SymmetricSyncMessage.MsgType.NewObject, sogxml); - SceneObjectGroup sog = (SceneObjectGroup)e; - HandleGetObjectRequest(syncConnector, sog); - } - } - * */ HandleGetObjectRequest(syncConnector); return; } case SymmetricSyncMessage.MsgType.NewObject: - HandleAddNewObject(msg, senderActorID); + //HandleAddNewObject(msg, senderActorID); + HandleSyncNewObject(msg, senderActorID); + break; + case SymmetricSyncMessage.MsgType.UpdatedPrimProperties: + HandleUpdatedPrimProperties(msg, senderActorID); break; case SymmetricSyncMessage.MsgType.UpdatedObject: { @@ -2178,12 +2293,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } case SymmetricSyncMessage.MsgType.LinkObject: { - HandleLinkObject(msg, senderActorID); + //HandleLinkObject(msg, senderActorID); + HandleSyncLinkObject(msg, senderActorID); return; } case SymmetricSyncMessage.MsgType.DelinkObject: { - HandleDelinkObject(msg, senderActorID); + //HandleDelinkObject(msg, senderActorID); + HandleSyncDelinkObject(msg, senderActorID); return; } //EVENTS PROCESSING @@ -2239,11 +2356,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } - private void HandleAddNewObject(SymmetricSyncMessage msg, string senderActorID) + /////////////////////////////////////////////////////////////////////// + // Per property sync handlers + /////////////////////////////////////////////////////////////////////// + + private void HandleSyncNewObject(SymmetricSyncMessage msg, string senderActorID) { - //string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); - //SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml); OSDMap data = DeserializeMessage(msg); //if this is a relay node, forward the event @@ -2260,11 +2379,262 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } * */ + + AddNewSceneObjectByDecoding(data); - Object sog; - NewObjectMessageDecoder(data, out sog); - SceneObjectGroup group = (SceneObjectGroup)sog; + } + private void HandleUpdatedPrimProperties(SymmetricSyncMessage msg, string senderActorID) + { + OSDMap data = DeserializeMessage(msg); + UUID primUUID; + HashSet propertiesSyncInfo; + + if (!data.ContainsKey("primUUID")) + { + m_log.WarnFormat("{0}: HandleUpdatedPrimProperties -- primUUID is missing in {1}", LogHeader, msg.Type.ToString()); + return; + } + primUUID = data["primUUID"].AsUUID(); + SceneObjectPart sop = m_scene.GetSceneObjectPart(primUUID); + + if (sop == null || sop.ParentGroup.IsDeleted) + { + m_log.WarnFormat("{0}: HandleUpdatedPrimProperties -- prim {1} no longer in local SceneGraph", LogHeader, primUUID); + return; + } + + propertiesSyncInfo = m_primSyncInfoManager.DecodePrimProperties(data); + + if (propertiesSyncInfo.Count>0) + { + //SYNC DEBUG + /* + string pString = ""; + foreach (PropertySyncInfo p in propertiesSyncInfo) + { + pString += p.Property.ToString() + " "; + if (p.Property == SceneObjectPartSyncProperties.Shape) + { + PrimitiveBaseShape shape = PropertySerializer.DeSerializeShape((String)p.LastUpdateValue); + m_log.DebugFormat("Shape to be changed on SOP {0}, {1} to ProfileShape {2}", sop.Name, sop.UUID, shape.ProfileShape); + } + } + * */ + + + //m_log.DebugFormat("ms {0}: HandleUpdatedPrimProperties, for prim {1},{2} with updated properties -- {3}", DateTime.Now.Millisecond, sop.Name, sop.UUID, pString); + + + List propertiesUpdated = m_primSyncInfoManager.UpdatePrimSyncInfoBySync(sop, propertiesSyncInfo); + + //SYNC DEBUG + if (propertiesUpdated.Contains(SceneObjectPartSyncProperties.AggregateScriptEvents)) + { + //m_log.DebugFormat("AggregateScriptEvents updated: " + sop.AggregateScriptEvents); + } + + /* + if (propertiesUpdated.Contains(SceneObjectPartSyncProperties.Shape)) + { + String hashedShape = Util.Md5Hash((PropertySerializer.SerializeShape(sop))); + m_log.DebugFormat("HandleUpdatedPrimProperties -- SOP {0},{1}, Shape updated, ProfileShape {2}, hashed value in SOP:{3}, in PrinSyncInfoManager: {4}", + sop.Name, sop.UUID, sop.Shape.ProfileShape, hashedShape, m_primSyncInfoManager.GetPrimSyncInfo(sop.UUID).PropertiesSyncInfo[SceneObjectPartSyncProperties.Shape].LastUpdateValueHash); + } + * */ + + if (propertiesUpdated.Count > 0) + { + //Enqueue the updated SOP and its properties for sync + ProcessAndEnqueuePrimUpdatesBySync(sop, propertiesUpdated); + + //Calling SOP.ScheduleFullUpdate(), so that viewers, if any, + //will receive updates as well. + sop.ScheduleFullUpdate(null); + } + } + } + + private void HandleSyncLinkObject(SymmetricSyncMessage msg, string senderActorID) + { + + // Get the data from message and error check + OSDMap data = DeserializeMessage(msg); + if (data == null) + { + SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data."); + return; + } + + OSDMap encodedSOG = (OSDMap)data["linkedGroup"]; + SceneObjectGroup linkedGroup; + Dictionary primsSyncInfo; + SceneObjectDecoder(encodedSOG, out linkedGroup, out primsSyncInfo); + + //TEMP DEBUG + // m_log.DebugFormat(" received linkedGroup: {0}", linkedGroup.DebugObjectUpdateResult()); + //m_log.DebugFormat(linkedGroup.DebugObjectUpdateResult()); + + if (linkedGroup == null) + { + m_log.WarnFormat("{0}: HandleSyncLinkObject, no valid Linked-Group has been deserialized", LogHeader); + return; + } + + UUID rootID = data["rootID"].AsUUID(); + int partCount = data["partCount"].AsInteger(); + List childrenIDs = new List(); + + for (int i = 0; i < partCount; i++) + { + string partTempID = "part" + i; + childrenIDs.Add(data[partTempID].AsUUID()); + } + + //if this is a relay node, forwards the event + if (m_isSyncRelay) + { + //SendSceneEventToRelevantSyncConnectors(senderActorID, msg, linkedGroup); + SendSpecialObjectUpdateToRelevantSyncConnectors(senderActorID, linkedGroup, msg); + } + + //TEMP SYNC DEBUG + //m_log.DebugFormat("{0}: received LinkObject from {1}", LogHeader, senderActorID); + + m_scene.LinkObjectBySync(linkedGroup, rootID, childrenIDs); + + //Update properties, if any has changed + foreach (KeyValuePair incomingPrimSyncInfo in primsSyncInfo) + { + UUID primUUID = incomingPrimSyncInfo.Key; + PrimSyncInfo updatedPrimSyncInfo = incomingPrimSyncInfo.Value; + + SceneObjectPart part = m_scene.GetSceneObjectPart(primUUID); + if (part == null) + { + m_log.WarnFormat("{0}: HandleSyncLinkObject, prim {1} not in local Scene Graph after LinkObjectBySync is called", LogHeader, primUUID); + } + else + { + m_primSyncInfoManager.UpdatePrimSyncInfoBySync(part, updatedPrimSyncInfo); + } + } + } + + private void HandleSyncDelinkObject(SymmetricSyncMessage msg, string senderActorID) + { + OSDMap data = DeserializeMessage(msg); + if (data == null) + { + SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data."); + return; + } + + //List localPrims = new List(); + List delinkPrimIDs = new List(); + List beforeDelinkGroupIDs = new List(); + List incomingAfterDelinkGroups = new List(); + List> incomingPrimSyncInfo = new List>(); + + int partCount = data["partCount"].AsInteger(); + for (int i = 0; i < partCount; i++) + { + string partTempID = "part" + i; + UUID primID = data[partTempID].AsUUID(); + //SceneObjectPart localPart = m_scene.GetSceneObjectPart(primID); + //localPrims.Add(localPart); + delinkPrimIDs.Add(primID); + } + + int beforeGroupCount = data["beforeGroupsCount"].AsInteger(); + for (int i = 0; i < beforeGroupCount; i++) + { + string groupTempID = "beforeGroup" + i; + UUID beforeGroupID = data[groupTempID].AsUUID(); + beforeDelinkGroupIDs.Add(beforeGroupID); + } + + int afterGroupsCount = data["afterGroupsCount"].AsInteger(); + for (int i = 0; i < afterGroupsCount; i++) + { + string groupTempID = "afterGroup" + i; + //string sogxml = data[groupTempID].AsString(); + SceneObjectGroup afterGroup; + OSDMap encodedSOG = (OSDMap)data[groupTempID]; + Dictionary primsSyncInfo; + SceneObjectDecoder(encodedSOG, out afterGroup, out primsSyncInfo); + incomingAfterDelinkGroups.Add(afterGroup); + incomingPrimSyncInfo.Add(primsSyncInfo); + } + + //if this is a relay node, forwards the event + if (m_isSyncRelay) + { + List beforeDelinkGroups = new List(); + foreach (UUID sogID in beforeDelinkGroupIDs) + { + SceneObjectGroup sog = m_scene.SceneGraph.GetGroupByPrim(sogID); + beforeDelinkGroups.Add(sog); + } + SendDelinkObjectToRelevantSyncConnectors(senderActorID, beforeDelinkGroups, msg); + } + + m_scene.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups); + + //Sync properties + //Update properties, for each prim in each deLinked-Object + foreach (Dictionary primsSyncInfo in incomingPrimSyncInfo) + { + foreach (KeyValuePair inPrimSyncInfo in primsSyncInfo) + { + UUID primUUID = inPrimSyncInfo.Key; + PrimSyncInfo updatedPrimSyncInfo = inPrimSyncInfo.Value; + + SceneObjectPart part = m_scene.GetSceneObjectPart(primUUID); + if (part == null) + { + m_log.WarnFormat("{0}: HandleSyncDelinkObject, prim {1} not in local Scene Graph after DelinkObjectsBySync is called", LogHeader, primUUID); + } + else + { + m_primSyncInfoManager.UpdatePrimSyncInfoBySync(part, updatedPrimSyncInfo); + } + } + } + + + } + + + /////////////////////////////////////////////////////////////////////// + // Bucket sync handlers + /////////////////////////////////////////////////////////////////////// + + private void HandleAddNewObject(SymmetricSyncMessage msg, string senderActorID) + { + + OSDMap data = DeserializeMessage(msg); + + //if this is a relay node, forward the event + Vector3 globalPos = data["GroupPosition"].AsVector3(); + if (m_isSyncRelay) + { + SendSpecialObjectUpdateToRelevantSyncConnectors(senderActorID, globalPos, msg); + } + + /* + if (!m_syncQuarkManager.IsPosInSyncQuarks(globalPos)) + { + m_log.WarnFormat("{0}: Received an update for object at global pos {1}, not within local quarks, ignore the update", LogHeader, globalPos.ToString()); + return; + } + * */ + + SceneObjectGroup sog; + Object group; + NewObjectMessageDecoder(data, out group); + sog = (SceneObjectGroup)group; + //Might need to do something with SOG, or no more actions, just return } /// @@ -2472,6 +2842,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule if (!softDelete) { //m_log.DebugFormat("{0}: hard delete object {1}", LogHeader, sog.UUID); + foreach (SceneObjectPart part in sog.Parts) + { + m_primSyncInfoManager.RemovePrimSyncInfo(part); + } m_scene.DeleteSceneObjectBySynchronization(sog); } else @@ -2585,6 +2959,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_scene.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups); } + #endregion //Sync message handlers + + #region Remote Event handlers /// /// The common actions for handling remote events (event initiated at other actors and propogated here) @@ -2732,58 +3109,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_scene.EventManager.TriggerScriptResetLocally(part.LocalId, itemID); } - /* - /// - /// Special actions for remote event ChatFromClient - /// - /// OSDMap data of event args - private void HandleRemoteEvent_OnChatFromClient(string actorID, ulong evSeqNum, OSDMap data) - { - //m_log.Debug(LogHeader + ": received ChatFromClient from "+actorID+", seq "+evSeqNum); - - OSChatMessage args = new OSChatMessage(); - args.Channel = data["channel"].AsInteger(); - args.Message = data["msg"].AsString(); - args.Position = data["pos"].AsVector3(); - args.From = data["name"].AsString(); - UUID id = data["id"].AsUUID(); - args.Scene = m_scene; - //args.Type = ChatTypeEnum.Say; - args.Type = (ChatTypeEnum) data["type"].AsInteger(); - ScenePresence sp; - m_scene.TryGetScenePresence(id, out sp); - - m_scene.EventManager.TriggerOnChatFromClientLocally(sp, args); //Let WorldCommModule and other modules to catch the event - m_scene.EventManager.TriggerOnChatFromWorldLocally(sp, args); //This is to let ChatModule to get the event and deliver it to avatars - } - - private void HandleRemoteEvent_OnChatFromWorld(string actorID, ulong evSeqNum, OSDMap data) - { - //m_log.Debug(LogHeader + ", " + m_actorID + ": received ChatFromWorld from " + actorID + ", seq " + evSeqNum); - - OSChatMessage args = new OSChatMessage(); - args.Channel = data["channel"].AsInteger(); - args.Message = data["msg"].AsString(); - args.Position = data["pos"].AsVector3(); - args.From = data["name"].AsString(); - UUID id = data["id"].AsUUID(); - args.Scene = m_scene; - //args.Type = ChatTypeEnum.Say; - args.Type = (ChatTypeEnum)data["type"].AsInteger(); - //ScenePresence sp; - //m_scene.TryGetScenePresence(id, out sp); - - m_log.Debug(LogHeader + " TriggerOnChatFromWorldLocally "); - - m_scene.EventManager.TriggerOnChatFromWorldLocally(m_scene, args); - } - - private void HandleRemoteEvent_OnChatBroadcast(string actorID, ulong evSeqNum, OSDMap data) - { - - } - * */ - /// /// Handlers for remote chat events: ChatFromClient, ChatFromWorld, ChatBroadcast /// @@ -3045,42 +3370,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule SendSceneEvent(SymmetricSyncMessage.MsgType.ScriptReset, data); } - /* - private void OnLocalChatFromClient(Object sender, OSChatMessage chat) - { - ScenePresence avatar = m_scene.GetScenePresence(chat.SenderUUID); - - if (avatar == null) - { - m_log.Warn(LogHeader + "avatar " + chat.SenderUUID + " not exist locally, NOT sending out ChatFromClient"); - return; - } - - OSDMap data = new OSDMap(); - data["channel"] = OSD.FromInteger(chat.Channel); - data["msg"] = OSD.FromString(chat.Message); - data["pos"] = OSD.FromVector3(chat.Position); - data["name"] = OSD.FromString(avatar.Name); //note this is different from OnLocalChatFromWorld - data["id"] = OSD.FromUUID(chat.SenderUUID); - data["type"] = OSD.FromInteger((int)chat.Type); - SendSceneEvent(SymmetricSyncMessage.MsgType.ChatFromClient, data); - } - - - private void OnLocalChatFromWorld(Object sender, OSChatMessage chat) - { - - OSDMap data = new OSDMap(); - data["channel"] = OSD.FromInteger(chat.Channel); - data["msg"] = OSD.FromString(chat.Message); - data["pos"] = OSD.FromVector3(chat.Position); - data["name"] = OSD.FromString(chat.From); //note this is different from OnLocalChatFromClient - data["id"] = OSD.FromUUID(chat.SenderUUID); - data["type"] = OSD.FromInteger((int)chat.Type); - SendSceneEvent(SymmetricSyncMessage.MsgType.ChatFromWorld, data); - } - * */ - private void OnLocalChatBroadcast(Object sender, OSChatMessage chat) { @@ -3137,49 +3426,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private void OnLocalGrabObject(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) { - /* - //we will use the prim's UUID as the identifier, not the localID, to publish the event for the prim - SceneObjectPart part = m_scene.GetSceneObjectPart(localID); - if (part == null) - { - m_log.Warn(LogHeader + ": part with localID " + localID + " not exist"); - return; - } - - //this seems to be useful if the prim touched and the prim handling the touch event are different: - //i.e. a child part is touched, pass the event to root, and root handles the event. then root is the "part", - //and the child part is the "originalPart" - SceneObjectPart originalPart = null; - if (originalID != 0) - { - originalPart = m_scene.GetSceneObjectPart(originalID); - if (originalPart == null) - { - m_log.Warn(LogHeader + ": part with localID " + localID + " not exist"); - return; - } - } - - OSDMap data = new OSDMap(); - data["agentID"] = OSD.FromUUID(remoteClient.AgentId); - data["primID"] = OSD.FromUUID(part.UUID); - if (originalID != 0) - { - data["originalPrimID"] = OSD.FromUUID(originalPart.UUID); - } - else - { - data["originalPrimID"] = OSD.FromUUID(UUID.Zero); - } - data["offsetPos"] = OSD.FromVector3(offsetPos); - - data["binormal"] = OSD.FromVector3(surfaceArgs.Binormal); - data["faceIndex"] = OSD.FromInteger(surfaceArgs.FaceIndex); - data["normal"] = OSD.FromVector3(surfaceArgs.Normal); - data["position"] = OSD.FromVector3(surfaceArgs.Position); - data["stCoord"] = OSD.FromVector3(surfaceArgs.STCoord); - data["uvCoord"] = OSD.FromVector3(surfaceArgs.UVCoord); - * */ OSDMap data = PrepareObjectGrabArgs(localID, originalID, offsetPos, remoteClient, surfaceArgs); SendSceneEvent(SymmetricSyncMessage.MsgType.ObjectGrab, data); } @@ -3262,8 +3508,423 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { return m_eventSeq++; } + #endregion //Remote Event handlers + + #region Prim Property Sync management + + + private PrimSyncInfoManager m_primSyncInfoManager; + //private + /// + /// Triggered when some properties in an SOP have been updated locally. + /// Sync the properties' values in this sync module with those in + /// SOP, and update timestamp accordingly. + /// + /// + /// + public void ProcessAndEnqueuePrimUpdatesByLocal(SceneObjectPart part, List updatedProperties) + { + if (part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + + //Sync values with SOP's data and update timestamp according, to + //obtain the list of properties that really have been updated + //and should be propogated to other sync nodes. + HashSet propertiesWithSyncInfoUpdated = m_primSyncInfoManager.UpdatePrimSyncInfoByLocal(part, updatedProperties); + + /* //Below is done at SOG level, not here (TO DOUBLE CHECK) + //For group properties, we only need to send it once per SOG, + //hence only enqueue it with root part + foreach (SceneObjectPartSyncProperties groupProperty in SceneObjectPart.GetGroupProperties()) + { + if (propertiesWithSyncInfoUpdated.Contains(groupProperty)) + { + SceneObjectPart rootpart = part.ParentGroup.RootPart; + if (m_primPropertyUpdates.ContainsKey(rootpart.UUID)) + { + m_primPropertyUpdates[rootpart.UUID].Add(groupProperty); + } + else + { + m_primPropertyUpdates.Add(rootpart.UUID, new HashSet() { groupProperty }); + } + } + propertiesWithSyncInfoUpdated.Remove(groupProperty); + } + * */ + + /* + if(updatedProperties.Contains(SceneObjectPartSyncProperties.Shape)) + { + string hashedShape = Util.Md5Hash((PropertySerializer.SerializeShape(part))); + m_log.DebugFormat("ProcessAndEnqueuePrimUpdatesByLocal: Shape of SOP {0}, {1} updated, ProfileShape {2}, hashed value in SOP: {3}, in PrimSyncInfoManager: {4}", + part.Name, part.UUID, part.Shape.ProfileShape, hashedShape, m_primSyncInfoManager.GetPrimSyncInfo(part.UUID).PropertiesSyncInfo[SceneObjectPartSyncProperties.Shape].LastUpdateValueHash); + } + * */ + + + //Enqueue the prim with the set of updated properties, excluding the group properties + if (propertiesWithSyncInfoUpdated.Count > 0) + { + lock (m_primPropertyUpdateLock) + { + if (m_primPropertyUpdates.ContainsKey(part.UUID)) + { + foreach (SceneObjectPartSyncProperties property in propertiesWithSyncInfoUpdated) + { + //Include the "property" into the list of updated properties. + //HashSet's Add function should handle it correctly whether the property + //is or is not in the set. + m_primPropertyUpdates[part.UUID].Add(property); + } + } + else + { + m_primPropertyUpdates.Add(part.UUID, propertiesWithSyncInfoUpdated); + } + } + } + } + + /// + /// Triggered when some properties of the given SOP have been updated by + /// receiving a sync message UpdatedPrimProperties. + /// + /// + /// + public void ProcessAndEnqueuePrimUpdatesBySync(SceneObjectPart part, List updatedProperties) + { + if (part.ParentGroup == null || part.ParentGroup.IsDeleted) + return; + + HashSet propertiesToSync = new HashSet(); + + if (m_isSyncRelay) + { + //If this is a sync relay node, it needs to forward out the updates + propertiesToSync = new HashSet(updatedProperties); + } + + //Enqueue the prim with the set of updated properties + if (propertiesToSync.Count > 0) + { + lock (m_primPropertyUpdateLock) + { + if (m_primPropertyUpdates.ContainsKey(part.UUID)) + { + foreach (SceneObjectPartSyncProperties property in propertiesToSync) + { + //Include the "property" into the list of updated properties. + //HashSet's Add function should handle it correctly whether the property + //is or is not in the set. + m_primPropertyUpdates[part.UUID].Add(property); + } + } + else + { + m_primPropertyUpdates.Add(part.UUID, propertiesToSync); + } + } + } + } + + + /// + /// Triggered periodically to send out sync messages that include + /// prim-properties that have been updated since last SyncOut. + /// + public void SyncOutPrimUpdates() + { + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. clear update queues and return. + m_primPropertyUpdates.Clear(); + return; + } + + //If no prim has been updated since last SyncOut, simply return. + if (m_primPropertyUpdates.Count == 0) + return; + + // Existing value of 1 indicates that updates are currently being sent so skip updates this pass + if (Interlocked.Exchange(ref m_sendingPrimPropertyUpdates, 1) == 1) + { + m_log.DebugFormat("{0} SyncOutPrimUpdates(): An update thread is already running.", LogHeader); + return; + } + + //copy the updated prim property list, and clear m_primPropertyUpdates immediately for future use + Dictionary> primPropertyUpdates = new Dictionary>(); + lock (m_primPropertyUpdateLock) + { + foreach (KeyValuePair> updatedPrimProperties in m_primPropertyUpdates) + { + UUID primUUID = updatedPrimProperties.Key; + SceneObjectPart prim = m_scene.GetSceneObjectPart(primUUID); + //Skip if the prim is on longer in the local Scene Graph + if (prim == null) + { + m_log.WarnFormat("{0}: in SyncOutPrimUpdates, prim {1} no longer in local SceneGraph", LogHeader, primUUID); + continue; + } + //Skip if the object group is being deleted + if (prim.ParentGroup.IsDeleted) + continue; + + primPropertyUpdates.Add(primUUID, updatedPrimProperties.Value); + } + m_primPropertyUpdates.Clear(); + } + + if (primPropertyUpdates.Count > 0) + { + //Starting a new thread to prepare sync message and enqueue it to SyncConnectors + System.Threading.ThreadPool.QueueUserWorkItem(delegate + { + foreach (KeyValuePair> updatedPrimProperties in primPropertyUpdates) + { + UUID primUUID = updatedPrimProperties.Key; + SceneObjectPart sop = m_scene.GetSceneObjectPart(primUUID); + + if (sop == null || sop.ParentGroup.IsDeleted) + continue; + else + { + HashSet updatedProperties = updatedPrimProperties.Value; + + //Sync the SOP data and cached property values in PrimSyncInfoManager again + HashSet propertiesWithSyncInfoUpdated = m_primSyncInfoManager.UpdatePrimSyncInfoByLocal(sop, new List(updatedProperties)); + SendPrimPropertyUpdates(sop, updatedProperties); + } + } + + // Indicate that the current batch of updates has been completed + Interlocked.Exchange(ref m_sendingPrimPropertyUpdates, 0); + }); + } + else + { + Interlocked.Exchange(ref m_sendingPrimPropertyUpdates, 0); + } + } + + private void SendPrimPropertyUpdates(SceneObjectPart sop, HashSet updatedProperties) + { + OSDMap syncData = m_primSyncInfoManager.EncodePrimProperties(sop, updatedProperties); + + if (syncData.Count > 0) + { + //DSG DEBUG + + string pString = ""; + foreach (SceneObjectPartSyncProperties property in updatedProperties) + { + pString += property.ToString() + " "; + } + //m_log.DebugFormat("{0}: SendPrimPropertyUpdates for {1}, {2}, with updated properties -- {3}", LogHeader, sop.Name, sop.UUID, pString); + + //DSG DEBUG + + if (updatedProperties.Contains(SceneObjectPartSyncProperties.AggregateScriptEvents)) + { + // m_log.DebugFormat("SendPrimPropertyUpdates -- AggregateScriptEvents: " + sop.AggregateScriptEvents); + } + + /* + if (updatedProperties.Contains(SceneObjectPartSyncProperties.Shape)) + { + String hashedShape = Util.Md5Hash((PropertySerializer.SerializeShape(sop))); + m_log.DebugFormat("SendPrimPropertyUpdates -- SOP {0},{1}, Shape updated: ProfileShape {2}, hashed value in SOP:{3}, in PrinSyncInfoManager: {4}", + sop.Name, sop.UUID, sop.Shape.ProfileShape, + hashedShape, m_primSyncInfoManager.GetPrimSyncInfo(sop.UUID).PropertiesSyncInfo[SceneObjectPartSyncProperties.Shape].LastUpdateValueHash); + } + */ + + + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedPrimProperties, OSDParser.SerializeJsonString(syncData)); + SendPrimUpdateToRelevantSyncConnectors(sop.UUID, syncMsg); + } + } + + //Object updates are sent by enqueuing into each connector's outQueue. + private void SendPrimUpdateToRelevantSyncConnectors(UUID primUUID, SymmetricSyncMessage syncMsg) + { + SceneObjectPart updatedPart = m_scene.GetSceneObjectPart(primUUID); + if (updatedPart == null) + return; + + HashSet syncConnectors = GetSyncConnectorsForPrimUpdates(updatedPart); + foreach (SyncConnector connector in syncConnectors) + { + connector.EnqueueOutgoingUpdate(updatedPart.UUID, syncMsg.ToBytes()); + } + } + + /// + /// Encode a SOG. Values of each part's properties are copied from + /// PrimSyncInfo, instead of from SOP's data. If a part's PrimSyncInfo + /// is not maintained by PrimSyncInfoManager yet, add it first. + /// + /// + /// + private OSDMap SceneObjectEncoder(SceneObjectGroup sog) + { + OSDMap data = new OSDMap(); + data["UUID"] = OSD.FromUUID(sog.UUID); + + Vector3 globalPos = sog.AbsolutePosition; + /* + if (CoordinatesConversionHandler != null) + { + bool inComingMsg = false; + globalPos = CoordinatesConversionHandler(globalPos, inComingMsg); + } + * */ + data["GroupPosition"] = OSDMap.FromVector3(globalPos); + + HashSet fullPropertyList = new HashSet() { SceneObjectPartSyncProperties.FullUpdate }; + if (!m_primSyncInfoManager.IsPrimSyncInfoExist(sog.RootPart.UUID)) + { + m_log.WarnFormat("{0}: SceneObjectEncoder -- SOP {1},{2} not in PrimSyncInfoManager's record yet", LogHeader, sog.RootPart.Name, sog.RootPart.UUID); + //This should not happen, but we deal with it by inserting a newly created PrimSynInfo + m_primSyncInfoManager.InsertPrimSyncInfo(sog.RootPart, DateTime.Now.Ticks, m_syncID); + } + data["RootPart"] = m_primSyncInfoManager.EncodePrimProperties(sog.RootPart, fullPropertyList); + + + //int otherPartsCount = sog.Parts.Length - 1; + //data["OtherPartsCount"] = OSD.FromInteger(otherPartsCount); + OSDArray otherPartsArray = new OSDArray(); + foreach (SceneObjectPart part in sog.Parts) + { + if (!part.UUID.Equals(sog.RootPart.UUID)) + { + if (!m_primSyncInfoManager.IsPrimSyncInfoExist(part.UUID)) + { + m_log.WarnFormat("{0}: SceneObjectEncoder -- SOP {1},{2} not in PrimSyncInfoManager's record yet", LogHeader, part.Name, part.UUID); + //This should not happen, but we deal with it by inserting a newly created PrimSynInfo + m_primSyncInfoManager.InsertPrimSyncInfo(part, DateTime.Now.Ticks, m_syncID); + } + OSDMap partData = m_primSyncInfoManager.EncodePrimProperties(part, fullPropertyList); + otherPartsArray.Add(partData); + } + } + data["OtherParts"] = otherPartsArray; + + //string sogxml = SceneObjectSerializer.ToXml2Format(sog); + //SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.NewObject, OSDParser.SerializeJsonString(data)); + + return data; + } + + private void AddNewSceneObjectByDecoding(OSDMap data) + { + SceneObjectGroup group; + Dictionary primsSyncInfo; + + SceneObjectDecoder(data, out group, out primsSyncInfo); + + if (group == null) + { + m_log.WarnFormat("{0}: AddNewSceneObjectByDecoding, no valid SceneObjectGroup has been created", LogHeader); + return; + } + + //DSG DEBUG + m_log.DebugFormat("calling AddNewSceneObjectByDecoding for SOG {0}, {1}", group.Name, group.UUID); + + //Add the list of PrimSyncInfo to PrimSyncInfoManager's record. + m_primSyncInfoManager.InsertMultiPrimSyncInfo(primsSyncInfo); + + //Add the decoded object to Scene + Scene.ObjectUpdateResult updateResult = m_scene.AddNewSceneObjectBySync(group); + + //Now the PhysActor of each part in sog have been created, let's + //set the PhysActor's properties + foreach (SceneObjectPart part in group.Parts) + { + //primsSyncInfo[part.UUID].SetSOPPhyscActorProperties(part); + m_primSyncInfoManager.SetSOPPhyscActorProperties(part); + } + } + + /// + /// Decode & create a SOG data structure. Due to the fact that PhysActor + /// is only created when SOG.AttachToScene() is called, the returned SOG + /// here only have non PhysActor properties decoded and values set. The + /// PhysActor properties should be set later by the caller. + /// + /// + /// + /// + private void SceneObjectDecoder(OSDMap data, out SceneObjectGroup sog, out Dictionary partsPrimSyncInfo) + { + sog = new SceneObjectGroup(); + partsPrimSyncInfo = new Dictionary(); + + //if(data.ContainsKey("UUID")){ + // sog.UUID = data["UUID"].AsUUID(); + //} + + if(!data.ContainsKey("RootPart")){ + m_log.WarnFormat("{0}: SceneObjectDecoder, no RootPart found in the OSDMap"); + return; + } + + OSDMap rootData = (OSDMap)data["RootPart"]; + //Decode and copy to the list of PrimSyncInfo + PrimSyncInfo primSyncInfo = m_primSyncInfoManager.DecodeFullSetPrimProperties(rootData); + SceneObjectPart root = primSyncInfo.PrimSyncInfoToSOP(); + + if (root != null) + { + sog.SetRootPart(root); + partsPrimSyncInfo.Add(root.UUID, primSyncInfo); + } + else + return; + + if (sog.UUID == UUID.Zero) + sog.UUID = sog.RootPart.UUID; + + //Decode the remaining parts and add them to the object group + if(data.ContainsKey("OtherParts")){ + //int otherPartsCount = data["OtherPartsCount"].AsInteger(); + OSDArray otherPartsArray = (OSDArray) data["OtherParts"]; + for(int i=0; i + /// The value of the most recent value sent/received by Sync Module. + /// For property with simple types, the value is copied directly. + /// For property with complex data structures, the value (values of + /// subproperties) is serialized and stored. + /// + private Object m_lastUpdateValue; + public Object LastUpdateValue + { + get { return m_lastUpdateValue; } + //set { m_lastUpdateValue = value; } + } + + private string m_lastUpdateValueHash = String.Empty; + public String LastUpdateValueHash + { + get {return m_lastUpdateValueHash;} + } + + /// + /// Record the time the last sync message about this property is received. + /// This value is only meaninful when m_lastUpdateSource==BySync + /// + private long m_lastSyncUpdateRecvTime; + public long LastSyncUpdateRecvTime + { + get { return m_lastSyncUpdateRecvTime; } + set { m_lastSyncUpdateRecvTime = value; } + } + + private PropertyUpdateSource m_lastUpdateSource; + public PropertyUpdateSource LastUpdateSource + { + get { return m_lastUpdateSource; } + } + + private SceneObjectPartSyncProperties m_property; + public SceneObjectPartSyncProperties Property + { + get { return m_property; } + } + + private Object m_syncInfoLock = new Object(); + + public PropertySyncInfo(SceneObjectPartSyncProperties property) + { + m_property = property; + } + + public PropertySyncInfo(SceneObjectPartSyncProperties property, Object initValue, long initTS, string syncID) + { + m_property = property; + m_lastUpdateValue = initValue; + m_lastUpdateTimeStamp = initTS; + m_lastUpdateSyncID = syncID; + //m_lastSyncUpdateRecvTime == ?? + + switch (property) + { + case SceneObjectPartSyncProperties.Shape: + case SceneObjectPartSyncProperties.TaskInventory: + m_lastUpdateValueHash = GetPropertyHashValue((string)initValue); + break; + } + } + + /// + /// Initialize from data in given OSDMap. + /// + /// + /// + public PropertySyncInfo(SceneObjectPartSyncProperties property, OSDMap syncData) + { + m_property = property; + FromOSDMap(syncData); + } + + /// + /// Update SyncInfo when the property is updated locally. This interface + /// is for complex properties that need hashValue for fast comparison, + /// such as Shape and TaskInventory. + /// + /// + /// + /// + /// This is only meaningful for complex properties: + /// Shape & TaskInventory. For other properties, it is ignore. + public void UpdateSyncInfoByLocal(long ts, string syncID, Object pValue, string pHashedValue) + { + lock (m_syncInfoLock) + { + m_lastUpdateValue = pValue; + m_lastUpdateTimeStamp = ts; + m_lastUpdateSyncID = syncID; + m_lastUpdateSource = PropertyUpdateSource.Local; + m_lastUpdateValueHash = pHashedValue; + } + } + + /// + /// Update SyncInfo when the property is updated locally. This interface + /// is for properties of simple types. + /// + /// + /// + /// + public void UpdateSyncInfoByLocal(long ts, string syncID, Object pValue) + { + lock (m_syncInfoLock) + { + m_lastUpdateValue = pValue; + m_lastUpdateTimeStamp = ts; + m_lastUpdateSyncID = syncID; + m_lastUpdateSource = PropertyUpdateSource.Local; + } + } + + /// + /// Compare the local timestamp with that in pSyncInfo. If the one in + /// pSyncInfo is newer, copy its members to the local record. + /// + /// + /// + public bool CompareAndUpdateSyncInfoBySync(PropertySyncInfo pSyncInfo, long recvTS) + { + if (pSyncInfo.LastUpdateTimeStamp > m_lastUpdateTimeStamp) + { + //update + UpdateSyncInfoBySync(pSyncInfo.m_lastUpdateTimeStamp, pSyncInfo.m_lastUpdateSyncID, pSyncInfo.m_lastUpdateValue, recvTS); + return true; + } + else + { + if (pSyncInfo.LastUpdateTimeStamp == m_lastUpdateTimeStamp) + { + if (!m_lastUpdateSyncID.Equals(pSyncInfo.LastUpdateSyncID)) + { + DebugLog.WarnFormat("CompareAndUpdateSyncInfoBySync: property {0} being updated by {1} and {2} at the same time. Do nothing as of current implementation. TO RESOLVE.", + m_property, m_lastUpdateSyncID, pSyncInfo.LastUpdateSyncID); + } + } + return false; + } + + } + + /// + /// Update SyncInfo when the property is updated by receiving a sync + /// message. + /// + /// + /// + public void UpdateSyncInfoBySync(long ts, string syncID, Object pValue, long recvTS) + { + lock (m_syncInfoLock) + { + m_lastUpdateValue = pValue; + m_lastUpdateTimeStamp = ts; + m_lastUpdateSyncID = syncID; + m_lastSyncUpdateRecvTime = recvTS; + m_lastUpdateSource = PropertyUpdateSource.BySync; + + switch (m_property) + { + case SceneObjectPartSyncProperties.Shape: + case SceneObjectPartSyncProperties.TaskInventory: + m_lastUpdateValueHash = GetPropertyHashValue((string)m_lastUpdateValue); + break; + } + } + } + + public bool IsHashValueEqual(string hashValue) + { + return m_lastUpdateValueHash.Equals(hashValue); + } + + public bool IsValueEqual(Object pValue) + { + return m_lastUpdateValue.Equals(pValue); + } + + /// + /// Convert the value of the given property to OSD type. + /// + /// + /// + public OSDMap ToOSDMap() + { + OSDMap propertyData = new OSDMap(); + propertyData["LastUpdateTimeStamp"] = LastUpdateTimeStamp; + propertyData["LastUpdateSyncID"] = LastUpdateSyncID; + + switch (m_property) + { + /////////////////////////////////////// + //SOP properties with complex structure + /////////////////////////////////////// + case SceneObjectPartSyncProperties.Shape: + case SceneObjectPartSyncProperties.TaskInventory: + propertyData["Value"] = OSD.FromString((string)LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, enum types + //////////////////////////// + case SceneObjectPartSyncProperties.AggregateScriptEvents: + propertyData["Value"] = OSD.FromInteger((int)((scriptEvents)LastUpdateValue)); + break; + case SceneObjectPartSyncProperties.Flags: + case SceneObjectPartSyncProperties.LocalFlags: + propertyData["Value"] = OSD.FromInteger((int)((PrimFlags)LastUpdateValue)); + break; + //////////////////////////// + //SOP properties, bool types + //////////////////////////// + case SceneObjectPartSyncProperties.AllowedDrop: + case SceneObjectPartSyncProperties.IsAttachment: + case SceneObjectPartSyncProperties.PassTouches: + propertyData["Value"] = OSD.FromBoolean((bool)LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, Vector3 types + //////////////////////////// + case SceneObjectPartSyncProperties.AngularVelocity: + case SceneObjectPartSyncProperties.AttachedPos: + case SceneObjectPartSyncProperties.GroupPosition: + case SceneObjectPartSyncProperties.OffsetPosition: + case SceneObjectPartSyncProperties.Scale: + case SceneObjectPartSyncProperties.SitTargetPosition: + case SceneObjectPartSyncProperties.SitTargetPositionLL: + case SceneObjectPartSyncProperties.SOP_Acceleration: + case SceneObjectPartSyncProperties.Velocity: + propertyData["Value"] = OSD.FromVector3((Vector3)LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, UUID types + //////////////////////////// + case SceneObjectPartSyncProperties.AttachedAvatar: + case SceneObjectPartSyncProperties.CollisionSound: + case SceneObjectPartSyncProperties.CreatorID: + case SceneObjectPartSyncProperties.FolderID: + case SceneObjectPartSyncProperties.GroupID: + case SceneObjectPartSyncProperties.LastOwnerID: + case SceneObjectPartSyncProperties.OwnerID: + case SceneObjectPartSyncProperties.Sound: + propertyData["Value"] = OSD.FromUUID((UUID)LastUpdateValue); + break; + + //case SceneObjectPartProperties.AttachedPos: + //////////////////////////// + //SOP properties, uint types + //////////////////////////// + case SceneObjectPartSyncProperties.AttachmentPoint: + case SceneObjectPartSyncProperties.BaseMask: + case SceneObjectPartSyncProperties.Category: + case SceneObjectPartSyncProperties.EveryoneMask: + case SceneObjectPartSyncProperties.GroupMask: + case SceneObjectPartSyncProperties.InventorySerial: + case SceneObjectPartSyncProperties.NextOwnerMask: + case SceneObjectPartSyncProperties.OwnerMask: + propertyData["Value"] = OSD.FromUInteger((uint)LastUpdateValue); + break; + + //case SceneObjectPartProperties.BaseMask: + //case SceneObjectPartProperties.Category: + + //////////////////////////// + //SOP properties, byte types + //////////////////////////// + case SceneObjectPartSyncProperties.ClickAction: + case SceneObjectPartSyncProperties.Material: + case SceneObjectPartSyncProperties.ObjectSaleType: + case SceneObjectPartSyncProperties.UpdateFlag: + propertyData["Value"] = OSD.FromInteger((byte)LastUpdateValue); + break; + //case SceneObjectPartProperties.CollisionSound: + + //////////////////////////// + //SOP properties, float types + //////////////////////////// + case SceneObjectPartSyncProperties.CollisionSoundVolume: + propertyData["Value"] = OSD.FromReal((float)LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, Color(struct type) + //////////////////////////// + case SceneObjectPartSyncProperties.Color: + propertyData["Value"] = OSD.FromString(PropertySerializer.SerializeColor((System.Drawing.Color)LastUpdateValue)); + break; + + //////////////////////////// + //SOP properties, int types + //////////////////////////// + case SceneObjectPartSyncProperties.CreationDate: + case SceneObjectPartSyncProperties.LinkNum: + case SceneObjectPartSyncProperties.OwnershipCost: + case SceneObjectPartSyncProperties.SalePrice: + case SceneObjectPartSyncProperties.ScriptAccessPin: + propertyData["Value"] = OSD.FromInteger((int)LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, string types + //////////////////////////// + case SceneObjectPartSyncProperties.CreatorData: + case SceneObjectPartSyncProperties.Description: + case SceneObjectPartSyncProperties.MediaUrl: + case SceneObjectPartSyncProperties.Name: + case SceneObjectPartSyncProperties.SitName: + case SceneObjectPartSyncProperties.Text: + case SceneObjectPartSyncProperties.TouchName: + propertyData["Value"] = OSD.FromString((string)LastUpdateValue); + break; + //////////////////////////// + //SOP properties, byte[] types + //////////////////////////// + case SceneObjectPartSyncProperties.ParticleSystem: + case SceneObjectPartSyncProperties.TextureAnimation: + propertyData["Value"] = OSD.FromBinary((byte[])LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, Quaternion types + //////////////////////////// + case SceneObjectPartSyncProperties.RotationOffset: + case SceneObjectPartSyncProperties.SitTargetOrientation: + case SceneObjectPartSyncProperties.SitTargetOrientationLL: + propertyData["Value"] = OSD.FromQuaternion((Quaternion)LastUpdateValue); + break; + + //////////////////////////////////// + //PhysActor properties, float type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Buoyancy: + propertyData["Value"] = OSD.FromReal((float)LastUpdateValue); + break; + + //////////////////////////////////// + //PhysActor properties, bool type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Flying: + case SceneObjectPartSyncProperties.IsColliding: + case SceneObjectPartSyncProperties.CollidingGround: + case SceneObjectPartSyncProperties.IsPhysical: + case SceneObjectPartSyncProperties.Kinematic: + propertyData["Value"] = OSD.FromBoolean((bool)LastUpdateValue); + break; + + //////////////////////////////////// + //PhysActor properties, Vector3 type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Force: + case SceneObjectPartSyncProperties.PA_Acceleration: + case SceneObjectPartSyncProperties.Position: + case SceneObjectPartSyncProperties.RotationalVelocity: + case SceneObjectPartSyncProperties.Size: + case SceneObjectPartSyncProperties.Torque: + propertyData["Value"] = OSD.FromVector3((Vector3)LastUpdateValue); + break; + + //////////////////////////////////// + //PhysActor properties, Quaternion type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Orientation: + propertyData["Value"] = OSD.FromQuaternion((Quaternion)LastUpdateValue); + break; + + /////////////////////// + //SOG properties + /////////////////////// + case SceneObjectPartSyncProperties.IsSelected: + propertyData["Value"] = OSD.FromBoolean((bool)LastUpdateValue); + break; + + default: + DebugLog.WarnFormat("PrimSynInfo.PropertyToOSD -- no handler for property {0} ", m_property); + break; + } + return propertyData; + } + + /// + /// Set member values by decoding out of propertyData. Should only + /// be called in initialization time (e.g. from constructor). + /// + /// + private void FromOSDMap(OSDMap propertyData) + { + if (!propertyData.ContainsKey("LastUpdateTimeStamp")) + { + DebugLog.WarnFormat("PrimSynInfo.FromOSDMap -- OSDMap missing LastUpdateTimeStamp"); + } + else + { + m_lastUpdateTimeStamp = propertyData["LastUpdateTimeStamp"].AsLong(); + } + + if (!propertyData.ContainsKey("LastUpdateSyncID")) + { + DebugLog.WarnFormat("PrimSynInfo.FromOSDMap -- OSDMap missing LastUpdateSyncID"); + } + else + { + m_lastUpdateSyncID = propertyData["LastUpdateSyncID"].AsString(); + } + + //We do not test if propertyData.ContainsKey("Value"), since Jason + //serialization seems does not include a value if it's equals to + //the default value. So just let Jason decoding to set the value + //either by reading out of the OSDMap, or set to default value. + + switch (m_property) + { + /////////////////////////////////////// + //SOP properties with complex structure + /////////////////////////////////////// + case SceneObjectPartSyncProperties.Shape: + case SceneObjectPartSyncProperties.TaskInventory: + m_lastUpdateValue = (Object)propertyData["Value"].AsString(); + m_lastUpdateValueHash = Util.Md5Hash((string)m_lastUpdateValue); + break; + + //////////////////////////// + //SOP properties, enum types + //////////////////////////// + case SceneObjectPartSyncProperties.AggregateScriptEvents: + scriptEvents sEvents = (scriptEvents)(propertyData["Value"].AsInteger()); + m_lastUpdateValue = (Object)sEvents; + //propertyData["Value"] = OSD.FromInteger((int)((scriptEvents)LastUpdateValue)); + break; + case SceneObjectPartSyncProperties.Flags: + case SceneObjectPartSyncProperties.LocalFlags: + PrimFlags flags = (PrimFlags)(propertyData["Value"].AsInteger()); + m_lastUpdateValue = (Object)flags; + //propertyData["Value"] = OSD.FromInteger((int)((PrimFlags)LastUpdateValue)); + break; + //////////////////////////// + //SOP properties, bool types + //////////////////////////// + case SceneObjectPartSyncProperties.AllowedDrop: + case SceneObjectPartSyncProperties.IsAttachment: + case SceneObjectPartSyncProperties.PassTouches: + m_lastUpdateValue = (Object)(propertyData["Value"].AsBoolean()); + //propertyData["Value"] = OSD.FromBoolean((bool)LastUpdateValue); + break; + + //////////////////////////// + //SOP properties, Vector3 types + //////////////////////////// + case SceneObjectPartSyncProperties.AngularVelocity: + case SceneObjectPartSyncProperties.AttachedPos: + case SceneObjectPartSyncProperties.GroupPosition: + case SceneObjectPartSyncProperties.OffsetPosition: + case SceneObjectPartSyncProperties.Scale: + case SceneObjectPartSyncProperties.SitTargetPosition: + case SceneObjectPartSyncProperties.SitTargetPositionLL: + case SceneObjectPartSyncProperties.SOP_Acceleration: + case SceneObjectPartSyncProperties.Velocity: + //propertyData["Value"] = OSD.FromVector3((Vector3)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsVector3()); + break; + + //////////////////////////// + //SOP properties, UUID types + //////////////////////////// + case SceneObjectPartSyncProperties.AttachedAvatar: + case SceneObjectPartSyncProperties.CollisionSound: + case SceneObjectPartSyncProperties.CreatorID: + case SceneObjectPartSyncProperties.FolderID: + case SceneObjectPartSyncProperties.GroupID: + case SceneObjectPartSyncProperties.LastOwnerID: + case SceneObjectPartSyncProperties.OwnerID: + case SceneObjectPartSyncProperties.Sound: + //propertyData["Value"] = OSD.FromUUID((UUID)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsUUID()); + break; + + //case SceneObjectPartProperties.AttachedPos: + //////////////////////////// + //SOP properties, uint types + //////////////////////////// + case SceneObjectPartSyncProperties.AttachmentPoint: + case SceneObjectPartSyncProperties.BaseMask: + case SceneObjectPartSyncProperties.Category: + case SceneObjectPartSyncProperties.EveryoneMask: + case SceneObjectPartSyncProperties.GroupMask: + case SceneObjectPartSyncProperties.InventorySerial: + case SceneObjectPartSyncProperties.NextOwnerMask: + case SceneObjectPartSyncProperties.OwnerMask: + //propertyData["Value"] = OSD.FromUInteger((uint)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsUInteger()); + break; + + //case SceneObjectPartProperties.BaseMask: + //case SceneObjectPartProperties.Category: + + //////////////////////////// + //SOP properties, byte types + //////////////////////////// + case SceneObjectPartSyncProperties.ClickAction: + case SceneObjectPartSyncProperties.Material: + case SceneObjectPartSyncProperties.ObjectSaleType: + case SceneObjectPartSyncProperties.UpdateFlag: + //propertyData["Value"] = OSD.FromInteger((byte)LastUpdateValue); + byte pValue = (byte)(propertyData["Value"].AsInteger()); + m_lastUpdateValue = (Object)pValue; + break; + //case SceneObjectPartProperties.CollisionSound: + + //////////////////////////// + //SOP properties, float types + //////////////////////////// + case SceneObjectPartSyncProperties.CollisionSoundVolume: + //propertyData["Value"] = OSD.FromReal((float)LastUpdateValue); + float csValue = (float)propertyData["Value"].AsReal(); + m_lastUpdateValue = (Object)(csValue); + break; + + //////////////////////////// + //SOP properties, Color(struct type) + //////////////////////////// + case SceneObjectPartSyncProperties.Color: + //propertyData["Value"] = OSD.FromString(PropertySerializer.SerializeColor((System.Drawing.Color)LastUpdateValue)); + System.Drawing.Color cValue = PropertySerializer.DeSerializeColor(propertyData["Value"].AsString()); + m_lastUpdateValue = (Object)cValue; + break; + + //////////////////////////// + //SOP properties, int types + //////////////////////////// + case SceneObjectPartSyncProperties.CreationDate: + case SceneObjectPartSyncProperties.LinkNum: + case SceneObjectPartSyncProperties.OwnershipCost: + case SceneObjectPartSyncProperties.SalePrice: + case SceneObjectPartSyncProperties.ScriptAccessPin: + //propertyData["Value"] = OSD.FromInteger((int)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsInteger()); + break; + + //////////////////////////// + //SOP properties, string types + //////////////////////////// + case SceneObjectPartSyncProperties.CreatorData: + case SceneObjectPartSyncProperties.Description: + case SceneObjectPartSyncProperties.MediaUrl: + case SceneObjectPartSyncProperties.Name: + case SceneObjectPartSyncProperties.SitName: + case SceneObjectPartSyncProperties.Text: + case SceneObjectPartSyncProperties.TouchName: + //propertyData["Value"] = OSD.FromString((string)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsString()); + break; + //////////////////////////// + //SOP properties, byte[] types + //////////////////////////// + case SceneObjectPartSyncProperties.ParticleSystem: + case SceneObjectPartSyncProperties.TextureAnimation: + //propertyData["Value"] = OSD.FromBinary((byte[])LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsBinary()); + break; + + //////////////////////////// + //SOP properties, Quaternion types + //////////////////////////// + case SceneObjectPartSyncProperties.RotationOffset: + case SceneObjectPartSyncProperties.SitTargetOrientation: + case SceneObjectPartSyncProperties.SitTargetOrientationLL: + //propertyData["Value"] = OSD.FromQuaternion((Quaternion)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsQuaternion()); + break; + + //////////////////////////////////// + //PhysActor properties, float type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Buoyancy: + //propertyData["Value"] = OSD.FromReal((float)LastUpdateValue); + float bValue = (float)propertyData["Value"].AsReal(); + m_lastUpdateValue = (Object)(bValue); + break; + + //////////////////////////////////// + //PhysActor properties, bool type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Flying: + case SceneObjectPartSyncProperties.IsColliding: + case SceneObjectPartSyncProperties.CollidingGround: + case SceneObjectPartSyncProperties.IsPhysical: + case SceneObjectPartSyncProperties.Kinematic: + //propertyData["Value"] = OSD.FromBoolean((bool)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsBoolean()); + break; + + //////////////////////////////////// + //PhysActor properties, Vector3 type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Force: + case SceneObjectPartSyncProperties.PA_Acceleration: + case SceneObjectPartSyncProperties.Position: + case SceneObjectPartSyncProperties.RotationalVelocity: + case SceneObjectPartSyncProperties.Size: + case SceneObjectPartSyncProperties.Torque: + //propertyData["Value"] = OSD.FromVector3((Vector3)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsVector3()); + break; + + //////////////////////////////////// + //PhysActor properties, Quaternion type + //////////////////////////////////// + case SceneObjectPartSyncProperties.Orientation: + //propertyData["Value"] = OSD.FromQuaternion((Quaternion)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsQuaternion()); + break; + + /////////////////////// + //SOG properties + /////////////////////// + case SceneObjectPartSyncProperties.IsSelected: + //propertyData["Value"] = OSD.FromBoolean((bool)LastUpdateValue); + m_lastUpdateValue = (Object)(propertyData["Value"].AsBoolean()); + break; + + default: + DebugLog.WarnFormat("PrimSynInfo.PropertyToOSD -- no handler for property {0} ", m_property); + break; + + } + } + + private string GetPropertyHashValue(string initValue) + { + return Util.Md5Hash(initValue); + } + + } + + public class PropertySerializer + { + //TO BE TESTED + + + public static string SerializeShape(SceneObjectPart part) + { + string serializedShape; + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter writer = new XmlTextWriter(sw)) + { + SceneObjectSerializer.WriteShape(writer, part.Shape, new Dictionary()); + } + serializedShape = sw.ToString(); + } + return serializedShape; + } + + public static PrimitiveBaseShape DeSerializeShape(string shapeString) + { + if (shapeString == null || shapeString == String.Empty || shapeString == "") + { + return null; + } + StringReader sr = new StringReader(shapeString); + XmlTextReader reader = new XmlTextReader(sr); + PrimitiveBaseShape shapeValue; + try + { + shapeValue = SceneObjectSerializer.ReadShape(reader, "Shape"); + } + catch (Exception e) + { + Console.WriteLine("DeSerializeShape: Error " + e.Message); + return null; + } + return shapeValue; + } + + public static string SerializeTaskInventory(SceneObjectPart part) + { + string serializedTaskInventory; + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter writer = new XmlTextWriter(sw)) + { + SceneObjectSerializer.WriteTaskInventory(writer, part.TaskInventory, new Dictionary(), part.ParentGroup.Scene); + } + serializedTaskInventory = sw.ToString(); + } + return serializedTaskInventory; + } + + public static TaskInventoryDictionary DeSerializeTaskInventory(string taskInvString) + { + if (taskInvString == null || taskInvString == String.Empty || taskInvString == "") + { + return null; + } + StringReader sr = new StringReader(taskInvString); + XmlTextReader reader = new XmlTextReader(sr); + TaskInventoryDictionary taskVal; + try + { + taskVal = SceneObjectSerializer.ReadTaskInventory(reader, "TaskInventory"); + }catch(Exception e) + { + Console.WriteLine("DeSerializeTaskInventory: Error " + e.Message); + return null; + } + return taskVal; + } + + //Copy code from SceneObjectSerializer.SOPToXml2 + public static string SerializeColor(System.Drawing.Color color) + { + string serializedColor; + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter writer = new XmlTextWriter(sw)) + { + writer.WriteStartElement("Color"); + writer.WriteElementString("R", color.R.ToString(Utils.EnUsCulture)); + writer.WriteElementString("G", color.G.ToString(Utils.EnUsCulture)); + writer.WriteElementString("B", color.B.ToString(Utils.EnUsCulture)); + writer.WriteElementString("A", color.G.ToString(Utils.EnUsCulture)); + writer.WriteEndElement(); + } + serializedColor = sw.ToString(); + } + return serializedColor; + } + + //Copy code from SceneObjectSerializer.ProcessColor + public static System.Drawing.Color DeSerializeColor(string colorString) + { + StringReader sr = new StringReader(colorString); + XmlTextReader reader = new XmlTextReader(sr); + + System.Drawing.Color color = new System.Drawing.Color(); + + reader.ReadStartElement("Color"); + if (reader.Name == "R") + { + float r = reader.ReadElementContentAsFloat("R", String.Empty); + float g = reader.ReadElementContentAsFloat("G", String.Empty); + float b = reader.ReadElementContentAsFloat("B", String.Empty); + float a = reader.ReadElementContentAsFloat("A", String.Empty); + color = System.Drawing.Color.FromArgb((int)a, (int)r, (int)g, (int)b); + reader.ReadEndElement(); + } + return color; + } + + } + + public class PrimSyncInfo + { + #region Members + public static long TimeOutThreshold; + public static ILog DebugLog; + + private Dictionary m_propertiesSyncInfo = new Dictionary(); + public Dictionary PropertiesSyncInfo + { + get { return m_propertiesSyncInfo; } + } + + private long m_PrimLastUpdateTime; + public long PrimLastUpdateTime + { + get { return m_PrimLastUpdateTime; } + } + + private UUID m_UUID; + public UUID UUID + { + get { return m_UUID; } + } + + private Object m_primSyncInfoLock = new Object(); + private static HashSet FullSetPrimProperties = SceneObjectPart.GetAllPrimProperties(); + private static HashSet PrimPhysActorProperties = SceneObjectPart.GetAllPhysActorProperties(); + private static HashSet PrimNonPhysActorProperties = SceneObjectPart.GetAllPrimNonPhysActorProperties(); + private static HashSet GroupProperties = SceneObjectPart.GetGroupProperties(); + + #endregion //Members + + #region Constructors + + public PrimSyncInfo(SceneObjectPart part, long initUpdateTimestamp, string syncID) + { + m_UUID = part.UUID; + InitPropertiesSyncInfo(part, initUpdateTimestamp, syncID); + } + + public PrimSyncInfo() + { + } + + public PrimSyncInfo(UUID id, OSDMap primSyncInfoData) + { + m_UUID = id; + InitPropertiesSyncInfoFromOSDMap(primSyncInfoData); + } + + #endregion //Constructors + + public void UpdatePropertyWithHashByLocal(SceneObjectPartSyncProperties property, long lastUpdateTS, string syncID, Object pValue, string pHashedValue) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateTS, syncID, pValue, pHashedValue); + } + + /* + public void UpdatePropertyByLocal(SceneObjectPartSyncProperties property, long lastUpdateTS, string syncID, Object pValue) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateTS, syncID, pValue); + } + * */ + + //public void UpdatePropertySyncInfoBySync(SceneObjectPartSyncProperties property, long lastUpdateTS, string syncID, Object pValue, Object pHashedValue, long recvTS) + //{ + // m_propertiesSyncInfo[property].UpdateSyncInfoBySync(lastUpdateTS, syncID, recvTS, pValue); + //} + + //Triggered when a set of local writes just happened, and ScheduleFullUpdate + //or ScheduleTerseUpdate has been called. + /// + /// Update copies of the given list of properties in the prim's SyncInfo. + /// + /// + /// + /// + /// + public HashSet UpdatePropertiesByLocal(SceneObjectPart part, List updatedProperties, long lastUpdateTS, string syncID) + { + //DSG DEBUG + /* + if (updatedProperties.Contains(SceneObjectPartSyncProperties.Shape)) + { + DebugLog.DebugFormat("UpdatePropertiesByLocal: To update SOP {0},{1} Shape to be {2}", part.Name, part.UUID, part.Shape.ProfileShape); + }*/ + + + HashSet propertiesToBeSynced = new HashSet(updatedProperties); + if (part == null) + { + propertiesToBeSynced.Clear(); + return propertiesToBeSynced; + } + + //pre-process properties in updatedProperties, for sanity checking + //or expanding/shrinking + foreach (SceneObjectPartSyncProperties property in updatedProperties) + { + //first, see if there are physics properties updated but PhysActor + //does not exist + if (SceneObjectPart.GetAllPhysActorProperties().Contains(property)) + { + if (part.PhysActor == null) + { + DebugLog.WarnFormat("PrimSyncInfo: Informed some physics property in SOP updated, yet SOP's PhysActor no longer exsits."); + return propertiesToBeSynced; + } + } + else + { + switch (property) + { + case SceneObjectPartSyncProperties.FullUpdate: + //Caller indicated many properties have changed. We need to + //compare and update all properties + if (part.PhysActor == null) + propertiesToBeSynced = PrimNonPhysActorProperties; + else + propertiesToBeSynced = FullSetPrimProperties; + break; + //return propertiesToBeSynced; + case SceneObjectPartSyncProperties.None: + propertiesToBeSynced.Clear(); + break; + } + } + } + + if(propertiesToBeSynced.Count==0){ + return propertiesToBeSynced; + } + + //Second, for each updated property in the list, find out the ones + //that really have recently been updated by local operations + HashSet propertiesUpdatedByLocal = new HashSet(); + + //DSG DEBUG + /* + if (propertiesToBeSynced.Contains(SceneObjectPartSyncProperties.Shape)) + { + DebugLog.DebugFormat("UpdatePropertiesByLocal: to update cache of SOP {0}, {1} Shape to {2}", part.Name, part.UUID, part.Shape.ProfileShape); + } + * */ + + lock (m_primSyncInfoLock) + { + foreach (SceneObjectPartSyncProperties property in propertiesToBeSynced) + { + bool updated = false; + //Compare if the value of the property in this SyncModule is + //different than the value in SOP + switch (property) + { + case SceneObjectPartSyncProperties.Shape: + case SceneObjectPartSyncProperties.TaskInventory: + //Convert the value of complex properties to string and hash + updated = CompareHashedValue_UpdateByLocal(part, property, lastUpdateTS, syncID); + break; + default: + updated = CompareValue_UpdateByLocal(part, property, lastUpdateTS, syncID); + break; + } + + if (updated) + { + propertiesUpdatedByLocal.Add(property); + } + } + } + return propertiesUpdatedByLocal; + } + + //TODO: might return status such as Updated, Unchanged, etc to caller + public List UpdatePropertiesBySync(SceneObjectPart part, HashSet propertiesSyncInfo) + { + long recvTS = DateTime.Now.Ticks; + List propertiesUpdated = new List(); + + lock (m_primSyncInfoLock) + { + foreach (PropertySyncInfo pSyncInfo in propertiesSyncInfo) + { + bool updated = false; + SceneObjectPartSyncProperties property = pSyncInfo.Property; + //Compare if the value of the property in this SyncModule is + //different than the value in SOP + if (!m_propertiesSyncInfo.ContainsKey(property)) + { + //Should not happen + DebugLog.WarnFormat("PrimSyncInfo.UpdatePropertiesBySync -- no record of property {0} for SOP {1},{2}", property, part.Name, part.UUID); + } + else + { + //Compare timestamp and update SyncInfo if necessary + updated = m_propertiesSyncInfo[property].CompareAndUpdateSyncInfoBySync(pSyncInfo, recvTS); + //If updated, update the property value in SOP + if (updated) + { + //DSG DEBUG + /* + if (property == SceneObjectPartSyncProperties.Shape) + { + DebugLog.DebugFormat("UpdatePropertiesBySync: updating Shape of {0}, {1}", part.Name, part.UUID); + } + * */ + + //UpdateSOPProperty(part, m_propertiesSyncInfo[property]); + SetSOPPropertyValue(part, property); + propertiesUpdated.Add(property); + } + } + } + } + return propertiesUpdated; + } + + public List UpdatePropertiesBySync(SceneObjectPart part, PrimSyncInfo updatedPrimSyncInfo) + { + HashSet propertiesSyncInfo = new HashSet(updatedPrimSyncInfo.PropertiesSyncInfo.Values); + return UpdatePropertiesBySync(part, propertiesSyncInfo); + } + + + /// + /// Encode the SyncInfo of each property, including its current value + /// maintained in this SyncModule, its timestamp and syncID. + /// + /// The list of properties to be encoded. + /// If FullUpdate is included, then encode all properties. + /// + public OSDMap EncodePropertiesSyncInfo(HashSet propertiesToSync) + { + OSDMap propertyData = new OSDMap(); + + //Lock first, so that we effectively freeze the record and take a snapshot + lock (m_primSyncInfoLock) + { + if (propertiesToSync.Contains(SceneObjectPartSyncProperties.FullUpdate)) + { + foreach (SceneObjectPartSyncProperties property in FullSetPrimProperties) + { + if (m_propertiesSyncInfo.ContainsKey(property)) + propertyData.Add(property.ToString(), m_propertiesSyncInfo[property].ToOSDMap()); + else + { + DebugLog.WarnFormat("PrimSyncInfo: property {0} not in sync cache", property); + } + } + } + else + { + foreach (SceneObjectPartSyncProperties property in propertiesToSync) + { + if (m_propertiesSyncInfo.ContainsKey(property)) + propertyData.Add(property.ToString(), m_propertiesSyncInfo[property].ToOSDMap()); + else + { + DebugLog.WarnFormat("PrimSyncInfo: property {0} not in sync cache", property); + } + } + } + } + return propertyData; + } + + /// + /// Decode a set of PropertySyncInfo from OSDMap. + /// + /// + public static HashSet DecodeProperiesSyncInfo(OSDMap primSyncInfoData) + { + HashSet propertiesSyncInfo = new HashSet(); + + foreach (string propertyString in primSyncInfoData.Keys) + { + //convert string to enum + SceneObjectPartSyncProperties property = (SceneObjectPartSyncProperties)Enum.Parse(typeof(SceneObjectPartSyncProperties), propertyString, true); + if (FullSetPrimProperties.Contains(property)) + { + //PropertySyncInfo propertySyncInfo = OSDMapToPropertySyncInfo((OSDMap)primSyncInfoData[property.ToString()]); + PropertySyncInfo propertySyncInfo = new PropertySyncInfo(property, (OSDMap)primSyncInfoData[propertyString]); + propertiesSyncInfo.Add(propertySyncInfo); + }else{ + //DebugLog.WarnFormat("DecodeAndSetProperiesSyncInfo: Property {0} not a valid SceneObjectPartSyncProperties", propertyString); + } + } + return propertiesSyncInfo; + } + + //Should only be called after receiving a message with encoded prim properties, + // + /// + /// Create a SOP instance based on the properties in PrimSyncInfo. Should + /// only be called after receiving a message with encoded prim properties, + /// and the SOP with the given UUID does not exsit locally yet. + /// + /// + public SceneObjectPart PrimSyncInfoToSOP() + { + SceneObjectPart sop = new SceneObjectPart(); + sop.UUID = m_UUID; + + foreach (SceneObjectPartSyncProperties property in FullSetPrimProperties) + { + if (m_propertiesSyncInfo.ContainsKey(property)) + SetSOPPropertyValue(sop, property); + else + { + //This might just be fine. For phantom objects, they don't have + //PhysActor properties, and those properties would end up here. + + //DebugLog.WarnFormat("PrimSyncInfoToSOP -- property {0} not in record.", property); + } + } + return sop; + } + + public void SetSOPPhyscActorProperties(SceneObjectPart sop) + { + foreach (SceneObjectPartSyncProperties property in PrimPhysActorProperties) + { + SetSOPPropertyValue(sop, property); + } + } + + public void SetGroupProperties(SceneObjectPart sop) + { + foreach (SceneObjectPartSyncProperties property in GroupProperties) + { + SetSOPPropertyValue(sop, property); + } + } + + /// + /// Initialize the properties with the values in the given SOP. + /// + /// + /// + /// + private void InitPropertiesSyncInfo(SceneObjectPart part, long initUpdateTimestamp, string syncID) + { + m_propertiesSyncInfo.Clear(); + HashSet initPrimProperties; + + if (part.PhysActor == null) + initPrimProperties = PrimNonPhysActorProperties; + else + initPrimProperties = FullSetPrimProperties; + + lock (m_primSyncInfoLock) + { + foreach (SceneObjectPartSyncProperties property in initPrimProperties) + { + Object initValue = GetSOPPropertyValue(part, property); + PropertySyncInfo syncInfo = new PropertySyncInfo(property, initValue, initUpdateTimestamp, syncID); + m_propertiesSyncInfo.Add(property, syncInfo); + } + } + } + + /// + /// Decode PropertySyncInfo for each property and insert into m_propertiesSyncInfo. + /// This is called to initialize this PrimSyncInfo by decoding from OSDMap. + /// + /// + private void InitPropertiesSyncInfoFromOSDMap(OSDMap primSyncInfoData) + { + lock (m_primSyncInfoLock) + { + m_propertiesSyncInfo.Clear(); + foreach (SceneObjectPartSyncProperties property in FullSetPrimProperties) + { + if (primSyncInfoData.ContainsKey(property.ToString())) + { + PropertySyncInfo propertySyncInfo = new PropertySyncInfo(property, (OSDMap)primSyncInfoData[property.ToString()]); + m_propertiesSyncInfo.Add(property, propertySyncInfo); + } + else + { + //For Phantom prims, they don't have PhysActor properties. So this branch could happen. + //DebugLog.WarnFormat("InitPropertiesSyncInfoFromOSDMap: Property {0} not included in the given OSDMap", property); + } + } + } + } + + //Assumption: the caller already locks the access lock, and no need to lock here + private bool CompareHashedValue_UpdateByLocal(SceneObjectPart part, SceneObjectPartSyncProperties property, long lastUpdateTS, string syncID) + { + bool updated = false; + if (!m_propertiesSyncInfo.ContainsKey(property)) + { + Object initValue = GetSOPPropertyValue(part, property); + PropertySyncInfo syncInfo = new PropertySyncInfo(property, initValue, lastUpdateTS, syncID); + m_propertiesSyncInfo.Add(property, syncInfo); + return true; + } + switch (property) + { + case SceneObjectPartSyncProperties.Shape: + string primShapeString = PropertySerializer.SerializeShape(part); + string primShapeStringHash = Util.Md5Hash(primShapeString); + + if (!m_propertiesSyncInfo[property].IsHashValueEqual(primShapeStringHash)) + { + //The SOP's property value has a newer timestamp, update the data in + //PrimSyncInfoManager to be consistent; otherwise, overwrite SOP's property + //value by copying that from PrimSyncInfoManager + if (lastUpdateTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + UpdatePropertyWithHashByLocal(property, lastUpdateTS, syncID, (Object)primShapeString, primShapeStringHash); + + //DSG DEBUG + //DebugLog.DebugFormat("CompareHashedValue_UpdateByLocal - Shape of {0}, {1} updated to ProfileShape {2}: SOP hashed shape: {3}, cached hash {4}", + // part.Name, part.UUID, part.Shape.ProfileShape, primShapeStringHash, m_propertiesSyncInfo[property].LastUpdateValueHash); + + updated = true; + } + else if (lastUpdateTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + PrimitiveBaseShape shape = PropertySerializer.DeSerializeShape((string)m_propertiesSyncInfo[property].LastUpdateValue); + part.Shape = shape; + } + + } + break; + case SceneObjectPartSyncProperties.TaskInventory: + string primTaskInventoryString = PropertySerializer.SerializeTaskInventory(part); + string primTaskInventoryStringHash = Util.Md5Hash(primTaskInventoryString); + if (!m_propertiesSyncInfo[property].IsHashValueEqual(primTaskInventoryStringHash)) + { + if (lastUpdateTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + UpdatePropertyWithHashByLocal(property, lastUpdateTS, syncID, (Object)primTaskInventoryString, primTaskInventoryStringHash); + updated = true; + } + else if (lastUpdateTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + TaskInventoryDictionary taskInv = PropertySerializer.DeSerializeTaskInventory((string)m_propertiesSyncInfo[property].LastUpdateValue); + part.TaskInventory = taskInv; + } + } + break; + default: + break; + } + return updated; + } + + + /// + /// Compare the value (not "reference") of the given property. + /// Assumption: the caller has already checked if PhysActor exists + /// if there are physics properties updated. + /// If the value maintained here is different from that in SOP data, + /// synchronize the two: + /// (1) if the value here has a timestamp newer than lastUpdateByLocalTS + /// (e.g. due to clock drifts among different sync nodes, a remote + /// write might have a newer timestamp than the local write), + /// overwrite the SOP's property with the value here (effectively + /// disvalidate the local write operation that just happened). + /// (2) otherwise, copy SOP's data and update timestamp and syncID + /// as indicated by "lastUpdateByLocalTS" and "syncID". + /// + /// + /// + /// + /// + /// Return true if the property's value maintained in this + /// RegionSyncModule is replaced by SOP's data. + private bool CompareValue_UpdateByLocal(SceneObjectPart part, SceneObjectPartSyncProperties property, long lastUpdateByLocalTS, string syncID) + { + bool propertyUpdatedByLocal = false; + + if (!m_propertiesSyncInfo.ContainsKey(property)) + { + Object initValue = GetSOPPropertyValue(part, property); + PropertySyncInfo syncInfo = new PropertySyncInfo(property, initValue, lastUpdateByLocalTS, syncID); + m_propertiesSyncInfo.Add(property, syncInfo); + return true; + } + + //First, check if the value maintained here is different from that + //in SOP's. If different, next check if the timestamp in SyncInfo is + //bigger (newer) than lastUpdateByLocalTS; if so (although ideally + //should not happen, but due to things likc clock not so perfectly + //sync'ed, it might happen), overwrite SOP's value with what's maintained + //in SyncInfo; otherwise, copy SOP's data to SyncInfo. + + //Note: for properties handled in this + //function, they are mainly value types (int, bool, struct, etc). + //So they are copied by value, not by reference. + //For a few properties, we copy by clone. + switch (property) + { + /////////////////////// + //SOP properties + /////////////////////// + case SceneObjectPartSyncProperties.AggregateScriptEvents: + if (!part.AggregateScriptEvents.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //copy from SOP's data + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.AggregateScriptEvents); + propertyUpdatedByLocal = true; + + //TEMP DEBUG + //DebugLog.DebugFormat("CompareValue_UpdateByLocal -- copy SOP's AggregateScriptEvents {0}", part.AggregateScriptEvents); + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.AggregateScriptEvents = (scriptEvents) m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.AllowedDrop: + if (!part.AllowedDrop.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.AllowedDrop); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.AllowedDrop = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.AngularVelocity: + if (!part.AngularVelocity.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.AngularVelocity); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.AngularVelocity = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.AttachedAvatar: + if (!part.AttachedAvatar.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.AttachedAvatar); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.AttachedAvatar = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.AttachedPos: + if (!part.AttachedPos.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.AttachedPos); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.AttachedPos = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.AttachmentPoint: + if (!part.AttachmentPoint.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.AttachmentPoint); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.AttachmentPoint = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.BaseMask: + if (!part.BaseMask.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.BaseMask); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.BaseMask = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Category: + if (!part.Category.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Category); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Category = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.ClickAction: + if (!part.ClickAction.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.ClickAction); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + SetSOPCollisionSound(part, (UUID)m_propertiesSyncInfo[property].LastUpdateValue); + } + } + break; + case SceneObjectPartSyncProperties.CollisionSound: + if (!part.CollisionSound.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.CollisionSound); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.CollisionSound = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.CollisionSoundVolume: + if (!part.CollisionSoundVolume.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.CollisionSoundVolume); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.CollisionSoundVolume = (float)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Color: + if (!part.Color.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Color); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Color = (System.Drawing.Color)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.CreationDate: + if (!part.CreationDate.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.CreationDate); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.CreationDate = (int)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.CreatorData: + if (!part.CreatorData.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.CreatorData.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.CreatorData = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.CreatorID: + if (!part.CreatorID.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.CreatorID); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.CreatorID = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Description: + if (!part.Description.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Description.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Description = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.EveryoneMask: + if (!part.EveryoneMask.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.EveryoneMask); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.EveryoneMask = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Flags: + if (!part.Flags.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Flags); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Flags = (PrimFlags)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.FolderID: + if (!part.FolderID.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.FolderID); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.FolderID = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + //Skip SceneObjectPartProperties.FullUpdate, which should be handled seperatedly + case SceneObjectPartSyncProperties.GroupID: + if (!part.GroupID.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.GroupID); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.GroupID = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.GroupMask: + if (!part.GroupMask.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.GroupMask); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.GroupMask = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.GroupPosition: + /* + if (!part.GroupPosition.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.GroupPosition); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.GroupPosition = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + * */ + propertyUpdatedByLocal = CompareAndUpdateSOPGroupPosition(part, lastUpdateByLocalTS, syncID); + break; + case SceneObjectPartSyncProperties.InventorySerial: + if (!part.InventorySerial.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.InventorySerial); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.InventorySerial = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.IsAttachment: + if (!part.IsAttachment.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.IsAttachment); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.IsAttachment = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.LastOwnerID: + if (!part.LastOwnerID.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.LastOwnerID); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.LastOwnerID = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.LinkNum: + if (!part.LinkNum.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.LinkNum); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.LinkNum = (int)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.LocalFlags: + if (!part.LocalFlags.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.LocalFlags); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.LocalFlags = (PrimFlags)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Material: + if (!part.Material.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Material); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Material = (byte)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.MediaUrl: + //Use "!=" to compare, instead of "Equals", because part.MediaUrl + //might be null. + //String assignment in C# create a new copy of the string, hence we do + //not call clone() explicitly, so that the case of "part.MediaUrl==null" + //can be handled properly as well + if (part.MediaUrl != (string) m_propertiesSyncInfo[property].LastUpdateValue) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.MediaUrl); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.MediaUrl = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Name: + if (!part.Name.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Name.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Name = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.NextOwnerMask: + if (!part.NextOwnerMask.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.NextOwnerMask); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.NextOwnerMask = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.ObjectSaleType: + if (!part.ObjectSaleType.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.ObjectSaleType); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.ObjectSaleType = (byte)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.OffsetPosition: + if (!part.OffsetPosition.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.OffsetPosition); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.OffsetPosition = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.OwnerID: + if (!part.OwnerID.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.OwnerID); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.OwnerID = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.OwnerMask: + if (!part.OwnerMask.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.OwnerMask); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.OwnerMask = (uint)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.OwnershipCost: + if (!part.OwnershipCost.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.OwnershipCost); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.OwnershipCost = (int)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.ParticleSystem: + if (!ByteArrayEquals(part.ParticleSystem, (Byte[])m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, part.ParticleSystem.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + byte[] pValue = (byte[])m_propertiesSyncInfo[property].LastUpdateValue; + part.ParticleSystem = (byte[])pValue.Clone(); + } + } + break; + case SceneObjectPartSyncProperties.PassTouches: + if (!part.PassTouches.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PassTouches); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.PassTouches = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.RotationOffset: + if (!part.RotationOffset.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.RotationOffset); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.RotationOffset = (Quaternion)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.SalePrice: + if (!part.SalePrice.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.SalePrice); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.SalePrice = (int)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Scale: + if (!part.Scale.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Scale); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Scale = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.ScriptAccessPin: + if (!part.ScriptAccessPin.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.ScriptAccessPin); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.ScriptAccessPin = (int)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + //case SceneObjectPartProperties.Shape: -- For "Shape", we need to call CompareHashValues + case SceneObjectPartSyncProperties.SitName: + if (!part.SitName.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.SitName.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.SitName = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.SitTargetOrientation: + if (!part.SitTargetOrientation.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.SitTargetOrientation); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.SitTargetOrientation = (Quaternion)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.SitTargetOrientationLL: + if (!part.SitTargetOrientationLL.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.SitTargetOrientationLL); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.SitTargetOrientationLL = (Quaternion)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.SitTargetPosition: + if (!part.SitTargetPosition.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.SitTargetPosition); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.SitTargetOrientation = (Quaternion)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.SitTargetPositionLL: + if (!part.SitTargetPositionLL.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.SitTargetPositionLL); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.SitTargetPosition = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.SOP_Acceleration: + if (!part.Acceleration.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Acceleration); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Acceleration = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Sound: + if (!part.Sound.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Sound); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Sound = (UUID)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + //case SceneObjectPartProperties.TaskInventory:-- For "TaskInventory", we need to call CompareHashValues + case SceneObjectPartSyncProperties.Text: + if (!part.Text.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Text.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Text = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.TextureAnimation: + if (!ByteArrayEquals(part.TextureAnimation, (Byte[])m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, part.TextureAnimation.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + byte[] pValue = (byte[])m_propertiesSyncInfo[property].LastUpdateValue; + part.TextureAnimation = (byte[])pValue.Clone(); + } + } + break; + case SceneObjectPartSyncProperties.TouchName: + if (!part.TouchName.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.TouchName.Clone()); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.TouchName = (string)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.UpdateFlag: + if (!part.UpdateFlag.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.UpdateFlag); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.UpdateFlag = (byte)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Velocity: + if (!part.Velocity.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.Velocity); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite SOP's data + part.Velocity = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + + /////////////////////// + //PhysActor properties + /////////////////////// + case SceneObjectPartSyncProperties.Buoyancy: + if (!part.PhysActor.Buoyancy.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Buoyancy); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Buoyancy = (float)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Flying: + if (!part.PhysActor.Flying.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Flying); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Flying = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Force: + if (!part.PhysActor.Force.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Force); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Force = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.IsColliding: + if (!part.PhysActor.IsColliding.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.IsColliding); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.IsColliding = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.CollidingGround: + if (!part.PhysActor.CollidingGround.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.CollidingGround); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.CollidingGround = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.IsPhysical: + if (!part.PhysActor.IsPhysical.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.IsPhysical); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.IsPhysical = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Kinematic: + if (!part.PhysActor.Kinematic.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Kinematic); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Kinematic = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Orientation: + if (!part.PhysActor.Orientation.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Orientation); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Orientation = (Quaternion)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.PA_Acceleration: + if (!part.PhysActor.Acceleration.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Acceleration); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Acceleration = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Position: + /* + if (!part.PhysActor.Position.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Position); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Position = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + * */ + propertyUpdatedByLocal = CompareAndUpdateSOPPosition(part, lastUpdateByLocalTS, syncID); + break; + case SceneObjectPartSyncProperties.RotationalVelocity: + if (!part.PhysActor.RotationalVelocity.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.RotationalVelocity); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.RotationalVelocity = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Size: + if (!part.PhysActor.Size.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Size); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Size = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + case SceneObjectPartSyncProperties.Torque: + if (!part.PhysActor.Torque.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Torque); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.PhysActor.Torque = (Vector3)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + + /////////////////////// + //SOG properties + /////////////////////// + case SceneObjectPartSyncProperties.IsSelected: + if (!part.ParentGroup.IsSelected.Equals(m_propertiesSyncInfo[property].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + m_propertiesSyncInfo[property].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.ParentGroup.IsSelected); + propertyUpdatedByLocal = true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[property].LastUpdateTimeStamp) + { + //overwrite PhysActor's data + part.ParentGroup.IsSelected = (bool)m_propertiesSyncInfo[property].LastUpdateValue; + } + } + break; + } + + return propertyUpdatedByLocal; + } + + + private bool ByteArrayEquals(byte[] a, byte[] b) + { + if (a.Length != b.Length) + return false; + for (int i = 0; i < a.Length; i++) + { + if (a[i] != b[i]) + return false; + } + return true; + } + + private Object GetSOPPropertyValue(SceneObjectPart part, SceneObjectPartSyncProperties property) + { + if (part == null) return null; + + Object pValue = null; + switch (property) + { + case SceneObjectPartSyncProperties.Shape: + return (Object)PropertySerializer.SerializeShape(part); + case SceneObjectPartSyncProperties.TaskInventory: + return (Object)PropertySerializer.SerializeTaskInventory(part); + + /////////////////////// + //SOP properties + /////////////////////// + case SceneObjectPartSyncProperties.AggregateScriptEvents: + return (Object)part.AggregateScriptEvents; + case SceneObjectPartSyncProperties.AllowedDrop: + return (Object)part.AllowedDrop; + case SceneObjectPartSyncProperties.AngularVelocity: + return (Object)part.AngularVelocity; + case SceneObjectPartSyncProperties.AttachedAvatar: + return (Object)part.AttachedAvatar; + case SceneObjectPartSyncProperties.AttachedPos: + return (Object)part.AttachedPos; + case SceneObjectPartSyncProperties.AttachmentPoint: + return (Object)part.AttachmentPoint; + case SceneObjectPartSyncProperties.BaseMask: + return (Object)part.BaseMask; + case SceneObjectPartSyncProperties.Category: + return (Object)part.Category; + case SceneObjectPartSyncProperties.ClickAction: + return (Object)part.ClickAction; + case SceneObjectPartSyncProperties.CollisionSound: + return (Object)part.CollisionSound; + case SceneObjectPartSyncProperties.CollisionSoundVolume: + return (Object)part.CollisionSoundVolume; + case SceneObjectPartSyncProperties.Color: + return (Object)part.Color; + case SceneObjectPartSyncProperties.CreationDate: + return (Object)part.CreationDate; + case SceneObjectPartSyncProperties.CreatorData: + return (Object)part.CreatorData; + case SceneObjectPartSyncProperties.CreatorID: + return (Object)part.CreatorID; + case SceneObjectPartSyncProperties.Description: + return (Object)part.Description; + case SceneObjectPartSyncProperties.EveryoneMask: + return (Object)part.EveryoneMask; + case SceneObjectPartSyncProperties.Flags: + return (Object)part.Flags; + case SceneObjectPartSyncProperties.FolderID: + return (Object)part.FolderID; + //Skip SceneObjectPartProperties.FullUpdate, which should be handled seperatedly + case SceneObjectPartSyncProperties.GroupID: + return (Object)part.GroupID; + case SceneObjectPartSyncProperties.GroupMask: + return (Object)part.GroupMask; + case SceneObjectPartSyncProperties.GroupPosition: + return (Object)part.GroupPosition; + case SceneObjectPartSyncProperties.InventorySerial: + return (Object)part.InventorySerial; + case SceneObjectPartSyncProperties.IsAttachment: + return (Object)part.IsAttachment; + case SceneObjectPartSyncProperties.LastOwnerID: + return (Object)part.LastOwnerID; + case SceneObjectPartSyncProperties.LinkNum: + return (Object)part.LinkNum; + case SceneObjectPartSyncProperties.LocalFlags: + return (Object)part.LocalFlags; + case SceneObjectPartSyncProperties.Material: + return (Object)part.Material; + case SceneObjectPartSyncProperties.MediaUrl: + return (Object)part.MediaUrl; + case SceneObjectPartSyncProperties.Name: + return (Object)part.Name; + case SceneObjectPartSyncProperties.NextOwnerMask: + return (Object)part.NextOwnerMask; + case SceneObjectPartSyncProperties.ObjectSaleType: + return (Object)part.ObjectSaleType; + case SceneObjectPartSyncProperties.OffsetPosition: + return (Object)part.OffsetPosition; + case SceneObjectPartSyncProperties.OwnerID: + return (Object)part.OwnerID; + case SceneObjectPartSyncProperties.OwnerMask: + return (Object)part.OwnerMask; + case SceneObjectPartSyncProperties.OwnershipCost: + return (Object)part.OwnershipCost; + case SceneObjectPartSyncProperties.ParticleSystem: + //byte[], return a cloned copy + return (Object)part.ParticleSystem.Clone(); + case SceneObjectPartSyncProperties.PassTouches: + return (Object)part.PassTouches; + case SceneObjectPartSyncProperties.RotationOffset: + return (Object)part.RotationOffset; + case SceneObjectPartSyncProperties.SalePrice: + return (Object)part.SalePrice; + case SceneObjectPartSyncProperties.Scale: + return (Object)part.Scale; + case SceneObjectPartSyncProperties.ScriptAccessPin: + return (Object)part.ScriptAccessPin; + //case SceneObjectPartProperties.Shape: -- For "Shape", we need to call CompareHashValues + case SceneObjectPartSyncProperties.SitName: + return (Object)part.SitName; + case SceneObjectPartSyncProperties.SitTargetOrientation: + return (Object)part.SitTargetOrientation; + case SceneObjectPartSyncProperties.SitTargetOrientationLL: + return (Object)part.SitTargetOrientationLL; + case SceneObjectPartSyncProperties.SitTargetPosition: + return (Object)part.SitTargetPosition; + case SceneObjectPartSyncProperties.SitTargetPositionLL: + return (Object)part.SitTargetPositionLL; + case SceneObjectPartSyncProperties.SOP_Acceleration: + return (Object)part.Acceleration; + case SceneObjectPartSyncProperties.Sound: + return (Object)part.Sound; + //case SceneObjectPartProperties.TaskInventory:-- For "TaskInventory", we need to call CompareHashValues + case SceneObjectPartSyncProperties.Text: + return (Object)part.Text; + case SceneObjectPartSyncProperties.TextureAnimation: + //byte[], return a cloned copy + return part.TextureAnimation.Clone(); + case SceneObjectPartSyncProperties.TouchName: + return (Object)part.TouchName; + case SceneObjectPartSyncProperties.UpdateFlag: + return (Object)part.UpdateFlag; + case SceneObjectPartSyncProperties.Velocity: + return (Object)part.Velocity; + + /////////////////////// + //PhysActor properties + /////////////////////// + case SceneObjectPartSyncProperties.Buoyancy: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Buoyancy; + case SceneObjectPartSyncProperties.Flying: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Flying; + case SceneObjectPartSyncProperties.Force: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Force; + case SceneObjectPartSyncProperties.IsColliding: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.IsColliding; + case SceneObjectPartSyncProperties.CollidingGround: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.CollidingGround; + case SceneObjectPartSyncProperties.IsPhysical: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.IsPhysical; + case SceneObjectPartSyncProperties.Kinematic: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Kinematic; + case SceneObjectPartSyncProperties.Orientation: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Orientation; + case SceneObjectPartSyncProperties.PA_Acceleration: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Acceleration; + case SceneObjectPartSyncProperties.Position: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Position; + case SceneObjectPartSyncProperties.RotationalVelocity: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.RotationalVelocity; + case SceneObjectPartSyncProperties.Size: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Size; + case SceneObjectPartSyncProperties.Torque: + if (part.PhysActor == null) + return null; + return (Object)part.PhysActor.Torque; + + /////////////////////// + //SOG properties + /////////////////////// + case SceneObjectPartSyncProperties.IsSelected: + return (Object)part.ParentGroup.IsSelected; + } + + return pValue; + } + + /// + /// Set the property's value based on the value maintained in PrimSyncInfoManager. + /// Assumption: caller will call ScheduleFullUpdate to enqueue updates properly. + /// + /// + /// + private void SetSOPPropertyValue(SceneObjectPart part, SceneObjectPartSyncProperties property) + { + if (part == null) return; + if (!m_propertiesSyncInfo.ContainsKey(property)){ + //DebugLog.WarnFormat("SetSOPPropertyValue: property {0} not in record.", property.ToString()); + //For phantom prims, they don't have physActor properties, + //so for those properties, simply return + return; + } + + if (!m_propertiesSyncInfo.ContainsKey(property)) + { + DebugLog.WarnFormat("PrimSyncInfo: property {0} not in sync cache", property); + return; + } + PropertySyncInfo pSyncInfo = m_propertiesSyncInfo[property]; + + switch (property) + { + case SceneObjectPartSyncProperties.Shape: + PrimitiveBaseShape shapeVal = PropertySerializer.DeSerializeShape((string)pSyncInfo.LastUpdateValue); + if (shapeVal != null) + { + part.Shape = shapeVal; + /* + String hashedShape = Util.Md5Hash((PropertySerializer.SerializeShape(part))); + DebugLog.DebugFormat("Shape of SOP {0}, {1}, changed, hashed shape = {2} in SOP, = {3} in PrimSyncInfoManager", + part.Name, part.UUID, hashedShape, pSyncInfo.LastUpdateValueHash); + * */ + + } + else + { + + } + break; + case SceneObjectPartSyncProperties.TaskInventory: + TaskInventoryDictionary taskVal = PropertySerializer.DeSerializeTaskInventory((string)pSyncInfo.LastUpdateValue); + if (taskVal != null) + part.TaskInventory = taskVal; + break; + + /////////////////////// + //SOP properties + /////////////////////// + case SceneObjectPartSyncProperties.AggregateScriptEvents: + part.AggregateScriptEvents = (scriptEvents)pSyncInfo.LastUpdateValue; + + //DebugLog.DebugFormat("set {0} value to be {1}", property.ToString(), part.AggregateScriptEvents); + + break; + case SceneObjectPartSyncProperties.AllowedDrop: + part.AllowedDrop = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.AngularVelocity: + part.AngularVelocity = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.AttachedAvatar: + part.AttachedAvatar = (UUID)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.AttachedPos: + part.AttachedPos = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.AttachmentPoint: + part.AttachmentPoint = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.BaseMask: + part.BaseMask = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Category: + part.Category = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.ClickAction: + part.ClickAction = (byte)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.CollisionSound: + //part.CollisionSound = (UUID)pSyncInfo.LastUpdateValue; + SetSOPCollisionSound(part, (UUID)pSyncInfo.LastUpdateValue); + break; + case SceneObjectPartSyncProperties.CollisionSoundVolume: + part.CollisionSoundVolume = (float)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Color: + part.Color = (System.Drawing.Color)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.CreationDate: + part.CreationDate = (int)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.CreatorData: + part.CreatorData = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.CreatorID: + part.CreatorID = (UUID)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Description: + part.Description = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.EveryoneMask: + part.EveryoneMask = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Flags: + part.Flags = (PrimFlags)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.FolderID: + part.FolderID = (UUID)pSyncInfo.LastUpdateValue; + break; + //Skip SceneObjectPartProperties.FullUpdate, which should be handled seperatedly + case SceneObjectPartSyncProperties.GroupID: + part.GroupID = (UUID)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.GroupMask: + part.GroupMask = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.GroupPosition: + part.GroupPosition = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.InventorySerial: + part.InventorySerial = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.IsAttachment: + part.IsAttachment = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.LastOwnerID: + part.LastOwnerID = (UUID)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.LinkNum: + part.LinkNum = (int)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.LocalFlags: + part.LocalFlags = (PrimFlags)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Material: + part.Material = (byte)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.MediaUrl: + part.MediaUrl = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Name: + part.Name = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.NextOwnerMask: + part.NextOwnerMask = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.ObjectSaleType: + part.ObjectSaleType = (byte)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.OffsetPosition: + part.OffsetPosition = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.OwnerID: + part.OwnerID = (UUID)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.OwnerMask: + part.OwnerMask = (uint)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.OwnershipCost: + part.OwnershipCost = (int)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.ParticleSystem: + //byte[], return a cloned copy + byte[] pValue = (byte[])pSyncInfo.LastUpdateValue; + part.ParticleSystem = (byte[])pValue.Clone(); + break; + case SceneObjectPartSyncProperties.PassTouches: + part.PassTouches = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.RotationOffset: + part.RotationOffset = (Quaternion)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.SalePrice: + part.SalePrice = (int)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Scale: + part.Scale = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.ScriptAccessPin: + part.ScriptAccessPin = (int)pSyncInfo.LastUpdateValue; + break; + //case SceneObjectPartProperties.Shape: -- For "Shape", we need to call CompareHashValues + case SceneObjectPartSyncProperties.SitName: + part.SitName = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.SitTargetOrientation: + part.SitTargetOrientation = (Quaternion)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.SitTargetOrientationLL: + part.SitTargetOrientationLL = (Quaternion)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.SitTargetPosition: + part.SitTargetPosition = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.SitTargetPositionLL: + part.SitTargetPositionLL = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.SOP_Acceleration: + part.Acceleration = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Sound: + part.Sound = (UUID)pSyncInfo.LastUpdateValue; + break; + //case SceneObjectPartProperties.TaskInventory:-- For "TaskInventory", we need to call CompareHashValues + case SceneObjectPartSyncProperties.Text: + part.Text = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.TextureAnimation: + //byte[], return a cloned copy + byte[] tValue = (byte[])pSyncInfo.LastUpdateValue; + part.TextureAnimation = (byte[])tValue.Clone(); + break; + case SceneObjectPartSyncProperties.TouchName: + part.TouchName = (string)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.UpdateFlag: + part.UpdateFlag = (byte)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Velocity: + part.Velocity = (Vector3)pSyncInfo.LastUpdateValue; + break; + + /////////////////////// + //PhysActor properties + /////////////////////// + case SceneObjectPartSyncProperties.Buoyancy: + if (part.PhysActor != null) + part.PhysActor.Buoyancy = (float)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Flying: + if (part.PhysActor != null) + part.PhysActor.Flying = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Force: + if (part.PhysActor != null) + part.PhysActor.Force = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.IsColliding: + if (part.PhysActor != null) + part.PhysActor.IsColliding = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.CollidingGround: + if (part.PhysActor != null) + part.PhysActor.CollidingGround = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.IsPhysical: + if (part.PhysActor != null) + part.PhysActor.IsPhysical = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Kinematic: + if (part.PhysActor != null) + part.PhysActor.Kinematic = (bool)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Orientation: + if (part.PhysActor != null) + part.PhysActor.Orientation = (Quaternion)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.PA_Acceleration: + if (part.PhysActor != null) + part.PhysActor.Acceleration = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Position: + if (part.PhysActor != null) + part.PhysActor.Position = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.RotationalVelocity: + if (part.PhysActor != null) + part.PhysActor.RotationalVelocity = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Size: + if (part.PhysActor != null) + part.PhysActor.Size = (Vector3)pSyncInfo.LastUpdateValue; + break; + case SceneObjectPartSyncProperties.Torque: + if (part.PhysActor != null) + part.PhysActor.Torque = (Vector3)pSyncInfo.LastUpdateValue; + break; + + /////////////////////// + //SOG properties + /////////////////////// + case SceneObjectPartSyncProperties.IsSelected: + if (part.ParentGroup != null) + part.ParentGroup.IsSelected = (bool)pSyncInfo.LastUpdateValue; + break; + } + + //Calling ScheduleFullUpdate to trigger enqueuing updates for sync'ing (relay sync nodes need to do so) + //part.ScheduleFullUpdate(new List() { property }); + } + + //Do not call "part.CollisionSound =" to go through its set function. + //We don't want the side effect of calling aggregateScriptEvents. + private void SetSOPCollisionSound(SceneObjectPart part, UUID cSound) + { + if (part.UpdateCollisionSound(cSound)) + { + part.ParentGroup.Scene.EventManager.TriggerAggregateScriptEvents(part); + } + } + + //In SOP's implementation, GroupPosition and SOP.PhysActor.Position are + //correlated. We need to make sure that they are both properly synced. + private bool CompareAndUpdateSOPGroupPosition(SceneObjectPart part, long lastUpdateByLocalTS, string syncID) + { + if (!part.GroupPosition.Equals(m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateTimeStamp) + { + //Update cached value with SOP.GroupPosition + m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.GroupPosition); + + //Also may need to cached PhysActor.Position + if (part.PhysActor != null) + { + if (!part.PhysActor.Position.Equals(m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateValue)) + { + m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Position); + } + + } + return true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateTimeStamp) + { + //overwrite SOP's data, set function of GroupPosition updates PhysActor.Position as well + part.GroupPosition = (Vector3)m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateValue; + + //PhysActor.Position is just updated by setting GroupPosition + //above, so need to update the cached value of Position here. + if (part.PhysActor != null) + { + if (!part.PhysActor.Position.Equals(m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateValue)) + { + //Set the timestamp and syncID to be the same with GroupPosition + long lastUpdateTimestamp = m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateTimeStamp; + string lastUpdateSyncID = m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateSyncID; + m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].UpdateSyncInfoByLocal(lastUpdateTimestamp, + lastUpdateSyncID, (Object)part.PhysActor.Position); + } + } + } + } + return false; + } + + private bool CompareAndUpdateSOPPosition(SceneObjectPart part, long lastUpdateByLocalTS, string syncID) + { + if (part.PhysActor == null) + return false; + + if (!part.PhysActor.Position.Equals(m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateValue)) + { + if (lastUpdateByLocalTS > m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateTimeStamp) + { + //Update SOP.PhysActor.Position + m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.PhysActor.Position); + + //Also may need to update SOP.GroupPosition (especially for root parts) + if (!part.GroupPosition.Equals(m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateValue)) + { + //Update SOP.GroupPosition + m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].UpdateSyncInfoByLocal(lastUpdateByLocalTS, syncID, (Object)part.GroupPosition); + } + return true; + } + else if (lastUpdateByLocalTS < m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateTimeStamp) + { + //overwrite PhysActor's data with the cached value + part.PhysActor.Position = (Vector3)m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateValue; + + //GroupPosition may change due to PhysActor.Position changes, + //especially for root parts. Sync the value of GroupPosition. + if (!part.GroupPosition.Equals(m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].LastUpdateValue)) + { + //Need to reset SOP.GroupPosition to the cached value here + //Set the timestamp and syncID to be the same with Position + long lastUpdateTimestamp = m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateTimeStamp; + string lastUpdateSyncID = m_propertiesSyncInfo[SceneObjectPartSyncProperties.Position].LastUpdateSyncID; + m_propertiesSyncInfo[SceneObjectPartSyncProperties.GroupPosition].UpdateSyncInfoByLocal(lastUpdateTimestamp, + lastUpdateSyncID, (Object)part.GroupPosition); + } + } + } + return false; + } + } + + public class PrimSyncInfoManager + { + //private ILog DebugLog; + public static ILog DebugLog; + + /// + /// Lock for write-accessing m_primsInSync. We assume accesses to m_primsInSync + /// are in the "many reads, a few writes" pattern. Writers needs to lock on it. + /// Readers who interate through m_primsInSync need to copy a reference to + /// m_primsInSync and operate on the reference, but no need to lock. (Readers who + /// just grabs reference to one item in m_primsInSync for further operation + /// might not even need to copy a reference to m_primsInSync initially???) + /// + private Object m_primsInSyncLock = new Object(); + private Dictionary m_primsInSync; + private RegionSyncModule m_regionSyncModule; + + + /// + /// The max time for a SOP's SyncInfo to sit in record + /// w/o being updated either locally or bySync. + /// + private long m_ageOutThreshold; + + public Dictionary PrimsInSync + { + get { return m_primsInSync; } + } + + public PrimSyncInfoManager(RegionSyncModule syncModule, long ageOutTh) + { + m_primsInSync = new Dictionary(); + m_regionSyncModule = syncModule; + m_ageOutThreshold = ageOutTh; + } + + public bool IsPrimSyncInfoExist(UUID primUUID) + { + return m_primsInSync.ContainsKey(primUUID); + } + + /// + /// For each property in updatedProperties, (1) if the value in SOP's + /// data is different than that in PrimSyncInfo, and what's in PrimSyncInfo + /// has an older timestamp, then update that property's value and syncInfo + /// in PrimSyncInfo; (2) otherwise, skip the property and do nothing. + /// + /// + /// + /// The list properties among updatedProperties whose value + /// have been copied over to PrimSyncInfo. + public HashSet UpdatePrimSyncInfoByLocal(SceneObjectPart part, List updatedProperties) + { + long currentTime = DateTime.Now.Ticks; + if (m_primsInSync.ContainsKey(part.UUID)) + { + PrimSyncInfo primSyncInfo = m_primsInSync[part.UUID]; + return primSyncInfo.UpdatePropertiesByLocal(part, updatedProperties, currentTime, m_regionSyncModule.SyncID); + } + else + { + //The SOP's SyncInfo is no longer in my record, may due to + //TimeOut or something. Add it back. Assume the properties + //were "AgeOut" seconds old. + PrimSyncInfo primSyncInfo = new PrimSyncInfo(part, currentTime, m_regionSyncModule.SyncID); + InsertPrimSyncInfo(part.UUID, primSyncInfo); + + return new HashSet(updatedProperties); + } + } + + public List UpdatePrimSyncInfoBySync(SceneObjectPart part, HashSet propertiesSyncInfo) + { + if (m_primsInSync.ContainsKey(part.UUID)) + { + PrimSyncInfo primSyncInfo = m_primsInSync[part.UUID]; + return primSyncInfo.UpdatePropertiesBySync(part, propertiesSyncInfo); + } + else + { + //This should not happen, as we should only receive UpdatedPrimProperties after receiving a NewObject message + DebugLog.WarnFormat("PrimSyncInfoManager.UpdatePrimSyncInfoBySync: SOP {0},{1} not in local record of PrimSyncInfo.", part.Name, part.UUID); + return new List(); + } + } + + public List UpdatePrimSyncInfoBySync(SceneObjectPart part, PrimSyncInfo updatedPrimSyncInfo) + { + if (m_primsInSync.ContainsKey(part.UUID)) + { + PrimSyncInfo primSyncInfo = m_primsInSync[part.UUID]; + return primSyncInfo.UpdatePropertiesBySync(part, updatedPrimSyncInfo); + } + else + { + //This should not happen, as we should only receive UpdatedPrimProperties after receiving a NewObject message + DebugLog.WarnFormat("PrimSyncInfoManager.UpdatePrimSyncInfoBySync: SOP {0},{1} not in local record of PrimSyncInfo.", part.Name, part.UUID); + return new List(); + } + } + + public OSDMap EncodePrimProperties(SceneObjectPart sop, HashSet updatedProperties) + { + OSDMap data = new OSDMap(); + UUID primUUID = sop.UUID; + if (!m_primsInSync.ContainsKey(primUUID)) + { + DebugLog.WarnFormat("EncodePrimProperties: {0} not in RegionSyncModule's PrimSyncInfo list yet", primUUID); + return data; + } + + data["primUUID"] = OSDMap.FromUUID(primUUID); + + //If SceneObjectPartProperties.FullUpdate is in updatedProperties, + //convert it to the full list of all properties + HashSet propertiesToEncoded = updatedProperties; + if (updatedProperties.Contains(SceneObjectPartSyncProperties.FullUpdate)) + { + if (sop.PhysActor != null) + propertiesToEncoded = SceneObjectPart.GetAllPrimProperties(); + else + propertiesToEncoded = SceneObjectPart.GetAllPrimNonPhysActorProperties(); + } + + OSDMap propertyData = m_primsInSync[primUUID].EncodePropertiesSyncInfo(propertiesToEncoded); + data["propertyData"] = propertyData; + + return data; + } + + public HashSet DecodePrimProperties(OSDMap primPropertiesData) + { + HashSet propertiesSyncInfo = new HashSet(); + if (!primPropertiesData.ContainsKey("propertyData")) + { + DebugLog.WarnFormat("DecodePrimProperties: propertyData is missing"); + return propertiesSyncInfo; + } + + //if(!m_primsInSync.ContainsKey(primUUID)){ + // DebugLog.WarnFormat("prim {0} not in PrimSyncInfoManager's record"); + // return; + //} + propertiesSyncInfo = PrimSyncInfo.DecodeProperiesSyncInfo((OSDMap)primPropertiesData["propertyData"]); + + return propertiesSyncInfo; + } + + public PrimSyncInfo DecodeFullSetPrimProperties(OSDMap primData) + { + if (!primData.ContainsKey("primUUID") || !primData.ContainsKey("propertyData")) + { + DebugLog.WarnFormat("DecodeFullSetPrimProperties: either primUUID or propertyData is missing"); + return null; + } + UUID primUUID = primData["primUUID"]; + OSDMap propertyData = (OSDMap)primData["propertyData"]; + + PrimSyncInfo primSynInfo = new PrimSyncInfo(primUUID, propertyData); + + return primSynInfo; + } + + /// + /// Insert a new PrimSyncInfo into local record. Implemented for access + /// pattern of many readers/a few writers. + /// + /// + /// + /// True if primSyncInfo is inserted; false if it is already in + /// but updated. + public bool InsertPrimSyncInfo(UUID primUUID, PrimSyncInfo primSyncInfo) + { + lock (m_primsInSyncLock) + { + if (m_primsInSync.ContainsKey(primUUID)) + { + m_primsInSync[primUUID] = primSyncInfo; + return false; + } + + //copy the items from the old list and insert the new record + Dictionary newPrimsInSync = new Dictionary(m_primsInSync); + newPrimsInSync.Add(primUUID, primSyncInfo); + + //replace the old list + m_primsInSync = newPrimsInSync; + } + return true; + } + + /// + /// For a new SOP, create a PrimSyncInfo for it. Assume the timestamp for + /// each property is at least T ticks old, T=m_ageOutThreshold. + /// + /// + /// + /// + /// + public bool InsertPrimSyncInfo(SceneObjectPart part, long syncInfoInitTime, string syncID) + { + long lastUpdateTimeStamp = syncInfoInitTime - m_ageOutThreshold; + + PrimSyncInfo primSyncInfo = new PrimSyncInfo(part, lastUpdateTimeStamp, syncID); + lock (m_primsInSyncLock) + { + if (m_primsInSync.ContainsKey(part.UUID)) + { + m_primsInSync[part.UUID] = primSyncInfo; + return false; + } + Dictionary newPrimsInSync = new Dictionary(m_primsInSync); + newPrimsInSync.Add(part.UUID, primSyncInfo); + + m_primsInSync = newPrimsInSync; + } + return true; + } + + public void InsertMultiPrimSyncInfo(Dictionary multiPrimsSyncInfo) + { + lock (m_primsInSyncLock) + { + //copy the old list, update the copied list + Dictionary newPrimsInSync = new Dictionary(m_primsInSync); + foreach (KeyValuePair valPair in multiPrimsSyncInfo) + { + UUID primUUID = valPair.Key; + PrimSyncInfo primSyncInfo = valPair.Value; + if (newPrimsInSync.ContainsKey(primUUID)) + { + newPrimsInSync[primUUID] = primSyncInfo; + continue; + } + newPrimsInSync.Add(primUUID, primSyncInfo); + } + + //replace the old list + m_primsInSync = newPrimsInSync; + } + } + + public bool RemovePrimSyncInfo(SceneObjectPart part) + { + if (!m_primsInSync.ContainsKey(part.UUID)) + { + return false; + } + lock (m_primsInSyncLock) + { + Dictionary newPrimsInSync = new Dictionary(m_primsInSync); + newPrimsInSync.Remove(part.UUID); + + m_primsInSync = newPrimsInSync; + } + return true; + } + + public PrimSyncInfo GetPrimSyncInfo(UUID primUUID) + { + if (m_primsInSync.ContainsKey(primUUID)) + { + return m_primsInSync[primUUID]; + } + else + return null; + } + + public bool SetSOPPhyscActorProperties(SceneObjectPart part) + { + if(m_primsInSync.ContainsKey(part.UUID)){ + m_primsInSync[part.UUID].SetSOPPhyscActorProperties(part); + return true; + } + return false; + } + } } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs index 987a563257..165f951e31 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs @@ -47,6 +47,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // SIM <-> CM Terrain, NewObject, // objects + UpdatedPrimProperties, //per property sync UpdatedObject, // objects UpdatedBucketProperties, //object properties in one bucket RemovedObject, // objects diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index 5299e0b4ca..e5c0586c26 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -32,6 +32,12 @@ using OpenMetaverse; namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { + public enum SyncConnectorState + { + Idle, //not connected + Initialization, //initializing local copy of Scene + Syncing, //done initialization, in normal process of syncing terrain, objects, etc + } // For implementations, a lot was copied from RegionSyncClientView, especially the SendLoop/ReceiveLoop. public class SyncConnector : ISyncStatistics { @@ -53,11 +59,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private long bytesIn=0; private long bytesOut=0; private DateTime lastStatTime; + // A queue for outgoing traffic. private BlockingUpdateQueue m_outQ = new BlockingUpdateQueue(); - + private RegionSyncModule m_regionSyncModule = null; + //members for keeping track of state of this connector + private SyncConnectorState m_syncState = SyncConnectorState.Idle; + // unique connector number across all regions private static int m_connectorNum = 0; public int ConnectorNum diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs index 86aa79d7dd..c132f8dc3e 100644 --- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs @@ -127,11 +127,11 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm m_listenerManager = new ListenerManager(maxlisteners, maxhandles); m_scene.EventManager.OnChatFromClient += DeliverClientMessage; m_scene.EventManager.OnChatBroadcast += DeliverClientMessage; - //SYMMETRIC SYNC + //DSG SYNC //m_scene.EventManager.OnChatFromWorld += DeliverClientMessage; //Kitty: temp debug //m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - //end SYMMETRIC SYNC + //end DSG SYNC m_pendingQ = new Queue(); m_pending = Queue.Synchronized(m_pendingQ); } diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index 5eda422b16..fe82487295 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs @@ -252,7 +252,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap SetPartMediaFlags(part, face, me != null); //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List() { SceneObjectPartProperties.MediaUrl, SceneObjectPartProperties.Shape}); + part.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.MediaUrl, SceneObjectPartSyncProperties.Shape}); part.TriggerScriptChangedEvent(Changed.MEDIA); } @@ -459,7 +459,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap // Arguably, we could avoid sending a full update to the avatar that just changed the texture. //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Shape, SceneObjectPartProperties.MediaUrl}); + part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Shape, SceneObjectPartSyncProperties.MediaUrl}); part.TriggerScriptChangedEvent(Changed.MEDIA); @@ -538,7 +538,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap UpdateMediaUrl(part, agentId); //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List(){SceneObjectPartProperties.MediaUrl}); + part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.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 253dbd7649..d389a475ee 100644 --- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs @@ -149,7 +149,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell part.TriggerScriptChangedEvent(Changed.OWNER); group.ResumeScripts(); //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List() { SceneObjectPartProperties.FullUpdate }); //quite some properties changed, let's just force all to be synchronized + part.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.FullUpdate }); //quite some properties changed, let's just force all to be synchronized break; diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index b9a366fd22..b18756647d 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -584,14 +584,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); m_scene.SaveTerrain(); - //SYMMETRIC SYNC + //DSG SYNC //Terrain has been modified, send out sync message if needed //if (m_scene.RegionSyncModule != null) //{ //m_log.DebugFormat("EventManager_OnTerrainTick: To call SendTerrainUpdates with TS {0} and actorID {1}", m_lastUpdateTimeStamp, m_lastUpdateActorID); //m_scene.RegionSyncModule.SendTerrainUpdates(m_lastUpdateTimeStamp, m_lastUpdateActorID); //} - //end of SYMMETRIC SYNC + //end of DSG SYNC // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. //m_scene.CreateTerrainTexture(true); @@ -633,7 +633,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain client.OnUnackedTerrain += client_OnUnackedTerrain; } - //SYMMETRIC SYNC + //DSG SYNC private long m_lastUpdateTimeStamp = DateTime.Now.Ticks; public long LastUpdateTimeStamp { @@ -708,7 +708,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_lastUpdateActorID = lastUpdateActorID; } - //end of SYMMETRIC SYNC + //end of DSG SYNC /// /// Checks to see if the terrain has been modified since last check @@ -717,7 +717,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// private void CheckForTerrainUpdates() { - //SYMMETRIC SYNC + //DSG SYNC m_log.DebugFormat("CheckForTerrainUpdates() called"); //Assumption: Thus function is only called when the terrain is updated by the local actor. // Updating terrain during receiving sync messages from another actor will call CheckForTerrainUpdates. @@ -729,7 +729,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain //Check if the terrain has been modified and send out sync message if modified. CheckForTerrainUpdates(false, currentTimeTick, localActorID); - //end of SYMMETRIC SYNC + //end of DSG SYNC //CheckForTerrainUpdates(false); } @@ -743,9 +743,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// should height map deltas be limited to the estate settings limits /// //private void CheckForTerrainUpdates(bool respectEstateSettings) - //SYMMETRIC SYNC: Change the interface, to input the right sync information for the most recent update + //DSG SYNC: Change the interface, to input the right sync information for the most recent update private void CheckForTerrainUpdates(bool respectEstateSettings, long lastUpdateTimeStamp, string lastUpdateActorID) - //end of SYMMETRIC SYNC + //end of DSG SYNC { bool shouldTaint = false; float[] serialised = m_channel.GetFloatsSerialised(); @@ -774,14 +774,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (shouldTaint) { m_tainted = true; - //SYMMETRIC SYNC + //DSG SYNC //Terrain has been modified, updated the sync info if (m_scene.RegionSyncModule != null) { SyncInfoUpdate(lastUpdateTimeStamp, lastUpdateActorID); m_scene.RegionSyncModule.SendTerrainUpdates(lastUpdateTimeStamp, lastUpdateActorID); } - //end of SYMMETRIC SYNC + //end of DSG SYNC } } @@ -895,9 +895,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel, allowMask, west, south, height, size, seconds); //CheckForTerrainUpdates(!god); //revert changes outside estate limits - //SYMMETRIC SYNC + //DSG SYNC CheckForTerrainUpdates(!god, DateTime.Now.Ticks, m_scene.GetSyncActorID()); - //end of SYMMETRIC SYNC + //end of DSG SYNC } } else @@ -939,9 +939,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_channel, fillArea, size); //CheckForTerrainUpdates(!god); //revert changes outside estate limits - //SYMMETRIC SYNC + //DSG SYNC CheckForTerrainUpdates(!god, DateTime.Now.Ticks, m_scene.GetSyncActorID()); - //end of SYMMETRIC SYNC + //end of DSG SYNC } } else diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs index 891e6761fd..e07b498500 100755 --- a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs @@ -52,31 +52,43 @@ namespace OpenSim.Region.Framework.Interfaces public interface IRegionSyncModule { bool Active { get; } //if true, this RegionSyncModule is connected into the synchronization overlay - string ActorID { get; } - DSGActorTypes DSGActorType { get; set; } + string ActorID { get; } //might be phased out soon + string SyncID { get; } + //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; } + 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); + //Legacy interface, used in Bucket-sync + //void QueueSceneObjectPartForUpdate(SceneObjectPart part); void QueueScenePresenceForTerseUpdate(ScenePresence presence); - //void QueueSceneObjectGroupForUpdate(SceneObjectGroup sog); + //void ProcessAndEnqueuePrimUpdatesBySync(SceneObjectPart part, List updatedProperties); + void ProcessAndEnqueuePrimUpdatesByLocal(SceneObjectPart part, List updatedProperties); + void SyncOutPrimUpdates(); + + //Legacy calls in Bucket sync'ing //The folloiwng calls deal with object updates, and will insert each update into an outgoing queue of each SyncConnector - void SendSceneUpdates(); + //void SendSceneUpdates(); void SendNewObject(SceneObjectGroup sog); void SendDeleteObject(SceneObjectGroup sog, bool softDelete); void SendLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children); void SendDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups); + //New functions for per property sync'ing + void SyncNewObject(SceneObjectGroup sog); + void SyncDeleteObject(SceneObjectGroup sog, bool softDelete); + void SyncLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children); + void SyncDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups); + //In RegionSyncModule's implementation, //The following calls send out a message immediately, w/o putting it in the SyncConnector's outgoing queue. //May need some optimization there on the priorities. @@ -89,6 +101,8 @@ namespace OpenSim.Region.Framework.Interfaces //void QueuePresenceForTerseUpdate(ScenePresence presence) //void SendAvatarUpdates(); + //Debug purpose, mainly for LSL scripts + void Debug(String debugMsg); } /// diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs index e3d8e8c780..252d68d015 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs @@ -65,7 +65,7 @@ namespace OpenSim.Region.Framework.Interfaces void UndoTerrain(ITerrainChannel channel); - //SYMMETRIC SYNC + //DSG SYNC /// /// Invoked by receiving a terrain sync message. First, check if the /// timestamp is more advance than the local copy. If so, update the @@ -96,6 +96,6 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void SetSyncInfo(long lastUpdateTimeStamp, string lastUpdateActorID); - //end of SYMMETRIC SYNC + //end of DSG SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 27c258ba6f..fb3088fc25 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -38,7 +38,7 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.Framework.Scenes { - //SYMMETRIC SYNC: Rename the original EventManager as EventManagerBase, and implement a new EventManager that inherits from EventManagerBase + //DSG SYNC: Rename the original EventManager as EventManagerBase, and implement a new EventManager that inherits from EventManagerBase /// /// A wrapper class to implement handle event differently depending on if they are initiated locally or remotelly (i.e. by another actor) @@ -1113,7 +1113,7 @@ namespace OpenSim.Region.Framework.Scenes } } - //SYMMETRIC SYNC: overridden at new EventManager class + //DSG SYNC: overridden at new EventManager class //public void TriggerObjectGrab(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) public virtual void TriggerObjectGrab(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) { @@ -1136,7 +1136,7 @@ namespace OpenSim.Region.Framework.Scenes } } - //SYMMETRIC SYNC: overridden at new EventManager class + //DSG SYNC: overridden at new EventManager class //public void TriggerObjectGrabbing(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) public virtual void TriggerObjectGrabbing(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) { @@ -1159,7 +1159,7 @@ namespace OpenSim.Region.Framework.Scenes } } - //SYMMETRIC SYNC: overridden at new EventManager class + //DSG SYNC: overridden at new EventManager class //public void TriggerObjectDeGrab(uint localID, uint originalID, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) public virtual void TriggerObjectDeGrab(uint localID, uint originalID, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs) { @@ -1851,7 +1851,7 @@ namespace OpenSim.Region.Framework.Scenes } } - //SYMMETRIC SYNC: the function is overridden in new EventManager + //DSG SYNC: the function is overridden in new EventManager //public void TriggerOnChatFromWorld(Object sender, OSChatMessage chat) public virtual void TriggerOnChatFromWorld(Object sender, OSChatMessage chat) { @@ -1874,7 +1874,7 @@ namespace OpenSim.Region.Framework.Scenes } } - //SYMMETRIC SYNC: overiding this in the inherited class + //DSG SYNC: overiding this in the inherited class //public void TriggerOnChatFromClient(Object sender, OSChatMessage chat) public virtual void TriggerOnChatFromClient(Object sender, OSChatMessage chat) { @@ -2550,7 +2550,7 @@ namespace OpenSim.Region.Framework.Scenes } #endregion - //SYMMETRIC SYNC + //DSG SYNC public event PostSceneCreation OnPostSceneCreation; public delegate void PostSceneCreation(Scene createdScene); public void TriggerOnPostSceneCreation(Scene createdScene) @@ -2619,6 +2619,6 @@ namespace OpenSim.Region.Framework.Scenes } } } - //end of SYMMETRIC SYNC + //end of DSG SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index f1ff5bc21e..28c9abfdf4 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -251,7 +251,7 @@ namespace OpenSim.Region.Framework.Scenes AssetService.Store(asset); //REGION SYNC: if RegionSyncEnabled, move script related operations to be after update inventory item - //SYMMETRIC SYNC: commenting out old REGION SYNC code, the RemoveScriptInstance would be handled by ScriptEngineSyncModule + //DSG SYNC: commenting out old REGION SYNC code, the RemoveScriptInstance would be handled by ScriptEngineSyncModule /* if (!RegionSyncEnabled) { @@ -270,7 +270,7 @@ namespace OpenSim.Region.Framework.Scenes part.GetProperties(remoteClient); ////REGION SYNC - //SYMMETRIC SYNC: commenting out old REGION SYNC code, the RemoveScriptInstance would be handled by ScriptEngineSyncModule + //DSG SYNC: commenting out old REGION SYNC code, the RemoveScriptInstance would be handled by ScriptEngineSyncModule /* if (!RegionSyncEnabled) { @@ -309,7 +309,7 @@ namespace OpenSim.Region.Framework.Scenes } * */ - //SYMMETRIC SYNC: Distributed Scene Graph implementation + //DSG SYNC: Distributed Scene Graph implementation m_log.Debug("Scene.Inventory: to call EventManager.TriggerUpdateScript, agentID: " + remoteClient.AgentId); //Trigger OnUpdateScript event. EventManager.TriggerUpdateScript(remoteClient.AgentId, itemId, primId, isScriptRunning, item.AssetID); @@ -370,7 +370,7 @@ namespace OpenSim.Region.Framework.Scenes } #endregion - #region SYMMETRIC SYNC + #region DSG SYNC public void SymSync_OnNewScript(UUID avatarID, UUID itemID, SceneObjectPart part) { TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID); @@ -433,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes return errors; } - #endregion //SYMMETRIC SYNC + #endregion //DSG SYNC /// @@ -1714,7 +1714,7 @@ namespace OpenSim.Region.Framework.Scenes part.ParentGroup.AddInventoryItem(remoteClient, localID, item, copyID); part.GetProperties(remoteClient); - //SYMMETRIC SYNC + //DSG SYNC /* Original OpenSim code, commented out // TODO: switch to posting on_rez here when scripts // have state in inventory @@ -1741,7 +1741,7 @@ namespace OpenSim.Region.Framework.Scenes //part.GetProperties(remoteClient); part.ParentGroup.ResumeScripts(); } - //end of SYMMETRIC SYNC + //end of DSG SYNC } else @@ -1801,7 +1801,7 @@ namespace OpenSim.Region.Framework.Scenes part.Inventory.AddInventoryItem(taskItem, false); part.GetProperties(remoteClient); - //SYMMETRIC SYNC + //DSG SYNC //part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0); //part.ParentGroup.ResumeScripts(); if (RegionSyncModule != null) @@ -1819,7 +1819,7 @@ namespace OpenSim.Region.Framework.Scenes //part.GetProperties(remoteClient); part.ParentGroup.ResumeScripts(); } - //end of SYMMETRIC SYNC + //end of DSG SYNC } } @@ -2256,7 +2256,7 @@ namespace OpenSim.Region.Framework.Scenes group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); //group.ScheduleGroupForFullUpdate(); - group.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.FullUpdate}); //new object, all properties have new value + group.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.FullUpdate}); //new object, all properties have new value return group; } @@ -2322,7 +2322,7 @@ namespace OpenSim.Region.Framework.Scenes sog.SetOwnerId(ownerID); sog.SetGroup(groupID, remoteClient); //sog.ScheduleGroupForFullUpdate(); - sog.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.OwnerID, SceneObjectPartProperties.GroupID}); + sog.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.OwnerID, SceneObjectPartSyncProperties.GroupID}); SceneObjectPart[] partList = sog.Parts; @@ -2386,6 +2386,9 @@ namespace OpenSim.Region.Framework.Scenes List children = new List(); SceneObjectPart root = GetSceneObjectPart(parentPrimId); + //DSG DEBUG + m_log.Debug("Scene.LinkObjects -- ROOT: " + root.DebugObjectPartProperties()); + if (root == null) { m_log.DebugFormat("[LINK]: Can't find linkset root prim {0}", parentPrimId); @@ -2405,6 +2408,9 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) continue; + //DSG DEBUG + m_log.Debug("Scene.LinkObjects -- child to link: " + part.DebugObjectPartProperties()); + if (!owners.Contains(part.OwnerID)) owners.Add(part.OwnerID); diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 22636b1b1d..f1de066c90 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -213,7 +213,7 @@ namespace OpenSim.Region.Framework.Scenes isAttachment = true; else //part.ParentGroup.ScheduleGroupForFullUpdate(); - part.ParentGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.IsSelected}); + part.ParentGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.FullUpdate}); // 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 9824a5eede..5fc58222a7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -634,9 +634,9 @@ namespace OpenSim.Region.Framework.Scenes #endregion - #region SYMMETRIC SYNC + #region DSG SYNC /////////////////////////////////////////////////////////////////////////////////////////////// - //KittyL: 12/23/2010. SYMMETRIC SYNC: Implementation for the symmetric synchronization model. + //KittyL: 12/23/2010. DSG SYNC: Implementation for the symmetric synchronization model. /////////////////////////////////////////////////////////////////////////////////////////////// private IRegionSyncModule m_regionSyncModule = null; @@ -709,9 +709,6 @@ namespace OpenSim.Region.Framework.Scenes //Similar to DeleteSceneObject, except that this does not change LastUpdateActorID and LastUpdateTimeStamp public void DeleteSceneObjectBySynchronization(SceneObjectGroup group) { - // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); - - //SceneObjectPart rootPart = group.GetChildPart(group.UUID); // Serialise calls to RemoveScriptInstances to avoid // deadlocking on m_parts inside SceneObjectGroup @@ -794,7 +791,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void LinkObjectBySync(SceneObjectGroup linkedGroup, UUID rootID, List childrenIDs) { - //m_log.Debug("Start to LinkObjectBySync"); + m_log.Debug("Start to LinkObjectBySync"); //DebugSceneObjectGroups(); List children = new List(); @@ -816,13 +813,17 @@ namespace OpenSim.Region.Framework.Scenes continue; } - //m_log.Debug("to link part " + part.DebugObjectPartProperties()); + //TEMP DEBUG + /* + m_log.Debug("to link part " + part.DebugObjectPartProperties()); + string partNames = ""; foreach (SceneObjectPart child in part.ParentGroup.Parts) { partNames += "(" + child.Name + "," + child.UUID + ")"; } //m_log.Debug("LinkObjectBySync: " + part.Name + "," + part.UUID + " with root "+root.Name+","+root.UUID+"; its SOG has " + part.ParentGroup.Parts.Length + " parts : "+partNames); + * */ children.Add(part); } @@ -830,17 +831,15 @@ namespace OpenSim.Region.Framework.Scenes //m_log.Debug("to link " + children.Count + " parts with " + root.Name); //Leverage the LinkObject implementation to get the book keeping of Group and Parts relations right - m_sceneGraph.LinkObjectsBySync(root, children); + m_sceneGraph.LinkObjectsBySync(root, children); - //The properties of the newly linked object should be updated later with another UpdatedObject message. - + //KittyL 04/19/2011: no longer update properties here, caller will do it //Set the property values as in the incoming copy of the object group + //SceneObjectGroup localGroup = root.ParentGroup; + //localGroup.UpdateObjectGroupBySync(linkedGroup); - SceneObjectGroup localGroup = root.ParentGroup; - localGroup.UpdateObjectGroupBySync(linkedGroup); - - //debug + //DSG DEBUG /* m_log.Debug("after SceneGraph.LinkObjectsBySync, the newly linked group is \n" + root.ParentGroup.DebugObjectUpdateResult()); m_log.Debug("parts before linking now have properties: "); @@ -848,9 +847,18 @@ namespace OpenSim.Region.Framework.Scenes { m_log.Debug(part.DebugObjectPartProperties()); } - * */ + * */ + } + /// + /// Delink objects after receiving DelinkObject sync message. + /// Assumption: the actor whichever initiates the DelinkObject + /// operation has already done premission checking. + /// + /// + /// + /// public void DelinkObjectsBySync(List delinkPrimIDs, List beforeDelinkGroupIDs, List incomingAfterDelinkGroups) { m_sceneGraph.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups); @@ -863,7 +871,18 @@ namespace OpenSim.Region.Framework.Scenes return m_sceneGraph.UpdateObjectPartBucketProperties(bucketName, partUUID, updatePart, bucketSyncInfo); } - #endregion //SYMMETRIC SYNC + public bool AddNewSceneObjectByDelink(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) + { + if (m_sceneGraph.AddNewSceneObjectByDelink(sceneObject, attachToBackup, sendClientUpdates)) + { + EventManager.TriggerObjectAddedToScene(sceneObject); + return true; + } + + return false; + } + + #endregion //DSG SYNC public ICapabilitiesModule CapsModule { @@ -1006,10 +1025,10 @@ namespace OpenSim.Region.Framework.Scenes m_physicalPrim = physicalPrim; m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor; - //SYMMETRIC SYNC: pass Scene reference to EventManager + //DSG SYNC: pass Scene reference to EventManager //m_eventManager = new EventManager(); m_eventManager = new EventManager(this); - //end of SYMMETRIC SYNC + //end of DSG SYNC m_permissions = new ScenePermissions(this); m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this); @@ -1215,10 +1234,10 @@ namespace OpenSim.Region.Framework.Scenes m_regInfo = regInfo; - //SYMMETRIC SYNC: pass Scene reference to EventManager + //DSG SYNC: pass Scene reference to EventManager //m_eventManager = new EventManager(); m_eventManager = new EventManager(this); - //end of SYMMETRIC SYNC + //end of DSG SYNC m_lastUpdate = Util.EnvironmentTickCount(); } @@ -1553,13 +1572,13 @@ namespace OpenSim.Region.Framework.Scenes PhysEngineToSceneConnectorModule = RequestModuleInterface(); SceneToPhysEngineSyncServer = RequestModuleInterface(); ////////////////////////////////////////////////////////////////////// - //SYMMETRIC SYNC (KittyL: started 12/23/2010) + //DSG SYNC (KittyL: started 12/23/2010) ////////////////////////////////////////////////////////////////////// m_regionSyncModule = RequestModuleInterface(); m_DSGActorSyncModule = RequestModuleInterface(); ////////////////////////////////////////////////////////////////////// - //end of SYMMETRIC SYNC + //end of DSG SYNC ////////////////////////////////////////////////////////////////////// // Shoving this in here for now, because we have the needed @@ -1739,14 +1758,15 @@ namespace OpenSim.Region.Framework.Scenes m_regionSyncServerModule.SendUpdates(); } - //SYMMETRIC SYNC + //DSG SYNC //NOTE: If it is configured as symmetric sync in opensim.ini, the above IsSyncedServer() or IsSyncedClient() should all return false if (RegionSyncModule != null) { - RegionSyncModule.SendSceneUpdates(); + //RegionSyncModule.SendSceneUpdates(); + RegionSyncModule.SyncOutPrimUpdates(); } - //end of SYMMETRIC SYNC + //end of DSG SYNC int tmpPhysicsMS2 = Util.EnvironmentTickCount(); if ((Frame % m_update_physics == 0) && m_physics_enabled && (IsSyncedServer() || IsPhysEngineActor())) @@ -2403,7 +2423,7 @@ namespace OpenSim.Region.Framework.Scenes } //sceneObject.ScheduleGroupForFullUpdate(); - sceneObject.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.FullUpdate}); //new object, all properties have new value + sceneObject.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.FullUpdate}); //new object, all properties have new value return sceneObject; } @@ -2580,16 +2600,18 @@ namespace OpenSim.Region.Framework.Scenes EventManager.TriggerParcelPrimCountTainted(); } - group.DeleteGroupFromScene(silent); - -// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); - + //DSG SYNC //Propagate the RemovedObject message if (RegionSyncModule != null) { - RegionSyncModule.SendDeleteObject(group, false); + //RegionSyncModule.SendDeleteObject(group, false); + RegionSyncModule.SyncDeleteObject(group, false); } - //end of SYMMETRIC SYNC + //end of DSG SYNC + + group.DeleteGroupFromScene(silent); + +// m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); } @@ -3210,7 +3232,7 @@ namespace OpenSim.Region.Framework.Scenes client.OnUpdatePrimFlags += m_sceneGraph.UpdatePrimFlags; client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily; client.OnObjectPermissions += HandleObjectPermissionsUpdate; - //SYMMETRIC SYNC: return the code back to its original OpenSim version + //DSG SYNC: return the code back to its original OpenSim version //if (IsSyncedServer()) //{ client.OnGrabObject += ProcessObjectGrab; @@ -3710,7 +3732,7 @@ namespace OpenSim.Region.Framework.Scenes ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); }); - //SYMMETRIC SYNC: object remove should be handled through RegionSyncModule + //DSG SYNC: object remove should be handled through RegionSyncModule // REGION SYNC /* if( IsSyncedServer() ) @@ -4532,7 +4554,7 @@ namespace OpenSim.Region.Framework.Scenes if (ent is SceneObjectGroup) { //((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(); - ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.None}); //This is not due to property being updated, hence passing "None" property. + ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.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 d060e6b3c8..70a63b9f19 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -47,9 +47,9 @@ namespace OpenSim.Region.Framework.Scenes public delegate void ObjectDeleteDelegate(EntityBase obj); - //SYMMETRIC SYNC + //DSG SYNC public delegate void ObjectCreateBySyncDelegate(EntityBase obj); - //end of SYMMETRIC SYNC + //end of DSG SYNC /// @@ -69,9 +69,9 @@ namespace OpenSim.Region.Framework.Scenes public event ObjectCreateDelegate OnObjectCreate; public event ObjectDeleteDelegate OnObjectRemove; - //SYMMETRIC SYNC + //DSG SYNC public event ObjectCreateBySyncDelegate OnObjectCreateBySync; - //end of SYMMETRIC SYNC + //end of DSG SYNC #endregion @@ -288,7 +288,7 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.HasGroupChanged = true; } - return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); + return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates, false); } /// @@ -310,7 +310,7 @@ namespace OpenSim.Region.Framework.Scenes if (attachToBackup) sceneObject.HasGroupChanged = true; - return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); + return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates, false); } /// @@ -344,7 +344,7 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.Velocity = vel; } - //SYMMETRIC SYNC + //DSG SYNC //Moving AddNewSceneObject to the end of this function, so that //all object properties are set when AddNewSceneObject is called. AddNewSceneObject(sceneObject, true, false); @@ -368,17 +368,17 @@ namespace OpenSim.Region.Framework.Scenes /// /// true if the object was added, false if an object with the same uuid was already in the scene /// - protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) + protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates, bool addedByDelink) { if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero) return false; if (Entities.ContainsKey(sceneObject.UUID)) return false; - -// m_log.DebugFormat( -// "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}", -// sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName); + + // m_log.DebugFormat( + // "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}", + // sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName); SceneObjectPart[] children = sceneObject.Parts; @@ -403,18 +403,18 @@ namespace OpenSim.Region.Framework.Scenes m_numPrim += children.Length; sceneObject.AttachToScene(m_parentScene); - + Entities.Add(sceneObject); if (attachToBackup) sceneObject.AttachToBackup(); - + if (OnObjectCreate != null) OnObjectCreate(sceneObject); lock (SceneObjectGroupsByFullID) SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; - + lock (SceneObjectGroupsByFullPartID) { SceneObjectGroupsByFullPartID[sceneObject.UUID] = sceneObject; @@ -429,15 +429,15 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; } - //SYMMETRIC SYNC: sending NewObject event, and sending it before calling ScheduleGroupForFullUpdate - if (m_parentScene.RegionSyncModule != null) - { - m_parentScene.RegionSyncModule.SendNewObject(sceneObject); - } - if (sendClientUpdates) //sceneObject.ScheduleGroupForFullUpdate(); - sceneObject.ScheduleGroupForFullUpdate(new List() { SceneObjectPartProperties.None }); + sceneObject.ScheduleGroupForFullUpdate(null); + + //DSG SYNC: sending NewObject event, and sending it before calling ScheduleGroupForFullUpdate + if (m_parentScene.RegionSyncModule != null && !addedByDelink) + { + m_parentScene.RegionSyncModule.SyncNewObject(sceneObject); + } return true; } @@ -1637,21 +1637,21 @@ namespace OpenSim.Region.Framework.Scenes parentGroup.TriggerScriptChangedEvent(Changed.LINK); parentGroup.HasGroupChanged = true; - //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. + //DSG SYNC + //Send out LinkObject sync messages. if (m_parentScene.RegionSyncModule != null) { //Tell other actors to link the SceneObjectParts together as a new group. - m_parentScene.RegionSyncModule.SendLinkObject(parentGroup, root, children); + //m_parentScene.RegionSyncModule.SendLinkObject(parentGroup, root, children); + m_parentScene.RegionSyncModule.SyncLinkObject(parentGroup, root, children); } //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 //via the LinkObject message sent above. - parentGroup.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + parentGroup.ScheduleGroupForFullUpdate(null); - //end of SYMMETRIC SYNC + //end of DSG SYNC } finally @@ -1673,7 +1673,7 @@ namespace OpenSim.Region.Framework.Scenes List rootParts = new List(); List affectedGroups = new List(); - //SYMMETRIC SYNC, record the new object groups after the delink operation + //DSG SYNC, record the new object groups after the delink operation List beforeDelinkGroups = new List(); List afterDelinkGroups = new List(); @@ -1694,7 +1694,7 @@ namespace OpenSim.Region.Framework.Scenes if (!affectedGroups.Contains(group)) { affectedGroups.Add(group); - //SYMMETRIC SYNC + //DSG SYNC beforeDelinkGroups.Add(group); } } @@ -1711,7 +1711,7 @@ namespace OpenSim.Region.Framework.Scenes // handled further. Do the honors here. child.ParentGroup.HasGroupChanged = true; - //SYMMETRIC SYNC, delay ScheduleGroupForFullUpdate till the end of the delink operations. + //DSG SYNC, delay ScheduleGroupForFullUpdate till the end of the delink operations. //child.ParentGroup.ScheduleGroupForFullUpdate(); afterDelinkGroups.Add(child.ParentGroup); } @@ -1783,24 +1783,24 @@ namespace OpenSim.Region.Framework.Scenes g.TriggerScriptChangedEvent(Changed.LINK); g.HasGroupChanged = true; // Persist - //SYMMETRIC SYNC, delay ScheduleGroupForFullUpdate till the end of the delink operations. + //DSG SYNC, delay ScheduleGroupForFullUpdate till the end of the delink operations. //g.ScheduleGroupForFullUpdate(); afterDelinkGroups.Add(g); } - //SYMMETRIC SYNC + //DSG SYNC //Send out DelinkObject message to other actors to sychronize their object list if (m_parentScene.RegionSyncModule != null) { - m_parentScene.RegionSyncModule.SendDeLinkObject(prims, beforeDelinkGroups, afterDelinkGroups); + m_parentScene.RegionSyncModule.SyncDeLinkObject(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 + //Schedule updates as in legacy OpenSim code, to send updates + //to viewers connected to this actor (at least needed for client managers). foreach (SceneObjectGroup sog in afterDelinkGroups) { - sog.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + sog.ScheduleGroupForFullUpdate(null); } - //end of SYMMETRIC SYNC + //end of DSG SYNC } finally { @@ -1961,7 +1961,7 @@ namespace OpenSim.Region.Framework.Scenes copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1); copy.HasGroupChanged = true; //copy.ScheduleGroupForFullUpdate(); - copy.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.FullUpdate}); //new object, all property values are new + copy.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.FullUpdate}); //new object, all property values are new copy.ResumeScripts(); // required for physics to update it's position @@ -2059,7 +2059,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion // REGION SYNC - #region SYMMETRIC SYNC + #region DSG SYNC public Scene.ObjectUpdateResult UpdateObjectBySynchronization(SceneObjectGroup updatedSog) { @@ -2175,9 +2175,13 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.RootPart.SetParentLocalId(avatar.LocalId); } - //SYMMETRIC SYNC, - sceneObject.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); - //end of SYMMETRIC SYNC, + //DSG SYNC, + sceneObject.HasGroupChanged = true; + //NewObject is sent via a specific sync message, not through updates; + //hence not passing any property list here in calling + //ScheduleGroupForFullUpdate(). + sceneObject.ScheduleGroupForFullUpdate(null); + //end of DSG SYNC, Entities.Add(sceneObject); @@ -2248,7 +2252,7 @@ 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 - //SYMMETRIC SYNC: need to copy value w/o trigger UpdateBucketSyncInfo + //DSG SYNC: need to copy value w/o trigger UpdateBucketSyncInfo //child.RootPart.ObjectSaleType = 0; //child.RootPart.SalePrice = 10; //child.RootPart.SetObjectSaleType(0); @@ -2285,7 +2289,7 @@ namespace OpenSim.Region.Framework.Scenes parentGroup.TriggerScriptChangedEvent(Changed.LINK); parentGroup.HasGroupChanged = true; //Do not change the timestamp and actorID values - parentGroup.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + parentGroup.ScheduleGroupForFullUpdate(null); } finally @@ -2304,6 +2308,7 @@ namespace OpenSim.Region.Framework.Scenes public void DelinkObjectsBySync(List delinkPrimIDs, List beforeDelinkGroupIDs, List incomingAfterDelinkGroups) { Dictionary localBeforeDelinkGroups = new Dictionary(); + List localAfterDelinkGroups = new List(); Dictionary delinkPrims = new Dictionary(); bool beforeStateConsistent = true; bool afterStateConsistent = true; @@ -2385,9 +2390,8 @@ namespace OpenSim.Region.Framework.Scenes m_log.Warn("DelinkObjectsBySync: before-delink state not consistent in local copy and the incoming copy. Return without further operations."); }else{ //Next, apply the delink operation locally. - List localAfterDelinkGroups = DelinkObjectsBySync(new List(delinkPrims.Values)); + localAfterDelinkGroups = DelinkObjectsBySync(new List(delinkPrims.Values)); - //Check if local after-state agrees with that in the remote copy, and update the groups' properties if (localAfterDelinkGroups.Count != incomingAfterDelinkGroups.Count) { @@ -2409,11 +2413,17 @@ namespace OpenSim.Region.Framework.Scenes } else { - localAfterGroup.UpdateObjectGroupBySync(incomingAfterDelinkGroupsDictionary[localAfterGroup.UUID]); + //No longer calling update prim's properties here, caller will do that + //localAfterGroup.UpdateObjectGroupBySync(incomingAfterDelinkGroupsDictionary[localAfterGroup.UUID]); } } } } + + foreach (SceneObjectGroup sog in localAfterDelinkGroups) + { + sog.ScheduleGroupForFullUpdate(null); + } } finally { @@ -2425,7 +2435,7 @@ namespace OpenSim.Region.Framework.Scenes } } - //Similar to DelinkObjects(), w/o triggering any ScheduleFullUpdate(), + //Similar to DelinkObjects(), but calling DelinkFromGroupBySync instead private List DelinkObjectsBySync(List prims) { //!!!Caller of this function should already lock on m_updateLock, so no locking here !!! @@ -2553,6 +2563,17 @@ namespace OpenSim.Region.Framework.Scenes return localPart.UpdateBucketProperties(bucketName, updatedPart, bucketSyncInfo); } - #endregion //SYMMETRIC SYNC + protected internal bool AddNewSceneObjectByDelink(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) + { + // Ensure that we persist this new scene object if it's not an + // attachment + if (attachToBackup) + sceneObject.HasGroupChanged = true; + + bool addedByDelink = true; + return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates, addedByDelink); + } + + #endregion //DSG SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 0e0f90d360..df462aac7c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -509,7 +509,7 @@ namespace OpenSim.Region.Framework.Scenes #region Constructors - //SYMMETRIC SYNC + //DSG SYNC public SceneObjectGroup(SceneObjectPart part, bool newGroupBySync) { if (!newGroupBySync) @@ -638,7 +638,7 @@ namespace OpenSim.Region.Framework.Scenes // for the same object with very different properties. The caller must schedule the update. //ScheduleGroupForFullUpdate(); - //SYMMETRIC SYNC + //DSG SYNC if (m_scene.RegionSyncModule != null) { foreach (SceneObjectPart part in Parts) @@ -1028,7 +1028,7 @@ namespace OpenSim.Region.Framework.Scenes AttachToBackup(); m_scene.EventManager.TriggerParcelPrimCountTainted(); //m_rootPart.ScheduleFullUpdate(); - m_rootPart.ScheduleFullUpdate(new List() { SceneObjectPartProperties.GroupPosition, SceneObjectPartProperties.AttachmentPoint}); //Physics properties, such as Position, OffsetPosition, etc, should be tainted in ApplyPhysics() + m_rootPart.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.GroupPosition, SceneObjectPartSyncProperties.AttachmentPoint}); //Physics properties, such as Position, OffsetPosition, etc, should be tainted in ApplyPhysics() m_rootPart.ClearUndoState(); } @@ -1223,7 +1223,7 @@ namespace OpenSim.Region.Framework.Scenes { SceneObjectPart part = parts[i]; - //SYMMETRIC SYNC: object remove should be handled through RegionSyncModule + //DSG SYNC: object remove should be handled through RegionSyncModule /* // REGION SYNC if (Scene.IsSyncedServer()) @@ -1232,7 +1232,7 @@ namespace OpenSim.Region.Framework.Scenes //return; } * */ - //end of SYMMETRIC SYNC + //end of DSG SYNC Scene.ForEachScenePresence(delegate(ScenePresence avatar) { @@ -1302,7 +1302,7 @@ namespace OpenSim.Region.Framework.Scenes } //ScheduleGroupForFullUpdate(); - ScheduleGroupForFullUpdate(new List(){ SceneObjectPartProperties.Flags}); //do we also need to synchronize SOG properties such as m_scriptListens_atRotTarget? (does any acotr other than script engine care about it?) + ScheduleGroupForFullUpdate(new List(){ SceneObjectPartSyncProperties.Flags, SceneObjectPartSyncProperties.AggregateScriptEvents}); //do we also need to synchronize SOG properties such as m_scriptListens_atRotTarget? (does any acotr other than script engine care about it?) } public void SetText(string text, Vector3 color, double alpha) @@ -1315,7 +1315,7 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; //m_rootPart.ScheduleFullUpdate(); - m_rootPart.ScheduleFullUpdate(new List() {SceneObjectPartProperties.Text, SceneObjectPartProperties.Color}); + m_rootPart.ScheduleFullUpdate(new List() {SceneObjectPartSyncProperties.Text, SceneObjectPartSyncProperties.Color}); } /// @@ -1377,13 +1377,13 @@ namespace OpenSim.Region.Framework.Scenes return; } - //SYMMETRIC SYNC + //DSG SYNC //if we are doing sync across different sync nodes, and are not told to persist the state, don't do anything (only persistence actor will do it) if (m_scene.RegionSyncModule != null && !ToPersistObjectState) { return; } - //end of SYMMETRIC SYNC + //end of DSG SYNC // Since this is the top of the section of call stack for backing up a particular scene object, don't let // any exception propogate upwards. @@ -1560,7 +1560,7 @@ namespace OpenSim.Region.Framework.Scenes dupe.AttachToBackup(); //ScheduleGroupForFullUpdate(); - ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.FullUpdate}); + ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.FullUpdate}); } return dupe; @@ -1814,7 +1814,7 @@ namespace OpenSim.Region.Framework.Scenes } //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List() {SceneObjectPartProperties.OwnerID, SceneObjectPartProperties.GroupID, SceneObjectPartProperties.LastOwnerID}); + part.ScheduleFullUpdate(new List() {SceneObjectPartSyncProperties.OwnerID, SceneObjectPartSyncProperties.GroupID, SceneObjectPartSyncProperties.LastOwnerID}); } /// @@ -1942,7 +1942,7 @@ namespace OpenSim.Region.Framework.Scenes /// Schedule a full update for this scene object /// //public void ScheduleGroupForFullUpdate() - public void ScheduleGroupForFullUpdate(List updatedProperties) + public void ScheduleGroupForFullUpdate(List updatedProperties) { // if (IsAttachment) // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); @@ -1951,13 +1951,29 @@ namespace OpenSim.Region.Framework.Scenes //RootPart.ScheduleFullUpdate(); RootPart.ScheduleFullUpdate(updatedProperties); + //For group properties, we only need to send it once per SOG, + //hence remove them from the updatedProperties for other parts + List otherPartsUpdatedProperties = updatedProperties; + if (updatedProperties!=null) + { + HashSet hashedList = new HashSet(updatedProperties); + foreach (SceneObjectPartSyncProperties groupProperty in SceneObjectPart.GetGroupProperties()) + { + if (updatedProperties.Contains(groupProperty)) + { + hashedList.Remove(groupProperty); + } + } + otherPartsUpdatedProperties = new List(hashedList); + } + SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) { SceneObjectPart part = parts[i]; if (part != RootPart) //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(updatedProperties); + part.ScheduleFullUpdate(otherPartsUpdatedProperties); } } @@ -1965,7 +1981,7 @@ namespace OpenSim.Region.Framework.Scenes /// Schedule a terse update for this scene object /// //public void ScheduleGroupForTerseUpdate() - public void ScheduleGroupForTerseUpdate(List updatedProperties) + public void ScheduleGroupForTerseUpdate(List updatedProperties) { // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); @@ -2215,11 +2231,11 @@ namespace OpenSim.Region.Framework.Scenes //HasGroupChanged = true; //ScheduleGroupForFullUpdate(); - //SYMMETRIC SYNC + //DSG SYNC //The DeleteObject message will be enqueued to be sent out by another thread, and the call will return quickly. //if (m_scene.RegionSyncModule != null) // m_scene.RegionSyncModule.SendDeleteObject(objectGroup, true); - //end of SYMMETRIC SYNC + //end of DSG SYNC } @@ -2322,7 +2338,11 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); - m_scene.AddNewSceneObject(objectGroup, true); + //m_scene.AddNewSceneObject(objectGroup, true); + //DSG SYNC: calling AddNewSceneObjectByDelink, so that later on we know + //the "new" object is added by delink operation, no need to send sync + //message of NewObject + m_scene.AddNewSceneObjectByDelink(objectGroup, true, true); if (sendEvents) linkPart.TriggerScriptChangedEvent(Changed.LINK); @@ -2731,7 +2751,7 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; part.TriggerScriptChangedEvent(Changed.SCALE); //ScheduleGroupForFullUpdate(); - ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.None}); //above actions only update Scale for the given part, and part.Resize() will taint Scale as updated + ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.None}); //above actions only update Scale for the given part, and part.Resize() will taint Scale as updated //if (part.UUID == m_rootPart.UUID) //{ @@ -2884,7 +2904,7 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); //ScheduleGroupForTerseUpdate(); - ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.Scale}); + ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.Scale}); } } @@ -2926,10 +2946,10 @@ 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(); - List updatedProperties = new List() { SceneObjectPartProperties.GroupPosition }; + List updatedProperties = new List() { SceneObjectPartSyncProperties.GroupPosition }; if (IsAttachment) { - updatedProperties.Add(SceneObjectPartProperties.AttachedPos); + updatedProperties.Add(SceneObjectPartSyncProperties.AttachedPos); } ScheduleGroupForTerseUpdate(updatedProperties); } @@ -2995,7 +3015,7 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; //ScheduleGroupForTerseUpdate(); - ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.Position, SceneObjectPartProperties.OffsetPosition}); + ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.Position, SceneObjectPartSyncProperties.OffsetPosition}); } public void OffsetForNewRegion(Vector3 offset) @@ -3028,7 +3048,7 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; //ScheduleGroupForTerseUpdate(); - ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.Orientation}); //Above actions only update m_rootPart's RotationOffset, and m_rootPart.UpdateRotation will taint RotationOffset as updated + ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.Orientation}); //Above actions only update m_rootPart's RotationOffset, and m_rootPart.UpdateRotation will taint RotationOffset as updated } /// @@ -3055,7 +3075,7 @@ namespace OpenSim.Region.Framework.Scenes HasGroupChanged = true; //ScheduleGroupForTerseUpdate(); - ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.Position, SceneObjectPartProperties.Orientation}); //RotationOffset is only updated for m_rootPart, and m_rootPart.UpdateRotation should already taint RotationOffset as updated + ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.Position, SceneObjectPartSyncProperties.Orientation}); //RotationOffset is only updated for m_rootPart, and m_rootPart.UpdateRotation should already taint RotationOffset as updated } /// @@ -3143,7 +3163,7 @@ namespace OpenSim.Region.Framework.Scenes newRot *= Quaternion.Inverse(axRot); prim.RotationOffset = newRot; //prim.ScheduleTerseUpdate(); - prim.ScheduleTerseUpdate(new List(){ SceneObjectPartProperties.RotationOffset, SceneObjectPartProperties.OffsetPosition}); + prim.ScheduleTerseUpdate(new List(){ SceneObjectPartSyncProperties.RotationOffset, SceneObjectPartSyncProperties.OffsetPosition}); } } @@ -3158,7 +3178,7 @@ namespace OpenSim.Region.Framework.Scenes } //m_rootPart.ScheduleTerseUpdate(); - m_rootPart.ScheduleTerseUpdate(new List(){SceneObjectPartProperties.RotationOffset}); + m_rootPart.ScheduleTerseUpdate(new List(){SceneObjectPartSyncProperties.RotationOffset}); } #endregion @@ -3571,7 +3591,7 @@ namespace OpenSim.Region.Framework.Scenes } #endregion - #region SYMMETRIC SYNC + #region DSG SYNC private bool m_toPersistObjectState = false; public bool ToPersistObjectState @@ -3794,14 +3814,11 @@ namespace OpenSim.Region.Framework.Scenes } //Similar actions with DelinkFromGroup, except that m_scene.AddNewSceneObjectBySync is called - //!!!!!!!!!!!!!!!!!!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}, {4} from group with root part {2}, {3}", + delinkPart.Name, delinkPart.UUID, RootPart.Name, RootPart.UUID, delinkPart.LocalId); SceneObjectPartBase linkPart = (SceneObjectPartBase)delinkPart; linkPart.ClearUndoState(); @@ -3818,9 +3835,7 @@ namespace OpenSim.Region.Framework.Scenes if (parts.Length == 1 && RootPart != null) { // Single prim left - //RootPart.LinkNum = 0; - //RootPart.SetProperty("LinkNum", 0); - ((SceneObjectPartBase)RootPart).LinkNum = 0; + RootPart.LinkNum = 0; } else { @@ -3830,16 +3845,13 @@ namespace OpenSim.Region.Framework.Scenes if (part.LinkNum > linkPart.LinkNum) { part.LinkNum--; - //int linkNum = part.LinkNum - 1; - //part.SetProperty("LinkNum", linkNum); } } } } - 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.ParentID = 0; //ParentID is a value set only locally and ignored in synchronization, so no need to set its value linkPart.LinkNum = 0; - //linkPart.SetParentID(0); if (linkPart.PhysActor != null) { @@ -3858,15 +3870,6 @@ namespace OpenSim.Region.Framework.Scenes linkPart.OffsetPosition = new Vector3(0, 0, 0); linkPart.RotationOffset = worldRot; - //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); @@ -4152,6 +4155,91 @@ namespace OpenSim.Region.Framework.Scenes } + /////////////////////////////////////////////////////////////////////// + // Per SOP property based sync + /////////////////////////////////////////////////////////////////////// + + /// + /// Update the existing copy of the object with updated properties in 'updatedSog'. + /// + /// + /// + public Scene.ObjectUpdateResult UpdateSOGBySync(SceneObjectGroup updatedSog) + { + //This GroupID check should be done by the actor who initiates the object update + //if (!this.GroupID.Equals(updatedSog.GroupID)) + // return Scene.ObjectUpdateResult.Error; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + //NOTE!!! + //We do not want to simply call SceneObjectGroup.Copy here to clone the object: + //the prims (SceneObjectParts) in updatedSog are different instances than those in the local copy, + //and we want to preserve the references to the prims in this local copy, especially for scripts + //of each prim, where the scripts have references to the local copy. If the local copy is replaced, + //the prims (parts) will be replaces and we need to update all the references that were pointing to + //the previous prims. + //////////////////////////////////////////////////////////////////////////////////////////////////// + + Scene.ObjectUpdateResult groupUpdateResult = Scene.ObjectUpdateResult.Unchanged; + Dictionary updatedParts = new Dictionary(); + + lock (m_parts.SyncRoot) + { + //This function is called by LinkObjectBySync and DelinkObjectBySinc(), + //which should have updated the parts in this SOG, hence should be no need to + //add or remove parts to sync + + if (this.PrimCount != updatedSog.PrimCount) + { + m_log.WarnFormat("UpdateSOGBySync: For SOP {0}, local copy has {1} parts, while incoming updated copy has {2} parts. Inconsistent.", this.UUID, + this.PrimCount, updatedSog.PrimCount); + } + + //now update properties of the parts + foreach (SceneObjectPart part in this.Parts) + { + Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged; + SceneObjectPart updatedPart = updatedSog.GetChildPart(part.UUID); + + if (updatedPart == null) + { + m_log.WarnFormat("UpdateSOGBySync: part {0},{1} exists in local copy, not in incoming updated copy", part.Name, part.UUID); + } + else + { + partUpdateResult = part.UpdateAllProperties(updatedPart); + + if (partUpdateResult != Scene.ObjectUpdateResult.Unchanged) + { + groupUpdateResult = partUpdateResult; + } + } + } + + //Just to make sure the parts each has the right localID of the rootpart + UpdateParentIDs(); + } + + //Schedule updates to be sent out, if the local copy has just been updated + //(1) if we are debugging the actor with a viewer attaching to it, + //we need to schedule updates to be sent to the viewer. + //(2) or if we are a relaying node to relay updates, we need to forward the updates. + //NOTE: LastUpdateTimeStamp and LastUpdateActorID should be kept the same as in the received copy of the object. + if (groupUpdateResult == Scene.ObjectUpdateResult.Updated) + { + ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + } + + //debug the update result + if (groupUpdateResult == Scene.ObjectUpdateResult.Updated) + { + DebugObjectUpdateResult(); + } + + return groupUpdateResult; + } + + #endregion } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4728012fcc..081ea22343 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -42,6 +42,7 @@ using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes.Scripting; using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Region.Physics.Manager; +using System.IO; namespace OpenSim.Region.Framework.Scenes { @@ -129,7 +130,7 @@ namespace OpenSim.Region.Framework.Scenes #region Fields - //SYMMETRIC SYNC + //DSG SYNC //public bool AllowedDrop; private bool m_allowedDrop; public bool AllowedDrop @@ -2799,7 +2800,7 @@ namespace OpenSim.Region.Framework.Scenes //m_parentGroup.RootPart.m_groupPosition = newpos; } //ScheduleTerseUpdate(); - ScheduleTerseUpdate(new List(){SceneObjectPartProperties.Position}); + ScheduleTerseUpdate(new List(){SceneObjectPartSyncProperties.Position}); //SendTerseUpdateToAllClients(); } @@ -2890,7 +2891,7 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; //ScheduleFullUpdate(); - ScheduleFullUpdate(new List(){SceneObjectPartProperties.Scale}); + ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Scale}); } public void RotLookAt(Quaternion target, float strength, float damping) @@ -2932,8 +2933,8 @@ namespace OpenSim.Region.Framework.Scenes /// /// Schedules this prim for a full update /// - //public void ScheduleFullUpdate() :: SYMMETRIC SYNC: changed the interface so that we can identify which property triggers calling this function - public virtual void ScheduleFullUpdate(List updatedProperties) + //public void ScheduleFullUpdate() :: DSG SYNC: changed the interface so that we can identify which property triggers calling this function + public virtual void ScheduleFullUpdate(List updatedProperties) { // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId); @@ -2968,7 +2969,7 @@ namespace OpenSim.Region.Framework.Scenes /// rotation, velocity, rotational velocity and shape information. /// //public void ScheduleTerseUpdate() - public virtual void ScheduleTerseUpdate(List updatedProperties) + public virtual void ScheduleTerseUpdate(List updatedProperties) { if (m_updateFlag < 1) { @@ -3201,12 +3202,16 @@ namespace OpenSim.Region.Framework.Scenes } ClearUpdateSchedule(); - //SYMMETRIC SYNC + //DSG SYNC + //KittyL: 04/06/2011, No longer calling QueueSceneObjectPartForUpdate + //from here. Local updates are now recorded by calling IRegionSyncModule.ProcessAndEnqueuePrimUpdatesByLocal(). + /* if (m_parentGroup.Scene.RegionSyncModule != null) { m_parentGroup.Scene.RegionSyncModule.QueueSceneObjectPartForUpdate((SceneObjectPart)this); } - //end of SYMMETRIC SYNC + * */ + //end of DSG SYNC } /// @@ -3670,7 +3675,7 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; //ScheduleFullUpdate(); - ScheduleFullUpdate(new List(){SceneObjectPartProperties.Text}); + ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Text}); } public void StopLookAt() @@ -3678,7 +3683,7 @@ namespace OpenSim.Region.Framework.Scenes m_parentGroup.stopLookAt(); //m_parentGroup.ScheduleGroupForTerseUpdate(); - m_parentGroup.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.None});//in stopLookAt(), PhysicsActor shall already take care of tainting which properties have been updated + m_parentGroup.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.None});//in stopLookAt(), PhysicsActor shall already take care of tainting which properties have been updated } /// @@ -3701,7 +3706,7 @@ namespace OpenSim.Region.Framework.Scenes m_parentGroup.stopMoveToTarget(); //m_parentGroup.ScheduleGroupForTerseUpdate(); - m_parentGroup.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.None}); //in stopMoveToTarget(), PhysicsActor shall already take care of tainting which properties have been updated + m_parentGroup.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.None}); //in stopMoveToTarget(), PhysicsActor shall already take care of tainting which properties have been updated //m_parentGroup.ScheduleGroupForFullUpdate(); } @@ -4250,7 +4255,7 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; //ScheduleFullUpdate(); - ScheduleFullUpdate(new List(){SceneObjectPartProperties.Shape}); + ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Shape}); } public void UpdateGroupPosition(Vector3 pos) @@ -4262,7 +4267,7 @@ namespace OpenSim.Region.Framework.Scenes Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); GroupPosition = newPos; //ScheduleTerseUpdate(); - ScheduleFullUpdate(new List(){SceneObjectPartProperties.GroupPosition}); + ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.GroupPosition}); } } @@ -4295,7 +4300,7 @@ namespace OpenSim.Region.Framework.Scenes OffsetPosition = newPos; //ScheduleTerseUpdate(); - ScheduleFullUpdate(new List(){SceneObjectPartProperties.OffsetPosition}); + ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.OffsetPosition}); } } @@ -4585,7 +4590,7 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; //ScheduleFullUpdate(); - ScheduleFullUpdate(new List() { SceneObjectPartProperties.Flags}); + ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.Flags}); } public void UpdateRotation(Quaternion rot) @@ -4598,7 +4603,7 @@ namespace OpenSim.Region.Framework.Scenes RotationOffset = rot; ParentGroup.HasGroupChanged = true; //ScheduleTerseUpdate(); - ScheduleFullUpdate(new List() {SceneObjectPartProperties.RotationOffset}); + ScheduleFullUpdate(new List() {SceneObjectPartSyncProperties.RotationOffset}); } } @@ -4644,7 +4649,11 @@ namespace OpenSim.Region.Framework.Scenes ParentGroup.HasGroupChanged = true; TriggerScriptChangedEvent(Changed.SHAPE); //ScheduleFullUpdate(); - ScheduleFullUpdate(new List() {SceneObjectPartProperties.Shape}); + + //DSG DEBUG + //m_log.DebugFormat("{0}, {1}: shaped updated to {2}, calling ScheduleFullUpdate.", Name, UUID, Shape.ProfileShape); + + ScheduleFullUpdate(new List() {SceneObjectPartSyncProperties.Shape}); } /// @@ -4692,7 +4701,7 @@ namespace OpenSim.Region.Framework.Scenes //ParentGroup.ScheduleGroupForFullUpdate(); //This is sparta //ScheduleFullUpdate(); - ScheduleFullUpdate(new List() {SceneObjectPartProperties.Shape}); + ScheduleFullUpdate(new List() {SceneObjectPartSyncProperties.Shape}); } public void aggregateScriptEvents() @@ -4761,7 +4770,7 @@ 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(new List() { SceneObjectPartProperties.Flags, SceneObjectPartProperties.AggregateScriptEvents}); + ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.Flags, SceneObjectPartSyncProperties.AggregateScriptEvents}); return; } @@ -4785,7 +4794,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(new List() { SceneObjectPartProperties.Flags, SceneObjectPartProperties.AggregateScriptEvents}); + ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.Flags, SceneObjectPartSyncProperties.LocalFlags, + SceneObjectPartSyncProperties.AggregateScriptEvents}); } } @@ -4978,7 +4988,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion - #region SYMMETRIC SYNC + #region DSG SYNC //Time stamp for the most recent update on this prim. We only have one time-stamp per prim for now. //The goal is to evetually have time-stamp per property bucket for each prim. @@ -4993,7 +5003,7 @@ namespace OpenSim.Region.Framework.Scenes } - //SYMMETRIC SYNC + //DSG SYNC //Information for concurrency control of one bucket of prim proproperties. public class BucketSyncInfo @@ -5150,7 +5160,7 @@ namespace OpenSim.Region.Framework.Scenes } */ - public enum SceneObjectPartProperties + public enum SceneObjectPartSyncProperties { None, //Following properties copied from SceneObjectSerializer(), @@ -5160,12 +5170,12 @@ namespace OpenSim.Region.Framework.Scenes FolderID , InventorySerial, TaskInventory, - //UUID", + //UUID", //UUID not supposed to be changed after SOP is created, not included in SyncProperties //LocalId", Name, Material, PassTouches, - RegionHandle, + //RegionHandle, ScriptAccessPin, GroupPosition, OffsetPosition, @@ -5188,7 +5198,7 @@ namespace OpenSim.Region.Framework.Scenes SitTargetPosition, SitTargetPositionLL, SitTargetOrientationLL, - ParentID, + //ParentID, CreationDate, Category, SalePrice, @@ -5208,7 +5218,8 @@ namespace OpenSim.Region.Framework.Scenes MediaUrl, TextureAnimation, ParticleSystem, - //Property names below copied from PhysicsActor, they are necessary in synchronization, but not covered the above properties + //Property names below copied from PhysicsActor, they are necessary in + //synchronization, but not covered by xml serialization //Physics properties "Velocity" is covered above Position, Size, @@ -5221,19 +5232,22 @@ namespace OpenSim.Region.Framework.Scenes Flying, Buoyancy, Kinematic, - IsCollidingGround, + CollidingGround, IsColliding, - //TODO!!!! To be handled in serialization/deserizaltion for synchronization + + //Properties need to be synced, but not in xml serializations AggregateScriptEvents, - IsAttachment, AttachedAvatar, AttachedPos, AttachmentPoint, + IsAttachment, + LocalFlags, //TODO!!!! To be handled in serialization/deserizaltion for synchronization - IsSelected, Sound, //This indicates any Sound related property has changed: Sound, SoundGain, SoundFlags,SoundRadius, //Addition properties to be added here + //Group properties + IsSelected, //Client Manager may want to add some property here that viewers care about and should be synchronized across actors FullUpdate, @@ -5266,7 +5280,7 @@ namespace OpenSim.Region.Framework.Scenes //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 Dictionary m_primPropertyBucketMap = null; private static List m_propertyBucketNames = null; private static string m_localActorID = ""; @@ -5359,8 +5373,111 @@ namespace OpenSim.Region.Framework.Scenes }; * */ + /// + /// Return the list of all prim (SOP) properties, in enum type. + /// Excluding None, FullUpdate. + /// + /// + public static HashSet GetAllPrimProperties() + { + HashSet allProperties = new HashSet(); + foreach (SceneObjectPartSyncProperties property in Enum.GetValues(typeof(SceneObjectPartSyncProperties))) + { + switch (property) + { + case SceneObjectPartSyncProperties.None: + case SceneObjectPartSyncProperties.FullUpdate: + break; + default: + allProperties.Add(property); + break; + } + } + return allProperties; + } - public static void InitializePropertyBucketInfo(Dictionary propertyBucketMap, List bucketNames, string actorID) + public static HashSet GetAllPrimNonPhysActorProperties() + { + HashSet allProperties = new HashSet(); + foreach (SceneObjectPartSyncProperties property in Enum.GetValues(typeof(SceneObjectPartSyncProperties))) + { + switch (property) + { + //Enum value that is not real properties + case SceneObjectPartSyncProperties.None: + case SceneObjectPartSyncProperties.FullUpdate: + //PhysActor properties + case SceneObjectPartSyncProperties.Buoyancy: + case SceneObjectPartSyncProperties.Flying: + case SceneObjectPartSyncProperties.Force: + case SceneObjectPartSyncProperties.IsColliding: + case SceneObjectPartSyncProperties.CollidingGround: + case SceneObjectPartSyncProperties.IsPhysical: + case SceneObjectPartSyncProperties.Kinematic: + case SceneObjectPartSyncProperties.Orientation: + case SceneObjectPartSyncProperties.PA_Acceleration: + case SceneObjectPartSyncProperties.Position: + case SceneObjectPartSyncProperties.RotationalVelocity: + case SceneObjectPartSyncProperties.Size: + case SceneObjectPartSyncProperties.Torque: + break; + default: + allProperties.Add(property); + break; + } + } + return allProperties; + } + + public static HashSet GetAllPhysActorProperties() + { + HashSet allProperties = new HashSet(); + foreach (SceneObjectPartSyncProperties property in Enum.GetValues(typeof(SceneObjectPartSyncProperties))) + { + switch (property) + { + //PhysActor properties + case SceneObjectPartSyncProperties.Buoyancy: + case SceneObjectPartSyncProperties.Flying: + case SceneObjectPartSyncProperties.Force: + case SceneObjectPartSyncProperties.IsColliding: + case SceneObjectPartSyncProperties.CollidingGround: + case SceneObjectPartSyncProperties.IsPhysical: + case SceneObjectPartSyncProperties.Kinematic: + case SceneObjectPartSyncProperties.Orientation: + case SceneObjectPartSyncProperties.PA_Acceleration: + case SceneObjectPartSyncProperties.Position: + case SceneObjectPartSyncProperties.RotationalVelocity: + case SceneObjectPartSyncProperties.Size: + case SceneObjectPartSyncProperties.Torque: + allProperties.Add(property); + break; + default: + break; + } + } + return allProperties; + } + + public static HashSet GetAllNonPhysActorProperties() + { + HashSet allProperties = GetAllPrimProperties(); + HashSet physActorProperties = GetAllPhysActorProperties(); + + foreach (SceneObjectPartSyncProperties pProperty in physActorProperties) + { + allProperties.Remove(pProperty); + } + return allProperties; + } + + public static HashSet GetGroupProperties() + { + HashSet allProperties = new HashSet(){SceneObjectPartSyncProperties.IsSelected}; + return allProperties; + } + + public static void InitializePropertyBucketInfo(Dictionary propertyBucketMap, List bucketNames, string actorID) { m_primPropertyBucketMap = propertyBucketMap; m_propertyBucketNames = bucketNames; @@ -5373,11 +5490,14 @@ namespace OpenSim.Region.Framework.Scenes 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; - } + //debugMsg += ", parentID " + ParentID + ", parentUUID " + ParentUUID; + //foreach (KeyValuePair pair in m_bucketSyncInfoList) + //{ + // debugMsg += ", Bucket " + pair.Key + ": TimeStamp - " + pair.Value.LastUpdateTimeStamp + ", ActorID - " + pair.Value.LastUpdateActorID; + //} + debugMsg += ", AggregateScriptEvents = " + AggregateScriptEvents.ToString()+", OffsetPosition: "+OffsetPosition; + String hashedShape = Util.Md5Hash(SerializeShape()); + debugMsg += ", hashed Shape = " + hashedShape; return debugMsg; } @@ -5705,14 +5825,14 @@ namespace OpenSim.Region.Framework.Scenes } //For tainitng and clearing taints, do i need to lock on m_bucketSyncTaint? - public void TaintBucketSyncInfo(SceneObjectPartProperties property) + public void TaintBucketSyncInfo(SceneObjectPartSyncProperties property) { if (m_syncEnabled) { - if (property == SceneObjectPartProperties.None) + if (property == SceneObjectPartSyncProperties.None) return; - if (property == SceneObjectPartProperties.FullUpdate) + if (property == SceneObjectPartSyncProperties.FullUpdate) { foreach (BucketSyncInfo bucketSynInfo in m_bucketSyncInfoList.Values) { @@ -5800,7 +5920,7 @@ namespace OpenSim.Region.Framework.Scenes /// 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) + public void UpdateBucketSyncInfo(SceneObjectPartSyncProperties property) { if (m_syncEnabled && m_bucketSyncInfoList != null && m_bucketSyncInfoList.Count > 0) { @@ -5936,6 +6056,9 @@ namespace OpenSim.Region.Framework.Scenes return partUpdateResult; } + //Implementation of ScheduleFullUpdate and ScheduleTerseUpdate for Bucket + //based synchronization + /* public override void ScheduleFullUpdate(List updatedProperties) { if (updatedProperties != null && updatedProperties.Count > 0) @@ -5963,6 +6086,49 @@ namespace OpenSim.Region.Framework.Scenes base.ScheduleTerseUpdate(updatedProperties); //TaintBucketSyncInfo(property); } + * */ + + //Implementation of ScheduleFullUpdate and ScheduleTerseUpdate for Bucket + //based synchronization + public override void ScheduleFullUpdate(List updatedProperties) + { + if (updatedProperties != null && updatedProperties.Count > 0) + { + if (m_parentGroup != null && m_parentGroup.Scene != null && m_parentGroup.Scene.RegionSyncModule != null) + { + /* + if (updatedProperties.Contains(SceneObjectPartSyncProperties.Shape)) + { + m_log.DebugFormat("{0}, {1} -- calling ProcessAndEnqueuePrimUpdatesByLocal to update to Shape {2}", Name, UUID, Shape.ProfileShape); + } + * */ + m_parentGroup.Scene.RegionSyncModule.ProcessAndEnqueuePrimUpdatesByLocal(this, updatedProperties); + } + else + { + if (updatedProperties.Contains(SceneObjectPartSyncProperties.Shape)) + { + m_log.DebugFormat("{0}, {1} Shape changed to {2}, but this SOP not attached to Scene yet", Name, UUID, Shape.ProfileShape); + } + } + } + + base.ScheduleFullUpdate(updatedProperties); + } + + public override void ScheduleTerseUpdate(List updatedProperties) + { + if (updatedProperties != null && updatedProperties.Count > 0) + { + if (m_parentGroup != null && m_parentGroup.Scene != null && m_parentGroup.Scene.RegionSyncModule != null) + { + m_parentGroup.Scene.RegionSyncModule.ProcessAndEnqueuePrimUpdatesByLocal(this, updatedProperties); + } + } + + base.ScheduleTerseUpdate(updatedProperties); + } + /// /// Schedules this prim for a full update, without changing the timestamp or actorID (info on when and who modified any property). @@ -5970,36 +6136,10 @@ namespace OpenSim.Region.Framework.Scenes /// public void ScheduleFullUpdate_SyncInfoUnchanged() { - //m_log.DebugFormat("[SCENE OBJECT PART]: ScheduleFullUpdate_SyncInfoUnchanged for {0} {1}", Name, LocalId); - - if (m_parentGroup != null) - { - m_parentGroup.QueueForUpdateCheck(); - } - - int timeNow = Util.UnixTimeSinceEpoch(); - - // If multiple updates are scheduled on the same second, we still need to perform all of them - // So we'll force the issue by bumping up the timestamp so that later processing sees these need - // to be performed. - if (timeNow <= TimeStampFull) - { - TimeStampFull += 1; - } - else - { - TimeStampFull = (uint)timeNow; - } - - m_updateFlag = 2; - - // m_log.DebugFormat( - // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", - // UUID, Name, TimeStampFull); - + base.ScheduleFullUpdate(null); } - private bool UpdateCollisionSound(UUID updatedCollisionSound) + public bool UpdateCollisionSound(UUID updatedCollisionSound) { if (this.CollisionSound != updatedCollisionSound) { @@ -6032,7 +6172,27 @@ namespace OpenSim.Region.Framework.Scenes { base.PhysicsCollision(e); } + + /////////////////////////////////////////////////////////////////////// + //Per property sync functions + /////////////////////////////////////////////////////////////////////// + + + //For debugging, same implemenation with PropertySerializer.SerializeShape + private string SerializeShape() + { + string serializedShape; + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter writer = new XmlTextWriter(sw)) + { + SceneObjectSerializer.WriteShape(writer, Shape, new Dictionary()); + } + serializedShape = sw.ToString(); + } + return serializedShape; + } } - //end of SYMMETRIC SYNC + //end of DSG SYNC } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 652acceba5..5676a4ddea 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -294,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(new List(){SceneObjectPartProperties.Flags, SceneObjectPartProperties.TaskInventory}); + m_part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Flags, SceneObjectPartSyncProperties.TaskInventory}); return; } @@ -322,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(new List(){SceneObjectPartProperties.Flags, SceneObjectPartProperties.TaskInventory}); + m_part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Flags, SceneObjectPartSyncProperties.TaskInventory}); } } } @@ -545,8 +545,8 @@ namespace OpenSim.Region.Framework.Scenes HasInventoryChanged = true; m_part.ParentGroup.HasGroupChanged = true; - //SYMMETRIC SYNC: add ScheduleFullUpdate to enable synchronization across actors - m_part.ScheduleFullUpdate(new List(){SceneObjectPartProperties.TaskInventory, SceneObjectPartProperties.InventorySerial}); + //DSG SYNC: add ScheduleFullUpdate to enable synchronization across actors + m_part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.TaskInventory, SceneObjectPartSyncProperties.InventorySerial}); } /// @@ -769,7 +769,7 @@ namespace OpenSim.Region.Framework.Scenes if (!ContainsScripts()) m_part.RemFlag(PrimFlags.Scripted); - m_part.ScheduleFullUpdate(new List(){SceneObjectPartProperties.TaskInventory}); + m_part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.TaskInventory}); return type; @@ -1183,7 +1183,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion REGION SYNC } - #region SYMMETRIC SYNC + #region DSG SYNC public class SceneObjectPartInventory : SceneObjectPartInventoryBase { private SceneObjectPart m_part; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 5d2c0aed86..b651720e8d 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -232,7 +232,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization sceneObject.AddPart(part); - //SYMMETRIC SYNC + //DSG SYNC //KittyL: 12/27/2010, added ActorID for symmetric synch model //part.SetLastUpdateActorID(); @@ -346,7 +346,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); - //SYMMETRIC SYNC + //DSG SYNC m_SOPXmlProcessors.Add("LocalFlags", ProcessLocalFlags); //m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp); //m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID); @@ -357,7 +357,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("AggregateScriptEvents", ProcessAggregateScriptEvents); m_SOPXmlProcessors.Add("BucketSyncInfoList", ProcessBucketSyncInfo); - //end of SYMMETRIC SYNC + //end of DSG SYNC #endregion @@ -442,7 +442,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } #region SOPXmlProcessors - //SYMMETRIC SYNC NOTE: -- assignments in de-serialization should directly set the values w/o triggering SceneObjectPart.UpdateBucketSyncInfo; + //DSG SYNC NOTE: -- assignments in de-serialization should directly set the values w/o triggering SceneObjectPart.UpdateBucketSyncInfo; private static void ProcessAllowedDrop(SceneObjectPart obj, XmlTextReader reader) { obj.AllowedDrop = Util.ReadBoolean(reader); @@ -595,7 +595,6 @@ 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")); } private static void ProcessUpdateFlag(SceneObjectPart obj, XmlTextReader reader) @@ -724,7 +723,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty)); } - //SYMMETRIC SYNC + //DSG SYNC /* private static void ProcessUpdateTimeStamp(SceneObjectPart obj, XmlTextReader reader) { @@ -817,7 +816,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization reader.ReadEndElement(); // BucketSyncInfoList } - //end of SYMMETRIC SYNC + //end of DSG SYNC #endregion @@ -1289,10 +1288,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("GroupMask", sop.GroupMask.ToString()); 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 + //DSG SYNC: also serialize SceneObjectPart:LocalFlags, so that it can be propogated across actors WriteFlags(writer, "Flags", sop.Flags.ToString(), options); WriteFlags(writer, "LocalFlags", sop.LocalFlags.ToString(), options); - //end SYMMETRIC SYNC + //end DSG SYNC WriteUUID(writer, "CollisionSound", sop.CollisionSound, options); writer.WriteElementString("CollisionSoundVolume", sop.CollisionSoundVolume.ToString()); if (sop.MediaUrl != null) @@ -1300,7 +1299,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); - //SYMMETRIC SYNC + //DSG SYNC //These properties are only meaningful for synchronization purpose. For saving oar files, they are not necessary. //We may remove these if later we use a different method to encode object properties for synchronization. WriteUUID(writer, "AttachedAvatar", sop.AttachedAvatar, options); @@ -1309,12 +1308,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization //writer.WriteElementString("IsAttachment", sop.IsAttachment.ToString().ToLower()); //IsAttachment is written last, so that on deserialization, it will be deserialized later than other Attachment properties WriteFlags(writer, "AggregateScriptEvents", sop.AggregateScriptEvents.ToString(), options); WriteBucketSyncInfo(writer, sop.BucketSyncInfoList); - //end of SYMMETRIC SYNC + //end of DSG SYNC writer.WriteEndElement(); } - //SYMMETRIC SYNC + //DSG SYNC public static void WriteBucketSyncInfo(XmlTextWriter writer, Dictionary bucketSyncInfoList) { if (bucketSyncInfoList!=null || bucketSyncInfoList.Count > 0) // otherwise skip this @@ -1336,7 +1335,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - //end of SYMMETRIC SYNC + //end of DSG SYNC static void WriteUUID(XmlTextWriter writer, string name, UUID id, Dictionary options) { @@ -1386,7 +1385,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString(name, flagsStr.Replace(",", "")); } - static void WriteTaskInventory(XmlTextWriter writer, TaskInventoryDictionary tinv, Dictionary options, Scene scene) + //DSG SYNC: make it a public function, so that we can call serialization of TaskInventory from other places + //static void WriteTaskInventory(XmlTextWriter writer, TaskInventoryDictionary tinv, Dictionary options, Scene scene) + public static void WriteTaskInventory(XmlTextWriter writer, TaskInventoryDictionary tinv, Dictionary options, Scene scene) { if (tinv.Count > 0) // otherwise skip this { @@ -1440,7 +1441,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - static void WriteShape(XmlTextWriter writer, PrimitiveBaseShape shp, Dictionary options) + //DSG SYNC: make it a public function, so that we can call serialization of Shape from other places + //static void WriteShape(XmlTextWriter writer, PrimitiveBaseShape shp, Dictionary options) + public static void WriteShape(XmlTextWriter writer, PrimitiveBaseShape shp, Dictionary options) { if (shp != null) { @@ -1484,6 +1487,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteElementString("ProfileBegin", shp.ProfileBegin.ToString()); writer.WriteElementString("ProfileEnd", shp.ProfileEnd.ToString()); writer.WriteElementString("ProfileHollow", shp.ProfileHollow.ToString()); + //DSG SYNC: added serialization of Shape + WriteVector(writer, "Scale", shp.Scale); + //end of DSG SYNC writer.WriteElementString("State", shp.State.ToString()); WriteFlags(writer, "ProfileShape", shp.ProfileShape.ToString(), options); @@ -1613,7 +1619,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return obj; } - static TaskInventoryDictionary ReadTaskInventory(XmlTextReader reader, string name) + //DSG SYNC: make it public to be called outside + //static TaskInventoryDictionary ReadTaskInventory(XmlTextReader reader, string name) + public static TaskInventoryDictionary ReadTaskInventory(XmlTextReader reader, string name) { TaskInventoryDictionary tinv = new TaskInventoryDictionary(); @@ -1652,7 +1660,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return tinv; } - static PrimitiveBaseShape ReadShape(XmlTextReader reader, string name) + //DSG SYNC: make it public to be called outside + //static PrimitiveBaseShape ReadShape(XmlTextReader reader, string name) + public static PrimitiveBaseShape ReadShape(XmlTextReader reader, string name) { PrimitiveBaseShape shape = new PrimitiveBaseShape(); diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs index 3a55ac3285..4ec6e155c7 100644 --- a/OpenSim/Region/Framework/Scenes/UndoState.cs +++ b/OpenSim/Region/Framework/Scenes/UndoState.cs @@ -94,13 +94,13 @@ namespace OpenSim.Region.Framework.Scenes if (Scale != Vector3.Zero) part.Resize(Scale); //part.ParentGroup.ScheduleGroupForTerseUpdate(); - //SYMMETRIC SYNC - List updatedProperties = new List(); - updatedProperties.Add(SceneObjectPartProperties.RotationOffset); + //DSG SYNC + List updatedProperties = new List(); + updatedProperties.Add(SceneObjectPartSyncProperties.RotationOffset); if (Position != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Position); + updatedProperties.Add(SceneObjectPartSyncProperties.Position); if (Scale != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Scale); + updatedProperties.Add(SceneObjectPartSyncProperties.Scale); part.ParentGroup.ScheduleGroupForTerseUpdate(updatedProperties); } else @@ -110,13 +110,13 @@ namespace OpenSim.Region.Framework.Scenes part.UpdateRotation(Rotation); if (Scale != Vector3.Zero) part.Resize(Scale); //part.ScheduleTerseUpdate(); - //SYMMETRIC SYNC - List updatedProperties = new List(); - updatedProperties.Add(SceneObjectPartProperties.RotationOffset); + //DSG SYNC + List updatedProperties = new List(); + updatedProperties.Add(SceneObjectPartSyncProperties.RotationOffset); if (Position != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.OffsetPosition); + updatedProperties.Add(SceneObjectPartSyncProperties.OffsetPosition); if (Scale != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Scale); + updatedProperties.Add(SceneObjectPartSyncProperties.Scale); part.ScheduleTerseUpdate(updatedProperties); } part.Undoing = false; @@ -138,14 +138,14 @@ namespace OpenSim.Region.Framework.Scenes if (Scale != Vector3.Zero) part.Resize(Scale); //part.ParentGroup.ScheduleGroupForTerseUpdate(); - //SYMMETRIC SYNC - List updatedProperties = new List(); + //DSG SYNC + List updatedProperties = new List(); if (Rotation != Quaternion.Identity) - updatedProperties.Add(SceneObjectPartProperties.RotationOffset); + updatedProperties.Add(SceneObjectPartSyncProperties.RotationOffset); if (Position != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Position); + updatedProperties.Add(SceneObjectPartSyncProperties.Position); if (Scale != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Scale); + updatedProperties.Add(SceneObjectPartSyncProperties.Scale); part.ParentGroup.ScheduleGroupForTerseUpdate(updatedProperties); } else @@ -157,14 +157,14 @@ namespace OpenSim.Region.Framework.Scenes if (Scale != Vector3.Zero) part.Resize(Scale); //part.ScheduleTerseUpdate(); - //SYMMETRIC SYNC - List updatedProperties = new List(); + //DSG SYNC + List updatedProperties = new List(); if (Rotation != Quaternion.Identity) - updatedProperties.Add(SceneObjectPartProperties.RotationOffset); + updatedProperties.Add(SceneObjectPartSyncProperties.RotationOffset); if (Position != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Position); + updatedProperties.Add(SceneObjectPartSyncProperties.Position); if (Scale != Vector3.Zero) - updatedProperties.Add(SceneObjectPartProperties.Scale); + updatedProperties.Add(SceneObjectPartSyncProperties.Scale); part.ScheduleTerseUpdate(updatedProperties); } diff --git a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs index 462b014306..2fcacddfef 100644 --- a/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs +++ b/OpenSim/Region/OptionalModules/ContentManagementSystem/CMModel.cs @@ -291,7 +291,7 @@ namespace OpenSim.Region.OptionalModules.ContentManagement ((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(new List(){SceneObjectPartProperties.FullUpdate}); //don't know what properties to taint, so just taint all + ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.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 75538c97f2..3b13a8bb84 100644 --- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs +++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs @@ -641,7 +641,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator s_tree.Scale += copse.m_rate; s_tree.ParentGroup.HasGroupChanged = true; //s_tree.ScheduleFullUpdate(); - s_tree.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Scale}); + s_tree.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.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 e2e54760e0..7884755dc0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -1388,6 +1388,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api tmp.Z = (float)scale.z; part.Scale = tmp; part.SendFullUpdateToAllClients(); + + //DSG SYNC + part.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.Scale }); } public LSL_Vector llGetScale() @@ -1402,7 +1405,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.ClickAction = (byte)action; if (m_host.ParentGroup != null) m_host.ParentGroup.HasGroupChanged = true; //m_host.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.ClickAction}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.ClickAction}); return; } @@ -1655,7 +1658,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.ParentGroup.HasGroupChanged = true; //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Shape}); + part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Shape}); } /// @@ -1691,7 +1694,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.ParentGroup.HasGroupChanged = true; //part.ScheduleFullUpdate(); - part.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Shape}); + part.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Shape}); } public LSL_Vector llGetColor(int face) @@ -1967,7 +1970,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SceneObjectGroup parent = part.ParentGroup; parent.HasGroupChanged = true; //parent.ScheduleGroupForTerseUpdate(); - parent.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartProperties.OffsetPosition}); + parent.ScheduleGroupForTerseUpdate(new List(){SceneObjectPartSyncProperties.OffsetPosition}); } } @@ -2314,7 +2317,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable? //m_host.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Sound}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Sound}); m_host.SendFullUpdateToAllClients(); } @@ -2335,7 +2338,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api prim.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable? //prim.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Sound}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Sound}); prim.SendFullUpdateToAllClients(); } } @@ -2348,7 +2351,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundRadius = 20; // Magic number, 20 seems reasonable. Make configurable? //m_host.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Sound}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Sound}); m_host.SendFullUpdateToAllClients(); } @@ -2391,7 +2394,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.SoundFlags = 0; part.SoundRadius = 0; //part.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Sound}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Sound}); part.SendFullUpdateToAllClients(); } m_host.ParentGroup.LoopSoundMasterPrim = null; @@ -2404,7 +2407,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundFlags = 0; m_host.SoundRadius = 0; //m_host.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Sound}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Sound}); m_host.SendFullUpdateToAllClients(); } } @@ -2415,7 +2418,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.SoundFlags = 0; m_host.SoundRadius = 0; //m_host.ScheduleFullUpdate(); - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Sound}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Sound}); m_host.SendFullUpdateToAllClients(); } } @@ -3326,7 +3329,7 @@ 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.ScheduleFullUpdate(new List(){SceneObjectPartProperties.AngularVelocity}); + m_host.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.AngularVelocity}); m_host.SendTerseUpdateToAllClients(); m_host.ParentGroup.HasGroupChanged = true; } @@ -3612,17 +3615,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parentPrim.RootPart.CreateSelected = true; parentPrim.HasGroupChanged = true; //parentPrim.ScheduleGroupForFullUpdate(); - //SYMMETRIC SYNC + //DSG 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, children); + //World.RegionSyncModule.SendLinkObject(parentPrim, parentPrim.RootPart, children); + World.RegionSyncModule.SyncLinkObject(parentPrim, parentPrim.RootPart, children); } - m_host.ScheduleFullUpdate(new List(){SceneObjectPartProperties.None}); //SendLinkObject above will synchronize the link operation, no need to taint updates here - //end of SYMMETRIC SYNC + m_host.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.None }); //SyncLinkObject above will synchronize the link operation, no need to taint updates here + //end of DSG SYNC if (client != null) parentPrim.GetProperties(client); @@ -3680,11 +3684,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (linknum == ScriptBaseClass.LINK_ROOT) { - //SYMMETRIC SYNC + //DSG SYNC List beforeDelinkGroups = new List(); beforeDelinkGroups.Add(parentPrim); List afterDelinkGroups = new List(); - //end of SYMMETRIC SYNC + //end of DSG SYNC // Restructuring Multiple Prims. List parts = new List(parentPrim.Parts); @@ -3692,19 +3696,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (SceneObjectPart part in parts) { parentPrim.DelinkFromGroup(part.LocalId, true); - //SYMMETRIC SYNC + //DSG SYNC afterDelinkGroups.Add(part.ParentGroup); } parentPrim.HasGroupChanged = true; //parentPrim.ScheduleGroupForFullUpdate(); - //SYMMETRIC SYNC + //DSG 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(new List(){SceneObjectPartProperties.None}); - //end of SYMMETRIC SYNC + parentPrim.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.None}); + //end of DSG SYNC parentPrim.TriggerScriptChangedEvent(Changed.LINK); if (parts.Count > 0) @@ -3718,13 +3722,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } newRoot.ParentGroup.HasGroupChanged = true; //newRoot.ParentGroup.ScheduleGroupForFullUpdate(); - //SYMMETRIC SYNC + //DSG SYNC if (World.RegionSyncModule != null) { - World.RegionSyncModule.SendLinkObject(newRoot.ParentGroup, newRoot, new List(newRoot.ParentGroup.Parts)); + //World.RegionSyncModule.SendLinkObject(newRoot.ParentGroup, newRoot, new List(newRoot.ParentGroup.Parts)); + World.RegionSyncModule.SyncLinkObject(newRoot.ParentGroup, newRoot, new List(newRoot.ParentGroup.Parts)); } - newRoot.ParentGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.None}); - //end of SYMMETRIC SYNC + newRoot.ParentGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.None}); + //end of DSG SYNC } } @@ -3736,7 +3741,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api parentPrim.DelinkFromGroup(childPrim.LocalId, true); parentPrim.HasGroupChanged = true; //parentPrim.ScheduleGroupForFullUpdate(); - //SYMMETRIC SYNC + //DSG SYNC //Send out DelinkObject message to other actors to sychronize their object list if (World.RegionSyncModule != null) { @@ -3746,7 +3751,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api afterDelinkGroups.Add(childPrim.ParentGroup); World.RegionSyncModule.SendDeLinkObject(new List(parentPrim.Parts), beforeDelinkGroups, afterDelinkGroups); } - //end of SYMMETRIC SYNC + //end of DSG SYNC parentPrim.TriggerScriptChangedEvent(Changed.LINK); } @@ -3759,12 +3764,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (parentPrim.RootPart.AttachmentPoint != 0) return; // Fail silently if attached - //SYMMETRIC SYNC + //DSG SYNC List beforeDelinkGroups = new List(); beforeDelinkGroups.Add(parentPrim); List afterDelinkGroups = new List(); SceneObjectPart rootPart = parentPrim.RootPart; - //end of SYMMETRIC SYNC + //end of DSG SYNC List parts = new List(parentPrim.Parts); parts.Remove(parentPrim.RootPart); @@ -3773,7 +3778,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { parentPrim.DelinkFromGroup(part.LocalId, true); parentPrim.TriggerScriptChangedEvent(Changed.LINK); - //SYMMETRIC SYNC + //DSG SYNC afterDelinkGroups.Add(part.ParentGroup); } parentPrim.HasGroupChanged = true; @@ -3785,8 +3790,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api afterDelinkGroups.Add(rootPart.ParentGroup); World.RegionSyncModule.SendDeLinkObject(parts, beforeDelinkGroups, afterDelinkGroups); } - parentPrim.ScheduleGroupForFullUpdate(new List(){SceneObjectPartProperties.None}); - //end of SYMMETRIC SYNC + parentPrim.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.None}); + //end of DSG SYNC } public LSL_String llGetLinkKey(int linknum) @@ -4025,7 +4030,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api 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(new List(){SceneObjectPartProperties.Text}); + m_host.ParentGroup.ScheduleGroupForFullUpdate(new List(){SceneObjectPartSyncProperties.Text}); } public LSL_Float llWater(LSL_Vector offset) @@ -5677,6 +5682,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.AddTextureAnimation(pTexAnim); part.SendFullUpdateToAllClients(); part.ParentGroup.HasGroupChanged = true; + + //DSG SYNC + part.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.TextureAnimation }); } public void llTriggerSoundLimited(string sound, double volume, LSL_Vector top_north_east, @@ -6189,6 +6197,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api part.ParentGroup.HasGroupChanged = true; } part.SendFullUpdateToAllClients(); + + //DSG SYNC + part.ScheduleFullUpdate(new List() { SceneObjectPartSyncProperties.ParticleSystem }); } public void llGroundRepel(double height, int water, double tau) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 4e5ed5c4d0..a9096fc855 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2346,7 +2346,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api obj.ParentGroup.HasGroupChanged = true; //obj.ScheduleFullUpdate(); - obj.ScheduleFullUpdate(new List(){SceneObjectPartProperties.Shape}); + obj.ScheduleFullUpdate(new List(){SceneObjectPartSyncProperties.Shape}); }