aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorMelanie2013-03-23 11:31:34 +0100
committerMelanie2013-03-23 11:31:34 +0100
commit8bc43ea773f6a56d34222f03c6ad7645b59347bf (patch)
tree4426b54b77a53014c7e90019124f26e338e40d26 /OpenSim/Region
parentFix SceneManager to use the new automatic property throughout. (diff)
parentMerge branch 'avination' into careminster (diff)
downloadopensim-SC-8bc43ea773f6a56d34222f03c6ad7645b59347bf.zip
opensim-SC-8bc43ea773f6a56d34222f03c6ad7645b59347bf.tar.gz
opensim-SC-8bc43ea773f6a56d34222f03c6ad7645b59347bf.tar.bz2
opensim-SC-8bc43ea773f6a56d34222f03c6ad7645b59347bf.tar.xz
Merge branch 'master' of ssh://3dhosting.de/var/git/careminster
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs17
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs10
-rw-r--r--OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs12
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs103
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs29
-rwxr-xr-xOpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs16
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs7
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs135
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs17
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs5
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs24
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs1
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs195
20 files changed, 502 insertions, 94 deletions
diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
index 96e8f35..08e7cb7 100644
--- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs
@@ -369,8 +369,7 @@ namespace OpenSim.Region.CoreModules.Asset
369 AssetBase asset = null; 369 AssetBase asset = null;
370 370
371 string filename = GetFileName(id); 371 string filename = GetFileName(id);
372 372 while (File.Exists(filename))
373 if (File.Exists(filename))
374 { 373 {
375 FileStream stream = null; 374 FileStream stream = null;
376 try 375 try
@@ -381,6 +380,8 @@ namespace OpenSim.Region.CoreModules.Asset
381 asset = (AssetBase)bformatter.Deserialize(stream); 380 asset = (AssetBase)bformatter.Deserialize(stream);
382 381
383 m_DiskHits++; 382 m_DiskHits++;
383
384 break;
384 } 385 }
385 catch (System.Runtime.Serialization.SerializationException e) 386 catch (System.Runtime.Serialization.SerializationException e)
386 { 387 {
@@ -393,12 +394,24 @@ namespace OpenSim.Region.CoreModules.Asset
393 // {different version of AssetBase} -- we should attempt to 394 // {different version of AssetBase} -- we should attempt to
394 // delete it and re-cache 395 // delete it and re-cache
395 File.Delete(filename); 396 File.Delete(filename);
397
398 break;
399 }
400 catch (IOException e)
401 {
402 // This is a sharing violation: File exists but can't be opened because it's
403 // being written
404 Thread.Sleep(100);
405
406 continue;
396 } 407 }
397 catch (Exception e) 408 catch (Exception e)
398 { 409 {
399 m_log.WarnFormat( 410 m_log.WarnFormat(
400 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", 411 "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}",
401 filename, id, e.Message, e.StackTrace); 412 filename, id, e.Message, e.StackTrace);
413
414 break;
402 } 415 }
403 finally 416 finally
404 { 417 {
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index c94d152..f62512e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -573,8 +573,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
573 } 573 }
574 574
575// m_log.DebugFormat( 575// m_log.DebugFormat(
576// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}", 576// "[ATTACHMENTS MODULE]: Detaching object {0} {1} (FromItemID {2}) for {3} in {4}",
577// so.Name, so.LocalId, sp.Name, m_scene.Name); 577// so.Name, so.LocalId, so.FromItemID, sp.Name, m_scene.Name);
578 578
579 // Scripts MUST be snapshotted before the object is 579 // Scripts MUST be snapshotted before the object is
580 // removed from the scene because doing otherwise will 580 // removed from the scene because doing otherwise will
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
index dee8ce3..a8fe045 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs
@@ -829,7 +829,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
829 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); 829 sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
830 830
831 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); 831 UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
832 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager); 832
833 AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
834 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
835 List<TestClient> destinationTestClients = new List<TestClient>();
836 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
837
838 ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
833 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); 839 beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
834 840
835 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); 841 InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
@@ -848,7 +854,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
848 teleportLookAt, 854 teleportLookAt,
849 (uint)TeleportFlags.ViaLocation); 855 (uint)TeleportFlags.ViaLocation);
850 856
851 ((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); 857 destinationTestClients[0].CompleteMovement();
852 858
853 // Check attachments have made it into sceneB 859 // Check attachments have made it into sceneB
854 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); 860 ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
index 864f33e..51fe1ea 100644
--- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs
@@ -361,7 +361,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
361 361
362 public void QueueAppearanceSave(UUID agentid) 362 public void QueueAppearanceSave(UUID agentid)
363 { 363 {
364 // m_log.WarnFormat("[AVFACTORY]: Queue appearance save for {0}", agentid); 364// m_log.DebugFormat("[AVFACTORY]: Queueing appearance save for {0}", agentid);
365 365
366 // 10000 ticks per millisecond, 1000 milliseconds per second 366 // 10000 ticks per millisecond, 1000 milliseconds per second
367 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000); 367 long timestamp = DateTime.Now.Ticks + Convert.ToInt64(m_savetime * 1000 * 10000);
@@ -658,7 +658,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
658 return; 658 return;
659 } 659 }
660 660
661 // m_log.WarnFormat("[AVFACTORY] avatar {0} save appearance",agentid); 661// m_log.DebugFormat("[AVFACTORY]: Saving appearance for avatar {0}", agentid);
662 662
663 // This could take awhile since it needs to pull inventory 663 // This could take awhile since it needs to pull inventory
664 // 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 664 // 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
667 // multiple save requests. 667 // multiple save requests.
668 SetAppearanceAssets(sp.UUID, sp.Appearance); 668 SetAppearanceAssets(sp.UUID, sp.Appearance);
669 669
670// List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
671// foreach (AvatarAttachment att in attachments)
672// {
673// m_log.DebugFormat(
674// "[AVFACTORY]: For {0} saving attachment {1} at point {2}",
675// sp.Name, att.ItemID, att.AttachPoint);
676// }
677
670 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance); 678 m_scene.AvatarService.SetAppearance(agentid, sp.Appearance);
671 679
672 // Trigger this here because it's the final step in the set/queue/save process for appearance setting. 680 // Trigger this here because it's the final step in the set/queue/save process for appearance setting.
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index 4c3f1cc..174642d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -256,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
256 // If camera is moved into client, then camera position can be used 256 // If camera is moved into client, then camera position can be used
257 // MT: No, it can't, as chat is heard from the avatar position, not 257 // MT: No, it can't, as chat is heard from the avatar position, not
258 // the camera position. 258 // the camera position.
259 s.ForEachRootScenePresence( 259 s.ForEachScenePresence(
260 delegate(ScenePresence presence) 260 delegate(ScenePresence presence)
261 { 261 {
262 if (destination != UUID.Zero && presence.UUID != destination) 262 if (destination != UUID.Zero && presence.UUID != destination)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index b2c9564..25334b9 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -167,6 +167,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
167 167
168 if (!DisableInterRegionTeleportCancellation) 168 if (!DisableInterRegionTeleportCancellation)
169 client.OnTeleportCancel += OnClientCancelTeleport; 169 client.OnTeleportCancel += OnClientCancelTeleport;
170
171 client.OnConnectionClosed += OnConnectionClosed;
170 } 172 }
171 173
172 public virtual void Close() {} 174 public virtual void Close() {}
@@ -185,6 +187,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
185 187
186 #region Agent Teleports 188 #region Agent Teleports
187 189
190 private void OnConnectionClosed(IClientAPI client)
191 {
192 if (client.IsLoggingOut)
193 {
194 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting);
195
196 m_log.DebugFormat(
197 "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout",
198 client.Name, Scene.Name);
199 }
200 }
201
188 private void OnClientCancelTeleport(IClientAPI client) 202 private void OnClientCancelTeleport(IClientAPI client)
189 { 203 {
190 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling); 204 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
@@ -520,12 +534,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
520 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", 534 "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.",
521 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); 535 sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName);
522 536
523// if (!sp.ValidateAttachments())
524// {
525// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
526// return;
527// }
528
529 string reason; 537 string reason;
530 string version; 538 string version;
531 if (!Scene.SimulationService.QueryAccess( 539 if (!Scene.SimulationService.QueryAccess(
@@ -588,6 +596,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
588 } 596 }
589 597
590 // Let's create an agent there if one doesn't exist yet. 598 // Let's create an agent there if one doesn't exist yet.
599 // NOTE: logout will always be false for a non-HG teleport.
591 bool logout = false; 600 bool logout = false;
592 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) 601 if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout))
593 { 602 {
@@ -608,6 +617,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
608 617
609 return; 618 return;
610 } 619 }
620 else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
621 {
622 m_log.DebugFormat(
623 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.",
624 sp.Name, finalDestination.RegionName, sp.Scene.Name);
625
626 return;
627 }
611 628
612 // Past this point we have to attempt clean up if the teleport fails, so update transfer state. 629 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
613 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 630 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
@@ -630,11 +647,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
630 647
631 if (m_eqModule != null) 648 if (m_eqModule != null)
632 { 649 {
650 // The EnableSimulator message makes the client establish a connection with the destination
651 // simulator by sending the initial UseCircuitCode UDP packet to the destination containing the
652 // correct circuit code.
633 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); 653 m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID);
634 654
635 // ES makes the client send a UseCircuitCode message to the destination, 655 // XXX: Is this wait necessary? We will always end up waiting on UpdateAgent for the destination
636 // which triggers a bunch of things there. 656 // simulator to confirm that it has established communication with the viewer.
637 // So let's wait
638 Thread.Sleep(200); 657 Thread.Sleep(200);
639 658
640 // At least on LL 3.3.4 for teleports between different regions on the same simulator this appears 659 // 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
645 } 664 }
646 else 665 else
647 { 666 {
667 // XXX: This is a little misleading since we're information the client of its avatar destination,
668 // which may or may not be a neighbour region of the source region. This path is probably little
669 // used anyway (with EQ being the one used). But it is currently being used for test code.
648 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); 670 sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint);
649 } 671 }
650 } 672 }
@@ -662,14 +684,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
662 684
663 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); 685 //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
664 686
687 // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to
688 // establish th econnection to the destination which makes it return true.
689 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
690 {
691 m_log.DebugFormat(
692 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent",
693 sp.Name, finalDestination.RegionName, sp.Scene.Name);
694
695 return;
696 }
697
698 // A common teleport failure occurs when we can send CreateAgent to the
699 // destination region but the viewer cannot establish the connection (e.g. due to network issues between
700 // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then
701 // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail().
665 if (!UpdateAgent(reg, finalDestination, agent, sp)) 702 if (!UpdateAgent(reg, finalDestination, agent, sp))
666 { 703 {
667 // Region doesn't take it 704 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
705 {
706 m_log.DebugFormat(
707 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.",
708 sp.Name, finalDestination.RegionName, sp.Scene.Name);
709
710 return;
711 }
712
668 m_log.WarnFormat( 713 m_log.WarnFormat(
669 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", 714 "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.",
670 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 715 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
671 716
672 Fail(sp, finalDestination, logout); 717 Fail(sp, finalDestination, logout, "Connection between viewer and destination region could not be established.");
673 return; 718 return;
674 } 719 }
675 720
@@ -679,7 +724,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
679 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", 724 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
680 sp.Name, finalDestination.RegionName, sp.Scene.Name); 725 sp.Name, finalDestination.RegionName, sp.Scene.Name);
681 726
682 CleanupAbortedInterRegionTeleport(sp, finalDestination); 727 CleanupFailedInterRegionTeleport(sp, finalDestination);
683 728
684 return; 729 return;
685 } 730 }
@@ -688,6 +733,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
688 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 733 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
689 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); 734 capsPath, sp.Scene.RegionInfo.RegionName, sp.Name);
690 735
736 // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator,
737 // where that neighbour simulator could otherwise request a child agent create on the source which then
738 // closes our existing agent which is still signalled as root.
739 sp.IsChildAgent = true;
740
691 if (m_eqModule != null) 741 if (m_eqModule != null)
692 { 742 {
693 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); 743 m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID);
@@ -698,19 +748,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
698 teleportFlags, capsPath); 748 teleportFlags, capsPath);
699 } 749 }
700 750
701 // Let's set this to true tentatively. This does not trigger OnChildAgent
702 sp.IsChildAgent = true;
703
704 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which 751 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
705 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation 752 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
706 // that the client contacted the destination before we close things here. 753 // that the client contacted the destination before we close things here.
707 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) 754 if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID))
708 { 755 {
756 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting)
757 {
758 m_log.DebugFormat(
759 "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.",
760 sp.Name, finalDestination.RegionName, sp.Scene.Name);
761
762 return;
763 }
764
709 m_log.WarnFormat( 765 m_log.WarnFormat(
710 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", 766 "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.",
711 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); 767 sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName);
712 768
713 Fail(sp, finalDestination, logout); 769 Fail(sp, finalDestination, logout, "Destination region did not signal teleport completion.");
714 return; 770 return;
715 } 771 }
716 772
@@ -733,8 +789,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
733 // Now let's make it officially a child agent 789 // Now let's make it officially a child agent
734 sp.MakeChildAgent(); 790 sp.MakeChildAgent();
735 791
736// sp.Scene.CleanDroppedAttachments();
737
738 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone 792 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
739 793
740 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) 794 if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg))
@@ -774,7 +828,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
774 /// <remarks> 828 /// <remarks>
775 /// <param name='sp'> </param> 829 /// <param name='sp'> </param>
776 /// <param name='finalDestination'></param> 830 /// <param name='finalDestination'></param>
777 protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) 831 protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
778 { 832 {
779 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 833 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
780 834
@@ -793,12 +847,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
793 /// <param name='sp'></param> 847 /// <param name='sp'></param>
794 /// <param name='finalDestination'></param> 848 /// <param name='finalDestination'></param>
795 /// <param name='logout'></param> 849 /// <param name='logout'></param>
796 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 850 /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param>
851 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason)
797 { 852 {
798 CleanupAbortedInterRegionTeleport(sp, finalDestination); 853 CleanupFailedInterRegionTeleport(sp, finalDestination);
799 854
800 sp.ControllingClient.SendTeleportFailed( 855 sp.ControllingClient.SendTeleportFailed(
801 string.Format("Problems connecting to destination {0}", finalDestination.RegionName)); 856 string.Format(
857 "Problems connecting to destination {0}, reason: {1}", finalDestination.RegionName, reason));
858
802 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 859 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
803 } 860 }
804 861
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index 8b2cd09..e903383 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -51,11 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 /// This is a state machine. 51 /// This is a state machine.
52 /// 52 ///
53 /// [Entry] => Preparing 53 /// [Entry] => Preparing
54 /// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] }
55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting }
56 /// Cancelling => CleaningUp 56 /// Cancelling => CleaningUp || Aborting
57 /// ReceivedAtDestination => CleaningUp 57 /// ReceivedAtDestination => CleaningUp || Aborting
58 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
59 /// Aborting => [Exit]
59 /// 60 ///
60 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp 61 /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp
61 /// However, any state can transition to CleaningUp if the teleport has failed. 62 /// However, any state can transition to CleaningUp if the teleport has failed.
@@ -66,7 +67,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
66 Transferring, // The agent is in the process of being transferred to a destination 67 Transferring, // The agent is in the process of being transferred to a destination
67 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received 68 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
68 CleaningUp, // The agent is being changed to child/removed after a transfer 69 CleaningUp, // The agent is being changed to child/removed after a transfer
69 Cancelling // The user has cancelled the teleport but we have yet to act upon this. 70 Cancelling, // The user has cancelled the teleport but we have yet to act upon this.
71 Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed
70 } 72 }
71 73
72 /// <summary> 74 /// <summary>
@@ -134,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
134 // Illegal to try and update an agent that's not actually in transit. 136 // Illegal to try and update an agent that's not actually in transit.
135 if (!m_agentsInTransit.ContainsKey(id)) 137 if (!m_agentsInTransit.ContainsKey(id))
136 { 138 {
137 if (newState != AgentTransferState.Cancelling) 139 if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting)
138 failureMessage = string.Format( 140 failureMessage = string.Format(
139 "Agent with ID {0} is not registered as in transit in {1}", 141 "Agent with ID {0} is not registered as in transit in {1}",
140 id, m_mod.Scene.RegionInfo.RegionName); 142 id, m_mod.Scene.RegionInfo.RegionName);
@@ -145,7 +147,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
145 { 147 {
146 oldState = m_agentsInTransit[id]; 148 oldState = m_agentsInTransit[id];
147 149
148 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 150 if (newState == AgentTransferState.Aborting)
151 {
152 transitionOkay = true;
153 }
154 else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
149 { 155 {
150 transitionOkay = true; 156 transitionOkay = true;
151 } 157 }
@@ -292,8 +298,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
292 298
293 // There should be no race condition here since no other code should be removing the agent transfer or 299 // There should be no race condition here since no other code should be removing the agent transfer or
294 // changing the state to another other than Transferring => ReceivedAtDestination. 300 // changing the state to another other than Transferring => ReceivedAtDestination.
295 while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) 301
302 while (count-- > 0)
296 { 303 {
304 lock (m_agentsInTransit)
305 {
306 if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination)
307 break;
308 }
309
297// m_log.Debug(" >>> Waiting... " + count); 310// m_log.Debug(" >>> Waiting... " + count);
298 Thread.Sleep(100); 311 Thread.Sleep(100);
299 } 312 }
diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
index 3c8e0ef..2fe9026 100755
--- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
+++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs
@@ -136,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
136 { 136 {
137 lock (m_logFileWriteLock) 137 lock (m_logFileWriteLock)
138 { 138 {
139 DateTime now = DateTime.Now; 139 DateTime now = DateTime.UtcNow;
140 if (m_logFile == null || now > m_logFileEndTime) 140 if (m_logFile == null || now > m_logFileEndTime)
141 { 141 {
142 if (m_logFile != null) 142 if (m_logFile != null)
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 92d0aff..6b031ae 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -2990,8 +2990,22 @@ namespace OpenSim.Region.Framework.Scenes
2990 sp.IsChildAgent = false; 2990 sp.IsChildAgent = false;
2991 sp.IsLoggingIn = true; 2991 sp.IsLoggingIn = true;
2992 2992
2993 // We leave a 5 second pause before attempting to rez attachments to avoid a clash with
2994 // version 3 viewers that maybe doing their own attachment rezzing related to their current
2995 // outfit folder on startup. If these operations do clash, then the symptoms are invisible
2996 // attachments until one zooms in on the avatar.
2997 //
2998 // We do not pause if we are launching on the same thread anyway in order to avoid pointlessly
2999 // delaying any attachment related regression tests.
2993 if (AttachmentsModule != null) 3000 if (AttachmentsModule != null)
2994 Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); 3001 Util.FireAndForget(
3002 o =>
3003 {
3004 if (Util.FireAndForgetMethod != FireAndForgetMethod.None)
3005 Thread.Sleep(5000);
3006
3007 AttachmentsModule.RezAttachments(sp);
3008 });
2995 } 3009 }
2996 } 3010 }
2997 else 3011 else
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index d041d8b..5ed7b67 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1529,6 +1529,15 @@ namespace OpenSim.Region.Framework.Scenes
1529 1529
1530 } 1530 }
1531 1531
1532 // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region
1533 // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work.
1534 // This may be due to viewer code or it may be something we're not doing properly simulator side.
1535 lock (m_attachments)
1536 {
1537 foreach (SceneObjectGroup sog in m_attachments)
1538 sog.ScheduleGroupForFullUpdate();
1539 }
1540
1532// m_log.DebugFormat( 1541// m_log.DebugFormat(
1533// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", 1542// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
1534// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); 1543// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
index 81a2fcc..8775949 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs
@@ -94,7 +94,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests
94// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA); 94// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA);
95 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); 95 SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
96 96
97 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 97 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
98 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
99 List<TestClient> destinationTestClients = new List<TestClient>();
100 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
101
102 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
98 originalSp.AbsolutePosition = new Vector3(128, 32, 10); 103 originalSp.AbsolutePosition = new Vector3(128, 32, 10);
99 104
100// originalSp.Flying = true; 105// originalSp.Flying = true;
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
index 8dd1f3d..de4458d 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs
@@ -26,7 +26,10 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Reflection; 29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Text;
30using Nini.Config; 33using Nini.Config;
31using NUnit.Framework; 34using NUnit.Framework;
32using OpenMetaverse; 35using OpenMetaverse;
@@ -40,8 +43,6 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
40using OpenSim.Region.CoreModules.World.Permissions; 43using OpenSim.Region.CoreModules.World.Permissions;
41using OpenSim.Tests.Common; 44using OpenSim.Tests.Common;
42using OpenSim.Tests.Common.Mock; 45using OpenSim.Tests.Common.Mock;
43using System.IO;
44using System.Text;
45 46
46namespace OpenSim.Region.Framework.Scenes.Tests 47namespace OpenSim.Region.Framework.Scenes.Tests
47{ 48{
@@ -68,7 +69,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
68 } 69 }
69 70
70 [Test] 71 [Test]
71 public void TestSameRegionTeleport() 72 public void TestSameRegion()
72 { 73 {
73 TestHelpers.InMethod(); 74 TestHelpers.InMethod();
74// log4net.Config.XmlConfigurator.Configure(); 75// log4net.Config.XmlConfigurator.Configure();
@@ -106,10 +107,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
106 } 107 }
107 108
108 [Test] 109 [Test]
109 public void TestSameSimulatorSeparatedRegionsTeleport() 110 public void TestSameSimulatorIsolatedRegions()
110 { 111 {
111 TestHelpers.InMethod(); 112 TestHelpers.InMethod();
112// log4net.Config.XmlConfigurator.Configure(); 113// TestHelpers.EnableLogging();
113 114
114 UUID userId = TestHelpers.ParseTail(0x1); 115 UUID userId = TestHelpers.ParseTail(0x1);
115 116
@@ -141,9 +142,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
141 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 142 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
142 sp.AbsolutePosition = new Vector3(30, 31, 32); 143 sp.AbsolutePosition = new Vector3(30, 31, 32);
143 144
144 // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole 145 List<TestClient> destinationTestClients = new List<TestClient>();
145 // UDP stack (?) 146 EntityTransferHelpers.SetUpInformClientOfNeighbour((TestClient)sp.ControllingClient, destinationTestClients);
146// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB;
147 147
148 sceneA.RequestTeleportLocation( 148 sceneA.RequestTeleportLocation(
149 sp.ControllingClient, 149 sp.ControllingClient,
@@ -152,7 +152,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests
152 teleportLookAt, 152 teleportLookAt,
153 (uint)TeleportFlags.ViaLocation); 153 (uint)TeleportFlags.ViaLocation);
154 154
155 ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); 155 // SetupInformClientOfNeighbour() will have handled the callback into the target scene to setup the child
156 // agent. This call will now complete the movement of the user into the destination and upgrade the agent
157 // from child to root.
158 destinationTestClients[0].CompleteMovement();
156 159
157 Assert.That(sceneA.GetScenePresence(userId), Is.Null); 160 Assert.That(sceneA.GetScenePresence(userId), Is.Null);
158 161
@@ -177,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
177 /// Test teleport procedures when the target simulator returns false when queried about access. 180 /// Test teleport procedures when the target simulator returns false when queried about access.
178 /// </summary> 181 /// </summary>
179 [Test] 182 [Test]
180 public void TestSameSimulatorSeparatedRegionsQueryAccessFails() 183 public void TestSameSimulatorIsolatedRegions_DeniedOnQueryAccess()
181 { 184 {
182 TestHelpers.InMethod(); 185 TestHelpers.InMethod();
183// TestHelpers.EnableLogging(); 186// TestHelpers.EnableLogging();
@@ -261,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
261 /// Test teleport procedures when the target simulator create agent step is refused. 264 /// Test teleport procedures when the target simulator create agent step is refused.
262 /// </summary> 265 /// </summary>
263 [Test] 266 [Test]
264 public void TestSameSimulatorSeparatedRegionsCreateAgentFails() 267 public void TestSameSimulatorIsolatedRegions_DeniedOnCreateAgent()
265 { 268 {
266 TestHelpers.InMethod(); 269 TestHelpers.InMethod();
267// TestHelpers.EnableLogging(); 270// TestHelpers.EnableLogging();
@@ -333,13 +336,101 @@ namespace OpenSim.Region.Framework.Scenes.Tests
333// TestHelpers.DisableLogging(); 336// TestHelpers.DisableLogging();
334 } 337 }
335 338
339 /// <summary>
340 /// Test teleport when the destination region does not process (or does not receive) the connection attempt
341 /// from the viewer.
342 /// </summary>
343 /// <remarks>
344 /// This could be quite a common case where the source region can connect to a remove destination region
345 /// (for CreateAgent) but the viewer cannot reach the destination region due to network issues.
346 /// </remarks>
336 [Test] 347 [Test]
337 public void TestSameSimulatorNeighbouringRegionsTeleport() 348 public void TestSameSimulatorIsolatedRegions_DestinationDidNotProcessViewerConnection()
338 { 349 {
339 TestHelpers.InMethod(); 350 TestHelpers.InMethod();
340// TestHelpers.EnableLogging(); 351// TestHelpers.EnableLogging();
341 352
342 UUID userId = TestHelpers.ParseTail(0x1); 353 UUID userId = TestHelpers.ParseTail(0x1);
354 Vector3 preTeleportPosition = new Vector3(30, 31, 32);
355
356 EntityTransferModule etmA = new EntityTransferModule();
357 EntityTransferModule etmB = new EntityTransferModule();
358
359 LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
360
361 IConfigSource config = new IniConfigSource();
362 config.AddConfig("Modules");
363 config.Configs["Modules"].Set("EntityTransferModule", etmA.Name);
364 config.Configs["Modules"].Set("SimulationServices", lscm.Name);
365
366 config.AddConfig("EntityTransfer");
367
368 // In order to run a single threaded regression test we do not want the entity transfer module waiting
369 // for a callback from the destination scene before removing its avatar data.
370 config.Configs["EntityTransfer"].Set("wait_for_callback", false);
371
372// config.AddConfig("Startup");
373// config.Configs["Startup"].Set("serverside_object_permissions", true);
374
375 SceneHelpers sh = new SceneHelpers();
376 TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
377 TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000);
378
379 SceneHelpers.SetupSceneModules(sceneA, config, etmA );
380
381 // We need to set up the permisions module on scene B so that our later use of agent limit to deny
382 // QueryAccess won't succeed anyway because administrators are always allowed in and the default
383 // IsAdministrator if no permissions module is present is true.
384 SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB });
385
386 // Shared scene modules
387 SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
388
389 Vector3 teleportPosition = new Vector3(10, 11, 12);
390 Vector3 teleportLookAt = new Vector3(20, 21, 22);
391
392 ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
393 sp.AbsolutePosition = preTeleportPosition;
394
395 sceneA.RequestTeleportLocation(
396 sp.ControllingClient,
397 sceneB.RegionInfo.RegionHandle,
398 teleportPosition,
399 teleportLookAt,
400 (uint)TeleportFlags.ViaLocation);
401
402 // FIXME: Not setting up InformClientOfNeighbour on the TestClient means that it does not initiate
403 // communication with the destination region. But this is a very non-obvious way of doing it - really we
404 // should be forced to expicitly set this up.
405
406 Assert.That(sceneB.GetScenePresence(userId), Is.Null);
407
408 ScenePresence sceneASp = sceneA.GetScenePresence(userId);
409 Assert.That(sceneASp, Is.Not.Null);
410 Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName));
411 Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition));
412
413 Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1));
414 Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0));
415 Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0));
416 Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0));
417
418 // TODO: Add assertions to check correct circuit details in both scenes.
419
420 // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera
421 // position instead).
422// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt));
423
424// TestHelpers.DisableLogging();
425 }
426
427 [Test]
428 public void TestSameSimulatorNeighbouringRegions()
429 {
430 TestHelpers.InMethod();
431 TestHelpers.EnableLogging();
432
433 UUID userId = TestHelpers.ParseTail(0x1);
343 434
344 EntityTransferModule etmA = new EntityTransferModule(); 435 EntityTransferModule etmA = new EntityTransferModule();
345 EntityTransferModule etmB = new EntityTransferModule(); 436 EntityTransferModule etmB = new EntityTransferModule();
@@ -366,10 +457,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests
366 Vector3 teleportPosition = new Vector3(10, 11, 12); 457 Vector3 teleportPosition = new Vector3(10, 11, 12);
367 Vector3 teleportLookAt = new Vector3(20, 21, 22); 458 Vector3 teleportLookAt = new Vector3(20, 21, 22);
368 459
369 ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); 460 AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
370 originalSp.AbsolutePosition = new Vector3(30, 31, 32); 461 TestClient tc = new TestClient(acd, sceneA, sh.SceneManager);
462 List<TestClient> destinationTestClients = new List<TestClient>();
463 EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients);
464
465 ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager);
466 beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32);
371 467
372 ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId);
373 Assert.That(beforeSceneASp, Is.Not.Null); 468 Assert.That(beforeSceneASp, Is.Not.Null);
374 Assert.That(beforeSceneASp.IsChildAgent, Is.False); 469 Assert.That(beforeSceneASp.IsChildAgent, Is.False);
375 470
@@ -377,10 +472,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
377 Assert.That(beforeSceneBSp, Is.Not.Null); 472 Assert.That(beforeSceneBSp, Is.Not.Null);
378 Assert.That(beforeSceneBSp.IsChildAgent, Is.True); 473 Assert.That(beforeSceneBSp.IsChildAgent, Is.True);
379 474
380 // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole 475 // In this case, we will not receieve a second InformClientOfNeighbour since the viewer already knows
381 // UDP stack (?) 476 // about the neighbour region it is teleporting to.
382// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB;
383
384 sceneA.RequestTeleportLocation( 477 sceneA.RequestTeleportLocation(
385 beforeSceneASp.ControllingClient, 478 beforeSceneASp.ControllingClient,
386 sceneB.RegionInfo.RegionHandle, 479 sceneB.RegionInfo.RegionHandle,
@@ -388,7 +481,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
388 teleportLookAt, 481 teleportLookAt,
389 (uint)TeleportFlags.ViaLocation); 482 (uint)TeleportFlags.ViaLocation);
390 483
391 ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); 484 destinationTestClients[0].CompleteMovement();
392 485
393 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); 486 ScenePresence afterSceneASp = sceneA.GetScenePresence(userId);
394 Assert.That(afterSceneASp, Is.Not.Null); 487 Assert.That(afterSceneASp, Is.Not.Null);
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
index d97e3b3..0333747 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
@@ -176,16 +176,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", 176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, 177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); 178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
179 ct.Rows.Add( 179
180 new ConsoleDisplayTableRow( 180 ct.AddRow(
181 new List<string>() 181 attachmentObject.Name,
182 { 182 attachmentObject.LocalId,
183 attachmentObject.Name, 183 attachmentObject.FromItemID,
184 attachmentObject.LocalId.ToString(), 184 ((AttachmentPoint)attachmentObject.AttachmentPoint),
185 attachmentObject.FromItemID.ToString(), 185 attachmentObject.RootPart.AttachedPos);
186 ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
187 attachmentObject.RootPart.AttachedPos.ToString()
188 }));
189// } 186// }
190 } 187 }
191 188
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
index 3a27d2c..77ea3ed 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -286,7 +286,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin)
286{ 286{
287 BulletShapeUnman shapeu = shape as BulletShapeUnman; 287 BulletShapeUnman shapeu = shape as BulletShapeUnman;
288 if (shapeu != null && shapeu.HasPhysicalShape) 288 if (shapeu != null && shapeu.HasPhysicalShape)
289 BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); 289 BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
290} 290}
291 291
292public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) 292public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
@@ -1420,7 +1420,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
1420public static extern bool IsNativeShape2(IntPtr shape); 1420public static extern bool IsNativeShape2(IntPtr shape);
1421 1421
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1423public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); 1423public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1424 1424
1425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1426public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 1426public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 38596fa..5549984 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -1201,8 +1201,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1201 1201
1202 VehicleAddForce(appliedGravity); 1202 VehicleAddForce(appliedGravity);
1203 1203
1204 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},appliedForce={3}", 1204 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
1205 Prim.LocalID, m_VehicleGravity, Prim.IsColliding, appliedGravity); 1205 Prim.LocalID, m_VehicleGravity,
1206 Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1206 } 1207 }
1207 1208
1208 // ======================================================================= 1209 // =======================================================================
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 77bdacb..4d89a88 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -39,6 +39,20 @@ public static class BSParam
39{ 39{
40 private static string LogHeader = "[BULLETSIM PARAMETERS]"; 40 private static string LogHeader = "[BULLETSIM PARAMETERS]";
41 41
42 // Tuning notes:
43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
44 // Contact points can be added even if the distance is positive. The constraint solver can deal with
45 // contacts with positive distances as well as negative (penetration). Contact points are discarded
46 // if the distance exceeds a certain threshold.
47 // Bullet has a contact processing threshold and a contact breaking threshold.
48 // If the distance is larger than the contact breaking threshold, it will be removed after one frame.
49 // If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
50
51 // This is separate/independent from the collision margin. The collision margin increases the object a bit
52 // to improve collision detection performance and accuracy.
53 // ===================
54 // From:
55
42 // Level of Detail values kept as float because that's what the Meshmerizer wants 56 // Level of Detail values kept as float because that's what the Meshmerizer wants
43 public static float MeshLOD { get; private set; } 57 public static float MeshLOD { get; private set; }
44 public static float MeshCircularLOD { get; private set; } 58 public static float MeshCircularLOD { get; private set; }
@@ -74,9 +88,11 @@ public static class BSParam
74 public static bool ShouldRemoveZeroWidthTriangles { get; private set; } 88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
75 89
76 public static float TerrainImplementation { get; private set; } 90 public static float TerrainImplementation { get; private set; }
91 public static int TerrainMeshMagnification { get; private set; }
77 public static float TerrainFriction { get; private set; } 92 public static float TerrainFriction { get; private set; }
78 public static float TerrainHitFraction { get; private set; } 93 public static float TerrainHitFraction { get; private set; }
79 public static float TerrainRestitution { get; private set; } 94 public static float TerrainRestitution { get; private set; }
95 public static float TerrainContactProcessingThreshold { get; private set; }
80 public static float TerrainCollisionMargin { get; private set; } 96 public static float TerrainCollisionMargin { get; private set; }
81 97
82 public static float DefaultFriction { get; private set; } 98 public static float DefaultFriction { get; private set; }
@@ -446,6 +462,10 @@ public static class BSParam
446 (float)BSTerrainPhys.TerrainImplementation.Mesh, 462 (float)BSTerrainPhys.TerrainImplementation.Mesh,
447 (s) => { return TerrainImplementation; }, 463 (s) => { return TerrainImplementation; },
448 (s,v) => { TerrainImplementation = v; } ), 464 (s,v) => { TerrainImplementation = v; } ),
465 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
466 3,
467 (s) => { return TerrainMeshMagnification; },
468 (s,v) => { TerrainMeshMagnification = v; } ),
449 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , 469 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
450 0.3f, 470 0.3f,
451 (s) => { return TerrainFriction; }, 471 (s) => { return TerrainFriction; },
@@ -458,6 +478,10 @@ public static class BSParam
458 0f, 478 0f,
459 (s) => { return TerrainRestitution; }, 479 (s) => { return TerrainRestitution; },
460 (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), 480 (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
481 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
482 0.0f,
483 (s) => { return TerrainContactProcessingThreshold; },
484 (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ),
461 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , 485 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
462 0.08f, 486 0.08f,
463 (s) => { return TerrainCollisionMargin; }, 487 (s) => { return TerrainCollisionMargin; },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index a465613..2cbbe9a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -947,9 +947,9 @@ public class BSPrim : BSPhysObject
947 ZeroMotion(true); 947 ZeroMotion(true);
948 948
949 // Set various physical properties so other object interact properly 949 // Set various physical properties so other object interact properly
950 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
951 PhysicsScene.PE.SetFriction(PhysBody, Friction); 950 PhysicsScene.PE.SetFriction(PhysBody, Friction);
952 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 951 PhysicsScene.PE.SetRestitution(PhysBody, Restitution);
952 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
953 953
954 // Mass is zero which disables a bunch of physics stuff in Bullet 954 // Mass is zero which disables a bunch of physics stuff in Bullet
955 UpdatePhysicalMassProperties(0f, false); 955 UpdatePhysicalMassProperties(0f, false);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 2e54a93..05c147d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -687,7 +687,7 @@ public sealed class BSShapeCollection : IDisposable
687 } 687 }
688 else 688 else
689 { 689 {
690 PhysicsScene.Logger.ErrorFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", 690 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
691 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name); 691 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
692 } 692 }
693 } 693 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index e8040d8..a60946d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -263,6 +263,7 @@ public sealed class BSTerrainManager : IDisposable
263 263
264 if (MegaRegionParentPhysicsScene == null) 264 if (MegaRegionParentPhysicsScene == null)
265 { 265 {
266 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
266 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 267 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
267 m_terrains.Add(terrainRegionBase, newTerrainPhys); 268 m_terrains.Add(terrainRegionBase, newTerrainPhys);
268 269
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index 57a5ff2..a9cd8a1 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -76,11 +76,26 @@ public sealed class BSTerrainMesh : BSTerrainPhys
76 m_sizeX = (int)(maxCoords.X - minCoords.X); 76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y); 77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78 78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, 79 bool meshCreationSuccess = false;
80 m_sizeX, m_sizeY, 80 if (BSParam.TerrainMeshMagnification == 1)
81 (float)m_sizeX, (float)m_sizeY, 81 {
82 Vector3.Zero, 1.0f, 82 // If a magnification of one, use the old routine that is tried and true.
83 out indicesCount, out indices, out verticesCount, out vertices)) 83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices);
87 }
88 else
89 {
90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize,
95 Vector3.Zero, // base for mesh
96 out indicesCount, out indices, out verticesCount, out vertices);
97 }
98 if (!meshCreationSuccess)
84 { 99 {
85 // DISASTER!! 100 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); 101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
@@ -88,6 +103,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 103 // Something is very messed up and a crash is in our future.
89 return; 104 return;
90 } 105 }
106
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", 107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length); 108 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
93 109
@@ -112,11 +128,13 @@ public sealed class BSTerrainMesh : BSTerrainPhys
112 // Something is very messed up and a crash is in our future. 128 // Something is very messed up and a crash is in our future.
113 return; 129 return;
114 } 130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
115 132
116 // Set current terrain attributes 133 // Set current terrain attributes
117 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); 134 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); 135 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); 136 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
137 PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
120 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); 138 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121 139
122 // Static objects are not very massive. 140 // Static objects are not very massive.
@@ -184,9 +202,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
184 // Return 'true' if successfully created. 202 // Return 'true' if successfully created.
185 public static bool ConvertHeightmapToMesh( BSScene physicsScene, 203 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
186 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap 204 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
187 float extentX, float extentY, // zero based range for output vertices
188 Vector3 extentBase, // base to be added to all vertices 205 Vector3 extentBase, // base to be added to all vertices
189 float magnification, // number of vertices to create between heightMap coords
190 out int indicesCountO, out int[] indicesO, 206 out int indicesCountO, out int[] indicesO,
191 out int verticesCountO, out float[] verticesO) 207 out int verticesCountO, out float[] verticesO)
192 { 208 {
@@ -207,17 +223,15 @@ public sealed class BSTerrainMesh : BSTerrainPhys
207 // of the heightmap. 223 // of the heightmap.
208 try 224 try
209 { 225 {
210 // One vertice per heightmap value plus the vertices off the top and bottom edge. 226 // One vertice per heightmap value plus the vertices off the side and bottom edge.
211 int totalVertices = (sizeX + 1) * (sizeY + 1); 227 int totalVertices = (sizeX + 1) * (sizeY + 1);
212 vertices = new float[totalVertices * 3]; 228 vertices = new float[totalVertices * 3];
213 int totalIndices = sizeX * sizeY * 6; 229 int totalIndices = sizeX * sizeY * 6;
214 indices = new int[totalIndices]; 230 indices = new int[totalIndices];
215 231
216 float magX = (float)sizeX / extentX;
217 float magY = (float)sizeY / extentY;
218 if (physicsScene != null) 232 if (physicsScene != null)
219 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 233 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
220 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 234 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
221 float minHeight = float.MaxValue; 235 float minHeight = float.MaxValue;
222 // Note that sizeX+1 vertices are created since there is land between this and the next region. 236 // Note that sizeX+1 vertices are created since there is land between this and the next region.
223 for (int yy = 0; yy <= sizeY; yy++) 237 for (int yy = 0; yy <= sizeY; yy++)
@@ -230,8 +244,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
230 if (xx == sizeX) offset -= 1; 244 if (xx == sizeX) offset -= 1;
231 float height = heightMap[offset]; 245 float height = heightMap[offset];
232 minHeight = Math.Min(minHeight, height); 246 minHeight = Math.Min(minHeight, height);
233 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 247 vertices[verticesCount + 0] = (float)xx + extentBase.X;
234 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 248 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
235 vertices[verticesCount + 2] = height + extentBase.Z; 249 vertices[verticesCount + 2] = height + extentBase.Z;
236 verticesCount += 3; 250 verticesCount += 3;
237 } 251 }
@@ -270,5 +284,158 @@ public sealed class BSTerrainMesh : BSTerrainPhys
270 284
271 return ret; 285 return ret;
272 } 286 }
287
288 private class HeightMapGetter
289 {
290 private float[] m_heightMap;
291 private int m_sizeX;
292 private int m_sizeY;
293 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
294 {
295 m_heightMap = pHeightMap;
296 m_sizeX = pSizeX;
297 m_sizeY = pSizeY;
298 }
299 // The heightmap is extended as an infinite plane at the last height
300 public float GetHeight(int xx, int yy)
301 {
302 int offset = 0;
303 // Extend the height with the height from the last row or column
304 if (yy >= m_sizeY)
305 if (xx >= m_sizeX)
306 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
307 else
308 offset = (m_sizeY - 1) * m_sizeX + xx;
309 else
310 if (xx >= m_sizeX)
311 offset = yy * m_sizeX + (m_sizeX - 1);
312 else
313 offset = yy * m_sizeX + xx;
314
315 return m_heightMap[offset];
316 }
317 }
318
319 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
320 // Version that handles magnification.
321 // Return 'true' if successfully created.
322 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
323 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
324 int magnification, // number of vertices per heighmap step
325 Vector3 extent, // dimensions of the output mesh
326 Vector3 extentBase, // base to be added to all vertices
327 out int indicesCountO, out int[] indicesO,
328 out int verticesCountO, out float[] verticesO)
329 {
330 bool ret = false;
331
332 int indicesCount = 0;
333 int verticesCount = 0;
334 int[] indices = new int[0];
335 float[] vertices = new float[0];
336
337 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
338
339 // The vertices dimension of the output mesh
340 int meshX = sizeX * magnification;
341 int meshY = sizeY * magnification;
342 // The output size of one mesh step
343 float meshXStep = extent.X / meshX;
344 float meshYStep = extent.Y / meshY;
345
346 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
347 // from zero to <= meshX). The triangle indices are then generated as two triangles
348 // per heightmap point. There are meshX by meshY of these squares. The extra row and
349 // column of vertices are used to complete the triangles of the last row and column
350 // of the heightmap.
351 try
352 {
353 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
354 int totalVertices = (meshX + 1) * (meshY + 1);
355 vertices = new float[totalVertices * 3];
356 int totalIndices = meshX * meshY * 6;
357 indices = new int[totalIndices];
358
359 if (physicsScene != null)
360 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
361 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
362 totalVertices, totalIndices, extentBase);
363
364 float minHeight = float.MaxValue;
365 // Note that sizeX+1 vertices are created since there is land between this and the next region.
366 // Loop through the output vertices and compute the mediun height in between the input vertices
367 for (int yy = 0; yy <= meshY; yy++)
368 {
369 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
370 {
371 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
372 int stepY = (int)offsetY;
373 float fractionalY = offsetY - (float)stepY;
374 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
375 int stepX = (int)offsetX;
376 float fractionalX = offsetX - (float)stepX;
377
378 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
379 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
380
381 // get the four corners of the heightmap square the mesh point is in
382 float heightUL = hmap.GetHeight(stepX , stepY );
383 float heightUR = hmap.GetHeight(stepX + 1, stepY );
384 float heightLL = hmap.GetHeight(stepX , stepY + 1);
385 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
386
387 // bilinear interplolation
388 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
389 + heightUR * fractionalX * (1 - fractionalY)
390 + heightLL * (1 - fractionalX) * fractionalY
391 + heightLR * fractionalX * fractionalY;
392
393 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
394 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
395
396 minHeight = Math.Min(minHeight, height);
397
398 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
399 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
400 vertices[verticesCount + 2] = height + extentBase.Z;
401 verticesCount += 3;
402 }
403 }
404 // The number of vertices generated
405 verticesCount /= 3;
406
407 // Loop through all the heightmap squares and create indices for the two triangles for that square
408 for (int yy = 0; yy < meshY; yy++)
409 {
410 for (int xx = 0; xx < meshX; xx++)
411 {
412 int offset = yy * (meshX + 1) + xx;
413 // Each vertices is presumed to be the upper left corner of a box of two triangles
414 indices[indicesCount + 0] = offset;
415 indices[indicesCount + 1] = offset + 1;
416 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
417 indices[indicesCount + 3] = offset + 1;
418 indices[indicesCount + 4] = offset + meshX + 2;
419 indices[indicesCount + 5] = offset + meshX + 1;
420 indicesCount += 6;
421 }
422 }
423
424 ret = true;
425 }
426 catch (Exception e)
427 {
428 if (physicsScene != null)
429 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
430 LogHeader, physicsScene.RegionName, extentBase, e);
431 }
432
433 indicesCountO = indicesCount;
434 indicesO = indices;
435 verticesCountO = verticesCount;
436 verticesO = vertices;
437
438 return ret;
439 }
273} 440}
274} 441}