diff --git a/Source/ZMMO/Game/Network/ZMMOWorldSubsystem.cpp b/Source/ZMMO/Game/Network/ZMMOWorldSubsystem.cpp index cf72d08..3850726 100644 --- a/Source/ZMMO/Game/Network/ZMMOWorldSubsystem.cpp +++ b/Source/ZMMO/Game/Network/ZMMOWorldSubsystem.cpp @@ -104,7 +104,10 @@ void UZMMOWorldSubsystem::HandlePlayerSpawned(const int32 EntityId, const bool b if (RemoteEntities.Contains(EntityId)) { - // Ja existe um proxy: reactivar e re-snap. + // Ja existe um proxy: tenta reactivar e re-snap. Se o weak ptr ficou + // stale (actor coletado pelo GC, stream-out do World Partition, etc.), + // remove a entry orfa e cai no caminho de spawn novo — evita SPAWN + // silenciosamente ignorado depois de oscilacoes na AOI. if (AActor* Existing = RemoteEntities[EntityId].Get()) { if (IZMMOEntityInterface* AsEntity = Cast(Existing)) @@ -112,8 +115,12 @@ void UZMMOWorldSubsystem::HandlePlayerSpawned(const int32 EntityId, const bool b AsEntity->SetEntityRelevant(true); } Existing->SetActorLocationAndRotation(PosCm, FRotator(0.0f, YawDeg, 0.0f)); + UE_LOG(LogZMMO, Verbose, TEXT("ZMMOWorldSubsystem: re-snap EntityId=%d"), EntityId); + return; } - return; + // weak ptr stale — limpa entry e cai pro spawn novo abaixo. + RemoteEntities.Remove(EntityId); + UE_LOG(LogZMMO, Log, TEXT("ZMMOWorldSubsystem: stale entry para EntityId=%d, respawnando"), EntityId); } UWorld* World = GetWorld(); @@ -166,15 +173,23 @@ void UZMMOWorldSubsystem::HandlePlayerDespawned(const int32 EntityId) return; } + // Destruir o actor pra valer + remover do mapa. Antes, despawn apenas + // fazia SetActorHiddenInGame(true) via SetEntityRelevant(false), o que + // deixava o entry no mapa apontando pra um actor escondido. SPAWN + // subsequente do mesmo entityId era detectado como "duplicate" e nada + // acontecia — pawn ficava invisivel ate' o weak ptr ser GC'd. Bug + // confirmado nos logs do AOI ao oscilar entrada/saida da ZI/ZD. if (AActor* Actor = Entry->Get()) { if (IZMMOEntityInterface* AsEntity = Cast(Actor)) { AsEntity->SetEntityRelevant(false); } + Actor->Destroy(); } + RemoteEntities.Remove(EntityId); - UE_LOG(LogZMMO, Log, TEXT("ZMMOWorldSubsystem: despawn EntityId=%d"), EntityId); + UE_LOG(LogZMMO, Log, TEXT("ZMMOWorldSubsystem: despawn EntityId=%d (destroyed)"), EntityId); } void UZMMOWorldSubsystem::HandlePlayerStateUpdate(const int32 EntityId, const int32 InputSeq,