AttachmentsModule.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using log4net;
  31. using Nini.Config;
  32. using OpenMetaverse;
  33. using OpenMetaverse.Packets;
  34. using OpenSim.Framework;
  35. using OpenSim.Region.Framework;
  36. using OpenSim.Region.Framework.Interfaces;
  37. using OpenSim.Region.Framework.Scenes;
  38. namespace OpenSim.Region.CoreModules.Avatar.Attachments
  39. {
  40. public class AttachmentsModule : IAttachmentsModule, IRegionModule
  41. {
  42. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. protected Scene m_scene = null;
  44. public void Initialise(Scene scene, IConfigSource source)
  45. {
  46. scene.RegisterModuleInterface<IAttachmentsModule>(this);
  47. m_scene = scene;
  48. }
  49. public void PostInitialise()
  50. {
  51. }
  52. public void Close()
  53. {
  54. }
  55. public string Name
  56. {
  57. get { return "Attachments Module"; }
  58. }
  59. public bool IsSharedModule
  60. {
  61. get { return false; }
  62. }
  63. public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent)
  64. {
  65. m_log.Debug("[ATTACHMENTS MODULE]: Invoking AttachObject");
  66. try
  67. {
  68. // If we can't take it, we can't attach it!
  69. SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID);
  70. if (part == null)
  71. return;
  72. if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId))
  73. return;
  74. // Calls attach with a Zero position
  75. if (AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false))
  76. {
  77. m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId);
  78. // Save avatar attachment information
  79. ScenePresence presence;
  80. if (m_scene.AvatarFactory != null && m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
  81. {
  82. m_log.Info(
  83. "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
  84. + ", AttachmentPoint: " + AttachmentPt);
  85. m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
  86. }
  87. }
  88. }
  89. catch (Exception e)
  90. {
  91. m_log.DebugFormat("[ATTACHMENTS MODULE]: exception upon Attach Object {0}", e);
  92. }
  93. }
  94. public bool AttachObject(
  95. IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent)
  96. {
  97. SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
  98. if (group != null)
  99. {
  100. if (m_scene.Permissions.CanTakeObject(group.UUID, remoteClient.AgentId))
  101. {
  102. // If the attachment point isn't the same as the one previously used
  103. // set it's offset position = 0 so that it appears on the attachment point
  104. // and not in a weird location somewhere unknown.
  105. if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
  106. {
  107. attachPos = Vector3.Zero;
  108. }
  109. // AttachmentPt 0 means the client chose to 'wear' the attachment.
  110. if (AttachmentPt == 0)
  111. {
  112. // Check object for stored attachment point
  113. AttachmentPt = (uint)group.GetAttachmentPoint();
  114. }
  115. // if we still didn't find a suitable attachment point.......
  116. if (AttachmentPt == 0)
  117. {
  118. // Stick it on left hand with Zero Offset from the attachment point.
  119. AttachmentPt = (uint)AttachmentPoint.LeftHand;
  120. attachPos = Vector3.Zero;
  121. }
  122. group.SetAttachmentPoint((byte)AttachmentPt);
  123. group.AbsolutePosition = attachPos;
  124. // Saves and gets itemID
  125. UUID itemId;
  126. if (group.GetFromItemID() == UUID.Zero)
  127. {
  128. m_scene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId);
  129. }
  130. else
  131. {
  132. itemId = group.GetFromItemID();
  133. }
  134. SetAttachmentInventoryStatus(remoteClient, AttachmentPt, itemId, group);
  135. group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent);
  136. // In case it is later dropped again, don't let
  137. // it get cleaned up
  138. group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
  139. group.HasGroupChanged = false;
  140. }
  141. else
  142. {
  143. remoteClient.SendAgentAlertMessage(
  144. "You don't have sufficient permissions to attach this object", false);
  145. return false;
  146. }
  147. }
  148. else
  149. {
  150. m_log.DebugFormat("[ATTACHMENTS MODULE]: AttachObject found no such scene object {0}", objectLocalID);
  151. return false;
  152. }
  153. return true;
  154. }
  155. public void RezMultipleAttachmentsFromInventory(
  156. IClientAPI remoteClient,
  157. RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header,
  158. RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects)
  159. {
  160. foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects)
  161. {
  162. RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt);
  163. }
  164. }
  165. public UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
  166. {
  167. m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name);
  168. return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true);
  169. }
  170. public UUID RezSingleAttachmentFromInventory(
  171. IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus)
  172. {
  173. SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt);
  174. if (updateInventoryStatus)
  175. {
  176. if (att == null)
  177. {
  178. ShowDetachInUserInventory(itemID, remoteClient);
  179. }
  180. SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt);
  181. }
  182. if (null == att)
  183. return UUID.Zero;
  184. else
  185. return att.UUID;
  186. }
  187. protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
  188. IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
  189. {
  190. IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
  191. if (invAccess != null)
  192. {
  193. SceneObjectGroup objatt = invAccess.RezObject(remoteClient,
  194. itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
  195. false, false, remoteClient.AgentId, true);
  196. // m_log.DebugFormat(
  197. // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
  198. // objatt.Name, remoteClient.Name, AttachmentPt);
  199. if (objatt != null)
  200. {
  201. bool tainted = false;
  202. if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint())
  203. tainted = true;
  204. AttachObject(
  205. remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false);
  206. //objatt.ScheduleGroupForFullUpdate();
  207. if (tainted)
  208. objatt.HasGroupChanged = true;
  209. // Fire after attach, so we don't get messy perms dialogs
  210. // 3 == AttachedRez
  211. objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 3);
  212. objatt.ResumeScripts();
  213. // Do this last so that event listeners have access to all the effects of the attachment
  214. m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId);
  215. }
  216. else
  217. {
  218. m_log.WarnFormat(
  219. "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
  220. itemID, remoteClient.Name, AttachmentPt);
  221. }
  222. return objatt;
  223. }
  224. return null;
  225. }
  226. public UUID SetAttachmentInventoryStatus(
  227. SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
  228. {
  229. m_log.DebugFormat(
  230. "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})",
  231. remoteClient.Name, att.Name, itemID);
  232. if (!att.IsDeleted)
  233. AttachmentPt = att.RootPart.AttachmentPoint;
  234. ScenePresence presence;
  235. if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
  236. {
  237. InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
  238. item = m_scene.InventoryService.GetItem(item);
  239. presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/);
  240. }
  241. return att.UUID;
  242. }
  243. /// <summary>
  244. /// Update the user inventory to reflect an attachment
  245. /// </summary>
  246. /// <param name="remoteClient"></param>
  247. /// <param name="AttachmentPt"></param>
  248. /// <param name="itemID"></param>
  249. /// <param name="att"></param>
  250. public void SetAttachmentInventoryStatus(
  251. IClientAPI remoteClient, uint AttachmentPt, UUID itemID, SceneObjectGroup att)
  252. {
  253. // m_log.DebugFormat(
  254. // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}",
  255. // att.Name, remoteClient.Name, AttachmentPt, itemID);
  256. if (UUID.Zero == itemID)
  257. {
  258. m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID.");
  259. return;
  260. }
  261. if (0 == AttachmentPt)
  262. {
  263. m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point.");
  264. return;
  265. }
  266. if (null == att.RootPart)
  267. {
  268. m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment for a prim without the rootpart!");
  269. return;
  270. }
  271. ScenePresence presence;
  272. if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
  273. {
  274. // XXYY!!
  275. InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
  276. item = m_scene.InventoryService.GetItem(item);
  277. presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */);
  278. if (m_scene.AvatarFactory != null)
  279. m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
  280. }
  281. }
  282. public void DetachObject(uint objectLocalID, IClientAPI remoteClient)
  283. {
  284. SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
  285. if (group != null)
  286. {
  287. //group.DetachToGround();
  288. ShowDetachInUserInventory(group.GetFromItemID(), remoteClient);
  289. }
  290. }
  291. public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient)
  292. {
  293. ScenePresence presence;
  294. if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
  295. {
  296. presence.Appearance.DetachAttachment(itemID);
  297. // Save avatar attachment information
  298. if (m_scene.AvatarFactory != null)
  299. {
  300. m_log.Debug("[ATTACHMENTS MODULE]: Dettaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID);
  301. m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
  302. }
  303. }
  304. DetachSingleAttachmentToInv(itemID, remoteClient);
  305. }
  306. public void DetachSingleAttachmentToGround(UUID itemID, IClientAPI remoteClient)
  307. {
  308. SceneObjectPart part = m_scene.GetSceneObjectPart(itemID);
  309. if (part == null || part.ParentGroup == null)
  310. return;
  311. UUID inventoryID = part.ParentGroup.GetFromItemID();
  312. ScenePresence presence;
  313. if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence))
  314. {
  315. if (!m_scene.Permissions.CanRezObject(
  316. part.ParentGroup.Children.Count, remoteClient.AgentId, presence.AbsolutePosition))
  317. return;
  318. presence.Appearance.DetachAttachment(itemID);
  319. if (m_scene.AvatarFactory != null)
  320. {
  321. m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
  322. }
  323. part.ParentGroup.DetachToGround();
  324. List<UUID> uuids = new List<UUID>();
  325. uuids.Add(inventoryID);
  326. m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids);
  327. remoteClient.SendRemoveInventoryItem(inventoryID);
  328. }
  329. m_scene.EventManager.TriggerOnAttach(part.ParentGroup.LocalId, itemID, UUID.Zero);
  330. }
  331. // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards.
  332. // To LocalId or UUID, *THAT* is the question. How now Brown UUID??
  333. protected void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient)
  334. {
  335. if (itemID == UUID.Zero) // If this happened, someone made a mistake....
  336. return;
  337. // We can NOT use the dictionries here, as we are looking
  338. // for an entity by the fromAssetID, which is NOT the prim UUID
  339. List<EntityBase> detachEntities = m_scene.GetEntities();
  340. SceneObjectGroup group;
  341. foreach (EntityBase entity in detachEntities)
  342. {
  343. if (entity is SceneObjectGroup)
  344. {
  345. group = (SceneObjectGroup)entity;
  346. if (group.GetFromItemID() == itemID)
  347. {
  348. m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
  349. group.DetachToInventoryPrep();
  350. m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
  351. m_scene.UpdateKnownItem(remoteClient, group,group.GetFromItemID(), group.OwnerID);
  352. m_scene.DeleteSceneObject(group, false);
  353. return;
  354. }
  355. }
  356. }
  357. }
  358. }
  359. }