Пример #1
0
    private static void HandleCreate(GameSession session, PacketReader packet)
    {
        Party party = GameServer.PartyManager.GetPartyByLeader(session.Player);

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

        int maxClubCount = int.Parse(ConstantsMetadataStorage.GetConstant("ClubMaxCount"));

        // Fail if a party member is offline or if member has joined max amount of clubs
        if (party.Members.Any(x => !x.Session.Connected()) || party.Members.Any(x => x.Clubs.Count >= maxClubCount))
        {
            session.Send(ClubPacket.ErrorNotice((int)ClubErrorNotice.SomePartyMembersCannotBeInvited));
            return;
        }

        string clubName = packet.ReadUnicodeString();

        if (!ValidClubName(session, clubName))
        {
            return;
        }


        Club club = new(party, clubName);

        GameServer.ClubManager.AddClub(club);

        party.BroadcastPacketParty(ClubPacket.Create(party, club));
    }
Пример #2
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));
    }
Пример #3
0
    public static PacketWriter SetMax(int unlocked)
    {
        PacketWriter pWriter = PacketWriter.Of(SendOp.CharMaxCount);

        pWriter.WriteInt(unlocked);
        pWriter.WriteInt(int.Parse(ConstantsMetadataStorage.GetConstant("MaxCharacterSlots")));

        return(pWriter);
    }
Пример #4
0
    public UgcMarketSale(long price, string itemName, long sellerCharacterId)
    {
        Price             = price;
        ItemName          = itemName;
        SellerCharacterId = sellerCharacterId;
        float fee = float.Parse(ConstantsMetadataStorage.GetConstant("UGCShopProfitFee")) * price;

        Profit        = (long)(price - fee);
        SoldTimestamp = TimeInfo.Now();
        Id            = DatabaseManager.UgcMarketSales.Insert(this);
        GameServer.UgcMarketManager.AddSale(this);
    }
Пример #5
0
    public LoginHandler()
    {
        ImmutableList <IPEndPoint> .Builder builder = ImmutableList.CreateBuilder <IPEndPoint>();
        string ipAddress = Environment.GetEnvironmentVariable("IP");
        int    port      = int.Parse(Environment.GetEnvironmentVariable("LOGIN_PORT"));

        builder.Add(new(IPAddress.Parse(ipAddress), port));

        ServerIPs    = builder.ToImmutable();
        ServerName   = Environment.GetEnvironmentVariable("NAME");
        ChannelCount = short.Parse(ConstantsMetadataStorage.GetConstant("ChannelCount"));
    }
Пример #6
0
    private static long GetListingFee(long characterId, bool promote)
    {
        int      activeListingsCount = GameServer.UgcMarketManager.GetItemsByCharacterId(characterId).Count;
        Script   script      = ScriptLoader.GetScript("Functions/calcMeretMarketRegisterFee");
        DynValue feeDynValue = script.RunFunction("calcMeretMarketRegisterFee", activeListingsCount);
        long     fee         = (long)feeDynValue.Number;

        if (promote)
        {
            fee += long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopAdFeeMerat"));
        }
        return(fee);
    }
Пример #7
0
    public MesoMarketListing(Player player, long price, long mesos)
    {
        OwnerAccountId   = player.AccountId;
        OwnerCharacterId = player.CharacterId;
        ListedTimestamp  = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
        int sellEndTime = int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketListingDayDuration")) * 86400;

        ExpiryTimestamp = ListedTimestamp + sellEndTime;
        Price           = price;
        Mesos           = mesos;
        Id = DatabaseManager.MesoMarketListings.Insert(this);
        GameServer.MesoMarketManager.AddListing(this);
    }
Пример #8
0
    private static long GetListingFee(long characterId, bool promote)
    {
        int  activeListingsCount = GameServer.UGCMarketManager.GetItemsByCharacterId(characterId).Count;
        long baseFee             = long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopBaseListFee"));
        long fee = baseFee + activeListingsCount * 100;

        // Max fee being 390
        fee = Math.Min(fee, baseFee + 200);
        if (promote)
        {
            fee += long.Parse(ConstantsMetadataStorage.GetConstant("UGCShopAdFeeMerat"));
        }
        return(fee);
    }
