aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorMW2009-06-26 12:09:43 +0000
committerMW2009-06-26 12:09:43 +0000
commit7a2c41dea0f1faf1c6de88d1a3da934d178bae84 (patch)
tree1a4f523917da00efd99366ce815c180888c9be1b /OpenSim
parentEnable the RemoteAdmin module to save regions as ini files rather than XML (diff)
downloadopensim-SC_OLD-7a2c41dea0f1faf1c6de88d1a3da934d178bae84.zip
opensim-SC_OLD-7a2c41dea0f1faf1c6de88d1a3da934d178bae84.tar.gz
opensim-SC_OLD-7a2c41dea0f1faf1c6de88d1a3da934d178bae84.tar.bz2
opensim-SC_OLD-7a2c41dea0f1faf1c6de88d1a3da934d178bae84.tar.xz
Extracted the code that handles the sending of prim updates to the client, from ScenePresence into ISceneViewer/SceneViewer. Currently ScenePresence "has" a ISceneViewer, although if we had a proper Node based scenegraph then it would most likely be attached directly to the nodes.
By extracting this code, it should make it easier to experiment with different ways of managing the update process. [Next step to make this module based, could be to create a SceneViewerFactoryModule]
Diffstat (limited to '')
-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}