diff options
author | Sean McNamara | 2011-04-23 18:33:08 -0400 |
---|---|---|
committer | Sean McNamara | 2011-04-23 18:33:08 -0400 |
commit | d287e0ac683acb0cab51bf0dbbc9d1fd08bd6bc9 (patch) | |
tree | 30a24bf66050c66ebe74b68745c4f1764fe09181 /OpenSim/Region/Framework | |
parent | AutoBackup: Removed unneeded imports. (diff) | |
parent | Added MaxAgents configuration option to RegionConfig.ini allowing region host... (diff) | |
download | opensim-SC_OLD-d287e0ac683acb0cab51bf0dbbc9d1fd08bd6bc9.zip opensim-SC_OLD-d287e0ac683acb0cab51bf0dbbc9d1fd08bd6bc9.tar.gz opensim-SC_OLD-d287e0ac683acb0cab51bf0dbbc9d1fd08bd6bc9.tar.bz2 opensim-SC_OLD-d287e0ac683acb0cab51bf0dbbc9d1fd08bd6bc9.tar.xz |
Merge git://opensimulator.org/git/opensim
Diffstat (limited to 'OpenSim/Region/Framework')
17 files changed, 620 insertions, 210 deletions
diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 05fc2ad..305975e 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs | |||
@@ -38,7 +38,23 @@ namespace OpenSim.Region.Framework.Interfaces | |||
38 | public interface IInventoryAccessModule | 38 | public interface IInventoryAccessModule |
39 | { | 39 | { |
40 | UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data); | 40 | UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data); |
41 | UUID DeleteToInventory(DeRezAction action, UUID folderID, List<SceneObjectGroup> objectGroups, IClientAPI remoteClient); | 41 | |
42 | /// <summary> | ||
43 | /// Copy objects to a user's inventory. | ||
44 | /// </summary> | ||
45 | /// <remarks> | ||
46 | /// Is it left to the caller to delete them from the scene if required. | ||
47 | /// </remarks> | ||
48 | /// <param name="action"></param> | ||
49 | /// <param name="folderID"></param> | ||
50 | /// <param name="objectGroups"></param> | ||
51 | /// <param name="remoteClient"></param> | ||
52 | /// <returns> | ||
53 | /// Returns the UUID of the newly created item asset (not the item itself). | ||
54 | /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. | ||
55 | /// </returns> | ||
56 | UUID CopyToInventory(DeRezAction action, UUID folderID, List<SceneObjectGroup> objectGroups, IClientAPI remoteClient); | ||
57 | |||
42 | SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, | 58 | SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, |
43 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | 59 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, |
44 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); | 60 | bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment); |
diff --git a/OpenSim/Region/Framework/ModuleLoader.cs b/OpenSim/Region/Framework/ModuleLoader.cs index 23be9c2..14ecd44 100644 --- a/OpenSim/Region/Framework/ModuleLoader.cs +++ b/OpenSim/Region/Framework/ModuleLoader.cs | |||
@@ -223,7 +223,8 @@ namespace OpenSim.Region.Framework | |||
223 | catch (Exception e) | 223 | catch (Exception e) |
224 | { | 224 | { |
225 | m_log.ErrorFormat( | 225 | m_log.ErrorFormat( |
226 | "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e); | 226 | "[MODULES]: Could not load types for plugin DLL {0}. Exception {1} {2}", |
227 | pluginAssembly.FullName, e.Message, e.StackTrace); | ||
227 | 228 | ||
228 | // justincc: Right now this is fatal to really get the user's attention | 229 | // justincc: Right now this is fatal to really get the user's attention |
229 | throw e; | 230 | throw e; |
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index 8feb022..3423542 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs | |||
@@ -143,7 +143,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
143 | { | 143 | { |
144 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 144 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); |
145 | if (invAccess != null) | 145 | if (invAccess != null) |
146 | invAccess.DeleteToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); | 146 | invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); |
147 | |||
147 | if (x.permissionToDelete) | 148 | if (x.permissionToDelete) |
148 | { | 149 | { |
149 | foreach (SceneObjectGroup g in x.objectGroups) | 150 | foreach (SceneObjectGroup g in x.objectGroups) |
diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs new file mode 100644 index 0000000..af8ccda --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs | |||
@@ -0,0 +1,154 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Framework.Scenes | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Represents a coalescene of scene objects. A coalescence occurs when objects that are not in the same linkset | ||
37 | /// are grouped together. | ||
38 | /// </summary> | ||
39 | public class CoalescedSceneObjects | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// The creator of this coalesence, though not necessarily the objects within it. | ||
43 | /// </summary> | ||
44 | public UUID CreatorId { get; set; } | ||
45 | |||
46 | /// <summary> | ||
47 | /// The number of objects in this coalesence | ||
48 | /// </summary> | ||
49 | public int Count | ||
50 | { | ||
51 | get | ||
52 | { | ||
53 | lock (m_memberObjects) | ||
54 | return m_memberObjects.Count; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /// <summary> | ||
59 | /// Does this coalesence have any member objects? | ||
60 | /// </summary> | ||
61 | public bool HasObjects { get { return Count > 0; } } | ||
62 | |||
63 | /// <summary> | ||
64 | /// Get the objects currently in this coalescence | ||
65 | /// </summary> | ||
66 | public List<SceneObjectGroup> Objects | ||
67 | { | ||
68 | get | ||
69 | { | ||
70 | lock (m_memberObjects) | ||
71 | return new List<SceneObjectGroup>(m_memberObjects); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | /// <summary> | ||
76 | /// Get the scene that contains the objects in this coalescence. If there are no objects then null is returned. | ||
77 | /// </summary> | ||
78 | public Scene Scene | ||
79 | { | ||
80 | get | ||
81 | { | ||
82 | if (!HasObjects) | ||
83 | return null; | ||
84 | else | ||
85 | return Objects[0].Scene; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | /// <summary> | ||
90 | /// At this point, we need to preserve the order of objects added to the coalescence, since the first | ||
91 | /// one will end up matching the item name when rerezzed. | ||
92 | /// </summary> | ||
93 | protected List<SceneObjectGroup> m_memberObjects = new List<SceneObjectGroup>(); | ||
94 | |||
95 | public CoalescedSceneObjects(UUID creatorId) | ||
96 | { | ||
97 | CreatorId = creatorId; | ||
98 | } | ||
99 | |||
100 | public CoalescedSceneObjects(UUID creatorId, params SceneObjectGroup[] objs) : this(creatorId) | ||
101 | { | ||
102 | foreach (SceneObjectGroup obj in objs) | ||
103 | Add(obj); | ||
104 | } | ||
105 | |||
106 | /// <summary> | ||
107 | /// Add an object to the coalescence. | ||
108 | /// </summary> | ||
109 | /// <param name="obj"></param> | ||
110 | /// <param name="offset">The offset of the object within the group</param> | ||
111 | public void Add(SceneObjectGroup obj) | ||
112 | { | ||
113 | lock (m_memberObjects) | ||
114 | m_memberObjects.Add(obj); | ||
115 | } | ||
116 | |||
117 | /// <summary> | ||
118 | /// Removes a scene object from the coalescene | ||
119 | /// </summary> | ||
120 | /// <param name="sceneObjectId"></param> | ||
121 | /// <returns>true if the object was there to be removed, false if not.</returns> | ||
122 | public bool Remove(SceneObjectGroup obj) | ||
123 | { | ||
124 | lock (m_memberObjects) | ||
125 | return m_memberObjects.Remove(obj); | ||
126 | } | ||
127 | |||
128 | /// <summary> | ||
129 | /// Get the total size of the coalescence (the size required to cover all the objects within it) and the | ||
130 | /// offsets of each of those objects. | ||
131 | /// </summary> | ||
132 | /// <param name="size"></param> | ||
133 | /// <returns> | ||
134 | /// An array of offsets. The order of objects is the same as returned from the Objects property | ||
135 | /// </returns> | ||
136 | public Vector3[] GetSizeAndOffsets(out Vector3 size) | ||
137 | { | ||
138 | float minX, minY, minZ; | ||
139 | float maxX, maxY, maxZ; | ||
140 | |||
141 | Vector3[] offsets | ||
142 | = Scene.GetCombinedBoundingBox( | ||
143 | Objects, out minX, out maxX, out minY, out maxY, out minZ, out maxZ); | ||
144 | |||
145 | float sizeX = maxX - minX; | ||
146 | float sizeY = maxY - minY; | ||
147 | float sizeZ = maxZ - minZ; | ||
148 | |||
149 | size = new Vector3(sizeX, sizeY, sizeZ); | ||
150 | |||
151 | return offsets; | ||
152 | } | ||
153 | } | ||
154 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index f9599f5..e3ed905 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs | |||
@@ -58,17 +58,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
58 | 58 | ||
59 | public class Prioritizer | 59 | public class Prioritizer |
60 | { | 60 | { |
61 | // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 61 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
62 | 62 | ||
63 | /// <summary> | ||
64 | /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the | ||
65 | /// viewer before child prim updates. | ||
66 | /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up | ||
67 | /// being double. We do it both ways so that there is a still a priority delta even if the priority is already | ||
68 | /// double.MinValue or double.MaxValue. | ||
69 | /// </summary> | ||
70 | private double m_childPrimAdjustmentFactor = 0.05; | ||
71 | |||
72 | private Scene m_scene; | 63 | private Scene m_scene; |
73 | 64 | ||
74 | public Prioritizer(Scene scene) | 65 | public Prioritizer(Scene scene) |
@@ -76,17 +67,35 @@ namespace OpenSim.Region.Framework.Scenes | |||
76 | m_scene = scene; | 67 | m_scene = scene; |
77 | } | 68 | } |
78 | 69 | ||
79 | public double GetUpdatePriority(IClientAPI client, ISceneEntity entity) | 70 | /// <summary> |
71 | /// Returns the priority queue into which the update should be placed. Updates within a | ||
72 | /// queue will be processed in arrival order. There are currently 12 priority queues | ||
73 | /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained | ||
74 | /// for avatar updates. The fair queuing discipline for processing the priority queues | ||
75 | /// assumes that the number of entities in each priority queues increases exponentially. | ||
76 | /// So for example... if queue 1 contains all updates within 10m of the avatar or camera | ||
77 | /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number | ||
78 | /// of updates. | ||
79 | /// </summary> | ||
80 | public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity) | ||
80 | { | 81 | { |
81 | double priority = 0; | 82 | // If entity is null we have a serious problem |
82 | |||
83 | if (entity == null) | 83 | if (entity == null) |
84 | return 100000; | 84 | { |
85 | m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity"); | ||
86 | throw new InvalidOperationException("Prioritization entity not defined"); | ||
87 | } | ||
88 | |||
89 | // If this is an update for our own avatar give it the highest priority | ||
90 | if (client.AgentId == entity.UUID) | ||
91 | return 0; | ||
92 | |||
93 | uint priority; | ||
85 | 94 | ||
86 | switch (m_scene.UpdatePrioritizationScheme) | 95 | switch (m_scene.UpdatePrioritizationScheme) |
87 | { | 96 | { |
88 | case UpdatePrioritizationSchemes.Time: | 97 | case UpdatePrioritizationSchemes.Time: |
89 | priority = GetPriorityByTime(); | 98 | priority = GetPriorityByTime(client, entity); |
90 | break; | 99 | break; |
91 | case UpdatePrioritizationSchemes.Distance: | 100 | case UpdatePrioritizationSchemes.Distance: |
92 | priority = GetPriorityByDistance(client, entity); | 101 | priority = GetPriorityByDistance(client, entity); |
@@ -104,180 +113,115 @@ namespace OpenSim.Region.Framework.Scenes | |||
104 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); | 113 | throw new InvalidOperationException("UpdatePrioritizationScheme not defined."); |
105 | } | 114 | } |
106 | 115 | ||
107 | // Adjust priority so that root prims are sent to the viewer first. This is especially important for | ||
108 | // attachments acting as huds, since current viewers fail to display hud child prims if their updates | ||
109 | // arrive before the root one. | ||
110 | if (entity is SceneObjectPart) | ||
111 | { | ||
112 | SceneObjectPart sop = ((SceneObjectPart)entity); | ||
113 | |||
114 | if (sop.IsRoot) | ||
115 | { | ||
116 | if (priority >= double.MinValue + m_childPrimAdjustmentFactor) | ||
117 | priority -= m_childPrimAdjustmentFactor; | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | if (priority <= double.MaxValue - m_childPrimAdjustmentFactor) | ||
122 | priority += m_childPrimAdjustmentFactor; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | return priority; | 116 | return priority; |
127 | } | 117 | } |
128 | 118 | ||
129 | private double GetPriorityByTime() | 119 | |
120 | private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) | ||
130 | { | 121 | { |
131 | return DateTime.UtcNow.ToOADate(); | 122 | return 1; |
132 | } | 123 | } |
133 | 124 | ||
134 | private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity) | 125 | private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) |
135 | { | 126 | { |
136 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 127 | return ComputeDistancePriority(client,entity,false); |
137 | if (presence != null) | 128 | } |
138 | { | 129 | |
139 | // If this is an update for our own avatar give it the highest priority | 130 | private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) |
140 | if (presence == entity) | 131 | { |
141 | return 0.0; | 132 | return ComputeDistancePriority(client,entity,true); |
142 | |||
143 | // Use the camera position for local agents and avatar position for remote agents | ||
144 | Vector3 presencePos = (presence.IsChildAgent) ? | ||
145 | presence.AbsolutePosition : | ||
146 | presence.CameraPosition; | ||
147 | |||
148 | // Use group position for child prims | ||
149 | Vector3 entityPos; | ||
150 | if (entity is SceneObjectPart) | ||
151 | { | ||
152 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
153 | // before its scheduled update was triggered | ||
154 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
155 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | entityPos = entity.AbsolutePosition; | ||
160 | } | ||
161 | |||
162 | return Vector3.DistanceSquared(presencePos, entityPos); | ||
163 | } | ||
164 | |||
165 | return double.NaN; | ||
166 | } | 133 | } |
167 | 134 | ||
168 | private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) | 135 | private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) |
169 | { | 136 | { |
137 | uint pqueue = ComputeDistancePriority(client,entity,true); | ||
138 | |||
170 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 139 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
171 | if (presence != null) | 140 | if (presence != null) |
172 | { | 141 | { |
173 | // If this is an update for our own avatar give it the highest priority | ||
174 | if (presence == entity) | ||
175 | return 0.0; | ||
176 | |||
177 | // Use group position for child prims | ||
178 | Vector3 entityPos = entity.AbsolutePosition; | ||
179 | if (entity is SceneObjectPart) | ||
180 | { | ||
181 | // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene | ||
182 | // before its scheduled update was triggered | ||
183 | //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; | ||
184 | entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition; | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | entityPos = entity.AbsolutePosition; | ||
189 | } | ||
190 | |||
191 | if (!presence.IsChildAgent) | 142 | if (!presence.IsChildAgent) |
192 | { | 143 | { |
193 | // Root agent. Use distance from camera and a priority decrease for objects behind us | 144 | if (entity is SceneObjectPart) |
194 | Vector3 camPosition = presence.CameraPosition; | 145 | { |
195 | Vector3 camAtAxis = presence.CameraAtAxis; | 146 | // Non physical prims are lower priority than physical prims |
196 | 147 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | |
197 | // Distance | 148 | if (physActor == null || !physActor.IsPhysical) |
198 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | 149 | pqueue++; |
199 | |||
200 | // Plane equation | ||
201 | float d = -Vector3.Dot(camPosition, camAtAxis); | ||
202 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | ||
203 | if (p < 0.0f) priority *= 2.0; | ||
204 | |||
205 | return priority; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | // Child agent. Use the normal distance method | ||
210 | Vector3 presencePos = presence.AbsolutePosition; | ||
211 | 150 | ||
212 | return Vector3.DistanceSquared(presencePos, entityPos); | 151 | // Attachments are high priority, |
152 | // MIC: shouldn't these already be in the highest priority queue already | ||
153 | // since their root position is same as the avatars? | ||
154 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | ||
155 | pqueue = 1; | ||
156 | } | ||
213 | } | 157 | } |
214 | } | 158 | } |
215 | 159 | ||
216 | return double.NaN; | 160 | return pqueue; |
217 | } | 161 | } |
218 | 162 | ||
219 | private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity) | 163 | private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack) |
220 | { | 164 | { |
221 | // If this is an update for our own avatar give it the highest priority | 165 | // Get this agent's position |
222 | if (client.AgentId == entity.UUID) | 166 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); |
223 | return 0.0; | 167 | if (presence == null) |
224 | if (entity == null) | 168 | { |
225 | return double.NaN; | 169 | // this shouldn't happen, it basically means that we are prioritizing |
170 | // updates to send to a client that doesn't have a presence in the scene | ||
171 | // seems like there's race condition here... | ||
226 | 172 | ||
227 | // Use group position for child prims | 173 | // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); |
174 | // throw new InvalidOperationException("Prioritization agent not defined"); | ||
175 | return Int32.MaxValue; | ||
176 | } | ||
177 | |||
178 | // Use group position for child prims, since we are putting child prims in | ||
179 | // the same queue with the root of the group, the root prim (which goes into | ||
180 | // the queue first) should always be sent first, no need to adjust child prim | ||
181 | // priorities | ||
228 | Vector3 entityPos = entity.AbsolutePosition; | 182 | Vector3 entityPos = entity.AbsolutePosition; |
229 | if (entity is SceneObjectPart) | 183 | if (entity is SceneObjectPart) |
230 | { | 184 | { |
231 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; | 185 | SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup; |
232 | if (group != null) | 186 | if (group != null) |
233 | entityPos = group.AbsolutePosition; | 187 | entityPos = group.AbsolutePosition; |
234 | else | ||
235 | entityPos = entity.AbsolutePosition; | ||
236 | } | 188 | } |
237 | else | ||
238 | entityPos = entity.AbsolutePosition; | ||
239 | 189 | ||
240 | ScenePresence presence = m_scene.GetScenePresence(client.AgentId); | 190 | // Use the camera position for local agents and avatar position for remote agents |
241 | if (presence != null) | 191 | Vector3 presencePos = (presence.IsChildAgent) ? |
242 | { | 192 | presence.AbsolutePosition : |
243 | if (!presence.IsChildAgent) | 193 | presence.CameraPosition; |
244 | { | ||
245 | if (entity is ScenePresence) | ||
246 | return 1.0; | ||
247 | |||
248 | // Root agent. Use distance from camera and a priority decrease for objects behind us | ||
249 | Vector3 camPosition = presence.CameraPosition; | ||
250 | Vector3 camAtAxis = presence.CameraAtAxis; | ||
251 | 194 | ||
252 | // Distance | 195 | // Compute the distance... |
253 | double priority = Vector3.DistanceSquared(camPosition, entityPos); | 196 | double distance = Vector3.Distance(presencePos, entityPos); |
254 | 197 | ||
255 | // Plane equation | 198 | // And convert the distance to a priority queue, this computation gives queues |
256 | float d = -Vector3.Dot(camPosition, camAtAxis); | 199 | // at 10, 20, 40, 80, 160, 320, 640, and 1280m |
257 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | 200 | uint pqueue = 1; |
258 | if (p < 0.0f) priority *= 2.0; | 201 | for (int i = 0; i < 8; i++) |
259 | 202 | { | |
260 | if (entity is SceneObjectPart) | 203 | if (distance < 10 * Math.Pow(2.0,i)) |
261 | { | 204 | break; |
262 | PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor; | 205 | pqueue++; |
263 | if (physActor == null || !physActor.IsPhysical) | 206 | } |
264 | priority += 100; | 207 | |
265 | 208 | // If this is a root agent, then determine front & back | |
266 | if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment) | 209 | // Bump up the priority queue (drop the priority) for any objects behind the avatar |
267 | priority = 1.0; | 210 | if (useFrontBack && ! presence.IsChildAgent) |
268 | } | 211 | { |
269 | return priority; | 212 | // Root agent, decrease priority for objects behind us |
270 | } | 213 | Vector3 camPosition = presence.CameraPosition; |
271 | else | 214 | Vector3 camAtAxis = presence.CameraAtAxis; |
272 | { | 215 | |
273 | // Child agent. Use the normal distance method | 216 | // Plane equation |
274 | Vector3 presencePos = presence.AbsolutePosition; | 217 | float d = -Vector3.Dot(camPosition, camAtAxis); |
275 | 218 | float p = Vector3.Dot(camAtAxis, entityPos) + d; | |
276 | return Vector3.DistanceSquared(presencePos, entityPos); | 219 | if (p < 0.0f) |
277 | } | 220 | pqueue++; |
278 | } | 221 | } |
279 | 222 | ||
280 | return double.NaN; | 223 | return pqueue; |
281 | } | 224 | } |
225 | |||
282 | } | 226 | } |
283 | } | 227 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 73dd531..0f85925 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -1955,11 +1955,49 @@ namespace OpenSim.Region.Framework.Scenes | |||
1955 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, | 1955 | UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, |
1956 | bool RezSelected, bool RemoveItem, UUID fromTaskID) | 1956 | bool RezSelected, bool RemoveItem, UUID fromTaskID) |
1957 | { | 1957 | { |
1958 | IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); | 1958 | // m_log.DebugFormat( |
1959 | if (invAccess != null) | 1959 | // "[PRIM INVENTORY]: RezObject from {0} for item {1} from task id {2}", |
1960 | invAccess.RezObject( | 1960 | // remoteClient.Name, itemID, fromTaskID); |
1961 | remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, | 1961 | |
1962 | RezSelected, RemoveItem, fromTaskID, false); | 1962 | if (fromTaskID == UUID.Zero) |
1963 | { | ||
1964 | IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>(); | ||
1965 | if (invAccess != null) | ||
1966 | invAccess.RezObject( | ||
1967 | remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, | ||
1968 | RezSelected, RemoveItem, fromTaskID, false); | ||
1969 | } | ||
1970 | else | ||
1971 | { | ||
1972 | SceneObjectPart part = GetSceneObjectPart(fromTaskID); | ||
1973 | if (part == null) | ||
1974 | { | ||
1975 | m_log.ErrorFormat( | ||
1976 | "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such scene object", | ||
1977 | remoteClient.Name, itemID, fromTaskID); | ||
1978 | |||
1979 | return; | ||
1980 | } | ||
1981 | |||
1982 | TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID); | ||
1983 | if (item == null) | ||
1984 | { | ||
1985 | m_log.ErrorFormat( | ||
1986 | "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such item", | ||
1987 | remoteClient.Name, itemID, fromTaskID); | ||
1988 | |||
1989 | return; | ||
1990 | } | ||
1991 | |||
1992 | byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); | ||
1993 | Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f); | ||
1994 | Vector3 pos | ||
1995 | = GetNewRezLocation( | ||
1996 | RayStart, RayEnd, RayTargetID, Quaternion.Identity, | ||
1997 | BypassRayCast, bRayEndIsIntersection, true, scale, false); | ||
1998 | |||
1999 | RezObject(part, item, pos, null, Vector3.Zero, 0); | ||
2000 | } | ||
1963 | } | 2001 | } |
1964 | 2002 | ||
1965 | /// <summary> | 2003 | /// <summary> |
@@ -1967,14 +2005,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1967 | /// </summary> | 2005 | /// </summary> |
1968 | /// <param name="sourcePart"></param> | 2006 | /// <param name="sourcePart"></param> |
1969 | /// <param name="item"></param> | 2007 | /// <param name="item"></param> |
1970 | /// <param name="pos"></param> | 2008 | /// <param name="pos">The position of the rezzed object.</param> |
1971 | /// <param name="rot"></param> | 2009 | /// <param name="rot">The rotation of the rezzed object. If null, then the rotation stored with the object |
1972 | /// <param name="vel"></param> | 2010 | /// will be used if it exists.</param> |
2011 | /// <param name="vel">The velocity of the rezzed object.</param> | ||
1973 | /// <param name="param"></param> | 2012 | /// <param name="param"></param> |
1974 | /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful</returns> | 2013 | /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful</returns> |
1975 | public virtual SceneObjectGroup RezObject( | 2014 | public virtual SceneObjectGroup RezObject( |
1976 | SceneObjectPart sourcePart, TaskInventoryItem item, | 2015 | SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param) |
1977 | Vector3 pos, Quaternion rot, Vector3 vel, int param) | ||
1978 | { | 2016 | { |
1979 | if (null == item) | 2017 | if (null == item) |
1980 | return null; | 2018 | return null; |
@@ -1992,8 +2030,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1992 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) | 2030 | if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) |
1993 | sourcePart.Inventory.RemoveInventoryItem(item.ItemID); | 2031 | sourcePart.Inventory.RemoveInventoryItem(item.ItemID); |
1994 | } | 2032 | } |
1995 | 2033 | ||
1996 | AddNewSceneObject(group, true, pos, rot, vel); | 2034 | AddNewSceneObject(group, true); |
2035 | |||
2036 | group.AbsolutePosition = pos; | ||
2037 | group.Velocity = vel; | ||
2038 | |||
2039 | if (rot != null) | ||
2040 | group.UpdateGroupRotationR((Quaternion)rot); | ||
1997 | 2041 | ||
1998 | // We can only call this after adding the scene object, since the scene object references the scene | 2042 | // We can only call this after adding the scene object, since the scene object references the scene |
1999 | // to find out if scripts should be activated at all. | 2043 | // to find out if scripts should be activated at all. |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f0acc38..01de824 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -3665,6 +3665,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
3665 | return false; | 3665 | return false; |
3666 | } | 3666 | } |
3667 | 3667 | ||
3668 | int num = m_sceneGraph.GetNumberOfScenePresences(); | ||
3669 | |||
3670 | if (num >= RegionInfo.RegionSettings.AgentLimit) | ||
3671 | { | ||
3672 | if (!Permissions.IsAdministrator(cAgentData.AgentID)) | ||
3673 | return false; | ||
3674 | } | ||
3675 | |||
3676 | |||
3668 | ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); | 3677 | ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); |
3669 | 3678 | ||
3670 | if (childAgentUpdate != null) | 3679 | if (childAgentUpdate != null) |
@@ -4839,7 +4848,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
4839 | } | 4848 | } |
4840 | } | 4849 | } |
4841 | 4850 | ||
4842 | public Vector3[] GetCombinedBoundingBox(List<SceneObjectGroup> objects, out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) | 4851 | /// <summary> |
4852 | /// Get the volume of space that will encompass all the given objects. | ||
4853 | /// </summary> | ||
4854 | /// <param name="objects"></param> | ||
4855 | /// <param name="minX"></param> | ||
4856 | /// <param name="maxX"></param> | ||
4857 | /// <param name="minY"></param> | ||
4858 | /// <param name="maxY"></param> | ||
4859 | /// <param name="minZ"></param> | ||
4860 | /// <param name="maxZ"></param> | ||
4861 | /// <returns></returns> | ||
4862 | public static Vector3[] GetCombinedBoundingBox( | ||
4863 | List<SceneObjectGroup> objects, | ||
4864 | out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) | ||
4843 | { | 4865 | { |
4844 | minX = 256; | 4866 | minX = 256; |
4845 | maxX = -256; | 4867 | maxX = -256; |
@@ -4857,6 +4879,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
4857 | Vector3 vec = g.AbsolutePosition; | 4879 | Vector3 vec = g.AbsolutePosition; |
4858 | 4880 | ||
4859 | g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); | 4881 | g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); |
4882 | |||
4883 | // m_log.DebugFormat( | ||
4884 | // "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}", | ||
4885 | // g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ)); | ||
4860 | 4886 | ||
4861 | ominX += vec.X; | 4887 | ominX += vec.X; |
4862 | omaxX += vec.X; | 4888 | omaxX += vec.X; |
@@ -4949,6 +4975,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
4949 | // child agent creation, thereby emulating the SL behavior. | 4975 | // child agent creation, thereby emulating the SL behavior. |
4950 | public bool QueryAccess(UUID agentID, Vector3 position, out string reason) | 4976 | public bool QueryAccess(UUID agentID, Vector3 position, out string reason) |
4951 | { | 4977 | { |
4978 | int num = m_sceneGraph.GetNumberOfScenePresences(); | ||
4979 | |||
4980 | if (num >= RegionInfo.RegionSettings.AgentLimit) | ||
4981 | { | ||
4982 | if (!Permissions.IsAdministrator(agentID)) | ||
4983 | { | ||
4984 | reason = "The region is full"; | ||
4985 | return false; | ||
4986 | } | ||
4987 | } | ||
4988 | |||
4952 | reason = String.Empty; | 4989 | reason = String.Empty; |
4953 | return true; | 4990 | return true; |
4954 | } | 4991 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 97af0a0..fc31b65 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -800,6 +800,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
800 | return m_scenePresenceArray; | 800 | return m_scenePresenceArray; |
801 | } | 801 | } |
802 | 802 | ||
803 | public int GetNumberOfScenePresences() | ||
804 | { | ||
805 | return m_scenePresenceArray.Count; | ||
806 | } | ||
807 | |||
803 | /// <summary> | 808 | /// <summary> |
804 | /// Request a scene presence by UUID. Fast, indexed lookup. | 809 | /// Request a scene presence by UUID. Fast, indexed lookup. |
805 | /// </summary> | 810 | /// </summary> |
@@ -997,6 +1002,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
997 | { | 1002 | { |
998 | foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts) | 1003 | foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts) |
999 | { | 1004 | { |
1005 | // m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name); | ||
1006 | |||
1000 | if (p.Name == name) | 1007 | if (p.Name == name) |
1001 | { | 1008 | { |
1002 | sop = p; | 1009 | sop = p; |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index e8095c0..4bca3d0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs | |||
@@ -81,16 +81,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
81 | } | 81 | } |
82 | 82 | ||
83 | /// <summary> | 83 | /// <summary> |
84 | /// Add an inventory item to a prim in this group. | 84 | /// Add an inventory item from a user's inventory to a prim in this scene object. |
85 | /// </summary> | 85 | /// </summary> |
86 | /// <param name="remoteClient"></param> | 86 | /// <param name="remoteClient">The client adding the item.</param> |
87 | /// <param name="localID"></param> | 87 | /// <param name="localID">The local ID of the part receiving the add.</param> |
88 | /// <param name="item"></param> | 88 | /// <param name="item">The user inventory item being added.</param> |
89 | /// <param name="copyItemID">The item UUID that should be used by the new item.</param> | 89 | /// <param name="copyItemID">The item UUID that should be used by the new item.</param> |
90 | /// <returns></returns> | 90 | /// <returns></returns> |
91 | public bool AddInventoryItem(IClientAPI remoteClient, uint localID, | 91 | public bool AddInventoryItem(IClientAPI remoteClient, uint localID, |
92 | InventoryItemBase item, UUID copyItemID) | 92 | InventoryItemBase item, UUID copyItemID) |
93 | { | 93 | { |
94 | // m_log.DebugFormat( | ||
95 | // "[PRIM INVENTORY]: Adding inventory item {0} from {1} to part with local ID {2}", | ||
96 | // item.Name, remoteClient.Name, localID); | ||
97 | |||
94 | UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID; | 98 | UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID; |
95 | 99 | ||
96 | SceneObjectPart part = GetChildPart(localID); | 100 | SceneObjectPart part = GetChildPart(localID); |
@@ -132,15 +136,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
132 | taskItem.GroupPermissions = item.GroupPermissions; | 136 | taskItem.GroupPermissions = item.GroupPermissions; |
133 | taskItem.NextPermissions = item.NextPermissions; | 137 | taskItem.NextPermissions = item.NextPermissions; |
134 | } | 138 | } |
135 | 139 | ||
136 | taskItem.Flags = item.Flags; | 140 | taskItem.Flags = item.Flags; |
141 | |||
142 | // m_log.DebugFormat( | ||
143 | // "[PRIM INVENTORY]: Flags are 0x{0:X} for item {1} added to part {2} by {3}", | ||
144 | // taskItem.Flags, taskItem.Name, localID, remoteClient.Name); | ||
145 | |||
137 | // TODO: These are pending addition of those fields to TaskInventoryItem | 146 | // TODO: These are pending addition of those fields to TaskInventoryItem |
138 | // taskItem.SalePrice = item.SalePrice; | 147 | // taskItem.SalePrice = item.SalePrice; |
139 | // taskItem.SaleType = item.SaleType; | 148 | // taskItem.SaleType = item.SaleType; |
140 | taskItem.CreationDate = (uint)item.CreationDate; | 149 | taskItem.CreationDate = (uint)item.CreationDate; |
141 | 150 | ||
142 | bool addFromAllowedDrop = false; | 151 | bool addFromAllowedDrop = false; |
143 | if (remoteClient!=null) | 152 | if (remoteClient != null) |
144 | { | 153 | { |
145 | addFromAllowedDrop = remoteClient.AgentId != part.OwnerID; | 154 | addFromAllowedDrop = remoteClient.AgentId != part.OwnerID; |
146 | } | 155 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ca7d9d9..19a9506 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -296,11 +296,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
296 | { | 296 | { |
297 | Vector3 val = value; | 297 | Vector3 val = value; |
298 | 298 | ||
299 | if ((m_scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || m_scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) | 299 | if (Scene != null) |
300 | || m_scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || m_scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) | ||
301 | && !IsAttachmentCheckFull() && (!m_scene.LoadingPrims)) | ||
302 | { | 300 | { |
303 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | 301 | if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) |
302 | || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) | ||
303 | && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) | ||
304 | { | ||
305 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | ||
306 | } | ||
304 | } | 307 | } |
305 | 308 | ||
306 | if (RootPart.GetStatusSandbox()) | 309 | if (RootPart.GetStatusSandbox()) |
@@ -308,8 +311,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
308 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) | 311 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) |
309 | { | 312 | { |
310 | RootPart.ScriptSetPhysicsStatus(false); | 313 | RootPart.ScriptSetPhysicsStatus(false); |
311 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), | 314 | |
312 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); | 315 | if (Scene != null) |
316 | Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"), | ||
317 | ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false); | ||
318 | |||
313 | return; | 319 | return; |
314 | } | 320 | } |
315 | } | 321 | } |
@@ -326,7 +332,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
326 | //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); | 332 | //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); |
327 | //} | 333 | //} |
328 | 334 | ||
329 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | 335 | if (Scene != null) |
336 | Scene.EventManager.TriggerParcelPrimCountTainted(); | ||
330 | } | 337 | } |
331 | } | 338 | } |
332 | 339 | ||
@@ -1765,10 +1772,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1765 | /// <param name="part"></param> | 1772 | /// <param name="part"></param> |
1766 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) | 1773 | public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) |
1767 | { | 1774 | { |
1768 | remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, | 1775 | remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); |
1769 | RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, | 1776 | |
1770 | RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | 1777 | // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, |
1771 | RootPart.CreatorID, RootPart.Name, RootPart.Description); | 1778 | // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, |
1779 | // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, | ||
1780 | // RootPart.CreatorID, RootPart.Name, RootPart.Description); | ||
1772 | } | 1781 | } |
1773 | 1782 | ||
1774 | public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) | 1783 | public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4d5eedf..8a8a699 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -2055,15 +2055,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2055 | 2055 | ||
2056 | public void GetProperties(IClientAPI client) | 2056 | public void GetProperties(IClientAPI client) |
2057 | { | 2057 | { |
2058 | //Viewer wants date in microseconds so multiply it by 1,000,000. | 2058 | client.SendObjectPropertiesReply(this); |
2059 | client.SendObjectPropertiesReply( | ||
2060 | m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero, | ||
2061 | _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, | ||
2062 | ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, | ||
2063 | ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, | ||
2064 | ParentGroup.RootPart._baseMask, | ||
2065 | ParentGroup.RootPart.ObjectSaleType, | ||
2066 | ParentGroup.RootPart.SalePrice); | ||
2067 | } | 2059 | } |
2068 | 2060 | ||
2069 | public UUID GetRootPartUUID() | 2061 | public UUID GetRootPartUUID() |
@@ -2088,7 +2080,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
2088 | 2080 | ||
2089 | axPos *= parentRot; | 2081 | axPos *= parentRot; |
2090 | Vector3 translationOffsetPosition = axPos; | 2082 | Vector3 translationOffsetPosition = axPos; |
2091 | return GroupPosition + translationOffsetPosition; | 2083 | |
2084 | // m_log.DebugFormat("[SCENE OBJECT PART]: Found group pos {0} for part {1}", GroupPosition, Name); | ||
2085 | |||
2086 | Vector3 worldPos = GroupPosition + translationOffsetPosition; | ||
2087 | |||
2088 | // m_log.DebugFormat("[SCENE OBJECT PART]: Found world pos {0} for part {1}", worldPos, Name); | ||
2089 | |||
2090 | return worldPos; | ||
2092 | } | 2091 | } |
2093 | 2092 | ||
2094 | /// <summary> | 2093 | /// <summary> |
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs new file mode 100644 index 0000000..55455cc --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs | |||
@@ -0,0 +1,160 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Drawing; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Xml; | ||
34 | using log4net; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | |||
40 | namespace OpenSim.Region.Framework.Scenes.Serialization | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// Serialize and deserialize coalesced scene objects. | ||
44 | /// </summary> | ||
45 | /// <remarks> | ||
46 | /// Deserialization not yet here. | ||
47 | /// </remarks> | ||
48 | public class CoalescedSceneObjectsSerializer | ||
49 | { | ||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | /// <summary> | ||
53 | /// Serialize coalesced objects to Xml | ||
54 | /// </summary> | ||
55 | /// <param name="coa"></param> | ||
56 | /// <returns></returns> | ||
57 | public static string ToXml(CoalescedSceneObjects coa) | ||
58 | { | ||
59 | using (StringWriter sw = new StringWriter()) | ||
60 | { | ||
61 | using (XmlTextWriter writer = new XmlTextWriter(sw)) | ||
62 | { | ||
63 | Vector3 size; | ||
64 | |||
65 | List<SceneObjectGroup> coaObjects = coa.Objects; | ||
66 | |||
67 | // m_log.DebugFormat( | ||
68 | // "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", | ||
69 | // coaObjects.Count); | ||
70 | |||
71 | // This is weak - we're relying on the set of coalesced objects still being identical | ||
72 | Vector3[] offsets = coa.GetSizeAndOffsets(out size); | ||
73 | |||
74 | writer.WriteStartElement("CoalescedObject"); | ||
75 | |||
76 | writer.WriteAttributeString("x", size.X.ToString()); | ||
77 | writer.WriteAttributeString("y", size.Y.ToString()); | ||
78 | writer.WriteAttributeString("z", size.Z.ToString()); | ||
79 | |||
80 | // Embed the offsets into the group XML | ||
81 | for (int i = 0; i < coaObjects.Count; i++) | ||
82 | { | ||
83 | SceneObjectGroup obj = coaObjects[i]; | ||
84 | |||
85 | // m_log.DebugFormat( | ||
86 | // "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}", | ||
87 | // i, obj.Name); | ||
88 | |||
89 | writer.WriteStartElement("SceneObjectGroup"); | ||
90 | writer.WriteAttributeString("offsetx", offsets[i].X.ToString()); | ||
91 | writer.WriteAttributeString("offsety", offsets[i].Y.ToString()); | ||
92 | writer.WriteAttributeString("offsetz", offsets[i].Z.ToString()); | ||
93 | |||
94 | SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); | ||
95 | |||
96 | writer.WriteEndElement(); // SceneObjectGroup | ||
97 | } | ||
98 | |||
99 | writer.WriteEndElement(); // CoalescedObject | ||
100 | } | ||
101 | |||
102 | string output = sw.ToString(); | ||
103 | |||
104 | // Console.WriteLine(output); | ||
105 | |||
106 | return output; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | public static bool TryFromXml(string xml, out CoalescedSceneObjects coa) | ||
111 | { | ||
112 | // m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); | ||
113 | |||
114 | coa = null; | ||
115 | |||
116 | using (StringReader sr = new StringReader(xml)) | ||
117 | { | ||
118 | using (XmlTextReader reader = new XmlTextReader(sr)) | ||
119 | { | ||
120 | try | ||
121 | { | ||
122 | reader.Read(); | ||
123 | if (reader.Name != "CoalescedObject") | ||
124 | { | ||
125 | // m_log.DebugFormat( | ||
126 | // "[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() root element was {0} so returning false", | ||
127 | // reader.Name); | ||
128 | |||
129 | return false; | ||
130 | } | ||
131 | |||
132 | coa = new CoalescedSceneObjects(UUID.Zero); | ||
133 | reader.Read(); | ||
134 | |||
135 | while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject") | ||
136 | { | ||
137 | if (reader.Name == "SceneObjectGroup") | ||
138 | { | ||
139 | string soXml = reader.ReadOuterXml(); | ||
140 | coa.Add(SceneObjectSerializer.FromOriginalXmlFormat(soXml)); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | reader.ReadEndElement(); // CoalescedObject | ||
145 | } | ||
146 | catch (Exception e) | ||
147 | { | ||
148 | m_log.ErrorFormat( | ||
149 | "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}", | ||
150 | e.Message, e.StackTrace); | ||
151 | |||
152 | return false; | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return true; | ||
158 | } | ||
159 | } | ||
160 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 57ae4fd..bb8a83a 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs | |||
@@ -139,6 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
139 | return sw.ToString(); | 139 | return sw.ToString(); |
140 | } | 140 | } |
141 | } | 141 | } |
142 | |||
142 | 143 | ||
143 | /// <summary> | 144 | /// <summary> |
144 | /// Serialize a scene object to the original xml format | 145 | /// Serialize a scene object to the original xml format |
@@ -147,10 +148,24 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
147 | /// <returns></returns> | 148 | /// <returns></returns> |
148 | public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer) | 149 | public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer) |
149 | { | 150 | { |
151 | ToOriginalXmlFormat(sceneObject, writer, false); | ||
152 | } | ||
153 | |||
154 | /// <summary> | ||
155 | /// Serialize a scene object to the original xml format | ||
156 | /// </summary> | ||
157 | /// <param name="sceneObject"></param> | ||
158 | /// <param name="writer"></param> | ||
159 | /// <param name="noRootElement">If false, don't write the enclosing SceneObjectGroup element</param> | ||
160 | /// <returns></returns> | ||
161 | public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer, bool noRootElement) | ||
162 | { | ||
150 | //m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", Name); | 163 | //m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", Name); |
151 | //int time = System.Environment.TickCount; | 164 | //int time = System.Environment.TickCount; |
152 | 165 | ||
153 | writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); | 166 | if (!noRootElement) |
167 | writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); | ||
168 | |||
154 | writer.WriteStartElement(String.Empty, "RootPart", String.Empty); | 169 | writer.WriteStartElement(String.Empty, "RootPart", String.Empty); |
155 | ToXmlFormat(sceneObject.RootPart, writer); | 170 | ToXmlFormat(sceneObject.RootPart, writer); |
156 | writer.WriteEndElement(); | 171 | writer.WriteEndElement(); |
@@ -170,10 +185,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
170 | 185 | ||
171 | writer.WriteEndElement(); // OtherParts | 186 | writer.WriteEndElement(); // OtherParts |
172 | sceneObject.SaveScriptedState(writer); | 187 | sceneObject.SaveScriptedState(writer); |
173 | writer.WriteEndElement(); // SceneObjectGroup | 188 | |
189 | if (!noRootElement) | ||
190 | writer.WriteEndElement(); // SceneObjectGroup | ||
174 | 191 | ||
175 | //m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); | 192 | //m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); |
176 | } | 193 | } |
177 | 194 | ||
178 | protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer) | 195 | protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer) |
179 | { | 196 | { |
@@ -1318,7 +1335,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization | |||
1318 | writer.WriteStartElement("SculptData"); | 1335 | writer.WriteStartElement("SculptData"); |
1319 | byte[] sd; | 1336 | byte[] sd; |
1320 | if (shp.SculptData != null) | 1337 | if (shp.SculptData != null) |
1321 | sd = shp.ExtraParams; | 1338 | sd = shp.SculptData; |
1322 | else | 1339 | else |
1323 | sd = Utils.EmptyBytes; | 1340 | sd = Utils.EmptyBytes; |
1324 | writer.WriteBase64(sd, 0, sd.Length); | 1341 | writer.WriteBase64(sd, 0, sd.Length); |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs index 8588f7f..dd28416 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs | |||
@@ -117,11 +117,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
117 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); | 117 | ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); |
118 | 118 | ||
119 | 119 | ||
120 | Scene sceneB = SceneSetupHelpers.SetupScene("sceneB", sceneBId, 1010, 1010, "grid"); | 120 | Scene sceneB = SceneSetupHelpers.SetupScene("sceneB", sceneBId, 1010, 1010); |
121 | SceneSetupHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms); | 121 | SceneSetupHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms); |
122 | sceneB.RegisterRegionWithGrid(); | 122 | sceneB.RegisterRegionWithGrid(); |
123 | 123 | ||
124 | Scene sceneA = SceneSetupHelpers.SetupScene("sceneA", sceneAId, 1000, 1000, "grid"); | 124 | Scene sceneA = SceneSetupHelpers.SetupScene("sceneA", sceneAId, 1000, 1000); |
125 | SceneSetupHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms); | 125 | SceneSetupHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms); |
126 | sceneA.RegisterRegionWithGrid(); | 126 | sceneA.RegisterRegionWithGrid(); |
127 | 127 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index 8138bcc..2aef4b0 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs | |||
@@ -101,7 +101,7 @@ namespace OpenSim.Region.Framework.Tests | |||
101 | TestHelper.InMethod(); | 101 | TestHelper.InMethod(); |
102 | // log4net.Config.XmlConfigurator.Configure(); | 102 | // log4net.Config.XmlConfigurator.Configure(); |
103 | 103 | ||
104 | Scene scene = SceneSetupHelpers.SetupScene("inventory"); | 104 | Scene scene = SceneSetupHelpers.SetupScene(); |
105 | UserAccount user1 = CreateUser(scene); | 105 | UserAccount user1 = CreateUser(scene); |
106 | SceneObjectGroup sog1 = CreateSO1(scene, user1.PrincipalID); | 106 | SceneObjectGroup sog1 = CreateSO1(scene, user1.PrincipalID); |
107 | SceneObjectPart sop1 = sog1.RootPart; | 107 | SceneObjectPart sop1 = sog1.RootPart; |
@@ -127,7 +127,7 @@ namespace OpenSim.Region.Framework.Tests | |||
127 | TestHelper.InMethod(); | 127 | TestHelper.InMethod(); |
128 | // log4net.Config.XmlConfigurator.Configure(); | 128 | // log4net.Config.XmlConfigurator.Configure(); |
129 | 129 | ||
130 | Scene scene = SceneSetupHelpers.SetupScene("inventory"); | 130 | Scene scene = SceneSetupHelpers.SetupScene(); |
131 | UserAccount user1 = CreateUser(scene); | 131 | UserAccount user1 = CreateUser(scene); |
132 | SceneObjectGroup sog1 = CreateSO1(scene, user1.PrincipalID); | 132 | SceneObjectGroup sog1 = CreateSO1(scene, user1.PrincipalID); |
133 | SceneObjectPart sop1 = sog1.RootPart; | 133 | SceneObjectPart sop1 = sog1.RootPart; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index 6b70865..dbf9e0f 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs | |||
@@ -47,7 +47,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
47 | [SetUp] | 47 | [SetUp] |
48 | public void Init() | 48 | public void Init() |
49 | { | 49 | { |
50 | m_assetService = new MockAssetService(); | 50 | // FIXME: We don't need a full scene here - it would be enough to set up the asset service. |
51 | Scene scene = SceneSetupHelpers.SetupScene(); | ||
52 | m_assetService = scene.AssetService; | ||
51 | m_uuidGatherer = new UuidGatherer(m_assetService); | 53 | m_uuidGatherer = new UuidGatherer(m_assetService); |
52 | } | 54 | } |
53 | 55 | ||
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 83906d7..77b1535 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs | |||
@@ -298,10 +298,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
298 | if (null != objectAsset) | 298 | if (null != objectAsset) |
299 | { | 299 | { |
300 | string xml = Utils.BytesToString(objectAsset.Data); | 300 | string xml = Utils.BytesToString(objectAsset.Data); |
301 | SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); | 301 | |
302 | 302 | CoalescedSceneObjects coa; | |
303 | if (null != sog) | 303 | if (CoalescedSceneObjectsSerializer.TryFromXml(xml, out coa)) |
304 | GatherAssetUuids(sog, assetUuids); | 304 | { |
305 | foreach (SceneObjectGroup sog in coa.Objects) | ||
306 | GatherAssetUuids(sog, assetUuids); | ||
307 | } | ||
308 | else | ||
309 | { | ||
310 | SceneObjectGroup sog = SceneObjectSerializer.FromOriginalXmlFormat(xml); | ||
311 | |||
312 | if (null != sog) | ||
313 | GatherAssetUuids(sog, assetUuids); | ||
314 | } | ||
305 | } | 315 | } |
306 | } | 316 | } |
307 | 317 | ||