Merge branch 'master' of ssh://3dhosting.de/var/git/careminster

avinationmerge
Melanie 2013-03-23 11:31:34 +01:00
commit 8bc43ea773
25 changed files with 679 additions and 156 deletions

View File

@ -561,45 +561,59 @@ namespace OpenSim.Framework
if (attachpoint == 0) if (attachpoint == 0)
return false; return false;
if (item == UUID.Zero) lock (m_attachments)
{ {
lock (m_attachments) if (item == UUID.Zero)
{ {
if (m_attachments.ContainsKey(attachpoint)) if (m_attachments.ContainsKey(attachpoint))
{ {
m_attachments.Remove(attachpoint); m_attachments.Remove(attachpoint);
return true; return true;
} }
return false;
}
// When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
// the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
// we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
// later fail unless the attachment is detached and reattached.
//
// Therefore, we will carry on with the set if the existing attachment has no asset id.
AvatarAttachment existingAttachment = GetAttachmentForItem(item);
if (existingAttachment != null)
{
// m_log.DebugFormat(
// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}",
// existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint);
if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F))
{
m_log.DebugFormat(
"[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}",
item, attachpoint);
return false;
}
else
{
// Remove it here so that the later append does not add a second attachment but we still update
// the assetID
DetachAttachment(existingAttachment.ItemID);
}
} }
return false; // check if this is an append or a replace, 0x80 marks it as an append
} if ((attachpoint & 0x80) > 0)
{
// When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, // strip the append bit
// the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If int point = attachpoint & 0x7F;
// we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments AppendAttachment(new AvatarAttachment(point, item, asset));
// later fail unless the attachment is detached and reattached. }
// else
// Therefore, we will carry on with the set if the existing attachment has no asset id. {
AvatarAttachment existingAttachment = GetAttachmentForItem(item); ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
if (existingAttachment != null }
&& existingAttachment.AssetID != UUID.Zero
&& existingAttachment.AttachPoint == (attachpoint & 0x7F))
{
// m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item);
return false;
}
// check if this is an append or a replace, 0x80 marks it as an append
if ((attachpoint & 0x80) > 0)
{
// strip the append bit
int point = attachpoint & 0x7F;
AppendAttachment(new AvatarAttachment(point, item, asset));
}
else
{
ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
} }
return true; return true;
@ -648,6 +662,10 @@ namespace OpenSim.Framework
int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
if (index >= 0) if (index >= 0)
{ {
// m_log.DebugFormat(
// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}",
// m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint);
// Remove it from the list of attachments at that attach point // Remove it from the list of attachments at that attach point
m_attachments[kvp.Key].RemoveAt(index); m_attachments[kvp.Key].RemoveAt(index);

View File

@ -359,8 +359,9 @@ Asset service request failures: {3}" + Environment.NewLine,
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
/* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by
* the two formatted printouts above.
SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats; SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats;
if (StatsManager.TryGetStats("scene", out sceneStats)) if (StatsManager.TryGetStats("scene", out sceneStats))
{ {
foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats) foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats)
@ -374,6 +375,7 @@ Asset service request failures: {3}" + Environment.NewLine,
} }
} }
} }
*/
/* /*
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);

View File

@ -369,8 +369,7 @@ namespace OpenSim.Region.CoreModules.Asset
AssetBase asset = null; AssetBase asset = null;
string filename = GetFileName(id); string filename = GetFileName(id);
while (File.Exists(filename))
if (File.Exists(filename))
{ {
FileStream stream = null; FileStream stream = null;
try try
@ -381,6 +380,8 @@ namespace OpenSim.Region.CoreModules.Asset
asset = (AssetBase)bformatter.Deserialize(stream); asset = (AssetBase)bformatter.Deserialize(stream);
m_DiskHits++; m_DiskHits++;
break;
} }
catch (System.Runtime.Serialization.SerializationException e) catch (System.Runtime.Serialization.SerializationException e)
{ {
@ -393,12 +394,24 @@ namespace OpenSim.Region.CoreModules.Asset
// {different version of AssetBase} -- we should attempt to // {different version of AssetBase} -- we should attempt to
// delete it and re-cache // delete it and re-cache
File.Delete(filename); File.Delete(filename);
break;
}
catch (IOException e)
{
// This is a sharing violation: File exists but can't be opened because it's
// being written
Thread.Sleep(100);
continue;
} }
catch (Exception e) catch (Exception e)
{ {
m_log.WarnFormat( m_log.WarnFormat(
"[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
filename, id, e.Message, e.StackTrace); filename, id, e.Message, e.StackTrace);
break;
} }
finally finally
{ {

View File

@ -573,8 +573,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
} }
// m_log.DebugFormat( // m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}", // "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
// so.Name, so.LocalId, sp.Name, m_scene.Name); // so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
// Scripts MUST be snapshotted before the object is // Scripts MUST be snapshotted before the object is
// removed from the scene because doing otherwise will // removed from the scene because doing otherwise will

View File

@ -829,7 +829,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager);
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
List<TestClient> destinationTestClients = new List<TestClient>();
EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
@ -848,7 +854,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
teleportLookAt, teleportLookAt,
(uint)TeleportFlags.ViaLocation); (uint)TeleportFlags.ViaLocation);
((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); destinationTestClients[0].CompleteMovement();
// Check attachments have made it into sceneB // Check attachments have made it into sceneB
ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);

View File

@ -361,7 +361,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
public void QueueAppearanceSave(UUID agentid) public void QueueAppearanceSave(UUID agentid)
{ {
// m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); // m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
// 10000 ticks per millisecond, 1000 milliseconds per second // 10000 ticks per millisecond, 1000 milliseconds per second
long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
@ -658,7 +658,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
return; return;
} }
// m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); // m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
// This could take awhile since it needs to pull inventory // This could take awhile since it needs to pull inventory
// We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape // We need to do it at the point of save so that there is a sufficient delay for any upload of new body part/shape
@ -667,6 +667,14 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// multiple save requests. // multiple save requests.
SetAppearanceAssets(sp.UUID, sp.Appearance); SetAppearanceAssets(sp.UUID, sp.Appearance);
// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
// foreach (AvatarAttachment att in attachments)
// {
// m_log.DebugFormat(
// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
// sp.Name, att.ItemID, att.AttachPoint);
// }
m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
// Trigger this here because it's the final step in the set/queue/save process for appearance setting. // Trigger this here because it's the final step in the set/queue/save process for appearance setting.

View File

@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
// If camera is moved into client, then camera position can be used // If camera is moved into client, then camera position can be used
// MT: No, it can't, as chat is heard from the avatar position, not // MT: No, it can't, as chat is heard from the avatar position, not
// the camera position. // the camera position.
s.ForEachRootScenePresence( s.ForEachScenePresence(
delegate(ScenePresence presence) delegate(ScenePresence presence)
{ {
if (destination != UUID.Zero && presence.UUID != destination) if (destination != UUID.Zero && presence.UUID != destination)

View File

@ -167,6 +167,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (!DisableInterRegionTeleportCancellation) if (!DisableInterRegionTeleportCancellation)
client.OnTeleportCancel += OnClientCancelTeleport; client.OnTeleportCancel += OnClientCancelTeleport;
client.OnConnectionClosed += OnConnectionClosed;
} }
public virtual void Close() {} public virtual void Close() {}
@ -185,6 +187,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
#region Agent Teleports #region Agent Teleports
private void OnConnectionClosed(IClientAPI client)
{
if (client.IsLoggingOut)
{
m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting);
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
client.Name, Scene.Name);
}
}
private void OnClientCancelTeleport(IClientAPI client) private void OnClientCancelTeleport(IClientAPI client)
{ {
m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling); m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
@ -520,12 +534,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
"[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName);
// if (!sp.ValidateAttachments())
// {
// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
// return;
// }
string reason; string reason;
string version; string version;
if (!Scene.SimulationService.QueryAccess( if (!Scene.SimulationService.QueryAccess(
@ -588,6 +596,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
// Let's create an agent there if one doesn't exist yet. // Let's create an agent there if one doesn't exist yet.
// NOTE: logout will always be false for a non-HG teleport.
bool logout = false; bool logout = false;
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
{ {
@ -608,6 +617,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return; return;
} }
else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
return;
}
// Past this point we have to attempt clean up if the teleport fails, so update transfer state. // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
@ -630,11 +647,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (m_eqModule != null) if (m_eqModule != null)
{ {
// The EnableSimulator message makes the client establish a connection with the destination
// simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
// correct circuit code.
m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID);
// ES makes the client send a UseCircuitCode message to the destination, // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
// which triggers a bunch of things there. // simulator to confirm that it has established communication with the viewer.
// So let's wait
Thread.Sleep(200); Thread.Sleep(200);
// At least on LL 3.3.4 for teleports between different regions on the same simulator this appears // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
@ -645,6 +664,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
} }
else else
{ {
// XXX: This is a little misleading since we're information the client of its avatar destination,
// which may or may not be a neighbour region of the source region. This path is probably little
// used anyway (with EQ being the one used). But it is currently being used for test code.
sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
} }
} }
@ -662,14 +684,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
// We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
// establish th econnection to the destination which makes it return true.
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
return;
}
// A common teleport failure occurs when we can send CreateAgent to the
// destination region but the viewer cannot establish the connection (e.g. due to network issues between
// the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
// there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
if (!UpdateAgent(reg, finalDestination, agent, sp)) if (!UpdateAgent(reg, finalDestination, agent, sp))
{ {
// Region doesn't take it if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
return;
}
m_log.WarnFormat( m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
Fail(sp, finalDestination, logout); Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established.");
return; return;
} }
@ -679,7 +724,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
sp.Name, finalDestination.RegionName, sp.Scene.Name); sp.Name, finalDestination.RegionName, sp.Scene.Name);
CleanupAbortedInterRegionTeleport(sp, finalDestination); CleanupFailedInterRegionTeleport(sp, finalDestination);
return; return;
} }
@ -688,6 +733,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
"[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
// We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
// where that neighbour simulator could otherwise request a child agent create on the source which then
// closes our existing agent which is still signalled as root.
sp.IsChildAgent = true;
if (m_eqModule != null) if (m_eqModule != null)
{ {
m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
@ -698,19 +748,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
teleportFlags, capsPath); teleportFlags, capsPath);
} }
// Let's set this to true tentatively. This does not trigger OnChildAgent
sp.IsChildAgent = true;
// TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
// trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
// that the client contacted the destination before we close things here. // that the client contacted the destination before we close things here.
if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
{ {
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
return;
}
m_log.WarnFormat( m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
Fail(sp, finalDestination, logout); Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
return; return;
} }
@ -733,8 +789,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Now let's make it officially a child agent // Now let's make it officially a child agent
sp.MakeChildAgent(); sp.MakeChildAgent();
// sp.Scene.CleanDroppedAttachments();
// Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
@ -774,7 +828,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// <remarks> /// <remarks>
/// <param name='sp'> </param> /// <param name='sp'> </param>
/// <param name='finalDestination'></param> /// <param name='finalDestination'></param>
protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
{ {
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
@ -793,12 +847,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// <param name='sp'></param> /// <param name='sp'></param>
/// <param name='finalDestination'></param> /// <param name='finalDestination'></param>
/// <param name='logout'></param> /// <param name='logout'></param>
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason)
{ {
CleanupAbortedInterRegionTeleport(sp, finalDestination); CleanupFailedInterRegionTeleport(sp, finalDestination);
sp.ControllingClient.SendTeleportFailed( sp.ControllingClient.SendTeleportFailed(
string.Format("Problems connecting to destination {0}", finalDestination.RegionName)); string.Format(
"Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
} }

View File

@ -51,11 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// This is a state machine. /// This is a state machine.
/// ///
/// [Entry] => Preparing /// [Entry] => Preparing
/// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] } /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
/// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp } /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
/// Cancelling => CleaningUp /// Cancelling => CleaningUp || Aborting
/// ReceivedAtDestination => CleaningUp /// ReceivedAtDestination => CleaningUp || Aborting
/// CleaningUp => [Exit] /// CleaningUp => [Exit]
/// Aborting => [Exit]
/// ///
/// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
/// However, any state can transition to CleaningUp if the teleport has failed. /// However, any state can transition to CleaningUp if the teleport has failed.
@ -66,7 +67,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Transferring, // The agent is in the process of being transferred to a destination Transferring, // The agent is in the process of being transferred to a destination
ReceivedAtDestination, // The destination has notified us that the agent has been successfully received ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
CleaningUp, // The agent is being changed to child/removed after a transfer CleaningUp, // The agent is being changed to child/removed after a transfer
Cancelling // The user has cancelled the teleport but we have yet to act upon this. Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
} }
/// <summary> /// <summary>
@ -134,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Illegal to try and update an agent that's not actually in transit. // Illegal to try and update an agent that's not actually in transit.
if (!m_agentsInTransit.ContainsKey(id)) if (!m_agentsInTransit.ContainsKey(id))
{ {
if (newState != AgentTransferState.Cancelling) if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
failureMessage = string.Format( failureMessage = string.Format(
"Agent with ID {0} is not registered as in transit in {1}", "Agent with ID {0} is not registered as in transit in {1}",
id, m_mod.Scene.RegionInfo.RegionName); id, m_mod.Scene.RegionInfo.RegionName);
@ -145,7 +147,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{ {
oldState = m_agentsInTransit[id]; oldState = m_agentsInTransit[id];
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) if (newState == AgentTransferState.Aborting)
{
transitionOkay = true;
}
else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
{ {
transitionOkay = true; transitionOkay = true;
} }
@ -292,8 +298,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// There should be no race condition here since no other code should be removing the agent transfer or // There should be no race condition here since no other code should be removing the agent transfer or
// changing the state to another other than Transferring => ReceivedAtDestination. // changing the state to another other than Transferring => ReceivedAtDestination.
while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0)
while (count-- > 0)
{ {
lock (m_agentsInTransit)
{
if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
break;
}
// m_log.Debug(" >>> Waiting... " + count); // m_log.Debug(" >>> Waiting... " + count);
Thread.Sleep(100); Thread.Sleep(100);
} }

View File

@ -136,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
{ {
lock (m_logFileWriteLock) lock (m_logFileWriteLock)
{ {
DateTime now = DateTime.Now; DateTime now = DateTime.UtcNow;
if (m_logFile == null || now > m_logFileEndTime) if (m_logFile == null || now > m_logFileEndTime)
{ {
if (m_logFile != null) if (m_logFile != null)

View File

@ -2990,8 +2990,22 @@ namespace OpenSim.Region.Framework.Scenes
sp.IsChildAgent = false; sp.IsChildAgent = false;
sp.IsLoggingIn = true; sp.IsLoggingIn = true;
// We leave a 5 second pause before attempting to rez attachments to avoid a clash with
// version 3 viewers that maybe doing their own attachment rezzing related to their current
// outfit folder on startup. If these operations do clash, then the symptoms are invisible
// attachments until one zooms in on the avatar.
//
// We do not pause if we are launching on the same thread anyway in order to avoid pointlessly
// delaying any attachment related regression tests.
if (AttachmentsModule != null) if (AttachmentsModule != null)
Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); Util.FireAndForget(
o =>
{
if (Util.FireAndForgetMethod != FireAndForgetMethod.None)
Thread.Sleep(5000);
AttachmentsModule.RezAttachments(sp);
});
} }
} }
else else

View File

@ -1529,6 +1529,15 @@ namespace OpenSim.Region.Framework.Scenes
} }
// XXX: If we force an update here, then multiple attachments do appear correctly on a destination region
// If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work.
// This may be due to viewer code or it may be something we're not doing properly simulator side.
lock (m_attachments)
{
foreach (SceneObjectGroup sog in m_attachments)
sog.ScheduleGroupForFullUpdate();
}
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);

View File

@ -94,7 +94,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA); // SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA);
SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
List<TestClient> destinationTestClients = new List<TestClient>();
EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
originalSp.AbsolutePosition = new Vector3(128, 32, 10); originalSp.AbsolutePosition = new Vector3(128, 32, 10);
// originalSp.Flying = true; // originalSp.Flying = true;

View File

@ -26,7 +26,10 @@
*/ */
using System; using System;
using System.Reflection; using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Nini.Config; using Nini.Config;
using NUnit.Framework; using NUnit.Framework;
using OpenMetaverse; using OpenMetaverse;
@ -40,8 +43,6 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.CoreModules.World.Permissions; using OpenSim.Region.CoreModules.World.Permissions;
using OpenSim.Tests.Common; using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock; using OpenSim.Tests.Common.Mock;
using System.IO;
using System.Text;
namespace OpenSim.Region.Framework.Scenes.Tests namespace OpenSim.Region.Framework.Scenes.Tests
{ {
@ -68,7 +69,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
} }
[Test] [Test]
public void TestSameRegionTeleport() public void TestSameRegion()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // log4net.Config.XmlConfigurator.Configure();
@ -106,10 +107,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
} }
[Test] [Test]
public void TestSameSimulatorSeparatedRegionsTeleport() public void TestSameSimulatorIsolatedRegions()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure(); // TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1); UUID userId = TestHelpers.ParseTail(0x1);
@ -141,9 +142,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
sp.AbsolutePosition = new Vector3(30, 31, 32); sp.AbsolutePosition = new Vector3(30, 31, 32);
// XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole List<TestClient> destinationTestClients = new List<TestClient>();
// UDP stack (?) EntityTransferHelpers.SetUpInformClientOfNeighbour((TestClient)sp.ControllingClient, destinationTestClients);
// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB;
sceneA.RequestTeleportLocation( sceneA.RequestTeleportLocation(
sp.ControllingClient, sp.ControllingClient,
@ -152,7 +152,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
teleportLookAt, teleportLookAt,
(uint)TeleportFlags.ViaLocation); (uint)TeleportFlags.ViaLocation);
((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); // SetupInformClientOfNeighbour() will have handled the callback into the target scene to setup the child
// agent. This call will now complete the movement of the user into the destination and upgrade the agent
// from child to root.
destinationTestClients[0].CompleteMovement();
Assert.That(sceneA.GetScenePresence(userId), Is.Null); Assert.That(sceneA.GetScenePresence(userId), Is.Null);
@ -177,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
/// Test teleport procedures when the target simulator returns false when queried about access. /// Test teleport procedures when the target simulator returns false when queried about access.
/// </summary> /// </summary>
[Test] [Test]
public void TestSameSimulatorSeparatedRegionsQueryAccessFails() public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
@ -261,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
/// Test teleport procedures when the target simulator create agent step is refused. /// Test teleport procedures when the target simulator create agent step is refused.
/// </summary> /// </summary>
[Test] [Test]
public void TestSameSimulatorSeparatedRegionsCreateAgentFails() public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
@ -333,12 +336,100 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// TestHelpers.DisableLogging(); // TestHelpers.DisableLogging();
} }
/// <summary>
/// Test teleport when the destination region does not process (or does not receive) the connection attempt
/// from the viewer.
/// </summary>
/// <remarks>
/// This could be quite a common case where the source region can connect to a remove destination region
/// (for CreateAgent) but the viewer cannot reach the destination region due to network issues.
/// </remarks>
[Test] [Test]
public void TestSameSimulatorNeighbouringRegionsTeleport() public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection()
{ {
TestHelpers.InMethod(); TestHelpers.InMethod();
// TestHelpers.EnableLogging(); // TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1);
Vector3 preTeleportPosition = new Vector3(30, 31, 32);
EntityTransferModule etmA = new EntityTransferModule();
EntityTransferModule etmB = new EntityTransferModule();
LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
IConfigSource config = new IniConfigSource();
config.AddConfig("Modules");
config.Configs["Modules"].Set("EntityTransferModule", etmA.Name);
config.Configs["Modules"].Set("SimulationServices", lscm.Name);
config.AddConfig("EntityTransfer");
// In order to run a single threaded regression test we do not want the entity transfer module waiting
// for a callback from the destination scene before removing its avatar data.
config.Configs["EntityTransfer"].Set("wait_for_callback", false);
// config.AddConfig("Startup");
// config.Configs["Startup"].Set("serverside_object_permissions", true);
SceneHelpers sh = new SceneHelpers();
TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000);
SceneHelpers.SetupSceneModules(sceneA, config, etmA );
// We need to set up the permisions module on scene B so that our later use of agent limit to deny
// QueryAccess won't succeed anyway because administrators are always allowed in and the default
// IsAdministrator if no permissions module is present is true.
SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB });
// Shared scene modules
SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
Vector3 teleportPosition = new Vector3(10, 11, 12);
Vector3 teleportLookAt = new Vector3(20, 21, 22);
ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
sp.AbsolutePosition = preTeleportPosition;
sceneA.RequestTeleportLocation(
sp.ControllingClient,
sceneB.RegionInfo.RegionHandle,
teleportPosition,
teleportLookAt,
(uint)TeleportFlags.ViaLocation);
// FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate
// communication with the destination region. But this is a very non-obvious way of doing it - really we
// should be forced to expicitly set this up.
Assert.That(sceneB.GetScenePresence(userId), Is.Null);
ScenePresence sceneASp = sceneA.GetScenePresence(userId);
Assert.That(sceneASp, Is.Not.Null);
Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName));
Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition));
Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1));
Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0));
Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0));
Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0));
// TODO: Add assertions to check correct circuit details in both scenes.
// Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera
// position instead).
// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
// TestHelpers.DisableLogging();
}
[Test]
public void TestSameSimulatorNeighbouringRegions()
{
TestHelpers.InMethod();
TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1); UUID userId = TestHelpers.ParseTail(0x1);
EntityTransferModule etmA = new EntityTransferModule(); EntityTransferModule etmA = new EntityTransferModule();
@ -366,10 +457,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportPosition = new Vector3(10, 11, 12);
Vector3 teleportLookAt = new Vector3(20, 21, 22); Vector3 teleportLookAt = new Vector3(20, 21, 22);
ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
originalSp.AbsolutePosition = new Vector3(30, 31, 32); TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
List<TestClient> destinationTestClients = new List<TestClient>();
EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32);
ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId);
Assert.That(beforeSceneASp, Is.Not.Null); Assert.That(beforeSceneASp, Is.Not.Null);
Assert.That(beforeSceneASp.IsChildAgent, Is.False); Assert.That(beforeSceneASp.IsChildAgent, Is.False);
@ -377,10 +472,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(beforeSceneBSp, Is.Not.Null); Assert.That(beforeSceneBSp, Is.Not.Null);
Assert.That(beforeSceneBSp.IsChildAgent, Is.True); Assert.That(beforeSceneBSp.IsChildAgent, Is.True);
// XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole // In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows
// UDP stack (?) // about the neighbour region it is teleporting to.
// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB;
sceneA.RequestTeleportLocation( sceneA.RequestTeleportLocation(
beforeSceneASp.ControllingClient, beforeSceneASp.ControllingClient,
sceneB.RegionInfo.RegionHandle, sceneB.RegionInfo.RegionHandle,
@ -388,7 +481,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
teleportLookAt, teleportLookAt,
(uint)TeleportFlags.ViaLocation); (uint)TeleportFlags.ViaLocation);
((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); destinationTestClients[0].CompleteMovement();
ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); ScenePresence afterSceneASp = sceneA.GetScenePresence(userId);
Assert.That(afterSceneASp, Is.Not.Null); Assert.That(afterSceneASp, Is.Not.Null);

