문제 인식

던전 세션 종료 후 마을 복귀 시 일부 유저 클라이언트에서 다른 유저 일부가 보이지 않는 현상이 발생했습니다.

🚫 문제점

해결 과정

씬 변경 시점 확인

// 기존 구조, PacketHandler.cs
...
public static void S_SpawnHandler(PacketSession session, IMessage packet)
{
  S_Spawn spawnPacket = packet as S_Spawn;
  if (spawnPacket == null)
    return;

  var playerList = spawnPacket.Players;
  foreach (var playerInfo in playerList)
  {
    var tr = playerInfo.Transform;

    var player = TownManager.Instance.CreatePlayer(playerInfo, new Vector3(tr.PosX, tr.PosY, tr.PosZ));
    player.SetIsMine(false);
  }
}

덮어쓰기된 임시 저장 패킷

// 수정 구조, PacketHandler.cs
...
public static void S_SpawnHandler(PacketSession session, IMessage packet)
{
	S_Spawn spawnPacket = packet as S_Spawn;
	if (spawnPacket == null)
    return;
 
	// 패킷을 임시 저장했으나 두 번째 패킷이 오는 시점 전에는 처리해줄 수 없고,
	// 두 번째 패킷이 덮어씌우게 됨
	GameManager.Instance.Pkt_S_SPAWN = spawnPacket;
	
	Scene scene = SceneManager.GetActiveScene();
	if (scene.name == GameManager.Instance.DungeonScene)
	{
		// 던전 수신 시
		SceneManager.LoadScene(GameManager.TownScene);
	}
	else {
		// 타운 수신 시
		TownManager.Instance.SpawnOthers();
	}
}

패킷 임시 저장 자료구조 Queue로 변경

// 최종 구조, GameManager.cs
..
public class GameManager : MonoBehaviour
{
    ..
    public Queue<S_Spawn> Pkt_S_SPAWN = new(); // Spawn 패킷 보관용 Queue

    ..
}

// 최종 구조, PacketHandler.cs
...
public static void S_SpawnHandler(PacketSession session, IMessage packet)
{
    S_Spawn spawnPacket = packet as S_Spawn;
    if (spawnPacket == null)
        return;
    
    Scene scene = SceneManager.GetActiveScene();
    if (scene.name == GameManager.Instance.DungeonScene)
    {
        if (GameManager.Instance.Pkt_S_SPAWN == null)
        {
            GameManager.Instance.Pkt_S_SPAWN = new Queue<S_Spawn>();
        }
        // 던전 수신 시 패킷을 Queue에 추가
        GameManager.Instance.Pkt_S_SPAWN.Enqueue(spawnPacket);
        
        SceneManager.LoadScene(GameManager.TownScene);
    }
    else {
        TownManager.Instance.SpawnOthers(spawnPacket);
    }
}

결론

✅ 패킷 임시 저장 자료구조를 Queue로 변경하여 해결