Fixed terrain synchroniztion to work properly when clients edit the terrain via viewer.

dsg
Huaiyu (Kitty) Liu 2011-03-28 17:22:24 -07:00
parent 0ad9366abb
commit eed53e8a56
6 changed files with 122 additions and 29 deletions

View File

@ -393,18 +393,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//The following Sendxxx calls,send out a message immediately, w/o putting it in the SyncConnector's outgoing queue.
//May need some optimization there on the priorities.
public void SendTerrainUpdates(string lastUpdateActorID)
public void SendTerrainUpdates(long updateTimeStamp, string lastUpdateActorID)
{
if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
if(m_isSyncRelay || m_actorID.Equals(lastUpdateActorID))
if (m_isSyncRelay || m_actorID.Equals(lastUpdateActorID))
{
//m_scene.Heightmap should have been updated already by the caller, send it out
//SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString());
SendTerrainUpdateMessage();
SendTerrainUpdateMessage(updateTimeStamp, lastUpdateActorID);
}
}
@ -804,6 +804,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
data["actorID"] = OSD.FromString(lastUpdateActorID);
data["timeStamp"] = OSD.FromLong(lastUpdateTimeStamp);
//m_log.DebugFormat("{0}: Send out terrain with TS {1}, actorID {2}", LogHeader, lastUpdateTimeStamp, lastUpdateActorID);
SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data));
connector.Send(syncMsg);
}
@ -1051,6 +1053,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
return (m_syncConnectors.Count > 0);
}
private void SendTerrainUpdateToRelevantSyncConnectors(SymmetricSyncMessage syncMsg, string lastUpdateActorID)
{
List<SyncConnector> syncConnectors = GetSyncConnectorsForSceneEvents(lastUpdateActorID, syncMsg, null);
foreach (SyncConnector connector in syncConnectors)
{
m_log.DebugFormat("{0}: Send terrain update to {1}", LogHeader, connector.OtherSideActorID);
connector.Send(syncMsg);
}
}
//Object updates are sent by enqueuing into each connector's outQueue.
private void SendObjectUpdateToRelevantSyncConnectors(SceneObjectGroup sog, SymmetricSyncMessage syncMsg)
{
@ -1761,13 +1775,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
}
string msgData = data["terrain"].AsString();
long lastUpdateTimeStamp = data["actorID"].AsLong();
string lastUpdateActorID = data["timeStamp"].AsString();
long lastUpdateTimeStamp = data["timeStamp"].AsLong();
string lastUpdateActorID = data["actorID"].AsString();
//set new terrain
m_scene.Heightmap.LoadFromXmlString(msgData);
m_scene.RequestModuleInterface<ITerrainModule>().TaintTerrianBySynchronization(lastUpdateTimeStamp, lastUpdateActorID); ;
m_log.DebugFormat("{0} : Synchronized terrain", LogHeader);
//m_log.DebugFormat("{0}: received Terrain update msg, with TS {1}, actorID {2}",LogHeader, lastUpdateTimeStamp, lastUpdateActorID);
//update the terrain if the incoming terrain data has an more recent timestamp
if (m_scene.RequestModuleInterface<ITerrainModule>().UpdateTerrianBySync(lastUpdateTimeStamp, lastUpdateActorID, msgData))
{
//m_scene.Heightmap.LoadFromXmlString(msgData);
//CheckForTerrainUpdates(false, timeStamp, actorID);
m_log.DebugFormat("{0} : Synchronized terrain", LogHeader);
}
}
private void HandleAddNewObject(SymmetricSyncMessage msg, string senderActorID)
@ -1912,19 +1931,30 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
m_scene.UpdateObjectPartBucketProperties(bucketName, partUUID, data, rBucketSyncInfo);
}
private void SendTerrainUpdateMessage()
/// <summary>
/// Send out a sync message about the updated Terrain. If this is a relay node,
/// forward the sync message to all connectors except the one which initiated
/// the update.
/// </summary>
/// <param name="lastUpdateTimeStamp"></param>
/// <param name="lastUpdateActorID"></param>
private void SendTerrainUpdateMessage(long lastUpdateTimeStamp, string lastUpdateActorID)
{
string msgData = m_scene.Heightmap.SaveToXmlString();
long lastUpdateTimeStamp;
string lastUpdateActorID;
m_scene.RequestModuleInterface<ITerrainModule>().GetSyncInfo(out lastUpdateTimeStamp, out lastUpdateActorID);
//long lastUpdateTimeStamp;
//string lastUpdateActorID;
//m_scene.RequestModuleInterface<ITerrainModule>().GetSyncInfo(out lastUpdateTimeStamp, out lastUpdateActorID);
OSDMap data = new OSDMap(3);
data["terrain"] = OSD.FromString(msgData);
data["actorID"] = OSD.FromString(lastUpdateActorID);
data["timeStamp"] = OSD.FromLong(lastUpdateTimeStamp);
SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data));
//m_log.DebugFormat("{0}: Ready to send terrain update with lastUpdateTimeStamp {1} and lastUpdateActorID {2}", LogHeader, lastUpdateTimeStamp, lastUpdateActorID);
SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data));
SendTerrainUpdateToRelevantSyncConnectors(syncMsg, lastUpdateActorID);
//SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data));
}

