aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim.RegionServer/SimClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim.RegionServer/SimClient.cs')
-rw-r--r--OpenSim.RegionServer/SimClient.cs662
1 files changed, 0 insertions, 662 deletions
diff --git a/OpenSim.RegionServer/SimClient.cs b/OpenSim.RegionServer/SimClient.cs
deleted file mode 100644
index 3b243cf..0000000
--- a/OpenSim.RegionServer/SimClient.cs
+++ /dev/null
@@ -1,662 +0,0 @@
1/*
2Copyright (c) OpenSim project, http://osgrid.org/
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are met:
6* * Redistributions of source code must retain the above copyright
7* notice, this list of conditions and the following disclaimer.
8* * Redistributions in binary form must reproduce the above copyright
9* notice, this list of conditions and the following disclaimer in the
10* documentation and/or other materials provided with the distribution.
11* * Neither the name of the <organization> nor the
12* names of its contributors may be used to endorse or promote products
13* derived from this software without specific prior written permission.
14*
15* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
16* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
19* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*/
26
27using System;
28using System.Collections;
29using System.Collections.Generic;
30using libsecondlife;
31using libsecondlife.Packets;
32using Nwc.XmlRpc;
33using System.Net;
34using System.Net.Sockets;
35using System.IO;
36using System.Threading;
37using System.Timers;
38using OpenSim.Framework.Interfaces;
39using OpenSim.Framework.Types;
40using OpenSim.Framework.Inventory;
41using OpenSim.Framework.Utilities;
42using OpenSim.world;
43using OpenSim.Assets;
44
45namespace OpenSim
46{
47 public delegate bool PacketMethod(SimClient simClient, Packet packet);
48
49 /// <summary>
50 /// Handles new client connections
51 /// Constructor takes a single Packet and authenticates everything
52 /// </summary>
53 public partial class SimClient
54 {
55 public LLUUID AgentID;
56 public LLUUID SessionID;
57 public LLUUID SecureSessionID = LLUUID.Zero;
58 public bool m_child;
59 public uint CircuitCode;
60 public world.Avatar ClientAvatar;
61 private UseCircuitCodePacket cirpack;
62 public Thread ClientThread;
63 public EndPoint userEP;
64 public LLVector3 startpos;
65 private BlockingQueue<QueItem> PacketQueue;
66 private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
67 private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
68 //private Dictionary<LLUUID, AssetBase> UploadedAssets = new Dictionary<LLUUID, AssetBase>();
69 private System.Timers.Timer AckTimer;
70 private uint Sequence = 0;
71 private object SequenceLock = new object();
72 private const int MAX_APPENDED_ACKS = 10;
73 private const int RESEND_TIMEOUT = 4000;
74 private const int MAX_SEQUENCE = 0xFFFFFF;
75 private AgentAssetUpload UploadAssets;
76 private LLUUID newAssetFolder = LLUUID.Zero;
77 private bool debug = false;
78 private World m_world;
79 private Dictionary<uint, SimClient> m_clientThreads;
80 private AssetCache m_assetCache;
81 private IGridServer m_gridServer;
82 private IUserServer m_userServer = null;
83 private OpenSimNetworkHandler m_networkServer;
84 private InventoryCache m_inventoryCache;
85 public bool m_sandboxMode;
86 private int cachedtextureserial = 0;
87 private RegionInfo m_regionData;
88 protected AuthenticateSessionsBase m_authenticateSessionsHandler;
89
90 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
91
92 protected Dictionary<PacketType, PacketMethod> m_packetHandlers = new Dictionary<PacketType, PacketMethod>(); //local handlers for this instance
93
94 public IUserServer UserServer
95 {
96 set
97 {
98 this.m_userServer = value;
99 }
100 }
101
102 public SimClient(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, World world, Dictionary<uint, SimClient> clientThreads, AssetCache assetCache, IGridServer gridServer, OpenSimNetworkHandler application, InventoryCache inventoryCache, bool sandboxMode, bool child, RegionInfo regionDat, AuthenticateSessionsBase authenSessions)
103 {
104 m_world = world;
105 m_clientThreads = clientThreads;
106 m_assetCache = assetCache;
107 m_gridServer = gridServer;
108 m_networkServer = application;
109 m_inventoryCache = inventoryCache;
110 m_sandboxMode = sandboxMode;
111 m_child = child;
112 m_regionData = regionDat;
113 m_authenticateSessionsHandler = authenSessions;
114
115 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "OpenSimClient.cs - Started up new client thread to handle incoming request");
116 cirpack = initialcirpack;
117 userEP = remoteEP;
118
119 if (m_gridServer.GetName() == "Remote")
120 {
121 this.m_child = m_authenticateSessionsHandler.GetAgentChildStatus(initialcirpack.CircuitCode.Code);
122 this.startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code);
123 //Console.WriteLine("start pos is " + this.startpos.X + " , " + this.startpos.Y + " , " + this.startpos.Z);
124 }
125 else
126 {
127 this.startpos = new LLVector3(128, 128, m_world.Terrain[(int)128, (int)128] + 15.0f); // new LLVector3(128.0f, 128.0f, 60f);
128 }
129
130 PacketQueue = new BlockingQueue<QueItem>();
131
132 this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
133 AckTimer = new System.Timers.Timer(500);
134 AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
135 AckTimer.Start();
136
137 this.RegisterLocalPacketHandlers();
138
139 ClientThread = new Thread(new ThreadStart(AuthUser));
140 ClientThread.IsBackground = true;
141 ClientThread.Start();
142 }
143
144 # region Client Methods
145 public void UpgradeClient()
146 {
147 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "SimClient.cs:UpgradeClient() - upgrading child to full agent");
148 this.m_child = false;
149 this.m_world.RemoveViewerAgent(this);
150 if (!this.m_sandboxMode)
151 {
152 this.startpos = m_authenticateSessionsHandler.GetPosition(CircuitCode);
153 m_authenticateSessionsHandler.UpdateAgentChildStatus(CircuitCode, false);
154 //Console.WriteLine("upgrade start pos is " + this.startpos.X + " , " + this.startpos.Y + " , " + this.startpos.Z);
155 }
156 this.InitNewClient();
157 }
158
159 public void DowngradeClient()
160 {
161 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "SimClient.cs:UpgradeClient() - changing full agent to child");
162 this.m_child = true;
163 this.m_world.RemoveViewerAgent(this);
164 this.m_world.AddViewerAgent(this);
165 }
166
167 public void KillClient()
168 {
169 KillObjectPacket kill = new KillObjectPacket();
170 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
171 kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
172 kill.ObjectData[0].ID = this.ClientAvatar.localid;
173 foreach (SimClient client in m_clientThreads.Values)
174 {
175 client.OutPacket(kill);
176 }
177 if (this.m_userServer != null)
178 {
179 this.m_inventoryCache.ClientLeaving(this.AgentID, this.m_userServer);
180 }
181 else
182 {
183 this.m_inventoryCache.ClientLeaving(this.AgentID, null);
184 }
185
186 m_world.RemoveViewerAgent(this);
187
188 m_clientThreads.Remove(this.CircuitCode);
189 m_networkServer.RemoveClientCircuit(this.CircuitCode);
190 this.ClientThread.Abort();
191 }
192 #endregion
193
194 # region Packet Handling
195 public static bool AddPacketHandler(PacketType packetType, PacketMethod handler)
196 {
197 bool result = false;
198 lock (PacketHandlers)
199 {
200 if (!PacketHandlers.ContainsKey(packetType))
201 {
202 PacketHandlers.Add(packetType, handler);
203 result = true;
204 }
205 }
206 return result;
207 }
208
209 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler)
210 {
211 bool result = false;
212 lock (m_packetHandlers)
213 {
214 if (!m_packetHandlers.ContainsKey(packetType))
215 {
216 m_packetHandlers.Add(packetType, handler);
217 result = true;
218 }
219 }
220 return result;
221 }
222
223 protected virtual bool ProcessPacketMethod(Packet packet)
224 {
225 bool result = false;
226 bool found = false;
227 PacketMethod method;
228 if (m_packetHandlers.TryGetValue(packet.Type, out method))
229 {
230 //there is a local handler for this packet type
231 result = method(this, packet);
232 }
233 else
234 {
235 //there is not a local handler so see if there is a Global handler
236 lock (PacketHandlers)
237 {
238 found = PacketHandlers.TryGetValue(packet.Type, out method);
239 }
240 if (found)
241 {
242 result = method(this, packet);
243 }
244 }
245 return result;
246 }
247
248 # endregion
249
250 # region Low Level Packet Methods
251
252 private void ack_pack(Packet Pack)
253 {
254 if (Pack.Header.Reliable)
255 {
256 libsecondlife.Packets.PacketAckPacket ack_it = new PacketAckPacket();
257 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
258 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
259 ack_it.Packets[0].ID = Pack.Header.Sequence;
260 ack_it.Header.Reliable = false;
261
262 OutPacket(ack_it);
263
264 }
265 /*
266 if (Pack.Header.Reliable)
267 {
268 lock (PendingAcks)
269 {
270 uint sequence = (uint)Pack.Header.Sequence;
271 if (!PendingAcks.ContainsKey(sequence)) { PendingAcks[sequence] = sequence; }
272 }
273 }*/
274 }
275
276 private void ResendUnacked()
277 {
278 int now = Environment.TickCount;
279
280 lock (NeedAck)
281 {
282 foreach (Packet packet in NeedAck.Values)
283 {
284 if ((now - packet.TickCount > RESEND_TIMEOUT) && (!packet.Header.Resent))
285 {
286 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.VERBOSE, "Resending " + packet.Type.ToString() + " packet, " +
287 (now - packet.TickCount) + "ms have passed");
288
289 packet.Header.Resent = true;
290 OutPacket(packet);
291 }
292 }
293 }
294 }
295
296 private void SendAcks()
297 {
298 lock (PendingAcks)
299 {
300 if (PendingAcks.Count > 0)
301 {
302 if (PendingAcks.Count > 250)
303 {
304 // FIXME: Handle the odd case where we have too many pending ACKs queued up
305 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.VERBOSE, "Too many ACKs queued up!");
306 return;
307 }
308
309 //OpenSim.Framework.Console.MainConsole.Instance.WriteLine("Sending PacketAck");
310
311
312 int i = 0;
313 PacketAckPacket acks = new PacketAckPacket();
314 acks.Packets = new PacketAckPacket.PacketsBlock[PendingAcks.Count];
315
316 foreach (uint ack in PendingAcks.Values)
317 {
318 acks.Packets[i] = new PacketAckPacket.PacketsBlock();
319 acks.Packets[i].ID = ack;
320 i++;
321 }
322
323 acks.Header.Reliable = false;
324 OutPacket(acks);
325
326 PendingAcks.Clear();
327 }
328 }
329 }
330
331 private void AckTimer_Elapsed(object sender, ElapsedEventArgs ea)
332 {
333 SendAcks();
334 ResendUnacked();
335 }
336
337 # endregion
338
339 #region Packet Queue Processing
340
341 protected virtual void ProcessOutPacket(Packet Pack)
342 {
343 // Keep track of when this packet was sent out
344 Pack.TickCount = Environment.TickCount;
345
346 if (!Pack.Header.Resent)
347 {
348 // Set the sequence number
349 lock (SequenceLock)
350 {
351 if (Sequence >= MAX_SEQUENCE)
352 Sequence = 1;
353 else
354 Sequence++;
355 Pack.Header.Sequence = Sequence;
356 }
357
358 if (Pack.Header.Reliable) //DIRTY HACK
359 {
360 lock (NeedAck)
361 {
362 if (!NeedAck.ContainsKey(Pack.Header.Sequence))
363 {
364 try
365 {
366 NeedAck.Add(Pack.Header.Sequence, Pack);
367 }
368 catch (Exception e) // HACKY
369 {
370 e.ToString();
371 // Ignore
372 // Seems to throw a exception here occasionally
373 // of 'duplicate key' despite being locked.
374 // !?!?!?
375 }
376 }
377 else
378 {
379 // Client.Log("Attempted to add a duplicate sequence number (" +
380 // packet.Header.Sequence + ") to the NeedAck dictionary for packet type " +
381 // packet.Type.ToString(), Helpers.LogLevel.Warning);
382 }
383 }
384
385 // Don't append ACKs to resent packets, in case that's what was causing the
386 // delivery to fail
387 if (!Pack.Header.Resent)
388 {
389 // Append any ACKs that need to be sent out to this packet
390 lock (PendingAcks)
391 {
392 if (PendingAcks.Count > 0 && PendingAcks.Count < MAX_APPENDED_ACKS &&
393 Pack.Type != PacketType.PacketAck &&
394 Pack.Type != PacketType.LogoutRequest)
395 {
396 Pack.Header.AckList = new uint[PendingAcks.Count];
397 int i = 0;
398
399 foreach (uint ack in PendingAcks.Values)
400 {
401 Pack.Header.AckList[i] = ack;
402 i++;
403 }
404
405 PendingAcks.Clear();
406 Pack.Header.AppendedAcks = true;
407 }
408 }
409 }
410 }
411 }
412
413 byte[] ZeroOutBuffer = new byte[4096];
414 byte[] sendbuffer;
415 sendbuffer = Pack.ToBytes();
416
417 try
418 {
419 if (Pack.Header.Zerocoded)
420 {
421 int packetsize = Helpers.ZeroEncode(sendbuffer, sendbuffer.Length, ZeroOutBuffer);
422 m_networkServer.SendPacketTo(ZeroOutBuffer, packetsize, SocketFlags.None, CircuitCode);//userEP);
423 }
424 else
425 {
426 m_networkServer.SendPacketTo(sendbuffer, sendbuffer.Length, SocketFlags.None, CircuitCode); //userEP);
427 }
428 }
429 catch (Exception)
430 {
431 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.MEDIUM, "OpenSimClient.cs:ProcessOutPacket() - WARNING: Socket exception occurred on connection " + userEP.ToString() + " - killing thread");
432 ClientThread.Abort();
433 }
434
435 }
436
437 public virtual void InPacket(Packet NewPack)
438 {
439 // Handle appended ACKs
440 if (NewPack.Header.AppendedAcks)
441 {
442 lock (NeedAck)
443 {
444 foreach (uint ack in NewPack.Header.AckList)
445 {
446 NeedAck.Remove(ack);
447 }
448 }
449 }
450
451 // Handle PacketAck packets
452 if (NewPack.Type == PacketType.PacketAck)
453 {
454 PacketAckPacket ackPacket = (PacketAckPacket)NewPack;
455
456 lock (NeedAck)
457 {
458 foreach (PacketAckPacket.PacketsBlock block in ackPacket.Packets)
459 {
460 NeedAck.Remove(block.ID);
461 }
462 }
463 }
464 else if ((NewPack.Type == PacketType.StartPingCheck))
465 {
466 //reply to pingcheck
467 libsecondlife.Packets.StartPingCheckPacket startPing = (libsecondlife.Packets.StartPingCheckPacket)NewPack;
468 libsecondlife.Packets.CompletePingCheckPacket endPing = new CompletePingCheckPacket();
469 endPing.PingID.PingID = startPing.PingID.PingID;
470 OutPacket(endPing);
471 }
472 else
473 {
474 QueItem item = new QueItem();
475 item.Packet = NewPack;
476 item.Incoming = true;
477 this.PacketQueue.Enqueue(item);
478 }
479
480 }
481
482 public virtual void OutPacket(Packet NewPack)
483 {
484 QueItem item = new QueItem();
485 item.Packet = NewPack;
486 item.Incoming = false;
487 this.PacketQueue.Enqueue(item);
488 }
489
490 protected virtual void ClientLoop()
491 {
492 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "OpenSimClient.cs:ClientLoop() - Entered loop");
493 while (true)
494 {
495 QueItem nextPacket = PacketQueue.Dequeue();
496 if (nextPacket.Incoming)
497 {
498 //is a incoming packet
499 ProcessInPacket(nextPacket.Packet);
500 }
501 else
502 {
503 //is a out going packet
504 ProcessOutPacket(nextPacket.Packet);
505 }
506 }
507 }
508
509 #endregion
510
511 # region Setup
512
513 protected virtual void InitNewClient()
514 {
515 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.LOW, "OpenSimClient.cs:InitNewClient() - Adding viewer agent to world");
516
517 m_world.AddViewerAgent(this);
518 world.Entity tempent = m_world.Entities[this.AgentID];
519
520 this.ClientAvatar = (world.Avatar)tempent;
521 }
522
523 protected virtual void AuthUser()
524 {
525 // AuthenticateResponse sessionInfo = m_gridServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code);
526 AuthenticateResponse sessionInfo = this.m_networkServer.AuthenticateSession(cirpack.CircuitCode.SessionID, cirpack.CircuitCode.ID, cirpack.CircuitCode.Code);
527 if (!sessionInfo.Authorised)
528 {
529 //session/circuit not authorised
530 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.NORMAL, "OpenSimClient.cs:AuthUser() - New user request denied to " + userEP.ToString());
531 ClientThread.Abort();
532 }
533 else
534 {
535 OpenSim.Framework.Console.MainConsole.Instance.WriteLine(OpenSim.Framework.Console.LogPriority.NORMAL, "OpenSimClient.cs:AuthUser() - Got authenticated connection from " + userEP.ToString());
536 //session is authorised
537 this.AgentID = cirpack.CircuitCode.ID;
538 this.SessionID = cirpack.CircuitCode.SessionID;
539 this.CircuitCode = cirpack.CircuitCode.Code;
540 InitNewClient(); //shouldn't be called here as we might be a child agent and not want a full avatar
541 this.ClientAvatar.firstname = sessionInfo.LoginInfo.First;
542 this.ClientAvatar.lastname = sessionInfo.LoginInfo.Last;
543 if (sessionInfo.LoginInfo.SecureSession != LLUUID.Zero)
544 {
545 this.SecureSessionID = sessionInfo.LoginInfo.SecureSession;
546 }
547
548 // Create Inventory, currently only works for sandbox mode
549 if (m_sandboxMode)
550 {
551 this.SetupInventory(sessionInfo);
552 }
553
554 ClientLoop();
555 }
556 }
557 # endregion
558
559 #region Inventory Creation
560 private void SetupInventory(AuthenticateResponse sessionInfo)
561 {
562 AgentInventory inventory = null;
563 if (sessionInfo.LoginInfo.InventoryFolder != null)
564 {
565 inventory = this.CreateInventory(sessionInfo.LoginInfo.InventoryFolder);
566 if (sessionInfo.LoginInfo.BaseFolder != null)
567 {
568 if (!inventory.HasFolder(sessionInfo.LoginInfo.BaseFolder))
569 {
570 m_inventoryCache.CreateNewInventoryFolder(this, sessionInfo.LoginInfo.BaseFolder);
571 }
572 this.newAssetFolder = sessionInfo.LoginInfo.BaseFolder;
573 AssetBase[] inventorySet = m_assetCache.CreateNewInventorySet(this.AgentID);
574 if (inventorySet != null)
575 {
576 for (int i = 0; i < inventorySet.Length; i++)
577 {
578 if (inventorySet[i] != null)
579 {
580 m_inventoryCache.AddNewInventoryItem(this, sessionInfo.LoginInfo.BaseFolder, inventorySet[i]);
581 }
582 }
583 }
584 }
585 }
586 }
587 private AgentInventory CreateInventory(LLUUID baseFolder)
588 {
589 AgentInventory inventory = null;
590 if (this.m_userServer != null)
591 {
592 // a user server is set so request the inventory from it
593 Console.WriteLine("getting inventory from user server");
594 inventory = m_inventoryCache.FetchAgentsInventory(this.AgentID, m_userServer);
595 }
596 else
597 {
598 inventory = new AgentInventory();
599 inventory.AgentID = this.AgentID;
600 inventory.CreateRootFolder(this.AgentID, false);
601 m_inventoryCache.AddNewAgentsInventory(inventory);
602 m_inventoryCache.CreateNewInventoryFolder(this, baseFolder);
603 }
604 return inventory;
605 }
606
607 private void CreateInventoryItem(CreateInventoryItemPacket packet)
608 {
609 if (!(packet.InventoryBlock.Type == 3 || packet.InventoryBlock.Type == 7))
610 {
611 System.Console.WriteLine("Attempted to create " + Util.FieldToString(packet.InventoryBlock.Name) + " in inventory. Unsupported type");
612 return;
613 }
614
615 //lets try this out with creating a notecard
616 AssetBase asset = new AssetBase();
617
618 asset.Name = Util.FieldToString(packet.InventoryBlock.Name);
619 asset.Description = Util.FieldToString(packet.InventoryBlock.Description);
620 asset.InvType = packet.InventoryBlock.InvType;
621 asset.Type = packet.InventoryBlock.Type;
622 asset.FullID = LLUUID.Random();
623
624 switch (packet.InventoryBlock.Type)
625 {
626 case 7: // Notecard
627 asset.Data = new byte[0];
628 break;
629
630 case 3: // Landmark
631 String content;
632 content = "Landmark version 2\n";
633 content += "region_id " + m_regionData.SimUUID + "\n";
634 String strPos = String.Format("%.2f %.2f %.2f>",
635 this.ClientAvatar.Pos.X,
636 this.ClientAvatar.Pos.Y,
637 this.ClientAvatar.Pos.Z);
638 content += "local_pos " + strPos + "\n";
639 asset.Data = (new System.Text.ASCIIEncoding()).GetBytes(content);
640 break;
641 default:
642 break;
643 }
644 m_assetCache.AddAsset(asset);
645 m_inventoryCache.AddNewInventoryItem(this, packet.InventoryBlock.FolderID, asset);
646 }
647 #endregion
648
649 #region Nested Classes
650
651 public class QueItem
652 {
653 public QueItem()
654 {
655 }
656
657 public Packet Packet;
658 public bool Incoming;
659 }
660 #endregion
661 }
662}