Added debug information regarding minions

This commit is contained in:
cake
2026-01-15 06:11:07 +01:00
parent 9fcbd68ca2
commit f6a5c85c2d
9 changed files with 894 additions and 142 deletions

View File

@@ -508,7 +508,10 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
return new ActorDescriptor(name, hashedCid, address, objectIndex, isLocal, isInGpose, objectKind, ownedKind, ownerEntityId);
}
private unsafe (LightlessObjectKind? OwnedKind, uint OwnerEntityId) DetermineOwnedKind(GameObject* gameObject, DalamudObjectKind objectKind, bool isLocalPlayer)
private unsafe (LightlessObjectKind? OwnedKind, uint OwnerEntityId) DetermineOwnedKind(
GameObject* gameObject,
DalamudObjectKind objectKind,
bool isLocalPlayer)
{
if (gameObject == null)
return (null, 0);
@@ -520,6 +523,7 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
}
var ownerId = ResolveOwnerId(gameObject);
var localPlayerAddress = _objectTable.LocalPlayer?.Address ?? nint.Zero;
if (localPlayerAddress == nint.Zero)
return (null, ownerId);
@@ -531,9 +535,7 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
if (objectKind is DalamudObjectKind.MountType or DalamudObjectKind.Companion)
{
var expectedMinionOrMount = GetMinionOrMountAddress(localPlayerAddress, localEntityId);
if (expectedMinionOrMount != nint.Zero
&& (nint)gameObject == expectedMinionOrMount
&& IsPlayerRelatedOwnedAddress(expectedMinionOrMount, LightlessObjectKind.MinionOrMount))
if (expectedMinionOrMount != nint.Zero && (nint)gameObject == expectedMinionOrMount)
{
var resolvedOwner = ownerId != 0 ? ownerId : localEntityId;
return (LightlessObjectKind.MinionOrMount, resolvedOwner);
@@ -543,20 +545,16 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
if (objectKind != DalamudObjectKind.BattleNpc)
return (null, ownerId);
if (ownerId != localEntityId)
if (ownerId != 0 && ownerId != localEntityId)
return (null, ownerId);
var expectedPet = GetPetAddress(localPlayerAddress, localEntityId);
if (expectedPet != nint.Zero
&& (nint)gameObject == expectedPet
&& IsPlayerRelatedOwnedAddress(expectedPet, LightlessObjectKind.Pet))
return (LightlessObjectKind.Pet, ownerId);
if (expectedPet != nint.Zero && (nint)gameObject == expectedPet)
return (LightlessObjectKind.Pet, ownerId != 0 ? ownerId : localEntityId);
var expectedCompanion = GetCompanionAddress(localPlayerAddress, localEntityId);
if (expectedCompanion != nint.Zero
&& (nint)gameObject == expectedCompanion
&& IsPlayerRelatedOwnedAddress(expectedCompanion, LightlessObjectKind.Companion))
return (LightlessObjectKind.Companion, ownerId);
if (expectedCompanion != nint.Zero && (nint)gameObject == expectedCompanion)
return (LightlessObjectKind.Companion, ownerId != 0 ? ownerId : localEntityId);
return (null, ownerId);
}
@@ -584,21 +582,25 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
return nint.Zero;
var playerObject = (GameObject*)localPlayerAddress;
var candidateAddress = _objectTable.GetObjectAddress(playerObject->ObjectIndex + 1);
if (ownerEntityId == 0)
return nint.Zero;
var candidateAddress = _objectTable.GetObjectAddress(playerObject->ObjectIndex + 1);
if (candidateAddress != nint.Zero)
{
var candidate = (GameObject*)candidateAddress;
var candidateKind = (DalamudObjectKind)candidate->ObjectKind;
if (candidateKind is DalamudObjectKind.MountType or DalamudObjectKind.Companion)
{
if (ResolveOwnerId(candidate) == ownerEntityId)
var resolvedOwner = ResolveOwnerId(candidate);
if (resolvedOwner == ownerEntityId || resolvedOwner == 0)
return candidateAddress;
}
}
if (ownerEntityId == 0)
return nint.Zero;
foreach (var obj in _objectTable)
{
if (obj is null || obj.Address == nint.Zero || obj.Address == localPlayerAddress)
@@ -615,6 +617,90 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
return nint.Zero;
}
public unsafe bool TryFindOwnedObject(uint ownerEntityId, LightlessObjectKind kind, out nint address)
{
address = nint.Zero;
if (ownerEntityId == 0) return false;
foreach (var addr in EnumerateActiveCharacterAddresses())
{
if (addr == nint.Zero) continue;
var go = (GameObject*)addr;
var ok = (DalamudObjectKind)go->ObjectKind;
switch (kind)
{
case LightlessObjectKind.MinionOrMount:
if (ok is DalamudObjectKind.MountType or DalamudObjectKind.Companion
&& ResolveOwnerId(go) == ownerEntityId)
{
address = addr;
return true;
}
break;
case LightlessObjectKind.Pet:
if (ok == DalamudObjectKind.BattleNpc
&& go->BattleNpcSubKind == BattleNpcSubKind.Pet
&& ResolveOwnerId(go) == ownerEntityId)
{
address = addr;
return true;
}
break;
case LightlessObjectKind.Companion:
if (ok == DalamudObjectKind.BattleNpc
&& go->BattleNpcSubKind == BattleNpcSubKind.Buddy
&& ResolveOwnerId(go) == ownerEntityId)
{
address = addr;
return true;
}
break;
}
}
return false;
}
public unsafe IReadOnlyList<nint> GetMinionOrMountCandidates(uint ownerEntityId, ushort preferredPlayerIndex)
{
var results = new List<(nint Ptr, int Score)>(4);
var manager = GameObjectManager.Instance();
if (manager == null || ownerEntityId == 0)
return Array.Empty<nint>();
const int objectLimit = 200;
for (var i = 0; i < objectLimit; i++)
{
var obj = manager->Objects.IndexSorted[i].Value;
if (obj == null)
continue;
var kind = (DalamudObjectKind)obj->ObjectKind;
if (kind is not (DalamudObjectKind.MountType or DalamudObjectKind.Companion))
continue;
var owner = ResolveOwnerId(obj);
if (owner != ownerEntityId)
continue;
var idx = obj->ObjectIndex;
var score = Math.Abs(idx - (preferredPlayerIndex + 1));
if (obj->DrawObject == null) score += 50;
results.Add(((nint)obj, score));
}
return results
.OrderBy(r => r.Score)
.Select(r => r.Ptr)
.ToArray();
}
private unsafe nint GetPetAddress(nint localPlayerAddress, uint ownerEntityId)
{
if (localPlayerAddress == nint.Zero || ownerEntityId == 0)
@@ -1219,21 +1305,19 @@ public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorS
private static unsafe bool IsObjectFullyLoaded(nint address)
{
if (address == nint.Zero)
return false;
if (address == nint.Zero) return false;
var gameObject = (GameObject*)address;
if (gameObject == null)
return false;
if (gameObject == null) return false;
var drawObject = gameObject->DrawObject;
if (drawObject == null)
return false;
if (drawObject == null) return false;
if ((ulong)gameObject->RenderFlags == 2048)
return false;
var characterBase = (CharacterBase*)drawObject;
if (characterBase->HasModelInSlotLoaded != 0)
return false;