Esempio n. 1
0
        /// <summary>
        /// Process a zone proto message and scan for relevant data.
        /// </summary>
        /// <param name="message">The message bytes.</param>
        /// <returns>True if an upload succeeded.</returns>
        private MarketBoardItemRequest GetRequestData(MatchaOpcode opcode, byte[] message)
        {
            if (opcode == MatchaOpcode.PlayerSetup)
            {
                LocalContentId = BitConverter.ToUInt64(message, 0x20);
                LocalContentId = LocalContentId & 0xffffffff00000000 | (uint)Config.Instance.UUIDHash; // mask the lower 32 bit for privacy concern
                Log?.Invoke(this, $"New CID: {LocalContentId.ToString("X")}");
                LocalContentIdUpdated?.Invoke(this, LocalContentId);
                return(null);
            }

            if (opcode == MatchaOpcode.MarketBoardItemListingCount)
            {
                var catalogId = (uint)BitConverter.ToInt32(message, 0x20);
                var amount    = message[0x2B];

                var request = _marketBoardRequests.LastOrDefault(r => r.CatalogId == catalogId);
                if (request == null)
                {
                    _marketBoardRequests.Add(new MarketBoardItemRequest
                    {
                        CatalogId      = catalogId,
                        AmountToArrive = amount,
                        Listings       = new List <MarketBoardCurrentOfferings.MarketBoardItemListing>(),
                        History        = new List <MarketBoardHistory.MarketBoardHistoryListing>()
                    });
                }
                else
                {
                    request.AmountToArrive = amount;
                    request.Listings.Clear();
                }

                Log?.Invoke(this, $"NEW MB REQUEST START: item#{catalogId} amount#{amount}");
                return(null);
            }

            if (opcode == MatchaOpcode.MarketBoardItemListing)
            {
                var listing = MarketBoardCurrentOfferings.Read(message.Skip(0x20).ToArray());

                var request =
                    _marketBoardRequests.LastOrDefault(
                        r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone);

                if (request == null)
                {
                    Log?.Invoke(this,
                                $"[ERROR] Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}");
                    return(null);
                }

                if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive)
                {
                    Log?.Invoke(this,
                                $"[ERROR] Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}");
                    _marketBoardRequests.Remove(request);
                    return(null);
                }

                if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId)
                {
                    Log?.Invoke(this,
                                $"[ERROR] Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}");
                    _marketBoardRequests.Remove(request);
                    return(null);
                }

                if (request.ListingsRequestId == -1 && request.Listings.Count > 0)
                {
                    Log?.Invoke(this,
                                $"[ERROR] Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
                    _marketBoardRequests.Remove(request);
                    return(null);
                }

                if (request.ListingsRequestId == -1)
                {
                    request.ListingsRequestId = listing.RequestId;
                    Log?.Invoke(this, $"First Market Board packet in sequence: {listing.RequestId}");
                }

                request.Listings.AddRange(listing.ItemListings);

                Log?.Invoke(this,
                            $"Added {listing.ItemListings.Count} ItemListings to request#{request.ListingsRequestId}, now {request.Listings.Count}/{request.AmountToArrive}, item#{request.CatalogId}");

                if (request.IsDone)
                {
                    if (CurrentWorldId == 0)
                    {
                        Log?.Invoke(this, "[ERROR] Not sure about your current world. Please move your character between zones once to start uploading.");
                        _marketBoardRequests.Remove(request);
                        return(null);
                    }

                    RequestContentIdUpdate?.Invoke(this, null);

                    if (LocalContentId == 0)
                    {
                        Log?.Invoke(this, "Not sure about your character information. Please log in once with your character while having the program open to verify it.");
                    }

                    LocalContentIdUpdated?.Invoke(this, LocalContentId);

                    Log?.Invoke(this,
                                $"Market Board request finished, starting upload: request#{request.ListingsRequestId} item#{request.CatalogId} amount#{request.AmountToArrive}");
                    return(request);
                }

                return(null);
            }

            if (opcode == MatchaOpcode.MarketBoardItemListingHistory)
            {
                var listing = MarketBoardHistory.Read(message.Skip(0x20).ToArray());

                var request = _marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId);

                if (request == null)
                {
                    request = new MarketBoardItemRequest
                    {
                        CatalogId      = listing.CatalogId,
                        AmountToArrive = 0,
                        Listings       = new List <MarketBoardCurrentOfferings.MarketBoardItemListing>(),
                        History        = new List <MarketBoardHistory.MarketBoardHistoryListing>()
                    };
                    _marketBoardRequests.Add(request);
                }

                request.History.AddRange(listing.HistoryListings);

                if (request.IsDone)
                {
                    if (CurrentWorldId == 0)
                    {
                        Log?.Invoke(this, "[ERROR] Not sure about your current world. Please move your character between zones once to start uploading.");
                        _marketBoardRequests.Remove(request);
                        return(null);
                    }

                    RequestContentIdUpdate?.Invoke(this, null);

                    if (LocalContentId == 0)
                    {
                        Log?.Invoke(this, "Not sure about your character information. Please log in once with your character while having the program open to verify it.");
                    }

                    LocalContentIdUpdated?.Invoke(this, LocalContentId);

                    Log?.Invoke(this,
                                $"Market Board request finished, starting upload: request#{request.ListingsRequestId} item#{request.CatalogId} amount#{request.AmountToArrive}");
                    return(request);
                }

                Log?.Invoke(this, $"Added history for item#{listing.CatalogId}");
                return(null);
            }

            return(null);
        }
        public static MarketBoardCurrentOfferings Read(byte[] message)
        {
            var output = new MarketBoardCurrentOfferings();

            using (var stream = new MemoryStream(message))
            {
                using (var reader = new BinaryReader(stream))
                {
                    output.ItemListings = new List <MarketBoardItemListing>();

                    for (var i = 0; i < 10; i++)
                    {
                        var listingEntry = new MarketBoardItemListing();

                        listingEntry.ListingId       = reader.ReadUInt64();
                        listingEntry.RetainerId      = reader.ReadUInt64();
                        listingEntry.RetainerOwnerId = reader.ReadUInt64();
                        listingEntry.ArtisanId       = reader.ReadUInt64();
                        listingEntry.PricePerUnit    = reader.ReadUInt32();
                        listingEntry.TotalTax        = reader.ReadUInt32();
                        listingEntry.ItemQuantity    = reader.ReadUInt32();
                        listingEntry.CatalogId       = reader.ReadUInt32();
                        listingEntry.LastReviewTime  = DateTimeOffset.UtcNow.AddSeconds(-reader.ReadUInt16()).DateTime;

                        reader.ReadUInt16(); // container
                        reader.ReadUInt32(); // slot
                        reader.ReadUInt16(); // durability
                        reader.ReadUInt16(); // spiritbond

                        listingEntry.Materia = new List <MarketBoardItemListing.ItemMateria>();

                        for (var materiaIndex = 0; materiaIndex < 5; materiaIndex++)
                        {
                            var materiaVal = reader.ReadUInt16();

                            var materiaEntry = new MarketBoardItemListing.ItemMateria();
                            materiaEntry.MateriaId = (materiaVal & 0xFF0) >> 4;
                            materiaEntry.Index     = materiaVal & 0xF;

                            if (materiaEntry.MateriaId != 0)
                            {
                                listingEntry.Materia.Add(materiaEntry);
                            }
                        }

                        reader.ReadUInt16();
                        reader.ReadUInt32();

                        listingEntry.RetainerName   = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd(new[] { '\u0000' });
                        listingEntry.PlayerName     = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd(new[] { '\u0000' });
                        listingEntry.IsHq           = reader.ReadBoolean();
                        listingEntry.MateriaCount   = reader.ReadByte();
                        listingEntry.OnMannequin    = reader.ReadBoolean();
                        listingEntry.RetainerCityId = reader.ReadByte();
                        listingEntry.StainId        = reader.ReadUInt16();

                        reader.ReadUInt16();
                        reader.ReadUInt32();

                        if (listingEntry.CatalogId != 0)
                        {
                            output.ItemListings.Add(listingEntry);
                        }
                    }

                    output.ListingIndexEnd   = reader.ReadByte();
                    output.ListingIndexStart = reader.ReadByte();
                    output.RequestId         = reader.ReadUInt16();
                }
            }

            return(output);
        }