Пример #9
0
    public BlackMarketListing(Player player, Item item, int listedQuantity, long price, long deposit)
    {
        ListedTimestamp = TimeInfo.Now();
        int sellEndTime = int.Parse(ConstantsMetadataStorage.GetConstant("BlackMarketSellEndDay")) * 86400;

        ExpiryTimestamp  = ListedTimestamp + sellEndTime;
        Price            = price;
        Deposit          = deposit;
        Item             = item;
        ListedQuantity   = listedQuantity;
        OwnerAccountId   = player.AccountId;
        OwnerCharacterId = player.CharacterId;
        Id = DatabaseManager.BlackMarketListings.Insert(this);
        GameServer.BlackMarketManager.AddListing(this);
    }
    private static void HandleExpandCharacterSlot(GameSession session, Item item)
    {
        Account account  = DatabaseManager.Accounts.FindById(session.Player.AccountId);
        int     maxSlots = int.Parse(ConstantsMetadataStorage.GetConstant("MaxCharacterSlots"));

        if (account.CharacterSlots >= maxSlots)
        {
            session.Send(CouponUsePacket.MaxCharacterSlots());
            return;
        }

        account.CharacterSlots++;
        DatabaseManager.Accounts.Update(account);
        session.Send(CouponUsePacket.CharacterSlotAdded());
        session.Player.Inventory.ConsumeItem(session, item.Uid, 1);
    }
Пример #11
0
    private static void GetSumMesos(Player player, long incomingMesos, long outgoingMesos)
    {
        long sumMesos = incomingMesos + outgoingMesos;

        if (sumMesos > 0)
        {
            float feeRate = int.Parse(ConstantsMetadataStorage.GetConstant("TradeFeePercent")) / 100f;
            long  tax     = (long)(feeRate * sumMesos);
            sumMesos -= tax;
        }

        if (sumMesos != 0)
        {
            player.Wallet.Meso.Modify(sumMesos);
        }
    }