View File

@ -176,16 +176,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", // " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, // attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); // (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
ct.Rows.Add(
new ConsoleDisplayTableRow( ct.AddRow(
new List<string>() attachmentObject.Name,
{ attachmentObject.LocalId,
attachmentObject.Name, attachmentObject.FromItemID,
attachmentObject.LocalId.ToString(), ((AttachmentPoint)attachmentObject.AttachmentPoint),
attachmentObject.FromItemID.ToString(), attachmentObject.RootPart.AttachedPos);
((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
attachmentObject.RootPart.AttachedPos.ToString()
}));
// } // }
} }

View File

@ -286,7 +286,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin)
{ {
BulletShapeUnman shapeu = shape as BulletShapeUnman; BulletShapeUnman shapeu = shape as BulletShapeUnman;
if (shapeu != null && shapeu.HasPhysicalShape) if (shapeu != null && shapeu.HasPhysicalShape)
BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
} }
public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
@ -1420,7 +1420,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
public static extern bool IsNativeShape2(IntPtr shape); public static extern bool IsNativeShape2(IntPtr shape);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);

View File

@ -1201,8 +1201,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
VehicleAddForce(appliedGravity); VehicleAddForce(appliedGravity);
VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},appliedForce={3}", VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
Prim.LocalID, m_VehicleGravity, Prim.IsColliding, appliedGravity); Prim.LocalID, m_VehicleGravity,
Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
} }
// ======================================================================= // =======================================================================

