Try to identify actors in banners correctly.

This commit is contained in:
Ottermandias 2023-01-17 15:03:59 +01:00
parent 23919d8083
commit 6b558c5940
4 changed files with 83 additions and 72 deletions

View file

@ -14,6 +14,7 @@ using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Group;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
using FFXIVClientStructs.FFXIV.Component.GUI;
using Lumina.Excel.GeneratedSheets;
using Lumina.Text;
using Penumbra.GameData.Data;
@ -227,7 +228,7 @@ public sealed partial class ActorManager : IDisposable
private unsafe bool SearchPlayerCustomize(Character* character, int idx, out ActorIdentifier id)
{
var other = (Character*)_objects.GetObjectAddress(idx);
if (other == null || !CustomizeData.Equals((CustomizeData*)character->CustomizeData, (CustomizeData*)other->CustomizeData))
if (other == null || !CustomizeData.ScreenActorEquals((CustomizeData*)character->CustomizeData, (CustomizeData*)other->CustomizeData))
{
id = ActorIdentifier.Invalid;
return false;
@ -246,14 +247,23 @@ public sealed partial class ActorManager : IDisposable
private unsafe ActorIdentifier SearchPlayersCustomize(Character* gameObject)
{
static bool Compare(Character* a, Character* b)
{
var data1 = (CustomizeData*)a->CustomizeData;
var data2 = (CustomizeData*)b->CustomizeData;
var equals = CustomizeData.ScreenActorEquals(data1, data2);
return equals;
}
for (var i = 0; i < (int)ScreenActor.CutsceneStart; i += 2)
{
var obj = (GameObject*)_objects.GetObjectAddress(i);
if (obj != null
&& obj->ObjectKind is (byte)ObjectKind.Player
&& CustomizeData.Equals((CustomizeData*)gameObject->CustomizeData, (CustomizeData*)((Character*)obj)->CustomizeData))
&& Compare(gameObject, (Character*)obj))
return FromObject(obj, out _, false, true);
}
return ActorIdentifier.Invalid;
}
@ -281,15 +291,18 @@ public sealed partial class ActorManager : IDisposable
public unsafe bool ResolvePvPBannerPlayer(ScreenActor type, out ActorIdentifier id)
{
id = ActorIdentifier.Invalid;
var addon = _gameGui.GetAddonByName("PvPMKSIntroduction");
if (addon == IntPtr.Zero)
if (!_clientState.IsPvPExcludingDen)
return false;
var addon = (AtkUnitBase*)_gameGui.GetAddonByName("PvPMap");
if (addon == null || addon->IsVisible)
return false;
var obj = (Character*)_objects.GetObjectAddress((int)type);
if (obj == null)
return false;
var identifier = type switch
id = type switch
{
ScreenActor.CharacterScreen => SearchPlayersCustomize(obj),
ScreenActor.ExamineScreen => SearchPlayersCustomize(obj),

View file

@ -1,8 +1,11 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Penumbra.String.Functions;
namespace Penumbra.GameData.Structs;
[StructLayout(LayoutKind.Sequential, Size = Size)]
public unsafe struct CustomizeData : IEquatable< CustomizeData >
{
public const int Size = 26;
@ -40,12 +43,18 @@ public unsafe struct CustomizeData : IEquatable< CustomizeData >
}
}
public static bool Equals( CustomizeData* lhs, CustomizeData* rhs )
=> MemoryUtility.MemCmpUnchecked( lhs, rhs, Size ) == 0;
public override bool Equals( object? obj )
=> obj is CustomizeData other && Equals( other );
public static bool Equals(CustomizeData* lhs, CustomizeData* rhs)
=> MemoryUtility.MemCmpUnchecked(lhs, rhs, Size) == 0;
/// <remarks>Compare Gender and then only from Height onwards, because all screen actors are set to Height 50,
/// the Race is implicitly included in the subrace (after height),
/// and the body type is irrelevant for players.</remarks>>
public static bool ScreenActorEquals(CustomizeData* lhs, CustomizeData* rhs)
=> lhs->Data[1] == rhs->Data[1] && MemoryUtility.MemCmpUnchecked(lhs->Data + 4, rhs->Data + 4, Size - 4) == 0;
public override int GetHashCode()
{
fixed( byte* ptr = Data )
@ -65,6 +74,17 @@ public unsafe struct CustomizeData : IEquatable< CustomizeData >
}
}
public string WriteBytes()
{
var sb = new StringBuilder(Size * 3);
for (var i = 0; i < Size - 1; ++i)
{
sb.Append($"{Data[i]:X2} ");
}
sb.Append($"{Data[Size - 1]:X2}");
return sb.ToString();
}
public bool LoadBase64( string base64 )
{
var buffer = stackalloc byte[Size];