コード例 #1
0
        private static void HandleMarketItemPay(GameSession session, MeretMarketItem marketItem, int itemIndex, int totalQuantity)
        {
            switch (marketItem.TokenType)
            {
            case MeretMarketCurrencyType.Meret:
                if (!session.Player.Account.RemoveMerets(marketItem.SalePrice))
                {
                    return;
                }
                break;

            case MeretMarketCurrencyType.Meso:
                if (!session.Player.Wallet.Meso.Modify(marketItem.SalePrice))
                {
                    return;
                }
                break;
            }

            Item item = new Item(marketItem.ItemId)
            {
                Amount = marketItem.Quantity + marketItem.BonusQuantity,
                Rarity = marketItem.Rarity
            };

            if (marketItem.Duration != 0)
            {
                item.ExpiryTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + Environment.TickCount + (marketItem.Duration * (24 * 60 * 60));
            }
            InventoryController.Add(session, item, true);
            session.Send(MeretMarketPacket.Purchase(marketItem, itemIndex, totalQuantity));
        }
コード例 #2
0
    private static void PurchaseUgcItem(GameSession session, long ugcMarketItemId)
    {
        UgcMarketItem marketItem = GameServer.UgcMarketManager.FindItemById(ugcMarketItemId);

        if (marketItem is null || marketItem.ListingExpirationTimestamp < TimeInfo.Now())
        {
            return;
        }

        if (!HandleMarketItemPay(session, marketItem.Price, MeretMarketCurrencyType.Meret))
        {
            return;
        }

        marketItem.SalesCount++;
        DatabaseManager.UgcMarketItems.Update(marketItem);
        _ = new UgcMarketSale(marketItem.Price, marketItem.Item.Ugc.Name, marketItem.SellerCharacterId);

        Item item = new(marketItem.Item)
        {
            CreationTime = TimeInfo.Now()
        };

        item.Uid = DatabaseManager.Items.Insert(item);

        session.Player.Inventory.AddItem(session, item, true);
        session.Send(MeretMarketPacket.Purchase(0, marketItem.MarketId, marketItem.Price, 1));
    }
コード例 #3
0
    private static void HandleRelistItem(GameSession session, PacketReader packet)
    {
        long          ugcMarketItemId = packet.ReadLong();
        long          price           = packet.ReadLong();
        bool          promote         = packet.ReadBool();
        List <string> tags            = packet.ReadUnicodeString().Split(",").ToList();
        string        description     = packet.ReadUnicodeString();
        long          listingFee      = packet.ReadLong();

        UgcMarketItem item = GameServer.UgcMarketManager.FindItemById(ugcMarketItemId);

        if (item is null || item.SellerCharacterId != session.Player.CharacterId || item.ListingExpirationTimestamp < TimeInfo.Now())
        {
            return;
        }

        long totalFee = GetListingFee(session.Player.CharacterId, promote);

        if (!HandleMarketItemPay(session, totalFee, MeretMarketCurrencyType.Meret))
        {
            return;
        }

        item.Price = price;
        item.ListingExpirationTimestamp = long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopSaleDay")) * 86400 + TimeInfo.Now();
        if (promote)
        {
            item.PromotionExpirationTimestamp = long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopAdHour")) * 3600 + item.ListingExpirationTimestamp;
        }
        item.Status      = UgcMarketListingStatus.Active;
        item.Description = description;
        item.Tags        = tags;
        DatabaseManager.UgcMarketItems.Update(item);
        session.Send(MeretMarketPacket.RelistItem(item));
    }
コード例 #4
0
    private static void HandleOpenUGCMarket(GameSession session, PacketReader packet, MeretMarketCategoryMetadata metadata)
    {
        GenderFlag gender = (GenderFlag)packet.ReadByte();
        JobFlag    job    = (JobFlag)packet.ReadInt();
        short      sortBy = packet.ReadByte();

        List <UGCMarketItem> items = GameServer.UGCMarketManager.FindItemsByCategory(metadata.ItemCategories, gender, job, sortBy);

        session.Send(MeretMarketPacket.LoadUGCShopCategory(items));
    }
コード例 #5
0
    private static void HandleOpenPremiumMarket(GameSession session, MeretMarketCategory category)
    {
        List <MeretMarketItem> marketItems = DatabaseManager.MeretMarket.FindAllByCategoryId((category));

        if (marketItems is null)
        {
            return;
        }
        session.Send(MeretMarketPacket.LoadPremiumShopCategory(marketItems));
    }
コード例 #6
0
        private static void HandleHome(GameSession session)
        {
            List <MeretMarketItem> marketItems = DatabaseManager.MeretMarket.FindAllByCategoryId(MeretMarketCategory.Promo);

            if (marketItems == null)
            {
                return;
            }
            session.Send(MeretMarketPacket.Promos(marketItems));
        }
コード例 #7
0
        private static void HandleHome(GameSession session)
        {
            List <MeretMarketMetadata> marketItems = MeretMarketMetadataStorage.GetCategoryItems(MeretMarketCategory.Promo);

            if (marketItems == null)
            {
                return;
            }
            session.Send(MeretMarketPacket.Promos(marketItems));
        }
コード例 #8
0
        private static void HandleOpenPremium(GameSession session, PacketReader packet)
        {
            MeretMarketCategory        category    = (MeretMarketCategory)packet.ReadInt();
            List <MeretMarketMetadata> marketItems = MeretMarketMetadataStorage.GetCategoryItems(category);

            if (marketItems == null)
            {
                return;
            }
            session.Send(MeretMarketPacket.Premium(marketItems));
        }
コード例 #9
0
        private static void HandleOpenPremium(GameSession session, PacketReader packet)
        {
            MeretMarketCategory    category    = (MeretMarketCategory)packet.ReadInt();
            List <MeretMarketItem> marketItems = DatabaseManager.MeretMarket.FindAllByCategoryId(category);

            if (marketItems == null)
            {
                return;
            }
            session.Send(MeretMarketPacket.Premium(marketItems));
        }
コード例 #10
0
        private static void HandleSendMarketRequest(GameSession session, PacketReader packet)
        {
            packet.ReadByte(); //constant 1
            int meretMarketItemUid = packet.ReadInt();
            List <MeretMarketItem> meretMarketItems = new()
            {
                DatabaseManager.MeretMarket.FindById(meretMarketItemUid)
            };

            session.Send(MeretMarketPacket.Premium(meretMarketItems));
        }
    }
コード例 #11
0
    private static void HandleLoadPersonalListings(GameSession session)
    {
        List <UGCMarketItem> items = GameServer.UGCMarketManager.GetItemsByCharacterId(session.Player.CharacterId);

        // TODO: Possibly a better way to implement updating item status?
        foreach (UGCMarketItem item in items)
        {
            if (item.ListingExpirationTimestamp < TimeInfo.Now() && item.Status == UGCMarketListingStatus.Active)
            {
                item.Status = UGCMarketListingStatus.Expired;
                DatabaseManager.UGCMarketItems.Update(item);
            }
        }
        session.Send(MeretMarketPacket.LoadPersonalListings(items));
    }