View File

@ -39,6 +39,20 @@ public static class BSParam
{ {
private static string LogHeader = "[BULLETSIM PARAMETERS]"; private static string LogHeader = "[BULLETSIM PARAMETERS]";
// Tuning notes:
// From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
// Contact points can be added even if the distance is positive. The constraint solver can deal with
// contacts with positive distances as well as negative (penetration). Contact points are discarded
// if the distance exceeds a certain threshold.
// Bullet has a contact processing threshold and a contact breaking threshold.
// If the distance is larger than the contact breaking threshold, it will be removed after one frame.
// If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
// This is separate/independent from the collision margin. The collision margin increases the object a bit
// to improve collision detection performance and accuracy.
// ===================
// From:
// Level of Detail values kept as float because that's what the Meshmerizer wants // Level of Detail values kept as float because that's what the Meshmerizer wants
public static float MeshLOD { get; private set; } public static float MeshLOD { get; private set; }
public static float MeshCircularLOD { get; private set; } public static float MeshCircularLOD { get; private set; }
@ -74,9 +88,11 @@ public static class BSParam
public static bool ShouldRemoveZeroWidthTriangles { get; private set; } public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
public static float TerrainImplementation { get; private set; } public static float TerrainImplementation { get; private set; }
public static int TerrainMeshMagnification { get; private set; }
public static float TerrainFriction { get; private set; } public static float TerrainFriction { get; private set; }
public static float TerrainHitFraction { get; private set; } public static float TerrainHitFraction { get; private set; }
public static float TerrainRestitution { get; private set; } public static float TerrainRestitution { get; private set; }
public static float TerrainContactProcessingThreshold { get; private set; }
public static float TerrainCollisionMargin { get; private set; } public static float TerrainCollisionMargin { get; private set; }
public static float DefaultFriction { get; private set; } public static float DefaultFriction { get; private set; }
@ -446,6 +462,10 @@ public static class BSParam
(float)BSTerrainPhys.TerrainImplementation.Mesh, (float)BSTerrainPhys.TerrainImplementation.Mesh,
(s) => { return TerrainImplementation; }, (s) => { return TerrainImplementation; },
(s,v) => { TerrainImplementation = v; } ), (s,v) => { TerrainImplementation = v; } ),
new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
3,
(s) => { return TerrainMeshMagnification; },
(s,v) => { TerrainMeshMagnification = v; } ),
new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.3f, 0.3f,
(s) => { return TerrainFriction; }, (s) => { return TerrainFriction; },
@ -458,6 +478,10 @@ public static class BSParam
0f, 0f,
(s) => { return TerrainRestitution; }, (s) => { return TerrainRestitution; },
(s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
0.0f,
(s) => { return TerrainContactProcessingThreshold; },
(s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ),
new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
0.08f, 0.08f,
(s) => { return TerrainCollisionMargin; }, (s) => { return TerrainCollisionMargin; },

View File

@ -947,9 +947,9 @@ public class BSPrim : BSPhysObject
ZeroMotion(true); ZeroMotion(true);
// Set various physical properties so other object interact properly // Set various physical properties so other object interact properly
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
PhysicsScene.PE.SetFriction(PhysBody, Friction); PhysicsScene.PE.SetFriction(PhysBody, Friction);
PhysicsScene.PE.SetRestitution(PhysBody, Restitution); PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
// Mass is zero which disables a bunch of physics stuff in Bullet // Mass is zero which disables a bunch of physics stuff in Bullet
UpdatePhysicalMassProperties(0f, false); UpdatePhysicalMassProperties(0f, false);

View File

@ -687,7 +687,7 @@ public sealed class BSShapeCollection : IDisposable
} }
else else
{ {
PhysicsScene.Logger.ErrorFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name); LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
} }
} }

