Skip to content

Unity의 지연 Destroy로 카드 동기화가 종류당 한 장만 제거함 #418

Description

@dev-yunseong

문제

GameSceneUIController.RemoveCardlowerBar.transform의 자식을 순회하다가 CardUI.CardName이 일치하는 첫 자식에서 Destroy(child.gameObject)를 호출하고 return 한다. UnityEngine.Object.Destroy는 프레임 끝까지 지연되므로 해당 자식은 그 프레임 동안 계속 부모에 붙어 있고 cardUI != null(50행)도 여전히 true다. 같은 프레임에 이어지는 호출은 같은 오브젝트를 다시 찾아 다시 Destroy 할 뿐이다. 호출자인 SyncFrameHandler.cs:50은 한 번의 Handler() 안에서 for (int i = 0; i < Math.Abs(diff); i++) RemoveCard(card);를 동기적으로 실행하므로, 실제로는 sync 한 틱당 카드 종류별로 한 장만 제거된다. 서버 DTO(CardInfoDto)에는 added 리스트만 있고 제거 필드가 없어 이 sync 경로가 유일한 교정 수단이다. GetAllCards(63-68행)도 같은 프레임 동안 동일한 지연 Destroy 노출을 갖는다.

위치

  • client/Assets/Scripts/GameScene/GameSceneUIController.cs:52
  • client/Assets/Scripts/GameScene/GameSceneUIController.cs:45

재현 / 영향

플레이어가 3장짜리 마법을 제출하면 서버는 카드를 소모하지만, magicValid 응답이 유실되거나 3초를 넘겨 지연되면 CardInputSender.WaitInputResponseTimeout(197-212행)이 CardUI를 파괴하는 대신 선택 상태를 복구한다. 이 시점에서 클라이언트 손패에는 서버가 갖고 있지 않은 카드 3장이 남는다. 다음 sync가 해당 종류에 대해 diff = -3을 계산하지만 실제로는 CardUI 한 장만 제거되므로, 유령 카드 두 장이 최소 한 sync 틱 이상 클릭 가능한 상태로 남는다. 플레이어는 서버가 갖고 있지 않은 카드로 selectCard/useMagic을 보내 거절당하고 턴을 낭비한다. 차이가 클수록 수렴에 그만큼 더 많은 틱이 걸린다.

수정 방향

각 호출이 서로 다른 오브젝트를 대상으로 하게 만든다. 일치하는 자식을 리스트로 모아 요청된 개수만큼 한 번에 파괴하거나(예: lowerBar.GetComponentsInChildren<CardUI>()를 순회해 앞에서 count개를 파괴하는 RemoveCards(string cardName, int count)), 파괴 전에 계층에서 분리한다: child.SetParent(null, false); Destroy(child.gameObject);. 또는 transform 계층을 재탐색하는 대신 GameSceneUIController에 명시적인 List<CardUI>로 손패를 추적한다. GetAllCardschild.GetComponent<CardUI>() null 체크도 함께 보완한다.


심각도: medium · 분류: correctness
자동 코드 리뷰(멀티 에이전트 검증 통과)에서 발견됨.

Metadata

Metadata

Assignees

Labels

fixfix bugspriority:P1조용히 틀린 값 / 데이터 소실

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions