/// <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 async void Upload(ushort worldId, MarketBoardItemRequest request) { using (var client = new WebClient()) { _packetProcessor.Log?.Invoke(this, "Starting Universalis upload."); var uploader = _packetProcessor.LocalContentId; var listingsRequestObject = new UniversalisItemListingsUploadRequest(); listingsRequestObject.WorldId = worldId; listingsRequestObject.UploaderId = uploader; listingsRequestObject.ItemId = request.CatalogId; listingsRequestObject.Listings = new List <UniversalisItemListingsEntry>(); foreach (var marketBoardItemListing in request.Listings) { var universalisListing = new UniversalisItemListingsEntry { Hq = marketBoardItemListing.IsHq, SellerId = marketBoardItemListing.RetainerOwnerId, RetainerName = marketBoardItemListing.RetainerName, RetainerId = marketBoardItemListing.RetainerId, CreatorId = marketBoardItemListing.ArtisanId, CreatorName = marketBoardItemListing.PlayerName, OnMannequin = marketBoardItemListing.OnMannequin, LastReviewTime = ((DateTimeOffset)marketBoardItemListing.LastReviewTime).ToUnixTimeSeconds(), PricePerUnit = marketBoardItemListing.PricePerUnit, Quantity = marketBoardItemListing.ItemQuantity, RetainerCity = marketBoardItemListing.RetainerCityId }; universalisListing.Materia = new List <UniversalisItemMateria>(); foreach (var itemMateria in marketBoardItemListing.Materia) { universalisListing.Materia.Add(new UniversalisItemMateria { MateriaId = itemMateria.MateriaId, SlotId = itemMateria.Index }); } listingsRequestObject.Listings.Add(universalisListing); } await Request.SendAsJson($"{ApiBase}/upload/{_apiKey}", "", listingsRequestObject); var historyRequestObject = new UniversalisHistoryUploadRequest(); historyRequestObject.WorldId = worldId; historyRequestObject.UploaderId = uploader; historyRequestObject.ItemId = request.CatalogId; historyRequestObject.Entries = new List <UniversalisHistoryEntry>(); foreach (var marketBoardHistoryListing in request.History) { historyRequestObject.Entries.Add(new UniversalisHistoryEntry { BuyerName = marketBoardHistoryListing.BuyerName, Hq = marketBoardHistoryListing.IsHq, OnMannequin = marketBoardHistoryListing.OnMannequin, PricePerUnit = marketBoardHistoryListing.SalePrice, Quantity = marketBoardHistoryListing.Quantity, Timestamp = ((DateTimeOffset)marketBoardHistoryListing.PurchaseTime).ToUnixTimeSeconds() }); } await Request.SendAsJson($"{ApiBase}/upload/{_apiKey}", "", historyRequestObject); _packetProcessor.Log?.Invoke(this, $"Universalis data upload for item#{request.CatalogId} to world#{historyRequestObject.WorldId} completed."); } }