public void Add(ClientMessage Message)
 {
     Messages.Add(Message);
 }
        /// <summary>
        /// Internal use only, fetches the correct handler for a given handler name. One packet name may map to multiple handler names.
        /// </summary>
        /// <param name="parserName">The packet handler to fetch</param>
        /// <returns></returns>
        private GamePacketParser GetPacketParser(String parserName)
        {
            if (parserName == "ErrorMessage")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Message"] = nmsg.ReadString();
                    return props;
                };
            else if (parserName == "MOTD")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Message"] = nmsg.ReadString();
                    return props;
                };
            else if (parserName == "Ping")
                return delegate(NetworkMessage nmsg)
                {
                    return new Packet(parserName);
                };

            else if (parserName == "PlayerLogin")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    Player = new ClientPlayer(nmsg.ReadU32());
                    props["DrawSpeed"] = nmsg.ReadU16();
                    props["CanReportBugs"] = nmsg.ReadByte() != 0;
                    props["Player"] = Player;
                    KnownCreatures[Player.ID] = Player;

                    return props;
                };
            else if (parserName == "MapDescription")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    CurrentPosition = ReadMapPosition(nmsg);
                    props["Center"] = CurrentPosition;
                    props["Tiles"] = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z, 18, 14);
                    return props;
                };

            else if (parserName == "UpdateInventory")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Slot"] = (int)nmsg.ReadByte();
                    props["Thing"] = ReadThing(nmsg);
                    return props;
                };
            else if (parserName == "ClearInventory")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Slot"] = (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "OpenContainer")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    int ContainerID = (int)nmsg.ReadByte();
                    props["ContainerID"] = ContainerID;
                    int ClientID = nmsg.ReadU16();
                    ItemType it = GameData.GetItemType(ClientID);
                    if (it == null)
                    {
                        Log.Warning("OpenContainer contains unrecognized item type (" + ClientID.ToString() + ").", this);
                        it = ItemType.NullType;
                    }
                    props["Thing"] = new ClientContainer(it, ContainerID);
                    props["Name"] = nmsg.ReadString();
                    props["Volume"] = (int)nmsg.ReadByte();
                    props["IsChild"] = nmsg.ReadByte() != 0;
                    int ItemCount = nmsg.ReadByte();
                    props["ItemCount"] = (int)ItemCount;
                    List<ClientItem> contents = new List<ClientItem>();
                    for (int i = 0; i < ItemCount; ++i)
                        contents.Add((ClientItem)ReadThing(nmsg));
                    props["Contents"] = contents;
                    return props;
                };
            else if (parserName == "CloseContainer")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["ContainerID"] = (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "ContainerAddItem")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["ContainerID"] = (int)nmsg.ReadByte();
                    props["Item"] = ReadItem(nmsg);
                    return props;
                };
            else if (parserName == "ContainerTransformItem")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["ContainerID"] = (int)nmsg.ReadByte();
                    props["Slot"] = (int)nmsg.ReadByte();
                    props["Item"] = ReadItem(nmsg);
                    return props;
                };
            else if (parserName == "ContainerRemoveItem")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["ContainerID"] = (int)nmsg.ReadByte();
                    props["Slot"] = (int)nmsg.ReadByte();
                    return props;
                };

            else if (parserName == "UpdateStats")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Health"] = (int)nmsg.ReadU16();
                    props["MaxHealth"] = (int)nmsg.ReadU16();
                    props["Capacity"] = (int)nmsg.ReadU16();
                    props["Experience"] = (int)nmsg.ReadU32();
                    props["Level"] = (int)nmsg.ReadByte();
                    props["LevelPercent"] = (int)nmsg.ReadByte();
                    props["Mana"] = (int)nmsg.ReadU16();
                    props["MaxMana"] = (int)nmsg.ReadU16();
                    props["MagicLevel"] = (int)nmsg.ReadByte();
                    props["MagicLevelPercent"] = (int)nmsg.ReadByte();
                    // TODO: Stamina for some versions
                    //int soul = nmsg.ReadByte();
                    //int staminaMinutes = nmsg.ReadU16();

                    return props;
                };
            else if (parserName == "UpdateSkills")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Fist"] = (int)nmsg.ReadByte();
                    props["FistPercent"] = (int)nmsg.ReadByte();
                    props["Club"] = (int)nmsg.ReadByte();
                    props["ClubPercent"] = (int)nmsg.ReadByte();
                    props["Sword"] = (int)nmsg.ReadByte();
                    props["SwordPercent"] = (int)nmsg.ReadByte();
                    props["Axe"] = (int)nmsg.ReadByte();
                    props["AxePercent"] = (int)nmsg.ReadByte();
                    props["Dist"] = (int)nmsg.ReadByte();
                    props["DistPercent"] = (int)nmsg.ReadByte();
                    props["Shield"] = (int)nmsg.ReadByte();
                    props["ShieldPercent"] = (int)nmsg.ReadByte();
                    props["Fish"] = (int)nmsg.ReadByte();
                    props["FishPercent"] = (int)nmsg.ReadByte();

                    return props;
                };
            else if (parserName == "PlayerIcons")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["ConditionState"] = (ConditionState)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "CancelAttack")
                return delegate(NetworkMessage nmsg)
                {
                    return new Packet(parserName);
                };
            else if (parserName == "CancelWalk")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["Direction"] = (Direction)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "Death")
                return delegate(NetworkMessage nmsg)
                {
                    return new Packet(parserName);
                };
            else if (parserName == "CanReport")
                return delegate(NetworkMessage nmsg)
                {
                    return new Packet(parserName);
                };
            else if (parserName == "MoveNorth")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    CurrentPosition.Y--;
                    props["Center"] = CurrentPosition;
                    props["Tiles"] = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z, 18, 1);
                    return props;
                };
            else if (parserName == "MoveSouth")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    CurrentPosition.Y++;
                    props["Center"] = CurrentPosition;
                    props["Tiles"] = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y + 7, CurrentPosition.Z, 18, 1);
                    return props;
                };
            else if (parserName == "MoveWest")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    CurrentPosition.X--;
                    props["Center"] = CurrentPosition;
                    props["Tiles"] = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z, 1, 14);
                    return props;
                };
            else if (parserName == "MoveEast")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    CurrentPosition.X++;
                    props["Center"] = CurrentPosition;
                    props["Tiles"] = ReadMapDescription(nmsg, CurrentPosition.X + 9, CurrentPosition.Y - 6, CurrentPosition.Z, 1, 14);
                    return props;
                };
            else if (parserName == "FloorUp")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    List<ClientTile> Tiles = new List<ClientTile>();
                    int skipTiles = 0;

                    CurrentPosition.Z--;
                    if (CurrentPosition.Z == 7)
                    {
                        for (int i = 5; i >= 0; i--)
                        {
                            Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, i, 18, 14, 8 - i));
                        }
                    }
                    else if (CurrentPosition.Z > 7)
                    {
                        Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z - 2, 18, 14, 3));
                    }
                    CurrentPosition.X++;
                    CurrentPosition.Y++;

                    props["Tiles"] = Tiles;
                    props["Center"] = CurrentPosition;
                    return props;
                };
            else if (parserName == "FloorDown")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    List<ClientTile> Tiles = new List<ClientTile>();
                    int skipTiles = 0;

                    CurrentPosition.Z++;
                    if (CurrentPosition.Z == 8)
                    {
                        int j = -1;
                        for (int i = CurrentPosition.Z; i < CurrentPosition.Z + 3; ++i, --j)
                        {
                            Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, i, 18, 14, j));
                        }
                    }
                    else if (CurrentPosition.Z > 8 && CurrentPosition.Z < 14)
                    {
                        Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z + 2, 18, 14, -3));
                    }
                    CurrentPosition.X--;
                    CurrentPosition.Y--;

                    props["Tiles"] = Tiles;
                    props["Center"] = CurrentPosition;
                    return props;
                };

            else if (parserName == "RefreshTile")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    MapPosition pos = ReadMapPosition(nmsg);
                    props["Position"] = pos;
                    props["Clear"] = false;
                    if (nmsg.PeekU16() == 0xFF01)
                    {
                        nmsg.ReadU16();
                        props["Clear"] = true;
                        return props;
                    }
                    else
                    {
                        props["NewTile"] = ReadTileDescription(nmsg, pos);
                        // Skip extra bytes after data (it signifies the end of data)
                        nmsg.ReadU16();
                        return props;
                    }
                };
            else if (parserName == "AddThing")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Position"] = ReadMapPosition(nmsg);
                    props["Thing"] = ReadThing(nmsg);
                    props["Push"] = true;
                    // TODO: >= 8.53, push thing should be false
                    return props;
                };
            else if (parserName == "TransformThing")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Position"] = ReadMapPosition(nmsg);
                    props["StackIndex"] = (int)nmsg.ReadByte();

                    if (nmsg.PeekU16() == 0x63)
                    {
                        nmsg.Skip(2);
                        // CreatureTurn2
                        props["Thing"] = KnownCreatures[nmsg.ReadU32()];
                        props["Direction"] = (Direction)nmsg.ReadByte();
                    }
                    else
                    {
                        props["Thing"] = ReadThing(nmsg);
                    }
                    return props;
                };
            else if (parserName == "RemoveThing")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Position"] = ReadMapPosition(nmsg);
                    props["StackIndex"] = (int)nmsg.ReadByte();

                    return props;
                };
            else if (parserName == "CreatureMove")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["OldPosition"] = ReadMapPosition(nmsg);
                    props["OldStackIndex"] = (int)nmsg.ReadByte();
                    props["Position"] = ReadMapPosition(nmsg);

                    if ((int)props["OldStackIndex"] > 9)
                        Log.Warning("CreatureMove - Old stack pos out of range.", this);

                    props["Push"] = true;
                    // TODO: >= 8.53, pushThing = false
                    return props;
                };

            else if (parserName == "WorldLight")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Level"] = (int)nmsg.ReadByte();
                    props["Color"] = (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "Effect")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Position"] = ReadMapPosition(nmsg);
                    props["Effect"] = 1 + (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "AnimatedText")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Position"] = ReadMapPosition(nmsg);
                    props["Color"] = (int)nmsg.ReadByte();
                    props["Text"] = nmsg.ReadString();
                    return props;
                };
            else if (parserName == "ShootEffect")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["From"] = ReadMapPosition(nmsg);
                    props["To"] = ReadMapPosition(nmsg);
                    props["Effect"] = (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "SquareEffect")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["Color"] = nmsg.ReadByte();
                    return props;
                };

            else if (parserName == "CreatureHealth")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["Health"] = (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "CreatureLight")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["Level"] = (int)nmsg.ReadByte();
                    props["Color"] = (int)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "CreatureRefresh")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    return props;
                };
            else if (parserName == "CreatureTurn")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["Direction"] = (Direction)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "CreatureSpeed")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["Speed"] = (int)nmsg.ReadU16();
                    return props;
                };
            else if (parserName == "CreatureSkull")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["Skull"] = (CreatureSkull)nmsg.ReadByte();
                    return props;
                };
            else if (parserName == "CreatureShield")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    props["PartyShield"] = (PartyShield)nmsg.ReadByte();
                    return props;
                };

            else if (parserName == "CreatureSpeak")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    ClientMessage Message = new ClientMessage();

                    //props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                    Message.Speaker = nmsg.ReadString();
                    //props["Level"] = nmsg.ReadU16();
                    Message.Type = (MessageType)nmsg.ReadByte();

                    switch (Message.Type)
                    {
                        case MessageType.Say:
                        case MessageType.Whisper:
                        case MessageType.Yell:
                        case MessageType.MonsterSay:
                        case MessageType.MonsterYell:
                        case MessageType.PrivateNPCToPlayer:
                        case MessageType.PrivatePlayerToNPC:
                            {
                                props["Position"] = ReadMapPosition(nmsg);
                                Message.Text = nmsg.ReadString();
                                break;
                            }
                        case MessageType.ChannelAnonymousRed:
                        case MessageType.ChannelOrange:
                        case MessageType.ChannelRed:
                        case MessageType.ChannelYellow:
                            {
                                props["ChannelID"] = nmsg.ReadU16();
                                Message.Text = nmsg.ReadString();
                                break;
                            }
                        case MessageType.Private:
                        case MessageType.Broadcast:
                        case MessageType.PrivateRed:
                            {
                                Message.Text = nmsg.ReadString();
                                break;
                            }
                        case MessageType.ReportRuleViolation:
                            {
                                Message.Time = Common.UnixTime(nmsg.ReadU32()); // time
                                Message.Text = nmsg.ReadString();
                                break;
                            }
                        case MessageType.RuleViolationGameMaster:
                        case MessageType.RuleViolationPlayer:
                            {
                                Message.Text = nmsg.ReadString();
                                break;
                            }
                        default:
                            Log.Warning("Unknown speak class " + (int)props["MessageType"], this);
                            return null;
                    }
                    props["Message"] = Message;
                    return props;
                };
            else if (parserName == "ChannelList")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    int count = nmsg.ReadByte();
                    props["ChannelCount"] = count;
                    while (count > 0)
                    {
                        int channelID = nmsg.ReadU16();
                        string channelName = nmsg.ReadString();
                        --count;
                    }
                    return null;
                };
            else if (parserName == "OpenChannel")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["ChannelID"] = nmsg.ReadU16();
                    props["ChannelName"] = nmsg.ReadString();
                    return props;
                };
            else if (parserName == "OpenPrivateChat")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["PlayerName"] = nmsg.ReadString();
                    return props;
                };
            else if (parserName == "TextMessage")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    MessageType Type = (MessageType)nmsg.ReadByte();
                    String Text = nmsg.ReadString();
                    props["Message"] = new ClientMessage(Type, DateTime.Now, Text);
                    return props;
                };

            else if (parserName == "VIPState")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);

                    props["CreatureID"] = nmsg.ReadU32();
                    props["Name"] = nmsg.ReadString();
                    props["Online"] = nmsg.ReadByte() != 0;
                    return props;
                };
            else if (parserName == "VIPLogin")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["CreatureID"] = nmsg.ReadU32();
                    return props;
                };
            else if (parserName == "VIPLogout")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    props["CreatureID"] = nmsg.ReadU32();
                    return props;
                };
            else if (parserName == "RuleViolationChannel")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    return props;
                };
            else if (parserName == "RuleViolationRemove")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    return props;
                };
            else if (parserName == "RuleViolationCancel")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    return props;
                };
            else if (parserName == "RuleViolationLock")
                return delegate(NetworkMessage nmsg)
                {
                    Packet props = new Packet(parserName);
                    return props;
                };

            throw new System.ArgumentException("Unknown packet handler.");
        }
        /// <summary>
        /// Internal use only, fetches the correct handler for a given handler name. One packet name may map to multiple handler names.
        /// </summary>
        /// <param name="parserName">The packet handler to fetch</param>
        /// <returns></returns>
        private GamePacketParser GetPacketParser(String parserName)
        {
            if (parserName == "ErrorMessage")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Message"] = nmsg.ReadString();
                           return props;
                       }
            }
            ;
            else if (parserName == "MOTD")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Message"] = nmsg.ReadString();
                           return props;
                       }
            }
            ;
            else if (parserName == "Ping")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           return new Packet(parserName);
                       }
            }
            ;

            else if (parserName == "PlayerLogin")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           Player                    = new ClientPlayer(nmsg.ReadU32());
                           props["DrawSpeed"]        = nmsg.ReadU16();
                           props["CanReportBugs"]    = nmsg.ReadByte() != 0;
                           props["Player"]           = Player;
                           KnownCreatures[Player.ID] = Player;

                           return props;
                       }
            }
            ;
            else if (parserName == "MapDescription")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           CurrentPosition = ReadMapPosition(nmsg);
                           props["Center"] = CurrentPosition;
                           props["Tiles"]  = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z, 18, 14);
                           return props;
                       }
            }
            ;

            else if (parserName == "UpdateInventory")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Slot"]  = (int)nmsg.ReadByte();
                           props["Thing"] = ReadThing(nmsg);
                           return props;
                       }
            }
            ;
            else if (parserName == "ClearInventory")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Slot"] = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "OpenContainer")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props       = new Packet(parserName);
                           int    ContainerID = (int)nmsg.ReadByte();
                           props["ContainerID"] = ContainerID;
                           int      ClientID = nmsg.ReadU16();
                           ItemType it       = GameData.GetItemType(ClientID);
                           if (it == null)
                           {
                               Log.Warning("OpenContainer contains unrecognized item type (" + ClientID.ToString() + ").", this);
                               it = ItemType.NullType;
                           }
                           props["Thing"]   = new ClientContainer(it, ContainerID);
                           props["Name"]    = nmsg.ReadString();
                           props["Volume"]  = (int)nmsg.ReadByte();
                           props["IsChild"] = nmsg.ReadByte() != 0;
                           int ItemCount = nmsg.ReadByte();
                           props["ItemCount"] = (int)ItemCount;
                           List <ClientItem> contents = new List <ClientItem>();
                           for (int i = 0; i < ItemCount; ++i)
                           {
                               contents.Add((ClientItem)ReadThing(nmsg));
                           }
                           props["Contents"] = contents;
                           return props;
                       }
            }
            ;
            else if (parserName == "CloseContainer")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["ContainerID"] = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "ContainerAddItem")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["ContainerID"] = (int)nmsg.ReadByte();
                           props["Item"]        = ReadItem(nmsg);
                           return props;
                       }
            }
            ;
            else if (parserName == "ContainerTransformItem")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["ContainerID"] = (int)nmsg.ReadByte();
                           props["Slot"]        = (int)nmsg.ReadByte();
                           props["Item"]        = ReadItem(nmsg);
                           return props;
                       }
            }
            ;
            else if (parserName == "ContainerRemoveItem")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["ContainerID"] = (int)nmsg.ReadByte();
                           props["Slot"]        = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;

            else if (parserName == "UpdateStats")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Health"]            = (int)nmsg.ReadU16();
                           props["MaxHealth"]         = (int)nmsg.ReadU16();
                           props["Capacity"]          = (int)nmsg.ReadU16();
                           props["Experience"]        = (int)nmsg.ReadU32();
                           props["Level"]             = (int)nmsg.ReadByte();
                           props["LevelPercent"]      = (int)nmsg.ReadByte();
                           props["Mana"]              = (int)nmsg.ReadU16();
                           props["MaxMana"]           = (int)nmsg.ReadU16();
                           props["MagicLevel"]        = (int)nmsg.ReadByte();
                           props["MagicLevelPercent"] = (int)nmsg.ReadByte();
                           // TODO: Stamina for some versions
                           //int soul = nmsg.ReadByte();
                           //int staminaMinutes = nmsg.ReadU16();

                           return props;
                       }
            }
            ;
            else if (parserName == "UpdateSkills")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Fist"]          = (int)nmsg.ReadByte();
                           props["FistPercent"]   = (int)nmsg.ReadByte();
                           props["Club"]          = (int)nmsg.ReadByte();
                           props["ClubPercent"]   = (int)nmsg.ReadByte();
                           props["Sword"]         = (int)nmsg.ReadByte();
                           props["SwordPercent"]  = (int)nmsg.ReadByte();
                           props["Axe"]           = (int)nmsg.ReadByte();
                           props["AxePercent"]    = (int)nmsg.ReadByte();
                           props["Dist"]          = (int)nmsg.ReadByte();
                           props["DistPercent"]   = (int)nmsg.ReadByte();
                           props["Shield"]        = (int)nmsg.ReadByte();
                           props["ShieldPercent"] = (int)nmsg.ReadByte();
                           props["Fish"]          = (int)nmsg.ReadByte();
                           props["FishPercent"]   = (int)nmsg.ReadByte();

                           return props;
                       }
            }
            ;
            else if (parserName == "PlayerIcons")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["ConditionState"] = (ConditionState)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "CancelAttack")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           return new Packet(parserName);
                       }
            }
            ;
            else if (parserName == "CancelWalk")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["Direction"] = (Direction)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "Death")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           return new Packet(parserName);
                       }
            }
            ;
            else if (parserName == "CanReport")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           return new Packet(parserName);
                       }
            }
            ;
            else if (parserName == "MoveNorth")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           CurrentPosition.Y--;
                           props["Center"] = CurrentPosition;
                           props["Tiles"]  = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z, 18, 1);
                           return props;
                       }
            }
            ;
            else if (parserName == "MoveSouth")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           CurrentPosition.Y++;
                           props["Center"] = CurrentPosition;
                           props["Tiles"]  = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y + 7, CurrentPosition.Z, 18, 1);
                           return props;
                       }
            }
            ;
            else if (parserName == "MoveWest")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           CurrentPosition.X--;
                           props["Center"] = CurrentPosition;
                           props["Tiles"]  = ReadMapDescription(nmsg, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z, 1, 14);
                           return props;
                       }
            }
            ;
            else if (parserName == "MoveEast")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           CurrentPosition.X++;
                           props["Center"] = CurrentPosition;
                           props["Tiles"]  = ReadMapDescription(nmsg, CurrentPosition.X + 9, CurrentPosition.Y - 6, CurrentPosition.Z, 1, 14);
                           return props;
                       }
            }
            ;
            else if (parserName == "FloorUp")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet            props = new Packet(parserName);
                           List <ClientTile> Tiles = new List <ClientTile>();
                           int skipTiles           = 0;

                           CurrentPosition.Z--;
                           if (CurrentPosition.Z == 7)
                           {
                               for (int i = 5; i >= 0; i--)
                               {
                                   Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, i, 18, 14, 8 - i));
                               }
                           }
                           else if (CurrentPosition.Z > 7)
                           {
                               Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z - 2, 18, 14, 3));
                           }
                           CurrentPosition.X++;
                           CurrentPosition.Y++;

                           props["Tiles"]  = Tiles;
                           props["Center"] = CurrentPosition;
                           return props;
                       }
            }
            ;
            else if (parserName == "FloorDown")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet            props = new Packet(parserName);
                           List <ClientTile> Tiles = new List <ClientTile>();
                           int skipTiles           = 0;

                           CurrentPosition.Z++;
                           if (CurrentPosition.Z == 8)
                           {
                               int j = -1;
                               for (int i = CurrentPosition.Z; i < CurrentPosition.Z + 3; ++i, --j)
                               {
                                   Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, i, 18, 14, j));
                               }
                           }
                           else if (CurrentPosition.Z > 8 && CurrentPosition.Z < 14)
                           {
                               Tiles.AddRange(ReadFloorDescription(nmsg, ref skipTiles, CurrentPosition.X - 8, CurrentPosition.Y - 6, CurrentPosition.Z + 2, 18, 14, -3));
                           }
                           CurrentPosition.X--;
                           CurrentPosition.Y--;

                           props["Tiles"]  = Tiles;
                           props["Center"] = CurrentPosition;
                           return props;
                       }
            }
            ;

            else if (parserName == "RefreshTile")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet      props = new Packet(parserName);
                           MapPosition pos   = ReadMapPosition(nmsg);
                           props["Position"] = pos;
                           props["Clear"]    = false;
                           if (nmsg.PeekU16() == 0xFF01)
                           {
                               nmsg.ReadU16();
                               props["Clear"] = true;
                               return props;
                           }
                           else
                           {
                               props["NewTile"] = ReadTileDescription(nmsg, pos);
                               // Skip extra bytes after data (it signifies the end of data)
                               nmsg.ReadU16();
                               return props;
                           }
                       }
            }
            ;
            else if (parserName == "AddThing")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Position"] = ReadMapPosition(nmsg);
                           props["Thing"]    = ReadThing(nmsg);
                           props["Push"]     = true;
                           // TODO: >= 8.53, push thing should be false
                           return props;
                       }
            }
            ;
            else if (parserName == "TransformThing")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Position"]   = ReadMapPosition(nmsg);
                           props["StackIndex"] = (int)nmsg.ReadByte();

                           if (nmsg.PeekU16() == 0x63)
                           {
                               nmsg.Skip(2);
                               // CreatureTurn2
                               props["Thing"]     = KnownCreatures[nmsg.ReadU32()];
                               props["Direction"] = (Direction)nmsg.ReadByte();
                           }
                           else
                           {
                               props["Thing"] = ReadThing(nmsg);
                           }
                           return props;
                       }
            }
            ;
            else if (parserName == "RemoveThing")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Position"]   = ReadMapPosition(nmsg);
                           props["StackIndex"] = (int)nmsg.ReadByte();

                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureMove")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["OldPosition"]   = ReadMapPosition(nmsg);
                           props["OldStackIndex"] = (int)nmsg.ReadByte();
                           props["Position"]      = ReadMapPosition(nmsg);

                           if ((int)props["OldStackIndex"] > 9)
                           {
                               Log.Warning("CreatureMove - Old stack pos out of range.", this);
                           }

                           props["Push"] = true;
                           // TODO: >= 8.53, pushThing = false
                           return props;
                       }
            }
            ;

            else if (parserName == "WorldLight")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Level"] = (int)nmsg.ReadByte();
                           props["Color"] = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "Effect")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Position"] = ReadMapPosition(nmsg);
                           props["Effect"]   = 1 + (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "AnimatedText")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Position"] = ReadMapPosition(nmsg);
                           props["Color"]    = (int)nmsg.ReadByte();
                           props["Text"]     = nmsg.ReadString();
                           return props;
                       }
            }
            ;
            else if (parserName == "ShootEffect")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["From"]   = ReadMapPosition(nmsg);
                           props["To"]     = ReadMapPosition(nmsg);
                           props["Effect"] = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "SquareEffect")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           props["Color"]    = nmsg.ReadByte();
                           return props;
                       }
            }
            ;

            else if (parserName == "CreatureHealth")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           props["Health"]   = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureLight")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           props["Level"]    = (int)nmsg.ReadByte();
                           props["Color"]    = (int)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureRefresh")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureTurn")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"]  = KnownCreatures[nmsg.ReadU32()];
                           props["Direction"] = (Direction)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureSpeed")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           props["Speed"]    = (int)nmsg.ReadU16();
                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureSkull")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           props["Skull"]    = (CreatureSkull)nmsg.ReadByte();
                           return props;
                       }
            }
            ;
            else if (parserName == "CreatureShield")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["Creature"]    = KnownCreatures[nmsg.ReadU32()];
                           props["PartyShield"] = (PartyShield)nmsg.ReadByte();
                           return props;
                       }
            }
            ;

            else if (parserName == "CreatureSpeak")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           ClientMessage Message = new ClientMessage();

                           //props["Creature"] = KnownCreatures[nmsg.ReadU32()];
                           Message.Speaker = nmsg.ReadString();
                           //props["Level"] = nmsg.ReadU16();
                           Message.Type = (MessageType)nmsg.ReadByte();

                           switch (Message.Type)
                           {
                           case MessageType.Say:
                           case MessageType.Whisper:
                           case MessageType.Yell:
                           case MessageType.MonsterSay:
                           case MessageType.MonsterYell:
                           case MessageType.PrivateNPCToPlayer:
                           case MessageType.PrivatePlayerToNPC:
                           {
                               props["Position"] = ReadMapPosition(nmsg);
                               Message.Text      = nmsg.ReadString();
                               break;
                           }

                           case MessageType.ChannelAnonymousRed:
                           case MessageType.ChannelOrange:
                           case MessageType.ChannelRed:
                           case MessageType.ChannelYellow:
                           {
                               props["ChannelID"] = nmsg.ReadU16();
                               Message.Text       = nmsg.ReadString();
                               break;
                           }

                           case MessageType.Private:
                           case MessageType.Broadcast:
                           case MessageType.PrivateRed:
                           {
                               Message.Text = nmsg.ReadString();
                               break;
                           }

                           case MessageType.ReportRuleViolation:
                           {
                               Message.Time = Common.UnixTime(nmsg.ReadU32());  // time
                               Message.Text = nmsg.ReadString();
                               break;
                           }

                           case MessageType.RuleViolationGameMaster:
                           case MessageType.RuleViolationPlayer:
                           {
                               Message.Text = nmsg.ReadString();
                               break;
                           }

                           default:
                               Log.Warning("Unknown speak class " + (int)props["MessageType"], this);
                               return null;
                           }
                           props["Message"] = Message;
                           return props;
                       }
            }
            ;
            else if (parserName == "ChannelList")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           int count = nmsg.ReadByte();
                           props["ChannelCount"] = count;
                           while (count > 0)
                           {
                               int    channelID   = nmsg.ReadU16();
                               string channelName = nmsg.ReadString();
                               --count;
                           }
                           return null;
                       }
            }
            ;
            else if (parserName == "OpenChannel")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["ChannelID"]   = nmsg.ReadU16();
                           props["ChannelName"] = nmsg.ReadString();
                           return props;
                       }
            }
            ;
            else if (parserName == "OpenPrivateChat")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["PlayerName"] = nmsg.ReadString();
                           return props;
                       }
            }
            ;
            else if (parserName == "TextMessage")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           MessageType Type = (MessageType)nmsg.ReadByte();
                           String      Text = nmsg.ReadString();
                           props["Message"] = new ClientMessage(Type, DateTime.Now, Text);
                           return props;
                       }
            }
            ;

            else if (parserName == "VIPState")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);

                           props["CreatureID"] = nmsg.ReadU32();
                           props["Name"]       = nmsg.ReadString();
                           props["Online"]     = nmsg.ReadByte() != 0;
                           return props;
                       }
            }
            ;
            else if (parserName == "VIPLogin")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["CreatureID"] = nmsg.ReadU32();
                           return props;
                       }
            }
            ;
            else if (parserName == "VIPLogout")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           props["CreatureID"] = nmsg.ReadU32();
                           return props;
                       }
            }
            ;
            else if (parserName == "RuleViolationChannel")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           return props;
                       }
            }
            ;
            else if (parserName == "RuleViolationRemove")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           return props;
                       }
            }
            ;
            else if (parserName == "RuleViolationCancel")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           return props;
                       }
            }
            ;
            else if (parserName == "RuleViolationLock")
            {
                return delegate(NetworkMessage nmsg)
                       {
                           Packet props = new Packet(parserName);
                           return props;
                       }
            }
            ;



            throw new System.ArgumentException("Unknown packet handler.");
        }