diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneGraph.cs | 402 |
1 files changed, 118 insertions, 284 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index bbcb85e..3a1962c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -35,6 +35,7 @@ using log4net; | |||
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Region.Framework.Scenes.Types; | 36 | using OpenSim.Region.Framework.Scenes.Types; |
37 | using OpenSim.Region.Physics.Manager; | 37 | using OpenSim.Region.Physics.Manager; |
38 | using OpenSim.Region.Framework.Interfaces; | ||
38 | 39 | ||
39 | namespace OpenSim.Region.Framework.Scenes | 40 | namespace OpenSim.Region.Framework.Scenes |
40 | { | 41 | { |
@@ -164,9 +165,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
164 | 165 | ||
165 | protected internal void UpdatePresences() | 166 | protected internal void UpdatePresences() |
166 | { | 167 | { |
167 | ScenePresence[] updateScenePresences = GetScenePresences(); | 168 | ForEachScenePresence(delegate(ScenePresence presence) |
168 | for (int i = 0; i < updateScenePresences.Length; i++) | 169 | { |
169 | updateScenePresences[i].Update(); | 170 | presence.Update(); |
171 | }); | ||
170 | } | 172 | } |
171 | 173 | ||
172 | protected internal float UpdatePhysics(double elapsed) | 174 | protected internal float UpdatePhysics(double elapsed) |
@@ -195,9 +197,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
195 | 197 | ||
196 | protected internal void UpdateScenePresenceMovement() | 198 | protected internal void UpdateScenePresenceMovement() |
197 | { | 199 | { |
198 | ScenePresence[] moveEntities = GetScenePresences(); | 200 | ForEachScenePresence(delegate(ScenePresence presence) |
199 | for (int i = 0; i < moveEntities.Length; i++) | 201 | { |
200 | moveEntities[i].UpdateMovement(); | 202 | presence.UpdateMovement(); |
203 | }); | ||
201 | } | 204 | } |
202 | 205 | ||
203 | #endregion | 206 | #endregion |
@@ -475,7 +478,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
475 | if (group != null) | 478 | if (group != null) |
476 | { | 479 | { |
477 | //group.DetachToGround(); | 480 | //group.DetachToGround(); |
478 | m_parentScene.DetachSingleAttachmentToInv(group.GetFromItemID(), remoteClient); | 481 | m_parentScene.AttachmentsModule.ShowDetachInUserInventory(group.GetFromItemID(), remoteClient); |
479 | } | 482 | } |
480 | } | 483 | } |
481 | 484 | ||
@@ -509,212 +512,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
509 | } | 512 | } |
510 | } | 513 | } |
511 | 514 | ||
512 | /// <summary> | ||
513 | /// Event Handling routine for Attach Object | ||
514 | /// </summary> | ||
515 | /// <param name="remoteClient"></param> | ||
516 | /// <param name="objectLocalID"></param> | ||
517 | /// <param name="AttachmentPt"></param> | ||
518 | /// <param name="rot"></param> | ||
519 | protected internal void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent) | ||
520 | { | ||
521 | // If we can't take it, we can't attach it! | ||
522 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(objectLocalID); | ||
523 | if (part == null) | ||
524 | return; | ||
525 | |||
526 | if (!m_parentScene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) | ||
527 | return; | ||
528 | |||
529 | // Calls attach with a Zero position | ||
530 | if (AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false)) | ||
531 | { | ||
532 | m_parentScene.SendAttachEvent(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | ||
533 | |||
534 | // Save avatar attachment information | ||
535 | ScenePresence presence; | ||
536 | if (m_parentScene.AvatarFactory != null && m_parentScene.TryGetAvatar(remoteClient.AgentId, out presence)) | ||
537 | { | ||
538 | m_log.Info( | ||
539 | "[SCENE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId | ||
540 | + ", AttachmentPoint: " + AttachmentPt); | ||
541 | |||
542 | m_parentScene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | |||
547 | /// <summary> | ||
548 | /// Rez an attachment | ||
549 | /// </summary> | ||
550 | /// <param name="remoteClient"></param> | ||
551 | /// <param name="itemID"></param> | ||
552 | /// <param name="AttachmentPt"></param> | ||
553 | /// <returns>The scene object that was attached. Null if the scene object could not be found</returns> | ||
554 | public SceneObjectGroup RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
555 | { | ||
556 | SceneObjectGroup objatt = m_parentScene.RezObject(remoteClient, | ||
557 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
558 | false, false, remoteClient.AgentId, true); | ||
559 | |||
560 | // m_log.DebugFormat( | ||
561 | // "[SCENE GRAPH]: Retrieved single object {0} for attachment to {1} on point {2}", | ||
562 | // objatt.Name, remoteClient.Name, AttachmentPt); | ||
563 | |||
564 | if (objatt != null) | ||
565 | { | ||
566 | bool tainted = false; | ||
567 | if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) | ||
568 | tainted = true; | ||
569 | |||
570 | AttachObject(remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false); | ||
571 | //objatt.ScheduleGroupForFullUpdate(); | ||
572 | |||
573 | if (tainted) | ||
574 | objatt.HasGroupChanged = true; | ||
575 | |||
576 | // Fire after attach, so we don't get messy perms dialogs | ||
577 | // 3 == AttachedRez | ||
578 | objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 3); | ||
579 | |||
580 | // Do this last so that event listeners have access to all the effects of the attachment | ||
581 | m_parentScene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); | ||
582 | } | ||
583 | else | ||
584 | { | ||
585 | m_log.WarnFormat( | ||
586 | "[SCENE GRAPH]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
587 | itemID, remoteClient.Name, AttachmentPt); | ||
588 | } | ||
589 | |||
590 | return objatt; | ||
591 | } | ||
592 | |||
593 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. | ||
594 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? | ||
595 | public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) | ||
596 | { | ||
597 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... | ||
598 | return; | ||
599 | |||
600 | // We can NOT use the dictionries here, as we are looking | ||
601 | // for an entity by the fromAssetID, which is NOT the prim UUID | ||
602 | // | ||
603 | List<EntityBase> detachEntities = GetEntities(); | ||
604 | SceneObjectGroup group; | ||
605 | |||
606 | foreach (EntityBase entity in detachEntities) | ||
607 | { | ||
608 | if (entity is SceneObjectGroup) | ||
609 | { | ||
610 | group = (SceneObjectGroup)entity; | ||
611 | if (group.GetFromItemID() == itemID) | ||
612 | { | ||
613 | m_parentScene.SendAttachEvent(group.LocalId, itemID, UUID.Zero); | ||
614 | bool hasScripts = false; | ||
615 | foreach (SceneObjectPart part in group.Children.Values) | ||
616 | { | ||
617 | if (part.Inventory.ContainsScripts()) | ||
618 | { | ||
619 | hasScripts = true; | ||
620 | break; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | if (hasScripts) // Allow the object to execute the attach(NULL_KEY) event | ||
625 | System.Threading.Thread.Sleep(100); | ||
626 | group.DetachToInventoryPrep(); | ||
627 | m_log.Debug("[DETACH]: Saving attachpoint: " + | ||
628 | ((uint)group.GetAttachmentPoint()).ToString()); | ||
629 | m_parentScene.UpdateKnownItem(remoteClient, group, | ||
630 | group.GetFromItemID(), group.OwnerID); | ||
631 | m_parentScene.DeleteSceneObject(group, false); | ||
632 | return; | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | } | ||
637 | |||
638 | /// <summary> | ||
639 | /// Attach a scene object to an avatar. | ||
640 | /// </summary> | ||
641 | /// <param name="remoteClient"></param> | ||
642 | /// <param name="objectLocalID"></param> | ||
643 | /// <param name="AttachmentPt"></param> | ||
644 | /// <param name="rot"></param> | ||
645 | /// <param name="attachPos"></param> | ||
646 | /// <param name="silent"></param> | ||
647 | /// <returns>true if the attachment was successful, false otherwise</returns> | ||
648 | protected internal bool AttachObject( | ||
649 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent) | ||
650 | { | ||
651 | SceneObjectGroup group = GetGroupByPrim(objectLocalID); | ||
652 | if (group != null) | ||
653 | { | ||
654 | if (m_parentScene.Permissions.CanTakeObject(group.UUID, remoteClient.AgentId)) | ||
655 | { | ||
656 | // If the attachment point isn't the same as the one previously used | ||
657 | // set it's offset position = 0 so that it appears on the attachment point | ||
658 | // and not in a weird location somewhere unknown. | ||
659 | if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint()) | ||
660 | { | ||
661 | attachPos = Vector3.Zero; | ||
662 | } | ||
663 | |||
664 | // AttachmentPt 0 means the client chose to 'wear' the attachment. | ||
665 | if (AttachmentPt == 0) | ||
666 | { | ||
667 | // Check object for stored attachment point | ||
668 | AttachmentPt = (uint)group.GetAttachmentPoint(); | ||
669 | } | ||
670 | |||
671 | // if we still didn't find a suitable attachment point....... | ||
672 | if (AttachmentPt == 0) | ||
673 | { | ||
674 | // Stick it on left hand with Zero Offset from the attachment point. | ||
675 | AttachmentPt = (uint)AttachmentPoint.LeftHand; | ||
676 | attachPos = Vector3.Zero; | ||
677 | } | ||
678 | |||
679 | group.SetAttachmentPoint((byte)AttachmentPt); | ||
680 | group.AbsolutePosition = attachPos; | ||
681 | |||
682 | // Saves and gets itemID | ||
683 | UUID itemId; | ||
684 | |||
685 | if (group.GetFromItemID() == UUID.Zero) | ||
686 | { | ||
687 | m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId); | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | itemId = group.GetFromItemID(); | ||
692 | } | ||
693 | |||
694 | m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group); | ||
695 | |||
696 | group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent); | ||
697 | // In case it is later dropped again, don't let | ||
698 | // it get cleaned up | ||
699 | // | ||
700 | group.RootPart.RemFlag(PrimFlags.TemporaryOnRez); | ||
701 | group.HasGroupChanged = false; | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false); | ||
706 | return false; | ||
707 | } | ||
708 | } | ||
709 | else | ||
710 | { | ||
711 | m_log.DebugFormat("[SCENE GRAPH]: AttachObject found no such scene object {0}", objectLocalID); | ||
712 | return false; | ||
713 | } | ||
714 | |||
715 | return true; | ||
716 | } | ||
717 | |||
718 | protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) | 515 | protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) |
719 | { | 516 | { |
720 | ScenePresence newAvatar = null; | 517 | ScenePresence newAvatar = null; |
@@ -845,18 +642,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
845 | 642 | ||
846 | public void RecalculateStats() | 643 | public void RecalculateStats() |
847 | { | 644 | { |
848 | ScenePresence[] presences = GetScenePresences(); | ||
849 | int rootcount = 0; | 645 | int rootcount = 0; |
850 | int childcount = 0; | 646 | int childcount = 0; |
851 | 647 | ||
852 | for (int i = 0; i < presences.Length; i++) | 648 | ForEachScenePresence(delegate(ScenePresence presence) |
853 | { | 649 | { |
854 | ScenePresence user = presences[i]; | 650 | if (presence.IsChildAgent) |
855 | if (user.IsChildAgent) | ||
856 | ++childcount; | 651 | ++childcount; |
857 | else | 652 | else |
858 | ++rootcount; | 653 | ++rootcount; |
859 | } | 654 | }); |
860 | 655 | ||
861 | m_numRootAgents = rootcount; | 656 | m_numRootAgents = rootcount; |
862 | m_numChildAgents = childcount; | 657 | m_numChildAgents = childcount; |
@@ -903,25 +698,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
903 | #endregion | 698 | #endregion |
904 | 699 | ||
905 | #region Get Methods | 700 | #region Get Methods |
906 | |||
907 | /// <summary> | ||
908 | /// Request a List of all scene presences in this scene. This is a new list, so no | ||
909 | /// locking is required to iterate over it. | ||
910 | /// </summary> | ||
911 | /// <returns></returns> | ||
912 | protected internal ScenePresence[] GetScenePresences() | ||
913 | { | ||
914 | return m_scenePresenceArray; | ||
915 | } | ||
916 | |||
917 | protected internal List<ScenePresence> GetAvatars() | ||
918 | { | ||
919 | List<ScenePresence> result = | ||
920 | GetScenePresences(delegate(ScenePresence scenePresence) { return !scenePresence.IsChildAgent; }); | ||
921 | |||
922 | return result; | ||
923 | } | ||
924 | |||
925 | /// <summary> | 701 | /// <summary> |
926 | /// Get the controlling client for the given avatar, if there is one. | 702 | /// Get the controlling client for the given avatar, if there is one. |
927 | /// | 703 | /// |
@@ -948,41 +724,83 @@ namespace OpenSim.Region.Framework.Scenes | |||
948 | } | 724 | } |
949 | 725 | ||
950 | /// <summary> | 726 | /// <summary> |
951 | /// Request a filtered list of m_scenePresences in this World | 727 | /// Request a copy of m_scenePresences in this World |
728 | /// There is no guarantee that presences will remain in the scene after the list is returned. | ||
729 | /// This list should remain private to SceneGraph. Callers wishing to iterate should instead | ||
730 | /// pass a delegate to ForEachScenePresence. | ||
952 | /// </summary> | 731 | /// </summary> |
953 | /// <returns></returns> | 732 | /// <returns></returns> |
954 | protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter) | 733 | private List<ScenePresence> GetScenePresences() |
955 | { | 734 | { |
956 | // No locking of scene presences here since we're passing back a list... | 735 | lock (m_scenePresences) |
957 | 736 | return new List<ScenePresence>(m_scenePresenceArray); | |
958 | List<ScenePresence> result = new List<ScenePresence>(); | 737 | } |
959 | ScenePresence[] scenePresences = GetScenePresences(); | ||
960 | 738 | ||
961 | for (int i = 0; i < scenePresences.Length; i++) | 739 | /// <summary> |
740 | /// Request a scene presence by UUID. Fast, indexed lookup. | ||
741 | /// </summary> | ||
742 | /// <param name="agentID"></param> | ||
743 | /// <returns>null if the presence was not found</returns> | ||
744 | protected internal ScenePresence GetScenePresence(UUID agentID) | ||
745 | { | ||
746 | ScenePresence sp; | ||
747 | lock (m_scenePresences) | ||
962 | { | 748 | { |
963 | ScenePresence avatar = scenePresences[i]; | 749 | m_scenePresences.TryGetValue(agentID, out sp); |
964 | if (filter(avatar)) | ||
965 | result.Add(avatar); | ||
966 | } | 750 | } |
751 | return sp; | ||
752 | } | ||
967 | 753 | ||
968 | return result; | 754 | /// <summary> |
755 | /// Request the scene presence by name. | ||
756 | /// </summary> | ||
757 | /// <param name="firstName"></param> | ||
758 | /// <param name="lastName"></param> | ||
759 | /// <returns>null if the presence was not found</returns> | ||
760 | protected internal ScenePresence GetScenePresence(string firstName, string lastName) | ||
761 | { | ||
762 | foreach (ScenePresence presence in GetScenePresences()) | ||
763 | { | ||
764 | if (presence.Firstname == firstName && presence.Lastname == lastName) | ||
765 | return presence; | ||
766 | } | ||
767 | return null; | ||
969 | } | 768 | } |
970 | 769 | ||
971 | /// <summary> | 770 | /// <summary> |
972 | /// Request a scene presence by UUID | 771 | /// Request the scene presence by localID. |
973 | /// </summary> | 772 | /// </summary> |
974 | /// <param name="avatarID"></param> | 773 | /// <param name="localID"></param> |
975 | /// <returns>null if the agent was not found</returns> | 774 | /// <returns>null if the presence was not found</returns> |
976 | protected internal ScenePresence GetScenePresence(UUID agentID) | 775 | protected internal ScenePresence GetScenePresence(uint localID) |
776 | { | ||
777 | foreach (ScenePresence presence in GetScenePresences()) | ||
778 | if (presence.LocalId == localID) | ||
779 | return presence; | ||
780 | return null; | ||
781 | } | ||
782 | |||
783 | protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar) | ||
977 | { | 784 | { |
978 | ScenePresence sp; | ||
979 | |||
980 | lock (m_scenePresences) | 785 | lock (m_scenePresences) |
981 | { | 786 | { |
982 | m_scenePresences.TryGetValue(agentID, out sp); | 787 | m_scenePresences.TryGetValue(agentID, out avatar); |
983 | } | 788 | } |
789 | return (avatar != null); | ||
790 | } | ||
984 | 791 | ||
985 | return sp; | 792 | protected internal bool TryGetAvatarByName(string name, out ScenePresence avatar) |
793 | { | ||
794 | avatar = null; | ||
795 | foreach (ScenePresence presence in GetScenePresences()) | ||
796 | { | ||
797 | if (String.Compare(name, presence.ControllingClient.Name, true) == 0) | ||
798 | { | ||
799 | avatar = presence; | ||
800 | break; | ||
801 | } | ||
802 | } | ||
803 | return (avatar != null); | ||
986 | } | 804 | } |
987 | 805 | ||
988 | /// <summary> | 806 | /// <summary> |
@@ -1136,34 +954,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1136 | return group.GetChildPart(fullID); | 954 | return group.GetChildPart(fullID); |
1137 | } | 955 | } |
1138 | 956 | ||
1139 | protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) | ||
1140 | { | ||
1141 | lock (m_scenePresences) | ||
1142 | return m_scenePresences.TryGetValue(avatarId, out avatar); | ||
1143 | } | ||
1144 | |||
1145 | protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) | ||
1146 | { | ||
1147 | ScenePresence[] presences = GetScenePresences(); | ||
1148 | |||
1149 | for (int i = 0; i < presences.Length; i++) | ||
1150 | { | ||
1151 | ScenePresence presence = presences[i]; | ||
1152 | |||
1153 | if (!presence.IsChildAgent) | ||
1154 | { | ||
1155 | if (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0) | ||
1156 | { | ||
1157 | avatar = presence; | ||
1158 | return true; | ||
1159 | } | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | avatar = null; | ||
1164 | return false; | ||
1165 | } | ||
1166 | |||
1167 | /// <summary> | 957 | /// <summary> |
1168 | /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over | 958 | /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over |
1169 | /// it | 959 | /// it |
@@ -1226,6 +1016,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1226 | return UUID.Zero; | 1016 | return UUID.Zero; |
1227 | } | 1017 | } |
1228 | 1018 | ||
1019 | /// <summary> | ||
1020 | /// Performs action on all scene object groups. | ||
1021 | /// </summary> | ||
1022 | /// <param name="action"></param> | ||
1229 | protected internal void ForEachSOG(Action<SceneObjectGroup> action) | 1023 | protected internal void ForEachSOG(Action<SceneObjectGroup> action) |
1230 | { | 1024 | { |
1231 | List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); | 1025 | List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values); |
@@ -1242,6 +1036,46 @@ namespace OpenSim.Region.Framework.Scenes | |||
1242 | } | 1036 | } |
1243 | } | 1037 | } |
1244 | } | 1038 | } |
1039 | |||
1040 | |||
1041 | /// <summary> | ||
1042 | /// Performs action on all scene presences. This can ultimately run the actions in parallel but | ||
1043 | /// any delegates passed in will need to implement their own locking on data they reference and | ||
1044 | /// modify outside of the scope of the delegate. | ||
1045 | /// </summary> | ||
1046 | /// <param name="action"></param> | ||
1047 | public void ForEachScenePresence(Action<ScenePresence> action) | ||
1048 | { | ||
1049 | // Once all callers have their delegates configured for parallelism, we can unleash this | ||
1050 | /* | ||
1051 | Action<ScenePresence> protectedAction = new Action<ScenePresence>(delegate(ScenePresence sp) | ||
1052 | { | ||
1053 | try | ||
1054 | { | ||
1055 | action(sp); | ||
1056 | } | ||
1057 | catch (Exception e) | ||
1058 | { | ||
1059 | m_log.Info("[BUG] in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString()); | ||
1060 | m_log.Info("[BUG] Stack Trace: " + e.StackTrace); | ||
1061 | } | ||
1062 | }); | ||
1063 | Parallel.ForEach<ScenePresence>(GetScenePresences(), protectedAction); | ||
1064 | */ | ||
1065 | // For now, perform actiona serially | ||
1066 | foreach (ScenePresence sp in GetScenePresences()) | ||
1067 | { | ||
1068 | try | ||
1069 | { | ||
1070 | action(sp); | ||
1071 | } | ||
1072 | catch (Exception e) | ||
1073 | { | ||
1074 | m_log.Info("[BUG] in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString()); | ||
1075 | m_log.Info("[BUG] Stack Trace: " + e.StackTrace); | ||
1076 | } | ||
1077 | } | ||
1078 | } | ||
1245 | 1079 | ||
1246 | #endregion | 1080 | #endregion |
1247 | 1081 | ||