대형 구조 관리
우리가 지금까지 만든 GameRoom 형태는 말 그대로 하나의 쓰레드가 Gamroom을 담당해 모든 연산, Job 방식으로 처리하고 있었다. 이를 더 넓은 영역에 대한 관리를 어떻게 해야할지 고민해보자.
심리스 MMO의 경우는 하나의 큰 GameRoom으로 관리할 수 있을지 의문이다. 왜냐하면 동접자 수가 수만명이 넘어가면 필히 렉이 발생하고 말것이다. 그렇다면 맵을 쪼개서 각각의 GameRoom으로 만드는건 괜찮을까? 이전보다 훨씬 나아질테지만 하나의 GameRoom안에 모든 유저가 모인다면 이 역시 문제가 발생할 것이다.
또한 서로의 GameRoom 경계에서 일어나는 일들을 관리해 주어야한다.
A의 영역 B의 영역 사이에서 스킬을 사용하거나 플레이어끼리 데미지를 준다거나 등 의 브로드캐스트나 각 다른 쓰레드에서 진행하기 때문에 연산 순서에 대한 보장이 되지 않는다.
그렇기 때문에 실제 심리스 MMO 같은 경우는 크게 두가지 방법을 사용한다고 한다.
1. 위에서 서술한대로 GameRoom을 특정 단위로 나눠 각 GameRoom의 경계에 맞춰 브로드캐스트나 실행 순서 보장등의 코드를 추가해서 작업한다.
2. 오브젝트, 객체마다 JobSerializer를 두어 그 객체에서 일어나는 일을 Job 단위로 처리하는 방식이다.
어느 방식이 더 좋다고 할 수 없다. 각각 장단점이 있고 2번의 경우는 고급 스킬이기 때문에 필자는 아직 다뤄본적이 없는 내용이고 카더라에 가깝다.
그래서 심리스MMO를 만들기 전에 존단위로 영역을 나눠 더 넓은 영역에 대한 관리를 어떻게 할 수 있을지, 그리고 서버 구조를 어떻게 개선해야할지 적어보겠다.
현재 쓰레드는 다음과 같다.
1. Recv (N개)(네트워크에서 통신을 받아 처리하는 쓰레드)
2. GameRoomManger (1개)
3. DB (1개)
멀티쓰레드에 익숙해지전에는 GameRoomManger라는 이름을 GameLogic으로 수정해서 Game에 대한 Logic을 전부 다룰 수 있는 쓰레드로 사용하는 것(마치 싱글쓰레드 처럼)이 좋을 수 있다.
드 넓은 세상에서 처리
이제 게임룸 자체를 하나의 세계로 구성을 했다면 그 안에서 브로드캐스팅의 범위를 어느정도로 해야 부하가 가장 적을까를 생각해보자.
자신의 플레이어 주변만 브로드캐스트 해주면 될 것이다. 그 범위는 카메라의 크기 보다 살짝 크게 적용한다.
단순한 생각이지만 구현을 하는 것은 생각보다 까다롭다.
지금 당장 생각할 수 있는건 모든 객체들이 내 관심 영역에 있는지 체크를 하면되지 않을까 싶다.
하지만 객체 수가 수만마리가 넘어가면 그리고 또 다른 플레이어도 같은 계산을 한다면 아마 성능상 문제가 많이 발생할 것이다.
이 부분을 아름답게 처리해 주어야 할 것이다.
방법은 Zone을 나누어 처리하는 것이다. GameRoom을 몇개의 Zone으로 쪼갠다.
내가 처리해야할 관심 영역이 어떤 Zone에 들어가 있다면 그 Zone안에 있는 객체만 스캔할 수 있기 때문에 전체 객체를 스캔할 필요가 없다. 물론 Zone의 영역에 운이 나쁘게 걸쳐 있다 하면 걸친 Zone에서 스캔하면 될 것이다. 이는 전체 객체를 스캔하는 것보다 훨씬 효율이 좋을 것이다.
using System;
using System.Collections.Generic;
using System.Text;
namespace Server.Game
{
public class Zone
{
public int IndexY { get; private set; }
public int IndexX { get; private set; }
public HashSet<Player> Players { get; set; } = new HashSet<Player>();
public Zone(int y, int x)
{
IndexY = y;
IndexX = x;
}
public Player FindOne(Func<Player, bool> condition)
{
foreach (var player in Players)
{
if(condition.Invoke(player))
return player;
}
return null;
}
public List<Player> FindAll(Func<Player, bool> condition)
{
List<Player> findList = new List<Player>();
foreach (var player in Players)
{
if (condition.Invoke(player))
findList.Add(player);
}
return findList;
}
}
}
Zone을 만들어주고 이를 GameRoom에서 입장할때와 브로드캐스트 할때의 코드를 수정해주면 된다.
public void Broadcast(Vector2Int pos, IMessage packet)
{
List<Zone> zones = GetAdjacentZones(pos);
foreach(Player p in zones.SelectMany(z => z.Players))
{
p.Session.Send(packet);
}
}
'Unity > 온라인 RPG' 카테고리의 다른 글
[Unity 3D] 캐릭터 선택창 및 캐릭터 생성 (0) | 2024.04.13 |
---|---|
[Unity 3D] Title과 Login 구현 (UI 작업, 서버 연동) (0) | 2024.04.09 |
[Unity 2D] DB 연동 - Reward 와 아이템 착용 (0) | 2024.03.29 |
[Unity 2D] Db 연동 - Item과 Inventory (0) | 2024.03.27 |
[Unity 2D] DB 연동 - Player, HP db 연동 (0) | 2024.03.26 |