コード例 #12
0
    private static void HandleListItem(GameSession session, PacketReader packet)
    {
        long          itemUid     = packet.ReadLong();
        long          salePrice   = packet.ReadLong();
        bool          promote     = packet.ReadBool();
        List <string> tags        = packet.ReadUnicodeString().Split(",").ToList();
        string        description = packet.ReadUnicodeString();
        long          listingFee  = packet.ReadLong();

        Item item = null;

        if (session.Player.Inventory.HasItem(itemUid))
        {
            item = session.Player.Inventory.GetByUid(itemUid);
        }
        else if (session.Player.Account.Home.WarehouseInventory.ContainsKey(itemUid))
        {
            item = session.Player.Account.Home.WarehouseInventory[itemUid];
        }

        if (item is null)
        {
            return;
        }

        if (item.Ugc is null || item.Ugc.CharacterId != session.Player.CharacterId || ItemMetadataStorage.GetLimitMetadata(item.Id).MeretMarketListable)
        {
            return;
        }

        if (salePrice < item.Ugc.SalePrice || salePrice > long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopSellMaxPrice")))
        {
            return;
        }

        long totalFee = GetListingFee(session.Player.CharacterId, promote);

        if (!HandleMarketItemPay(session, totalFee, MeretMarketCurrencyType.Meret))
        {
            return;
        }

        UgcMarketItem marketItem = new(item, salePrice, session.Player, tags, description, promote);

        session.Send(MeretMarketPacket.ListItem(marketItem));
        session.Send(MeretMarketPacket.UpdateExpiration(marketItem));
    }
コード例 #13
0
    private static void PurchasePremiumItem(GameSession session, PacketReader packet, int marketItemId)
    {
        packet.ReadInt();
        int    childMarketItemId = packet.ReadInt();
        long   unk2          = packet.ReadLong();
        int    itemIndex     = packet.ReadInt();
        int    totalQuantity = packet.ReadInt();
        int    unk3          = packet.ReadInt();
        byte   unk4          = packet.ReadByte();
        string unk5          = packet.ReadUnicodeString();
        string unk6          = packet.ReadUnicodeString();
        long   price         = packet.ReadLong();

        MeretMarketItem marketItem = DatabaseManager.MeretMarket.FindById(marketItemId);

        if (marketItem is null)
        {
            return;
        }

        if (childMarketItemId != 0)
        {
            marketItem = marketItem.AdditionalQuantities.FirstOrDefault(x => x.MarketId == childMarketItemId);
            if (marketItem is null)
            {
                return;
            }
        }

        if (!HandleMarketItemPay(session, marketItem.Price, marketItem.TokenType))
        {
            return;
        }

        Item item = new(marketItem.ItemId)
        {
            Amount = marketItem.Quantity + marketItem.BonusQuantity,
            Rarity = marketItem.Rarity
        };

        if (marketItem.Duration != 0)
        {
            item.ExpiryTime = TimeInfo.Now() + Environment.TickCount + marketItem.Duration * 24 * 60 * 60;
        }
        session.Player.Inventory.AddItem(session, item, true);
        session.Send(MeretMarketPacket.Purchase(marketItem.MarketId, 0, marketItem.Price, totalQuantity, itemIndex));
    }
コード例 #14
0
    private static void HandleRemoveListing(GameSession session, PacketReader packet)
    {
        packet.ReadInt(); // 0
        long ugcMarketItemId = packet.ReadLong();

        packet.ReadLong(); // duplicate id read?

        UgcMarketItem item = GameServer.UgcMarketManager.FindItemById(ugcMarketItemId);

        if (item is null || item.SellerCharacterId != session.Player.CharacterId)
        {
            return;
        }

        session.Send(MeretMarketPacket.RemoveListing(item.MarketId));
        DatabaseManager.UgcMarketItems.Delete(item.MarketId);
        GameServer.UgcMarketManager.RemoveListing(item);
    }
コード例 #15
0
    private static void HandleOpenShop(GameSession session, PacketReader packet)
    {
        MeretMarketCategory category = (MeretMarketCategory)packet.ReadInt();
        GenderFlag          gender   = (GenderFlag)packet.ReadByte();
        JobFlag             job      = (JobFlag)packet.ReadInt();
        MeretMarketSort     sortBy   = (MeretMarketSort)packet.ReadByte();
        string searchString          = packet.ReadUnicodeString();
        int    startPage             = packet.ReadInt();

        packet.ReadInt(); // repeat page?
        MeretMarketSection section = ReadMarketSection(packet.ReadByte());

        packet.ReadByte();
        byte itemsPerPage = packet.ReadByte();

        MeretMarketTab metadata = MeretMarketCategoryMetadataStorage.GetTabMetadata(section, (int)category);

        if (metadata is null)
        {
            return;
        }

        List <MeretMarketItem> items = new();

        switch (section)
        {
        case MeretMarketSection.UgcMarket:
            items.AddRange(GameServer.UgcMarketManager.FindItems(metadata.ItemCategories, gender, job, searchString));
            break;

        case MeretMarketSection.PremiumMarket:
        case MeretMarketSection.RedMeretMarket:
            items.AddRange(DatabaseManager.MeretMarket.FindAllByCategory(section, category, gender, job, searchString));
            break;
        }

        int totalItems = items.Count;

        items = MeretMarketHelper.MarketItemsSorted(items, sortBy);
        items = MeretMarketHelper.TakeLimit(items, startPage, itemsPerPage);

        session.Send(MeretMarketPacket.LoadShopCategory(items, totalItems));
    }
コード例 #16
0
    private static void HandleUnlistItem(GameSession session, PacketReader packet)
    {
        packet.ReadInt(); // 0
        long ugcMarketItemId = packet.ReadLong();

        packet.ReadLong(); // duplicate id read?

        UgcMarketItem item = GameServer.UgcMarketManager.FindItemById(ugcMarketItemId);

        if (item is null || item.SellerCharacterId != session.Player.CharacterId)
        {
            return;
        }

        item.ListingExpirationTimestamp   = long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopExpiredListingRemovalHour")) * 3600 + TimeInfo.Now();
        item.PromotionExpirationTimestamp = 0;
        item.Status = UgcMarketListingStatus.Expired;
        DatabaseManager.UgcMarketItems.Update(item);
        session.Send(MeretMarketPacket.UpdateExpiration(item));
    }
コード例 #17
0
    private static void HandleListItem(GameSession session, PacketReader packet)
    {
        long          itemUid     = packet.ReadLong();
        long          salePrice   = packet.ReadLong();
        bool          promote     = packet.ReadBool();
        List <string> tags        = packet.ReadUnicodeString().Split(",").ToList();
        string        description = packet.ReadUnicodeString();
        long          listingFee  = packet.ReadLong();

        // TODO: Check if item is a ugc block and not an item. Find item from their block inventory
        if (!session.Player.Inventory.Items.ContainsKey(itemUid))
        {
            return;
        }

        Item item = session.Player.Inventory.Items[itemUid];

        if (item.UGC is null || item.UGC.CharacterId != session.Player.CharacterId)
        {
            return;
        }

        if (salePrice < item.UGC.SalePrice || salePrice > long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopSellMaxPrice")))
        {
            return;
        }

        long totalFee = GetListingFee(session.Player.CharacterId, promote);

        if (!HandleMarketItemPay(session, totalFee, MeretMarketCurrencyType.Meret))
        {
            return;
        }

        UGCMarketItem marketItem = new(item, salePrice, session.Player, tags, description, promote);

        session.Send(MeretMarketPacket.ListItem(marketItem));
        session.Send(MeretMarketPacket.UpdateExpiration(marketItem));
    }
コード例 #18
0
    private static void HandleCollectProfit(GameSession session, PacketReader packet)
    {
        long saleId = packet.ReadLong();

        List <UgcMarketSale> sales = GameServer.UgcMarketManager.GetSalesByCharacterId(session.Player.CharacterId);
        long profitDelayTime       = long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopProfitDelayInDays"));
        long totalProfit           = 0;

        foreach (UgcMarketSale sale in sales)
        {
            if (!(sale.SoldTimestamp + profitDelayTime < TimeInfo.Now()))
            {
                continue;
            }
            totalProfit += sale.Profit;
            GameServer.UgcMarketManager.RemoveSale(sale);
            DatabaseManager.UgcMarketSales.Delete(saleId);
        }

        session.Player.Account.GameMeret.Modify(totalProfit);
        session.Send(MeretsPacket.UpdateMerets(session.Player.Account, totalProfit));
        session.Send(MeretMarketPacket.UpdateProfit(saleId));
    }
コード例 #19
0
    public override void Handle(GameSession session, PacketReader packet)
    {
        long     accountId = packet.ReadLong();
        AuthData authData  = DatabaseManager.AuthData.GetByAccountId(accountId);

        Player dbPlayer = DatabaseManager.Characters.FindPlayerById(authData.OnlineCharacterId, session);

        // Backwards seeking because we read accountId here
        packet.Skip(-8);
        HandleCommon(session, packet);

        session.InitPlayer(dbPlayer);

        Player player = session.Player;

        player.BuddyList = GameServer.BuddyManager.GetBuddies(player.CharacterId);
        player.Mailbox   = GameServer.MailManager.GetMails(player.CharacterId);

        GameServer.PlayerManager.AddPlayer(player);
        GameServer.BuddyManager.SetFriendSessions(player);

        // Only send buddy login notification if player is not changing channels
        if (!player.IsMigrating)
        {
            player.UpdateBuddies();
        }

        if (player.GuildId != 0)
        {
            Guild guild = GameServer.GuildManager.GetGuildById(player.GuildId);
            player.Guild = guild;
            GuildMember guildMember = guild.Members.First(x => x.Id == player.CharacterId);
            guildMember.Player.Session = session;
            player.GuildMember         = guildMember;
            session.Send(GuildPacket.UpdateGuild(guild));
            guild.BroadcastPacketGuild(GuildPacket.MemberJoin(player));
            guild.BroadcastPacketGuild(GuildPacket.MemberLoggedIn(player), session);
        }

        player.IsMigrating = false;

        //session.Send(0x27, 0x01); // Meret market related...?
        session.Send(MushkingRoyaleSystemPacket.LoadStats(player.Account.MushkingRoyaleStats));
        session.Send(MushkingRoyaleSystemPacket.LoadMedals(player.Account));

        player.GetUnreadMailCount();
        session.Send(BuddyPacket.Initialize());
        session.Send(BuddyPacket.LoadList(player.BuddyList));
        session.Send(BuddyPacket.EndList(player.BuddyList.Count));

        // Meret market
        //session.Send("6E 00 0B 00 00 00 00 00 00 00 00 00 00 00 00".ToByteArray());
        //session.Send("6E 00 0C 00 00 00 00".ToByteArray());
        // UserConditionEvent
        //session.Send("BF 00 00 00 00 00 00".ToByteArray());
        // PCBangBonus
        //session.Send("A7 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00".ToByteArray());

        session.Send(TimeSyncPacket.SetInitial1());
        session.Send(TimeSyncPacket.SetInitial2());

        session.Send(StatPacket.SetStats(session.Player.FieldPlayer));
        // session.Send(StatPacket.SetStats(session.Player.FieldPlayer)); // Second packet is meant to send the stats initialized, for now we'll just send the first one

        session.Player.ClientTickSyncLoop();
        session.Send(DynamicChannelPacket.DynamicChannel(short.Parse(ConstantsMetadataStorage.GetConstant("ChannelCount"))));

        session.Send(ServerEnterPacket.Enter(session));
        session.Send(UgcPacket.Unknown22());
        session.Send(CashPacket.Unknown09());

        // SendContentShutdown f(0x01, 0x04)
        session.Send(PvpPacket.Mode0C());
        session.Send(SyncNumberPacket.Send());
        session.Send(SyncValuePacket.SetSyncValue(120000)); // unknown what this value means

        session.Send(PrestigePacket.SetLevels(player));
        session.Send(PrestigePacket.WeeklyMissions());

        // Load inventory tabs
        foreach (InventoryTab tab in Enum.GetValues(typeof(InventoryTab)))
        {
            player.Inventory.LoadInventoryTab(session, tab);
        }

        if (player.Account.HomeId != 0)
        {
            Home home = GameServer.HomeManager.GetHomeById(player.Account.HomeId);
            player.Account.Home = home;
            session.Send(WarehouseInventoryPacket.StartList());
            int counter = 0;
            foreach (KeyValuePair <long, Item> kvp in home.WarehouseInventory)
            {
                session.Send(WarehouseInventoryPacket.Load(kvp.Value, ++counter));
            }

            session.Send(WarehouseInventoryPacket.EndList());

            session.Send(FurnishingInventoryPacket.StartList());
            foreach (Cube cube in home.FurnishingInventory.Values.Where(x => x.Item != null))
            {
                session.Send(FurnishingInventoryPacket.Load(cube));
            }

            session.Send(FurnishingInventoryPacket.EndList());
        }

        session.Send(QuestPacket.StartList());
        session.Send(QuestPacket.Packet1F());
        session.Send(QuestPacket.Packet20());

        IEnumerable <List <QuestStatus> > packetCount = player.QuestData.Values.ToList().SplitList(200); // Split the quest list in 200 quests per packet

        foreach (List <QuestStatus> item in packetCount)
        {
            session.Send(QuestPacket.SendQuests(item));
        }

        session.Send(QuestPacket.EndList());

        session.Send(TrophyPacket.WriteTableStart());
        List <Trophy> trophyList = new(player.TrophyData.Values);
        IEnumerable <List <Trophy> > trophyListPackets = trophyList.SplitList(60);

        foreach (List <Trophy> trophy in trophyListPackets)
        {
            session.Send(TrophyPacket.WriteTableContent(trophy));
        }

        // SendQuest, SendAchieve, SendManufacturer, SendUserMaid
        session.Send(UserEnvPacket.SetTitles(player));
        session.Send(UserEnvPacket.Send04());
        session.Send(UserEnvPacket.Send05());
        session.Send(UserEnvPacket.UpdateLifeSkills(player.GatheringCount));
        session.Send(UserEnvPacket.Send09());
        session.Send(UserEnvPacket.Send10());
        session.Send(UserEnvPacket.Send12());

        session.Send(MeretMarketPacket.ModeC9());

        session.Send(FishingPacket.LoadAlbum(player));

        session.Send(PvpPacket.Mode16());
        session.Send(PvpPacket.Mode17());

        session.Send(ResponsePetPacket.Mode07());
        // LegionBattle (0xF6)
        // CharacterAbility
        // E1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

        // Key bindings and skill slots would normally be loaded from a database
        // If the character is not a new character, this is what we would send
        session.Send(KeyTablePacket.SendFullOptions(player.GameOptions));

        if (player.MapId == (int)Map.UnknownLocation)  // tutorial map
        {
            session.Send(KeyTablePacket.AskKeyboardOrMouse());
        }

        // SendKeyTable f(0x00), SendGuideRecord f(0x03), GameEvent f(0x00)
        // SendBannerList f(0x19), SendRoomDungeon f(0x05, 0x14, 0x17)
        session.Send(DungeonListPacket.DungeonList());
        // 0xF0, ResponsePet P(0F 01)
        // RequestFieldEnter
        //session.Send("16 00 00 41 75 19 03 00 01 8A 42 0F 00 00 00 00 00 00 C0 28 C4 00 40 03 44 00 00 16 44 00 00 00 00 00 00 00 00 55 FF 33 42 E8 49 01 00".ToByteArray());
        session.Send(RequestFieldEnterPacket.RequestEnter(player.FieldPlayer));

        Party party = GameServer.PartyManager.GetPartyByMember(player.CharacterId);

        if (party != null)
        {
            player.Party = party;
            party.BroadcastPacketParty(PartyPacket.LoginNotice(player), session);
            session.Send(PartyPacket.Create(party, false));
        }

        // SendUgc: 15 01 00 00 00 00 00 00 00 00 00 00 00 4B 00 00 00
        // SendHomeCommand: 00 E1 0F 26 89 7F 98 3C 26 00 00 00 00 00 00 00 00

        player.TimeSyncLoop();
        session.Send(TimeSyncPacket.SetSessionServerTick(0));
        //session.Send("B9 00 00 E1 0F 26 89 7F 98 3C 26 00 00 00 00 00 00 00 00".ToByteArray());
        session.Send(ServerEnterPacket.Confirm());

        //session.Send(0xF0, 0x00, 0x1F, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00);
        //session.Send(0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00);
    }
コード例 #20
0
    private static void HandleLoadSales(GameSession session)
    {
        List <UGCMarketSale> sales = GameServer.UGCMarketManager.GetSalesByCharacterId(session.Player.CharacterId);

        session.Send(MeretMarketPacket.LoadSales(sales));
    }
コード例 #21
0
 private static void HandleInitialize(GameSession session)
 {
     session.Send(MeretMarketPacket.Initialize());
 }
コード例 #22
0
 private static void HandleLoadCart(GameSession session)
 {
     session.Send(MeretMarketPacket.LoadCart());
 }
コード例 #23
0
    private static void PurchasePremiumItem(GameSession session, PacketReader packet, int marketItemId)
    {
        packet.ReadInt();
        int    childMarketItemId = packet.ReadInt();
        long   unk2          = packet.ReadLong();
        int    itemIndex     = packet.ReadInt();
        int    totalQuantity = packet.ReadInt();
        int    unk3          = packet.ReadInt();
        byte   unk4          = packet.ReadByte();
        string unk5          = packet.ReadUnicodeString();
        string unk6          = packet.ReadUnicodeString();
        long   price         = packet.ReadLong();

        PremiumMarketItem marketItem = DatabaseManager.MeretMarket.FindById(marketItemId);

        if (marketItem is null)
        {
            return;
        }

        if (childMarketItemId != 0)
        {
            marketItem = marketItem.AdditionalQuantities.FirstOrDefault(x => x.MarketId == childMarketItemId);
            if (marketItem is null)
            {
                return;
            }
        }

        long itemPrice = marketItem.Price;

        if (marketItem.SalePrice != 0)
        {
            itemPrice = marketItem.SalePrice;
        }
        if (!HandleMarketItemPay(session, itemPrice, marketItem.TokenType))
        {
            SystemNotice noticeId = SystemNotice.EmptyString;
            switch (marketItem.TokenType)
            {
            case MeretMarketCurrencyType.Meso:
                noticeId = SystemNotice.ErrorInsufficientMeso;
                break;

            case MeretMarketCurrencyType.Meret:
                noticeId = SystemNotice.ErrorInsufficientMeret;
                break;

            case MeretMarketCurrencyType.RedMeret:
                noticeId = SystemNotice.ErrorInsufficientMeretRed;
                break;
            }

            session.Send(NoticePacket.Notice(noticeId, NoticeType.Popup));
            return;
        }

        Item item = new(marketItem.ItemId, marketItem.Quantity + marketItem.BonusQuantity, marketItem.Rarity);

        if (marketItem.Duration != 0)
        {
            item.ExpiryTime = TimeInfo.Now() + Environment.TickCount + marketItem.Duration * 24 * 60 * 60;
        }
        session.Player.Inventory.AddItem(session, item, true);
        session.Send(MeretMarketPacket.Purchase((int)marketItem.MarketId, 0, marketItem.Price, totalQuantity, itemIndex));
    }