TextureDownloadModule.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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 OpenSim 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 libsecondlife;
  31. using libsecondlife.Packets;
  32. using Nini.Config;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.Environment.Interfaces;
  35. using OpenSim.Region.Environment.Scenes;
  36. namespace OpenSim.Region.Environment.Modules
  37. {
  38. public class TextureDownloadModule : IRegionModule
  39. {
  40. private Scene m_scene;
  41. private List<Scene> m_scenes = new List<Scene>();
  42. private Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>> ClientRequests =
  43. new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
  44. private BlockingQueue<TextureSender> QueueSenders = new BlockingQueue<TextureSender>();
  45. private Dictionary<LLUUID, List<LLUUID>> InProcess = new Dictionary<LLUUID, List<LLUUID>>();
  46. // private Thread m_thread;
  47. public TextureDownloadModule()
  48. {
  49. // m_thread = new Thread(new ThreadStart(ProcessTextureSenders));
  50. // m_thread.IsBackground = true;
  51. // m_thread.Start();
  52. }
  53. public void Initialise(Scene scene, IConfigSource config)
  54. {
  55. if (!m_scenes.Contains(scene))
  56. {
  57. m_scenes.Add(scene);
  58. m_scene = scene;
  59. m_scene.EventManager.OnNewClient += NewClient;
  60. }
  61. }
  62. public void PostInitialise()
  63. {
  64. }
  65. public void Close()
  66. {
  67. }
  68. public string Name
  69. {
  70. get { return "TextureDownloadModule"; }
  71. }
  72. public bool IsSharedModule
  73. {
  74. get { return true; }
  75. }
  76. public void NewClient(IClientAPI client)
  77. {
  78. /* lock (ClientRequests)
  79. {
  80. if (!ClientRequests.ContainsKey(client.AgentId))
  81. {
  82. ClientRequests.Add(client.AgentId, new Dictionary<LLUUID, AssetRequest>());
  83. InProcess.Add(client.AgentId, new List<LLUUID>());
  84. }
  85. }
  86. client.OnRequestTexture += TextureRequest;
  87. */
  88. }
  89. public void TextureCallback(LLUUID textureID, AssetBase asset)
  90. {
  91. lock (ClientRequests)
  92. {
  93. foreach (Dictionary<LLUUID, AssetRequest> reqList in ClientRequests.Values)
  94. {
  95. if (reqList.ContainsKey(textureID))
  96. {
  97. //check the texture isn't already in the process of being sent to the client.
  98. if (!InProcess[reqList[textureID].RequestUser.AgentId].Contains(textureID))
  99. {
  100. TextureSender sender = new TextureSender(reqList[textureID], asset);
  101. QueueSenders.Enqueue(sender);
  102. InProcess[reqList[textureID].RequestUser.AgentId].Add(textureID);
  103. reqList.Remove(textureID);
  104. }
  105. }
  106. }
  107. }
  108. }
  109. public void TextureRequest(Object sender, TextureRequestArgs e)
  110. {
  111. IClientAPI client = (IClientAPI) sender;
  112. if (!ClientRequests[client.AgentId].ContainsKey(e.RequestedAssetID))
  113. {
  114. lock (ClientRequests)
  115. {
  116. AssetRequest request = new AssetRequest(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
  117. ClientRequests[client.AgentId].Add(e.RequestedAssetID, request);
  118. }
  119. m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
  120. }
  121. }
  122. public void ProcessTextureSenders()
  123. {
  124. while (true)
  125. {
  126. TextureSender sender = QueueSenders.Dequeue();
  127. bool finished = sender.SendTexture();
  128. if (finished)
  129. {
  130. TextureSent(sender);
  131. }
  132. else
  133. {
  134. QueueSenders.Enqueue(sender);
  135. }
  136. }
  137. }
  138. private void TextureSent(TextureSender sender)
  139. {
  140. if (InProcess[sender.request.RequestUser.AgentId].Contains(sender.request.RequestAssetID))
  141. {
  142. InProcess[sender.request.RequestUser.AgentId].Remove(sender.request.RequestAssetID);
  143. }
  144. }
  145. public class TextureSender
  146. {
  147. public AssetRequest request;
  148. private int counter = 0;
  149. private AssetBase m_asset;
  150. public long DataPointer = 0;
  151. public int NumPackets = 0;
  152. public int PacketCounter = 0;
  153. public TextureSender(AssetRequest req, AssetBase asset)
  154. {
  155. request = req;
  156. m_asset = asset;
  157. if (asset.Data.LongLength > 600)
  158. {
  159. NumPackets = 2 + (int) (asset.Data.Length - 601)/1000;
  160. }
  161. else
  162. {
  163. NumPackets = 1;
  164. }
  165. PacketCounter = (int) req.PacketNumber;
  166. }
  167. public bool SendTexture()
  168. {
  169. SendPacket();
  170. counter++;
  171. if ((PacketCounter >= NumPackets) || counter > 100 || (NumPackets == 1) || (request.DiscardLevel == -1))
  172. {
  173. return true;
  174. }
  175. return false;
  176. }
  177. public void SendPacket()
  178. {
  179. AssetRequest req = request;
  180. if (PacketCounter == 0)
  181. {
  182. if (NumPackets == 1)
  183. {
  184. ImageDataPacket im = new ImageDataPacket();
  185. im.Header.Reliable = false;
  186. im.ImageID.Packets = 1;
  187. im.ImageID.ID = m_asset.FullID;
  188. im.ImageID.Size = (uint) m_asset.Data.Length;
  189. im.ImageData.Data = m_asset.Data;
  190. im.ImageID.Codec = 2;
  191. req.RequestUser.OutPacket(im);
  192. PacketCounter++;
  193. }
  194. else
  195. {
  196. ImageDataPacket im = new ImageDataPacket();
  197. im.Header.Reliable = false;
  198. im.ImageID.Packets = (ushort) (NumPackets);
  199. im.ImageID.ID = m_asset.FullID;
  200. im.ImageID.Size = (uint) m_asset.Data.Length;
  201. im.ImageData.Data = new byte[600];
  202. Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600);
  203. im.ImageID.Codec = 2;
  204. req.RequestUser.OutPacket(im);
  205. PacketCounter++;
  206. }
  207. }
  208. else
  209. {
  210. ImagePacketPacket im = new ImagePacketPacket();
  211. im.Header.Reliable = false;
  212. im.ImageID.Packet = (ushort) (PacketCounter);
  213. im.ImageID.ID = m_asset.FullID;
  214. int size = m_asset.Data.Length - 600 - (1000*(PacketCounter - 1));
  215. if (size > 1000) size = 1000;
  216. im.ImageData.Data = new byte[size];
  217. Array.Copy(m_asset.Data, 600 + (1000*(PacketCounter - 1)), im.ImageData.Data, 0, size);
  218. req.RequestUser.OutPacket(im);
  219. PacketCounter++;
  220. }
  221. }
  222. }
  223. public class AssetRequest
  224. {
  225. public IClientAPI RequestUser;
  226. public LLUUID RequestAssetID;
  227. public int DiscardLevel = -1;
  228. public uint PacketNumber = 0;
  229. public AssetRequest(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
  230. {
  231. RequestUser = client;
  232. RequestAssetID = textureID;
  233. DiscardLevel = discardLevel;
  234. PacketNumber = packetNumber;
  235. }
  236. }
  237. }
  238. }