proxy: document visual sneak SetSneaking result
This commit is contained in:
@@ -72,6 +72,9 @@ namespace
|
||||
constexpr auto kRuntimeProxyVisibilityDiagnosticLogInterval = 2s;
|
||||
constexpr auto kProxyNeutralizationInterval = 2s;
|
||||
constexpr bool kEnableProxyAIMovementIntentSuppression = false;
|
||||
// Stage 1 tested RE::Actor::SetSneaking(bool). It compiled and did not
|
||||
// crash, but did not visually crouch runtime proxy actors. Keep disabled
|
||||
// until animation graph/state investigation identifies a better visual route.
|
||||
constexpr bool kEnableProxyVisualSneakSync = false;
|
||||
constexpr bool kEnableProxyVisualSneakExperimentalGraph = false;
|
||||
constexpr auto kNotInTestCellLogInterval = 30s;
|
||||
@@ -4073,6 +4076,34 @@ namespace
|
||||
a_slot.lastAppliedVisualSneakingState.reset();
|
||||
}
|
||||
|
||||
void ClearSlotVisualSneakIfApplied(
|
||||
ProxyActorSlot& a_slot,
|
||||
RE::Actor& a_proxy,
|
||||
std::string_view a_reason)
|
||||
{
|
||||
if (!a_slot.hasAppliedVisualSneakingState) {
|
||||
ResetSlotVisualSneakTracking(a_slot);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto applied = a_proxy.SetSneaking(false);
|
||||
if (applied) {
|
||||
LogInfoWithLocalPlayerPrefix(std::format(
|
||||
"Runtime proxy visual sneak cleared on {} for remote player {}: actor={:08X}, appliedSneaking=false.",
|
||||
a_reason,
|
||||
a_slot.remotePlayerId,
|
||||
a_proxy.GetFormID()));
|
||||
} else {
|
||||
LogWarningWithLocalPlayerPrefix(std::format(
|
||||
"Runtime proxy visual sneak clear on {} returned false for remote player {}: actor={:08X}, requestedSneaking=false.",
|
||||
a_reason,
|
||||
a_slot.remotePlayerId,
|
||||
a_proxy.GetFormID()));
|
||||
}
|
||||
|
||||
ResetSlotVisualSneakTracking(a_slot);
|
||||
}
|
||||
|
||||
void ResetSlotObservationState(ProxyActorSlot& a_slot)
|
||||
{
|
||||
a_slot.hasLoggedInitialAnimationState = false;
|
||||
@@ -4143,10 +4174,11 @@ namespace
|
||||
return;
|
||||
}
|
||||
|
||||
ClearSlotVisualSneakIfApplied(
|
||||
a_slot,
|
||||
a_proxy,
|
||||
a_reason == ProxyLifecycleState::kHeldDisconnected ? "disconnect hold" : "hold");
|
||||
a_proxy.SetPosition(GetSlotHoldingPosition(a_slot), true);
|
||||
// TODO: If a later approved visual writer is added, clear any applied
|
||||
// proxy sneak visual here before holding/reusing the actor.
|
||||
ResetSlotVisualSneakTracking(a_slot);
|
||||
if (auto* player = RE::PlayerCharacter::GetSingleton()) {
|
||||
NeutralizeProxyActor(a_slot, a_proxy, *player, ProxyNeutralizationReason::kHolding);
|
||||
}
|
||||
@@ -4199,7 +4231,9 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
void MarkReusableSlots()
|
||||
void MarkReusableSlots(
|
||||
RE::TESObjectCELL& a_parentCell,
|
||||
const RE::PlayerCharacter& a_player)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
for (auto& [playerId, slot] : g_proxySlots) {
|
||||
@@ -4212,10 +4246,14 @@ namespace
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto* proxy = TryResolveSlotProxy(slot, a_parentCell, a_player)) {
|
||||
ClearSlotVisualSneakIfApplied(slot, *proxy, "reuse");
|
||||
} else {
|
||||
ResetSlotVisualSneakTracking(slot);
|
||||
}
|
||||
slot.lifecycleState = ProxyLifecycleState::kReusable;
|
||||
slot.holdReason.reset();
|
||||
slot.previousRemotePlayerId = playerId;
|
||||
ResetSlotVisualSneakTracking(slot);
|
||||
if (!slot.reusableLogged) {
|
||||
LogInfoWithLocalPlayerPrefix(std::format(
|
||||
"Runtime proxy slot for disconnected remote player {} became reusable after {:.1f}s held.",
|
||||
@@ -4306,18 +4344,30 @@ namespace
|
||||
}
|
||||
|
||||
if constexpr (kEnableProxyVisualSneakSync) {
|
||||
if (!a_slot.hasLoggedVisualSneakDisabled) {
|
||||
LogWarningWithLocalPlayerPrefix(std::format(
|
||||
"Runtime proxy visual sneak sync flag is enabled for remote player {}, but no actor-mutating sneak writer is implemented in this scaffolding pass. actor={:08X}.",
|
||||
const auto requestedSneaking = a_remotePlayer.isSneaking;
|
||||
if (a_slot.hasAppliedVisualSneakingState &&
|
||||
a_slot.lastAppliedVisualSneakingState &&
|
||||
*a_slot.lastAppliedVisualSneakingState == requestedSneaking) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto applied = a_proxy.SetSneaking(requestedSneaking);
|
||||
a_slot.hasAppliedVisualSneakingState = true;
|
||||
a_slot.lastAppliedVisualSneakingState = requestedSneaking;
|
||||
|
||||
if (applied) {
|
||||
LogInfoWithLocalPlayerPrefix(std::format(
|
||||
"Runtime proxy visual sneak applied {} for remote player {}: actor={:08X}.",
|
||||
requestedSneaking,
|
||||
a_remotePlayer.playerId,
|
||||
a_proxy.GetFormID()));
|
||||
a_slot.hasLoggedVisualSneakDisabled = true;
|
||||
} else {
|
||||
LogWarningWithLocalPlayerPrefix(std::format(
|
||||
"Runtime proxy visual sneak SetSneaking returned false for remote player {}: actor={:08X}, requestedSneaking={}.",
|
||||
a_remotePlayer.playerId,
|
||||
a_proxy.GetFormID(),
|
||||
requestedSneaking));
|
||||
}
|
||||
// TODO: In a separately approved experiment, consider calling
|
||||
// RE::Actor::SetSneaking(a_remotePlayer.isSneaking) here behind this
|
||||
// flag, with explicit clear handling on false, disconnect, hold,
|
||||
// reassignment, and reuse. Do not add graph writes/events,
|
||||
// PerformAction, ActorState writes, or package/procedure crouch logic.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4479,6 +4529,11 @@ namespace
|
||||
|
||||
auto& slotValue = node.mapped();
|
||||
const auto previousRemotePlayerId = slotValue.remotePlayerId;
|
||||
if (auto* proxy = TryResolveSlotProxy(slotValue, a_parentCell, a_player)) {
|
||||
ClearSlotVisualSneakIfApplied(slotValue, *proxy, "reassignment");
|
||||
} else {
|
||||
ResetSlotVisualSneakTracking(slotValue);
|
||||
}
|
||||
slotValue.previousRemotePlayerId = previousRemotePlayerId;
|
||||
slotValue.remotePlayerId = a_remotePlayer.playerId;
|
||||
slotValue.lifecycleState = ProxyLifecycleState::kHeldNoRemote;
|
||||
@@ -4738,7 +4793,7 @@ namespace F4T::ProxyActorController
|
||||
}
|
||||
|
||||
const auto remotePlayers = GetSortedRemotePlayerSnapshot();
|
||||
MarkReusableSlots();
|
||||
MarkReusableSlots(*parentCell, *player);
|
||||
std::unordered_set<std::uint32_t> seenRemotePlayerIds;
|
||||
seenRemotePlayerIds.reserve(remotePlayers.size());
|
||||
std::optional<RemotePlayer> fallbackCandidate;
|
||||
@@ -4795,7 +4850,7 @@ namespace F4T::ProxyActorController
|
||||
}
|
||||
|
||||
HoldDisconnectedSlots(seenRemotePlayerIds, *parentCell, *player);
|
||||
MarkReusableSlots();
|
||||
MarkReusableSlots(*parentCell, *player);
|
||||
CorrectHeldSlotPositions(*parentCell, *player);
|
||||
HoldFallbackIfRepresentedPlayerDisconnected(seenRemotePlayerIds, *parentCell, *player);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user