public override void Setup() { try { shortenedWandererTag = Marshal.AllocHGlobal(60); var seStr = new SeString(new List <Payload>() { new TextPayload(" «"), new IconPayload(BitmapFontIcon.CrossWorld), new TextPayload("»"), }); var bytes = seStr.Encode(); Marshal.Copy(bytes, 0, shortenedWandererTag, bytes.Length); Marshal.WriteByte(shortenedWandererTag, bytes.Length, 0); playerNamePlateSetTextAddress = PluginInterface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 4C 8B 5C 24"); base.Setup(); } catch (Exception ex) { SimpleLog.Log($"Failed Setup of {GetType().Name}: {ex.Message}"); } }
public void SaleDebugCommand(string command, string args) { // make a sample sale message. This is using Titanium Ore for an item Item sampleitem = Interface.Data.GetExcelSheet <Item>().GetRow(12537); SeString sameplesale = new SeString(new Payload[] { new TextPayload("The "), new ItemPayload(Interface.Data, sampleitem.RowId, true), new TextPayload(sampleitem.Name), new TextPayload(" you put up for sale in the Crystarium markets has sold for 777 gil (after fees).") }); // PluginLog.Information($"Trying to make a fake sale: {sameplesale.TextValue}"); this.Discord.MessageQueue.Enqueue(new QueuedRetainerItemSaleEvent { ChatType = XivChatType.RetainerSale, Message = sameplesale, Sender = new SeString(new Payload[] { new TextPayload("Test Sender"), }) }); Interface.Framework.Gui.Chat.PrintChat(new XivChatEntry { MessageBytes = sameplesale.Encode() }); }
/// <summary> /// Show a toast message with the given content. /// </summary> /// <param name="message">The message to be shown.</param> /// <param name="options">Options for the toast.</param> public void ShowNormal(SeString message, ToastOptions options = null) { options ??= new ToastOptions(); this.normalQueue.Enqueue((message.Encode(), options)); }
public async Task ProcessChatMessage(XivChatType type, SeString message, SeString sender) { if (this.dalamud.SeStringManager == null) { return; } // Special case for outgoing tells, these should be sent under Incoming tells var wasOutgoingTell = false; if (type == XivChatType.TellOutgoing) { type = XivChatType.TellIncoming; wasOutgoingTell = true; } var chatTypeConfigs = this.config.ChatTypeConfigurations.Where(typeConfig => typeConfig.ChatType == type); if (!chatTypeConfigs.Any()) { return; } var chatTypeDetail = type.GetDetails(); var channels = chatTypeConfigs.Select(c => GetChannel(c.Channel).GetAwaiter().GetResult()); var playerLink = sender.Payloads.FirstOrDefault(x => x.Type == PayloadType.Player) as PlayerPayload; string senderName; string senderWorld; if (playerLink == null) { // chat messages from the local player do not include a player link, and are just the raw name // but we should still track other instances to know if this is ever an issue otherwise // Special case 2 - When the local player talks in party/alliance, the name comes through as raw text, // but prefixed by their position number in the party (which for local player may always be 1) if (sender.TextValue.EndsWith(this.dalamud.ClientState.LocalPlayer.Name)) { senderName = this.dalamud.ClientState.LocalPlayer.Name; } else { Log.Error("playerLink was null. Sender: {0}", BitConverter.ToString(sender.Encode())); senderName = wasOutgoingTell ? this.dalamud.ClientState.LocalPlayer.Name : sender.TextValue; } senderWorld = this.dalamud.ClientState.LocalPlayer.HomeWorld.GameData.Name; } else { senderName = wasOutgoingTell ? this.dalamud.ClientState.LocalPlayer.Name : playerLink.PlayerName; senderWorld = playerLink.World.Name; } var rawMessage = message.TextValue; var avatarUrl = string.Empty; var lodestoneId = string.Empty; if (!this.config.DisableEmbeds && !string.IsNullOrEmpty(senderName)) { var searchResult = await GetCharacterInfo(senderName, senderWorld); lodestoneId = searchResult.LodestoneId; avatarUrl = searchResult.AvatarUrl; } Thread.Sleep(this.config.ChatDelayMs); var name = wasOutgoingTell ? "You" : senderName + (string.IsNullOrEmpty(senderWorld) || string.IsNullOrEmpty(senderName) ? "" : $" on {senderWorld}"); for (var chatTypeIndex = 0; chatTypeIndex < chatTypeConfigs.Count(); chatTypeIndex++) { if (!this.config.DisableEmbeds) { var embedBuilder = new EmbedBuilder { Author = new EmbedAuthorBuilder { IconUrl = avatarUrl, Name = name, Url = !string.IsNullOrEmpty(lodestoneId) ? "https://eu.finalfantasyxiv.com/lodestone/character/" + lodestoneId : null }, Description = rawMessage, Timestamp = DateTimeOffset.Now, Footer = new EmbedFooterBuilder { Text = type.GetDetails().FancyName }, Color = new Color((uint)(chatTypeConfigs.ElementAt(chatTypeIndex).Color & 0xFFFFFF)) }; if (this.config.CheckForDuplicateMessages) { var recentMsg = this.recentMessages.FirstOrDefault( msg => msg.Embeds.FirstOrDefault( embed => embed.Description == embedBuilder.Description && embed.Author.HasValue && embed.Author.Value.Name == embedBuilder.Author.Name && embed.Timestamp.HasValue && Math.Abs( (embed.Timestamp.Value.ToUniversalTime().Date - embedBuilder .Timestamp.Value.ToUniversalTime().Date) .Milliseconds) < 15000) != null); if (recentMsg != null) { Log.Verbose("Duplicate message: [{0}] {1}", embedBuilder.Author.Name, embedBuilder.Description); this.recentMessages.Remove(recentMsg); return; } } await channels.ElementAt(chatTypeIndex).SendMessageAsync(embed: embedBuilder.Build()); } else { var simpleMessage = $"{name}: {rawMessage}"; if (this.config.CheckForDuplicateMessages) { var recentMsg = this.recentMessages.FirstOrDefault( msg => msg.Content == simpleMessage); if (recentMsg != null) { Log.Verbose("Duplicate message: {0}", simpleMessage); this.recentMessages.Remove(recentMsg); return; } } await channels.ElementAt(chatTypeIndex).SendMessageAsync($"**[{chatTypeDetail.Slug}]{name}**: {rawMessage}"); } } }
private void OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled) { if (type == XivChatType.Notice && !this.hasSeenLoadingMsg) { PrintWelcomeMessage(); } // For injections while logged in if (this.dalamud.ClientState.LocalPlayer != null && this.dalamud.ClientState.TerritoryType == 0 && !this.hasSeenLoadingMsg) { PrintWelcomeMessage(); } #if !DEBUG && false if (!this.hasSeenLoadingMsg) { return; } #endif if (type == XivChatType.RetainerSale) { foreach (var regex in retainerSaleRegexes[dalamud.StartInfo.Language]) { var matchInfo = regex.Match(message.TextValue); // we no longer really need to do/validate the item matching since we read the id from the byte array // but we'd be checking the main match anyway var itemInfo = matchInfo.Groups["item"]; if (!itemInfo.Success) { continue; } var itemLink = message.Payloads.First(x => x.Type == PayloadType.Item) as ItemPayload; if (itemLink == null) { Log.Error("itemLink was null. Msg: {0}", BitConverter.ToString(message.Encode())); break; } Log.Debug($"Probable retainer sale: {message}, decoded item {itemLink.Item.RowId}, HQ {itemLink.IsHQ}"); var valueInfo = matchInfo.Groups["value"]; // not sure if using a culture here would work correctly, so just strip symbols instead if (!valueInfo.Success || !int.TryParse(valueInfo.Value.Replace(",", "").Replace(".", ""), out var itemValue)) { continue; } //Task.Run(() => this.dalamud.BotManager.ProcessRetainerSale(itemLink.Item.RowId, itemValue, itemLink.IsHQ)); break; } } var messageCopy = message; var senderCopy = sender; // Handle all of this with SeString some day /* * if ((this.HandledChatTypeColors.ContainsKey(type) || type == XivChatType.Say || type == XivChatType.Shout || * type == XivChatType.Alliance || type == XivChatType.TellOutgoing || type == XivChatType.Yell)) { * var italicsStart = message.TextValue.IndexOf("*", StringComparison.InvariantCulture); * var italicsEnd = message.TextValue.IndexOf("*", italicsStart + 1, StringComparison.InvariantCulture); * * var messageString = message.TextValue; * * while (italicsEnd != -1) { * var it = MakeItalics( * messageString.Substring(italicsStart, italicsEnd - italicsStart + 1).Replace("*", "")); * messageString = messageString.Remove(italicsStart, italicsEnd - italicsStart + 1); * messageString = messageString.Insert(italicsStart, it); * italicsStart = messageString.IndexOf("*"); * italicsEnd = messageString.IndexOf("*", italicsStart + 1); * } * * message.RawData = Encoding.UTF8.GetBytes(messageString); * } */ var linkMatch = this.urlRegex.Match(message.TextValue); if (linkMatch.Value.Length > 0) { LastLink = linkMatch.Value; } }