Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
avinationmerge
Melanie 2013-03-22 01:01:24 +00:00
commit 68b910c1ff
24 changed files with 597 additions and 144 deletions

View File

@ -561,45 +561,59 @@ namespace OpenSim.Framework
if (attachpoint == 0)
return false;
if (item == UUID.Zero)
lock (m_attachments)
{
lock (m_attachments)
if (item == UUID.Zero)
{
if (m_attachments.ContainsKey(attachpoint))
{
m_attachments.Remove(attachpoint);
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;
}
// 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
&& 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));
// 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;
@ -648,6 +662,10 @@ namespace OpenSim.Framework
int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
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
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,
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;
if (StatsManager.TryGetStats("scene", out 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);

View File

@ -573,8 +573,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
}
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}",
// so.Name, so.LocalId, sp.Name, m_scene.Name);
// "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
// so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
// Scripts MUST be snapshotted before the object is
// 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());
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);
InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
@ -848,7 +854,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
teleportLookAt,
(uint)TeleportFlags.ViaLocation);
((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide();
destinationTestClients[0].CompleteMovement();
// Check attachments have made it into sceneB
ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);

View File

@ -361,7 +361,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
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
long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
@ -658,7 +658,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
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
// 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.
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);
// 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
// MT: No, it can't, as chat is heard from the avatar position, not
// the camera position.
s.ForEachRootScenePresence(
s.ForEachScenePresence(
delegate(ScenePresence presence)
{
if (destination != UUID.Zero && presence.UUID != destination)

View File

@ -520,12 +520,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
"[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);
// if (!sp.ValidateAttachments())
// {
// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
// return;
// }
string reason;
string version;
if (!Scene.SimulationService.QueryAccess(
@ -588,6 +582,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
}
// 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;
if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
{
@ -630,11 +625,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
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);
// ES makes the client send a UseCircuitCode message to the destination,
// which triggers a bunch of things there.
// So let's wait
// XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
// simulator to confirm that it has established communication with the viewer.
Thread.Sleep(200);
// At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
@ -645,6 +642,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
}
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);
}
}
@ -662,14 +662,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
// 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))
{
// Region doesn't take it
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);
Fail(sp, finalDestination, logout);
Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established.");
return;
}
@ -688,6 +691,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
"[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
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)
{
m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
@ -698,9 +706,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
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
// 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.
@ -710,7 +715,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
"[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);
Fail(sp, finalDestination, logout);
Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
return;
}
@ -733,8 +738,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Now let's make it officially a child agent
sp.MakeChildAgent();
// sp.Scene.CleanDroppedAttachments();
// 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))
@ -793,12 +796,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// <param name='sp'></param>
/// <param name='finalDestination'></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);
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);
}

View File

@ -292,8 +292,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
// 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);
Thread.Sleep(100);
}

View File

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

View File

@ -2990,8 +2990,22 @@ namespace OpenSim.Region.Framework.Scenes
sp.IsChildAgent = false;
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)
Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); });
Util.FireAndForget(
o =>
{
if (Util.FireAndForgetMethod != FireAndForgetMethod.None)
Thread.Sleep(5000);
AttachmentsModule.RezAttachments(sp);
});
}
}
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(
// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
// 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(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.Flying = true;

View File

@ -26,7 +26,10 @@
*/
using System;
using System.Reflection;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
@ -40,8 +43,6 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Region.CoreModules.World.Permissions;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
using System.IO;
using System.Text;
namespace OpenSim.Region.Framework.Scenes.Tests
{
@ -68,7 +69,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
}
[Test]
public void TestSameRegionTeleport()
public void TestSameRegion()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
@ -106,10 +107,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
}
[Test]
public void TestSameSimulatorSeparatedRegionsTeleport()
public void TestSameSimulatorIsolatedRegions()
{
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
// TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1);
@ -141,9 +142,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
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
// UDP stack (?)
// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB;
List<TestClient> destinationTestClients = new List<TestClient>();
EntityTransferHelpers.SetUpInformClientOfNeighbour((TestClient)sp.ControllingClient, destinationTestClients);
sceneA.RequestTeleportLocation(
sp.ControllingClient,
@ -152,7 +152,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
teleportLookAt,
(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);
@ -177,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
/// Test teleport procedures when the target simulator returns false when queried about access.
/// </summary>
[Test]
public void TestSameSimulatorSeparatedRegionsQueryAccessFails()
public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
@ -261,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
/// Test teleport procedures when the target simulator create agent step is refused.
/// </summary>
[Test]
public void TestSameSimulatorSeparatedRegionsCreateAgentFails()
public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
@ -333,12 +336,100 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// 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]
public void TestSameSimulatorNeighbouringRegionsTeleport()
public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection()
{
TestHelpers.InMethod();
// 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);
EntityTransferModule etmA = new EntityTransferModule();
@ -366,10 +457,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Vector3 teleportPosition = new Vector3(10, 11, 12);
Vector3 teleportLookAt = new Vector3(20, 21, 22);
ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
originalSp.AbsolutePosition = new Vector3(30, 31, 32);
AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
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.IsChildAgent, Is.False);
@ -377,10 +472,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Assert.That(beforeSceneBSp, Is.Not.Null);
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
// UDP stack (?)
// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB;
// In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows
// about the neighbour region it is teleporting to.
sceneA.RequestTeleportLocation(
beforeSceneASp.ControllingClient,
sceneB.RegionInfo.RegionHandle,
@ -388,7 +481,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
teleportLookAt,
(uint)TeleportFlags.ViaLocation);
((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide();
destinationTestClients[0].CompleteMovement();
ScenePresence afterSceneASp = sceneA.GetScenePresence(userId);
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",
// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
ct.Rows.Add(
new ConsoleDisplayTableRow(
new List<string>()
{
attachmentObject.Name,
attachmentObject.LocalId.ToString(),
attachmentObject.FromItemID.ToString(),
((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
attachmentObject.RootPart.AttachedPos.ToString()
}));
ct.AddRow(
attachmentObject.Name,
attachmentObject.LocalId,
attachmentObject.FromItemID,
((AttachmentPoint)attachmentObject.AttachmentPoint),
attachmentObject.RootPart.AttachedPos);
// }
}

View File

@ -286,7 +286,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin)
{
BulletShapeUnman shapeu = shape as BulletShapeUnman;
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)
@ -1420,7 +1420,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
public static extern bool IsNativeShape2(IntPtr shape);
[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]
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);
VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},appliedForce={3}",
Prim.LocalID, m_VehicleGravity, Prim.IsColliding, appliedGravity);
VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
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]";
// 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
public static float MeshLOD { 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 float TerrainImplementation { get; private set; }
public static int TerrainMeshMagnification { get; private set; }
public static float TerrainFriction { get; private set; }
public static float TerrainHitFraction { 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 DefaultFriction { get; private set; }
@ -446,6 +462,10 @@ public static class BSParam
(float)BSTerrainPhys.TerrainImplementation.Mesh,
(s) => { return TerrainImplementation; },
(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" ,
0.3f,
(s) => { return TerrainFriction; },
@ -458,6 +478,10 @@ public static class BSParam
0f,
(s) => { return TerrainRestitution; },
(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" ,
0.08f,
(s) => { return TerrainCollisionMargin; },

View File

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

View File

@ -687,7 +687,7 @@ public sealed class BSShapeCollection : IDisposable
}
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);
}
}

View File

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

View File

@ -76,11 +76,26 @@ public sealed class BSTerrainMesh : BSTerrainPhys
m_sizeX = (int)(maxCoords.X - minCoords.X);
m_sizeY = (int)(maxCoords.Y - minCoords.Y);
if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
m_sizeX, m_sizeY,
(float)m_sizeX, (float)m_sizeY,
Vector3.Zero, 1.0f,
out indicesCount, out indices, out verticesCount, out vertices))
bool meshCreationSuccess = false;
if (BSParam.TerrainMeshMagnification == 1)
{
// If a magnification of one, use the old routine that is tried and true.
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!!
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.
return;
}
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
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.
return;
}
physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
// Set current terrain attributes
PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
// Static objects are not very massive.
@ -184,9 +202,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh( BSScene physicsScene,
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
float magnification, // number of vertices to create between heightMap coords
out int indicesCountO, out int[] indicesO,
out int verticesCountO, out float[] verticesO)
{
@ -207,17 +223,15 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// of the heightmap.
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);
vertices = new float[totalVertices * 3];
int totalIndices = sizeX * sizeY * 6;
indices = new int[totalIndices];
float magX = (float)sizeX / extentX;
float magY = (float)sizeY / extentY;
if (physicsScene != null)
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region.
for (int yy = 0; yy <= sizeY; yy++)
@ -230,8 +244,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
if (xx == sizeX) offset -= 1;
float height = heightMap[offset];
minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
vertices[verticesCount + 0] = (float)xx + extentBase.X;
vertices[verticesCount + 1] = (float)yy + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z;
verticesCount += 3;
}
@ -270,5 +284,158 @@ public sealed class BSTerrainMesh : BSTerrainPhys
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>
/// <returns></returns>
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
@ -541,7 +566,7 @@ namespace OpenSim.Tests.Common
lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID);
// 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.
sp.CompleteMovement(sp.ControllingClient, true);
@ -558,11 +583,11 @@ namespace OpenSim.Tests.Common
/// neighbours and where no teleporting takes place.
/// </param>
/// <param name='scene'></param>
/// <param name='sceneManager></param>
/// <param name='testClient'></param>
/// <param name='agentData'></param>
/// <param name='tf'></param>
private static ScenePresence IntroduceClientToScene(
Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf)
Scene scene, IClientAPI client, AgentCircuitData agentData, TeleportFlags tf)
{
string reason;
@ -571,10 +596,9 @@ namespace OpenSim.Tests.Common
Console.WriteLine("NewUserConnection failed: " + reason);
// 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);
return scene.GetScenePresence(agentData.AgentID);
return scene.GetScenePresence(client.AgentId);
}
public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId)
@ -583,7 +607,8 @@ namespace OpenSim.Tests.Common
acd.child = true;
// 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>

View File

@ -46,8 +46,6 @@ namespace OpenSim.Tests.Common.Mock
EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
private TestClient TeleportSceneClient;
private Scene m_scene;
private SceneManager m_sceneManager;
@ -60,7 +58,9 @@ namespace OpenSim.Tests.Common.Mock
public List<ImagePacketPacket> SentImagePacketPackets { 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<ulong, IPEndPoint> OnTestClientInformClientOfNeighbour;
// disable warning: public events, part of the public API
#pragma warning disable 67
@ -604,23 +604,8 @@ namespace OpenSim.Tests.Common.Mock
public virtual void InformClientOfNeighbour(ulong neighbourHandle, IPEndPoint neighbourExternalEndPoint)
{
m_log.DebugFormat("[TEST CLIENT]: Processing inform client of neighbour");
// 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);
if (OnTestClientInformClientOfNeighbour != null)
OnTestClientInformClientOfNeighbour(neighbourHandle, neighbourExternalEndPoint);
}
public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint,
@ -635,12 +620,6 @@ namespace OpenSim.Tests.Common.Mock
// CompleteTeleportClientSide();
}
public void CompleteTeleportClientSide()
{
TeleportSceneClient.CompleteMovement();
//TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false);
}
public virtual void SendTeleportFailed(string reason)
{
m_log.DebugFormat("[TEST CLIENT]: Teleport failed with reason {0}", reason);