View File

@ -105,7 +105,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//InstallInterfaces();
//Register for the OnPostSceneCreation event
//m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation;
m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation;
//Register for Scene/SceneGraph events
m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScenePersistence_OnObjectCreate);
@ -177,6 +177,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//If this is the local scene the actor is working on, do something
if (createdScene == m_scene)
{
m_scene.RequestModuleInterface<ITerrainModule>().SetSyncInfo(DateTime.Now.Ticks, m_scene.GetSyncActorID());
}
}

View File

@ -241,9 +241,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
}
}, null);
}
catch (IOException)
catch (Exception e)
{
m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum);
m_log.WarnFormat("{0}:Error in Send() {1} has disconnected -- error message: {2}.", Description, m_connectorNum, e.Message);
}
}
}
@ -264,10 +264,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//m_log.WarnFormat("{0} Received: {1}", LogHeader, msg.ToString());
}
// If there is a problem reading from the client, shut 'er down.
catch
catch (Exception e)
{
//ShutdownClient();
m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum);
m_log.WarnFormat("{0}: ReceiveLoop error {1} has disconnected -- error message {2}.", Description, m_connectorNum, e.Message);
Shutdown();
return;
}
@ -281,7 +281,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
m_log.WarnFormat("{0} Encountered an exception: {1} (MSGTYPE = {2})", Description, e.Message, msg.ToString());
}
}
}
}
private void HandleMessage(SymmetricSyncMessage msg)
{

View File

@ -551,6 +551,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
m_scene.SaveTerrain();
//SYMMETRIC 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
// 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);
}
@ -610,12 +619,41 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{
m_lastUpdateTimeStamp = timeStamp;
m_lastUpdateActorID = actorID;
// m_log.DebugFormat("TerrainModule: updated syncinfo -- TS {0}, actorID {1}", m_lastUpdateTimeStamp, m_lastUpdateActorID);
}
public void TaintTerrianBySynchronization(long timeStamp, string actorID)
/// <summary>
/// Invoked by receiving a terrain sync message. First, check if the
/// timestamp is more advance than the local copy. If so, update the
/// local terrain copy, update the sync info (timestamp and actorID).
/// <param name="timeStamp"></param>
/// <param name="actorID"></param>
/// <param name="terrainData"></param>
/// <returns></returns>
public bool UpdateTerrianBySync(long timeStamp, string actorID, string terrainData)
{
SyncInfoUpdate(timeStamp, actorID);
CheckForTerrainUpdates(false, timeStamp, actorID);
if (timeStamp > m_lastUpdateTimeStamp)
{
if (actorID.Equals(m_lastUpdateActorID) && actorID.Equals(m_scene.GetSyncActorID()))
{
m_log.WarnFormat("TerrainModule: Received a Terrain sync message with a more recent timestamp, HOWEVER, actorID on the update is the same with local acotrID ({0})",
actorID);
}
//SyncInfoUpdate(timeStamp, actorID);
//m_log.DebugFormat("TerrainModule: to copy new terrain data with TS {0}, actorID {1}", timeStamp, actorID);
m_scene.Heightmap.LoadFromXmlString(terrainData);
CheckForTerrainUpdates(false, timeStamp, actorID);
return true;
}
else if ((timeStamp == m_lastUpdateTimeStamp) && !actorID.Equals(m_lastUpdateActorID))
{
m_log.WarnFormat("TerrainModule: actors {0} and {1} have edited terrain with the same timestamp, TO DE DONE: need to pick a winner.",
actorID, m_lastUpdateActorID);
}
return false;
}
public bool TerrianModifiedLocally(string localActorID)
@ -631,6 +669,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
lastUpdateActorID = m_lastUpdateActorID;
}
public void SetSyncInfo(long lastUpdateTimeStamp, string lastUpdateActorID)
{
m_lastUpdateTimeStamp = lastUpdateTimeStamp;
m_lastUpdateActorID = lastUpdateActorID;
}
//end of SYMMETRIC SYNC
/// <summary>
@ -641,14 +685,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void CheckForTerrainUpdates()
{
//SYMMETRIC 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.
//Update the timestamp to the current time tick, and set the LastUpdateActorID to be self
long currentTimeTick = DateTime.Now.Ticks;
string localActorID = m_scene.GetSyncActorID();
SyncInfoUpdate(currentTimeTick, localActorID);
//SyncInfoUpdate(currentTimeTick, localActorID);
//Check if the terrain has been modified and send out sync message if modified.
CheckForTerrainUpdates(false, currentTimeTick, localActorID);
@ -698,10 +742,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{
m_tainted = true;
//SYMMETRIC SYNC
//Terrain has been modified, send out sync message if needed
//Terrain has been modified, updated the sync info
if (m_scene.RegionSyncModule != null)
{
m_scene.RegionSyncModule.SendTerrainUpdates(m_lastUpdateActorID);
SyncInfoUpdate(lastUpdateTimeStamp, lastUpdateActorID);
m_scene.RegionSyncModule.SendTerrainUpdates(lastUpdateTimeStamp, lastUpdateActorID);
}
//end of SYMMETRIC SYNC
}

View File

@ -80,7 +80,7 @@ namespace OpenSim.Region.Framework.Interfaces
//In RegionSyncModule's implementation,
//The following calls send out a message immediately, w/o putting it in the SyncConnector's outgoing queue.
//May need some optimization there on the priorities.
void SendTerrainUpdates(string lastUpdateActorID);
void SendTerrainUpdates(long updateTimeStamp, string lastUpdateActorID);
//For propogating scene events to other actors
void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs);