View File

@ -263,6 +263,7 @@ public sealed class BSTerrainManager : IDisposable
if (MegaRegionParentPhysicsScene == null) if (MegaRegionParentPhysicsScene == null)
{ {
// This terrain is not part of the mega-region scheme. Create vanilla terrain.
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrains.Add(terrainRegionBase, newTerrainPhys);

View File

@ -76,11 +76,26 @@ public sealed class BSTerrainMesh : BSTerrainPhys
m_sizeX = (int)(maxCoords.X - minCoords.X); m_sizeX = (int)(maxCoords.X - minCoords.X);
m_sizeY = (int)(maxCoords.Y - minCoords.Y); m_sizeY = (int)(maxCoords.Y - minCoords.Y);
if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, bool meshCreationSuccess = false;
m_sizeX, m_sizeY, if (BSParam.TerrainMeshMagnification == 1)
(float)m_sizeX, (float)m_sizeY, {
Vector3.Zero, 1.0f, // If a magnification of one, use the old routine that is tried and true.
out indicesCount, out indices, out verticesCount, out vertices)) meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene,
initialMap, m_sizeX, m_sizeY, // input size
Vector3.Zero, // base for mesh
out indicesCount, out indices, out verticesCount, out vertices);
}
else
{
// Other magnifications use the newer routine
meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene,
initialMap, m_sizeX, m_sizeY, // input size
BSParam.TerrainMeshMagnification,
physicsScene.TerrainManager.DefaultRegionSize,
Vector3.Zero, // base for mesh
out indicesCount, out indices, out verticesCount, out vertices);
}
if (!meshCreationSuccess)
{ {
// DISASTER!! // DISASTER!!
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
@ -88,6 +103,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
} }
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
ID, indicesCount, indices.Length, verticesCount, vertices.Length); ID, indicesCount, indices.Length, verticesCount, vertices.Length);
@ -112,11 +128,13 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; return;
} }
physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
// Set current terrain attributes // Set current terrain attributes
PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
// Static objects are not very massive. // Static objects are not very massive.
@ -184,9 +202,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Return 'true' if successfully created. // Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh( BSScene physicsScene, public static bool ConvertHeightmapToMesh( BSScene physicsScene,
float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
float extentX, float extentY, // zero based range for output vertices
Vector3 extentBase, // base to be added to all vertices Vector3 extentBase, // base to be added to all vertices
float magnification, // number of vertices to create between heightMap coords
out int indicesCountO, out int[] indicesO, out int indicesCountO, out int[] indicesO,
out int verticesCountO, out float[] verticesO) out int verticesCountO, out float[] verticesO)
{ {
@ -207,17 +223,15 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// of the heightmap. // of the heightmap.
try try
{ {
// One vertice per heightmap value plus the vertices off the top and bottom edge. // One vertice per heightmap value plus the vertices off the side and bottom edge.
int totalVertices = (sizeX + 1) * (sizeY + 1); int totalVertices = (sizeX + 1) * (sizeY + 1);
vertices = new float[totalVertices * 3]; vertices = new float[totalVertices * 3];
int totalIndices = sizeX * sizeY * 6; int totalIndices = sizeX * sizeY * 6;
indices = new int[totalIndices]; indices = new int[totalIndices];
float magX = (float)sizeX / extentX;
float magY = (float)sizeY / extentY;
if (physicsScene != null) if (physicsScene != null)
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
float minHeight = float.MaxValue; float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region. // Note that sizeX+1 vertices are created since there is land between this and the next region.
for (int yy = 0; yy <= sizeY; yy++) for (int yy = 0; yy <= sizeY; yy++)
@ -230,8 +244,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
if (xx == sizeX) offset -= 1; if (xx == sizeX) offset -= 1;
float height = heightMap[offset]; float height = heightMap[offset];
minHeight = Math.Min(minHeight, height); minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; vertices[verticesCount + 0] = (float)xx + extentBase.X;
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; vertices[verticesCount + 1] = (float)yy + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z; vertices[verticesCount + 2] = height + extentBase.Z;
verticesCount += 3; verticesCount += 3;
} }
@ -270,5 +284,158 @@ public sealed class BSTerrainMesh : BSTerrainPhys
return ret; return ret;
} }
private class HeightMapGetter
{
private float[] m_heightMap;
private int m_sizeX;
private int m_sizeY;
public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
{
m_heightMap = pHeightMap;
m_sizeX = pSizeX;
m_sizeY = pSizeY;
}
// The heightmap is extended as an infinite plane at the last height
public float GetHeight(int xx, int yy)
{
int offset = 0;
// Extend the height with the height from the last row or column
if (yy >= m_sizeY)
if (xx >= m_sizeX)
offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
else
offset = (m_sizeY - 1) * m_sizeX + xx;
else
if (xx >= m_sizeX)
offset = yy * m_sizeX + (m_sizeX - 1);
else
offset = yy * m_sizeX + xx;
return m_heightMap[offset];
}
}
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
// Version that handles magnification.
// Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
int magnification, // number of vertices per heighmap step
Vector3 extent, // dimensions of the output mesh
Vector3 extentBase, // base to be added to all vertices
out int indicesCountO, out int[] indicesO,
out int verticesCountO, out float[] verticesO)
{
bool ret = false;
int indicesCount = 0;
int verticesCount = 0;
int[] indices = new int[0];
float[] vertices = new float[0];
HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
// The vertices dimension of the output mesh
int meshX = sizeX * magnification;
int meshY = sizeY * magnification;
// The output size of one mesh step
float meshXStep = extent.X / meshX;
float meshYStep = extent.Y / meshY;
// Create an array of vertices that is meshX+1 by meshY+1 (note the loop
// from zero to <= meshX). The triangle indices are then generated as two triangles
// per heightmap point. There are meshX by meshY of these squares. The extra row and
// column of vertices are used to complete the triangles of the last row and column
// of the heightmap.
try
{
// Vertices for the output heightmap plus one on the side and bottom to complete triangles
int totalVertices = (meshX + 1) * (meshY + 1);
vertices = new float[totalVertices * 3];
int totalIndices = meshX * meshY * 6;
indices = new int[totalIndices];
if (physicsScene != null)
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
totalVertices, totalIndices, extentBase);
float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region.
// Loop through the output vertices and compute the mediun height in between the input vertices
for (int yy = 0; yy <= meshY; yy++)
{
for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
{
float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
int stepY = (int)offsetY;
float fractionalY = offsetY - (float)stepY;
float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
int stepX = (int)offsetX;
float fractionalX = offsetX - (float)stepX;
// physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
// BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
// get the four corners of the heightmap square the mesh point is in
float heightUL = hmap.GetHeight(stepX , stepY );
float heightUR = hmap.GetHeight(stepX + 1, stepY );
float heightLL = hmap.GetHeight(stepX , stepY + 1);
float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
// bilinear interplolation
float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
+ heightUR * fractionalX * (1 - fractionalY)
+ heightLL * (1 - fractionalX) * fractionalY
+ heightLR * fractionalX * fractionalY;
// physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
// BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z;
verticesCount += 3;
}
}
// The number of vertices generated
verticesCount /= 3;
// Loop through all the heightmap squares and create indices for the two triangles for that square
for (int yy = 0; yy < meshY; yy++)
{
for (int xx = 0; xx < meshX; xx++)
{
int offset = yy * (meshX + 1) + xx;
// Each vertices is presumed to be the upper left corner of a box of two triangles
indices[indicesCount + 0] = offset;
indices[indicesCount + 1] = offset + 1;
indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
indices[indicesCount + 3] = offset + 1;
indices[indicesCount + 4] = offset + meshX + 2;
indices[indicesCount + 5] = offset + meshX + 1;
indicesCount += 6;
}
}
ret = true;
}
catch (Exception e)
{
if (physicsScene != null)
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
LogHeader, physicsScene.RegionName, extentBase, e);
}
indicesCountO = indicesCount;
indicesO = indices;
verticesCountO = verticesCount;
verticesO = vertices;
return ret;
}
} }
} }

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using log4net;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Servers;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules.Framework;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
namespace OpenSim.Tests.Common
{
public static class EntityTransferHelpers
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Set up correct handling of the InformClientOfNeighbour call from the source region that triggers the
/// viewer to setup a connection with the destination region.
/// </summary>
/// <param name='tc'></param>
/// <param name='neighbourTcs'>
/// A list that will be populated with any TestClients set up in response to
/// being informed about a destination region.
/// </param>
public static void SetUpInformClientOfNeighbour(TestClient tc, List<TestClient> neighbourTcs)
{
// XXX: Confusingly, this is also used for non-neighbour notification (as in teleports that do not use the
// event queue).
tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) =>
{
uint x, y;
Utils.LongToUInts(neighbourHandle, out x, out y);
x /= Constants.RegionSize;
y /= Constants.RegionSize;
m_log.DebugFormat(
"[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}",
x, y, neighbourExternalEndPoint);
// In response to this message, we are going to make a teleport to the scene we've previous been told
// about by test code (this needs to be improved).
AgentCircuitData newAgent = tc.RequestClientInfo();
Scene neighbourScene;
SceneManager.Instance.TryGetScene(x, y, out neighbourScene);
TestClient neighbourTc = new TestClient(newAgent, neighbourScene, SceneManager.Instance);
neighbourTcs.Add(neighbourTc);
neighbourScene.AddNewClient(neighbourTc, PresenceType.User);
};
}
}
}

