/// <summary> /// 周辺のキャラ情報を取得 /// </summary> private unsafe List <Combatant> _getCombatantList() { int num = 344; List <Combatant> result = new List <Combatant>(); int sz = 8; byte[] source = GetByteArray(charmapAddress, sz * num); if (source == null || source.Length == 0) { return(result); } for (int i = 0; i < num; i++) { IntPtr p; fixed(byte *bp = source) p = new IntPtr(*(Int64 *)&bp[i * sz]); if (!(p == IntPtr.Zero)) { byte[] c = GetByteArray(p, combatantDataSize); Combatant combatant = GetCombatantFromByteArray(c); if (combatant.type != ObjectType.PC && combatant.type != ObjectType.Monster) { continue; } if (combatant.ID != 0 && combatant.ID != 3758096384u && !result.Exists((Combatant x) => x.ID == combatant.ID)) { combatant.Order = i; result.Add(combatant); } } } return(result); }
/// <summary> /// 敵視リスト情報を取得 /// </summary> public unsafe List <AggroEntry> GetAggroList() { int num = 0; uint currentTargetID = 0; List <AggroEntry> result = new List <AggroEntry>(); List <Combatant> combatantList = Combatants; Combatant mychar = GetSelfCombatant(); // 一度に全部読む byte[] buffer = GetByteArray(aggroAddress, 32 * 72 + 2); fixed(byte *p = buffer) num = (short)p[2296]; if (num <= 0) { return(result); } if (num > 31) { num = 31; // max changed??? 32->31 } // current target //currentTargetID = GetUInt32(aggroAddress, -4); //if (currentTargetID == 3758096384u) currentTargetID = 0; var targetCombatant = GetTargetCombatant(); if (targetCombatant != null) { currentTargetID = targetCombatant.ID; } else { currentTargetID = 0; } // for (int i = 0; i < num; i++) { int p = i * 72; uint _id; short _enmity; fixed(byte *bp = buffer) { _id = *(uint *)&bp[p + 56]; _enmity = (short)bp[p + 60]; } var entry = new AggroEntry() { ID = _id, HateRate = _enmity, Name = "Unknown", }; if (entry.ID <= 0) { continue; } Combatant c = combatantList.Find(x => x.ID == entry.ID); if (c != null) { entry.ID = c.ID; entry.Order = c.Order; entry.isCurrentTarget = (c.ID == currentTargetID); entry.Name = c.Name; entry.MaxHP = c.MaxHP; entry.CurrentHP = c.CurrentHP; entry.Statuses = c.Statuses; if (c.TargetID > 0) { Combatant t = combatantList.Find(x => x.ID == c.TargetID); if (t != null) { entry.Target = new EnmityEntry() { ID = t.ID, Name = t.Name, Job = t.Job, OwnerID = t.OwnerID, isMe = mychar.ID == t.ID ? true : false, Enmity = 0, HateRate = 0 }; } } } result.Add(entry); } return(result); }
/// <summary> /// カレントターゲットの敵視情報を取得 /// </summary> public unsafe List <EnmityEntry> GetEnmityEntryList() { short num = 0; uint topEnmity = 0; List <EnmityEntry> result = new List <EnmityEntry>(); List <Combatant> combatantList = Combatants; Combatant mychar = GetSelfCombatant(); /// 一度に全部読む byte[] buffer = GetByteArray(enmityAddress, 0x900 + 2); fixed(byte *p = buffer) num = (short)p[2296]; if (num <= 0) { return(result); } if (num > 31) { num = 31; // changed??? 32->31 } for (short i = 0; i < num; i++) { int p = i * 72; uint _id; uint _enmity; fixed(byte *bp = buffer) { _id = *(uint *)&bp[p + 56]; _enmity = *(uint *)&bp[p + 60]; } var entry = new EnmityEntry() { ID = _id, Enmity = _enmity, isMe = false, Name = "Unknown", Job = 0x00 }; if (entry.ID > 0) { Combatant c = combatantList.Find(x => x.ID == entry.ID); if (c != null) { entry.Name = c.Name; entry.Job = c.Job; entry.OwnerID = c.OwnerID; } if (entry.ID == mychar.ID) { entry.isMe = true; } if (topEnmity <= entry.Enmity) { topEnmity = entry.Enmity; } entry.HateRate = (int)(((double)entry.Enmity / (double)topEnmity) * 100); result.Add(entry); } } return(result); }
/// <summary> /// メモリのバイト配列からキャラ情報に変換 /// </summary> public unsafe Combatant GetCombatantFromByteArray(byte[] source) { int offset = 0; Combatant combatant = new Combatant(); fixed(byte *p = source) { //combatant.BoA = BitConverter.ToString(source); combatant.Name = GetStringFromBytes(source, 0x30); combatant.ID = *(uint *)&p[0x74]; combatant.OwnerID = *(uint *)&p[0x84]; if (combatant.OwnerID == 3758096384u) { combatant.OwnerID = 0u; } combatant.type = (ObjectType)p[0x8C]; combatant.EffectiveDistance = p[0x92]; offset = 0xA0; combatant.PosX = *(Single *)&p[offset]; combatant.PosZ = *(Single *)&p[offset + 4]; combatant.PosY = *(Single *)&p[offset + 8]; offset = 5792 + 16; combatant.TargetID = *(uint *)&p[5680]; //5672? 5680? 5796? 6744? in 4.2 if (combatant.type == ObjectType.PC || combatant.type == ObjectType.Monster) { combatant.Job = p[offset + 0x3E]; combatant.Level = p[offset + 0x40]; combatant.CurrentHP = *(int *)&p[offset + 8]; combatant.MaxHP = *(int *)&p[offset + 12]; combatant.CurrentMP = *(int *)&p[offset + 16]; combatant.MaxMP = *(int *)&p[offset + 20]; combatant.CurrentTP = *(short *)&p[offset + 24]; combatant.MaxTP = 1000; // Status aka Buff,Debuff combatant.Statuses = new List <Status>(); const int StatusEffectOffset = 5992; const int statusSize = 12; int statusCountLimit = 60; if (combatant.type == ObjectType.PC) { statusCountLimit = 30; } var statusesSource = new byte[statusCountLimit * statusSize]; Buffer.BlockCopy(source, StatusEffectOffset, statusesSource, 0, statusCountLimit * statusSize); for (var i = 0; i < statusCountLimit; i++) { var statusBytes = new byte[statusSize]; Buffer.BlockCopy(statusesSource, i * statusSize, statusBytes, 0, statusSize); var status = new Status { StatusID = BitConverter.ToInt16(statusBytes, 0), Stacks = statusBytes[2], Duration = BitConverter.ToSingle(statusBytes, 4), CasterID = BitConverter.ToUInt32(statusBytes, 8), IsOwner = false, }; if (status.IsValid()) { combatant.Statuses.Add(status); } } // Cast combatant.Casting = new Cast { ID = BitConverter.ToInt16(source, 6372), TargetID = BitConverter.ToUInt32(source, 6384), Progress = BitConverter.ToSingle(source, 6420), Time = BitConverter.ToSingle(source, 6424), }; } else { combatant.CurrentHP = combatant.MaxHP = combatant.CurrentMP = combatant.MaxMP = combatant.MaxTP = combatant.CurrentTP = 0; combatant.Statuses = new List <Status>(); combatant.Casting = new Cast(); } } return(combatant); }
/// <summary> /// 各ポインタのアドレスを取得 /// </summary> private bool getPointerAddress() { bool success = true; bool bRIP = true; string charmapSignature = charmapSignature64; string targetSignature = targetSignature64; string enmitySignature = enmitySignature64; int targetOffset = targetOffset64; int charmapOffset = charmapOffset64; int enmityOffset = enmityOffset64; List <string> fail = new List <string>(); /// CHARMAP List <IntPtr> list = SigScan(charmapSignature, 0, bRIP); if (list == null || list.Count == 0) { charmapAddress = IntPtr.Zero; } if (list.Count == 1) { charmapAddress = list[0] + charmapOffset; } if (charmapAddress == IntPtr.Zero) { fail.Add(nameof(charmapAddress)); success = false; } // ENMITY //enmityAddress = IntPtr.Add(charmapAddress, enmityOffset); //aggroAddress = IntPtr.Add(enmityAddress, 0x900 + 8); list = SigScan(enmitySignature, 0, bRIP); if (list == null || list.Count == 0) { enmityAddress = IntPtr.Zero; } if (list.Count == 1) { enmityAddress = list[0] + enmityOffset; aggroAddress = IntPtr.Add(enmityAddress, 0x900 + 8); } if (enmityAddress == IntPtr.Zero) { fail.Add(nameof(enmityAddress)); success = false; } aggroAddress = IntPtr.Add(enmityAddress, 0x900 + 8); /// TARGET list = SigScan(targetSignature, 0, bRIP); if (list == null || list.Count == 0) { targetAddress = IntPtr.Zero; } if (list.Count == 1) { targetAddress = list[0] + targetOffset; } if (targetAddress == IntPtr.Zero) { fail.Add(nameof(targetAddress)); success = false; } _overlay.LogDebug("charmapAddress: 0x{0:X}", charmapAddress.ToInt64()); _overlay.LogDebug("enmityAddress: 0x{0:X}", enmityAddress.ToInt64()); _overlay.LogDebug("targetAddress: 0x{0:X}", targetAddress.ToInt64()); Combatant c = GetSelfCombatant(); if (c != null) { _overlay.LogDebug("MyCharacter: '{0}' ({1})", c.Name, c.ID); } if (!success) { throw new MemoryScanException(String.Format(Messages.FailedToSigScan, String.Join(",", fail))); } return(success); }
/// <summary> /// メモリのバイト配列からキャラ情報に変換 /// </summary> public unsafe Combatant GetCombatantFromByteArray(byte[] source) { Combatant combatant = new Combatant(); fixed(byte *p = source) { // For Debug //combatant.BoA = BitConverter.ToString(source); combatant.Name = GetStringFromBytes(source, combatantStructureOffset_Name); combatant.ID = *(uint *)&p[combatantStructureOffset_ID]; combatant.OwnerID = *(uint *)&p[combatantStructureOffset_OwnerID]; if (combatant.OwnerID == 3758096384u) { combatant.OwnerID = 0u; } combatant.type = (ObjectType)p[combatantStructureOffset_Type]; combatant.EffectiveDistance = p[combatantStructureOffset_EffectiveDistance]; combatant.PosX = *(Single *)&p[combatantStructureOffset_PosX]; combatant.PosZ = *(Single *)&p[combatantStructureOffset_PosZ]; combatant.PosY = *(Single *)&p[combatantStructureOffset_PosY]; combatant.Heading = *(Single *)&p[combatantStructureOffset_Heading]; combatant.TargetID = *(uint *)&p[combatantStructureOffset_TargetID]; if (combatant.type == ObjectType.PC || combatant.type == ObjectType.Monster) { combatant.CurrentHP = *(int *)&p[combatantStructureOffset_CurrentHP]; combatant.MaxHP = *(int *)&p[combatantStructureOffset_MaxHP]; combatant.CurrentMP = *(int *)&p[combatantStructureOffset_CurrentMP]; combatant.MaxMP = *(int *)&p[combatantStructureOffset_MaxMP]; combatant.Job = p[combatantStructureOffset_Job]; combatant.Level = p[combatantStructureOffset_Level]; combatant.CurrentTP = 0; combatant.MaxTP = 0; // Status aka Buff,Debuff combatant.Statuses = new List <Status>(); int statusCountLimit = (combatant.type == ObjectType.PC) ? 30 : 60; var statusesSource = new byte[statusCountLimit * combatantStructureOffset_StatusItemSize]; Buffer.BlockCopy(source, combatantStructureOffset_StatusOffset, statusesSource, 0, statusCountLimit * combatantStructureOffset_StatusItemSize); for (var i = 0; i < statusCountLimit; i++) { var statusBytes = new byte[combatantStructureOffset_StatusItemSize]; Buffer.BlockCopy(statusesSource, i * combatantStructureOffset_StatusItemSize, statusBytes, 0, combatantStructureOffset_StatusItemSize); var status = new Status { StatusID = BitConverter.ToUInt16(statusBytes, combatantStructureOffset_StatusItem_ID), Stacks = statusBytes[combatantStructureOffset_StatusItem_Stacks], Duration = BitConverter.ToSingle(statusBytes, combatantStructureOffset_StatusItem_Duration), CasterID = BitConverter.ToUInt32(statusBytes, combatantStructureOffset_StatusItem_CasterID), IsOwner = false, }; if (status.IsValid()) { combatant.Statuses.Add(status); } } // Cast combatant.Casting = new Cast { ID = *(ushort *)&p[combatantStructureOffset_CastingID], TargetID = *(uint *)&p[combatantStructureOffset_CastingTargetID], Progress = *(Single *)&p[combatantStructureOffset_CastingProgress], Time = *(Single *)&p[combatantStructureOffset_CastingTime], }; } else { combatant.CurrentHP = combatant.MaxHP = combatant.CurrentTP = combatant.MaxTP = combatant.CurrentMP = combatant.MaxMP = 0; combatant.Statuses = new List <Status>(); combatant.Casting = new Cast(); } } return(combatant); }
public float GetHorizontalDistanceTo(Combatant target) { var distanceX = (float)Math.Abs(PosX - target.PosX); var distanceY = (float)Math.Abs(PosY - target.PosY); return (float)Math.Sqrt((distanceX * distanceX) + (distanceY * distanceY)); }
public float GetDistanceTo(Combatant target) { var distanceX = (float)Math.Abs(PosX - target.PosX); var distanceY = (float)Math.Abs(PosY - target.PosY); var distanceZ = (float)Math.Abs(PosZ - target.PosZ); return (float)Math.Sqrt((distanceX * distanceX) + (distanceY * distanceY) + (distanceZ * distanceZ)); }
public static List<Combatant> GetCombatantList() { List<Combatant> result = new List<Combatant>(); try { var scanCombatants = GetScanCombatants(); if (scanCombatants == null) return null; var item = scanCombatants.GetType().InvokeMember("GetCombatantList", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, scanCombatants, null); FieldInfo fi = item.GetType().GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); Type[] nestedType = item.GetType().GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); object tmp = fi.GetValue(item); if (tmp.GetType().IsArray) { foreach (object temp in (Array)tmp) { if (temp == null) break; Combatant combatant = new Combatant(); fi = temp.GetType().GetField("ID", BindingFlags.Public | BindingFlags.Instance); combatant.ID = (uint)fi.GetValue(temp); fi = temp.GetType().GetField("OwnerID", BindingFlags.Public | BindingFlags.Instance); combatant.OwnerID = (uint)fi.GetValue(temp); fi = temp.GetType().GetField("Job", BindingFlags.Public | BindingFlags.Instance); combatant.Job = (int)fi.GetValue(temp); fi = temp.GetType().GetField("Name", BindingFlags.Public | BindingFlags.Instance); combatant.Name = (string)fi.GetValue(temp); fi = temp.GetType().GetField("CurrentTP", BindingFlags.Public | BindingFlags.Instance); combatant.CurrentTP = (int)fi.GetValue(temp); fi = temp.GetType().GetField("CurrentHP", BindingFlags.Public | BindingFlags.Instance); combatant.CurrentHP = (int)fi.GetValue(temp); fi = temp.GetType().GetField("MaxHP", BindingFlags.Public | BindingFlags.Instance); combatant.MaxHP = (int)fi.GetValue(temp); result.Add(combatant); } } } catch { } return result; }
/// <summary> /// メモリのバイト配列からキャラ情報に変換 /// </summary> public unsafe Combatant GetCombatantFromByteArray(byte[] source) { int offset = 0; Combatant combatant = new Combatant(); fixed (byte* p = source) { combatant.Name = GetStringFromBytes(source, 48); combatant.ID = *(uint*)&p[0x74]; combatant.OwnerID = *(uint*)&p[0x84]; if (combatant.OwnerID == 3758096384u) { combatant.OwnerID = 0u; } combatant.type = (ObjectType)p[0x8A]; combatant.EffectiveDistance = p[0x91]; offset = (_mode == FFXIVClientMode.FFXIV_64) ? 176 : 160; combatant.PosX = *(Single*)&p[offset]; combatant.PosZ = *(Single*)&p[offset + 4]; combatant.PosY = *(Single*)&p[offset + 8]; offset = (_mode == FFXIVClientMode.FFXIV_64) ? 448 : 392; combatant.TargetID = *(uint*)&p[offset]; if (combatant.TargetID == 3758096384u) { offset = (_mode == FFXIVClientMode.FFXIV_64) ? 2448 : 2520; combatant.TargetID = *(uint*)&p[offset]; } if (combatant.type == ObjectType.PC || combatant.type == ObjectType.Monster) { offset = (_mode == FFXIVClientMode.FFXIV_64) ? 5872 : 5312; combatant.Job = p[offset]; combatant.Level = p[offset + 1]; combatant.CurrentHP = *(int*)&p[offset + 8]; combatant.MaxHP = *(int*)&p[offset + 12]; combatant.CurrentMP = *(int*)&p[offset + 16]; combatant.MaxMP = *(int*)&p[offset + 20]; combatant.CurrentTP = *(short*)&p[offset + 24]; combatant.MaxTP = 1000; } else { combatant.CurrentHP = combatant.MaxHP = combatant.CurrentMP = combatant.MaxMP = combatant.MaxTP = combatant.CurrentTP = 0; } } return combatant; }