TIL-sparta

스파르타) The Last Rollback (D-25, Node.js 게임 서버 최종 프로젝트) - timer

Megadr0ne 2024. 8. 3. 03:35


 > 과제 진행 간 완료한 사항 및 문제점과 해결 과정을 정리해보았다.

 

학습 키워드: Node.js, Unity, C#

 

과제 진행 사항

1) 라운드 전환, 몬스터 목록 전송, 낮 라운드 타이머 등:

 

Update 낮 밤 라운드 기능 2 · Issue #56 · eliotjang/the-last-rollback-server

할 일 패킷 구조 확실하게 정의하기 클라이언트 낮 라운드 낮 라운드 시작 시 서버와 동기화 된 시간으로 타이머 카운트다운 시작 준비 버튼 클릭 시 C_DayRoundReady 패킷 송신 낮 라운드에만 나타

github.com

 - (상세 작업 내용은 위 Issue 참고)

 

 

2) 낮 라운드 타이머 기능:

 현재 게임의 기획은 준비 라운드인 낮 라운드와 전투 라운드인 밤 라운드를 일정 횟수만큼 번갈아가며 반복하는 구조로 되어있다. 여기서 낮 라운드에 제한 시간을 두기로 했는데, 각 클라이언트의 타이머 및 서버의 타이머를 일치시켜야하는 부분을 고민해보게 되었다. 기능 구현에는 setTimeout을 사용하기로 했는데, 처음에는 여러 세션이 setTimeout을 했을 때 서버에 부담이 갈까 싶었으나 수백개의 세션이 돌아갈 때 각 세션에서 낮 라운드 타이머는 하나씩만 돌아가며, 타이머 자체가 별다른 무거운 작업을 실행하지는 않을 것이기 때문에 영향이 미미할 것이라고 판단했다.

 

 일단 타이머의 시간은 세션 내 모든 클라이언트가 동일한 값을 공유해야하고, 실제로 라운드를 시작시키려면 이 값을 서버에서 관리해야한다. 그래서 서버에서 setTimeout을 호출하여 30초 후에 밤 라운드 시작 패킷을 보내도록 설정하고, 동시에 타이머가 시작한 시점의 timestamp와 설정된 시간을 타이머 설정 패킷에 담아 보내주도록 설정했다. 클라이언트가 타이머 패킷을 수신하면 받은 타이머의 시간과 서버의 시작 timestamp, 수신 시 timestamp를 계산하여 실제 서버의 남은 시간을 화면에 출력하도록 설정했다.

 

// dungeon.class.js (서버)
  ...
  setDayRoundTimer() {
    (async () => {
      setTimeout(() => {
        this._isNight = true;
        this.notifyAll(payloadTypes.S_NIGHT_ROUND_START, {});
      }, DAY_DURATION);
    })();
    (async () => {
      const data = {
        startTime: Date.now(),
        milliseconds: DAY_DURATION,
      };
      this.notifyAll(payloadTypes.S_DAY_ROUND_TIMER, data);
    })();
  }
  ...
// DungeonManager.cs (클라이언트)
...
public void SetTimer(ulong timestamp, uint milliseconds) 
{
    ulong now = (ulong) DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    float time = (float) (milliseconds - (now - timestamp)) / 1000;
    uiTimer.SetCurrentTime(time);
    uiTimer.gameObject.SetActive(true);
    uiTimer.StartTimer();
}
...

 

 추가로 고려할 사항은 클라이언트가 타이머 패킷을 수신하는 시점이 이미 타이머가 조금 흘러간 시점이라는 부분인데, ping 기능을 도입하여 latency를 계산하고 그만큼 setTimeout 실행을 실짝 늦춰야 하는 건가 싶다. 또한, 위 방식으로 구현한 타이머에는 한 가지 문제점이 있는데, setTimeout은 event loop에 blocking 작업이나 GC 등으로 인해 지연될 수가 있기 때문에 정확한 시간으로 동기화가 불가능하다. 추후 MVP 기능 구현 완료 후 여유가 생기면 이를 해결할 방법이 있는지 알아봐야겠다.

 

 

--


REFERENCES:

 

 

GitHub - eliotjang/the-last-rollback-server: 액션 MORPG

액션 MORPG. Contribute to eliotjang/the-last-rollback-server development by creating an account on GitHub.

github.com

 > 프로젝트 repo

 

728x90