aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISceneViewer.cs14
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs180
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneViewer.cs226
4 files changed, 269 insertions, 159 deletions
diff --git a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs
new file mode 100644
index 0000000..1b2cdee
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs
@@ -0,0 +1,14 @@
1using System;
2using OpenSim.Region.Framework.Scenes;
3
4namespace OpenSim.Region.Framework.Interfaces
5{
6 public interface ISceneViewer
7 {
8 void Reset();
9 void Close();
10 int MaxPrimsPerFrame { get; set; }
11 void QueuePartForUpdate(SceneObjectPart part);
12 void SendPrimUpdates();
13 }
14}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index a9a150a..dd00ff4 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1145,13 +1145,13 @@ if (m_shape != null) {
1145 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); 1145 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
1146 for (int i = 0; i < avatars.Count; i++) 1146 for (int i = 0; i < avatars.Count; i++)
1147 { 1147 {
1148 avatars[i].QueuePartForUpdate(this); 1148 avatars[i].SceneViewer.QueuePartForUpdate(this);
1149 } 1149 }
1150 } 1150 }
1151 1151
1152 public void AddFullUpdateToAvatar(ScenePresence presence) 1152 public void AddFullUpdateToAvatar(ScenePresence presence)
1153 { 1153 {
1154 presence.QueuePartForUpdate(this); 1154 presence.SceneViewer.QueuePartForUpdate(this);
1155 } 1155 }
1156 1156
1157 public void AddNewParticleSystem(Primitive.ParticleSystem pSystem) 1157 public void AddNewParticleSystem(Primitive.ParticleSystem pSystem)
@@ -1170,13 +1170,13 @@ if (m_shape != null) {
1170 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); 1170 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
1171 for (int i = 0; i < avatars.Count; i++) 1171 for (int i = 0; i < avatars.Count; i++)
1172 { 1172 {
1173 avatars[i].QueuePartForUpdate(this); 1173 avatars[i].SceneViewer.QueuePartForUpdate(this);
1174 } 1174 }
1175 } 1175 }
1176 1176
1177 public void AddTerseUpdateToAvatar(ScenePresence presence) 1177 public void AddTerseUpdateToAvatar(ScenePresence presence)
1178 { 1178 {
1179 presence.QueuePartForUpdate(this); 1179 presence.SceneViewer.QueuePartForUpdate(this);
1180 } 1180 }
1181 1181
1182 public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim) 1182 public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index cdd1a85..1bee3c0 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -74,6 +74,9 @@ namespace OpenSim.Region.Framework.Scenes
74 public static byte[] DefaultTexture; 74 public static byte[] DefaultTexture;
75 75
76 public UUID currentParcelUUID = UUID.Zero; 76 public UUID currentParcelUUID = UUID.Zero;
77
78 private ISceneViewer m_sceneViewer;
79
77 private AnimationSet m_animations = new AnimationSet(); 80 private AnimationSet m_animations = new AnimationSet();
78 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>(); 81 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>();
79 private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; 82 private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO;
@@ -222,11 +225,6 @@ namespace OpenSim.Region.Framework.Scenes
222 /// </summary> 225 /// </summary>
223 private Vector3 posLastSignificantMove; 226 private Vector3 posLastSignificantMove;
224 227
225 private UpdateQueue m_partsUpdateQueue = new UpdateQueue();
226 private Queue<SceneObjectGroup> m_pendingObjects;
227
228 private Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>();
229
230 // For teleports and crossings callbacks 228 // For teleports and crossings callbacks
231 string m_callbackURI; 229 string m_callbackURI;
232 ulong m_rootRegionHandle; 230 ulong m_rootRegionHandle;
@@ -396,8 +394,8 @@ namespace OpenSim.Region.Framework.Scenes
396 394
397 public int MaxPrimsPerFrame 395 public int MaxPrimsPerFrame
398 { 396 {
399 get { return m_maxPrimsPerFrame; } 397 get { return m_sceneViewer.MaxPrimsPerFrame; }
400 set { m_maxPrimsPerFrame = value; } 398 set { m_sceneViewer.MaxPrimsPerFrame = value; }
401 } 399 }
402 400
403 /// <summary> 401 /// <summary>
@@ -527,6 +525,11 @@ namespace OpenSim.Region.Framework.Scenes
527 } 525 }
528 } 526 }
529 527
528 public ISceneViewer SceneViewer
529 {
530 get { return m_sceneViewer; }
531 }
532
530 public void AdjustKnownSeeds() 533 public void AdjustKnownSeeds()
531 { 534 {
532 Dictionary<ulong, string> seeds = Scene.CapsModule.GetChildrenSeeds(UUID); 535 Dictionary<ulong, string> seeds = Scene.CapsModule.GetChildrenSeeds(UUID);
@@ -601,7 +604,7 @@ namespace OpenSim.Region.Framework.Scenes
601 604
602 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo) 605 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo)
603 { 606 {
604 607 CreateSceneViewer();
605 m_regionHandle = reginfo.RegionHandle; 608 m_regionHandle = reginfo.RegionHandle;
606 m_controllingClient = client; 609 m_controllingClient = client;
607 m_firstname = m_controllingClient.FirstName; 610 m_firstname = m_controllingClient.FirstName;
@@ -643,15 +646,22 @@ namespace OpenSim.Region.Framework.Scenes
643 AvatarWearable[] wearables) 646 AvatarWearable[] wearables)
644 : this(client, world, reginfo) 647 : this(client, world, reginfo)
645 { 648 {
649 CreateSceneViewer();
646 m_appearance = new AvatarAppearance(m_uuid, wearables, visualParams); 650 m_appearance = new AvatarAppearance(m_uuid, wearables, visualParams);
647 } 651 }
648 652
649 public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance) 653 public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance)
650 : this(client, world, reginfo) 654 : this(client, world, reginfo)
651 { 655 {
656 CreateSceneViewer();
652 m_appearance = appearance; 657 m_appearance = appearance;
653 } 658 }
654 659
660 private void CreateSceneViewer()
661 {
662 m_sceneViewer = new SceneViewer(this);
663 }
664
655 public void RegisterToEvents() 665 public void RegisterToEvents()
656 { 666 {
657 m_controllingClient.OnRequestWearables += SendWearables; 667 m_controllingClient.OnRequestWearables += SendWearables;
@@ -704,13 +714,7 @@ namespace OpenSim.Region.Framework.Scenes
704 /// <param name="part"></param> 714 /// <param name="part"></param>
705 public void QueuePartForUpdate(SceneObjectPart part) 715 public void QueuePartForUpdate(SceneObjectPart part)
706 { 716 {
707 //if (InterestList.Contains(part.ParentGroup)) 717 m_sceneViewer.QueuePartForUpdate(part);
708 //{
709 lock (m_partsUpdateQueue)
710 {
711 m_partsUpdateQueue.Enqueue(part);
712 }
713 // }
714 } 718 }
715 719
716 public uint GenerateClientFlags(UUID ObjectID) 720 public uint GenerateClientFlags(UUID ObjectID)
@@ -725,122 +729,9 @@ namespace OpenSim.Region.Framework.Scenes
725 /// </summary> 729 /// </summary>
726 public void SendPrimUpdates() 730 public void SendPrimUpdates()
727 { 731 {
728 // if (m_scene.QuadTree.GetNodeID(this.AbsolutePosition.X, this.AbsolutePosition.Y) != m_currentQuadNode)
729 //{
730 // this.UpdateQuadTreeNode();
731 //this.RefreshQuadObject();
732 //}
733 m_perfMonMS = Environment.TickCount; 732 m_perfMonMS = Environment.TickCount;
734 733
735 if (m_pendingObjects == null) 734 m_sceneViewer.SendPrimUpdates();
736 {
737 if (!m_isChildAgent || m_scene.m_seeIntoRegionFromNeighbor)
738 {
739 m_pendingObjects = new Queue<SceneObjectGroup>();
740
741 List<EntityBase> ents = new List<EntityBase>(m_scene.Entities);
742 if (!m_isChildAgent) // Proximity sort makes no sense for
743 { // Child agents
744 ents.Sort(delegate(EntityBase a, EntityBase b)
745 {
746 return Vector3.Distance(AbsolutePosition, a.AbsolutePosition).CompareTo(Vector3.Distance(AbsolutePosition, b.AbsolutePosition));
747 });
748 }
749
750 foreach (EntityBase e in ents)
751 {
752 if (e is SceneObjectGroup)
753 m_pendingObjects.Enqueue((SceneObjectGroup)e);
754 }
755 }
756 }
757
758 while (m_pendingObjects != null && m_pendingObjects.Count > 0 && m_partsUpdateQueue.Count < m_maxPrimsPerFrame)
759 {
760 SceneObjectGroup g = m_pendingObjects.Dequeue();
761
762 // This is where we should check for draw distance
763 // do culling and stuff. Problem with that is that until
764 // we recheck in movement, that won't work right.
765 // So it's not implemented now.
766 //
767
768 // Don't even queue if we have sent this one
769 //
770 if (!m_updateTimes.ContainsKey(g.UUID))
771 g.ScheduleFullUpdateToAvatar(this);
772 }
773
774 while (m_partsUpdateQueue.Count > 0)
775 {
776 SceneObjectPart part = m_partsUpdateQueue.Dequeue();
777
778 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
779 continue;
780
781 if (m_updateTimes.ContainsKey(part.UUID))
782 {
783 ScenePartUpdate update = m_updateTimes[part.UUID];
784
785 // We deal with the possibility that two updates occur at
786 // the same unix time at the update point itself.
787
788 if ((update.LastFullUpdateTime < part.TimeStampFull) ||
789 part.IsAttachment)
790 {
791// m_log.DebugFormat(
792// "[SCENE PRESENCE]: Fully updating prim {0}, {1} - part timestamp {2}",
793// part.Name, part.UUID, part.TimeStampFull);
794
795 part.SendFullUpdate(ControllingClient,
796 GenerateClientFlags(part.UUID));
797
798 // We'll update to the part's timestamp rather than
799 // the current time to avoid the race condition
800 // whereby the next tick occurs while we are doing
801 // this update. If this happened, then subsequent
802 // updates which occurred on the same tick or the
803 // next tick of the last update would be ignored.
804
805 update.LastFullUpdateTime = part.TimeStampFull;
806
807 }
808 else if (update.LastTerseUpdateTime <= part.TimeStampTerse)
809 {
810// m_log.DebugFormat(
811// "[SCENE PRESENCE]: Tersely updating prim {0}, {1} - part timestamp {2}",
812// part.Name, part.UUID, part.TimeStampTerse);
813
814 part.SendTerseUpdateToClient(ControllingClient);
815
816 update.LastTerseUpdateTime = part.TimeStampTerse;
817 }
818 }
819 else
820 {
821 //never been sent to client before so do full update
822 ScenePartUpdate update = new ScenePartUpdate();
823 update.FullID = part.UUID;
824 update.LastFullUpdateTime = part.TimeStampFull;
825 m_updateTimes.Add(part.UUID, update);
826
827 // Attachment handling
828 //
829 if (part.ParentGroup.RootPart.Shape.PCode == 9 && part.ParentGroup.RootPart.Shape.State != 0)
830 {
831 if (part != part.ParentGroup.RootPart)
832 continue;
833
834 part.ParentGroup.SendFullUpdateToClient(ControllingClient);
835 continue;
836 }
837
838 part.SendFullUpdate(ControllingClient,
839 GenerateClientFlags(part.UUID));
840 }
841 }
842
843 ControllingClient.FlushPrimUpdates();
844 735
845 m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS); 736 m_scene.StatsReporter.AddAgentTime(Environment.TickCount - m_perfMonMS);
846 } 737 }
@@ -935,7 +826,7 @@ namespace OpenSim.Region.Framework.Scenes
935 826
936 // On the next prim update, all objects will be sent 827 // On the next prim update, all objects will be sent
937 // 828 //
938 m_pendingObjects = null; 829 m_sceneViewer.Reset();
939 830
940 m_isChildAgent = false; 831 m_isChildAgent = false;
941 832
@@ -3062,7 +2953,7 @@ namespace OpenSim.Region.Framework.Scenes
3062 2953
3063 // Sends out the objects in the user's draw distance if m_sendTasksToChild is true. 2954 // Sends out the objects in the user's draw distance if m_sendTasksToChild is true.
3064 if (m_scene.m_seeIntoRegionFromNeighbor) 2955 if (m_scene.m_seeIntoRegionFromNeighbor)
3065 m_pendingObjects = null; 2956 m_sceneViewer.Reset();
3066 2957
3067 //cAgentData.AVHeight; 2958 //cAgentData.AVHeight;
3068 //cAgentData.regionHandle; 2959 //cAgentData.regionHandle;
@@ -3269,7 +3160,6 @@ namespace OpenSim.Region.Framework.Scenes
3269 { 3160 {
3270 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture(); 3161 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture();
3271 DefaultTexture = textu.GetBytes(); 3162 DefaultTexture = textu.GetBytes();
3272
3273 } 3163 }
3274 3164
3275 public class NewForce 3165 public class NewForce
@@ -3279,20 +3169,6 @@ namespace OpenSim.Region.Framework.Scenes
3279 public float Z; 3169 public float Z;
3280 } 3170 }
3281 3171
3282 public class ScenePartUpdate
3283 {
3284 public UUID FullID;
3285 public uint LastFullUpdateTime;
3286 public uint LastTerseUpdateTime;
3287
3288 public ScenePartUpdate()
3289 {
3290 FullID = UUID.Zero;
3291 LastFullUpdateTime = 0;
3292 LastTerseUpdateTime = 0;
3293 }
3294 }
3295
3296 public override void SetText(string text, Vector3 color, double alpha) 3172 public override void SetText(string text, Vector3 color, double alpha)
3297 { 3173 {
3298 throw new Exception("Can't set Text on avatar."); 3174 throw new Exception("Can't set Text on avatar.");
@@ -3394,14 +3270,7 @@ namespace OpenSim.Region.Framework.Scenes
3394 { 3270 {
3395 m_knownChildRegions.Clear(); 3271 m_knownChildRegions.Clear();
3396 } 3272 }
3397 lock (m_updateTimes) 3273 m_sceneViewer.Close();
3398 {
3399 m_updateTimes.Clear();
3400 }
3401 lock (m_partsUpdateQueue)
3402 {
3403 m_partsUpdateQueue.Clear();
3404 }
3405 3274
3406 RemoveFromPhysicalScene(); 3275 RemoveFromPhysicalScene();
3407 GC.Collect(); 3276 GC.Collect();
@@ -3413,7 +3282,8 @@ namespace OpenSim.Region.Framework.Scenes
3413 { 3282 {
3414 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture(); 3283 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture();
3415 DefaultTexture = textu.GetBytes(); 3284 DefaultTexture = textu.GetBytes();
3416 } 3285 }
3286 CreateSceneViewer();
3417 } 3287 }
3418 3288
3419 public void AddAttachment(SceneObjectGroup gobj) 3289 public void AddAttachment(SceneObjectGroup gobj)
diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs
new file mode 100644
index 0000000..4e542b8
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs
@@ -0,0 +1,226 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using log4net;
32using OpenSim.Framework;
33using OpenSim.Framework.Client;
34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes.Types;
37
38namespace OpenSim.Region.Framework.Scenes
39{
40 public class SceneViewer : ISceneViewer
41 {
42 protected ScenePresence m_presence;
43 protected UpdateQueue m_partsUpdateQueue = new UpdateQueue();
44 protected Queue<SceneObjectGroup> m_pendingObjects;
45
46 protected Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>();
47
48 protected int m_maxPrimsPerFrame = 200;
49
50 public int MaxPrimsPerFrame
51 {
52 get { return m_maxPrimsPerFrame; }
53 set { m_maxPrimsPerFrame = value; }
54 }
55
56 public SceneViewer()
57 {
58 }
59
60 public SceneViewer(ScenePresence presence)
61 {
62 m_presence = presence;
63 }
64
65 /// <summary>
66 /// Add the part to the queue of parts for which we need to send an update to the client
67 /// </summary>
68 /// <param name="part"></param>
69 public void QueuePartForUpdate(SceneObjectPart part)
70 {
71 lock (m_partsUpdateQueue)
72 {
73 m_partsUpdateQueue.Enqueue(part);
74 }
75 }
76
77 public void SendPrimUpdates()
78 {
79 if (m_pendingObjects == null)
80 {
81 if (!m_presence.IsChildAgent || (m_presence.Scene.m_seeIntoRegionFromNeighbor))
82 {
83 m_pendingObjects = new Queue<SceneObjectGroup>();
84
85 List<EntityBase> ents = new List<EntityBase>(m_presence.Scene.Entities);
86 if (!m_presence.IsChildAgent) // Proximity sort makes no sense for
87 { // Child agents
88 ents.Sort(delegate(EntityBase a, EntityBase b)
89 {
90 return Vector3.Distance(m_presence.AbsolutePosition, a.AbsolutePosition).CompareTo(Vector3.Distance(m_presence.AbsolutePosition, b.AbsolutePosition));
91 });
92 }
93
94 foreach (EntityBase e in ents)
95 {
96 if (e is SceneObjectGroup)
97 m_pendingObjects.Enqueue((SceneObjectGroup)e);
98 }
99 }
100 }
101
102 while (m_pendingObjects != null && m_pendingObjects.Count > 0 && m_partsUpdateQueue.Count < m_maxPrimsPerFrame)
103 {
104 SceneObjectGroup g = m_pendingObjects.Dequeue();
105
106 // This is where we should check for draw distance
107 // do culling and stuff. Problem with that is that until
108 // we recheck in movement, that won't work right.
109 // So it's not implemented now.
110 //
111
112 // Don't even queue if we have sent this one
113 //
114 if (!m_updateTimes.ContainsKey(g.UUID))
115 g.ScheduleFullUpdateToAvatar(m_presence);
116 }
117
118 while (m_partsUpdateQueue.Count > 0)
119 {
120 SceneObjectPart part = m_partsUpdateQueue.Dequeue();
121
122 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
123 continue;
124
125 if (m_updateTimes.ContainsKey(part.UUID))
126 {
127 ScenePartUpdate update = m_updateTimes[part.UUID];
128
129 // We deal with the possibility that two updates occur at
130 // the same unix time at the update point itself.
131
132 if ((update.LastFullUpdateTime < part.TimeStampFull) ||
133 part.IsAttachment)
134 {
135// m_log.DebugFormat(
136// "[SCENE PRESENCE]: Fully updating prim {0}, {1} - part timestamp {2}",
137// part.Name, part.UUID, part.TimeStampFull);
138
139 part.SendFullUpdate(m_presence.ControllingClient,
140 m_presence.GenerateClientFlags(part.UUID));
141
142 // We'll update to the part's timestamp rather than
143 // the current time to avoid the race condition
144 // whereby the next tick occurs while we are doing
145 // this update. If this happened, then subsequent
146 // updates which occurred on the same tick or the
147 // next tick of the last update would be ignored.
148
149 update.LastFullUpdateTime = part.TimeStampFull;
150
151 }
152 else if (update.LastTerseUpdateTime <= part.TimeStampTerse)
153 {
154// m_log.DebugFormat(
155// "[SCENE PRESENCE]: Tersely updating prim {0}, {1} - part timestamp {2}",
156// part.Name, part.UUID, part.TimeStampTerse);
157
158 part.SendTerseUpdateToClient(m_presence.ControllingClient);
159
160 update.LastTerseUpdateTime = part.TimeStampTerse;
161 }
162 }
163 else
164 {
165 //never been sent to client before so do full update
166 ScenePartUpdate update = new ScenePartUpdate();
167 update.FullID = part.UUID;
168 update.LastFullUpdateTime = part.TimeStampFull;
169 m_updateTimes.Add(part.UUID, update);
170
171 // Attachment handling
172 //
173 if (part.ParentGroup.RootPart.Shape.PCode == 9 && part.ParentGroup.RootPart.Shape.State != 0)
174 {
175 if (part != part.ParentGroup.RootPart)
176 continue;
177
178 part.ParentGroup.SendFullUpdateToClient(m_presence.ControllingClient);
179 continue;
180 }
181
182 part.SendFullUpdate(m_presence.ControllingClient,
183 m_presence.GenerateClientFlags(part.UUID));
184 }
185 }
186
187 m_presence.ControllingClient.FlushPrimUpdates();
188 }
189
190 public void Reset()
191 {
192 lock (m_pendingObjects)
193 {
194 m_pendingObjects.Clear();
195 m_pendingObjects = null;
196 }
197 }
198
199 public void Close()
200 {
201 lock (m_updateTimes)
202 {
203 m_updateTimes.Clear();
204 }
205 lock (m_partsUpdateQueue)
206 {
207 m_partsUpdateQueue.Clear();
208 }
209 Reset();
210 }
211
212 public class ScenePartUpdate
213 {
214 public UUID FullID;
215 public uint LastFullUpdateTime;
216 public uint LastTerseUpdateTime;
217
218 public ScenePartUpdate()
219 {
220 FullID = UUID.Zero;
221 LastFullUpdateTime = 0;
222 LastTerseUpdateTime = 0;
223 }
224 }
225 }
226}