feat(client): consumir yaw do snapshot quantizado v3 (Etapa 7)

Etapa 7 do refactor de networking server-side bumpou o protocolo para
v3 e passou a enviar yaw no S_PLAYER_STATE (campo novo no payload).
Cliente agora consome esse yaw via TryGetLastPlayerStateExtended do
plugin ZeusNetwork (cache local com YawDeg + Flags).

Antes (v2):
- S_PLAYER_STATE nao tinha yaw. Comentario do codigo dizia exatamente
  "Yaw nao chega no opcode S_PLAYER_STATE actual; derivamos do XY da
  velocidade quando significativo, caso contrario mantemos rotacao
  do ator." Resultado: proxy parado nao girava, e proxy em movimento
  ficava com yaw inferido (impreciso quando vel pequena).

Depois (v3):
- HandlePlayerStateUpdate consulta TryGetLastPlayerStateExtended para
  pegar YawDeg + Flags do cache do plugin (populado pelo parser v3).
- Se PSF_HasYaw esta set, usa o YawDeg autoritativo do servidor.
- Caso contrario, fallback antigo (atan2 da vel ou rotacao do ator),
  preservando comportamento se algum dia o flag vier desligado.

Validacao runtime (~5 min, 2 clients UE conectados ao server v3):
- Connected sessionId=1 e =2 (handshake v3 OK).
- parseRej=0 no servidor (cliente fala v3).
- Proxies giram conforme yaw autoritativo (visual; nao tem metrica
  numerica para isso).

Depende de:
- ZeusNetwork plugin v3 (commit 3b97500 no repo ZeusServerEngine).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 03:32:36 -03:00
parent 86df9478d4
commit 1fe5109c0d

View File

@@ -195,15 +195,45 @@ void UZMMOWorldSubsystem::HandlePlayerStateUpdate(const int32 EntityId, const in
Snapshot.LastProcessedInputSeq = InputSeq; Snapshot.LastProcessedInputSeq = InputSeq;
Snapshot.PositionCm = PosCm; Snapshot.PositionCm = PosCm;
Snapshot.VelocityCmS = VelCmS; Snapshot.VelocityCmS = VelCmS;
// Yaw nao chega no opcode S_PLAYER_STATE actual; derivamos do XY da
// velocidade quando significativo, caso contrario mantemos rotacao do ator. // Etapa 7 (server-side networking refactor): yaw agora chega no
if (!FVector(VelCmS.X, VelCmS.Y, 0.0f).IsNearlyZero(1.0f)) // snapshot quantizado v3. Buscamos via TryGetLastPlayerStateExtended
// (cache local do plugin). Se PSF_HasYaw nao estiver set ou se o cache
// nao tiver entrada, caimos no fallback antigo (derivar do XY da
// velocidade ou manter rotacao do ator).
bool bYawFromSnapshot = false;
if (UZeusNetworkSubsystem* ZeusNet = ResolveZeusNetworkSubsystem())
{ {
Snapshot.YawDeg = FMath::RadiansToDegrees(FMath::Atan2(VelCmS.Y, VelCmS.X)); int32 CachedInputSeq = 0;
FVector CachedPos = FVector::ZeroVector;
FVector CachedVel = FVector::ZeroVector;
float CachedYawDeg = 0.f;
int32 CachedFlags = 0;
int64 CachedServerTimeMs = 0;
if (ZeusNet->TryGetLastPlayerStateExtended(
EntityId, CachedInputSeq, CachedPos, CachedVel,
CachedYawDeg, CachedFlags, CachedServerTimeMs))
{
constexpr int32 PSF_HasYaw = 1 << 5;
if ((CachedFlags & PSF_HasYaw) != 0)
{
Snapshot.YawDeg = CachedYawDeg;
bYawFromSnapshot = true;
}
}
} }
else if (!bYawFromSnapshot)
{ {
Snapshot.YawDeg = Actor->GetActorRotation().Yaw; // Fallback: deriva yaw do XY da velocidade quando significativo;
// caso contrario mantem rotacao do ator (comportamento pre-Etapa 7).
if (!FVector(VelCmS.X, VelCmS.Y, 0.0f).IsNearlyZero(1.0f))
{
Snapshot.YawDeg = FMath::RadiansToDegrees(FMath::Atan2(VelCmS.Y, VelCmS.X));
}
else
{
Snapshot.YawDeg = Actor->GetActorRotation().Yaw;
}
} }
Snapshot.bGrounded = bGrounded; Snapshot.bGrounded = bGrounded;
Snapshot.ServerTimeMs = ServerTimeMs; Snapshot.ServerTimeMs = ServerTimeMs;