Added synchronization functions to RegionSyncModule, Scene, SceneGraph, SceneObjectGroup and
SceneObjectPart: examples: HandleAddOrUpdateObjectBySynchronization QueueSceneObjectPartForUpdate SceneObjectGroup.UpdateObjectAllProperties SceneObjectPart.UpdateAllProperties Now script engine and Scene can sync on script updating or Scene editing objects.dsg
parent
f10059ccd9
commit
384895cbdd
|
@ -170,32 +170,130 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
// Lock is used to synchronize access to the update status and update queues
|
// Lock is used to synchronize access to the update status and update queues
|
||||||
private object m_updateSceneObjectPartLock = new object();
|
private object m_updateSceneObjectPartLock = new object();
|
||||||
private Dictionary<UUID, SceneObjectGroup> m_primUpdates = new Dictionary<UUID, SceneObjectGroup>();
|
private Dictionary<UUID, SceneObjectGroup> m_primUpdates = new Dictionary<UUID, SceneObjectGroup>();
|
||||||
private object m_updatePresenceLock = new object();
|
private object m_updateScenePresenceLock = new object();
|
||||||
private Dictionary<UUID, ScenePresence> m_presenceUpdates = new Dictionary<UUID, ScenePresence>();
|
private Dictionary<UUID, ScenePresence> m_presenceUpdates = new Dictionary<UUID, ScenePresence>();
|
||||||
|
private int m_sendingUpdates;
|
||||||
|
|
||||||
public void QueueSceneObjectPartForUpdate(SceneObjectPart part)
|
public void QueueSceneObjectPartForUpdate(SceneObjectPart part)
|
||||||
{
|
{
|
||||||
lock (m_updateSceneObjectPartLock)
|
//if the last update of the prim is caused by this actor itself, or if the actor is a relay node, then enqueue the update
|
||||||
|
if (part.LastUpdateActorID.Equals(m_actorID) || m_isSyncRelay)
|
||||||
{
|
{
|
||||||
m_primUpdates[part.UUID] = part.ParentGroup;
|
lock (m_updateSceneObjectPartLock)
|
||||||
|
{
|
||||||
|
m_primUpdates[part.UUID] = part.ParentGroup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueScenePresenceForTerseUpdate(ScenePresence presence)
|
public void QueueScenePresenceForTerseUpdate(ScenePresence presence)
|
||||||
{
|
{
|
||||||
lock (m_updateSceneObjectPartLock)
|
lock (m_updateScenePresenceLock)
|
||||||
{
|
{
|
||||||
m_presenceUpdates[presence.UUID] = presence;
|
m_presenceUpdates[presence.UUID] = presence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendObjectUpdates(List<SceneObjectGroup> sog)
|
public void SendSceneUpdates()
|
||||||
{
|
{
|
||||||
|
// Existing value of 1 indicates that updates are currently being sent so skip updates this pass
|
||||||
|
if (Interlocked.Exchange(ref m_sendingUpdates, 1) == 1)
|
||||||
|
{
|
||||||
|
m_log.WarnFormat("[REGION SYNC SERVER MODULE] SendUpdates(): An update thread is already running.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SceneObjectGroup> primUpdates;
|
||||||
|
List<ScenePresence> presenceUpdates;
|
||||||
|
|
||||||
|
lock (m_updateSceneObjectPartLock)
|
||||||
|
{
|
||||||
|
primUpdates = new List<SceneObjectGroup>(m_primUpdates.Values);
|
||||||
|
//presenceUpdates = new List<ScenePresence>(m_presenceUpdates.Values);
|
||||||
|
m_primUpdates.Clear();
|
||||||
|
//m_presenceUpdates.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (m_updateScenePresenceLock)
|
||||||
|
{
|
||||||
|
presenceUpdates = new List<ScenePresence>(m_presenceUpdates.Values);
|
||||||
|
m_presenceUpdates.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This could be another thread for sending outgoing messages or just have the Queue functions
|
||||||
|
// create and queue the messages directly into the outgoing server thread.
|
||||||
|
System.Threading.ThreadPool.QueueUserWorkItem(delegate
|
||||||
|
{
|
||||||
|
// Dan's note: 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
|
||||||
|
foreach (SceneObjectGroup sog in primUpdates)
|
||||||
|
{
|
||||||
|
//If this is a relay node, or at least one part of the object has the last update caused by this actor, then send the update
|
||||||
|
if (m_isSyncRelay || CheckObjectForSendingUpdate(sog))
|
||||||
|
{
|
||||||
|
//send
|
||||||
|
List<SyncConnector> syncConnectors = GetSyncConnectorsForObjectUpdates(sog);
|
||||||
|
|
||||||
|
foreach (SyncConnector connector in syncConnectors)
|
||||||
|
{
|
||||||
|
string sogxml = SceneObjectSerializer.ToXml2Format(sog);
|
||||||
|
SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml);
|
||||||
|
connector.EnqueueOutgoingUpdate(sog.UUID, syncMsg.ToBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
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 SERVER MODULE] Caught exception sending presence updates for {0}: {1}", presence.Name, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
* */
|
||||||
|
|
||||||
|
// Indicate that the current batch of updates has been completed
|
||||||
|
Interlocked.Exchange(ref m_sendingUpdates, 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion //IRegionSyncModule
|
#endregion //IRegionSyncModule
|
||||||
|
|
||||||
#region ICommandableModule Members
|
#region ICommandableModule Members
|
||||||
|
@ -296,6 +394,60 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented.");
|
m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if we need to send out an update message for the given object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sog"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool CheckObjectForSendingUpdate(SceneObjectGroup sog)
|
||||||
|
{
|
||||||
|
if (sog == null || sog.IsDeleted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//If any part in the object has the last update caused by this actor itself, then send the update
|
||||||
|
foreach (SceneObjectPart part in sog.Parts)
|
||||||
|
{
|
||||||
|
if (part.LastUpdateActorID.Equals(m_actorID))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the set of SyncConnectors to send updates of the given object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sog"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private List<SyncConnector> GetSyncConnectorsForObjectUpdates(SceneObjectGroup sog)
|
||||||
|
{
|
||||||
|
List<SyncConnector> syncConnectors = new List<SyncConnector>();
|
||||||
|
if (m_isSyncRelay)
|
||||||
|
{
|
||||||
|
//This is a relay node in the synchronization overlay, forward it to all connectors.
|
||||||
|
//Note LastUpdateTimeStamp and LastUpdateActorID is one per SceneObjectPart, not one per SceneObjectGroup,
|
||||||
|
//hence an actor sending in an update on one SceneObjectPart of a SceneObjectGroup may need to know updates
|
||||||
|
//in other parts as well, so we are sending to all connectors.
|
||||||
|
ForEachSyncConnector(delegate(SyncConnector connector)
|
||||||
|
{
|
||||||
|
syncConnectors.Add(connector);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//This is a end node in the synchronization overlay (e.g. a non ScenePersistence actor). Get the right set of synconnectors.
|
||||||
|
//This may go more complex when an actor connects to several ScenePersistence actors.
|
||||||
|
ForEachSyncConnector(delegate(SyncConnector connector)
|
||||||
|
{
|
||||||
|
syncConnectors.Add(connector);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return syncConnectors;
|
||||||
|
}
|
||||||
|
|
||||||
//NOTE: We proably don't need to do this, and there might not be a need for OnPostSceneCreation event to let RegionSyncModule
|
//NOTE: We proably don't need to do this, and there might not be a need for OnPostSceneCreation event to let RegionSyncModule
|
||||||
// and ActorSyncModules to gain some access to each other. We'll keep it here for a while, until we are sure it's not
|
// and ActorSyncModules to gain some access to each other. We'll keep it here for a while, until we are sure it's not
|
||||||
// needed.
|
// needed.
|
||||||
|
@ -526,7 +678,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
List<SyncConnector> closed = null;
|
List<SyncConnector> closed = null;
|
||||||
foreach (SyncConnector syncConnector in m_syncConnectors)
|
foreach (SyncConnector syncConnector in m_syncConnectors)
|
||||||
{
|
{
|
||||||
// If connected, send the message.
|
// If connected, apply the action
|
||||||
if (syncConnector.Connected)
|
if (syncConnector.Connected)
|
||||||
{
|
{
|
||||||
action(syncConnector);
|
action(syncConnector);
|
||||||
|
@ -584,22 +736,50 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SymmetricSyncMessage.MsgType.NewObject:
|
case SymmetricSyncMessage.MsgType.NewObject:
|
||||||
|
case SymmetricSyncMessage.MsgType.UpdatedObject:
|
||||||
{
|
{
|
||||||
string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length);
|
HandleAddOrUpdateObjectBySynchronization(msg);
|
||||||
|
//HandleAddNewObject(sog);
|
||||||
//m_log.Debug(LogHeader + ": " + sogxml);
|
return;
|
||||||
|
|
||||||
SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml);
|
|
||||||
|
|
||||||
//HandleAddOrUpdateObjectInLocalScene(sog, true, true);
|
|
||||||
HandleAddNewObject(sog);
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void HandleAddOrUpdateObjectBySynchronization(SymmetricSyncMessage msg)
|
||||||
|
{
|
||||||
|
string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length);
|
||||||
|
SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml);
|
||||||
|
|
||||||
|
if (sog.IsDeleted)
|
||||||
|
{
|
||||||
|
SymmetricSyncMessage.HandleTrivial(LogHeader, msg, String.Format("Ignoring update on deleted object, UUID: {0}.", sog.UUID));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Scene.ObjectUpdateResult updateResult = m_scene.AddOrUpdateObjectBySynchronization(sog);
|
||||||
|
|
||||||
|
//if (added)
|
||||||
|
switch (updateResult)
|
||||||
|
{
|
||||||
|
case Scene.ObjectUpdateResult.New:
|
||||||
|
m_log.DebugFormat("[{0} Object \"{1}\" ({1}) ({2}) added.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
|
||||||
|
break;
|
||||||
|
case Scene.ObjectUpdateResult.Updated:
|
||||||
|
m_log.DebugFormat("[{0} Object \"{1}\" ({1}) ({2}) updated.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
|
||||||
|
break;
|
||||||
|
case Scene.ObjectUpdateResult.Error:
|
||||||
|
m_log.WarnFormat("[{0} Object \"{1}\" ({1}) ({2}) -- add or update ERROR.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
|
||||||
|
break;
|
||||||
|
case Scene.ObjectUpdateResult.Unchanged:
|
||||||
|
m_log.DebugFormat("[{0} Object \"{1}\" ({1}) ({2}) unchanged after receiving an update.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleAddNewObject(SceneObjectGroup sog)
|
private void HandleAddNewObject(SceneObjectGroup sog)
|
||||||
{
|
{
|
||||||
//RegionSyncModule only add object to SceneGraph. Any actor specific actions will be implemented
|
//RegionSyncModule only add object to SceneGraph. Any actor specific actions will be implemented
|
||||||
|
|
|
@ -21,61 +21,22 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
public enum MsgType
|
public enum MsgType
|
||||||
{
|
{
|
||||||
Null,
|
Null,
|
||||||
//ConnectSyncClient,
|
// Actor -> SIM(Scene)
|
||||||
//DisconnectSyncClient,
|
|
||||||
// CM -> SIM(Scene)
|
|
||||||
ActorConnect,
|
|
||||||
AgentAdd,
|
|
||||||
AgentUpdate,
|
|
||||||
AgentRemove,
|
|
||||||
AgentRequestSit,
|
|
||||||
AgentSit,
|
|
||||||
GrabObject,
|
|
||||||
GrabUpdate,
|
|
||||||
DeGrabObject,
|
|
||||||
StartAnim,
|
|
||||||
StopAnim,
|
|
||||||
GetTerrain,
|
GetTerrain,
|
||||||
GetObjects,
|
GetObjects,
|
||||||
SubscribeObjects,
|
|
||||||
GetAvatars,
|
|
||||||
SubscribeAvatars,
|
|
||||||
ChatFromClient,
|
|
||||||
AvatarTeleportOut, // An LLClientView (real client) was converted to a RegionSyncAvatar
|
|
||||||
AvatarTeleportIn, // A RegionSyncAvatar was converted to an LLClientView (real client)
|
|
||||||
// SIM -> CM
|
// SIM -> CM
|
||||||
Terrain,
|
Terrain,
|
||||||
NewObject, // objects
|
NewObject, // objects
|
||||||
UpdatedObject, // objects
|
UpdatedObject, // objects
|
||||||
RemovedObject, // objects
|
RemovedObject, // objects
|
||||||
NewAvatar, // avatars
|
|
||||||
UpdatedAvatar, // avatars
|
|
||||||
AnimateAvatar,
|
|
||||||
AvatarAppearance,
|
|
||||||
RemovedAvatar, // avatars
|
|
||||||
BalanceClientLoad, // Tells CM a client load target and a place to teleport the extras
|
|
||||||
ChatFromSim,
|
|
||||||
SitResponse,
|
|
||||||
SendAnimations,
|
|
||||||
// BIDIR
|
|
||||||
EchoRequest,
|
|
||||||
EchoResponse,
|
|
||||||
RegionName,
|
|
||||||
RegionStatus,
|
|
||||||
//Added by KittyL
|
|
||||||
// Actor -> Scene
|
|
||||||
// ActorType, //to register the type (e.g. Client Manager or Script Engine) with Scene when sync channel is initialized
|
|
||||||
//SetObjectProperty,
|
|
||||||
// ActorStop,
|
|
||||||
ResetScene,
|
|
||||||
OnRezScript,
|
|
||||||
OnScriptReset,
|
|
||||||
OnUpdateScript,
|
|
||||||
//QuarkSubscription,
|
|
||||||
|
|
||||||
// Scene -> Script Engine
|
// BIDIR
|
||||||
//NewObjectWithScript,
|
//EchoRequest,
|
||||||
//SceneLocation,
|
//EchoResponse,
|
||||||
|
RegionName,
|
||||||
|
//RegionStatus,
|
||||||
|
ActorID,
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -164,27 +125,27 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
public static void HandleSuccess(string header, RegionSyncMessage msg, string message)
|
public static void HandleSuccess(string header, SymmetricSyncMessage msg, string message)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("{0} Handled {1}: {2}", header, msg.ToString(), message);
|
m_log.WarnFormat("{0} Handled {1}: {2}", header, msg.ToString(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HandleTrivial(string header, RegionSyncMessage msg, string message)
|
public static void HandleTrivial(string header, SymmetricSyncMessage msg, string message)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("{0} Issue handling {1}: {2}", header, msg.ToString(), message);
|
m_log.WarnFormat("{0} Issue handling {1}: {2}", header, msg.ToString(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HandleWarning(string header, RegionSyncMessage msg, string message)
|
public static void HandleWarning(string header, SymmetricSyncMessage msg, string message)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("{0} Warning handling {1}: {2}", header, msg.ToString(), message);
|
m_log.WarnFormat("{0} Warning handling {1}: {2}", header, msg.ToString(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HandleError(string header, RegionSyncMessage msg, string message)
|
public static void HandleError(string header, SymmetricSyncMessage msg, string message)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("{0} Error handling {1}: {2}", header, msg.ToString(), message);
|
m_log.WarnFormat("{0} Error handling {1}: {2}", header, msg.ToString(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HandlerDebug(string header, RegionSyncMessage msg, string message)
|
public static bool HandlerDebug(string header, SymmetricSyncMessage msg, string message)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("{0} DBG ({1}): {2}", header, msg.ToString(), message);
|
m_log.WarnFormat("{0} DBG ({1}): {2}", header, msg.ToString(), message);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -45,6 +45,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
get { return m_connectorNum; }
|
get { return m_connectorNum; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//the actorID of the other end of the connection
|
||||||
|
private string m_syncOtherSideActorID;
|
||||||
|
public string OtherSideActorID
|
||||||
|
{
|
||||||
|
get { return m_syncOtherSideActorID; }
|
||||||
|
set { m_syncOtherSideActorID = value; }
|
||||||
|
}
|
||||||
|
|
||||||
//The region name of the other side of the connection
|
//The region name of the other side of the connection
|
||||||
private string m_syncOtherSideRegionName="";
|
private string m_syncOtherSideRegionName="";
|
||||||
public string OtherSideRegionName
|
public string OtherSideRegionName
|
||||||
|
@ -267,6 +275,17 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
|
||||||
m_log.DebugFormat("Syncing to region \"{0}\"", m_syncOtherSideRegionName);
|
m_log.DebugFormat("Syncing to region \"{0}\"", m_syncOtherSideRegionName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case SymmetricSyncMessage.MsgType.ActorID:
|
||||||
|
{
|
||||||
|
m_syncOtherSideActorID = Encoding.ASCII.GetString(msg.Data, 0, msg.Length);
|
||||||
|
if (m_regionSyncModule.IsSyncRelay)
|
||||||
|
{
|
||||||
|
SymmetricSyncMessage outMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.ActorID, m_regionSyncModule.ActorID);
|
||||||
|
Send(outMsg);
|
||||||
|
}
|
||||||
|
m_log.DebugFormat("Syncing to actor \"{0}\"", m_syncOtherSideActorID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -598,6 +598,29 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//This enumeration would help to identify if after a NewObject/UpdatedObject message is received,
|
||||||
|
//the object is a new object and hence added to the scene graph, or it an object with some properties
|
||||||
|
//just updated, or the copy of the object in the UpdatedObject message is the same with local copy
|
||||||
|
//(before we add time-stamp to identify updates from different actors/scene, it could be possible the same
|
||||||
|
//update be forwarded, say from script engine to scene, and then back to script engine.
|
||||||
|
public enum ObjectUpdateResult
|
||||||
|
{
|
||||||
|
New, //the New/UpdatedObject message ends up adding a new object to local scene graph
|
||||||
|
Updated, //the object has some property updated after processing the New/UpdatedObject
|
||||||
|
Unchanged, //no property of the object has been changed after processing the New/UpdatedObject
|
||||||
|
//(it probably is the same update this end has sent out before
|
||||||
|
Error //Errors happen during processing the message, e.g. the entity with the given UUID is not of type SceneObjectGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
//This function should only be called by an actor who's local Scene is just a cache of the authorative Scene.
|
||||||
|
//If the object already exists, use the new copy to replace it.
|
||||||
|
//Return true if added, false if just updated
|
||||||
|
public ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup sog)
|
||||||
|
{
|
||||||
|
return m_sceneGraph.AddOrUpdateObjectBySynchronization(sog);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion //SYMMETRIC SYNC
|
#endregion //SYMMETRIC SYNC
|
||||||
|
|
||||||
public ICapabilitiesModule CapsModule
|
public ICapabilitiesModule CapsModule
|
||||||
|
@ -1484,24 +1507,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_regionSyncServerModule.SendUpdates();
|
m_regionSyncServerModule.SendUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
//SYMMETRIC SYNC
|
||||||
// The authoritative sim should not try to send coarse locations
|
|
||||||
// Leave this up to the client managers
|
//NOTE: If it is configured as symmetric sync in opensim.ini, the above IsSyncedServer() or IsSyncedClient() should all return false
|
||||||
if (!IsSyncedServer())
|
if (RegionSyncModule != null)
|
||||||
{
|
{
|
||||||
if (m_frame % m_update_coarse_locations == 0)
|
RegionSyncModule.SendSceneUpdates();
|
||||||
{
|
|
||||||
List<Vector3> coarseLocations;
|
|
||||||
List<UUID> avatarUUIDs;
|
|
||||||
SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60);
|
|
||||||
// Send coarse locations to clients
|
|
||||||
ForEachScenePresence(delegate(ScenePresence presence)
|
|
||||||
{
|
|
||||||
presence.SendCoarseLocations(coarseLocations, avatarUUIDs);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
* */
|
//end of SYMMETRIC SYNC
|
||||||
|
|
||||||
int tmpPhysicsMS2 = Util.EnvironmentTickCount();
|
int tmpPhysicsMS2 = Util.EnvironmentTickCount();
|
||||||
// Do not simulate physics locally if this is a synced client
|
// Do not simulate physics locally if this is a synced client
|
||||||
|
|
|
@ -1920,10 +1920,105 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion // REGION SYNC
|
||||||
|
|
||||||
|
#region SYMMETRIC SYNC
|
||||||
|
|
||||||
|
public Scene.ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup updatedSog)
|
||||||
|
{
|
||||||
|
UUID sogID = updatedSog.UUID;
|
||||||
|
|
||||||
|
if (Entities.ContainsKey(sogID))
|
||||||
|
{
|
||||||
|
//update the object
|
||||||
|
EntityBase entity = Entities[sogID];
|
||||||
|
if (entity is SceneObjectGroup)
|
||||||
|
{
|
||||||
|
SceneObjectGroup localSog = (SceneObjectGroup)entity;
|
||||||
|
Scene.ObjectUpdateResult updateResult = localSog.UpdateObjectAllProperties(updatedSog);
|
||||||
|
return updateResult;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Warn("Entity with " + sogID + " is not of type SceneObjectGroup");
|
||||||
|
//return false;
|
||||||
|
return Scene.ObjectUpdateResult.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddSceneObjectByStateSynch(updatedSog);
|
||||||
|
return Scene.ObjectUpdateResult.New;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//This is an object added due to receiving a state synchronization message from Scene or an actor. Do similar things as the original AddSceneObject(),
|
||||||
|
//but call ScheduleGroupForFullUpdate_TimeStampUnchanged() instead, so as not to modify the timestamp or actorID, since the object was not created
|
||||||
|
//locally.
|
||||||
|
protected bool AddSceneObjectByStateSynch(SceneObjectGroup sceneObject)
|
||||||
|
{
|
||||||
|
if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Entities.ContainsKey(sceneObject.UUID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SceneObjectPart[] children = sceneObject.Parts;
|
||||||
|
|
||||||
|
// Clamp child prim sizes and add child prims to the m_numPrim count
|
||||||
|
if (m_parentScene.m_clampPrimSize)
|
||||||
|
{
|
||||||
|
foreach (SceneObjectPart part in children)
|
||||||
|
{
|
||||||
|
Vector3 scale = part.Shape.Scale;
|
||||||
|
|
||||||
|
if (scale.X > m_parentScene.m_maxNonphys)
|
||||||
|
scale.X = m_parentScene.m_maxNonphys;
|
||||||
|
if (scale.Y > m_parentScene.m_maxNonphys)
|
||||||
|
scale.Y = m_parentScene.m_maxNonphys;
|
||||||
|
if (scale.Z > m_parentScene.m_maxNonphys)
|
||||||
|
scale.Z = m_parentScene.m_maxNonphys;
|
||||||
|
|
||||||
|
part.Shape.Scale = scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_numPrim += children.Length;
|
||||||
|
|
||||||
|
sceneObject.AttachToScene(m_parentScene);
|
||||||
|
|
||||||
|
//SYMMETRIC SYNC,
|
||||||
|
sceneObject.ScheduleGroupForFullUpdate_SyncInfoUnchanged();
|
||||||
|
//end of SYMMETRIC SYNC,
|
||||||
|
|
||||||
|
Entities.Add(sceneObject);
|
||||||
|
|
||||||
|
//ScenePersistenceSyncModule will attach the object to backup when it catches the OnObjectCreate event.
|
||||||
|
//if (attachToBackup)
|
||||||
|
// sceneObject.AttachToBackup();
|
||||||
|
|
||||||
|
if (OnObjectCreate != null)
|
||||||
|
OnObjectCreate(sceneObject);
|
||||||
|
|
||||||
|
lock (SceneObjectGroupsByFullID)
|
||||||
|
{
|
||||||
|
SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
|
||||||
|
foreach (SceneObjectPart part in children)
|
||||||
|
SceneObjectGroupsByFullID[part.UUID] = sceneObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (SceneObjectGroupsByLocalID)
|
||||||
|
{
|
||||||
|
SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject;
|
||||||
|
foreach (SceneObjectPart part in children)
|
||||||
|
SceneObjectGroupsByLocalID[part.LocalId] = sceneObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion //SYMMETRIC SYNC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3459,6 +3459,141 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
#region SYMMETRIC SYNC
|
#region SYMMETRIC SYNC
|
||||||
|
|
||||||
|
//update the existing copy of the object with updated properties in 'updatedSog'
|
||||||
|
//NOTE: updates on script content are handled seperately (e.g. user edited the script and saved it) -- SESyncServerOnUpdateScript(), a handler of EventManager.OnUpdateScript
|
||||||
|
//public void UpdateObjectProperties(SceneObjectGroup updatedSog)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the existing copy of the object with updated properties in 'updatedSog'. For now we update
|
||||||
|
/// all properties. Later on this should be edited to allow only updating a bucket of properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updatedSog"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Scene.ObjectUpdateResult UpdateObjectAllProperties(SceneObjectGroup updatedSog)
|
||||||
|
{
|
||||||
|
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<UUID, SceneObjectPart> updatedParts = new Dictionary<UUID, SceneObjectPart>();
|
||||||
|
bool partsRemoved = false; //has any old part been removed?
|
||||||
|
bool rootPartChanged = false; //has the rootpart be changed to a different prim?
|
||||||
|
|
||||||
|
lock (m_parts)
|
||||||
|
{
|
||||||
|
//update rootpart, if changed
|
||||||
|
if (m_rootPart.UUID != updatedSog.RootPart.UUID)
|
||||||
|
{
|
||||||
|
m_rootPart = updatedSog.RootPart;
|
||||||
|
rootPartChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//foreach (KeyValuePair<UUID, SceneObjectPart> pair in updatedSog.Parts)
|
||||||
|
foreach (SceneObjectPart updatedPart in updatedSog.Parts)
|
||||||
|
{
|
||||||
|
UUID partUUID = updatedPart.UUID;
|
||||||
|
Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged;
|
||||||
|
if (HasChildPrim(partUUID))
|
||||||
|
{
|
||||||
|
//update the existing part
|
||||||
|
SceneObjectPart oldPart = GetChildPart(partUUID);
|
||||||
|
partUpdateResult = oldPart.UpdateAllProperties(updatedPart);
|
||||||
|
updatedParts.Add(partUUID, updatedPart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//a new part
|
||||||
|
//m_parts.Add(partUUID, updatedPart);
|
||||||
|
AddPart(updatedPart);
|
||||||
|
partUpdateResult = Scene.ObjectUpdateResult.New;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partUpdateResult != Scene.ObjectUpdateResult.Unchanged)
|
||||||
|
{
|
||||||
|
if (partUpdateResult == Scene.ObjectUpdateResult.New)
|
||||||
|
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
|
||||||
|
else
|
||||||
|
groupUpdateResult = partUpdateResult; //Error or Updated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//For any parts that are not in the updatesParts (the old parts that are still in updatedSog), delete them.
|
||||||
|
foreach (SceneObjectPart oldPart in this.Parts)
|
||||||
|
{
|
||||||
|
if (!updatedParts.ContainsKey(oldPart.UUID))
|
||||||
|
{
|
||||||
|
m_parts.Remove(oldPart.UUID);
|
||||||
|
partsRemoved = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update the rootpart's ID in each non root parts
|
||||||
|
if (rootPartChanged)
|
||||||
|
{
|
||||||
|
UpdateParentIDs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partsRemoved)
|
||||||
|
{
|
||||||
|
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//update the authoritative scene that this object is located, which is identified by (LocX, LocY)
|
||||||
|
if (this.m_locX != updatedSog.LocX)
|
||||||
|
{
|
||||||
|
this.m_locX = updatedSog.LocX;
|
||||||
|
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
|
||||||
|
}
|
||||||
|
if (this.m_locY != updatedSog.LocY)
|
||||||
|
{
|
||||||
|
this.m_locY = updatedSog.LocY;
|
||||||
|
groupUpdateResult = Scene.ObjectUpdateResult.Updated;
|
||||||
|
}
|
||||||
|
* */
|
||||||
|
|
||||||
|
//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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupUpdateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleGroupForFullUpdate_SyncInfoUnchanged()
|
||||||
|
{
|
||||||
|
if (IsAttachment)
|
||||||
|
m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
|
||||||
|
|
||||||
|
checkAtTargets();
|
||||||
|
RootPart.ScheduleFullUpdate_SyncInfoUnchanged();
|
||||||
|
|
||||||
|
lock (m_parts)
|
||||||
|
{
|
||||||
|
foreach (SceneObjectPart part in this.Parts)
|
||||||
|
{
|
||||||
|
if (part != RootPart)
|
||||||
|
part.ScheduleFullUpdate_SyncInfoUnchanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3147,6 +3147,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
//SYMMETRIC SYNC
|
//SYMMETRIC SYNC
|
||||||
|
|
||||||
|
m_parentGroup.Scene.RegionSyncModule.QueueSceneObjectPartForUpdate(this);
|
||||||
|
|
||||||
//end of SYMMETRIC SYNC
|
//end of SYMMETRIC SYNC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4962,6 +4964,158 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//!!!!!! -- TODO:
|
||||||
|
//!!!!!! -- We should call UpdateXXX functions to update each property, cause some of such updates involves sanity checking.
|
||||||
|
public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart)
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//NOTE!!!: So far this function is written with Script Engine updating local Scene cache in mind.
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
////////////////////Assumptions: ////////////////////
|
||||||
|
//(1) prim's UUID and LocalID shall not change (UUID is the unique identifies, LocalID is used to refer to the prim by, say scripts)
|
||||||
|
//(2) RegionHandle won't be updated -- each copy of Scene is hosted on a region with different region handle
|
||||||
|
//(3) ParentID won't be updated -- if the rootpart of the SceneObjectGroup changed, that will be updated in SceneObjectGroup.UpdateObjectProperties
|
||||||
|
|
||||||
|
////////////////////Furture enhancements:////////////////////
|
||||||
|
//For now, we only update the set of properties that are included in serialization.
|
||||||
|
//See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart.
|
||||||
|
//Later on, we may implement update functions that allow updating certain properties or certain buckets of properties.
|
||||||
|
|
||||||
|
if (updatedPart == null)
|
||||||
|
return Scene.ObjectUpdateResult.Error;
|
||||||
|
|
||||||
|
if (m_lastUpdateTimeStamp > updatedPart.LastUpdateTimeStamp)
|
||||||
|
{
|
||||||
|
//Our timestamp is more update to date, keep our values of the properties. Do not update anything.
|
||||||
|
return Scene.ObjectUpdateResult.Unchanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_lastUpdateTimeStamp == updatedPart.LastUpdateTimeStamp)
|
||||||
|
{
|
||||||
|
//if (m_parentGroup.Scene.GetActorID() != updatedPart.LastUpdatedByActorID)
|
||||||
|
if (m_lastUpdateByActorID != updatedPart.LastUpdateActorID)
|
||||||
|
{
|
||||||
|
m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp, CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!");
|
||||||
|
return Scene.ObjectUpdateResult.Unchanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
//My own update was relayed back. Don't relay it.
|
||||||
|
return Scene.ObjectUpdateResult.Unchanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Otherwise, our timestamp is less up to date, update the prim with the received copy
|
||||||
|
|
||||||
|
Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Updated;
|
||||||
|
|
||||||
|
//See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart.
|
||||||
|
this.AllowedDrop = updatedPart.AllowedDrop;
|
||||||
|
this.CreatorID = updatedPart.CreatorID;
|
||||||
|
this.CreatorData = updatedPart.CreatorData;
|
||||||
|
this.FolderID = updatedPart.FolderID;
|
||||||
|
this.InventorySerial = updatedPart.InventorySerial;
|
||||||
|
this.TaskInventory = updatedPart.TaskInventory;
|
||||||
|
//Following two properties, UUID and LocalId, shall not be updated.
|
||||||
|
//this.UUID
|
||||||
|
//this.LocalId
|
||||||
|
this.Name = updatedPart.Name;
|
||||||
|
this.Material = updatedPart.Material;
|
||||||
|
this.PassTouches = updatedPart.PassTouches;
|
||||||
|
//RegionHandle shall not be copied, since updatedSog is sent by a different actor, which has a different local region
|
||||||
|
//this.RegionHandle
|
||||||
|
this.ScriptAccessPin = updatedPart.ScriptAccessPin;
|
||||||
|
this.GroupPosition = updatedPart.GroupPosition;
|
||||||
|
this.OffsetPosition = updatedPart.OffsetPosition;
|
||||||
|
this.RotationOffset = updatedPart.RotationOffset;
|
||||||
|
this.Velocity = updatedPart.Velocity;
|
||||||
|
this.AngularVelocity = updatedPart.AngularVelocity;
|
||||||
|
this.Acceleration = updatedPart.Acceleration;
|
||||||
|
this.Description = updatedPart.Description;
|
||||||
|
this.Color = updatedPart.Color;
|
||||||
|
this.Text = updatedPart.Text;
|
||||||
|
this.SitName = updatedPart.SitName;
|
||||||
|
this.TouchName = updatedPart.TouchName;
|
||||||
|
this.LinkNum = updatedPart.LinkNum;
|
||||||
|
this.ClickAction = updatedPart.ClickAction;
|
||||||
|
this.Shape = updatedPart.Shape;
|
||||||
|
this.Scale = updatedPart.Scale;
|
||||||
|
this.UpdateFlag = updatedPart.UpdateFlag;
|
||||||
|
this.SitTargetOrientation = updatedPart.SitTargetOrientation;
|
||||||
|
this.SitTargetPosition = updatedPart.SitTargetPosition;
|
||||||
|
this.SitTargetPositionLL = updatedPart.SitTargetPositionLL;
|
||||||
|
this.SitTargetOrientationLL = updatedPart.SitTargetOrientationLL;
|
||||||
|
//ParentID should still point to the rootpart in the local sog, do not update. If the root part changed, we will update it in SceneObjectGroup.UpdateObjectProperties()
|
||||||
|
//this.ParentID;
|
||||||
|
this.CreationDate = updatedPart.CreationDate;
|
||||||
|
this.Category = updatedPart.Category;
|
||||||
|
this.SalePrice = updatedPart.SalePrice;
|
||||||
|
this.ObjectSaleType = updatedPart.ObjectSaleType;
|
||||||
|
this.OwnershipCost = updatedPart.OwnershipCost;
|
||||||
|
this.GroupID = updatedPart.GroupID;
|
||||||
|
this.OwnerID = updatedPart.OwnerID;
|
||||||
|
this.LastOwnerID = updatedPart.LastOwnerID;
|
||||||
|
this.BaseMask = updatedPart.BaseMask;
|
||||||
|
this.OwnerMask = updatedPart.OwnerMask;
|
||||||
|
this.GroupMask = updatedPart.GroupMask;
|
||||||
|
this.EveryoneMask = updatedPart.EveryoneMask;
|
||||||
|
this.NextOwnerMask = updatedPart.NextOwnerMask;
|
||||||
|
this.Flags = updatedPart.Flags;
|
||||||
|
this.CollisionSound = updatedPart.CollisionSound;
|
||||||
|
this.CollisionSoundVolume = updatedPart.CollisionSoundVolume;
|
||||||
|
this.MediaUrl = updatedPart.MediaUrl;
|
||||||
|
this.TextureAnimation = updatedPart.TextureAnimation;
|
||||||
|
this.ParticleSystem = updatedPart.ParticleSystem;
|
||||||
|
|
||||||
|
//Update the timestamp and LastUpdatedByActorID first.
|
||||||
|
this.m_lastUpdateByActorID = updatedPart.LastUpdateActorID;
|
||||||
|
this.m_lastUpdateTimeStamp = updatedPart.LastUpdateTimeStamp;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
this.m_inventory.Items = (TaskInventoryDictionary)updatedPart.m_inventory.Items.Clone();
|
||||||
|
//update shape information, for now, only update fileds in Shape whose set functions are defined in PrimitiveBaseShape
|
||||||
|
this.Shape = updatedPart.Shape.Copy();
|
||||||
|
this.Shape.TextureEntry = updatedPart.Shape.TextureEntry;
|
||||||
|
* */
|
||||||
|
|
||||||
|
return partUpdateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Schedules this prim for a full update, without changing the timestamp or actorID (info on when and who modified any property).
|
||||||
|
/// NOTE: this is the same as the original SceneObjectPart.ScheduleFullUpdate().
|
||||||
|
/// </summary>
|
||||||
|
public void ScheduleFullUpdate_SyncInfoUnchanged()
|
||||||
|
{
|
||||||
|
// m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue