diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Attachments')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 129 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | 129 |
2 files changed, 233 insertions, 25 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 6495f3f..d47ca4b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Threading; | ||
32 | using System.Xml; | 33 | using System.Xml; |
33 | using log4net; | 34 | using log4net; |
34 | using Mono.Addins; | 35 | using Mono.Addins; |
@@ -51,6 +52,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
52 | 53 | ||
53 | public int DebugLevel { get; set; } | 54 | public int DebugLevel { get; set; } |
55 | |||
56 | /// <summary> | ||
57 | /// Period to sleep per 100 prims in order to avoid CPU spikes when an avatar with many attachments logs in/changes | ||
58 | /// outfit or many avatars with a medium levels of attachments login/change outfit simultaneously. | ||
59 | /// </summary> | ||
60 | /// <remarks> | ||
61 | /// A value of 0 will apply no pause. The pause is specified in milliseconds. | ||
62 | /// </remarks> | ||
63 | public int ThrottlePer100PrimsRezzed { get; set; } | ||
54 | 64 | ||
55 | private Scene m_scene; | 65 | private Scene m_scene; |
56 | private IInventoryAccessModule m_invAccessModule; | 66 | private IInventoryAccessModule m_invAccessModule; |
@@ -67,18 +77,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
67 | { | 77 | { |
68 | IConfig config = source.Configs["Attachments"]; | 78 | IConfig config = source.Configs["Attachments"]; |
69 | if (config != null) | 79 | if (config != null) |
80 | { | ||
70 | Enabled = config.GetBoolean("Enabled", true); | 81 | Enabled = config.GetBoolean("Enabled", true); |
82 | |||
83 | ThrottlePer100PrimsRezzed = config.GetInt("ThrottlePer100PrimsRezzed", 0); | ||
84 | } | ||
71 | else | 85 | else |
86 | { | ||
72 | Enabled = true; | 87 | Enabled = true; |
88 | } | ||
73 | } | 89 | } |
74 | 90 | ||
75 | public void AddRegion(Scene scene) | 91 | public void AddRegion(Scene scene) |
76 | { | 92 | { |
77 | m_scene = scene; | 93 | m_scene = scene; |
78 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); | ||
79 | |||
80 | if (Enabled) | 94 | if (Enabled) |
81 | { | 95 | { |
96 | // Only register module with scene if it is enabled. All callers check for a null attachments module. | ||
97 | // Ideally, there should be a null attachments module for when this core attachments module has been | ||
98 | // disabled. Registering only when enabled allows for other attachments module implementations. | ||
99 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); | ||
82 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; | 100 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; |
83 | m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true); | 101 | m_scene.EventManager.OnStartScript += (localID, itemID) => HandleScriptStateChange(localID, true); |
84 | m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false); | 102 | m_scene.EventManager.OnStopScript += (localID, itemID) => HandleScriptStateChange(localID, false); |
@@ -86,24 +104,43 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
86 | MainConsole.Instance.Commands.AddCommand( | 104 | MainConsole.Instance.Commands.AddCommand( |
87 | "Debug", | 105 | "Debug", |
88 | false, | 106 | false, |
89 | "debug attachments", | 107 | "debug attachments log", |
90 | "debug attachments [0|1]", | 108 | "debug attachments log [0|1]", |
91 | "Turn on attachments debugging\n" | 109 | "Turn on attachments debug logging", |
92 | + " <= 0 - turns off debugging\n" | 110 | " <= 0 - turns off debug logging\n" |
93 | + " >= 1 - turns on attachment message logging\n", | 111 | + " >= 1 - turns on attachment message debug logging", |
94 | HandleDebugAttachments); | 112 | HandleDebugAttachmentsLog); |
113 | |||
114 | MainConsole.Instance.Commands.AddCommand( | ||
115 | "Debug", | ||
116 | false, | ||
117 | "debug attachments throttle", | ||
118 | "debug attachments throttle <ms>", | ||
119 | "Turn on attachments throttling.", | ||
120 | "This requires a millisecond value. " + | ||
121 | " == 0 - disable throttling.\n" | ||
122 | + " > 0 - sleeps for this number of milliseconds per 100 prims rezzed.", | ||
123 | HandleDebugAttachmentsThrottle); | ||
124 | |||
125 | MainConsole.Instance.Commands.AddCommand( | ||
126 | "Debug", | ||
127 | false, | ||
128 | "debug attachments status", | ||
129 | "debug attachments status", | ||
130 | "Show current attachments debug status", | ||
131 | HandleDebugAttachmentsStatus); | ||
95 | } | 132 | } |
96 | 133 | ||
97 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI | 134 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI |
98 | } | 135 | } |
99 | 136 | ||
100 | private void HandleDebugAttachments(string module, string[] args) | 137 | private void HandleDebugAttachmentsLog(string module, string[] args) |
101 | { | 138 | { |
102 | int debugLevel; | 139 | int debugLevel; |
103 | 140 | ||
104 | if (!(args.Length == 3 && int.TryParse(args[2], out debugLevel))) | 141 | if (!(args.Length == 4 && int.TryParse(args[3], out debugLevel))) |
105 | { | 142 | { |
106 | MainConsole.Instance.OutputFormat("Usage: debug attachments [0|1]"); | 143 | MainConsole.Instance.OutputFormat("Usage: debug attachments log [0|1]"); |
107 | } | 144 | } |
108 | else | 145 | else |
109 | { | 146 | { |
@@ -113,6 +150,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
113 | } | 150 | } |
114 | } | 151 | } |
115 | 152 | ||
153 | private void HandleDebugAttachmentsThrottle(string module, string[] args) | ||
154 | { | ||
155 | int ms; | ||
156 | |||
157 | if (args.Length == 4 && int.TryParse(args[3], out ms)) | ||
158 | { | ||
159 | ThrottlePer100PrimsRezzed = ms; | ||
160 | MainConsole.Instance.OutputFormat( | ||
161 | "Attachments rez throttle per 100 prims is now {0} in {1}", ThrottlePer100PrimsRezzed, m_scene.Name); | ||
162 | |||
163 | return; | ||
164 | } | ||
165 | |||
166 | MainConsole.Instance.OutputFormat("Usage: debug attachments throttle <ms>"); | ||
167 | } | ||
168 | |||
169 | private void HandleDebugAttachmentsStatus(string module, string[] args) | ||
170 | { | ||
171 | MainConsole.Instance.OutputFormat("Settings for {0}", m_scene.Name); | ||
172 | MainConsole.Instance.OutputFormat("Debug logging level: {0}", DebugLevel); | ||
173 | MainConsole.Instance.OutputFormat("Throttle per 100 prims: {0}ms", ThrottlePer100PrimsRezzed); | ||
174 | } | ||
175 | |||
116 | /// <summary> | 176 | /// <summary> |
117 | /// Listen for client triggered running state changes so that we can persist the script's object if necessary. | 177 | /// Listen for client triggered running state changes so that we can persist the script's object if necessary. |
118 | /// </summary> | 178 | /// </summary> |
@@ -273,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
273 | List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); | 333 | List<AvatarAttachment> attachments = sp.Appearance.GetAttachments(); |
274 | foreach (AvatarAttachment attach in attachments) | 334 | foreach (AvatarAttachment attach in attachments) |
275 | { | 335 | { |
276 | uint p = (uint)attach.AttachPoint; | 336 | uint attachmentPt = (uint)attach.AttachPoint; |
277 | 337 | ||
278 | // m_log.DebugFormat( | 338 | // m_log.DebugFormat( |
279 | // "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}", | 339 | // "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}", |
@@ -302,13 +362,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
302 | // If we're an NPC then skip all the item checks and manipulations since we don't have an | 362 | // If we're an NPC then skip all the item checks and manipulations since we don't have an |
303 | // inventory right now. | 363 | // inventory right now. |
304 | RezSingleAttachmentFromInventoryInternal( | 364 | RezSingleAttachmentFromInventoryInternal( |
305 | sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, p, true, d); | 365 | sp, sp.PresenceType == PresenceType.Npc ? UUID.Zero : attach.ItemID, attach.AssetID, attachmentPt, true, d); |
306 | } | 366 | } |
307 | catch (Exception e) | 367 | catch (Exception e) |
308 | { | 368 | { |
309 | UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId; | 369 | UUID agentId = (sp.ControllingClient == null) ? default(UUID) : sp.ControllingClient.AgentId; |
310 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}", | 370 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}", |
311 | attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace); | 371 | attach.ItemID, attach.AssetID, attachmentPt, agentId, e.Message, e.StackTrace); |
312 | } | 372 | } |
313 | } | 373 | } |
314 | } | 374 | } |
@@ -422,13 +482,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
422 | attachPos = Vector3.Zero; | 482 | attachPos = Vector3.Zero; |
423 | } | 483 | } |
424 | 484 | ||
425 | // AttachmentPt 0 (default) means the client chose to 'wear' the attachment. | 485 | // if the attachment point is the same as previous, make sure we get the saved |
486 | // position info. | ||
487 | if (attachmentPt != 0 && attachmentPt == group.RootPart.Shape.LastAttachPoint) | ||
488 | { | ||
489 | attachPos = group.RootPart.AttachedPos; | ||
490 | } | ||
491 | |||
492 | // AttachmentPt 0 means the client chose to 'wear' the attachment. | ||
426 | if (attachmentPt == (uint)AttachmentPoint.Default) | 493 | if (attachmentPt == (uint)AttachmentPoint.Default) |
427 | { | 494 | { |
428 | // Check object for stored attachment point | 495 | // Check object for stored attachment point |
429 | attachmentPt = group.AttachmentPoint; | 496 | attachmentPt = group.AttachmentPoint; |
430 | } | 497 | } |
431 | 498 | ||
499 | // if we didn't find an attach point, look for where it was last attached | ||
500 | if (attachmentPt == 0) | ||
501 | { | ||
502 | attachmentPt = (uint)group.RootPart.Shape.LastAttachPoint; | ||
503 | attachPos = group.RootPart.AttachedPos; | ||
504 | group.HasGroupChanged = true; | ||
505 | } | ||
506 | |||
432 | // if we still didn't find a suitable attachment point....... | 507 | // if we still didn't find a suitable attachment point....... |
433 | if (attachmentPt == 0) | 508 | if (attachmentPt == 0) |
434 | { | 509 | { |
@@ -610,6 +685,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
610 | if (changed && m_scene.AvatarFactory != null) | 685 | if (changed && m_scene.AvatarFactory != null) |
611 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); | 686 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
612 | 687 | ||
688 | so.RootPart.Shape.LastAttachPoint = (byte)so.AttachmentPoint; | ||
689 | |||
613 | sp.RemoveAttachment(so); | 690 | sp.RemoveAttachment(so); |
614 | so.FromItemID = UUID.Zero; | 691 | so.FromItemID = UUID.Zero; |
615 | 692 | ||
@@ -841,7 +918,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
841 | m_scene.ForEachClient( | 918 | m_scene.ForEachClient( |
842 | client => | 919 | client => |
843 | { if (client.AgentId != so.AttachedAvatar) | 920 | { if (client.AgentId != so.AttachedAvatar) |
844 | client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId }); | 921 | client.SendKillObject(new List<uint>() { so.LocalId }); |
845 | }); | 922 | }); |
846 | } | 923 | } |
847 | 924 | ||
@@ -982,8 +1059,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
982 | 1059 | ||
983 | if (DebugLevel > 0) | 1060 | if (DebugLevel > 0) |
984 | m_log.DebugFormat( | 1061 | m_log.DebugFormat( |
985 | "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", | 1062 | "[ATTACHMENTS MODULE]: Rezzed single object {0} with {1} prims for attachment to {2} on point {3} in {4}", |
986 | objatt.Name, sp.Name, attachmentPt, m_scene.Name); | 1063 | objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); |
987 | 1064 | ||
988 | // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. | 1065 | // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. |
989 | objatt.HasGroupChanged = false; | 1066 | objatt.HasGroupChanged = false; |
@@ -1020,7 +1097,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
1020 | } | 1097 | } |
1021 | 1098 | ||
1022 | if (tainted) | 1099 | if (tainted) |
1023 | objatt.HasGroupChanged = true; | 1100 | objatt.HasGroupChanged = true; |
1101 | |||
1102 | if (ThrottlePer100PrimsRezzed > 0) | ||
1103 | { | ||
1104 | int throttleMs = (int)Math.Round((float)objatt.PrimCount / 100 * ThrottlePer100PrimsRezzed); | ||
1105 | |||
1106 | if (DebugLevel > 0) | ||
1107 | m_log.DebugFormat( | ||
1108 | "[ATTACHMENTS MODULE]: Throttling by {0}ms after rez of {1} with {2} prims for attachment to {3} on point {4} in {5}", | ||
1109 | throttleMs, objatt.Name, objatt.PrimCount, sp.Name, attachmentPt, m_scene.Name); | ||
1110 | |||
1111 | Thread.Sleep(throttleMs); | ||
1112 | } | ||
1024 | 1113 | ||
1025 | return objatt; | 1114 | return objatt; |
1026 | } | 1115 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 1a38619..f023e77 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -38,6 +38,8 @@ using NUnit.Framework; | |||
38 | using OpenMetaverse; | 38 | using OpenMetaverse; |
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Framework.Communications; | 40 | using OpenSim.Framework.Communications; |
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Region.CoreModules.Avatar.Attachments; | 43 | using OpenSim.Region.CoreModules.Avatar.Attachments; |
42 | using OpenSim.Region.CoreModules.Framework; | 44 | using OpenSim.Region.CoreModules.Framework; |
43 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | 45 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; |
@@ -717,7 +719,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
717 | SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; | 719 | SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; |
718 | 720 | ||
719 | m_numberOfAttachEventsFired = 0; | 721 | m_numberOfAttachEventsFired = 0; |
720 | scene.IncomingCloseAgent(presence.UUID, false); | 722 | scene.CloseAgent(presence.UUID, false); |
721 | 723 | ||
722 | // Check that we can't retrieve this attachment from the scene. | 724 | // Check that we can't retrieve this attachment from the scene. |
723 | Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); | 725 | Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); |
@@ -797,11 +799,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
797 | } | 799 | } |
798 | 800 | ||
799 | [Test] | 801 | [Test] |
800 | public void TestSameSimulatorNeighbouringRegionsTeleport() | 802 | public void TestSameSimulatorNeighbouringRegionsTeleportV1() |
801 | { | 803 | { |
802 | TestHelpers.InMethod(); | 804 | TestHelpers.InMethod(); |
803 | // TestHelpers.EnableLogging(); | 805 | // TestHelpers.EnableLogging(); |
804 | 806 | ||
807 | BaseHttpServer httpServer = new BaseHttpServer(99999); | ||
808 | MainServer.AddHttpServer(httpServer); | ||
809 | MainServer.Instance = httpServer; | ||
810 | |||
805 | AttachmentsModule attModA = new AttachmentsModule(); | 811 | AttachmentsModule attModA = new AttachmentsModule(); |
806 | AttachmentsModule attModB = new AttachmentsModule(); | 812 | AttachmentsModule attModB = new AttachmentsModule(); |
807 | EntityTransferModule etmA = new EntityTransferModule(); | 813 | EntityTransferModule etmA = new EntityTransferModule(); |
@@ -830,14 +836,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
830 | SceneHelpers.SetupSceneModules( | 836 | SceneHelpers.SetupSceneModules( |
831 | sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); | 837 | sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); |
832 | 838 | ||
839 | // FIXME: Hack - this is here temporarily to revert back to older entity transfer behaviour | ||
840 | lscm.ServiceVersion = "SIMULATION/0.1"; | ||
841 | |||
833 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); | 842 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); |
834 | 843 | ||
835 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); | 844 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); |
836 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); | 845 | TestClient tc = new TestClient(acd, sceneA); |
837 | List<TestClient> destinationTestClients = new List<TestClient>(); | 846 | List<TestClient> destinationTestClients = new List<TestClient>(); |
838 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | 847 | EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); |
839 | 848 | ||
840 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | 849 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); |
841 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); | 850 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); |
842 | 851 | ||
843 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); | 852 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); |
@@ -895,5 +904,115 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
895 | // Check events | 904 | // Check events |
896 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); | 905 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); |
897 | } | 906 | } |
907 | |||
908 | [Test] | ||
909 | public void TestSameSimulatorNeighbouringRegionsTeleportV2() | ||
910 | { | ||
911 | TestHelpers.InMethod(); | ||
912 | // TestHelpers.EnableLogging(); | ||
913 | |||
914 | BaseHttpServer httpServer = new BaseHttpServer(99999); | ||
915 | MainServer.AddHttpServer(httpServer); | ||
916 | MainServer.Instance = httpServer; | ||
917 | |||
918 | AttachmentsModule attModA = new AttachmentsModule(); | ||
919 | AttachmentsModule attModB = new AttachmentsModule(); | ||
920 | EntityTransferModule etmA = new EntityTransferModule(); | ||
921 | EntityTransferModule etmB = new EntityTransferModule(); | ||
922 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); | ||
923 | |||
924 | IConfigSource config = new IniConfigSource(); | ||
925 | IConfig modulesConfig = config.AddConfig("Modules"); | ||
926 | modulesConfig.Set("EntityTransferModule", etmA.Name); | ||
927 | modulesConfig.Set("SimulationServices", lscm.Name); | ||
928 | |||
929 | modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); | ||
930 | |||
931 | SceneHelpers sh = new SceneHelpers(); | ||
932 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); | ||
933 | TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); | ||
934 | |||
935 | SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); | ||
936 | SceneHelpers.SetupSceneModules( | ||
937 | sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule()); | ||
938 | SceneHelpers.SetupSceneModules( | ||
939 | sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); | ||
940 | |||
941 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); | ||
942 | |||
943 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); | ||
944 | TestClient tc = new TestClient(acd, sceneA); | ||
945 | List<TestClient> destinationTestClients = new List<TestClient>(); | ||
946 | EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); | ||
947 | |||
948 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); | ||
949 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); | ||
950 | |||
951 | Assert.That(destinationTestClients.Count, Is.EqualTo(1)); | ||
952 | Assert.That(destinationTestClients[0], Is.Not.Null); | ||
953 | |||
954 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); | ||
955 | |||
956 | sceneA.AttachmentsModule.RezSingleAttachmentFromInventory( | ||
957 | beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest); | ||
958 | |||
959 | Vector3 teleportPosition = new Vector3(10, 11, 12); | ||
960 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | ||
961 | |||
962 | // Here, we need to make clientA's receipt of SendRegionTeleport trigger clientB's CompleteMovement(). This | ||
963 | // is to operate the teleport V2 mechanism where the EntityTransferModule will first request the client to | ||
964 | // CompleteMovement to the region and then call UpdateAgent to the destination region to confirm the receipt | ||
965 | // Both these operations will occur on different threads and will wait for each other. | ||
966 | // We have to do this via ThreadPool directly since FireAndForget has been switched to sync for the V1 | ||
967 | // test protocol, where we are trying to avoid unpredictable async operations in regression tests. | ||
968 | tc.OnTestClientSendRegionTeleport | ||
969 | += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) | ||
970 | => ThreadPool.UnsafeQueueUserWorkItem(o => destinationTestClients[0].CompleteMovement(), null); | ||
971 | |||
972 | m_numberOfAttachEventsFired = 0; | ||
973 | sceneA.RequestTeleportLocation( | ||
974 | beforeTeleportSp.ControllingClient, | ||
975 | sceneB.RegionInfo.RegionHandle, | ||
976 | teleportPosition, | ||
977 | teleportLookAt, | ||
978 | (uint)TeleportFlags.ViaLocation); | ||
979 | |||
980 | // Check attachments have made it into sceneB | ||
981 | ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); | ||
982 | |||
983 | // This is appearance data, as opposed to actually rezzed attachments | ||
984 | List<AvatarAttachment> sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments(); | ||
985 | Assert.That(sceneBAttachments.Count, Is.EqualTo(1)); | ||
986 | Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); | ||
987 | Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID)); | ||
988 | Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); | ||
989 | Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
990 | |||
991 | // This is the actual attachment | ||
992 | List<SceneObjectGroup> actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments(); | ||
993 | Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1)); | ||
994 | SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; | ||
995 | Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); | ||
996 | Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); | ||
997 | |||
998 | Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); | ||
999 | |||
1000 | // Check attachments have been removed from sceneA | ||
1001 | ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID); | ||
1002 | |||
1003 | // Since this is appearance data, it is still present on the child avatar! | ||
1004 | List<AvatarAttachment> sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments(); | ||
1005 | Assert.That(sceneAAttachments.Count, Is.EqualTo(1)); | ||
1006 | Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
1007 | |||
1008 | // This is the actual attachment, which should no longer exist | ||
1009 | List<SceneObjectGroup> actualSceneAAttachments = afterTeleportSceneASp.GetAttachments(); | ||
1010 | Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); | ||
1011 | |||
1012 | Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); | ||
1013 | |||
1014 | // Check events | ||
1015 | Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0)); | ||
1016 | } | ||
898 | } | 1017 | } |
899 | } | 1018 | } |