View File

@ -531,6 +531,31 @@ namespace OpenSim.Tests.Common
/// <param name="sceneManager"></param> /// <param name="sceneManager"></param>
/// <returns></returns> /// <returns></returns>
public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager)
{
return AddScenePresence(scene, new TestClient(agentData, scene, sceneManager), agentData, sceneManager);
}
/// <summary>
/// Add a root agent.
/// </summary>
/// <remarks>
/// This function
///
/// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the
/// userserver if grid) would give initial login data back to the client and separately tell the scene that the
/// agent was coming.
///
/// 2) Connects the agent with the scene
///
/// This function performs actions equivalent with notifying the scene that an agent is
/// coming and then actually connecting the agent to the scene. The one step missed out is the very first
/// </remarks>
/// <param name="scene"></param>
/// <param name="agentData"></param>
/// <param name="sceneManager"></param>
/// <returns></returns>
public static ScenePresence AddScenePresence(
Scene scene, IClientAPI client, AgentCircuitData agentData, SceneManager sceneManager)
{ {
// We emulate the proper login sequence here by doing things in four stages // We emulate the proper login sequence here by doing things in four stages
@ -541,7 +566,7 @@ namespace OpenSim.Tests.Common
lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID);
// Stages 1 & 2 // Stages 1 & 2
ScenePresence sp = IntroduceClientToScene(scene, sceneManager, agentData, TeleportFlags.ViaLogin); ScenePresence sp = IntroduceClientToScene(scene, client, agentData, TeleportFlags.ViaLogin);
// Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent.
sp.CompleteMovement(sp.ControllingClient, true); sp.CompleteMovement(sp.ControllingClient, true);
@ -558,11 +583,11 @@ namespace OpenSim.Tests.Common
/// neighbours and where no teleporting takes place. /// neighbours and where no teleporting takes place.
/// </param> /// </param>
/// <param name='scene'></param> /// <param name='scene'></param>
/// <param name='sceneManager></param> /// <param name='testClient'></param>
/// <param name='agentData'></param> /// <param name='agentData'></param>
/// <param name='tf'></param> /// <param name='tf'></param>
private static ScenePresence IntroduceClientToScene( private static ScenePresence IntroduceClientToScene(
Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf) Scene scene, IClientAPI client, AgentCircuitData agentData, TeleportFlags tf)
{ {
string reason; string reason;
@ -571,10 +596,9 @@ namespace OpenSim.Tests.Common
Console.WriteLine("NewUserConnection failed: " + reason); Console.WriteLine("NewUserConnection failed: " + reason);
// Stage 2: add the new client as a child agent to the scene // Stage 2: add the new client as a child agent to the scene
TestClient client = new TestClient(agentData, scene, sceneManager);
scene.AddNewClient(client, PresenceType.User); scene.AddNewClient(client, PresenceType.User);
return scene.GetScenePresence(agentData.AgentID); return scene.GetScenePresence(client.AgentId);
} }
public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId) public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId)
@ -583,7 +607,8 @@ namespace OpenSim.Tests.Common
acd.child = true; acd.child = true;
// XXX: ViaLogin may not be correct for child agents // XXX: ViaLogin may not be correct for child agents
return IntroduceClientToScene(scene, null, acd, TeleportFlags.ViaLogin); TestClient client = new TestClient(acd, scene, null);
return IntroduceClientToScene(scene, client, acd, TeleportFlags.ViaLogin);
} }
/// <summary> /// <summary>

