/// <summary> /// Opens the in-game map with a flag on the location of the parameter. /// </summary> /// <param name="mapLink">Link to the map to be opened.</param> /// <returns>True if there were no errors and it could open the map.</returns> public bool OpenMapWithMapLink(MapLinkPayload mapLink) { var uiObjectPtr = this.getUIObject(); if (uiObjectPtr.Equals(IntPtr.Zero)) { Log.Error("OpenMapWithMapLink: Null pointer returned from getUIObject()"); return(false); } this.getUIMapObject = this.address.GetVirtualFunction <GetUIMapObjectDelegate>(uiObjectPtr, 0, 8); var uiMapObjectPtr = this.getUIMapObject(uiObjectPtr); if (uiMapObjectPtr.Equals(IntPtr.Zero)) { Log.Error("OpenMapWithMapLink: Null pointer returned from GetUIMapObject()"); return(false); } this.openMapWithFlag = this.address.GetVirtualFunction <OpenMapWithFlagDelegate>(uiMapObjectPtr, 0, 63); var mapLinkString = mapLink.DataString; Log.Debug($"OpenMapWithMapLink: Opening Map Link: {mapLinkString}"); return(this.openMapWithFlag(uiMapObjectPtr, mapLinkString)); }
public bool OpenMapWithMapLink(MapLinkPayload mapLink) { var uiObjectPtr = getUIObject(); if (uiObjectPtr.Equals(IntPtr.Zero)) { Log.Error("OpenMapWithMapLink: Null pointer returned from getUIObject()"); return(false); } getUIMapObject = Address.GetVirtualFunction <GetUIMapObjectDelegate>(uiObjectPtr, 0, 8); var uiMapObjectPtr = this.getUIMapObject(uiObjectPtr); if (uiMapObjectPtr.Equals(IntPtr.Zero)) { Log.Error("OpenMapWithMapLink: Null pointer returned from GetUIMapObject()"); return(false); } openMapWithFlag = Address.GetVirtualFunction <OpenMapWithFlagDelegate>(uiMapObjectPtr, 0, 63); var mapLinkString = $"m:{mapLink.TerritoryTypeId},{mapLink.MapId},{unchecked((int)mapLink.RawX)},{unchecked((int)mapLink.RawY)}"; Log.Debug($"OpenMapWithMapLink: Opening Map Link: {mapLinkString}"); return(this.openMapWithFlag(uiMapObjectPtr, mapLinkString)); }
public void PlaceMapMarker(MapLinkMessage maplinkMessage) { Log($"Viewing {maplinkMessage.Text}"); var map = DataManager.GetExcelSheet <TerritoryType>().GetRow(maplinkMessage.TerritoryId).Map; var maplink = new MapLinkPayload(maplinkMessage.TerritoryId, map.Row, maplinkMessage.X, maplinkMessage.Y); GameGui.OpenMapWithMapLink(maplink); }
public MapLink(TeleporterPlugin plugin, XivChatType type, MapLinkPayload payload, string senderName, SeString message) { _plugin = plugin; ChatType = type; Location = new Vector2(payload.XCoord, payload.YCoord); PlaceName = payload.PlaceName; TerritoryId = payload.TerritoryType.RowId; SenderName = senderName; Message = message.TextValue; Data = message.Encode(); Aetheryte = GetClosestAetheryte(); Payload = new MapLinkPayload(_plugin.Interface.Data, payload.TerritoryType.RowId, payload.Map.RowId, payload.RawX, payload.RawY); }
/// <summary> /// Creates an SeString representing an entire Payload chain that can be used to link a map position in the chat log. /// </summary> /// <param name="territoryId">The id of the TerritoryType for this map link.</param> /// <param name="mapId">The id of the Map for this map link.</param> /// <param name="xCoord">The human-readable x-coordinate for this link.</param> /// <param name="yCoord">The human-readable y-coordinate for this link.</param> /// <param name="fudgeFactor">An optional offset to account for rounding and truncation errors; it is best to leave this untouched in most cases.</param> /// <returns>An SeString containing all of the payloads necessary to display a map link in the chat log.</returns> public static SeString CreateMapLink(uint territoryId, uint mapId, float xCoord, float yCoord, float fudgeFactor = 0.05f) { var mapPayload = new MapLinkPayload(territoryId, mapId, xCoord, yCoord, fudgeFactor); var nameString = $"{mapPayload.PlaceName} {mapPayload.CoordinateString}"; var payloads = new List <Payload>(new Payload[] { mapPayload, // arrow goes here new TextPayload(nameString), RawPayload.LinkTerminator }); payloads.InsertRange(1, TextArrowPayloads()); return(new SeString(payloads)); }
public SeString CreateMapLink(uint territoryId, uint mapId, int rawX, int rawY) { var mapPayload = new MapLinkPayload(this.data, territoryId, mapId, rawX, rawY); var nameString = $"{mapPayload.PlaceName} {mapPayload.CoordinateString}"; var payloads = new List <Payload>(new Payload[] { mapPayload, // arrow goes here new TextPayload(nameString), RawPayload.LinkTerminator }); payloads.InsertRange(1, TextArrowPayloads()); return(new SeString(payloads)); }
private static Payload DecodeChunk(BinaryReader reader) { Payload payload = null; reader.ReadByte(); // START_BYTE var chunkType = (SeStringChunkType)reader.ReadByte(); var chunkLen = GetInteger(reader); var packetStart = reader.BaseStream.Position; // any unhandled payload types will be turned into a RawPayload with the exact same binary data switch (chunkType) { case SeStringChunkType.EmphasisItalic: payload = new EmphasisItalicPayload(); break; case SeStringChunkType.SeHyphen: payload = SeHyphenPayload.Payload; break; case SeStringChunkType.Interactable: { var subType = (EmbeddedInfoType)reader.ReadByte(); switch (subType) { case EmbeddedInfoType.PlayerName: payload = new PlayerPayload(); break; case EmbeddedInfoType.ItemLink: payload = new ItemPayload(); break; case EmbeddedInfoType.MapPositionLink: payload = new MapLinkPayload(); break; case EmbeddedInfoType.Status: payload = new StatusPayload(); break; case EmbeddedInfoType.QuestLink: payload = new QuestPayload(); break; case EmbeddedInfoType.DalamudLink: payload = new DalamudLinkPayload(); break; case EmbeddedInfoType.LinkTerminator: // this has no custom handling and so needs to fallthrough to ensure it is captured default: // but I'm also tired of this log if (subType != EmbeddedInfoType.LinkTerminator) { Log.Verbose("Unhandled EmbeddedInfoType: {0}", subType); } // rewind so we capture the Interactable byte in the raw data reader.BaseStream.Seek(-1, SeekOrigin.Current); break; } } break; case SeStringChunkType.AutoTranslateKey: payload = new AutoTranslatePayload(); break; case SeStringChunkType.UIForeground: payload = new UIForegroundPayload(); break; case SeStringChunkType.UIGlow: payload = new UIGlowPayload(); break; case SeStringChunkType.Icon: payload = new IconPayload(); break; default: Log.Verbose("Unhandled SeStringChunkType: {0}", chunkType); break; } payload ??= new RawPayload((byte)chunkType); payload.DecodeImpl(reader, reader.BaseStream.Position + chunkLen - 1); // read through the rest of the packet var readBytes = (uint)(reader.BaseStream.Position - packetStart); reader.ReadBytes((int)(chunkLen - readBytes + 1)); // +1 for the END_BYTE marker return(payload); }
private static Payload ProcessChunk(BinaryReader reader) { Payload payload = null; reader.ReadByte(); // START_BYTE var chunkType = (SeStringChunkType)reader.ReadByte(); var chunkLen = GetInteger(reader); var packetStart = reader.BaseStream.Position; switch (chunkType) { case SeStringChunkType.Interactable: { var subType = (EmbeddedInfoType)reader.ReadByte(); switch (subType) { case EmbeddedInfoType.PlayerName: payload = new PlayerPayload(); break; case EmbeddedInfoType.ItemLink: payload = new ItemPayload(); break; case EmbeddedInfoType.MapPositionLink: payload = new MapLinkPayload(); break; case EmbeddedInfoType.Status: payload = new StatusPayload(); break; case EmbeddedInfoType.LinkTerminator: // this has no custom handling and so needs to fallthrough to ensure it is captured default: Log.Verbose("Unhandled EmbeddedInfoType: {0}", subType); // rewind so we capture the Interactable byte in the raw data reader.BaseStream.Seek(-1, SeekOrigin.Current); payload = new RawPayload((byte)chunkType); break; } } break; case SeStringChunkType.AutoTranslateKey: payload = new AutoTranslatePayload(); break; case SeStringChunkType.UIForeground: payload = new UIForegroundPayload(); break; case SeStringChunkType.UIGlow: payload = new UIGlowPayload(); break; default: Log.Verbose("Unhandled SeStringChunkType: {0}", chunkType); payload = new RawPayload((byte)chunkType); break; } payload?.ProcessChunkImpl(reader, reader.BaseStream.Position + chunkLen - 1); // read through the rest of the packet var readBytes = (uint)(reader.BaseStream.Position - packetStart); reader.ReadBytes((int)(chunkLen - readBytes + 1)); // +1 for the END_BYTE marker return(payload); }
private void Chat_OnChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled) { if (!Config.Recording) { return; } bool hasMapLink = false; float coordX = 0; float coordY = 0; float scale = 100; MapLinkPayload maplinkPayload = null; foreach (var payload in message.Payloads) { if (payload is MapLinkPayload mapLinkload) { maplinkPayload = mapLinkload; hasMapLink = true; // float fudge = 0.05f; scale = mapLinkload.TerritoryType.Map.Value.SizeFactor; // coordX = ConvertRawPositionToMapCoordinate(mapLinkload.RawX, scale) - fudge; // coordY = ConvertRawPositionToMapCoordinate(mapLinkload.RawY, scale) - fudge; coordX = mapLinkload.XCoord; coordY = mapLinkload.YCoord; Log($"TerritoryId: {mapLinkload.TerritoryType.RowId} {mapLinkload.PlaceName} ({coordX} ,{coordY})"); } } string messageText = message.TextValue; if (hasMapLink) { var newMapLinkMessage = new MapLinkMessage( (ushort)type, sender.TextValue, messageText, coordX, coordY, scale, maplinkPayload.TerritoryType.RowId, maplinkPayload.PlaceName, DateTime.Now ); bool filteredOut = false; if (sender.TextValue.ToLower() == "sonar") { filteredOut = true; } bool alreadyInList = Config.MapLinkMessageList.Any(w => { bool sameText = w.Text == newMapLinkMessage.Text; var timeoutMin = new TimeSpan(0, Config.FilterDupTimeout, 0); if (newMapLinkMessage.RecordTime < w.RecordTime + timeoutMin) { bool sameX = (int)(w.X * 10) == (int)(newMapLinkMessage.X * 10); bool sameY = (int)(w.Y * 10) == (int)(newMapLinkMessage.Y * 10); bool sameTerritory = w.TerritoryId == newMapLinkMessage.TerritoryId; return(sameTerritory && sameX && sameY); } return(sameText); }); if (Config.FilterDuplicates && alreadyInList) { filteredOut = true; } if (!filteredOut && Config.FilteredChannels.IndexOf((ushort)type) != -1) { filteredOut = true; } if (!filteredOut) { Config.MapLinkMessageList.Add(newMapLinkMessage); if (Config.MapLinkMessageList.Count > Config.MaxRecordings) { var tempList = Config.MapLinkMessageList.OrderBy(e => e.RecordTime); Config.MapLinkMessageList.RemoveRange(0, Config.MapLinkMessageList.Count - Config.MaxRecordings); var infoMsg = $"There are too many records, truncated to the latest {Config.MaxRecordings} records"; PluginLog.Information(infoMsg); } Config.Save(); } } }
public static IEnumerable <ColorString> FromMapLink(string str, ColorRef color, ColorRef shadowColor, MapLinkPayload map, TextTypes source) { yield return(MakeLinkChar(source)); foreach (var s in FromStringSplitDelimiters(str, color, shadowColor, source)) { yield return(s); } }