TIL 2025.03.09 기록
0. 개요
오늘도 강의를 들었다.
그리고 챌린지반 과제를 진행했는데, 이는 내일 정리해서 다시 기록하려 한다.
또.. 오늘은 강으를 듣다가 궁금한 점이 생겨서 질문을 드렸었는데, 처음 배우는 부분에 대해서 알게되고, 또 수업에서 왜 해당 내용을 가르쳐주신 것인지 알 수 있게되어서 좋은 경험이었다.
1. 온라인 게임과 네트워크 구성 이해하기
< 온라인 게임의 종류 >
온라인 게임은 크게 2가지 종류가 있다.
- 싱크 (Sync)
실시간, 리얼 타임 이런것들을 동기화된 게임이라고 한다.
싱크는 온라인 서버도 있고, LAN을 이용해 작은 환경에서 하는 게임도있다. - 어싱크 (Async)
대부분의 모바일 게임이라고 생각하면 된다.
< CAP 이론이란? >
CAP 이론이란건, 우리가 구축하는 네트워크 게임은 일관성, 가용성, 분할 용인 이 3가지를 갖춰야 한다는 것이다.
그런데, CAP 이론의 핵심은 이 3가지 모두 만족하는 시스템은 없다는 것이다.
2가지를 선택하면, 나머지 하나는 포기해야한다는 것이고, 이게 시스템 설계의 기본이다.
또한 이론으로 인정받고 있다.
- Consistency (일관성)
전체 시스템은 동일한 상태 값을 갖고 있어야 한다. - Availability (가용성)
언제든지 시스템에 접근하여 값을 읽고 쓸 수 있어야 한다. - Partition Tolerance (분할 용인)
시스템을 분할하여 병렬처리 등이 가능해야 한다.
< 게임에서의 동기화 방법 >
CAP 3가지를 동시에 갖출 수 없기 때문에 동기화하는 방법이 크게 2가지가 있다.
초기 온라인 게임 방식
옛날부터 계속 내려오던 방식 중 하나가 일관성을 유지하고 가용성을 포기하는 것이다.
가용성이라는 것은 언제든 내가 시스템을 사용할 수 있다는 것이다.
일관성을 유지할 수 밖에 없기 때문에 가용성을 포기하는건데, 왜냐면 분할 용인성이 네트워크의 기본이기 때문에 포기할 수 있는게 가용성밖에 안남는 것이다.
가용성을 포기한다는 것은 클라이언트가 어떤 이밴트(RPC)를 보내면, 한 tick마다 브로드캐스팅을하고 클라이언트가 그때 업데이트한다.
이게 기본적이고, 현대 게임에서도 작동하는 방식이다.
그래서 이런 경우는 빠른 반응속도가 필요없을 때만 사용이 가능하다.
실시간으로 별도의 채널을 통해 다중 브로드캐스팅을 하는 방식
앞에서 설명한 동기화 방법은 기본으로 깔고 가고, 사용자가 입력을하면, 클라이언트에 업데이트를 먼저하고 서버에서 바로 브로드캐스팅을 한다.
대신 RPC를 호출한 쪽에서는 서버에서 가져온 값으로 검증하고 보증하는 단계를 거친다.
만약 다르다면 롤백하는 경우도 있다.
와우 같은게 이런 경우라고 하시는데, A가 움직이면 B,C쪽에서 A가 나중에 움직인다고 하신다.
이렇게 동기화방법은 크게 2가지이다.
더 자새한 내용
가용성 보정
첫번째 방식의 경우 가용성을 포기한 것이다.
대신 일관성이 있다.
=> 전체가 업데이트가 되기 때문에. (스타크래프트가 이런 방식으로 만들어졌다.)
왜 중간에 우리가 서버의 Round 시간(브로드캐스팅 대기 시간)을 느끼지 않냐면, 우리가 입력을 했다는 음성 피드백을 주기 때문에 나중에 움직인다는 느낌을 주지 않게 만들었기 때문이다.
이런 설계를 CP 설계라 한다. (CAP에서 A를 뺀것)
CP 설계의 특징은 가용성이 떨어지는 경우 세션을 폭파시키고 남은 플레이어가 승리한다.
일관성 보정
FPS, 최근의 MMORPG 같은 경우 입력을 받으면 바로 움직여야 한다.
클릭을 하면, 브로드캐스팅을 받기 전까지 움직이고, 서버가 준 결과가 다르다면 다시 롤백한다.
즉, 예측과 서버 값이 맞으면 그대로 진행하고, 예측과 서버 값이 틀리면 서버값으로 반영한다.
롤 백 현상은 응답속도가 낮아서 브로드캐스팅을 제때 못받아서 발생하는 일이다.
이게 클라이언트 예측, 서버 조정을 사용한다고 한다.
이를 AP 또는 PA 설계라고 한다.
AP 설계의 특징은 특정 플레이어가 응답속도(Latency) 가 떨어지더라도 세션을 그대로 유지됩니다.
클라이언트 보간 (클라이언트 예측)
왜 그러냐면, 서버에서 보내주는 시그널이 같은 일정한 주기로 온다고 생각하는데, 실제 데이터로는 그 주기가 다르다.
때문에 클라이언트에서는 보간이라는 작업을 거친다.
서버에서 데이터를 받아오면, 클라이언트에서 바로 랜더링하는게 아니라 버퍼에 약간의 지연시간을 두고 쌓아뒀다가, 들쭉날쭉한 이런 시그널인 네트워크 지터를 보정하고 보간값으로 활용한다.
( 그러니까.. 서버에서 데이터를 받은 시간과 로컬의 랜더링 타이밍이 서로 안맞기 때문에 랜더링 타이밍때, 해당 시점에는 어떤 값을 랜더링할지를 보간해 사용한다는 이야기. )
< 비동기 방식 >
궁극에 가용성을 포기하고, 궁극의 동기화와 궁극의 분할 용인을 선택한 것이다.
얘는 UDP를 사용하지 않고, TCP를 사용해 서버에 이밴트 결과값만 보내고, 이게 DB에 저장된다.
⇒ 느리지만 손실이 허용이 안되기 때문에 TCP 프로토콜을 사용한다.
클래시로얄로 예를 들면, 상대 영역에 침범해 약탈을 하면, 상대는 약탈당한 것을 실시간으로 보지는 않는다.
즉, 싱크해서 바로 보지는 않는다.
대신 나중에 접속해서 보면 털려있는 것을 보게된다.
대부분의 모바일 게임은 이렇게 사용자의 값들의 전체를 일치화 시킨다.
다른 플레이어의 접속여부와 관계없이 진행되기 때문에 서버 수용 인원도 많고, 이론적으론 확장이 무한한 모델이다.
< 채팅 서버와 온라인 게임 서버의 유사점과 차이점 >
이러한 과정들 사실 1978년 MUD(Mullti User Dungeon)게임에서부터 내려온 것들이다.
근데, 이러한 것들이 채팅서버와 굉장히 유사한 점이 많다.
그당시 터미널 사이에서 메세지를 주고받던 것을 가지고 텍스트 MUD게임이 그래픽 MUD게임이된것이고, 그게 지금 온라인 RPG게임이 된것이다.
때문에 유사하다.
유사점
- 사용자의 입력을 전체 사용자에게 브로드캐스팅합니다.
- 사용자의 세션을 관리합니다.
- 채널(또는 서버) 별로 다른 상태를 가집니다.
- 채널을 선택하거나, 내 아바타를 커스텀 하거나, 친구 목록을 보는 등의 로비가 있습니다.
차이점
- 채팅에서는 사용자를 그래픽으로 표현하지 않습니다.
- 채팅에서는 사용자의 상태를 그래픽으로 표현하지 않습니다.
- 게임은 승과 패, 성공과 실패가 그래픽으로 표현되지만, 채팅은 부모님 안부 묻는 걸로 표현합니다.
- 채팅은 데이터 량이 작으므로 접속이 끊겨서 새로 접속하면 채널의 모든 정보를 줄 수도 있습니다.
- 채팅은 낮은 Latency를 고려하지 않지만, 게임 서버는 경우에 따라 고려(클라이언트 예측과 서버 보정을 한다) 합니다.
게임서버가 서로 같은 환경에서 게임이 불공평하지 않게 핑 같은 것을 보존해주는 로직이 들어가야 하는 부분에서는 더 복잡하지만, 싱크 시켜주거나 하는 쪽에서는 채팅서버가 더 복잡하다.
( 채팅 서버가 개발의 끝판왕이다 라는 이야기도 많이 나온다고 한다. )
( 요점은 온라인 서버를 개발한다는 생각을 하지 말고, (상용엔진에서는 관리 해주는 부분이 꽤 많아서) 채팅 서버를 만든다 생각하고 공부하는 것이 좋아보인다고 하신다. )
< 어느 잘 되는 온라인 게임 회사의 네트워크 구성 진화 >
사용량이나 유저 케이스마다 다 틀려서 게임 서버와 클라인언트가 서로 어떻게 연결되는지는 설명이 복잡하다.
때문에 가상의 회사가 처음 설립되어 어떻게 서버가 초기부터 발전해 나아가는지를 보여주는 가상 시나리오를 만들어보셨다고 하신다.
처음 개발 때는 보통 서버와 DB 하나만 가지고 시작을 하는데, 알파, 베타 테스트를 거쳐 점점 사용자가 늘어나게 되면, 서버에 병목현상이 발생하기 시작한다.
네트워크에서 가장 많이 하는 일이 이 병목현상 지점을 찾고, 해소하는 일이다.
때문에 서버를 분리했더니 채팅량 때문에 또 병목이 발생해 또 나눠주었다.
또, 게임 업데이트가 많아지면서 CDN 컨텐츠 딜리버리 네트워크에다가 업데이트 파일을 쌓아두면서 분리가 되었다.
이 상황에서는 로그인 서버, 게임 서버 등 하나만 터져도 전체 시스템이 박살나게 된다.
때문에 클러스팅이라고 해서 병렬로 서버를 더 확장했다.
이러한 클러스팅을 구성할 때 가장 먼저 들어가는게 L4스위치 혹은 L7스위치이다.
스위치가 로그인 서버(혹은 다른 서버) 123에 붙어서 로드 밸런싱에 따라서 트래픽이 적은 얘한테 새로운 트래픽을 보내는 것이다.
그러면 전체적으로 장기적으로 봤을 때, 서버 3개가 동시에 일을하면서 부하가 분산되게 되는 것이다.
또, 서버 한대가 죽어도 서비스를 중단 없이 할 수 있다.
이렇게 잘되다보니 해커들이 오기 시작한다. 이를 막기 위해 방화벽을 설치한다.
( 원랜 더 앞쪽부터 사용하는데, 설명을 위해서 이때 붙이는 시나리오로 하셨다고 하신다. )
이제 접속되는 서버는 많은데, DB가 하나이다보니 DB를 클러스터링한다.
래빗 MQ를 사용해 서버의 부하를 줄일 수 있다. 단점은 속도가 조금 느리다.
설명에서 빼둔 서버들이 굉장히 많기 때문에 실제 실무에서는 이보다 훨씬 복잡하다고 하신다.. ex) 테스트 서버, 매치 메이킹 서버, 결제 서버 등등...
( 쭉~ 보니 병목을 줄이고 서버나 DB의 부하가 적게 만드는 작업이 주인것 같다. )
< 튜터님의 조언! >
네트워크 기본 용어는 반드시 알아야한다.
게임 시스템에서 플레이어 세션 동기화 기법의 원리는 반드시 숙지해라.
네트워크 시스템의 구성은 어떻게 확장되는지 등은 알아두는게 좋다. (나중에 업무에서 대화를 위해)
2. 언리얼 소스 코드 빌드하기
이론적인 부분을 살펴봤으니 이제 언리얼 소스를 직접 빌드해볼 것이다.
또, 언리얼의 파이프라인을 어떻게 가지고 작업을 해나가는지 살펴볼 것이다.
< 깃 토큰 만들기 >
소스트리에서 언리얼에 접근하기 위한 깃 인증용 토큰을 만든 것 이다.
물론 모든 것들을 오픈해서 해킹에 위험해서 중요한 레포지토리라면 주의해야 하지만, 우선 학습용으로 언리얼 레포지토리에 접속해 다운해서 빌드하기 위해서 하는 것이다.
해당 토큰 주소를 나중에 잊어버리면, 나중에 삭제했다가 다시 만들어야 한다.
< 에픽 게임즈 연결하기 >
에픽게임즈에 가입하고나면, 계정쪽에 들어가서 앱 및 계정에서 Git에 연결해야 한다.
https://github.com/EpicGames/UnrealEngine
그러면 에픽게임즈쪽에 초대를 받는다.
< 소스 트리 다운 >
https://www.sourcetreeapp.com/
이후에는 소스 트리를 다운해야 한다.
( 음.. 꼭 소스트리여야 하나? 아닐것 같다. )
이후에는 소스트리를 이용해 언리얼 소스코드를 클론해 받아오면 된다.
태그를 눌러서 최신 버전을 더블 클릭해 파일을 최신 버전으로 다시 갱신해준다.
< VS 패키지 및 컴파일러, 빌드 도구 추가 설치 >
주의해야할 점이 비쥬얼 스튜디오 2022는 언리얼 엔진과 C++빌드툴이 호환이 안된다.
때문에 이걸 호환성 있게 바꿔주어야 한다.
필수로 해야할 부분이
.Net Mutiplayer 개발, .Net데스크톱 개발, C++을 사용한 데스크톱개발, WinUI 어플리케이션 개발, C++을 사용한 게임개발이 선택이 되어있어야 한다.
또 개별 구성요소에서 컴파일러, 빌드 도구 중 14.38 MSVC v143 x64x86 빌드 도구 버전 1438-17.8도 설치해주어야 한다.
❗❗주의사항❗❗
주의할 점은 언리얼은 버전별로 다른 빌드 컴파일러를 필요로하기 때문에 주의해 언리얼 버전에 따라 따로 설치를 해주어야 한다.
- 5.2 build tools 14.34
- 5.3 build tools 14.36
- 5.4, 5.5 build tools 14.38
< SDK 설치하기 >
Windows SDK - Windows app development
The Windows SDK for Windows 11 contains headers, libraries, and tools you can use when you create apps that run on Windows.
developer.microsoft.com
설치가 끝난 후에는 WindowSDK를 반드시 설치해주어야 한다.
pdbcopy.exe 파일이 가장 큰 문제인데, 알맞은 버전의 SDK를 다운해주면 된다.
이렇게하면, 기본적인 빌드 준비는 다 끝난 것이다.
< Setup bat 파일 실행하기 >
다음은 소스를 다 받은 상태인데,
커맨드 창을 관리자 권한으로 열어서 우리가 소스코드를 설치한 곳으로 이동해서 Setup을 해준다.
이때 다시 시간이 걸리는데, 다시 한번 더 업데이트를 해주는 것이다.
마지막으로 GenerateProjectFiles.bat 파일을 실행해주면 모든게 끝난다.
< 빌드하는 방법! >
VS를 이용해 빌드하는 방법보다 추천해주시는 방법은 실무에서는 Jenkins라는 오토빌드 시스템을 사용하는데, 밤에 엔진쪽 소스 업데이트가 끝나고, 밤에 빌드를 돌리면 4시간~6시간동안 걸리는 빌드를 마치고 아침에 팀원분들께 배포하는 방식을 추천하신다고 하신다.
( 와.. 진짜 직접 소스 코드를 빌드하려 해보니... 진짜 저정도 시간이 걸릴 것 같았다. )
또, 명령어가 있는데, 이 명령어를 이용해 실행하면, 빌드 러닝 오토메이션 툴이 돌아가게되고 로컬에서 커맨드라인에서 바로 빌드를 할 수 있다.
빌드가 됐다면, local builds라는 폴더가 생긴다.
그러면 Engine아래 Windows Engine에 Binaries/Win64에 들어가서 보면, UnrealEditor.exe 파일을 찾을 수 있다.
이러면 빌드가 완전히 끝난 상태이다.
이러면 실행준비까지 끝이난다.
해당 실행파일을 실행시키면 에디터가 실행되는 것을 확인할 수 있다.
네트워크를 데디케이트 서버를 쓰든 다른 서버를 쓰든 빌드 커맨드를 사용할 수 있고, 소스코드가 없다면, 빌드가 안되서 나중에 추가해야하기 때문에 C++로 프로젝트를 생성하는게 좋다.
< CI/CD >
왜 소스 코드를 처음부터 빌드를 하는 걸까에 대한 궁금증이 생겼다.
때문에 튜터님께 질문을 드렸는데, 지금 해보는 이 소스 코드 빌드 및 자동화는 CI/CD가 어떻게 이루어지는지 일부분을 보여주시고, 소스 코드 빌드를 이렇게도 해볼 수 있다인 취지인 것 같다.
즉, 일단 네트워크 기능을 추가할 때, 적어도 우리 수업에서는 영향이 없는 듯 하다… ㅠ
< 정리 >
인원수가 많이 작업하면 매번 리소스가 코드 종속적이고 할 수 있는데, 이런 상황을 막아야해서 아트팀에 배포를 할때는 프로그래머들이 최신화한 빌드한 것을 보내야한다.
근데, 프로그래머가 아니라면 VS가 없기 때문에 그리고 프로그램이 익숙하지 않을 수 있기 때문에 빌드를 하는게 어렵다.
때문에 받을 때 완성된 최종 배포 버전을 받을 수 있도록 하는 것이다.
즉, 소스 코드를 프로그래머가 업데이트하면, 다른 팀분들께 배포를 해야하는데, 이때 매번 직접 하기 힘드니까 자동화 툴을 사용하는 것이다.
또 요즘은 Jenkins가 아니라 TeamCity를 사용하는게 더 많은 것 같다고 하신다. 음.. 양대산맥 느낌인것 같다.
또 이처럼 소스 코드가 업데이트되면, 빌드해 배포하고, 또 패키징을 하는 팀이 따로 있고, 이런 과정들을 CI/CD라고 한다고 하신다.
CI/CD(Continuous Integration / Continuous Delivery & Deployment)
⇒ 의미하는게 계속 통합시키고 계속 배포한다는 의미이다.
이런걸 자동화한 걸 CI/CD라 한다.
RunUAT.bat
UAT의 의미가 Unreal Automation Tool이다.
즉, 빌드 시키는 역할을 해주는 배치 파일이다.
따라서 이번 수업의 내용은 배치파일을 만들어서도 빌드가 가능하고, 이렇게 만든 배치파일을 Jenkins에 넣어서 사용한다는 내용이다.
이때 단순히 빌드만 넣는게 아니라 복사 이동, 패키징 등등도 들어갈 수 있는것 같다. 음.. 그러니까 빌드 자동화는 CI/CD의 일부분일 뿐이다.
또, 런처가 없는 언리얼 유료시절에는 엔진 소스코드를 받아서 엔진부터 직접 빌드를 했어야 했는데, 지금은 엔진 코드는 dll로 빌드되고 따로 소스 코드파일이 외부에 존재하는 식이다.
⇒ 라이브 코딩 기술도 dll 파일 덕분에 가능한 기술로 알고 있다.
또, 엔진 빌드가 오래걸리기 때문에 옛날에는 IncrediBuild를 사용했었다.
3. 언리얼 네트워크와 객체 통신 이해하기
4. 마무리
음.. 강의도 여러 강의를 듣고.. 또 챌린지반 과제도 진행하는 등 오늘은 알차게 보낸 것 같다.
멀티쪽도.. 좀 미리 몇 번 해봐야할 거 같아서 최대한 빨리 강의를 듣고, 이것저것 해봐야할 것 같다.
또.. 3주정도 뒤엔 멀티 게임 프로젝트가 시작되니까..
그래도 확실히 잘 모르는 부분을 배우는 것도, 막히는 것들도 전부 다 재밌는 것 같다. ㅎㅎ
프로그래밍이 잘 맞는 것 같다 느껴져서 다행이라는 생각이 드는 날이었다.