private void OnNetworkEvent(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) { if (direction != NetworkMessageDirection.ZoneDown) { return; } if (!this.pi.Data.IsDataReady) { return; } if (opCode == this.pi.Data.ServerOpCodes["MarketBoardItemRequestStart"]) { this.newRequest = true; } if (opCode != this.pi.Data.ServerOpCodes["MarketBoardOfferings"] || !this.newRequest) { return; } if (!this.configuration.alwaysOn && (!this.configuration.smart || !Retainer())) { return; } var listing = MarketBoardCurrentOfferings.Read(dataPtr); var i = 0; if (this.configuration.hq && this.items.Single(j => j.RowId == listing.ItemListings[0].CatalogId).CanBeHq) { while (i < listing.ItemListings.Count && !listing.ItemListings[i].IsHq) { i++; } if (i == listing.ItemListings.Count) { return; } } while (i != listing.ItemListings.Count && this.configuration.whitelist.Contains(listing.ItemListings[i].RetainerName)) { i++; } var price = listing.ItemListings[i].PricePerUnit - this.configuration.delta; Clipboard.SetText(price.ToString()); if (this.configuration.verbose) { this.pi.Framework.Gui.Chat.Print($"{price} copied to clipboard."); } this.newRequest = false; }
private void OnNetworkEvent(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) { if (direction != NetworkMessageDirection.ZoneDown) { return; } if (!Data.IsDataReady) { return; } if (opCode == Data.ServerOpCodes["MarketBoardItemRequestStart"]) { newRequest = true; } if (opCode != Data.ServerOpCodes["MarketBoardOfferings"] || !newRequest) { return; } if (!configuration.alwaysOn && (!configuration.smart || !Retainer())) { return; } var listing = MarketBoardCurrentOfferings.Read(dataPtr); var i = 0; if (configuration.hq && items.Single(j => j.RowId == listing.ItemListings[0].CatalogId).CanBeHq) { while (i < listing.ItemListings.Count && !listing.ItemListings[i].IsHq) { i++; } if (i == listing.ItemListings.Count) { return; } } var price = listing.ItemListings[i].PricePerUnit - (listing.ItemListings[i].PricePerUnit % configuration.mod) - configuration.delta; price = Math.Max(price, configuration.min); ImGui.SetClipboardText(price.ToString()); if (configuration.verbose) { Chat.Print((configuration.hq ? "[HQ] " : string.Empty) + $"{price:n0} copied to clipboard."); } newRequest = false; }
private void OnZonePacket(IntPtr dataPtr) { if (!this.dalamud.Data.IsDataReady) { return; } var opCode = (ushort)Marshal.ReadInt16(dataPtr, 2); if (opCode == this.dalamud.Data.ServerOpCodes["CfNotifyPop"]) { var data = new byte[64]; Marshal.Copy(dataPtr, data, 0, 64); var notifyType = data[16]; var contentFinderConditionId = BitConverter.ToUInt16(data, 36); if (notifyType != 3) { return; } var contentFinderCondition = this.dalamud.Data.GetExcelSheet <ContentFinderCondition>().GetRow(contentFinderConditionId); if (contentFinderCondition == null) { Log.Error("CFC key {0} not in lumina data.", contentFinderConditionId); return; } if (string.IsNullOrEmpty(contentFinderCondition.Name)) { contentFinderCondition.Name = "Duty Roulette"; contentFinderCondition.Image = 112324; } var flashInfo = new NativeFunctions.FLASHWINFO(); flashInfo.cbSize = (uint)Marshal.SizeOf <NativeFunctions.FLASHWINFO>(); flashInfo.uCount = uint.MaxValue; flashInfo.dwTimeout = 0; flashInfo.dwFlags = NativeFunctions.FlashWindow.FLASHW_TRAY | NativeFunctions.FlashWindow.FLASHW_TIMERNOFG; flashInfo.hwnd = Process.GetCurrentProcess().MainWindowHandle; NativeFunctions.FlashWindowEx(ref flashInfo); Task.Run(async() => { this.dalamud.Framework.Gui.Chat.Print("Duty pop: " + contentFinderCondition.Name); await this.ProcessCfPop?.Invoke(contentFinderCondition); }); return; } if (opCode == this.dalamud.Data.ServerOpCodes["CfPreferredRole"]) { if (this.dalamud.Configuration.PreferredRoleReminders == null) { return; } var data = new byte[64]; Marshal.Copy(dataPtr, data, 0, 32); if (this.lastPreferredRole == null) { this.lastPreferredRole = data; return; } Task.Run(async() => { for (var rouletteIndex = 1; rouletteIndex < 11; rouletteIndex++) { var currentRoleKey = data[16 + rouletteIndex]; var prevRoleKey = this.lastPreferredRole[16 + rouletteIndex]; Log.Verbose("CfPreferredRole: {0} - {1} => {2}", rouletteIndex, prevRoleKey, currentRoleKey); if (currentRoleKey != prevRoleKey) { var rouletteName = rouletteIndex switch { 1 => "Duty Roulette: Leveling", 2 => "Duty Roulette: Level 50/60/70 Dungeons", 3 => "Duty Roulette: Main Scenario", 4 => "Duty Roulette: Guildhests", 5 => "Duty Roulette: Expert", 6 => "Duty Roulette: Trials", 8 => "Duty Roulette: Mentor", 9 => "Duty Roulette: Alliance Raids", 10 => "Duty Roulette: Normal Raids", _ => "Unknown ContentRoulette" }; var prevRoleName = RoleKeyToPreferredRole(prevRoleKey); var currentRoleName = RoleKeyToPreferredRole(currentRoleKey); if (!this.dalamud.Configuration.PreferredRoleReminders.TryGetValue(rouletteIndex, out var roleToCheck)) { return; } if (roleToCheck == DalamudConfiguration.PreferredRole.All || currentRoleName != roleToCheck) { return; } this.dalamud.Framework.Gui.Chat.Print($"Roulette bonus for {rouletteName} changed: {prevRoleName} => {currentRoleName}"); if (this.dalamud.BotManager.IsConnected) { await this.dalamud.BotManager.ProcessCfPreferredRoleChange(rouletteName, prevRoleName.ToString(), currentRoleName.ToString()); } } } this.lastPreferredRole = data; }); return; } if (!this.optOutMbUploads) { if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardItemRequestStart"]) { var catalogId = (uint)Marshal.ReadInt32(dataPtr + 0x10); var amount = Marshal.ReadByte(dataPtr + 0x1B); this.marketBoardRequests.Add(new MarketBoardItemRequest { CatalogId = catalogId, AmountToArrive = amount, Listings = new List <MarketBoardCurrentOfferings.MarketBoardItemListing>(), History = new List <MarketBoardHistory.MarketBoardHistoryListing>() }); Log.Verbose($"NEW MB REQUEST START: item#{catalogId} amount#{amount}"); return; } if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardOfferings"]) { var listing = MarketBoardCurrentOfferings.Read(dataPtr + 0x10); var request = this.marketBoardRequests.LastOrDefault( r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone); if (request == null) { Log.Error( $"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}"); return; } if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive) { Log.Error( $"Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}"); return; } if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) { Log.Error( $"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}"); return; } if (request.ListingsRequestId == -1 && request.Listings.Count > 0) { Log.Error( $"Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return; } if (request.ListingsRequestId == -1) { request.ListingsRequestId = listing.RequestId; Log.Verbose($"First Market Board packet in sequence: {listing.RequestId}"); } request.Listings.AddRange(listing.ItemListings); Log.Verbose("Added {0} ItemListings to request#{1}, now {2}/{3}, item#{4}", listing.ItemListings.Count, request.ListingsRequestId, request.Listings.Count, request.AmountToArrive, request.CatalogId); if (request.IsDone) { Log.Verbose("Market Board request finished, starting upload: request#{0} item#{1} amount#{2}", request.ListingsRequestId, request.CatalogId, request.AmountToArrive); try { Task.Run(() => this.uploader.Upload(request)); } catch (Exception ex) { Log.Error(ex, "Market Board data upload failed."); } } return; } if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardHistory"]) { var listing = MarketBoardHistory.Read(dataPtr + 0x10); var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId); if (request == null) { Log.Error( $"Market Board data arrived without a corresponding request: item#{listing.CatalogId}"); return; } if (request.ListingsRequestId != -1) { Log.Error( $"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return; } request.History.AddRange(listing.HistoryListings); Log.Verbose("Added history for item#{0}", listing.CatalogId); } if (opCode == this.dalamud.Data.ServerOpCodes["MarketTaxRates"]) { var taxes = MarketTaxRates.Read(dataPtr + 0x10); Log.Verbose("MarketTaxRates: limsa#{0} grid#{1} uldah#{2} ish#{3} kugane#{4} cr#{5}", taxes.LimsaLominsaTax, taxes.GridaniaTax, taxes.UldahTax, taxes.IshgardTax, taxes.KuganeTax, taxes.CrystariumTax); try { Task.Run(() => this.uploader.UploadTax(taxes)); } catch (Exception ex) { Log.Error(ex, "Market Board data upload failed."); } } } }
private void OnNetworkMessage(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) { if (direction != NetworkMessageDirection.ZoneDown) { return; } if (!this.dalamud.Data.IsDataReady) { return; } if (opCode == this.dalamud.Data.ServerOpCodes["CfNotifyPop"]) { var data = new byte[64]; Marshal.Copy(dataPtr, data, 0, 64); var notifyType = data[0]; var contentFinderConditionId = BitConverter.ToUInt16(data, 0x14); if (notifyType != 3) { return; } var contentFinderCondition = this.dalamud.Data.GetExcelSheet <ContentFinderCondition>().GetRow(contentFinderConditionId); if (contentFinderCondition == null) { Log.Error("CFC key {0} not in lumina data.", contentFinderConditionId); return; } var cfcName = contentFinderCondition.Name.ToString(); if (string.IsNullOrEmpty(contentFinderCondition.Name)) { cfcName = "Duty Roulette"; contentFinderCondition.Image = 112324; } if (this.dalamud.Configuration.DutyFinderTaskbarFlash && !NativeFunctions.ApplicationIsActivated()) { var flashInfo = new NativeFunctions.FLASHWINFO { cbSize = (uint)Marshal.SizeOf <NativeFunctions.FLASHWINFO>(), uCount = uint.MaxValue, dwTimeout = 0, dwFlags = NativeFunctions.FlashWindow.FLASHW_ALL | NativeFunctions.FlashWindow.FLASHW_TIMERNOFG, hwnd = Process.GetCurrentProcess().MainWindowHandle }; NativeFunctions.FlashWindowEx(ref flashInfo); } Task.Run(() => { if (this.dalamud.Configuration.DutyFinderChatMessage) { this.dalamud.Framework.Gui.Chat.Print("Duty pop: " + cfcName); } CfPop?.Invoke(this, contentFinderCondition); }); return; } if (!this.optOutMbUploads) { if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardItemRequestStart"]) { var catalogId = (uint)Marshal.ReadInt32(dataPtr); var amount = Marshal.ReadByte(dataPtr + 0xB); this.marketBoardRequests.Add(new MarketBoardItemRequest { CatalogId = catalogId, AmountToArrive = amount, Listings = new List <MarketBoardCurrentOfferings.MarketBoardItemListing>(), History = new List <MarketBoardHistory.MarketBoardHistoryListing>() }); Log.Verbose($"NEW MB REQUEST START: item#{catalogId} amount#{amount}"); return; } if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardOfferings"]) { var listing = MarketBoardCurrentOfferings.Read(dataPtr); var request = this.marketBoardRequests.LastOrDefault( r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone); if (request == null) { Log.Error( $"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}"); return; } if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive) { Log.Error( $"Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}"); return; } if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) { Log.Error( $"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}"); return; } if (request.ListingsRequestId == -1 && request.Listings.Count > 0) { Log.Error( $"Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return; } if (request.ListingsRequestId == -1) { request.ListingsRequestId = listing.RequestId; Log.Verbose($"First Market Board packet in sequence: {listing.RequestId}"); } request.Listings.AddRange(listing.ItemListings); Log.Verbose("Added {0} ItemListings to request#{1}, now {2}/{3}, item#{4}", listing.ItemListings.Count, request.ListingsRequestId, request.Listings.Count, request.AmountToArrive, request.CatalogId); if (request.IsDone) { Log.Verbose("Market Board request finished, starting upload: request#{0} item#{1} amount#{2}", request.ListingsRequestId, request.CatalogId, request.AmountToArrive); try { Task.Run(() => this.uploader.Upload(request)); } catch (Exception ex) { Log.Error(ex, "Market Board data upload failed."); } } return; } if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardHistory"]) { var listing = MarketBoardHistory.Read(dataPtr); var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId); if (request == null) { Log.Error( $"Market Board data arrived without a corresponding request: item#{listing.CatalogId}"); return; } if (request.ListingsRequestId != -1) { Log.Error( $"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return; } request.History.AddRange(listing.HistoryListings); Log.Verbose("Added history for item#{0}", listing.CatalogId); if (request.AmountToArrive == 0) { Log.Verbose("Request had 0 amount, uploading now"); try { Task.Run(() => this.uploader.Upload(request)); } catch (Exception ex) { Log.Error(ex, "Market Board data upload failed."); } } } if (opCode == this.dalamud.Data.ServerOpCodes["MarketTaxRates"]) { var category = (uint)Marshal.ReadInt32(dataPtr); // Result dialog packet does not contain market tax rates if (category != 720905) { return; } var taxes = MarketTaxRates.Read(dataPtr); Log.Verbose("MarketTaxRates: limsa#{0} grid#{1} uldah#{2} ish#{3} kugane#{4} cr#{5}", taxes.LimsaLominsaTax, taxes.GridaniaTax, taxes.UldahTax, taxes.IshgardTax, taxes.KuganeTax, taxes.CrystariumTax); try { Task.Run(() => this.uploader.UploadTax(taxes)); } catch (Exception ex) { Log.Error(ex, "Market Board data upload failed."); } } } }
private void DataSubscriptionOnNetworkReceived(string connection, long epoch, byte[] message) { var opCode = BitConverter.ToInt16(message, 0x12); if (opCode == _definitions.PlayerSetup) { LocalContentId = BitConverter.ToUInt64(message, 0x20); Log($"New CID: {LocalContentId.ToString("X")}"); return; } if (opCode == _definitions.MarketBoardItemRequestStart) { var catalogId = (uint)BitConverter.ToInt32(message, 0x20); var amount = message[0x2B]; _marketBoardRequests.Add(new MarketBoardItemRequest { CatalogId = catalogId, AmountToArrive = amount, Listings = new List <MarketBoardCurrentOfferings.MarketBoardItemListing>(), History = new List <MarketBoardHistory.MarketBoardHistoryListing>() }); Log($"NEW MB REQUEST START: item#{catalogId} amount#{amount}"); return; } if (opCode == _definitions.MarketBoardOfferings) { var listing = MarketBoardCurrentOfferings.Read(message.Skip(0x20).ToArray()); var request = this._marketBoardRequests.LastOrDefault( r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone); if (request == null) { Log( $"[ERROR] Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}"); return; } if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive) { Log( $"[ERROR] Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}"); return; } if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) { Log( $"[ERROR] Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}"); return; } if (request.ListingsRequestId == -1 && request.Listings.Count > 0) { Log( $"[ERROR] Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return; } if (request.ListingsRequestId == -1) { request.ListingsRequestId = listing.RequestId; Log($"First Market Board packet in sequence: {listing.RequestId}"); } request.Listings.AddRange(listing.ItemListings); Log($"Added {listing.ItemListings.Count} ItemListings to request#{request.ListingsRequestId}, now {request.Listings.Count}/{request.AmountToArrive}, item#{request.CatalogId}"); if (request.IsDone) { Log($"Market Board request finished, starting upload: request#{request.ListingsRequestId} item#{request.CatalogId} amount#{request.AmountToArrive}"); try { this._uploader.Upload(request); } catch (Exception ex) { Log("[ERROR] Market Board data upload failed:\n" + ex); } } return; } if (opCode == _definitions.MarketBoardHistory) { var listing = MarketBoardHistory.Read(message.Skip(0x20).ToArray()); var request = this._marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId); if (request == null) { Log( $"Market Board data arrived without a corresponding request: item#{listing.CatalogId}"); return; } if (request.ListingsRequestId != -1) { Log( $"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return; } request.History.AddRange(listing.HistoryListings); Log($"Added history for item#{listing.CatalogId}"); } }
/// <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> public bool ProcessZonePacket(byte[] message) { var opCode = BitConverter.ToInt16(message, 0x12); if (opCode == _definitions.PlayerSpawn) { CurrentWorldId = BitConverter.ToUInt16(message, 0x24); return(false); } if (opCode == _definitions.PlayerSetup) { LocalContentId = BitConverter.ToUInt64(message, 0x20); Log?.Invoke(this, $"New CID: {LocalContentId.ToString("X")}"); LocalContentIdUpdated?.Invoke(this, LocalContentId); return(false); } if (opCode == _definitions.MarketBoardItemRequestStart) { var catalogId = (uint)BitConverter.ToInt32(message, 0x20); var amount = message[0x2B]; _marketBoardRequests.Add(new MarketBoardItemRequest { CatalogId = catalogId, AmountToArrive = amount, Listings = new List <MarketBoardCurrentOfferings.MarketBoardItemListing>(), History = new List <MarketBoardHistory.MarketBoardHistoryListing>() }); Log?.Invoke(this, $"NEW MB REQUEST START: item#{catalogId} amount#{amount}"); return(false); } if (opCode == _definitions.MarketBoardOfferings) { 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(false); } 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}"); return(false); } if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) { Log?.Invoke(this, $"[ERROR] Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}"); return(false); } if (request.ListingsRequestId == -1 && request.Listings.Count > 0) { Log?.Invoke(this, $"[ERROR] Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return(false); } 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."); return(false); } RequestContentIdUpdate?.Invoke(this, null); if (LocalContentId == 0) { Log?.Invoke(this, "[ERROR] Not sure about your character information. Please log in once with your character while having the program open to verify it."); //return false; } LocalContentIdUpdated?.Invoke(this, LocalContentId); Log?.Invoke(this, $"Market Board request finished, starting upload: request#{request.ListingsRequestId} item#{request.CatalogId} amount#{request.AmountToArrive}"); try { _uploader.Upload(request); return(true); } catch (Exception ex) { Log?.Invoke(this, "[ERROR] Market Board data upload failed:\n" + ex); } } return(false); } if (opCode == _definitions.MarketBoardHistory) { var listing = MarketBoardHistory.Read(message.Skip(0x20).ToArray()); var request = _marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId); if (request == null) { Log?.Invoke(this, $"[ERROR] Market Board data arrived without a corresponding request: item#{listing.CatalogId}"); return(false); } if (request.ListingsRequestId != -1) { Log?.Invoke(this, $"[ERROR] Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}"); return(false); } request.History.AddRange(listing.HistoryListings); Log?.Invoke(this, $"Added history for item#{listing.CatalogId}"); return(false); } if (opCode == _definitions.ContentIdNameMapResp) { var cid = BitConverter.ToUInt64(message, 0x20); var name = Encoding.UTF8.GetString(message, 0x28, 32).TrimEnd(new [] { '\u0000' }); try { _uploader.UploadCrafterName(cid, name); return(true); } catch (Exception ex) { Log?.Invoke(this, "[ERROR] Content ID upload failed:\n" + ex); } } return(false); }