aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs513
1 files changed, 389 insertions, 124 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index 47476a9..8be0455 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -47,7 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
47 { 47 {
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 49
50 protected Scene m_scene = null; 50 private Scene m_scene;
51 private IDialogModule m_dialogModule;
51 52
52 public string Name { get { return "Attachments Module"; } } 53 public string Name { get { return "Attachments Module"; } }
53 public Type ReplaceableInterface { get { return null; } } 54 public Type ReplaceableInterface { get { return null; } }
@@ -57,6 +58,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
57 public void AddRegion(Scene scene) 58 public void AddRegion(Scene scene)
58 { 59 {
59 m_scene = scene; 60 m_scene = scene;
61 m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
60 m_scene.RegisterModuleInterface<IAttachmentsModule>(this); 62 m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
61 m_scene.EventManager.OnNewClient += SubscribeToClientEvents; 63 m_scene.EventManager.OnNewClient += SubscribeToClientEvents;
62 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI 64 // TODO: Should probably be subscribing to CloseClient too, but this doesn't yet give us IClientAPI
@@ -81,7 +83,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
81 client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory; 83 client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachmentsFromInventory;
82 client.OnObjectAttach += AttachObject; 84 client.OnObjectAttach += AttachObject;
83 client.OnObjectDetach += DetachObject; 85 client.OnObjectDetach += DetachObject;
84 client.OnDetachAttachmentIntoInv += ShowDetachInUserInventory; 86 client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv;
87 client.OnObjectDrop += DetachSingleAttachmentToGround;
85 } 88 }
86 89
87 public void UnsubscribeFromClientEvents(IClientAPI client) 90 public void UnsubscribeFromClientEvents(IClientAPI client)
@@ -90,7 +93,77 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
90 client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory; 93 client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachmentsFromInventory;
91 client.OnObjectAttach -= AttachObject; 94 client.OnObjectAttach -= AttachObject;
92 client.OnObjectDetach -= DetachObject; 95 client.OnObjectDetach -= DetachObject;
93 client.OnDetachAttachmentIntoInv -= ShowDetachInUserInventory; 96 client.OnDetachAttachmentIntoInv -= DetachSingleAttachmentToInv;
97 client.OnObjectDrop -= DetachSingleAttachmentToGround;
98 }
99
100 /// <summary>
101 /// RezAttachments. This should only be called upon login on the first region.
102 /// Attachment rezzings on crossings and TPs are done in a different way.
103 /// </summary>
104 public void RezAttachments(IScenePresence sp)
105 {
106 if (null == sp.Appearance)
107 {
108 m_log.WarnFormat("[ATTACHMENTS MODULE]: Appearance has not been initialized for agent {0}", sp.UUID);
109 return;
110 }
111
112 List<AvatarAttachment> attachments = sp.Appearance.GetAttachments();
113 foreach (AvatarAttachment attach in attachments)
114 {
115 uint p = (uint)attach.AttachPoint;
116
117// m_log.DebugFormat(
118// "[ATTACHMENTS MODULE]: Doing initial rez of attachment with itemID {0}, assetID {1}, point {2} for {3} in {4}",
119// attach.ItemID, attach.AssetID, p, sp.Name, m_scene.RegionInfo.RegionName);
120
121 // For some reason assetIDs are being written as Zero's in the DB -- need to track tat down
122 // But they're not used anyway, the item is being looked up for now, so let's proceed.
123 //if (UUID.Zero == assetID)
124 //{
125 // m_log.DebugFormat("[ATTACHMENT]: Cannot rez attachment in point {0} with itemID {1}", p, itemID);
126 // continue;
127 //}
128
129 try
130 {
131 // If we're an NPC then skip all the item checks and manipulations since we don't have an
132 // inventory right now.
133 if (sp.PresenceType == PresenceType.Npc)
134 RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p);
135 else
136 RezSingleAttachmentFromInventory(sp.ControllingClient, attach.ItemID, p);
137 }
138 catch (Exception e)
139 {
140 m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment: {0}{1}", e.Message, e.StackTrace);
141 }
142 }
143 }
144
145 public void SaveChangedAttachments(IScenePresence sp)
146 {
147 foreach (SceneObjectGroup grp in sp.GetAttachments())
148 {
149 if (grp.HasGroupChanged) // Resizer scripts?
150 {
151 grp.IsAttachment = false;
152 grp.AbsolutePosition = grp.RootPart.AttachedPos;
153 UpdateKnownItem(sp.ControllingClient, grp, grp.GetFromItemID(), grp.OwnerID);
154 grp.IsAttachment = true;
155 }
156 }
157 }
158
159 public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent)
160 {
161 foreach (SceneObjectGroup sop in sp.GetAttachments())
162 {
163 sop.Scene.DeleteSceneObject(sop, silent);
164 }
165
166 sp.ClearAttachments();
94 } 167 }
95 168
96 /// <summary> 169 /// <summary>
@@ -102,10 +175,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
102 /// <param name="silent"></param> 175 /// <param name="silent"></param>
103 public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) 176 public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent)
104 { 177 {
105 m_log.Debug("[ATTACHMENTS MODULE]: Invoking AttachObject"); 178// m_log.DebugFormat(
179// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})",
180// objectLocalID, remoteClient.Name, AttachmentPt, silent);
106 181
107 try 182 try
108 { 183 {
184 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
185
186 if (sp == null)
187 {
188 m_log.ErrorFormat(
189 "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId);
190 return;
191 }
192
109 // If we can't take it, we can't attach it! 193 // If we can't take it, we can't attach it!
110 SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); 194 SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID);
111 if (part == null) 195 if (part == null)
@@ -131,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
131 AttachmentPt &= 0x7f; 215 AttachmentPt &= 0x7f;
132 216
133 // Calls attach with a Zero position 217 // Calls attach with a Zero position
134 if (AttachObject(remoteClient, part.ParentGroup, AttachmentPt, false)) 218 if (AttachObject(sp, part.ParentGroup, AttachmentPt, false))
135 { 219 {
136 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); 220 m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId);
137 221
@@ -144,73 +228,94 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
144 } 228 }
145 catch (Exception e) 229 catch (Exception e)
146 { 230 {
147 m_log.DebugFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}", e); 231 m_log.ErrorFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}{1}", e.Message, e.StackTrace);
148 } 232 }
149 } 233 }
150 234
151 public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent) 235 public bool AttachObject(IClientAPI remoteClient, SceneObjectGroup group, uint AttachmentPt, bool silent)
152 { 236 {
237 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
238
239 if (sp == null)
240 {
241 m_log.ErrorFormat(
242 "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1}", remoteClient.Name, remoteClient.AgentId);
243 return false;
244 }
245
246 return AttachObject(sp, group, AttachmentPt, silent);
247 }
248
249 private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent)
250 {
251// m_log.DebugFormat(
252// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
253// group.Name, group.LocalId, sp.Name, AttachmentPt, silent);
254
255 if (sp.GetAttachments(attachmentPt).Contains(group))
256 {
257// m_log.WarnFormat(
258// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached",
259// group.Name, group.LocalId, sp.Name, AttachmentPt);
260
261 return false;
262 }
263
153 Vector3 attachPos = group.AbsolutePosition; 264 Vector3 attachPos = group.AbsolutePosition;
154 265
155 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 266 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
156 // be removed when that functionality is implemented in opensim 267 // be removed when that functionality is implemented in opensim
157 AttachmentPt &= 0x7f; 268 attachmentPt &= 0x7f;
158 269
159 // If the attachment point isn't the same as the one previously used 270 // If the attachment point isn't the same as the one previously used
160 // set it's offset position = 0 so that it appears on the attachment point 271 // set it's offset position = 0 so that it appears on the attachment point
161 // and not in a weird location somewhere unknown. 272 // and not in a weird location somewhere unknown.
162 if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint()) 273 if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint)
163 { 274 {
164 attachPos = Vector3.Zero; 275 attachPos = Vector3.Zero;
165 } 276 }
166 277
167 // AttachmentPt 0 means the client chose to 'wear' the attachment. 278 // AttachmentPt 0 means the client chose to 'wear' the attachment.
168 if (AttachmentPt == 0) 279 if (attachmentPt == 0)
169 { 280 {
170 // Check object for stored attachment point 281 // Check object for stored attachment point
171 AttachmentPt = (uint)group.GetAttachmentPoint(); 282 attachmentPt = group.AttachmentPoint;
172 } 283 }
173 284
174 // if we still didn't find a suitable attachment point....... 285 // if we still didn't find a suitable attachment point.......
175 if (AttachmentPt == 0) 286 if (attachmentPt == 0)
176 { 287 {
177 // Stick it on left hand with Zero Offset from the attachment point. 288 // Stick it on left hand with Zero Offset from the attachment point.
178 AttachmentPt = (uint)AttachmentPoint.LeftHand; 289 attachmentPt = (uint)AttachmentPoint.LeftHand;
179 attachPos = Vector3.Zero; 290 attachPos = Vector3.Zero;
180 } 291 }
181 292
182 group.SetAttachmentPoint((byte)AttachmentPt); 293 group.AttachmentPoint = attachmentPt;
183 group.AbsolutePosition = attachPos; 294 group.AbsolutePosition = attachPos;
184 295
185 // Remove any previous attachments 296 // Remove any previous attachments
186 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
187 UUID itemID = UUID.Zero; 297 UUID itemID = UUID.Zero;
188 if (sp != null)
189 {
190 foreach (SceneObjectGroup grp in sp.Attachments)
191 {
192 if (grp.GetAttachmentPoint() == (byte)AttachmentPt)
193 {
194 itemID = grp.GetFromItemID();
195 break;
196 }
197 }
198 if (itemID != UUID.Zero)
199 DetachSingleAttachmentToInv(itemID, remoteClient);
200 }
201 298
202 if (group.GetFromItemID() == UUID.Zero) 299 List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
203 { 300
204 m_scene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemID); 301 // At the moment we can only deal with a single attachment
205 } 302 // We also don't want to do any of the inventory operations for an NPC.
206 else 303 if (sp.PresenceType != PresenceType.Npc)
207 { 304 {
305 if (attachments.Count != 0)
306 itemID = attachments[0].GetFromItemID();
307
308 if (itemID != UUID.Zero)
309 DetachSingleAttachmentToInv(itemID, sp);
310
208 itemID = group.GetFromItemID(); 311 itemID = group.GetFromItemID();
312 if (itemID == UUID.Zero)
313 itemID = AddSceneObjectAsAttachment(sp.ControllingClient, group).ID;
314
315 ShowAttachInUserInventory(sp, attachmentPt, itemID, group);
209 } 316 }
210 317
211 ShowAttachInUserInventory(remoteClient, AttachmentPt, itemID, group); 318 AttachToAgent(sp, group, attachmentPt, attachPos, silent);
212
213 AttachToAgent(sp, group, AttachmentPt, attachPos, silent);
214 319
215 return true; 320 return true;
216 } 321 }
@@ -226,12 +331,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
226 } 331 }
227 } 332 }
228 333
229 public UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) 334 public ISceneEntity RezSingleAttachmentFromInventory(
335 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
230 { 336 {
231 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true); 337 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true);
232 } 338 }
233 339
234 public UUID RezSingleAttachmentFromInventory( 340 public ISceneEntity RezSingleAttachmentFromInventory(
235 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) 341 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
236 { 342 {
237 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null); 343 return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null);
@@ -239,7 +345,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
239 345
240 public UUID RezSingleAttachmentFromInventory( 346 public UUID RezSingleAttachmentFromInventory(
241 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) 347 IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc)
348 ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
349
242 { 350 {
351 if (sp == null) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", remoteClient.Name, remoteClient.AgentId); return null; }
243 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should 352 // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should
244 // be removed when that functionality is implemented in opensim 353 // be removed when that functionality is implemented in opensim
245 AttachmentPt &= 0x7f; 354 AttachmentPt &= 0x7f;
@@ -249,15 +358,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
249 if (updateInventoryStatus) 358 if (updateInventoryStatus)
250 { 359 {
251 if (att == null) 360 if (att == null)
252 ShowDetachInUserInventory(itemID, remoteClient); 361 DetachSingleAttachmentToInv(itemID, sp.ControllingClient);
253 else 362 else
254 ShowAttachInUserInventory(att, remoteClient, itemID, AttachmentPt); 363 ShowAttachInUserInventory(att, sp, itemID, AttachmentPt);
255 } 364 }
256 365
257 if (null == att) 366 return att;
258 return UUID.Zero;
259 else
260 return att.UUID;
261 } 367 }
262 368
263 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( 369 protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
@@ -266,12 +372,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
266 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); 372 IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
267 if (invAccess != null) 373 if (invAccess != null)
268 { 374 {
269 SceneObjectGroup objatt = invAccess.RezObject(remoteClient, 375 SceneObjectGroup objatt;
270 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, 376
271 false, false, remoteClient.AgentId, true); 377 if (itemID != UUID.Zero)
378 objatt = invAccess.RezObject(sp.ControllingClient,
379 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
380 false, false, sp.UUID, true);
381 else
382 objatt = invAccess.RezObject(sp.ControllingClient,
383 null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
384 false, false, sp.UUID, true);
272 385
273// m_log.DebugFormat( 386// m_log.DebugFormat(
274// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", 387// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
275// objatt.Name, remoteClient.Name, AttachmentPt); 388// objatt.Name, remoteClient.Name, AttachmentPt);
276 389
277 if (objatt != null) 390 if (objatt != null)
@@ -281,17 +394,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
281 // since scripts aren't running yet. So, clear it here. 394 // since scripts aren't running yet. So, clear it here.
282 objatt.HasGroupChanged = false; 395 objatt.HasGroupChanged = false;
283 bool tainted = false; 396 bool tainted = false;
284 if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) 397 if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
285 tainted = true; 398 tainted = true;
286 399
287 // This will throw if the attachment fails 400 // This will throw if the attachment fails
288 try 401 try
289 { 402 {
290 AttachObject(remoteClient, objatt, AttachmentPt, false); 403 AttachObject(sp, objatt, attachmentPt, false);
291 } 404 }
292 catch 405 catch (Exception e)
293 { 406 {
407 m_log.ErrorFormat(
408 "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
409 objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
410
294 // Make sure the object doesn't stick around and bail 411 // Make sure the object doesn't stick around and bail
412 sp.RemoveAttachment(objatt);
295 m_scene.DeleteSceneObject(objatt, false); 413 m_scene.DeleteSceneObject(objatt, false);
296 return null; 414 return null;
297 } 415 }
@@ -311,13 +429,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
311 objatt.ResumeScripts(); 429 objatt.ResumeScripts();
312 430
313 // Do this last so that event listeners have access to all the effects of the attachment 431 // Do this last so that event listeners have access to all the effects of the attachment
314 //m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); 432 m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
315 } 433 }
316 else 434 else
317 { 435 {
318 m_log.WarnFormat( 436 m_log.WarnFormat(
319 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", 437 "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
320 itemID, remoteClient.Name, AttachmentPt); 438 itemID, sp.Name, attachmentPt);
321 } 439 }
322 440
323 return objatt; 441 return objatt;
@@ -330,31 +448,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
330 /// Update the user inventory to the attachment of an item 448 /// Update the user inventory to the attachment of an item
331 /// </summary> 449 /// </summary>
332 /// <param name="att"></param> 450 /// <param name="att"></param>
333 /// <param name="remoteClient"></param> 451 /// <param name="sp"></param>
334 /// <param name="itemID"></param> 452 /// <param name="itemID"></param>
335 /// <param name="AttachmentPt"></param> 453 /// <param name="attachmentPoint"></param>
336 /// <returns></returns> 454 /// <returns></returns>
337 protected UUID ShowAttachInUserInventory( 455 private UUID ShowAttachInUserInventory(
338 SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) 456 SceneObjectGroup att, IScenePresence sp, UUID itemID, uint attachmentPoint)
339 { 457 {
340// m_log.DebugFormat( 458// m_log.DebugFormat(
341// "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})", 459// "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} {2} (item ID {3}) at {4}",
342// remoteClient.Name, att.Name, itemID); 460// sp.Name, att.Name, att.LocalId, itemID, AttachmentPt);
343 461
344 if (!att.IsDeleted) 462 if (!att.IsDeleted)
345 AttachmentPt = att.RootPart.AttachmentPoint; 463 attachmentPoint = att.AttachmentPoint;
346 464
347 ScenePresence presence; 465 ScenePresence presence;
348 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 466 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
349 { 467 {
350 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 468 InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
351 if (m_scene.InventoryService != null) 469 if (m_scene.InventoryService != null)
352 item = m_scene.InventoryService.GetItem(item); 470 item = m_scene.InventoryService.GetItem(item);
353 471
354 bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); 472 bool changed = sp.Appearance.SetAttachment((int)attachmentPoint, itemID, item.AssetID);
355 if (changed && m_scene.AvatarFactory != null) 473 if (changed && m_scene.AvatarFactory != null)
356 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); 474 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
357 }
358 475
359 return att.UUID; 476 return att.UUID;
360 } 477 }
@@ -362,12 +479,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
362 /// <summary> 479 /// <summary>
363 /// Update the user inventory to reflect an attachment 480 /// Update the user inventory to reflect an attachment
364 /// </summary> 481 /// </summary>
365 /// <param name="remoteClient"></param> 482 /// <param name="sp"></param>
366 /// <param name="AttachmentPt"></param> 483 /// <param name="AttachmentPt"></param>
367 /// <param name="itemID"></param> 484 /// <param name="itemID"></param>
368 /// <param name="att"></param> 485 /// <param name="att"></param>
369 protected void ShowAttachInUserInventory( 486 private void ShowAttachInUserInventory(
370 IClientAPI remoteClient, uint AttachmentPt, UUID itemID, SceneObjectGroup att) 487 IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att)
371 { 488 {
372// m_log.DebugFormat( 489// m_log.DebugFormat(
373// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", 490// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
@@ -390,23 +507,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
390 m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment for a prim without the rootpart!"); 507 m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment for a prim without the rootpart!");
391 return; 508 return;
392 } 509 }
510 InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
393 511
394 ScenePresence presence; 512
395 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 513
396 { 514
397 // XXYY!! 515
398 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 516
399 if (item == null) 517 item = m_scene.InventoryService.GetItem(item);
400 m_log.Error("[ATTACHMENT]: item == null"); 518 bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
401 if (m_scene == null) 519 if (changed && m_scene.AvatarFactory != null)
402 m_log.Error("[ATTACHMENT]: m_scene == null"); 520 m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
403 if (m_scene.InventoryService == null)
404 m_log.Error("[ATTACHMENT]: m_scene.InventoryService == null");
405 item = m_scene.InventoryService.GetItem(item);
406 bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
407 if (changed && m_scene.AvatarFactory != null)
408 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
409 }
410 } 521 }
411 522
412 public void DetachObject(uint objectLocalID, IClientAPI remoteClient) 523 public void DetachObject(uint objectLocalID, IClientAPI remoteClient)
@@ -414,12 +525,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
414 SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); 525 SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
415 if (group != null) 526 if (group != null)
416 { 527 {
417 //group.DetachToGround(); 528 DetachSingleAttachmentToInv(group.GetFromItemID(), remoteClient);
418 ShowDetachInUserInventory(group.GetFromItemID(), remoteClient);
419 } 529 }
420 } 530 }
421 531
422 public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient) 532 public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient)
423 { 533 {
424 ScenePresence presence; 534 ScenePresence presence;
425 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 535 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
@@ -430,34 +540,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
430 bool changed = presence.Appearance.DetachAttachment(itemID); 540 bool changed = presence.Appearance.DetachAttachment(itemID);
431 if (changed && m_scene.AvatarFactory != null) 541 if (changed && m_scene.AvatarFactory != null)
432 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); 542 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
433 }
434 543
435 DetachSingleAttachmentToInv(itemID, remoteClient); 544 DetachSingleAttachmentToInv(itemID, presence);
545 }
436 } 546 }
437 547
438 public void DetachSingleAttachmentToGround(UUID itemID, IClientAPI remoteClient) 548 public void DetachSingleAttachmentToGround(uint soLocalId, IClientAPI remoteClient)
439 { 549 {
440 SceneObjectPart part = m_scene.GetSceneObjectPart(itemID); 550// m_log.DebugFormat(
441 if (part == null || part.ParentGroup == null) 551// "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}",
552// remoteClient.Name, sceneObjectID);
553
554 SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId);
555
556 if (so == null)
442 return; 557 return;
443 558
444 if (part.ParentGroup.RootPart.AttachedAvatar != remoteClient.AgentId) 559 if (so.AttachedAvatar != remoteClient.AgentId)
445 return; 560 return;
446 561
447 UUID inventoryID = part.ParentGroup.GetFromItemID(); 562 UUID inventoryID = so.GetFromItemID();
563
564// m_log.DebugFormat(
565// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
566// so.Name, so.LocalId, inventoryID);
448 567
449 ScenePresence presence; 568 ScenePresence presence;
450 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) 569 if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
451 { 570 {
452 if (!m_scene.Permissions.CanRezObject( 571 if (!m_scene.Permissions.CanRezObject(
453 part.ParentGroup.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) 572 so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition))
454 return; 573 return;
455 574
456 bool changed = presence.Appearance.DetachAttachment(itemID); 575 bool changed = presence.Appearance.DetachAttachment(inventoryID);
457 if (changed && m_scene.AvatarFactory != null) 576 if (changed && m_scene.AvatarFactory != null)
458 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); 577 m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId);
459 578
460 part.ParentGroup.DetachToGround(); 579 presence.RemoveAttachment(so);
580 DetachSceneObjectToGround(so, presence);
461 581
462 List<UUID> uuids = new List<UUID>(); 582 List<UUID> uuids = new List<UUID>();
463 uuids.Add(inventoryID); 583 uuids.Add(inventoryID);
@@ -465,12 +585,39 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
465 remoteClient.SendRemoveInventoryItem(inventoryID); 585 remoteClient.SendRemoveInventoryItem(inventoryID);
466 } 586 }
467 587
468 m_scene.EventManager.TriggerOnAttach(part.ParentGroup.LocalId, itemID, UUID.Zero); 588 m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero);
589 }
590
591 /// <summary>
592 /// Detach the given scene object to the ground.
593 /// </summary>
594 /// <remarks>
595 /// The caller has to take care of all the other work in updating avatar appearance, inventory, etc.
596 /// </remarks>
597 /// <param name="so">The scene object to detach.</param>
598 /// <param name="sp">The scene presence from which the scene object is being detached.</param>
599 private void DetachSceneObjectToGround(SceneObjectGroup so, ScenePresence sp)
600 {
601 SceneObjectPart rootPart = so.RootPart;
602
603 rootPart.FromItemID = UUID.Zero;
604 so.AbsolutePosition = sp.AbsolutePosition;
605 so.AttachedAvatar = UUID.Zero;
606 rootPart.SetParentLocalId(0);
607 so.ClearPartAttachmentData();
608 rootPart.ApplyPhysics(rootPart.GetEffectiveObjectFlags(), rootPart.VolumeDetectActive, m_scene.m_physicalPrim);
609 so.HasGroupChanged = true;
610 rootPart.Rezzed = DateTime.Now;
611 rootPart.RemFlag(PrimFlags.TemporaryOnRez);
612 so.AttachToBackup();
613 m_scene.EventManager.TriggerParcelPrimCountTainted();
614 rootPart.ScheduleFullUpdate();
615 rootPart.ClearUndoState();
469 } 616 }
470 617
471 // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. 618 // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards.
472 // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? 619 // To LocalId or UUID, *THAT* is the question. How now Brown UUID??
473 protected void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient) 620 private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp)
474 { 621 {
475 if (itemID == UUID.Zero) // If this happened, someone made a mistake.... 622 if (itemID == UUID.Zero) // If this happened, someone made a mistake....
476 return; 623 return;
@@ -493,27 +640,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
493 group.DetachToInventoryPrep(); 640 group.DetachToInventoryPrep();
494 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 641 m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
495 642
496 // If an item contains scripts, it's always changed. 643 // Prepare sog for storage
497 // This ensures script state is saved on detach 644 group.AttachedAvatar = UUID.Zero;
498 foreach (SceneObjectPart p in group.Parts) 645
499 if (p.Inventory.ContainsScripts()) 646 group.ForEachPart(
500 group.HasGroupChanged = true; 647 delegate(SceneObjectPart part)
648 {
649 // If there are any scripts,
650 // then always trigger a new object and state persistence in UpdateKnownItem()
651 if (part.Inventory.ContainsScripts())
652 group.HasGroupChanged = true;
653 }
654 );
501 655
502 UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID); 656 group.RootPart.SetParentLocalId(0);
657 group.IsAttachment = false;
658 group.AbsolutePosition = group.RootPart.AttachedPos;
659
660 UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID);
503 m_scene.DeleteSceneObject(group, false); 661 m_scene.DeleteSceneObject(group, false);
662
504 return; 663 return;
505 } 664 }
506 } 665 }
507 } 666 }
508 } 667 }
509 668
669 public void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos)
670 {
671 // First we save the
672 // attachment point information, then we update the relative
673 // positioning. Then we have to mark the object as NOT an
674 // attachment. This is necessary in order to correctly save
675 // and retrieve GroupPosition information for the attachment.
676 // Finally, we restore the object's attachment status.
677 uint attachmentPoint = sog.AttachmentPoint;
678 sog.UpdateGroupPosition(pos);
679 sog.IsAttachment = false;
680 sog.AbsolutePosition = sog.RootPart.AttachedPos;
681 sog.AttachmentPoint = attachmentPoint;
682 sog.HasGroupChanged = true;
683 }
684
510 /// <summary> 685 /// <summary>
511 /// Update the attachment asset for the new sog details if they have changed. 686 /// Update the attachment asset for the new sog details if they have changed.
512 /// </summary> 687 /// </summary>
513 /// 688 /// <remarks>
514 /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects, 689 /// This is essential for preserving attachment attributes such as permission. Unlike normal scene objects,
515 /// these details are not stored on the region. 690 /// these details are not stored on the region.
516 /// 691 /// </remarks>
517 /// <param name="remoteClient"></param> 692 /// <param name="remoteClient"></param>
518 /// <param name="grp"></param> 693 /// <param name="grp"></param>
519 /// <param name="itemID"></param> 694 /// <param name="itemID"></param>
@@ -524,15 +699,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
524 { 699 {
525 if (!grp.HasGroupChanged) 700 if (!grp.HasGroupChanged)
526 { 701 {
527 m_log.WarnFormat("[ATTACHMENTS MODULE]: Save request for {0} which is unchanged", grp.UUID); 702 m_log.DebugFormat(
703 "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
704 grp.UUID, grp.AttachmentPoint);
705
528 return; 706 return;
529 } 707 }
530 708
531 m_log.DebugFormat( 709 m_log.DebugFormat(
532 "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", 710 "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
533 grp.UUID, grp.GetAttachmentPoint()); 711 grp.UUID, grp.AttachmentPoint);
534 712
535 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); 713 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
714
536 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); 715 InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
537 item = m_scene.InventoryService.GetItem(item); 716 item = m_scene.InventoryService.GetItem(item);
538 717
@@ -564,20 +743,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
564 /// <summary> 743 /// <summary>
565 /// Attach this scene object to the given avatar. 744 /// Attach this scene object to the given avatar.
566 /// </summary> 745 /// </summary>
567 /// 746 /// <remarks>
568 /// This isn't publicly available since attachments should always perform the corresponding inventory 747 /// This isn't publicly available since attachments should always perform the corresponding inventory
569 /// operation (to show the attach in user inventory and update the asset with positional information). 748 /// operation (to show the attach in user inventory and update the asset with positional information).
570 /// 749 /// </remarks>
571 /// <param name="sp"></param> 750 /// <param name="sp"></param>
572 /// <param name="so"></param> 751 /// <param name="so"></param>
573 /// <param name="attachmentpoint"></param> 752 /// <param name="attachmentpoint"></param>
574 /// <param name="attachOffset"></param> 753 /// <param name="attachOffset"></param>
575 /// <param name="silent"></param> 754 /// <param name="silent"></param>
576 protected void AttachToAgent(ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) 755 private void AttachToAgent(
756 IScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
577 { 757 {
578 758// m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}",
579 m_log.DebugFormat("[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", Name, avatar.Name, 759// so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos);
580 attachmentpoint, attachOffset, so.RootPart.AttachedPos);
581 760
582 so.DetachFromBackup(); 761 so.DetachFromBackup();
583 762
@@ -585,12 +764,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
585 m_scene.DeleteFromStorage(so.UUID); 764 m_scene.DeleteFromStorage(so.UUID);
586 m_scene.EventManager.TriggerParcelPrimCountTainted(); 765 m_scene.EventManager.TriggerParcelPrimCountTainted();
587 766
588 so.RootPart.AttachedAvatar = avatar.UUID; 767 so.AttachedAvatar = avatar.UUID;
589
590 //Anakin Lohner bug #3839
591 SceneObjectPart[] parts = so.Parts;
592 for (int i = 0; i < parts.Length; i++)
593 parts[i].AttachedAvatar = avatar.UUID;
594 768
595 if (so.RootPart.PhysActor != null) 769 if (so.RootPart.PhysActor != null)
596 { 770 {
@@ -600,10 +774,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
600 774
601 so.AbsolutePosition = attachOffset; 775 so.AbsolutePosition = attachOffset;
602 so.RootPart.AttachedPos = attachOffset; 776 so.RootPart.AttachedPos = attachOffset;
603 so.RootPart.IsAttachment = true; 777 so.IsAttachment = true;
604
605 so.RootPart.SetParentLocalId(avatar.LocalId); 778 so.RootPart.SetParentLocalId(avatar.LocalId);
606 so.SetAttachmentPoint(Convert.ToByte(attachmentpoint)); 779 so.AttachmentPoint = attachmentpoint;
607 780
608 avatar.AddAttachment(so); 781 avatar.AddAttachment(so);
609 782
@@ -617,5 +790,97 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
617 // it get cleaned up 790 // it get cleaned up
618 so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); 791 so.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
619 } 792 }
793
794 /// <summary>
795 /// Add a scene object that was previously free in the scene as an attachment to an avatar.
796 /// </summary>
797 /// <param name="remoteClient"></param>
798 /// <param name="grp"></param>
799 /// <returns>The user inventory item created that holds the attachment.</returns>
800 private InventoryItemBase AddSceneObjectAsAttachment(IClientAPI remoteClient, SceneObjectGroup grp)
801 {
802// m_log.DebugFormat("[SCENE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2} {3} {4}", grp.Name, grp.LocalId, remoteClient.Name, remoteClient.AgentId, AgentId);
803
804 Vector3 inventoryStoredPosition = new Vector3
805 (((grp.AbsolutePosition.X > (int)Constants.RegionSize)
806 ? Constants.RegionSize - 6
807 : grp.AbsolutePosition.X)
808 ,
809 (grp.AbsolutePosition.Y > (int)Constants.RegionSize)
810 ? Constants.RegionSize - 6
811 : grp.AbsolutePosition.Y,
812 grp.AbsolutePosition.Z);
813
814 Vector3 originalPosition = grp.AbsolutePosition;
815
816 grp.AbsolutePosition = inventoryStoredPosition;
817
818 // If we're being called from a script, then trying to serialize that same script's state will not complete
819 // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if
820 // the client/server crashes rather than logging out normally, the attachment's scripts will resume
821 // without state on relog. Arguably, this is what we want anyway.
822 string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false);
823
824 grp.AbsolutePosition = originalPosition;
825
826 AssetBase asset = m_scene.CreateAsset(
827 grp.GetPartName(grp.LocalId),
828 grp.GetPartDescription(grp.LocalId),
829 (sbyte)AssetType.Object,
830 Utils.StringToBytes(sceneObjectXml),
831 remoteClient.AgentId);
832
833 m_scene.AssetService.Store(asset);
834
835 InventoryItemBase item = new InventoryItemBase();
836 item.CreatorId = grp.RootPart.CreatorID.ToString();
837 item.CreatorData = grp.RootPart.CreatorData;
838 item.Owner = remoteClient.AgentId;
839 item.ID = UUID.Random();
840 item.AssetID = asset.FullID;
841 item.Description = asset.Description;
842 item.Name = asset.Name;
843 item.AssetType = asset.Type;
844 item.InvType = (int)InventoryType.Object;
845
846 InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object);
847 if (folder != null)
848 item.Folder = folder.ID;
849 else // oopsies
850 item.Folder = UUID.Zero;
851
852 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions())
853 {
854 item.BasePermissions = grp.RootPart.NextOwnerMask;
855 item.CurrentPermissions = grp.RootPart.NextOwnerMask;
856 item.NextPermissions = grp.RootPart.NextOwnerMask;
857 item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
858 item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
859 }
860 else
861 {
862 item.BasePermissions = grp.RootPart.BaseMask;
863 item.CurrentPermissions = grp.RootPart.OwnerMask;
864 item.NextPermissions = grp.RootPart.NextOwnerMask;
865 item.EveryOnePermissions = grp.RootPart.EveryoneMask;
866 item.GroupPermissions = grp.RootPart.GroupMask;
867 }
868 item.CreationDate = Util.UnixTimeSinceEpoch();
869
870 // sets itemID so client can show item as 'attached' in inventory
871 grp.SetFromItemID(item.ID);
872
873 if (m_scene.AddInventoryItem(item))
874 {
875 remoteClient.SendInventoryItemCreateUpdate(item, 0);
876 }
877 else
878 {
879 if (m_dialogModule != null)
880 m_dialogModule.SendAlertToUser(remoteClient, "Operation failed");
881 }
882
883 return item;
884 }
620 } 885 }
621} 886}