diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 356 |
1 files changed, 262 insertions, 94 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 97a1be6..3e1cb02 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -46,7 +46,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
46 | { | 46 | { |
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
48 | 48 | ||
49 | protected Scene m_scene = null; | 49 | private Scene m_scene = null; |
50 | private IDialogModule m_dialogModule; | ||
50 | 51 | ||
51 | public string Name { get { return "Attachments Module"; } } | 52 | public string Name { get { return "Attachments Module"; } } |
52 | public Type ReplaceableInterface { get { return null; } } | 53 | public Type ReplaceableInterface { get { return null; } } |
@@ -56,6 +57,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
56 | public void AddRegion(Scene scene) | 57 | public void AddRegion(Scene scene) |
57 | { | 58 | { |
58 | m_scene = scene; | 59 | m_scene = scene; |
60 | m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>(); | ||
59 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); | 61 | m_scene.RegisterModuleInterface<IAttachmentsModule>(this); |
60 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; | 62 | m_scene.EventManager.OnNewClient += SubscribeToClientEvents; |
61 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI | 63 | // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI |
@@ -80,7 +82,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
80 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; | 82 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; |
81 | client.OnObjectAttach += AttachObject; | 83 | client.OnObjectAttach += AttachObject; |
82 | client.OnObjectDetach += DetachObject; | 84 | client.OnObjectDetach += DetachObject; |
83 | client.OnDetachAttachmentIntoInv += ShowDetachInUserInventory; | 85 | client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv; |
84 | } | 86 | } |
85 | 87 | ||
86 | public void UnsubscribeFromClientEvents(IClientAPI client) | 88 | public void UnsubscribeFromClientEvents(IClientAPI client) |
@@ -89,7 +91,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
89 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; | 91 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; |
90 | client.OnObjectAttach -= AttachObject; | 92 | client.OnObjectAttach -= AttachObject; |
91 | client.OnObjectDetach -= DetachObject; | 93 | client.OnObjectDetach -= DetachObject; |
92 | client.OnDetachAttachmentIntoInv -= ShowDetachInUserInventory; | 94 | client.OnDetachAttachmentIntoInv -= DetachSingleAttachmentToInv; |
93 | } | 95 | } |
94 | 96 | ||
95 | /// <summary> | 97 | /// <summary> |
@@ -101,10 +103,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
101 | /// <param name="silent"></param> | 103 | /// <param name="silent"></param> |
102 | public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) | 104 | public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) |
103 | { | 105 | { |
104 | // m_log.Debug("[ATTACHMENTS MODULE]: Invoking AttachObject"); | 106 | // m_log.DebugFormat( |
107 | // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", | ||
108 | // objectLocalID, remoteClient.Name, AttachmentPt, silent); | ||
105 | 109 | ||
106 | try | 110 | try |
107 | { | 111 | { |
112 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
113 | |||
114 | if (sp == null) | ||
115 | { | ||
116 | m_log.ErrorFormat( | ||
117 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); | ||
118 | return; | ||
119 | } | ||
120 | |||
108 | // If we can't take it, we can't attach it! | 121 | // If we can't take it, we can't attach it! |
109 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); | 122 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); |
110 | if (part == null) | 123 | if (part == null) |
@@ -123,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
123 | AttachmentPt &= 0x7f; | 136 | AttachmentPt &= 0x7f; |
124 | 137 | ||
125 | // Calls attach with a Zero position | 138 | // Calls attach with a Zero position |
126 | if (AttachObject(remoteClient, part.ParentGroup, AttachmentPt, false)) | 139 | if (AttachObject(sp, part.ParentGroup, AttachmentPt, false)) |
127 | { | 140 | { |
128 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | 141 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); |
129 | 142 | ||
@@ -136,12 +149,39 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
136 | } | 149 | } |
137 | catch (Exception e) | 150 | catch (Exception e) |
138 | { | 151 | { |
139 | m_log.DebugFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}", e); | 152 | m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace); |
140 | } | 153 | } |
141 | } | 154 | } |
142 | 155 | ||
143 | public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) | 156 | public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) |
144 | { | 157 | { |
158 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
159 | |||
160 | if (sp == null) | ||
161 | { | ||
162 | m_log.ErrorFormat( | ||
163 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId); | ||
164 | return false; | ||
165 | } | ||
166 | |||
167 | return AttachObject(sp, group, AttachmentPt, silent); | ||
168 | } | ||
169 | |||
170 | private bool AttachObject(ScenePresence sp, SceneObjectGroup group, uint AttachmentPt, bool silent) | ||
171 | { | ||
172 | // m_log.DebugFormat( | ||
173 | // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", | ||
174 | // group.Name, group.LocalId, sp.Name, AttachmentPt, silent); | ||
175 | |||
176 | if (sp.GetAttachments(AttachmentPt).Contains(group)) | ||
177 | { | ||
178 | // m_log.WarnFormat( | ||
179 | // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", | ||
180 | // group.Name, group.LocalId, sp.Name, AttachmentPt); | ||
181 | |||
182 | return false; | ||
183 | } | ||
184 | |||
145 | Vector3 attachPos = group.AbsolutePosition; | 185 | Vector3 attachPos = group.AbsolutePosition; |
146 | 186 | ||
147 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | 187 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should |
@@ -175,32 +215,24 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
175 | group.AbsolutePosition = attachPos; | 215 | group.AbsolutePosition = attachPos; |
176 | 216 | ||
177 | // Remove any previous attachments | 217 | // Remove any previous attachments |
178 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
179 | UUID itemID = UUID.Zero; | 218 | UUID itemID = UUID.Zero; |
180 | if (sp != null) | 219 | foreach (SceneObjectGroup grp in sp.Attachments) |
181 | { | 220 | { |
182 | foreach (SceneObjectGroup grp in sp.Attachments) | 221 | if (grp.GetAttachmentPoint() == (byte)AttachmentPt) |
183 | { | 222 | { |
184 | if (grp.GetAttachmentPoint() == (byte)AttachmentPt) | 223 | itemID = grp.GetFromItemID(); |
185 | { | 224 | break; |
186 | itemID = grp.GetFromItemID(); | ||
187 | break; | ||
188 | } | ||
189 | } | 225 | } |
190 | if (itemID != UUID.Zero) | ||
191 | DetachSingleAttachmentToInv(itemID, remoteClient); | ||
192 | } | 226 | } |
193 | 227 | ||
194 | if (group.GetFromItemID() == UUID.Zero) | 228 | if (itemID != UUID.Zero) |
195 | { | 229 | DetachSingleAttachmentToInv(itemID, sp); |
196 | m_scene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemID); | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | itemID = group.GetFromItemID(); | ||
201 | } | ||
202 | 230 | ||
203 | ShowAttachInUserInventory(remoteClient, AttachmentPt, itemID, group); | 231 | itemID = group.GetFromItemID(); |
232 | if (itemID == UUID.Zero) | ||
233 | itemID = AddSceneObjectAsAttachment(sp.ControllingClient, group).ID; | ||
234 | |||
235 | ShowAttachInUserInventory(sp, AttachmentPt, itemID, group); | ||
204 | 236 | ||
205 | AttachToAgent(sp, group, AttachmentPt, attachPos, silent); | 237 | AttachToAgent(sp, group, AttachmentPt, attachPos, silent); |
206 | 238 | ||
@@ -229,19 +261,29 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
229 | // m_log.DebugFormat( | 261 | // m_log.DebugFormat( |
230 | // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", | 262 | // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", |
231 | // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); | 263 | // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); |
264 | |||
265 | ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); | ||
266 | |||
267 | if (sp == null) | ||
268 | { | ||
269 | m_log.ErrorFormat( | ||
270 | "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", | ||
271 | remoteClient.Name, remoteClient.AgentId); | ||
272 | return UUID.Zero; | ||
273 | } | ||
232 | 274 | ||
233 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should | 275 | // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should |
234 | // be removed when that functionality is implemented in opensim | 276 | // be removed when that functionality is implemented in opensim |
235 | AttachmentPt &= 0x7f; | 277 | AttachmentPt &= 0x7f; |
236 | 278 | ||
237 | SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt); | 279 | SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, AttachmentPt); |
238 | 280 | ||
239 | if (updateInventoryStatus) | 281 | if (updateInventoryStatus) |
240 | { | 282 | { |
241 | if (att == null) | 283 | if (att == null) |
242 | ShowDetachInUserInventory(itemID, remoteClient); | 284 | DetachSingleAttachmentToInv(itemID, sp.ControllingClient); |
243 | else | 285 | else |
244 | ShowAttachInUserInventory(att, remoteClient, itemID, AttachmentPt); | 286 | ShowAttachInUserInventory(att, sp, itemID, AttachmentPt); |
245 | } | 287 | } |
246 | 288 | ||
247 | if (null == att) | 289 | if (null == att) |
@@ -250,15 +292,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
250 | return att.UUID; | 292 | return att.UUID; |
251 | } | 293 | } |
252 | 294 | ||
253 | protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( | 295 | private SceneObjectGroup RezSingleAttachmentFromInventoryInternal( |
254 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | 296 | ScenePresence sp, UUID itemID, uint AttachmentPt) |
255 | { | 297 | { |
256 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | 298 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); |
257 | if (invAccess != null) | 299 | if (invAccess != null) |
258 | { | 300 | { |
259 | SceneObjectGroup objatt = invAccess.RezObject(remoteClient, | 301 | SceneObjectGroup objatt = invAccess.RezObject(sp.ControllingClient, |
260 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | 302 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, |
261 | false, false, remoteClient.AgentId, true); | 303 | false, false, sp.UUID, true); |
262 | 304 | ||
263 | // m_log.DebugFormat( | 305 | // m_log.DebugFormat( |
264 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", | 306 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", |
@@ -277,11 +319,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
277 | // This will throw if the attachment fails | 319 | // This will throw if the attachment fails |
278 | try | 320 | try |
279 | { | 321 | { |
280 | AttachObject(remoteClient, objatt, AttachmentPt, false); | 322 | AttachObject(sp, objatt, AttachmentPt, false); |
281 | } | 323 | } |
282 | catch | 324 | catch (Exception e) |
283 | { | 325 | { |
326 | m_log.ErrorFormat( | ||
327 | "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", | ||
328 | objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); | ||
329 | |||
284 | // Make sure the object doesn't stick around and bail | 330 | // Make sure the object doesn't stick around and bail |
331 | sp.RemoveAttachment(objatt); | ||
285 | m_scene.DeleteSceneObject(objatt, false); | 332 | m_scene.DeleteSceneObject(objatt, false); |
286 | return null; | 333 | return null; |
287 | } | 334 | } |
@@ -295,13 +342,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
295 | objatt.ResumeScripts(); | 342 | objatt.ResumeScripts(); |
296 | 343 | ||
297 | // Do this last so that event listeners have access to all the effects of the attachment | 344 | // Do this last so that event listeners have access to all the effects of the attachment |
298 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); | 345 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); |
299 | } | 346 | } |
300 | else | 347 | else |
301 | { | 348 | { |
302 | m_log.WarnFormat( | 349 | m_log.WarnFormat( |
303 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | 350 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", |
304 | itemID, remoteClient.Name, AttachmentPt); | 351 | itemID, sp.Name, AttachmentPt); |
305 | } | 352 | } |
306 | 353 | ||
307 | return objatt; | 354 | return objatt; |
@@ -314,12 +361,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
314 | /// Update the user inventory to the attachment of an item | 361 | /// Update the user inventory to the attachment of an item |
315 | /// </summary> | 362 | /// </summary> |
316 | /// <param name="att"></param> | 363 | /// <param name="att"></param> |
317 | /// <param name="remoteClient"></param> | 364 | /// <param name="sp"></param> |
318 | /// <param name="itemID"></param> | 365 | /// <param name="itemID"></param> |
319 | /// <param name="AttachmentPt"></param> | 366 | /// <param name="AttachmentPt"></param> |
320 | /// <returns></returns> | 367 | /// <returns></returns> |
321 | protected UUID ShowAttachInUserInventory( | 368 | private UUID ShowAttachInUserInventory( |
322 | SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | 369 | SceneObjectGroup att, ScenePresence sp, UUID itemID, uint AttachmentPt) |
323 | { | 370 | { |
324 | // m_log.DebugFormat( | 371 | // m_log.DebugFormat( |
325 | // "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})", | 372 | // "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})", |
@@ -328,16 +375,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
328 | if (!att.IsDeleted) | 375 | if (!att.IsDeleted) |
329 | AttachmentPt = att.RootPart.AttachmentPoint; | 376 | AttachmentPt = att.RootPart.AttachmentPoint; |
330 | 377 | ||
331 | ScenePresence presence; | 378 | InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); |
332 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 379 | item = m_scene.InventoryService.GetItem(item); |
333 | { | ||
334 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | ||
335 | item = m_scene.InventoryService.GetItem(item); | ||
336 | 380 | ||
337 | bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | 381 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); |
338 | if (changed && m_scene.AvatarFactory != null) | 382 | if (changed && m_scene.AvatarFactory != null) |
339 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | 383 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
340 | } | ||
341 | 384 | ||
342 | return att.UUID; | 385 | return att.UUID; |
343 | } | 386 | } |
@@ -345,12 +388,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
345 | /// <summary> | 388 | /// <summary> |
346 | /// Update the user inventory to reflect an attachment | 389 | /// Update the user inventory to reflect an attachment |
347 | /// </summary> | 390 | /// </summary> |
348 | /// <param name="remoteClient"></param> | 391 | /// <param name="sp"></param> |
349 | /// <param name="AttachmentPt"></param> | 392 | /// <param name="AttachmentPt"></param> |
350 | /// <param name="itemID"></param> | 393 | /// <param name="itemID"></param> |
351 | /// <param name="att"></param> | 394 | /// <param name="att"></param> |
352 | protected void ShowAttachInUserInventory( | 395 | private void ShowAttachInUserInventory( |
353 | IClientAPI remoteClient, uint AttachmentPt, UUID itemID, SceneObjectGroup att) | 396 | ScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) |
354 | { | 397 | { |
355 | // m_log.DebugFormat( | 398 | // m_log.DebugFormat( |
356 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", | 399 | // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", |
@@ -374,16 +417,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
374 | return; | 417 | return; |
375 | } | 418 | } |
376 | 419 | ||
377 | ScenePresence presence; | 420 | InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); |
378 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 421 | item = m_scene.InventoryService.GetItem(item); |
379 | { | 422 | bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); |
380 | // XXYY!! | 423 | if (changed && m_scene.AvatarFactory != null) |
381 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | 424 | m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); |
382 | item = m_scene.InventoryService.GetItem(item); | ||
383 | bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); | ||
384 | if (changed && m_scene.AvatarFactory != null) | ||
385 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | ||
386 | } | ||
387 | } | 425 | } |
388 | 426 | ||
389 | public void DetachObject(uint objectLocalID, IClientAPI remoteClient) | 427 | public void DetachObject(uint objectLocalID, IClientAPI remoteClient) |
@@ -391,12 +429,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
391 | SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); | 429 | SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); |
392 | if (group != null) | 430 | if (group != null) |
393 | { | 431 | { |
394 | //group.DetachToGround(); | 432 | DetachSingleAttachmentToInv(group.GetFromItemID(), remoteClient); |
395 | ShowDetachInUserInventory(group.GetFromItemID(), remoteClient); | ||
396 | } | 433 | } |
397 | } | 434 | } |
398 | 435 | ||
399 | public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient) | 436 | public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) |
400 | { | 437 | { |
401 | ScenePresence presence; | 438 | ScenePresence presence; |
402 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 439 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) |
@@ -407,34 +444,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
407 | bool changed = presence.Appearance.DetachAttachment(itemID); | 444 | bool changed = presence.Appearance.DetachAttachment(itemID); |
408 | if (changed && m_scene.AvatarFactory != null) | 445 | if (changed && m_scene.AvatarFactory != null) |
409 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | 446 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); |
410 | } | ||
411 | 447 | ||
412 | DetachSingleAttachmentToInv(itemID, remoteClient); | 448 | DetachSingleAttachmentToInv(itemID, presence); |
449 | } | ||
413 | } | 450 | } |
414 | 451 | ||
415 | public void DetachSingleAttachmentToGround(UUID itemID, IClientAPI remoteClient) | 452 | public void DetachSingleAttachmentToGround(UUID sceneObjectID, IClientAPI remoteClient) |
416 | { | 453 | { |
417 | SceneObjectPart part = m_scene.GetSceneObjectPart(itemID); | 454 | SceneObjectGroup so = m_scene.GetSceneObjectGroup(sceneObjectID); |
418 | if (part == null || part.ParentGroup == null) | 455 | |
456 | if (so == null) | ||
419 | return; | 457 | return; |
420 | 458 | ||
421 | if (part.ParentGroup.RootPart.AttachedAvatar != remoteClient.AgentId) | 459 | if (so.AttachedAvatar != remoteClient.AgentId) |
422 | return; | 460 | return; |
423 | 461 | ||
424 | UUID inventoryID = part.ParentGroup.GetFromItemID(); | 462 | UUID inventoryID = so.GetFromItemID(); |
425 | 463 | ||
426 | ScenePresence presence; | 464 | ScenePresence presence; |
427 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) | 465 | if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) |
428 | { | 466 | { |
429 | if (!m_scene.Permissions.CanRezObject( | 467 | if (!m_scene.Permissions.CanRezObject( |
430 | part.ParentGroup.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) | 468 | so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) |
431 | return; | 469 | return; |
432 | 470 | ||
433 | bool changed = presence.Appearance.DetachAttachment(itemID); | 471 | bool changed = presence.Appearance.DetachAttachment(sceneObjectID); |
434 | if (changed && m_scene.AvatarFactory != null) | 472 | if (changed && m_scene.AvatarFactory != null) |
435 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); | 473 | m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); |
436 | 474 | ||
437 | part.ParentGroup.DetachToGround(); | 475 | presence.RemoveAttachment(so); |
476 | DetachSceneObjectToGround(so, presence); | ||
438 | 477 | ||
439 | List<UUID> uuids = new List<UUID>(); | 478 | List<UUID> uuids = new List<UUID>(); |
440 | uuids.Add(inventoryID); | 479 | uuids.Add(inventoryID); |
@@ -442,12 +481,39 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
442 | remoteClient.SendRemoveInventoryItem(inventoryID); | 481 | remoteClient.SendRemoveInventoryItem(inventoryID); |
443 | } | 482 | } |
444 | 483 | ||
445 | m_scene.EventManager.TriggerOnAttach(part.ParentGroup.LocalId, itemID, UUID.Zero); | 484 | m_scene.EventManager.TriggerOnAttach(so.LocalId, sceneObjectID, UUID.Zero); |
485 | } | ||
486 | |||
487 | /// <summary> | ||
488 | /// Detach the given scene objet to the ground. | ||
489 | /// </summary> | ||
490 | /// <remarks> | ||
491 | /// The caller has to take care of all the other work in updating avatar appearance, inventory, etc. | ||
492 | /// </remarks> | ||
493 | /// <param name="so">The scene object to detach.</param> | ||
494 | /// <param name="sp">The scene presence from which the scene object is being detached.</param> | ||
495 | private void DetachSceneObjectToGround(SceneObjectGroup so, ScenePresence sp) | ||
496 | { | ||
497 | SceneObjectPart rootPart = so.RootPart; | ||
498 | |||
499 | rootPart.FromItemID = UUID.Zero; | ||
500 | so.AbsolutePosition = sp.AbsolutePosition; | ||
501 | so.AttachedAvatar = UUID.Zero; | ||
502 | rootPart.SetParentLocalId(0); | ||
503 | so.ClearPartAttachmentData(); | ||
504 | rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim); | ||
505 | so.HasGroupChanged = true; | ||
506 | rootPart.Rezzed = DateTime.Now; | ||
507 | rootPart.RemFlag(PrimFlags.TemporaryOnRez); | ||
508 | so.AttachToBackup(); | ||
509 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | ||
510 | rootPart.ScheduleFullUpdate(); | ||
511 | rootPart.ClearUndoState(); | ||
446 | } | 512 | } |
447 | 513 | ||
448 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. | 514 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. |
449 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? | 515 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? |
450 | protected void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) | 516 | private void DetachSingleAttachmentToInv(UUID itemID, ScenePresence sp) |
451 | { | 517 | { |
452 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... | 518 | if (itemID == UUID.Zero) // If this happened, someone made a mistake.... |
453 | return; | 519 | return; |
@@ -465,17 +531,28 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
465 | if (group.GetFromItemID() == itemID) | 531 | if (group.GetFromItemID() == itemID) |
466 | { | 532 | { |
467 | m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); | 533 | m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); |
468 | group.DetachToInventoryPrep(); | 534 | sp.RemoveAttachment(group); |
469 | // m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); | 535 | |
470 | 536 | // Prepare sog for storage | |
471 | // If an item contains scripts, it's always changed. | 537 | group.AttachedAvatar = UUID.Zero; |
472 | // This ensures script state is saved on detach | 538 | |
473 | foreach (SceneObjectPart p in group.Parts) | 539 | group.ForEachPart( |
474 | if (p.Inventory.ContainsScripts()) | 540 | delegate(SceneObjectPart part) |
475 | group.HasGroupChanged = true; | 541 | { |
476 | 542 | // If there are any scripts, | |
477 | UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID); | 543 | // then always trigger a new object and state persistence in UpdateKnownItem() |
544 | if (part.Inventory.ContainsScripts()) | ||
545 | group.HasGroupChanged = true; | ||
546 | } | ||
547 | ); | ||
548 | |||
549 | group.RootPart.SetParentLocalId(0); | ||
550 | group.RootPart.IsAttachment = false; | ||
551 | group.AbsolutePosition = group.RootPart.AttachedPos; | ||
552 | |||
553 | UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); | ||
478 | m_scene.DeleteSceneObject(group, false); | 554 | m_scene.DeleteSceneObject(group, false); |
555 | |||
479 | return; | 556 | return; |
480 | } | 557 | } |
481 | } | 558 | } |
@@ -515,7 +592,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
515 | { | 592 | { |
516 | if (!grp.HasGroupChanged) | 593 | if (!grp.HasGroupChanged) |
517 | { | 594 | { |
518 | m_log.WarnFormat("[ATTACHMENTS MODULE]: Save request for {0} which is unchanged", grp.UUID); | 595 | m_log.DebugFormat( |
596 | "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", | ||
597 | grp.UUID, grp.GetAttachmentPoint()); | ||
598 | |||
519 | return; | 599 | return; |
520 | } | 600 | } |
521 | 601 | ||
@@ -524,6 +604,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
524 | grp.UUID, grp.GetAttachmentPoint()); | 604 | grp.UUID, grp.GetAttachmentPoint()); |
525 | 605 | ||
526 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); | 606 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); |
607 | |||
527 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); | 608 | InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); |
528 | item = m_scene.InventoryService.GetItem(item); | 609 | item = m_scene.InventoryService.GetItem(item); |
529 | 610 | ||
@@ -575,12 +656,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
575 | m_scene.DeleteFromStorage(so.UUID); | 656 | m_scene.DeleteFromStorage(so.UUID); |
576 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | 657 | m_scene.EventManager.TriggerParcelPrimCountTainted(); |
577 | 658 | ||
578 | so.RootPart.AttachedAvatar = avatar.UUID; | 659 | so.AttachedAvatar = avatar.UUID; |
579 | |||
580 | //Anakin Lohner bug #3839 | ||
581 | SceneObjectPart[] parts = so.Parts; | ||
582 | for (int i = 0; i < parts.Length; i++) | ||
583 | parts[i].AttachedAvatar = avatar.UUID; | ||
584 | 660 | ||
585 | if (so.RootPart.PhysActor != null) | 661 | if (so.RootPart.PhysActor != null) |
586 | { | 662 | { |
@@ -616,5 +692,97 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
616 | // it get cleaned up | 692 | // it get cleaned up |
617 | so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); | 693 | so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); |
618 | } | 694 | } |
695 | |||
696 | /// <summary> | ||
697 | /// Add a scene object that was previously free in the scene as an attachment to an avatar. | ||
698 | /// </summary> | ||
699 | /// <param name="remoteClient"></param> | ||
700 | /// <param name="grp"></param> | ||
701 | /// <returns>The user inventory item created that holds the attachment.</returns> | ||
702 | private InventoryItemBase AddSceneObjectAsAttachment(IClientAPI remoteClient, SceneObjectGroup grp) | ||
703 | { | ||
704 | // m_log.DebugFormat("[SCENE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2} {3} {4}", grp.Name, grp.LocalId, remoteClient.Name, remoteClient.AgentId, AgentId); | ||
705 | |||
706 | Vector3 inventoryStoredPosition = new Vector3 | ||
707 | (((grp.AbsolutePosition.X > (int)Constants.RegionSize) | ||
708 | ? Constants.RegionSize - 6 | ||
709 | : grp.AbsolutePosition.X) | ||
710 | , | ||
711 | (grp.AbsolutePosition.Y > (int)Constants.RegionSize) | ||
712 | ? Constants.RegionSize - 6 | ||
713 | : grp.AbsolutePosition.Y, | ||
714 | grp.AbsolutePosition.Z); | ||
715 | |||
716 | Vector3 originalPosition = grp.AbsolutePosition; | ||
717 | |||
718 | grp.AbsolutePosition = inventoryStoredPosition; | ||
719 | |||
720 | // If we're being called from a script, then trying to serialize that same script's state will not complete | ||
721 | // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if | ||
722 | // the client/server crashes rather than logging out normally, the attachment's scripts will resume | ||
723 | // without state on relog. Arguably, this is what we want anyway. | ||
724 | string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false); | ||
725 | |||
726 | grp.AbsolutePosition = originalPosition; | ||
727 | |||
728 | AssetBase asset = m_scene.CreateAsset( | ||
729 | grp.GetPartName(grp.LocalId), | ||
730 | grp.GetPartDescription(grp.LocalId), | ||
731 | (sbyte)AssetType.Object, | ||
732 | Utils.StringToBytes(sceneObjectXml), | ||
733 | remoteClient.AgentId); | ||
734 | |||
735 | m_scene.AssetService.Store(asset); | ||
736 | |||
737 | InventoryItemBase item = new InventoryItemBase(); | ||
738 | item.CreatorId = grp.RootPart.CreatorID.ToString(); | ||
739 | item.CreatorData = grp.RootPart.CreatorData; | ||
740 | item.Owner = remoteClient.AgentId; | ||
741 | item.ID = UUID.Random(); | ||
742 | item.AssetID = asset.FullID; | ||
743 | item.Description = asset.Description; | ||
744 | item.Name = asset.Name; | ||
745 | item.AssetType = asset.Type; | ||
746 | item.InvType = (int)InventoryType.Object; | ||
747 | |||
748 | InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object); | ||
749 | if (folder != null) | ||
750 | item.Folder = folder.ID; | ||
751 | else // oopsies | ||
752 | item.Folder = UUID.Zero; | ||
753 | |||
754 | if ((remoteClient.AgentId != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) | ||
755 | { | ||
756 | item.BasePermissions = grp.RootPart.NextOwnerMask; | ||
757 | item.CurrentPermissions = grp.RootPart.NextOwnerMask; | ||
758 | item.NextPermissions = grp.RootPart.NextOwnerMask; | ||
759 | item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; | ||
760 | item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; | ||
761 | } | ||
762 | else | ||
763 | { | ||
764 | item.BasePermissions = grp.RootPart.BaseMask; | ||
765 | item.CurrentPermissions = grp.RootPart.OwnerMask; | ||
766 | item.NextPermissions = grp.RootPart.NextOwnerMask; | ||
767 | item.EveryOnePermissions = grp.RootPart.EveryoneMask; | ||
768 | item.GroupPermissions = grp.RootPart.GroupMask; | ||
769 | } | ||
770 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
771 | |||
772 | // sets itemID so client can show item as 'attached' in inventory | ||
773 | grp.SetFromItemID(item.ID); | ||
774 | |||
775 | if (m_scene.AddInventoryItem(item)) | ||
776 | { | ||
777 | remoteClient.SendInventoryItemCreateUpdate(item, 0); | ||
778 | } | ||
779 | else | ||
780 | { | ||
781 | if (m_dialogModule != null) | ||
782 | m_dialogModule.SendAlertToUser(remoteClient, "Operation failed"); | ||
783 | } | ||
784 | |||
785 | return item; | ||
786 | } | ||
619 | } | 787 | } |
620 | } | 788 | } |