Files
a301_mmo_game_server/MMOTestServer/MMOserver/Game/Channel/Channel.cs
tolelom 53eabe2f3d fix: MMO 서버 버그 수정 및 안정성 개선 (20건)
- VerifyTokenAsync 인증 우회 차단 (빈 문자열→null 반환)
- HandleAuth/OnIntoBossRaid async void→async Task 전환
- await 후 스레드 안전성 확보 (sessionLock 도입)
- 보스레이드 파티원 세션/토큰 개별 전달 (tokens Dictionary 타입 수정)
- 409 Conflict 처리 추가, bossId 하드코딩 제거
- 채널 이동 시 레이드 맵 해제, 플레이어 상태 보존
- 파티원 닉네임 손실 수정, HandlePartyLeaveOnExit 알림 타입 수정
- PacketCode enum 명시적 값 할당, MaplId→MapId/BossRaidAccesss→Access 오타 수정
- Channel.UserCount 음수 방지, HandleAuth 재연결 로직 수정

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 23:26:39 +09:00

208 lines
5.1 KiB
C#

using LiteNetLib;
using MMOserver.Game.Channel.Maps;
using MMOserver.Game.Channel.Maps.InstanceDungeun;
using MMOserver.Game.Party;
namespace MMOserver.Game.Channel;
public class Channel
{
// 채널 내 유저 NetPeer (hashKey → NetPeer) — BroadcastToChannel 교차 조회 제거용
private readonly Dictionary<int, NetPeer> connectPeers = new();
// 채널 내 유저 상태 (hashKey → Player)
private readonly Dictionary<int, Player> connectUsers = new();
// 채널 맵 관리
private readonly Dictionary<int, AMap> maps = new();
// 진행중 채널 맵 관리
private readonly Dictionary<int, AMap> useInstanceMaps = new();
// 동적 레이드 맵 할당용 ID 카운터 (사전 생성 10개 이후부터 시작)
private int nextDynamicRaidMapId = 1011;
// 파티
private readonly PartyManager partyManager = new();
public Channel(int channelId)
{
ChannelId = channelId;
// 일단 하드코딩으로 맵 생성
{
// 로비
maps.Add(1, new Robby(1));
// 인던
int defaultValue = 1000;
for (int i = 1; i <= 10; i++)
{
maps.Add(i + defaultValue, new BossInstance(i + defaultValue));
}
}
}
public int ChannelId
{
get;
}
public int UserCount
{
get;
private set;
}
public int UserCountMax
{
get;
private set;
} = 100;
public void AddUser(int userId, Player player, NetPeer peer)
{
connectUsers[userId] = player;
connectPeers[userId] = peer;
UserCount++;
// 처음 접속 시 1번 맵(로비)으로 입장
ChangeMap(userId, player, 1);
}
public void RemoveUser(int userId)
{
// 현재 맵에서도 제거
if (connectUsers.TryGetValue(userId, out Player? player) &&
maps.TryGetValue(player.CurrentMapId, out AMap? currentMap))
{
currentMap.RemoveUser(userId);
}
if (connectUsers.Remove(userId))
{
UserCount--;
}
connectPeers.Remove(userId);
}
// 맵 이동 (현재 맵 제거 → 새 맵 추가 → CurrentMapId 갱신)
public bool ChangeMap(int userId, Player player, int mapId)
{
if (!maps.TryGetValue(mapId, out AMap? newMap))
{
return false;
}
// 기존 맵에서 제거
if (maps.TryGetValue(player.CurrentMapId, out AMap? oldMap))
{
oldMap.RemoveUser(userId);
}
newMap.AddUser(userId, player);
player.CurrentMapId = mapId;
return true;
}
// 재연결(WiFi→LTE 등) 시 동일 유저의 peer 교체
public void UpdatePeer(int userId, NetPeer peer)
{
connectPeers[userId] = peer;
}
// 채널 내 모든 유저의 hashKey 반환 (채널 입장 시 기존 플레이어 목록 조회용)
public IEnumerable<int> GetConnectUsers()
{
return connectUsers.Keys;
}
// 채널 내 모든 Player 반환
public IEnumerable<Player> GetPlayers()
{
return connectUsers.Values;
}
// 채널 내 모든 NetPeer 반환 — BroadcastToChannel 전용 (sessions 교차 조회 불필요)
public IEnumerable<NetPeer> GetConnectPeers()
{
return connectPeers.Values;
}
// 특정 유저의 Player 반환
public Player? GetPlayer(int userId)
{
connectUsers.TryGetValue(userId, out Player? player);
return player;
}
public int HasUser(int userId)
{
if (connectUsers.ContainsKey(userId))
{
return ChannelId;
}
return -1;
}
// 맵들 가져옴
public Dictionary<int, AMap> GetMaps()
{
return maps;
}
// 맵 가져옴
public AMap? GetMap(int mapId)
{
AMap? map = null;
maps.TryGetValue(mapId, out map);
return map;
}
// 사용 가능한 레이드 맵 ID 반환
// 기존 맵(1001~) 중 미사용 탐색 → 없으면 동적 생성 후 반환
public int GetOrCreateAvailableRaidMap()
{
// 기존 맵 중 미사용 탐색
foreach (int mapId in maps.Keys)
{
if (mapId >= 1001 && !useInstanceMaps.ContainsKey(mapId))
{
return mapId;
}
}
// 모두 사용 중 → 동적 생성
int newMapId = nextDynamicRaidMapId++;
BossInstance newMap = new(newMapId);
maps.Add(newMapId, newMap);
return newMapId;
}
// 레이드 맵 사용 시작 (진행중 목록에 등록)
public void AddInstanceMap(int mapId)
{
if (maps.TryGetValue(mapId, out AMap? map))
{
useInstanceMaps[mapId] = map;
}
}
// 레이드 맵 사용 종료 (진행중 목록에서 제거)
public void RemoveInstanceMap(int mapId)
{
useInstanceMaps.Remove(mapId);
}
// 파티매니저 가져옴
public PartyManager GetPartyManager()
{
return partyManager;
}
// TODO : 채널 가져오기
}