View File

@ -66,7 +66,16 @@ namespace OpenSim.Region.Framework.Interfaces
void UndoTerrain(ITerrainChannel channel);
//SYMMETRIC SYNC
void TaintTerrianBySynchronization(long timeStamp, string actorID);
/// <summary>
/// Invoked by receiving a terrain sync message. First, check if the
/// timestamp is more advance than the local copy. If so, update the
/// local terrain copy.
/// </summary>
/// <param name="timeStamp">The time that the updated terrain was
/// created</param>
/// <param name="actorID">The actor who created the update.</param>
/// <param name="terrainData">The updated terrain</param>
bool UpdateTerrianBySync(long timeStamp, string actorID, string terrainData);
/// <summary>
/// Return true if the most recent update on terrain is done locally (i.e. not by receiving a terrain-sync message).
/// </summary>
@ -79,6 +88,14 @@ namespace OpenSim.Region.Framework.Interfaces
/// <param name="lastUpdateTimeStamp"></param>
/// <param name="lastUpdateActorID"></param>
void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID);
/// <summary>
/// This is only supposed to be called by Persistence actor, which will
/// set the timestamp and actorID values for terrain upon initialization time.
/// </summary>
/// <param name="lastUpdateTimeStamp"></param>
/// <param name="lastUpdateActorID"></param>
void SetSyncInfo(long lastUpdateTimeStamp, string lastUpdateActorID);
//end of SYMMETRIC SYNC
}
}