뒤끝 매치 데이터 송수신 및 데이터 동기화

고객님의 문의에 답변하는 직원은 고객 여러분의 가족 중 한 사람일 수 있습니다.
고객의 언어폭력(비하, 조롱, 욕설, 협박, 성희롱 등)으로부터 직원을 보호하기 위해
관련 법에 따라 수사기관에 필요한 조치를 요구할 수 있으며, 형법에 의해 처벌 대상이 될 수 있습니다.

커뮤니티 이용 정책에 위배되는 게시물을 작성할 경우, 별도 안내 없이 게시물 삭제 또는 커뮤니티 이용이 제한될 수 있습니다.

문의 응대 : 평일 오전 10시 ~ 오후 6시
문의를 남기실 경우 다음 항목을 작성해 주세요.
정보가 부족하거나 응대시간 외 문의하는 경우 확인 및 답변이 지연될 수 있습니다.

  • 뒤끝 SDK 버전 : 버전: SDK-5.11.1
  • 프로젝트명 :
  • 스테이터스 코드 :
  • 에러 코드 :
  • 에러 메시지 :

안녕하세요. 이번에 뒤끝 매치를 통해서 멀티게임을 구현해보려는 학생입니다.
다름이 아니라 이번 뒤끝매치 튜토리얼을 기반으로 제작하고 있습니다.
현재 뒤끝 튜토리얼의 PlayerDamegedMessage 메세지를 기반으로 버튼을 클릭한다면 랜덤으로 다른 플레이어의 피를 100 제거하여 바로 사망할 수 있도록 변경하였습니다.
하지만 클라이언트에서는 남은 플레이어수와 게임오브젝트가 제거가 잘 되지만 비클라이언트에서 실행하게 된다면 클라이언트만 동기화되고 나머지 비클라이언트에서는 데이터가 동기화 되지 않습니다.
이때 데이터 동기화는 남은 플레이어수 및 게임오브젝트 SetActive(false)만 연동이 안되고 게임의 결과나 매칭은 잘 됩니다.
따라서 SendDataToInGame를 잘못 사용하여 문제가 생겼나해서 확인해 보았지만 이 부분의 문제라고는 생각되지 않더군요…
따라서 다른 문제가 있는지
OnMatchRelay가 오지 않는 상황인지 여부
데이터 파싱에서 에러가 발생하는 상환인지 여부
class 형식이 뒤끝 매치에서 제공하는 것처럼 3~5개만이 존재하는 여부

이렇게 3부분으로 확인해 보았지만 큰 문제는 없어 보입니다…

기존의 매치 튜토리얼에서 바꾼 코드들도 작성해 드리겠습니다.

블릿 클래스를 참고하여 제작
public void killPlayer()
    {
        int k = Random.Range(0, 8);
        if(TTPlayers[k])
        {
            Protocol.PlayerDamegedMessage message =
                new Protocol.PlayerDamegedMessage(TTPlayers[k].GetIndex());
            BackEndMatchManager.GetInstance().SendDataToInGame<Protocol.PlayerDamegedMessage>(message);
        }
    }

월드 클래스 부분
private void PlayerDieEvent(SessionId index)
    {
        alivePlayer -= 1;
        players[index].gameObject.SetActive(false);

        InGameUiManager.GetInstance().SetScoreBoard(alivePlayer);
        gameRecord.Push(index);

        Debug.Log(string.Format("Player Die : " + players[index].GetNickName()));

        // 호스트가 아니면 바로 리턴
        if (!BackEndMatchManager.GetInstance().IsHost())
        {
            return;
        }

        // 1명 이하로 플레이어가 남으면 바로 종료 체크
        if (alivePlayer <= 1)
        {
            SendGameEndOrder();
        }
    }

월드 클래스 부분
case Protocol.Type.PlayerDamaged:
                PlayerDamegedMessage damegedMessage = DataParser.ReadJsonData<PlayerDamegedMessage>(args.BinaryUserData);
                ProcessPlayerData(damegedMessage);
                break;

