aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Caches/AssetCache.cs
diff options
context:
space:
mode:
authorMW2007-06-27 15:28:52 +0000
committerMW2007-06-27 15:28:52 +0000
commit646bbbc84b8010e0dacbeed5342cdb045f46cc49 (patch)
tree770b34d19855363c3c113ab9a0af9a56d821d887 /OpenSim/Region/Caches/AssetCache.cs
downloadopensim-SC_OLD-646bbbc84b8010e0dacbeed5342cdb045f46cc49.zip
opensim-SC_OLD-646bbbc84b8010e0dacbeed5342cdb045f46cc49.tar.gz
opensim-SC_OLD-646bbbc84b8010e0dacbeed5342cdb045f46cc49.tar.bz2
opensim-SC_OLD-646bbbc84b8010e0dacbeed5342cdb045f46cc49.tar.xz
Some work on restructuring the namespaces / project names. Note this doesn't compile yet as not all the code has been changed to use the new namespaces. Am committing it now for feedback on the namespaces.
Diffstat (limited to 'OpenSim/Region/Caches/AssetCache.cs')
-rw-r--r--OpenSim/Region/Caches/AssetCache.cs670
1 files changed, 670 insertions, 0 deletions
diff --git a/OpenSim/Region/Caches/AssetCache.cs b/OpenSim/Region/Caches/AssetCache.cs
new file mode 100644
index 0000000..d0cc370
--- /dev/null
+++ b/OpenSim/Region/Caches/AssetCache.cs
@@ -0,0 +1,670 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.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
29using System;
30using System.Collections.Generic;
31using System.Threading;
32using System.Reflection;
33using libsecondlife;
34using libsecondlife.Packets;
35using OpenSim.Framework.Interfaces;
36using OpenSim.Framework.Types;
37using OpenSim.Framework.Utilities;
38
39namespace OpenSim.Caches
40{
41 public delegate void DownloadComplete(AssetCache.TextureSender sender);
42
43 /// <summary>
44 /// Manages local cache of assets and their sending to viewers.
45 /// </summary>
46 public class AssetCache : IAssetReceiver
47 {
48 public Dictionary<libsecondlife.LLUUID, AssetInfo> Assets;
49 public Dictionary<libsecondlife.LLUUID, TextureImage> Textures;
50
51 public List<AssetRequest> AssetRequests = new List<AssetRequest>(); //assets ready to be sent to viewers
52 public List<AssetRequest> TextureRequests = new List<AssetRequest>(); //textures ready to be sent
53
54 public Dictionary<LLUUID, AssetRequest> RequestedAssets = new Dictionary<LLUUID, AssetRequest>(); //Assets requested from the asset server
55 public Dictionary<LLUUID, AssetRequest> RequestedTextures = new Dictionary<LLUUID, AssetRequest>(); //Textures requested from the asset server
56
57 public Dictionary<LLUUID, TextureSender> SendingTextures = new Dictionary<LLUUID, TextureSender>();
58 private IAssetServer _assetServer;
59 private Thread _assetCacheThread;
60 private LLUUID[] textureList = new LLUUID[5];
61
62 /// <summary>
63 ///
64 /// </summary>
65 public AssetCache(IAssetServer assetServer)
66 {
67 Console.WriteLine("Creating Asset cache");
68 _assetServer = assetServer;
69 _assetServer.SetReceiver(this);
70 Assets = new Dictionary<libsecondlife.LLUUID, AssetInfo>();
71 Textures = new Dictionary<libsecondlife.LLUUID, TextureImage>();
72 this._assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
73 this._assetCacheThread.IsBackground = true;
74 this._assetCacheThread.Start();
75
76 }
77
78 public AssetCache(string assetServerDLLName, string assetServerURL, string assetServerKey)
79 {
80 Console.WriteLine("Creating Asset cache");
81 _assetServer = this.LoadAssetDll(assetServerDLLName);
82 _assetServer.SetServerInfo(assetServerURL, assetServerKey);
83 _assetServer.SetReceiver(this);
84 Assets = new Dictionary<libsecondlife.LLUUID, AssetInfo>();
85 Textures = new Dictionary<libsecondlife.LLUUID, TextureImage>();
86 this._assetCacheThread = new Thread(new ThreadStart(RunAssetManager));
87 this._assetCacheThread.IsBackground = true;
88 this._assetCacheThread.Start();
89
90 }
91
92 /// <summary>
93 ///
94 /// </summary>
95 public void RunAssetManager()
96 {
97 while (true)
98 {
99 try
100 {
101 //Console.WriteLine("Asset cache loop");
102 this.ProcessAssetQueue();
103 this.ProcessTextureQueue();
104 Thread.Sleep(500);
105 }
106 catch (Exception e)
107 {
108 Console.WriteLine(e.Message);
109 }
110 }
111 }
112
113 public void LoadDefaultTextureSet()
114 {
115 //hack: so we can give each user a set of textures
116 textureList[0] = new LLUUID("00000000-0000-0000-9999-000000000001");
117 textureList[1] = new LLUUID("00000000-0000-0000-9999-000000000002");
118 textureList[2] = new LLUUID("00000000-0000-0000-9999-000000000003");
119 textureList[3] = new LLUUID("00000000-0000-0000-9999-000000000004");
120 textureList[4] = new LLUUID("00000000-0000-0000-9999-000000000005");
121
122 for (int i = 0; i < textureList.Length; i++)
123 {
124 this._assetServer.RequestAsset(textureList[i], true);
125 }
126
127 }
128
129 public AssetBase[] CreateNewInventorySet(LLUUID agentID)
130 {
131 AssetBase[] inventorySet = new AssetBase[this.textureList.Length];
132 for (int i = 0; i < textureList.Length; i++)
133 {
134 if (this.Textures.ContainsKey(textureList[i]))
135 {
136 inventorySet[i] = this.CloneImage(agentID, this.Textures[textureList[i]]);
137 TextureImage image = new TextureImage(inventorySet[i]);
138 this.Textures.Add(image.FullID, image);
139 this._assetServer.UploadNewAsset(image); //save the asset to the asset server
140 }
141 }
142 return inventorySet;
143 }
144
145 public AssetBase GetAsset(LLUUID assetID)
146 {
147 AssetBase asset = null;
148 if (this.Textures.ContainsKey(assetID))
149 {
150 asset = this.Textures[assetID];
151 }
152 else if (this.Assets.ContainsKey(assetID))
153 {
154 asset = this.Assets[assetID];
155 }
156 return asset;
157 }
158
159 public void AddAsset(AssetBase asset)
160 {
161 // Console.WriteLine("adding asset " + asset.FullID.ToStringHyphenated());
162 if (asset.Type == 0)
163 {
164 //Console.WriteLine("which is a texture");
165 if (!this.Textures.ContainsKey(asset.FullID))
166 { //texture
167 TextureImage textur = new TextureImage(asset);
168 this.Textures.Add(textur.FullID, textur);
169 this._assetServer.UploadNewAsset(asset);
170 }
171 }
172 else
173 {
174 if (!this.Assets.ContainsKey(asset.FullID))
175 {
176 AssetInfo assetInf = new AssetInfo(asset);
177 this.Assets.Add(assetInf.FullID, assetInf);
178 this._assetServer.UploadNewAsset(asset);
179 }
180 }
181 }
182
183 /// <summary>
184 ///
185 /// </summary>
186 private void ProcessTextureQueue()
187 {
188 if (this.TextureRequests.Count == 0)
189 {
190 //no requests waiting
191 return;
192 }
193 int num;
194 num = this.TextureRequests.Count;
195
196 AssetRequest req;
197 for (int i = 0; i < num; i++)
198 {
199 req = (AssetRequest)this.TextureRequests[i];
200 if (!this.SendingTextures.ContainsKey(req.ImageInfo.FullID))
201 {
202 TextureSender sender = new TextureSender(req);
203 sender.OnComplete += this.TextureSent;
204 lock (this.SendingTextures)
205 {
206 this.SendingTextures.Add(req.ImageInfo.FullID, sender);
207 }
208 }
209
210 }
211
212 this.TextureRequests.Clear();
213 }
214
215 /// <summary>
216 /// Event handler, called by a TextureSender object to say that texture has been sent
217 /// </summary>
218 /// <param name="sender"></param>
219 public void TextureSent(AssetCache.TextureSender sender)
220 {
221 if (this.SendingTextures.ContainsKey(sender.request.ImageInfo.FullID))
222 {
223 lock (this.SendingTextures)
224 {
225 this.SendingTextures.Remove(sender.request.ImageInfo.FullID);
226 }
227 }
228 }
229
230 public void AssetReceived(AssetBase asset, bool IsTexture)
231 {
232 if (asset.FullID != LLUUID.Zero) // if it is set to zero then the asset wasn't found by the server
233 {
234 //check if it is a texture or not
235 //then add to the correct cache list
236 //then check for waiting requests for this asset/texture (in the Requested lists)
237 //and move those requests into the Requests list.
238 if (IsTexture)
239 {
240 TextureImage image = new TextureImage(asset);
241 this.Textures.Add(image.FullID, image);
242 if (this.RequestedTextures.ContainsKey(image.FullID))
243 {
244 AssetRequest req = this.RequestedTextures[image.FullID];
245 req.ImageInfo = image;
246 if (image.Data.LongLength > 600)
247 {
248 //over 600 bytes so split up file
249 req.NumPackets = 1 + (int)(image.Data.Length - 600 + 999) / 1000;
250 }
251 else
252 {
253 req.NumPackets = 1;
254 }
255 this.RequestedTextures.Remove(image.FullID);
256 this.TextureRequests.Add(req);
257 }
258 }
259 else
260 {
261 AssetInfo assetInf = new AssetInfo(asset);
262 this.Assets.Add(assetInf.FullID, assetInf);
263 if (this.RequestedAssets.ContainsKey(assetInf.FullID))
264 {
265 AssetRequest req = this.RequestedAssets[assetInf.FullID];
266 req.AssetInf = assetInf;
267 if (assetInf.Data.LongLength > 600)
268 {
269 //over 600 bytes so split up file
270 req.NumPackets = 1 + (int)(assetInf.Data.Length - 600 + 999) / 1000;
271 }
272 else
273 {
274 req.NumPackets = 1;
275 }
276 this.RequestedAssets.Remove(assetInf.FullID);
277 this.AssetRequests.Add(req);
278 }
279 }
280 }
281 }
282
283 public void AssetNotFound(AssetBase asset)
284 {
285 //the asset server had no knowledge of requested asset
286
287 }
288
289 #region Assets
290 /// <summary>
291 ///
292 /// </summary>
293 /// <param name="userInfo"></param>
294 /// <param name="transferRequest"></param>
295 public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
296 {
297 LLUUID requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
298 //check to see if asset is in local cache, if not we need to request it from asset server.
299
300 if (!this.Assets.ContainsKey(requestID))
301 {
302 //not found asset
303 // so request from asset server
304 if (!this.RequestedAssets.ContainsKey(requestID))
305 {
306 AssetRequest request = new AssetRequest();
307 request.RequestUser = userInfo;
308 request.RequestAssetID = requestID;
309 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
310 this.RequestedAssets.Add(requestID, request);
311 this._assetServer.RequestAsset(requestID, false);
312 }
313 return;
314 }
315 //it is in our cache
316 AssetInfo asset = this.Assets[requestID];
317
318 //work out how many packets it should be sent in
319 // and add to the AssetRequests list
320 AssetRequest req = new AssetRequest();
321 req.RequestUser = userInfo;
322 req.RequestAssetID = requestID;
323 req.TransferRequestID = transferRequest.TransferInfo.TransferID;
324 req.AssetInf = asset;
325
326 if (asset.Data.LongLength > 600)
327 {
328 //over 600 bytes so split up file
329 req.NumPackets = 1 + (int)(asset.Data.Length - 600 + 999) / 1000;
330 }
331 else
332 {
333 req.NumPackets = 1;
334 }
335
336 this.AssetRequests.Add(req);
337 }
338
339 /// <summary>
340 ///
341 /// </summary>
342 private void ProcessAssetQueue()
343 {
344 if (this.AssetRequests.Count == 0)
345 {
346 //no requests waiting
347 return;
348 }
349 int num;
350
351 if (this.AssetRequests.Count < 5)
352 {
353 //lower than 5 so do all of them
354 num = this.AssetRequests.Count;
355 }
356 else
357 {
358 num = 5;
359 }
360 AssetRequest req;
361 for (int i = 0; i < num; i++)
362 {
363 req = (AssetRequest)this.AssetRequests[i];
364
365 TransferInfoPacket Transfer = new TransferInfoPacket();
366 Transfer.TransferInfo.ChannelType = 2;
367 Transfer.TransferInfo.Status = 0;
368 Transfer.TransferInfo.TargetType = 0;
369 Transfer.TransferInfo.Params = req.RequestAssetID.GetBytes();
370 Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
371 Transfer.TransferInfo.TransferID = req.TransferRequestID;
372 req.RequestUser.OutPacket(Transfer);
373
374 if (req.NumPackets == 1)
375 {
376 TransferPacketPacket TransferPacket = new TransferPacketPacket();
377 TransferPacket.TransferData.Packet = 0;
378 TransferPacket.TransferData.ChannelType = 2;
379 TransferPacket.TransferData.TransferID = req.TransferRequestID;
380 TransferPacket.TransferData.Data = req.AssetInf.Data;
381 TransferPacket.TransferData.Status = 1;
382 req.RequestUser.OutPacket(TransferPacket);
383 }
384 else
385 {
386 //more than one packet so split file up , for now it can't be bigger than 2000 bytes
387 TransferPacketPacket TransferPacket = new TransferPacketPacket();
388 TransferPacket.TransferData.Packet = 0;
389 TransferPacket.TransferData.ChannelType = 2;
390 TransferPacket.TransferData.TransferID = req.TransferRequestID;
391 byte[] chunk = new byte[1000];
392 Array.Copy(req.AssetInf.Data, chunk, 1000);
393 TransferPacket.TransferData.Data = chunk;
394 TransferPacket.TransferData.Status = 0;
395 req.RequestUser.OutPacket(TransferPacket);
396
397 TransferPacket = new TransferPacketPacket();
398 TransferPacket.TransferData.Packet = 1;
399 TransferPacket.TransferData.ChannelType = 2;
400 TransferPacket.TransferData.TransferID = req.TransferRequestID;
401 byte[] chunk1 = new byte[(req.AssetInf.Data.Length - 1000)];
402 Array.Copy(req.AssetInf.Data, 1000, chunk1, 0, chunk1.Length);
403 TransferPacket.TransferData.Data = chunk1;
404 TransferPacket.TransferData.Status = 1;
405 req.RequestUser.OutPacket(TransferPacket);
406 }
407
408 }
409
410 //remove requests that have been completed
411 for (int i = 0; i < num; i++)
412 {
413 this.AssetRequests.RemoveAt(0);
414 }
415
416 }
417
418 public AssetInfo CloneAsset(LLUUID newOwner, AssetInfo sourceAsset)
419 {
420 AssetInfo newAsset = new AssetInfo();
421 newAsset.Data = new byte[sourceAsset.Data.Length];
422 Array.Copy(sourceAsset.Data, newAsset.Data, sourceAsset.Data.Length);
423 newAsset.FullID = LLUUID.Random();
424 newAsset.Type = sourceAsset.Type;
425 newAsset.InvType = sourceAsset.InvType;
426 return (newAsset);
427 }
428 #endregion
429
430 #region Textures
431 /// <summary>
432 ///
433 /// </summary>
434 /// <param name="userInfo"></param>
435 /// <param name="imageID"></param>
436 public void AddTextureRequest(IClientAPI userInfo, LLUUID imageID)
437 {
438 //Console.WriteLine("texture request for " + imageID.ToStringHyphenated());
439 //check to see if texture is in local cache, if not request from asset server
440 if (!this.Textures.ContainsKey(imageID))
441 {
442 if (!this.RequestedTextures.ContainsKey(imageID))
443 {
444 //not is cache so request from asset server
445 AssetRequest request = new AssetRequest();
446 request.RequestUser = userInfo;
447 request.RequestAssetID = imageID;
448 request.IsTextureRequest = true;
449 this.RequestedTextures.Add(imageID, request);
450 this._assetServer.RequestAsset(imageID, true);
451 }
452 return;
453 }
454
455 //Console.WriteLine("texture already in cache");
456 TextureImage imag = this.Textures[imageID];
457 AssetRequest req = new AssetRequest();
458 req.RequestUser = userInfo;
459 req.RequestAssetID = imageID;
460 req.IsTextureRequest = true;
461 req.ImageInfo = imag;
462
463 if (imag.Data.LongLength > 600)
464 {
465 //over 600 bytes so split up file
466 req.NumPackets = 1 + (int)(imag.Data.Length - 600 + 999) / 1000;
467 }
468 else
469 {
470 req.NumPackets = 1;
471 }
472 this.TextureRequests.Add(req);
473 }
474
475 public TextureImage CloneImage(LLUUID newOwner, TextureImage source)
476 {
477 TextureImage newImage = new TextureImage();
478 newImage.Data = new byte[source.Data.Length];
479 Array.Copy(source.Data, newImage.Data, source.Data.Length);
480 //newImage.filename = source.filename;
481 newImage.FullID = LLUUID.Random();
482 newImage.Name = source.Name;
483 return (newImage);
484 }
485 #endregion
486
487 private IAssetServer LoadAssetDll(string dllName)
488 {
489 Assembly pluginAssembly = Assembly.LoadFrom(dllName);
490 IAssetServer server = null;
491
492 foreach (Type pluginType in pluginAssembly.GetTypes())
493 {
494 if (pluginType.IsPublic)
495 {
496 if (!pluginType.IsAbstract)
497 {
498 Type typeInterface = pluginType.GetInterface("IAssetPlugin", true);
499
500 if (typeInterface != null)
501 {
502 IAssetPlugin plug = (IAssetPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
503 server = plug.GetAssetServer();
504 break;
505 }
506
507 typeInterface = null;
508 }
509 }
510 }
511 pluginAssembly = null;
512 return server;
513 }
514
515 public class AssetRequest
516 {
517 public IClientAPI RequestUser;
518 public LLUUID RequestAssetID;
519 public AssetInfo AssetInf;
520 public TextureImage ImageInfo;
521 public LLUUID TransferRequestID;
522 public long DataPointer = 0;
523 public int NumPackets = 0;
524 public int PacketCounter = 0;
525 public bool IsTextureRequest;
526 //public bool AssetInCache;
527 //public int TimeRequested;
528
529 public AssetRequest()
530 {
531
532 }
533 }
534
535 public class AssetInfo : AssetBase
536 {
537 public AssetInfo()
538 {
539
540 }
541
542 public AssetInfo(AssetBase aBase)
543 {
544 Data = aBase.Data;
545 FullID = aBase.FullID;
546 Type = aBase.Type;
547 InvType = aBase.InvType;
548 Name = aBase.Name;
549 Description = aBase.Description;
550 }
551 }
552
553 public class TextureImage : AssetBase
554 {
555 public TextureImage()
556 {
557
558 }
559
560 public TextureImage(AssetBase aBase)
561 {
562 Data = aBase.Data;
563 FullID = aBase.FullID;
564 Type = aBase.Type;
565 InvType = aBase.InvType;
566 Name = aBase.Name;
567 Description = aBase.Description;
568 }
569 }
570
571 public class TextureSender
572 {
573 public AssetRequest request;
574 public event DownloadComplete OnComplete;
575 Thread m_thread;
576 public TextureSender(AssetRequest req)
577 {
578 request = req;
579 //Console.WriteLine("creating worker thread for texture " + req.ImageInfo.FullID.ToStringHyphenated());
580 //Console.WriteLine("texture data length is " + req.ImageInfo.Data.Length);
581 // Console.WriteLine("in " + req.NumPackets + " packets");
582 //ThreadPool.QueueUserWorkItem(new WaitCallback(SendTexture), new object());
583
584 //need some sort of custom threadpool here, as using the .net one, overloads it and stops the handling of incoming packets etc
585 //but don't really want to create a thread for every texture download
586 m_thread = new Thread(new ThreadStart(SendTexture));
587 m_thread.IsBackground = true;
588 m_thread.Start();
589 }
590
591 public void SendTexture()
592 {
593 //Console.WriteLine("starting to send sending texture " + request.ImageInfo.FullID.ToStringHyphenated());
594 while (request.PacketCounter != request.NumPackets)
595 {
596 SendPacket();
597 Thread.Sleep(500);
598 }
599
600 //Console.WriteLine("finished sending texture " + request.ImageInfo.FullID.ToStringHyphenated());
601 if (OnComplete != null)
602 {
603 OnComplete(this);
604 }
605 }
606
607 public void SendPacket()
608 {
609 AssetRequest req = request;
610 // Console.WriteLine("sending " + req.ImageInfo.FullID);
611
612 // if (req.ImageInfo.FullID == new LLUUID("00000000-0000-0000-5005-000000000005"))
613 if (req.PacketCounter == 0)
614 {
615 //first time for this request so send imagedata packet
616 if (req.NumPackets == 1)
617 {
618 //only one packet so send whole file
619 ImageDataPacket im = new ImageDataPacket();
620 im.ImageID.Packets = 1;
621 im.ImageID.ID = req.ImageInfo.FullID;
622 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
623 im.ImageData.Data = req.ImageInfo.Data;
624 im.ImageID.Codec = 2;
625 req.RequestUser.OutPacket(im);
626 req.PacketCounter++;
627 //req.ImageInfo.l= time;
628 //System.Console.WriteLine("sent texture: " + req.ImageInfo.FullID);
629 // Console.WriteLine("sending packet 1 for " + req.ImageInfo.FullID.ToStringHyphenated());
630 }
631 else
632 {
633 //more than one packet so split file up
634 ImageDataPacket im = new ImageDataPacket();
635 im.ImageID.Packets = (ushort)req.NumPackets;
636 im.ImageID.ID = req.ImageInfo.FullID;
637 im.ImageID.Size = (uint)req.ImageInfo.Data.Length;
638 im.ImageData.Data = new byte[600];
639 Array.Copy(req.ImageInfo.Data, 0, im.ImageData.Data, 0, 600);
640 im.ImageID.Codec = 2;
641 req.RequestUser.OutPacket(im);
642 req.PacketCounter++;
643 //req.ImageInfo.last_used = time;
644 //System.Console.WriteLine("sent first packet of texture:
645 // Console.WriteLine("sending packet 1 for " + req.ImageInfo.FullID.ToStringHyphenated());
646 }
647 }
648 else
649 {
650 //Console.WriteLine("sending packet" + req.PacketCounter + "for " + req.ImageInfo.FullID.ToStringHyphenated());
651 //send imagepacket
652 //more than one packet so split file up
653 ImagePacketPacket im = new ImagePacketPacket();
654 im.ImageID.Packet = (ushort)req.PacketCounter;
655 im.ImageID.ID = req.ImageInfo.FullID;
656 int size = req.ImageInfo.Data.Length - 600 - 1000 * (req.PacketCounter - 1);
657 if (size > 1000) size = 1000;
658 im.ImageData.Data = new byte[size];
659 Array.Copy(req.ImageInfo.Data, 600 + 1000 * (req.PacketCounter - 1), im.ImageData.Data, 0, size);
660 req.RequestUser.OutPacket(im);
661 req.PacketCounter++;
662 //req.ImageInfo.last_used = time;
663 //System.Console.WriteLine("sent a packet of texture: "+req.image_info.FullID);
664 }
665
666 }
667 }
668 }
669}
670