aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorDan Lake2010-03-17 06:40:00 -0700
committerJohn Hurliman2010-03-17 11:21:27 -0700
commit73e9b0be725a73a489b29f3fe2df236c897ef3b5 (patch)
tree0d039d61d327e98ed22e4bce30de65c24fc5780d /OpenSim
parentminor logging changes to BaseHttpServer, OSHttpRequest (diff)
downloadopensim-SC_OLD-73e9b0be725a73a489b29f3fe2df236c897ef3b5.zip
opensim-SC_OLD-73e9b0be725a73a489b29f3fe2df236c897ef3b5.tar.gz
opensim-SC_OLD-73e9b0be725a73a489b29f3fe2df236c897ef3b5.tar.bz2
opensim-SC_OLD-73e9b0be725a73a489b29f3fe2df236c897ef3b5.tar.xz
Inconsistent locking of ScenePresence array in SceneGraph. Fixed by eliminating option to return the actual list. Callers can now either request a copy of the array as a new List or ask the SceneGraph to call a delegate function on every ScenePresence. Iteration and locking of the ScenePresences now takes place only within the SceneGraph class.
This patch also applies a fix to Combat/CombatModule.cs which had unlocked iteration of the ScenePresences and inconsistent try/catch around the use of those ScenePresences.
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs77
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs30
-rw-r--r--OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs52
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs193
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs17
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs12
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs82
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs20
-rw-r--r--OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs2
10 files changed, 258 insertions, 233 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
index 3614915..9df6074 100644
--- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs
@@ -89,60 +89,57 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule
89 get { return true; } 89 get { return true; }
90 } 90 }
91 91
92 private void KillAvatar(uint killerObjectLocalID, ScenePresence DeadAvatar) 92 private void KillAvatar(uint killerObjectLocalID, ScenePresence deadAvatar)
93 { 93 {
94 string deadAvatarMessage;
95 ScenePresence killingAvatar = null;
96 string killingAvatarMessage;
97
94 if (killerObjectLocalID == 0) 98 if (killerObjectLocalID == 0)
95 DeadAvatar.ControllingClient.SendAgentAlertMessage("You committed suicide!", true); 99 deadAvatarMessage = "You committed suicide!";
96 else 100 else
97 { 101 {
98 bool foundResult = false; 102 // Try to get the avatar responsible for the killing
99 string resultstring = String.Empty; 103 killingAvatar = deadAvatar.Scene.GetScenePresence(killerObjectLocalID);
100 ScenePresence[] allav = DeadAvatar.Scene.GetScenePresences(); 104 if (killingAvatar == null)
101 try
102 { 105 {
103 for (int i = 0; i < allav.Length; i++) 106 // Try to get the object which was responsible for the killing
107 SceneObjectPart part = deadAvatar.Scene.GetSceneObjectPart(killerObjectLocalID);
108 if (part == null)
104 { 109 {
105 ScenePresence av = allav[i]; 110 // Cause of death: Unknown
106 111 deadAvatarMessage = "You died!";
107 if (av.LocalId == killerObjectLocalID)
108 {
109 av.ControllingClient.SendAlertMessage("You fragged " + DeadAvatar.Firstname + " " + DeadAvatar.Lastname);
110 resultstring = av.Firstname + " " + av.Lastname;
111 foundResult = true;
112 }
113 } 112 }
114 } catch (InvalidOperationException) 113 else
115 {
116
117 }
118
119 if (!foundResult)
120 {
121 SceneObjectPart part = DeadAvatar.Scene.GetSceneObjectPart(killerObjectLocalID);
122 if (part != null)
123 { 114 {
124 ScenePresence av = DeadAvatar.Scene.GetScenePresence(part.OwnerID); 115 // Try to find the avatar wielding the killing object
125 if (av != null) 116 killingAvatar = deadAvatar.Scene.GetScenePresence(part.OwnerID);
126 { 117 if (killingAvatar == null)
127 av.ControllingClient.SendAlertMessage("You fragged " + DeadAvatar.Firstname + " " + DeadAvatar.Lastname); 118 deadAvatarMessage = String.Format("You impaled yourself on {0} owned by {1}!", part.Name, deadAvatar.Scene.GetUserName(part.OwnerID));
128 resultstring = av.Firstname + " " + av.Lastname;
129 DeadAvatar.ControllingClient.SendAgentAlertMessage("You got killed by " + resultstring + "!", true);
130 }
131 else 119 else
132 { 120 {
133 string killer = DeadAvatar.Scene.GetUserName(part.OwnerID); 121 killingAvatarMessage = String.Format("You fragged {0}!", deadAvatar.Name);
134 DeadAvatar.ControllingClient.SendAgentAlertMessage("You impaled yourself on " + part.Name + " owned by " + killer +"!", true); 122 deadAvatarMessage = String.Format("You got killed by {0}!", killingAvatar.Name);
135 } 123 }
136 //DeadAvatar.Scene. part.ObjectOwner
137 }
138 else
139 {
140 DeadAvatar.ControllingClient.SendAgentAlertMessage("You died!", true);
141 } 124 }
142 } 125 }
126 else
127 {
128 killingAvatarMessage = String.Format("You fragged {0}!", deadAvatar.Name);
129 deadAvatarMessage = String.Format("You got killed by {0}!", killingAvatar.Name);
130 }
143 } 131 }
144 DeadAvatar.Health = 100; 132 try
145 DeadAvatar.Scene.TeleportClientHome(DeadAvatar.UUID, DeadAvatar.ControllingClient); 133 {
134 deadAvatar.ControllingClient.SendAgentAlertMessage(deadAvatarMessage, true);
135 if(killingAvatar != null)
136 killingAvatar.ControllingClient.SendAlertMessage("You fragged " + deadAvatar.Firstname + " " + deadAvatar.Lastname);
137 }
138 catch (InvalidOperationException)
139 { }
140
141 deadAvatar.Health = 100;
142 deadAvatar.Scene.TeleportClientHome(deadAvatar.UUID, deadAvatar.ControllingClient);
146 } 143 }
147 144
148 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) 145 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
diff --git a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
index b8e013c..c31266c 100644
--- a/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Dialog/DialogModule.cs
@@ -87,31 +87,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
87 87
88 public void SendAlertToUser(string firstName, string lastName, string message, bool modal) 88 public void SendAlertToUser(string firstName, string lastName, string message, bool modal)
89 { 89 {
90 ScenePresence[] presenceList = m_scene.GetScenePresences(); 90 ScenePresence presence = m_scene.GetScenePresence(firstName, lastName);
91 91 if(presence != null)
92 for (int i = 0; i < presenceList.Length; i++) 92 presence.ControllingClient.SendAgentAlertMessage(message, modal);
93 {
94 ScenePresence presence = presenceList[i];
95
96 if (presence.Firstname == firstName && presence.Lastname == lastName)
97 {
98 presence.ControllingClient.SendAgentAlertMessage(message, modal);
99 break;
100 }
101 }
102 } 93 }
103 94
104 public void SendGeneralAlert(string message) 95 public void SendGeneralAlert(string message)
105 { 96 {
106 ScenePresence[] presenceList = m_scene.GetScenePresences(); 97 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
107
108 for (int i = 0; i < presenceList.Length; i++)
109 { 98 {
110 ScenePresence presence = presenceList[i];
111
112 if (!presence.IsChildAgent) 99 if (!presence.IsChildAgent)
113 presence.ControllingClient.SendAlertMessage(message); 100 presence.ControllingClient.SendAlertMessage(message);
114 } 101 });
115 } 102 }
116 103
117 public void SendDialogToUser( 104 public void SendDialogToUser(
@@ -179,14 +166,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
179 public void SendNotificationToUsersInRegion( 166 public void SendNotificationToUsersInRegion(
180 UUID fromAvatarID, string fromAvatarName, string message) 167 UUID fromAvatarID, string fromAvatarName, string message)
181 { 168 {
182 ScenePresence[] presences = m_scene.GetScenePresences(); 169 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
183
184 for (int i = 0; i < presences.Length; i++)
185 { 170 {
186 ScenePresence presence = presences[i];
187 if (!presence.IsChildAgent) 171 if (!presence.IsChildAgent)
188 presence.ControllingClient.SendBlueBoxMessage(fromAvatarID, fromAvatarName, message); 172 presence.ControllingClient.SendBlueBoxMessage(fromAvatarID, fromAvatarName, message);
189 } 173 });
190 } 174 }
191 175
192 /// <summary> 176 /// <summary>
diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
index e3bab2d..464d922 100644
--- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs
@@ -469,12 +469,10 @@ namespace OpenSim.Region.CoreModules.World.Estate
469 private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID) 469 private void handleEstateTeleportAllUsersHomeRequest(IClientAPI remover_client, UUID invoice, UUID senderID)
470 { 470 {
471 // Get a fresh list that will not change as people get teleported away 471 // Get a fresh list that will not change as people get teleported away
472 ScenePresence[] presences = m_scene.GetScenePresences(); 472 List<ScenePresence> presences = m_scene.GetScenePresences();
473 473
474 for (int i = 0; i < presences.Length; i++) 474 foreach(ScenePresence p in presences)
475 { 475 {
476 ScenePresence p = presences[i];
477
478 if (p.UUID != senderID) 476 if (p.UUID != senderID)
479 { 477 {
480 // make sure they are still there, we could be working down a long list 478 // make sure they are still there, we could be working down a long list
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index baa8759..a86a33c 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3599,9 +3599,7 @@ namespace OpenSim.Region.Framework.Scenes
3599 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) 3599 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
3600 { 3600 {
3601 ScenePresence presence; 3601 ScenePresence presence;
3602 m_sceneGraph.TryGetAvatar(agentID, out presence); 3602 if(m_sceneGraph.TryGetAvatar(agentID, out presence))
3603
3604 if (presence != null)
3605 { 3603 {
3606 try 3604 try
3607 { 3605 {
@@ -3776,9 +3774,7 @@ namespace OpenSim.Region.Framework.Scenes
3776 Vector3 lookAt, uint teleportFlags) 3774 Vector3 lookAt, uint teleportFlags)
3777 { 3775 {
3778 ScenePresence sp; 3776 ScenePresence sp;
3779 m_sceneGraph.TryGetAvatar(remoteClient.AgentId, out sp); 3777 if(m_sceneGraph.TryGetAvatar(remoteClient.AgentId, out sp))
3780
3781 if (sp != null)
3782 { 3778 {
3783 uint regionX = m_regInfo.RegionLocX; 3779 uint regionX = m_regInfo.RegionLocX;
3784 uint regionY = m_regInfo.RegionLocY; 3780 uint regionY = m_regInfo.RegionLocY;
@@ -4134,6 +4130,11 @@ namespace OpenSim.Region.Framework.Scenes
4134 4130
4135 //The idea is to have a group of method that return a list of avatars meeting some requirement 4131 //The idea is to have a group of method that return a list of avatars meeting some requirement
4136 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar. 4132 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar.
4133 //
4134 // GetAvatars returns a new list of all root agent presences in the scene
4135 // GetScenePresences returns a new list of all presences in the scene or a filter may be passed.
4136 // GetScenePresence returns the presence with matching UUID or first/last name.
4137 // ForEachScenePresence requests the Scene to run a delegate function against all presences.
4137 4138
4138 /// <summary> 4139 /// <summary>
4139 /// Return a list of all avatars in this region. 4140 /// Return a list of all avatars in this region.
@@ -4150,7 +4151,7 @@ namespace OpenSim.Region.Framework.Scenes
4150 /// This list is a new object, so it can be iterated over without locking. 4151 /// This list is a new object, so it can be iterated over without locking.
4151 /// </summary> 4152 /// </summary>
4152 /// <returns></returns> 4153 /// <returns></returns>
4153 public ScenePresence[] GetScenePresences() 4154 public List<ScenePresence> GetScenePresences()
4154 { 4155 {
4155 return m_sceneGraph.GetScenePresences(); 4156 return m_sceneGraph.GetScenePresences();
4156 } 4157 }
@@ -4176,6 +4177,28 @@ namespace OpenSim.Region.Framework.Scenes
4176 return m_sceneGraph.GetScenePresence(avatarID); 4177 return m_sceneGraph.GetScenePresence(avatarID);
4177 } 4178 }
4178 4179
4180 /// <summary>
4181 /// Request the ScenePresence in this region by first/last name.
4182 /// Should normally only be a single match, but first is always returned
4183 /// </summary>
4184 /// <param name="firstName"></param>
4185 /// <param name="lastName"></param>
4186 /// <returns></returns>
4187 public ScenePresence GetScenePresence(string firstName, string lastName)
4188 {
4189 return m_sceneGraph.GetScenePresence(firstName, lastName);
4190 }
4191
4192 /// <summary>
4193 /// Request the ScenePresence in this region by localID.
4194 /// </summary>
4195 /// <param name="localID"></param>
4196 /// <returns></returns>
4197 public ScenePresence GetScenePresence(uint localID)
4198 {
4199 return m_sceneGraph.GetScenePresence(localID);
4200 }
4201
4179 public override bool PresenceChildStatus(UUID avatarID) 4202 public override bool PresenceChildStatus(UUID avatarID)
4180 { 4203 {
4181 ScenePresence cp = GetScenePresence(avatarID); 4204 ScenePresence cp = GetScenePresence(avatarID);
@@ -4191,25 +4214,14 @@ namespace OpenSim.Region.Framework.Scenes
4191 } 4214 }
4192 4215
4193 /// <summary> 4216 /// <summary>
4194 /// 4217 /// Performs action on all scene presences.
4195 /// </summary> 4218 /// </summary>
4196 /// <param name="action"></param> 4219 /// <param name="action"></param>
4197 public void ForEachScenePresence(Action<ScenePresence> action) 4220 public void ForEachScenePresence(Action<ScenePresence> action)
4198 { 4221 {
4199 // We don't want to try to send messages if there are no avatars.
4200 if (m_sceneGraph != null) 4222 if (m_sceneGraph != null)
4201 { 4223 {
4202 try 4224 m_sceneGraph.ForEachScenePresence(action);
4203 {
4204 ScenePresence[] presences = GetScenePresences();
4205 for (int i = 0; i < presences.Length; i++)
4206 action(presences[i]);
4207 }
4208 catch (Exception e)
4209 {
4210 m_log.Info("[BUG] in " + RegionInfo.RegionName + ": " + e.ToString());
4211 m_log.Info("[BUG] Stack Trace: " + e.StackTrace);
4212 }
4213 } 4225 }
4214 } 4226 }
4215 4227
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index d944834..d259c42 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -165,9 +165,10 @@ namespace OpenSim.Region.Framework.Scenes
165 165
166 protected internal void UpdatePresences() 166 protected internal void UpdatePresences()
167 { 167 {
168 ScenePresence[] updateScenePresences = GetScenePresences(); 168 ForEachScenePresence(delegate(ScenePresence presence)
169 for (int i = 0; i < updateScenePresences.Length; i++) 169 {
170 updateScenePresences[i].Update(); 170 presence.Update();
171 });
171 } 172 }
172 173
173 protected internal float UpdatePhysics(double elapsed) 174 protected internal float UpdatePhysics(double elapsed)
@@ -196,9 +197,10 @@ namespace OpenSim.Region.Framework.Scenes
196 197
197 protected internal void UpdateScenePresenceMovement() 198 protected internal void UpdateScenePresenceMovement()
198 { 199 {
199 ScenePresence[] moveEntities = GetScenePresences(); 200 ForEachScenePresence(delegate(ScenePresence presence)
200 for (int i = 0; i < moveEntities.Length; i++) 201 {
201 moveEntities[i].UpdateMovement(); 202 presence.UpdateMovement();
203 });
202 } 204 }
203 205
204 #endregion 206 #endregion
@@ -616,18 +618,16 @@ namespace OpenSim.Region.Framework.Scenes
616 618
617 public void RecalculateStats() 619 public void RecalculateStats()
618 { 620 {
619 ScenePresence[] presences = GetScenePresences();
620 int rootcount = 0; 621 int rootcount = 0;
621 int childcount = 0; 622 int childcount = 0;
622 623
623 for (int i = 0; i < presences.Length; i++) 624 ForEachScenePresence(delegate(ScenePresence presence)
624 { 625 {
625 ScenePresence user = presences[i]; 626 if (presence.IsChildAgent)
626 if (user.IsChildAgent)
627 ++childcount; 627 ++childcount;
628 else 628 else
629 ++rootcount; 629 ++rootcount;
630 } 630 });
631 631
632 m_numRootAgents = rootcount; 632 m_numRootAgents = rootcount;
633 m_numChildAgents = childcount; 633 m_numChildAgents = childcount;
@@ -674,25 +674,6 @@ namespace OpenSim.Region.Framework.Scenes
674 #endregion 674 #endregion
675 675
676 #region Get Methods 676 #region Get Methods
677
678 /// <summary>
679 /// Request a List of all scene presences in this scene. This is a new list, so no
680 /// locking is required to iterate over it.
681 /// </summary>
682 /// <returns></returns>
683 protected internal ScenePresence[] GetScenePresences()
684 {
685 return m_scenePresenceArray;
686 }
687
688 protected internal List<ScenePresence> GetAvatars()
689 {
690 List<ScenePresence> result =
691 GetScenePresences(delegate(ScenePresence scenePresence) { return !scenePresence.IsChildAgent; });
692
693 return result;
694 }
695
696 /// <summary> 677 /// <summary>
697 /// Get the controlling client for the given avatar, if there is one. 678 /// Get the controlling client for the given avatar, if there is one.
698 /// 679 ///
@@ -718,45 +699,119 @@ namespace OpenSim.Region.Framework.Scenes
718 return null; 699 return null;
719 } 700 }
720 701
702 // The idea is to have a group of method that return a list of avatars meeting some requirement
703 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar.
704 //
705 // GetAvatars returns a new list of all root agent presences in the scene
706 // GetScenePresences returns a new list of all presences in the scene or a filter may be passed.
707 // GetScenePresence returns the presence with matching UUID or the first presence matching the passed filter.
708 // ForEachScenePresence requests the Scene to run a delegate function against all presences.
709
710 /// <summary>
711 /// Request a list of all avatars in this region (no child agents)
712 /// This list is a new object, so it can be iterated over without locking.
713 /// </summary>
714 /// <returns></returns>
715 public List<ScenePresence> GetAvatars()
716 {
717 return GetScenePresences(delegate(ScenePresence scenePresence)
718 {
719 return !scenePresence.IsChildAgent;
720 });
721 }
722
723 /// <summary>
724 /// Request a list of m_scenePresences in this World
725 /// Returns a copy so it can be iterated without a lock.
726 /// There is no guarantee that presences will remain in the scene after the list is returned.
727 /// </summary>
728 /// <returns></returns>
729 protected internal List<ScenePresence> GetScenePresences()
730 {
731 List<ScenePresence> result;
732 lock (m_scenePresences)
733 {
734 result = new List<ScenePresence>(m_scenePresenceArray.Length);
735 result.AddRange(m_scenePresenceArray);
736 }
737 return result;
738 }
739
721 /// <summary> 740 /// <summary>
722 /// Request a filtered list of m_scenePresences in this World 741 /// Request a filtered list of m_scenePresences in this World
742 /// Returns a copy so it can be iterated without a lock.
743 /// There is no guarantee that presences will remain in the scene after the list is returned.
723 /// </summary> 744 /// </summary>
724 /// <returns></returns> 745 /// <returns></returns>
725 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter) 746 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter)
726 { 747 {
727 // No locking of scene presences here since we're passing back a list...
728
729 List<ScenePresence> result = new List<ScenePresence>(); 748 List<ScenePresence> result = new List<ScenePresence>();
730 ScenePresence[] scenePresences = GetScenePresences(); 749 // Check each ScenePresence against the filter
750 ForEachScenePresence(delegate(ScenePresence presence)
751 {
752 if (filter(presence))
753 result.Add(presence);
754 });
755 return result;
756 }
731 757
732 for (int i = 0; i < scenePresences.Length; i++) 758 /// <summary>
759 /// Request the ScenePresence in this region matching filter.
760 /// Only the first match is returned.
761 ///
762 /// </summary>
763 /// <param name="filter"></param>
764 /// <returns></returns>
765 protected internal ScenePresence GetScenePresence(FilterAvatarList filter)
766 {
767 ScenePresence result = null;
768 // Get all of the ScenePresences
769 List<ScenePresence> presences = GetScenePresences();
770 foreach (ScenePresence presence in presences)
733 { 771 {
734 ScenePresence avatar = scenePresences[i]; 772 if (filter(presence))
735 if (filter(avatar)) 773 {
736 result.Add(avatar); 774 result = presence;
775 break;
776 }
737 } 777 }
738
739 return result; 778 return result;
740 } 779 }
741 780
781 protected internal ScenePresence GetScenePresence(string firstName, string lastName)
782 {
783 return GetScenePresence(delegate(ScenePresence presence)
784 {
785 return(presence.Firstname == firstName && presence.Lastname == lastName);
786 });
787 }
788
742 /// <summary> 789 /// <summary>
743 /// Request a scene presence by UUID 790 /// Request a scene presence by UUID
744 /// </summary> 791 /// </summary>
745 /// <param name="avatarID"></param> 792 /// <param name="agentID"></param>
746 /// <returns>null if the agent was not found</returns> 793 /// <returns>null if the agent was not found</returns>
747 protected internal ScenePresence GetScenePresence(UUID agentID) 794 protected internal ScenePresence GetScenePresence(UUID agentID)
748 { 795 {
749 ScenePresence sp; 796 ScenePresence sp;
750 797 TryGetAvatar(agentID, out sp);
751 lock (m_scenePresences)
752 {
753 m_scenePresences.TryGetValue(agentID, out sp);
754 }
755
756 return sp; 798 return sp;
757 } 799 }
758 800
759 /// <summary> 801 /// <summary>
802 /// Request the ScenePresence in this region by localID.
803 /// </summary>
804 /// <param name="localID"></param>
805 /// <returns></returns>
806 protected internal ScenePresence GetScenePresence(uint localID)
807 {
808 return GetScenePresence(delegate(ScenePresence presence)
809 {
810 return (presence.LocalId == localID);
811 });
812 }
813
814 /// <summary>
760 /// Get a scene object group that contains the prim with the given local id 815 /// Get a scene object group that contains the prim with the given local id
761 /// </summary> 816 /// </summary>
762 /// <param name="localID"></param> 817 /// <param name="localID"></param>
@@ -910,29 +965,19 @@ namespace OpenSim.Region.Framework.Scenes
910 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar) 965 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
911 { 966 {
912 lock (m_scenePresences) 967 lock (m_scenePresences)
913 return m_scenePresences.TryGetValue(avatarId, out avatar); 968 {
969 m_scenePresences.TryGetValue(avatarId, out avatar);
970 }
971 return (avatar != null);
914 } 972 }
915 973
916 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar) 974 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
917 { 975 {
918 ScenePresence[] presences = GetScenePresences(); 976 avatar = GetScenePresence(delegate(ScenePresence presence)
919
920 for (int i = 0; i < presences.Length; i++)
921 { 977 {
922 ScenePresence presence = presences[i]; 978 return (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0);
923 979 });
924 if (!presence.IsChildAgent) 980 return (avatar != null);
925 {
926 if (String.Compare(avatarName, presence.ControllingClient.Name, true) == 0)
927 {
928 avatar = presence;
929 return true;
930 }
931 }
932 }
933
934 avatar = null;
935 return false;
936 } 981 }
937 982
938 /// <summary> 983 /// <summary>
@@ -1013,6 +1058,28 @@ namespace OpenSim.Region.Framework.Scenes
1013 } 1058 }
1014 } 1059 }
1015 } 1060 }
1061
1062
1063 /// <summary>
1064 /// Performs action on all scene presences.
1065 /// </summary>
1066 /// <param name="action"></param>
1067 public void ForEachScenePresence(Action<ScenePresence> action)
1068 {
1069 List<ScenePresence> presences = GetScenePresences();
1070 try
1071 {
1072 foreach(ScenePresence presence in presences)
1073 {
1074 action(presence);
1075 }
1076 }
1077 catch (Exception e)
1078 {
1079 m_log.Info("[BUG] in " + m_parentScene.RegionInfo.RegionName + ": " + e.ToString());
1080 m_log.Info("[BUG] Stack Trace: " + e.StackTrace);
1081 }
1082 }
1016 1083
1017 #endregion 1084 #endregion
1018 1085
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
index 680c39a..a955532 100644
--- a/OpenSim/Region/Framework/Scenes/SceneManager.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -414,12 +414,8 @@ namespace OpenSim.Region.Framework.Scenes
414 ForEachCurrentScene( 414 ForEachCurrentScene(
415 delegate(Scene scene) 415 delegate(Scene scene)
416 { 416 {
417 ScenePresence[] scenePresences = scene.GetScenePresences(); 417 scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
418
419 for (int i = 0; i < scenePresences.Length; i++)
420 { 418 {
421 ScenePresence scenePresence = scenePresences[i];
422
423 if (!scenePresence.IsChildAgent) 419 if (!scenePresence.IsChildAgent)
424 { 420 {
425 m_log.DebugFormat("Packet debug for {0} {1} set to {2}", 421 m_log.DebugFormat("Packet debug for {0} {1} set to {2}",
@@ -429,7 +425,7 @@ namespace OpenSim.Region.Framework.Scenes
429 425
430 scenePresence.ControllingClient.SetDebugPacketLevel(newDebug); 426 scenePresence.ControllingClient.SetDebugPacketLevel(newDebug);
431 } 427 }
432 } 428 });
433 } 429 }
434 ); 430 );
435 } 431 }
@@ -441,14 +437,11 @@ namespace OpenSim.Region.Framework.Scenes
441 ForEachCurrentScene( 437 ForEachCurrentScene(
442 delegate(Scene scene) 438 delegate(Scene scene)
443 { 439 {
444 ScenePresence[] scenePresences = scene.GetScenePresences(); 440 scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
445
446 for (int i = 0; i < scenePresences.Length; i++)
447 { 441 {
448 ScenePresence scenePresence = scenePresences[i];
449 if (!scenePresence.IsChildAgent) 442 if (!scenePresence.IsChildAgent)
450 avatars.Add(scenePresence); 443 avatars.Add(scenePresence);
451 } 444 });
452 } 445 }
453 ); 446 );
454 447
@@ -461,7 +454,7 @@ namespace OpenSim.Region.Framework.Scenes
461 454
462 ForEachCurrentScene(delegate(Scene scene) 455 ForEachCurrentScene(delegate(Scene scene)
463 { 456 {
464 ScenePresence[] scenePresences = scene.GetScenePresences(); 457 List<ScenePresence> scenePresences = scene.GetScenePresences();
465 presences.AddRange(scenePresences); 458 presences.AddRange(scenePresences);
466 }); 459 });
467 460
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 88deedf..8aefd50 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -1268,22 +1268,20 @@ namespace OpenSim.Region.Framework.Scenes
1268 foreach (SceneObjectPart part in m_parts.Values) 1268 foreach (SceneObjectPart part in m_parts.Values)
1269 { 1269 {
1270// part.Inventory.RemoveScriptInstances(); 1270// part.Inventory.RemoveScriptInstances();
1271 1271 Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1272 ScenePresence[] avatars = Scene.GetScenePresences();
1273 for (int i = 0; i < avatars.Length; i++)
1274 { 1272 {
1275 if (avatars[i].ParentID == LocalId) 1273 if (avatar.ParentID == LocalId)
1276 { 1274 {
1277 avatars[i].StandUp(); 1275 avatar.StandUp();
1278 } 1276 }
1279 1277
1280 if (!silent) 1278 if (!silent)
1281 { 1279 {
1282 part.UpdateFlag = 0; 1280 part.UpdateFlag = 0;
1283 if (part == m_rootPart) 1281 if (part == m_rootPart)
1284 avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId); 1282 avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1285 } 1283 }
1286 } 1284 });
1287 } 1285 }
1288 } 1286 }
1289 } 1287 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index a2b98b9..0e21487 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1197,15 +1197,14 @@ namespace OpenSim.Region.Framework.Scenes
1197 1197
1198 private void SendObjectPropertiesToClient(UUID AgentID) 1198 private void SendObjectPropertiesToClient(UUID AgentID)
1199 { 1199 {
1200 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 1200 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1201 for (int i = 0; i < avatars.Length; i++)
1202 { 1201 {
1203 // Ugly reference :( 1202 // Ugly reference :(
1204 if (avatars[i].UUID == AgentID) 1203 if (avatar.UUID == AgentID)
1205 { 1204 {
1206 m_parentGroup.GetProperties(avatars[i].ControllingClient); 1205 m_parentGroup.GetProperties(avatar.ControllingClient);
1207 } 1206 }
1208 } 1207 });
1209 } 1208 }
1210 1209
1211 // TODO: unused: 1210 // TODO: unused:
@@ -1260,11 +1259,10 @@ namespace OpenSim.Region.Framework.Scenes
1260 /// </summary> 1259 /// </summary>
1261 public void AddFullUpdateToAllAvatars() 1260 public void AddFullUpdateToAllAvatars()
1262 { 1261 {
1263 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 1262 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1264 for (int i = 0; i < avatars.Length; i++)
1265 { 1263 {
1266 avatars[i].SceneViewer.QueuePartForUpdate(this); 1264 avatar.SceneViewer.QueuePartForUpdate(this);
1267 } 1265 });
1268 } 1266 }
1269 1267
1270 public void AddFullUpdateToAvatar(ScenePresence presence) 1268 public void AddFullUpdateToAvatar(ScenePresence presence)
@@ -1285,11 +1283,10 @@ namespace OpenSim.Region.Framework.Scenes
1285 /// Terse updates 1283 /// Terse updates
1286 public void AddTerseUpdateToAllAvatars() 1284 public void AddTerseUpdateToAllAvatars()
1287 { 1285 {
1288 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 1286 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1289 for (int i = 0; i < avatars.Length; i++)
1290 { 1287 {
1291 avatars[i].SceneViewer.QueuePartForUpdate(this); 1288 avatar.SceneViewer.QueuePartForUpdate(this);
1292 } 1289 });
1293 } 1290 }
1294 1291
1295 public void AddTerseUpdateToAvatar(ScenePresence presence) 1292 public void AddTerseUpdateToAvatar(ScenePresence presence)
@@ -2121,17 +2118,13 @@ namespace OpenSim.Region.Framework.Scenes
2121 } 2118 }
2122 else 2119 else
2123 { 2120 {
2124 ScenePresence[] avlist = m_parentGroup.Scene.GetScenePresences(); 2121 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence av)
2125
2126 for (int i = 0; i < avlist.Length; i++)
2127 { 2122 {
2128 ScenePresence av = avlist[i];
2129
2130 if (av.LocalId == localId) 2123 if (av.LocalId == localId)
2131 { 2124 {
2132 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) 2125 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name))
2133 { 2126 {
2134 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2127 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2135 //If it is 1, it is to accept ONLY collisions from this avatar 2128 //If it is 1, it is to accept ONLY collisions from this avatar
2136 if (found) 2129 if (found)
2137 { 2130 {
@@ -2153,7 +2146,7 @@ namespace OpenSim.Region.Framework.Scenes
2153 } 2146 }
2154 else 2147 else
2155 { 2148 {
2156 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2149 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2157 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work 2150 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
2158 if (!found) 2151 if (!found)
2159 { 2152 {
@@ -2171,7 +2164,7 @@ namespace OpenSim.Region.Framework.Scenes
2171 } 2164 }
2172 2165
2173 } 2166 }
2174 } 2167 });
2175 } 2168 }
2176 } 2169 }
2177 if (colliding.Count > 0) 2170 if (colliding.Count > 0)
@@ -2257,17 +2250,13 @@ namespace OpenSim.Region.Framework.Scenes
2257 } 2250 }
2258 else 2251 else
2259 { 2252 {
2260 ScenePresence[] avlist = m_parentGroup.Scene.GetScenePresences(); 2253 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence av)
2261
2262 for (int i = 0; i < avlist.Length; i++)
2263 { 2254 {
2264 ScenePresence av = avlist[i];
2265
2266 if (av.LocalId == localId) 2255 if (av.LocalId == localId)
2267 { 2256 {
2268 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) 2257 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name))
2269 { 2258 {
2270 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2259 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2271 //If it is 1, it is to accept ONLY collisions from this avatar 2260 //If it is 1, it is to accept ONLY collisions from this avatar
2272 if (found) 2261 if (found)
2273 { 2262 {
@@ -2289,7 +2278,7 @@ namespace OpenSim.Region.Framework.Scenes
2289 } 2278 }
2290 else 2279 else
2291 { 2280 {
2292 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2281 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2293 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work 2282 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
2294 if (!found) 2283 if (!found)
2295 { 2284 {
@@ -2307,7 +2296,7 @@ namespace OpenSim.Region.Framework.Scenes
2307 } 2296 }
2308 2297
2309 } 2298 }
2310 } 2299 });
2311 } 2300 }
2312 } 2301 }
2313 if (colliding.Count > 0) 2302 if (colliding.Count > 0)
@@ -2388,17 +2377,13 @@ namespace OpenSim.Region.Framework.Scenes
2388 } 2377 }
2389 else 2378 else
2390 { 2379 {
2391 ScenePresence[] avlist = m_parentGroup.Scene.GetScenePresences(); 2380 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence av)
2392
2393 for (int i = 0; i < avlist.Length; i++)
2394 { 2381 {
2395 ScenePresence av = avlist[i];
2396
2397 if (av.LocalId == localId) 2382 if (av.LocalId == localId)
2398 { 2383 {
2399 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name)) 2384 if (m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) || m_parentGroup.RootPart.CollisionFilter.ContainsValue(av.Name))
2400 { 2385 {
2401 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2386 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2402 //If it is 1, it is to accept ONLY collisions from this avatar 2387 //If it is 1, it is to accept ONLY collisions from this avatar
2403 if (found) 2388 if (found)
2404 { 2389 {
@@ -2420,7 +2405,7 @@ namespace OpenSim.Region.Framework.Scenes
2420 } 2405 }
2421 else 2406 else
2422 { 2407 {
2423 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1,out data); 2408 bool found = m_parentGroup.RootPart.CollisionFilter.TryGetValue(1, out data);
2424 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work 2409 //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
2425 if (!found) 2410 if (!found)
2426 { 2411 {
@@ -2438,7 +2423,7 @@ namespace OpenSim.Region.Framework.Scenes
2438 } 2423 }
2439 2424
2440 } 2425 }
2441 } 2426 });
2442 } 2427 }
2443 } 2428 }
2444 2429
@@ -2877,11 +2862,10 @@ namespace OpenSim.Region.Framework.Scenes
2877 /// </summary> 2862 /// </summary>
2878 public void SendFullUpdateToAllClients() 2863 public void SendFullUpdateToAllClients()
2879 { 2864 {
2880 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 2865 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
2881 for (int i = 0; i < avatars.Length; i++)
2882 { 2866 {
2883 SendFullUpdate(avatars[i].ControllingClient, avatars[i].GenerateClientFlags(UUID)); 2867 SendFullUpdate(avatar.ControllingClient, avatar.GenerateClientFlags(UUID));
2884 } 2868 });
2885 } 2869 }
2886 2870
2887 /// <summary> 2871 /// <summary>
@@ -2890,13 +2874,12 @@ namespace OpenSim.Region.Framework.Scenes
2890 /// <param name="agentID"></param> 2874 /// <param name="agentID"></param>
2891 public void SendFullUpdateToAllClientsExcept(UUID agentID) 2875 public void SendFullUpdateToAllClientsExcept(UUID agentID)
2892 { 2876 {
2893 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 2877 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
2894 for (int i = 0; i < avatars.Length; i++)
2895 { 2878 {
2896 // Ugly reference :( 2879 // Ugly reference :(
2897 if (avatars[i].UUID != agentID) 2880 if (avatar.UUID != agentID)
2898 SendFullUpdate(avatars[i].ControllingClient, avatars[i].GenerateClientFlags(UUID)); 2881 SendFullUpdate(avatar.ControllingClient, avatar.GenerateClientFlags(UUID));
2899 } 2882 });
2900 } 2883 }
2901 2884
2902 /// <summary> 2885 /// <summary>
@@ -3096,11 +3079,10 @@ namespace OpenSim.Region.Framework.Scenes
3096 /// </summary> 3079 /// </summary>
3097 public void SendTerseUpdateToAllClients() 3080 public void SendTerseUpdateToAllClients()
3098 { 3081 {
3099 ScenePresence[] avatars = m_parentGroup.Scene.GetScenePresences(); 3082 m_parentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
3100 for (int i = 0; i < avatars.Length; i++)
3101 { 3083 {
3102 SendTerseUpdateToClient(avatars[i].ControllingClient); 3084 SendTerseUpdateToClient(avatar.ControllingClient);
3103 } 3085 });
3104 } 3086 }
3105 3087
3106 public void SetAttachmentPoint(uint AttachmentPoint) 3088 public void SetAttachmentPoint(uint AttachmentPoint)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 6f16ff3..766f6d3 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -912,14 +912,11 @@ namespace OpenSim.Region.Framework.Scenes
912 912
913 m_isChildAgent = false; 913 m_isChildAgent = false;
914 914
915 ScenePresence[] animAgents = m_scene.GetScenePresences(); 915 m_scene.ForEachScenePresence(delegate(ScenePresence presence)
916 for (int i = 0; i < animAgents.Length; i++)
917 { 916 {
918 ScenePresence presence = animAgents[i];
919
920 if (presence != this) 917 if (presence != this)
921 presence.Animator.SendAnimPackToClient(ControllingClient); 918 presence.Animator.SendAnimPackToClient(ControllingClient);
922 } 919 });
923 920
924 m_scene.EventManager.TriggerOnMakeRootAgent(this); 921 m_scene.EventManager.TriggerOnMakeRootAgent(this);
925 } 922 }
@@ -2469,13 +2466,10 @@ namespace OpenSim.Region.Framework.Scenes
2469 public void SendInitialFullUpdateToAllClients() 2466 public void SendInitialFullUpdateToAllClients()
2470 { 2467 {
2471 m_perfMonMS = Util.EnvironmentTickCount(); 2468 m_perfMonMS = Util.EnvironmentTickCount();
2472 2469 int avUpdates = 0;
2473 ScenePresence[] avatars = m_scene.GetScenePresences(); 2470 m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
2474
2475 for (int i = 0; i < avatars.Length; i++)
2476 { 2471 {
2477 ScenePresence avatar = avatars[i]; 2472 ++avUpdates;
2478
2479 // only send if this is the root (children are only "listening posts" in a foreign region) 2473 // only send if this is the root (children are only "listening posts" in a foreign region)
2480 if (!IsChildAgent) 2474 if (!IsChildAgent)
2481 { 2475 {
@@ -2491,9 +2485,9 @@ namespace OpenSim.Region.Framework.Scenes
2491 avatar.Animator.SendAnimPackToClient(ControllingClient); 2485 avatar.Animator.SendAnimPackToClient(ControllingClient);
2492 } 2486 }
2493 } 2487 }
2494 } 2488 });
2495 2489
2496 m_scene.StatsReporter.AddAgentUpdates(avatars.Length); 2490 m_scene.StatsReporter.AddAgentUpdates(avUpdates);
2497 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS)); 2491 m_scene.StatsReporter.AddAgentTime(Util.EnvironmentTickCountSubtract(m_perfMonMS));
2498 2492
2499 //Animator.SendAnimPack(); 2493 //Animator.SendAnimPack();
diff --git a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
index 704b74f..a567413 100644
--- a/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
+++ b/OpenSim/Region/UserStatistics/ActiveConnectionsAJAX.cs
@@ -68,7 +68,7 @@ namespace OpenSim.Region.UserStatistics
68 HTMLUtil.OL_O(ref output, ""); 68 HTMLUtil.OL_O(ref output, "");
69 foreach (Scene scene in all_scenes) 69 foreach (Scene scene in all_scenes)
70 { 70 {
71 ScenePresence[] avatarInScene = scene.GetScenePresences(); 71 List<ScenePresence> avatarInScene = scene.GetScenePresences();
72 72
73 HTMLUtil.LI_O(ref output, String.Empty); 73 HTMLUtil.LI_O(ref output, String.Empty);
74 output.Append(scene.RegionInfo.RegionName); 74 output.Append(scene.RegionInfo.RegionName);