월드 클래스 부분
private void ProcessPlayerData(PlayerDamegedMessage data)
    {
        players[data.playerSession].Damaged();
        //EffectManager.instance.EnableEffect(data.hit_x, data.hit_y, data.hit_z);
    }

프로토콜 클래스 부분
 public class PlayerDamegedMessage : Message
    {
        public SessionId playerSession;
        public PlayerDamegedMessage(SessionId session) : base(Type.PlayerDamaged)
        {
            this.playerSession = session;
        }
    }


그리고 가능하다면 뒤끝 매치 튜토리얼에서 데이터 동기화를 어떻게 진행하고 있는지 간단하게 라도 알려주시면 감사하겠습니다.

안녕하세요 개발자님,
뒤끝 매치 예제 게임에서는, 슈퍼 게이머만이 모든 게임의 연산을 담당하고 있습니다.

유저1이 총을 쏠 경우, 유저 2가 방향을 변경할 경우 모두 슈퍼 게이머에게 통신을 보내고, 슈퍼 게이머가 모든 유저들에게 다시 재송신합니다.
유저1은 슈퍼 게이머에게 유저1이 총을 쏜 데이터와 유저 2가 방향을 변경한 데이터을 받아야지만 자신의 클라이언트에 대입합니다.
다른 유저들이 보낸 요청 또한 슈퍼 게이머가 아니라면 모두 요청을 거절합니다.(return)

따라서 OnMatchRelay 이후에 슈퍼 게이머인지 일반 유저인지 판별하고, 슈퍼 게이머에 대한 로직만 작동하는것이 맞는지 로직을 확인해 주세요. :D

감사합니다! 잘 해결했습니다.

좋아요 1

안녕하세요.
추가적인 질문이 있어서 여기에 적어봅니다.
현재 오토배틀러 게임(TFT) 같은 게임을 제작하고 있습니다.

따라서 각 기물(오브젝트)가 각 플레이어의 소속(?)이 되어야 하고, 각 오브젝트가 데이터를 받기위해서는 세션ID를 각 기물(오브젝트)가 모두 가지고 있어야 되는지와 세션ID는 플레이어와 기물이 구분이 가능한지 여부가 궁금합니다.

 private Dictionary<SessionId, Player> players;
 private Dictionary<SessionId, Piece> pieces;

이런 식으로 각 구분되어 있는 기물(오브젝트)가 움직이는 것을 보여주고 싶다면 세션 ID가 필요할까요?

만약 각 기물(오브젝트)가 오토배틀러 장르처럼 자동으로 전투를 하는 모습을 보여주고 싶다면 어떻게하면 좋을지 어렵네요.

안녕하세요 개발자님,

  1. 유저 1이 유닛 A를 소환 => 슈퍼게이머에게 정보 전송
  2. 전송받은 내역에 따라 슈퍼게이머는 유닛 A를 소환하는 데이터를 모든 유저에게 전송
  3. 요청을 수신한 유저는 자신의 클라이언트에 유닛 A를 소환
  4. 유닛 A가 스킬을 쓰거나 움직임을 시작할때에만 슈퍼게이머가 해당 명령을 모든 유저에게 전송
  5. 모든 유저는 해당 요청을 수신하고 자신의 클라이언트에서 유닛 A의 스킬을 사용하거나 움직임을 동일하게 적용

위와 같이 슈퍼게이머가 유닛의 움직임을 지정하고,
다른 클라이언트들은 슈퍼게이머가 보낸 유닛의 움직임을 자신의 클라이언트에 적용시키면 됩니다.
각 유닛마다 별도의 세션 아이디는 필요하지 않을 것 같습니다.

안녕하세요.
구현 중 List 송수신 부분에서 Null 값이 계속 나와 문의드립니다.
저랑 비슷한 글을 본적이 있네요. List 혹은 배열을 사용할 경우 데이터값이 Null이 뜨는 경우 입니다.
그렇다면 List와 배열이 아닌 데이터 형식이 게임오브젝트 혹은 스크립터블 오브젝트에 대한 데이터 형식은 보낼 수 있을까요?
또한 궁금한점 중 하나인데 현재 인게임 상점을 통해서 기물을 구매하는 기능을 구현중입니다만, 위 문제로 인해서 생각을 바꾸어야 합니다. 따라서 뒤끝 기능에 있는 확율관리를 뒤끝 매치에 연결하여 사용이 가능할까요?
혹시 가능하다면 예제 코드도 부탁드리겠습니다.
추가적으로 상점은 각 플레이어가 자신의 세션 아이디가 아니라면 리롤 및 구매는 불가능하고 5개의 기물 카드를 가지고 랜덤으로 값을 돌리는 형태이며 값에는 스크립터블 오브젝트의 값이 들어있습니다.

