diff options
author | Tom | 2011-09-04 07:06:36 -0700 |
---|---|---|
committer | Tom | 2011-09-04 07:06:36 -0700 |
commit | 66dec3b8742eff04fbbcc6e3249fe4ba87986500 (patch) | |
tree | 76cc708a821d35fac5cdbbce2de304b47064e732 /OpenSim/Region/CoreModules/Avatar/Attachments | |
parent | Guard another nullref (diff) | |
parent | Fixed BulletSim config files for Linux *.so libraries. (diff) | |
download | opensim-SC_OLD-66dec3b8742eff04fbbcc6e3249fe4ba87986500.zip opensim-SC_OLD-66dec3b8742eff04fbbcc6e3249fe4ba87986500.tar.gz opensim-SC_OLD-66dec3b8742eff04fbbcc6e3249fe4ba87986500.tar.bz2 opensim-SC_OLD-66dec3b8742eff04fbbcc6e3249fe4ba87986500.tar.xz |
Resolve merge commits, stage 1
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Attachments')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | 513 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | 274 |
2 files changed, 663 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 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs new file mode 100644 index 0000000..363e258 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -0,0 +1,274 @@ | |||
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.Reflection; | ||
31 | using System.Text; | ||
32 | using System.Threading; | ||
33 | using System.Timers; | ||
34 | using Timer=System.Timers.Timer; | ||
35 | using Nini.Config; | ||
36 | using NUnit.Framework; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.CoreModules.Avatar.Attachments; | ||
41 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | ||
42 | using OpenSim.Region.CoreModules.World.Serialiser; | ||
43 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Tests.Common; | ||
47 | using OpenSim.Tests.Common.Mock; | ||
48 | |||
49 | namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | ||
50 | { | ||
51 | /// <summary> | ||
52 | /// Attachment tests | ||
53 | /// </summary> | ||
54 | [TestFixture] | ||
55 | public class AttachmentsModuleTests | ||
56 | { | ||
57 | private Scene scene; | ||
58 | private AttachmentsModule m_attMod; | ||
59 | private ScenePresence m_presence; | ||
60 | |||
61 | [SetUp] | ||
62 | public void Init() | ||
63 | { | ||
64 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
65 | Util.FireAndForgetMethod = FireAndForgetMethod.None; | ||
66 | |||
67 | IConfigSource config = new IniConfigSource(); | ||
68 | config.AddConfig("Modules"); | ||
69 | config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); | ||
70 | |||
71 | scene = SceneHelpers.SetupScene(); | ||
72 | m_attMod = new AttachmentsModule(); | ||
73 | SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule()); | ||
74 | } | ||
75 | |||
76 | [TearDown] | ||
77 | public void TearDown() | ||
78 | { | ||
79 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
80 | // threads. Possibly, later tests should be rewritten not to worry about such things. | ||
81 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
82 | } | ||
83 | |||
84 | /// <summary> | ||
85 | /// Add the standard presence for a test. | ||
86 | /// </summary> | ||
87 | private void AddPresence() | ||
88 | { | ||
89 | UUID userId = TestHelpers.ParseTail(0x1); | ||
90 | UserAccountHelpers.CreateUserWithInventory(scene, userId); | ||
91 | m_presence = SceneHelpers.AddScenePresence(scene, userId); | ||
92 | } | ||
93 | |||
94 | [Test] | ||
95 | public void TestAddAttachmentFromGround() | ||
96 | { | ||
97 | TestHelpers.InMethod(); | ||
98 | // log4net.Config.XmlConfigurator.Configure(); | ||
99 | |||
100 | AddPresence(); | ||
101 | string attName = "att"; | ||
102 | |||
103 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName).ParentGroup; | ||
104 | |||
105 | m_attMod.AttachObject(m_presence.ControllingClient, so, (uint)AttachmentPoint.Chest, false); | ||
106 | |||
107 | // Check status on scene presence | ||
108 | Assert.That(m_presence.HasAttachments(), Is.True); | ||
109 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
110 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
111 | SceneObjectGroup attSo = attachments[0]; | ||
112 | Assert.That(attSo.Name, Is.EqualTo(attName)); | ||
113 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
114 | Assert.That(attSo.IsAttachment); | ||
115 | Assert.That(attSo.UsesPhysics, Is.False); | ||
116 | Assert.That(attSo.IsTemporary, Is.False); | ||
117 | |||
118 | // Check item status | ||
119 | Assert.That(m_presence.Appearance.GetAttachpoint( | ||
120 | attSo.GetFromItemID()), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
121 | } | ||
122 | |||
123 | [Test] | ||
124 | public void TestAddAttachmentFromInventory() | ||
125 | { | ||
126 | TestHelpers.InMethod(); | ||
127 | // log4net.Config.XmlConfigurator.Configure(); | ||
128 | |||
129 | AddPresence(); | ||
130 | |||
131 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
132 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
133 | string attName = "att"; | ||
134 | |||
135 | UserInventoryHelpers.CreateInventoryItem( | ||
136 | scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); | ||
137 | |||
138 | m_attMod.RezSingleAttachmentFromInventory( | ||
139 | m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); | ||
140 | |||
141 | // Check scene presence status | ||
142 | Assert.That(m_presence.HasAttachments(), Is.True); | ||
143 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
144 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
145 | SceneObjectGroup attSo = attachments[0]; | ||
146 | Assert.That(attSo.Name, Is.EqualTo(attName)); | ||
147 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
148 | Assert.That(attSo.IsAttachment); | ||
149 | Assert.That(attSo.UsesPhysics, Is.False); | ||
150 | Assert.That(attSo.IsTemporary, Is.False); | ||
151 | |||
152 | // Check appearance status | ||
153 | Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest)); | ||
154 | } | ||
155 | |||
156 | [Test] | ||
157 | public void TestDetachAttachmentToGround() | ||
158 | { | ||
159 | TestHelpers.InMethod(); | ||
160 | // log4net.Config.XmlConfigurator.Configure(); | ||
161 | |||
162 | AddPresence(); | ||
163 | |||
164 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
165 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
166 | string attName = "att"; | ||
167 | |||
168 | UserInventoryHelpers.CreateInventoryItem( | ||
169 | scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); | ||
170 | |||
171 | ISceneEntity so = m_attMod.RezSingleAttachmentFromInventory( | ||
172 | m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); | ||
173 | m_attMod.DetachSingleAttachmentToGround(so.LocalId, m_presence.ControllingClient); | ||
174 | |||
175 | // Check scene presence status | ||
176 | Assert.That(m_presence.HasAttachments(), Is.False); | ||
177 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
178 | Assert.That(attachments.Count, Is.EqualTo(0)); | ||
179 | |||
180 | // Check appearance status | ||
181 | Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(0)); | ||
182 | |||
183 | // Check item status | ||
184 | Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItemId)), Is.Null); | ||
185 | |||
186 | // Check object in scene | ||
187 | Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); | ||
188 | } | ||
189 | |||
190 | [Test] | ||
191 | public void TestDetachAttachmentToInventory() | ||
192 | { | ||
193 | TestHelpers.InMethod(); | ||
194 | // log4net.Config.XmlConfigurator.Configure(); | ||
195 | |||
196 | AddPresence(); | ||
197 | |||
198 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
199 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
200 | string attName = "att"; | ||
201 | |||
202 | UserInventoryHelpers.CreateInventoryItem( | ||
203 | scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); | ||
204 | |||
205 | m_attMod.RezSingleAttachmentFromInventory( | ||
206 | m_presence.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); | ||
207 | m_attMod.DetachSingleAttachmentToInv(attItemId, m_presence.ControllingClient); | ||
208 | |||
209 | // Check status on scene presence | ||
210 | Assert.That(m_presence.HasAttachments(), Is.False); | ||
211 | List<SceneObjectGroup> attachments = m_presence.GetAttachments(); | ||
212 | Assert.That(attachments.Count, Is.EqualTo(0)); | ||
213 | |||
214 | // Check item status | ||
215 | Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0)); | ||
216 | } | ||
217 | |||
218 | [Test] | ||
219 | public void TestRezAttachmentsOnAvatarEntrance() | ||
220 | { | ||
221 | TestHelpers.InMethod(); | ||
222 | // log4net.Config.XmlConfigurator.Configure(); | ||
223 | |||
224 | UUID userId = TestHelpers.ParseTail(0x1); | ||
225 | UUID attItemId = TestHelpers.ParseTail(0x2); | ||
226 | UUID attAssetId = TestHelpers.ParseTail(0x3); | ||
227 | string attName = "att"; | ||
228 | |||
229 | UserAccountHelpers.CreateUserWithInventory(scene, userId); | ||
230 | InventoryItemBase attItem | ||
231 | = UserInventoryHelpers.CreateInventoryItem( | ||
232 | scene, attName, attItemId, attAssetId, userId, InventoryType.Object); | ||
233 | |||
234 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | ||
235 | acd.Appearance = new AvatarAppearance(); | ||
236 | acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); | ||
237 | ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); | ||
238 | |||
239 | Assert.That(presence.HasAttachments(), Is.True); | ||
240 | List<SceneObjectGroup> attachments = presence.GetAttachments(); | ||
241 | |||
242 | Assert.That(attachments.Count, Is.EqualTo(1)); | ||
243 | SceneObjectGroup attSo = attachments[0]; | ||
244 | Assert.That(attSo.Name, Is.EqualTo(attName)); | ||
245 | Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); | ||
246 | Assert.That(attSo.IsAttachment); | ||
247 | Assert.That(attSo.UsesPhysics, Is.False); | ||
248 | Assert.That(attSo.IsTemporary, Is.False); | ||
249 | } | ||
250 | |||
251 | // I'm commenting this test because scene setup NEEDS InventoryService to | ||
252 | // be non-null | ||
253 | //[Test] | ||
254 | // public void T032_CrossAttachments() | ||
255 | // { | ||
256 | // TestHelpers.InMethod(); | ||
257 | // | ||
258 | // ScenePresence presence = scene.GetScenePresence(agent1); | ||
259 | // ScenePresence presence2 = scene2.GetScenePresence(agent1); | ||
260 | // presence2.AddAttachment(sog1); | ||
261 | // presence2.AddAttachment(sog2); | ||
262 | // | ||
263 | // ISharedRegionModule serialiser = new SerialiserModule(); | ||
264 | // SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser); | ||
265 | // SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser); | ||
266 | // | ||
267 | // Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross"); | ||
268 | // | ||
269 | // //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful"); | ||
270 | // Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted"); | ||
271 | // Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects"); | ||
272 | // } | ||
273 | } | ||
274 | } \ No newline at end of file | ||