Пример #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
    public static PacketWriter LoadMarket()
    {
        PacketWriter pWriter = PacketWriter.Of(SendOp.MESO_MARKET);

        pWriter.Write(MesoMarketPacketMode.LoadMarket);
        pWriter.WriteFloat(float.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketTax")));
        pWriter.WriteFloat(float.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketPriceRange")));
        pWriter.WriteLong(long.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketAveragePrice"))); // TODO: Calculate average price
        pWriter.WriteInt(int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketTotaListingsLimit")));
        pWriter.WriteInt(int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketDailyListingsLimit")));
        pWriter.WriteInt(int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketMonthlyPurchaseLimit")));
        pWriter.WriteInt(int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketListingDayDuration")));
        pWriter.WriteInt(int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketListingsDisplayCount")));
        pWriter.WriteInt(100);  // unk
        pWriter.WriteInt(1000); // unk
        return(pWriter);
    }
Пример #14
0
    private static void HandleRoll(GameSession session, GameEventUserValue totalTileValue, GameEventUserValue freeRollValue)
    {
        // Check if player can roll
        int tokenItemId = int.Parse(ConstantsMetadataStorage.GetConstant("MapleopolyTokenItemId"));
        int tokenCost   = int.Parse(ConstantsMetadataStorage.GetConstant("MapleopolyTokenCost"));

        Item token = session.Player.Inventory.GetById(tokenItemId);

        int.TryParse(freeRollValue.EventValue, out int freeRolls);

        if (freeRolls > 0)
        {
            freeRolls--;
        }
        else if (token != null && token.Amount >= tokenCost)
        {
            session.Player.Inventory.ConsumeItem(session, token.Uid, tokenCost);
        }
        else
        {
            session.Send(MapleopolyPacket.Notice((byte)MapleopolyNotice.NotEnoughTokens));
            return;
        }

        Random rnd = Random.Shared;

        // roll two dice
        int roll1     = rnd.Next(1, 6);
        int roll2     = rnd.Next(1, 6);
        int totalRoll = roll1 + roll2;

        int.TryParse(totalTileValue.EventValue, out int totalTiles);
        totalTiles += totalRoll;
        if (roll1 == roll2)
        {
            freeRolls++;
        }

        // update user event values
        freeRollValue.UpdateValue(session, freeRolls);
        totalTileValue.UpdateValue(session, totalTiles);

        session.Send(MapleopolyPacket.Roll(totalTiles, roll1, roll2));
    }
Пример #15
0
    private static void HandleNewClubInvite(GameSession session, PacketReader packet)
    {
        if (session.Player.Clubs.Count > int.Parse(ConstantsMetadataStorage.GetConstant("ClubMaxCount")))
        {
            return;
        }

        long clubId = packet.ReadLong();

        Club club = GameServer.ClubManager.GetClubById(clubId);

        if (club == null)
        {
            return;
        }

        ClubInviteResponse response = (ClubInviteResponse)packet.ReadInt();

        club.InvitedPlayerResponse(session.Player, response);
    }
Пример #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 HandleSendInvite(GameSession session, PacketReader packet)
    {
        long   clubId  = packet.ReadLong();
        string invitee = packet.ReadUnicodeString();

        Player other = GameServer.PlayerManager.GetPlayerByName(invitee);

        if (other == null)
        {
            return;
        }

        if (other.Clubs.Any(x => x.Id == clubId))
        {
            session.Send(ClubPacket.ErrorNotice((int)ClubErrorNotice.AlreadyInClub));
            return;
        }

        if (other.Clubs.Count >= int.Parse(ConstantsMetadataStorage.GetConstant("ClubMaxCount")))
        {
            session.Send(ClubPacket.ErrorNotice((int)ClubErrorNotice.PlayerCannotJoinMoreClubs));
            return;
        }

        Club club = GameServer.ClubManager.GetClubById(clubId);

        if (club == null)
        {
            return;
        }

        if (club.Members.Count >= int.Parse(ConstantsMetadataStorage.GetConstant("ClubMaxMembers")))
        {
            session.Send(ClubPacket.ErrorNotice((int)ClubErrorNotice.ClubIsFull));
            return;
        }

        session.Send(ClubPacket.InviteSentReceipt(clubId, other));
        other.Session.Send(ClubPacket.Invite(club, other));
    }
Пример #18
0
    private static void HandleOpen(GameSession session, GameEventUserValue totalTileValue, GameEventUserValue freeRollValue)
    {
        List <MapleopolyTile> tiles = DatabaseManager.Mapleopoly.FindAllTiles();

        if (tiles.Count == 0)
        {
            return;
        }

        int  tokenAmount = 0;
        int  tokenItemId = int.Parse(ConstantsMetadataStorage.GetConstant("MapleopolyTokenItemId"));
        Item token       = session.Player.Inventory.GetById(tokenItemId);

        if (token != null)
        {
            tokenAmount = token.Amount;
        }

        int.TryParse(totalTileValue.EventValue, out int totalTiles);
        int.TryParse(freeRollValue.EventValue, out int freeRolls);
        session.Send(MapleopolyPacket.Open(totalTiles, freeRolls, tiles, tokenItemId, tokenAmount));
    }
Пример #19
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));
    }
Пример #20
0
    private static void HandlePurchase(GameSession session, PacketReader packet)
    {
        long listingId = packet.ReadLong();

        if (session.Player.Account.MesoMarketMonthlyPurchases >= int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketMonthlyPurchaseLimit")))
        {
            return;
        }

        MesoMarketListing listing = GameServer.MesoMarketManager.GetListingById(listingId);

        if (listing is null)
        {
            session.Send(MesoMarketPacket.Error((int)MesoMarketError.ItemSoldOut));
            return;
        }

        if (!session.Player.Account.MesoToken.Modify(-listing.Price))
        {
            session.Send(MesoMarketPacket.Error((int)MesoMarketError.NotEnoughMesos));
            return;
        }

        if (listing.OwnerAccountId == session.Player.AccountId)
        {
            session.Send(MesoMarketPacket.Error((int)MesoMarketError.CantPurchaseOwnMeso));
            return;
        }

        session.Player.Account.MesoMarketMonthlyPurchases++;
        DatabaseManager.Accounts.Update(session.Player.Account);
        session.Send(MesoMarketPacket.Purchase(listingId));
        session.Send(MesoMarketPacket.AccountStats(session.Player.Account.MesoMarketDailyListings, session.Player.Account.MesoMarketMonthlyPurchases));

        MailHelper.MesoMarketTransaction(listing, session.Player.CharacterId);
        GameServer.MesoMarketManager.RemoveListing(listing);
        DatabaseManager.MesoMarketListings.Delete(listingId);
    }
Пример #21
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));
    }
Пример #22
0
    private static void HandleCreateListing(GameSession session, PacketReader packet)
    {
        long mesos = packet.ReadLong();
        long price = packet.ReadLong();

        if (session.Player.Account.MesoMarketDailyListings >= int.Parse(ConstantsMetadataStorage.GetConstant("MesoMarketDailyListingsLimit")))
        {
            session.Send(MesoMarketPacket.Error((int)MesoMarketError.ReachedListingLimit));
            return;
        }

        if (!session.Player.Wallet.Meso.Modify(-mesos))
        {
            session.Send(MesoMarketPacket.Error((int)MesoMarketError.NotEnoughMesosToList));
            return;
        }

        MesoMarketListing listing = new(session.Player, price, mesos);

        session.Player.Account.MesoMarketDailyListings++;
        DatabaseManager.Accounts.Update(session.Player.Account);
        session.Send(MesoMarketPacket.CreateListing(listing));
        session.Send(MesoMarketPacket.AccountStats(session.Player.Account.MesoMarketDailyListings, session.Player.Account.MesoMarketMonthlyPurchases));
    }
Пример #23
0
    private static void SendBlackMarketSoldMail(BlackMarketListing listing, Item item, long price, bool removeListing)
    {
        float salesFeeRate = float.Parse(ConstantsMetadataStorage.GetConstant("BlackMarketSalesFeeRate"));
        long  tax          = (long)(salesFeeRate * (item.Amount * price));
        long  revenue      = item.Amount * price - tax;

        string senderName    = "<ms2><v key=\"s_blackmarket_mail_to_sender\" /></ms2>";
        string title         = "<ms2><v key=\"s_blackmarket_mail_to_seller_title\" /></ms2>";
        string body          = "<ms2><v key=\"s_blackmarket_mail_to_seller_content\" /></ms2>";
        string addParameter1 = $"<ms2><v item=\"{item.Id}\" ></v></ms2>";
        string addParameter2 = $"<ms2><v item=\"{item.Id}\" ></v><v str=\"{item.Amount}\" ></v><v money=\"{price * item.Amount}\" ></v><v money=\"{price}\" ></v><v money=\"{tax}\" ></v><v str=\"{salesFeeRate * 100}%\" ></v><v money=\"{revenue}\" ></v></ms2>";

        if (removeListing)
        {
            revenue      += listing.Deposit;
            body          = "<ms2><v key=\"s_blackmarket_mail_to_seller_content_soldout\" /></ms2>";
            addParameter2 = $"<ms2><v item=\"{item.Id}\" ></v><v str=\"{item.Amount}\" ></v><v money=\"{price * item.Amount}\" ></v><v money=\"{price}\" ></v><v money=\"{tax}\" ></v><v str=\"{salesFeeRate * 100}%\" ></v><v money=\"{listing.Deposit}\" ></v><v money=\"{revenue}\" ></v></ms2>";
        }

        Mail mail = new(MailType.BlackMarketSale, listing.OwnerCharacterId, 0, senderName, title, body, addParameter1, addParameter2, new(), revenue, 0);

        GameServer.MailManager.AddMail(mail);
        SendNotification(mail);
    }
Пример #24
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);
    }