chore: add AI state diagnostics for animation investigation

Added diagnostic functions to inspect proxy actor AI state:
- DiagnosticProxyAIState(): logs AIProcess presence, current package, pathfinding state
- EnableProxyAIAnimationMode(): placeholder for AI animation enablement
- Called on proxy spawn to gather evidence about AI setup

This is part of the AI approach investigation - we need to verify if proxies
already have active AIProcess instances and what packages they have assigned.
If the animation issue is just about calling Move() naturally (which happens
when the AI runs), we can potentially enable this by assigning proper packages
to the proxy and letting the game loop drive movement.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-03 14:41:19 +12:00
co-authored by Cursor
parent b9ea0ac8a7
commit 89249db2d1
2 changed files with 132 additions and 4 deletions
+76 -4
View File
@@ -481,6 +481,74 @@ namespace
a_proxy.SetHeading(a_heading);
}
// NEW: Enable AI-driven animation mode
// This function attempts to make the proxy a "real" AI actor that plays animations
// Strategy: Let the AI system drive movement via Move(), which triggers animations
// Override position with SetPosition() to keep network sync accurate
void EnableProxyAIAnimationMode(
RE::Actor& a_proxy,
const RE::PlayerCharacter& a_player)
{
(void)a_player;
// Ensure the proxy has an AIProcess (normally should have one by default)
if (!a_proxy.currentProcess) {
// If no AI process exists, we can't enable animation mode
LogWarningWithLocalPlayerPrefix(std::format(
"EnableProxyAIAnimationMode: Proxy {:08X} has no AIProcess; cannot enable animation mode.",
a_proxy.GetFormID()));
return;
}
// Check if the proxy is already set up for movement
auto* process = a_proxy.currentProcess;
// Key insight: We want the proxy to think it's following the player
// But we DON'T want actual pathfinding (Creation Engine path bugs)
// Solution: The proxy will idle, and we'll move it via our network updates
// While the animation system still gets velocity updates from game loop
// For now, just document that this mode is available
LogInfoWithLocalPlayerPrefix(std::format(
"Proxy {:08X} has active AIProcess; AI animation mode is available.",
a_proxy.GetFormID()));
}
// Diagnostic: Log proxy's AI state
void DiagnosticProxyAIState(
RE::Actor& a_proxy,
std::string_view a_label)
{
if (!a_proxy.currentProcess) {
LogInfoWithLocalPlayerPrefix(std::format(
"[{}] Proxy {:08X}: NO AIProcess",
a_label,
a_proxy.GetFormID()));
return;
}
// Get package info
std::string packageInfo = "NO_PACKAGE";
if (a_proxy.currentProcess->currentPackage.package) {
packageInfo = std::format("PACKAGE_EXISTS");
}
// Get locomotion state
bool isPathing = a_proxy.IsPathing();
bool isPathValid = a_proxy.IsPathValid();
bool isPathComplete = a_proxy.IsPathingComplete();
LogInfoWithLocalPlayerPrefix(std::format(
"[{}] Proxy {:08X}: AIProcess={}, {}, isPathing={}, pathValid={}, pathComplete={}",
a_label,
a_proxy.GetFormID(),
(void*)a_proxy.currentProcess,
packageInfo,
isPathing,
isPathValid,
isPathComplete));
}
bool IsProxyMovementPackageType(RE::PTYPE a_type)
{
switch (a_type) {
@@ -3479,10 +3547,14 @@ namespace
}
const auto finalSpawnPosition = spawnedActor->GetPosition();
g_runtimeProxySpawnSucceeded = true;
g_runtimeProxySpawnAttemptInProgress = false;
StartRuntimeProxyVisibilityHoldIfNeeded();
LogInfoWithLocalPlayerPrefix(std::format(
g_runtimeProxySpawnSucceeded = true;
g_runtimeProxySpawnAttemptInProgress = false;
StartRuntimeProxyVisibilityHoldIfNeeded();
// NEW: Log AI state for animation investigation
DiagnosticProxyAIState(*spawnedActor, "ProxySpawnSuccess");
LogInfoWithLocalPlayerPrefix(std::format(
"Runtime proxy spawn succeeded: actorBase={:08X}, actorBaseSource={}, handle={:08X}, createdRef={:08X}, resolvedAsActor=true, parentCell={:08X}, position={}. Stage 3 will prefer this actor for the single active remote representation while keeping the placed fallback available.",
a_baseActor->GetFormID(),
GetRuntimeActorBaseSourceLabel(a_actorBaseSource),