diff options
author | Melanie | 2013-03-23 11:31:34 +0100 |
---|---|---|
committer | Melanie | 2013-03-23 11:31:34 +0100 |
commit | 8bc43ea773f6a56d34222f03c6ad7645b59347bf (patch) | |
tree | 4426b54b77a53014c7e90019124f26e338e40d26 /OpenSim/Region | |
parent | Fix SceneManager to use the new automatic property throughout. (diff) | |
parent | Merge branch 'avination' into careminster (diff) | |
download | opensim-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')
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 | ||
28 | using System; | 28 | using System; |
29 | using System.Reflection; | 29 | using System.Collections.Generic; |
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Text; | ||
30 | using Nini.Config; | 33 | using Nini.Config; |
31 | using NUnit.Framework; | 34 | using NUnit.Framework; |
32 | using OpenMetaverse; | 35 | using OpenMetaverse; |
@@ -40,8 +43,6 @@ using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | |||
40 | using OpenSim.Region.CoreModules.World.Permissions; | 43 | using OpenSim.Region.CoreModules.World.Permissions; |
41 | using OpenSim.Tests.Common; | 44 | using OpenSim.Tests.Common; |
42 | using OpenSim.Tests.Common.Mock; | 45 | using OpenSim.Tests.Common.Mock; |
43 | using System.IO; | ||
44 | using System.Text; | ||
45 | 46 | ||
46 | namespace OpenSim.Region.Framework.Scenes.Tests | 47 | namespace 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 | ||
292 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) | 292 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) |
@@ -1420,7 +1420,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) | |||
1420 | public static extern bool IsNativeShape2(IntPtr shape); | 1420 | public static extern bool IsNativeShape2(IntPtr shape); |
1421 | 1421 | ||
1422 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1422 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1423 | public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); | 1423 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); |
1424 | 1424 | ||
1425 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1425 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1426 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | 1426 | public 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 | } |