또한 뒤끝 확율 시스템과 차트 시스템을 생각하고 있으며 뒤끝 펑션도 확인해 보았습니다.
귀끝 펑션같은 경우 보안을 위해 사용한다고 생각되며 나머지 확율과 차트 시스템을 생각하고 있습니다만 레퍼런스가 없네용

안녕하세요 개발자님,
문의하신 내용 답변드립니다.

  1. 현재는 class 를 JsonData로 변환하여 바이너리 데이터로 보내도록 되어있습니다.

  2. 매치 기능의 경우 해당 매칭에 대한 일회성 통신이기 때문에, 영구적으로 저장되어야 할 경우 뒤끝베이스의 게임정보관리 기능을 구현하셔야 합니다. 따라서 매칭만으로는 상점 기능을 구현하는 것은 불가능합니다.

  3. 뒤끝 펑션의 경우, C#으로 되어있기 떄문에 기존에 유니티 클라이언트에서 사용된 뒤끝 이용 코드를 그대로 펑션에서 이용하는 것이 가능합니다. 펑션의 경우 해당 로직을 TODO에 그대로 옮겨적으시면 됩니다.

  4. 확률의 경우 뒤끝 콘솔에 각 행(row)의 퍼센트를 지정한 확률 파일을 업로드하고, 뒤끝 SDK를 통해 해당하는 확률로 도출된 결과를 받아와 보다 확률 뽑기등의 컨텐츠에 활용할 수 있습니다.
    차트는 게임정보관리 데이터와 달리 모든 유저가 공통적으로 조회할 수 있는 데이터로 여러 방면에서 활용할 수 있습니다.
    예를들어 아이템 차트 파일을 만들어 업로드 후, 게임 내 상점에서 아이템 리스트를 불러와 이를 출력할 수 있습니다. 더불어 차트 파일은 콘솔에서 간단한 수정 기능도 제공됩니다.
    차트 기능과 관련하여서는 아래 안내드리는 링크의 뒤끝 블로그를 통해 활용 방법에 대한 컨텐츠가 제공되고 있습니다.

답변 감사합니다. 뒤끝 펑션이라는 것을 진작에 찾아보면 좋았네요.
혹시 뒤끝 펑션같은 경우는 서버에 직접 함수를 실행 시키는 것이라고 이해하면 좋을까요?
즉, 호스트 + 비호스트를 거치지 않고 서버가 계산? 하는 느낌이라고 이해하고 있습니다.

또한 차트 기능같은 경우 인게임에서 실시간 데이터 변경이 가능한지 궁금합니다.
접근은 가능해서 리스트를 불러오는 경우는 있는거 같은데 차트 안에 있는 값의 수정은 못하는 것인지 궁금하네요.

뒤끝 펑션의 경우, 클라이언트에서 작동하는 코드를 그대로 서버로 분리하여 실행시키는 작업이라고 생각하시면 됩니다. 보안이 강한 클라이언트의 경우, 자신의 골드가 현재 레벨에 비해 많이 벌어지면 핵이라고 감지하는 코드를 추가하는데, 해킹을 하게 될 경우 이런 로직이 무효가 됩니다. 그래서 이런 로직은 건드리지 못하도록 서버로 띄우는 것입니다.

따라서 로그인 이후 현재 자신의 로그인 정보는 자동으로, 요청할 param과 함께 뒤끝 펑션을 호출합니다.

차트의 경우, 실시간적으로 데이터가 변경됨에 따라 응답이 오거나 하는 실시간 적 기능은 현재 존재하지 않습니다.