View File

@ -46,8 +46,6 @@ namespace OpenSim.Tests.Common.Mock
EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
private TestClient TeleportSceneClient;
private Scene m_scene; private Scene m_scene;
private SceneManager m_sceneManager; private SceneManager m_sceneManager;
@ -60,7 +58,9 @@ namespace OpenSim.Tests.Common.Mock
public List<ImagePacketPacket> SentImagePacketPackets { get; private set; } public List<ImagePacketPacket> SentImagePacketPackets { get; private set; }
public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; } public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; }
// Test client specific events - for use by tests to implement some IClientAPI behaviour.
public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion; public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion;
public event Action<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour;
// disable warning: public events, part of the public API // disable warning: public events, part of the public API
#pragma warning disable 67 #pragma warning disable 67
@ -604,23 +604,8 @@ namespace OpenSim.Tests.Common.Mock
public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint) public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint)
{ {
m_log.DebugFormat("[TEST CLIENT]: Processing inform client of neighbour"); if (OnTestClientInformClientOfNeighbour != null)
OnTestClientInformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint);
// In response to this message, we are going to make a teleport to the scene we've previous been told
// about by test code (this needs to be improved).
AgentCircuitData newAgent = RequestClientInfo();
// Stage 2: add the new client as a child agent to the scene
uint x, y;
Utils.LongToUInts(neighbourHandle, out x, out y);
x /= Constants.RegionSize;
y /= Constants.RegionSize;
Scene neighbourScene;
m_sceneManager.TryGetScene(x, y, out neighbourScene);
TeleportSceneClient = new TestClient(newAgent, neighbourScene, m_sceneManager);
neighbourScene.AddNewClient(TeleportSceneClient, PresenceType.User);
} }
public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
@ -635,12 +620,6 @@ namespace OpenSim.Tests.Common.Mock
// CompleteTeleportClientSide(); // CompleteTeleportClientSide();
} }
public void CompleteTeleportClientSide()
{
TeleportSceneClient.CompleteMovement();
//TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false);
}
public virtual void SendTeleportFailed(string reason) public virtual void SendTeleportFailed(string reason)
{ {
m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason); m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason);