feat : 보스전 채널 생성, 파티 함께 채널 이동 구현

This commit is contained in:
qornwh1
2026-03-12 13:23:30 +09:00
parent 4956a2e26d
commit 0ebe269146
8 changed files with 268 additions and 27 deletions

View File

@@ -22,6 +22,7 @@ public class GameServer : ServerBase
packetHandlers = new Dictionary<ushort, Action<NetPeer, int, byte[]>>
{
[(ushort)PacketCode.INTO_CHANNEL] = OnIntoChannel,
[(ushort)PacketCode.INTO_CHANNEL_PARTY] = OnIntoChannelParty,
[(ushort)PacketCode.EXIT_CHANNEL] = OnExitChannel,
[(ushort)PacketCode.TRANSFORM_PLAYER] = OnTransformPlayer,
[(ushort)PacketCode.ACTION_PLAYER] = OnActionPlayer,
@@ -208,7 +209,7 @@ public class GameServer : ServerBase
private void SendLoadChannelPacket(NetPeer peer, int hashKey)
{
LoadChannelPacket loadChannelPacket = new LoadChannelPacket();
foreach (Channel.Channel channel in ChannelManager.Instance.GetChannels())
foreach (Channel.Channel channel in ChannelManager.Instance.GetChannels().Values)
{
if (channel.ChannelId <= 0)
{
@@ -376,13 +377,34 @@ public class GameServer : ServerBase
IntoChannelPacket packet = Serializer.Deserialize<IntoChannelPacket>(new ReadOnlyMemory<byte>(payload));
ChannelManager cm = ChannelManager.Instance;
Channel.Channel channel = cm.GetChannel(packet.ChannelId);
// 이전에 다른 채널에 있었는지 체크
int preChannelId = cm.HasUser(hashKey);
if (preChannelId >= 0)
{
// 제거 전에 채널/플레이어 정보 저장 (브로드캐스트에 필요)
Player? player = cm.GetChannel(preChannelId).GetPlayer(hashKey);
// 파티 자동 탈퇴
HandlePartyLeaveOnExit(preChannelId, hashKey);
cm.RemoveUser(hashKey);
Log.Debug("[GameServer] EXIT_CHANNEL HashKey={Key} PlayerId={PlayerId}", hashKey, preChannelId);
// 같은 채널 유저들에게 나갔다고 알림
if (player != null)
{
SendExitChannelPacket(peer, hashKey, preChannelId, player);
}
}
Channel.Channel newChannel = cm.GetChannel(packet.ChannelId);
// 최대 인원 체크
if (channel.UserCount >= channel.UserCountMax)
if (newChannel.UserCount >= newChannel.UserCountMax)
{
Log.Warning("[GameServer] INTO_CHANNEL 채널 인원 초과 HashKey={Key} ChannelId={ChannelId} UserCount={Count}/{Max}",
hashKey, packet.ChannelId, channel.UserCount, channel.UserCountMax);
hashKey, packet.ChannelId, newChannel.UserCount, newChannel.UserCountMax);
byte[] full = PacketSerializer.Serialize<IntoChannelPacket>((ushort)PacketCode.INTO_CHANNEL,
new IntoChannelPacket { ChannelId = -1 });
SendTo(peer, full);
@@ -407,6 +429,110 @@ public class GameServer : ServerBase
SendLoadGame(peer, hashKey);
}
private void OnIntoChannelParty(NetPeer peer, int hashKey, byte[] payload)
{
IntoChannelPartyPacket packet = Serializer.Deserialize<IntoChannelPartyPacket>(new ReadOnlyMemory<byte>(payload));
ChannelManager cm = ChannelManager.Instance;
int preChannelId = cm.HasUser(hashKey);
Channel.Channel preChannel = cm.GetChannel(preChannelId);
Channel.Channel newChannel = cm.GetChannel(packet.ChannelId);
PartyInfo? preParty = preChannel.GetPartyManager().GetParty(packet.PartyId);
// 이전에 다른 채널에 있었는지 체크 / 파티이동은 이미 접속한 상태여야 한다.
if (preChannelId < 0 || preParty == null)
{
Log.Warning("[GameServer] INTO_CHANNEL_PARTY 해당 파티 없음");
return;
}
// 새로운 파티를 복사한다
PartyInfo newParty = new PartyInfo();
newParty.DeepCopySemi(preParty);
// 최대 인원 체크
if (newChannel.UserCount + newParty.PartyMemberIds.Count >= newChannel.UserCountMax)
{
Log.Warning("[GameServer] INTO_CHANNEL_PARTY 채널 인원 초과 HashKey={Key} ChannelId={ChannelId} UserCount={Count}/{Max}",
hashKey, packet.ChannelId, newChannel.UserCount, newChannel.UserCountMax);
byte[] full = PacketSerializer.Serialize<IntoChannelPacket>((ushort)PacketCode.INTO_CHANNEL,
new IntoChannelPacket { ChannelId = -1 });
SendTo(peer, full);
return;
}
// 기존 채널에서 제거 + 기존 채널 유저들에게 나감 알림
foreach (int memberId in preParty.PartyMemberIds)
{
Player? player = preChannel.GetPlayer(memberId);
if (player != null)
{
UpdateChannelUserPacket exitNotify = new UpdateChannelUserPacket
{
Players = ToPlayerInfo(player),
IsAdd = false
};
byte[] exitData = PacketSerializer.Serialize<UpdateChannelUserPacket>((ushort)PacketCode.UPDATE_CHANNEL_USER, exitNotify);
BroadcastToChannel(preChannelId, exitData);
// 이전 채널에서 제거
preChannel.RemoveUser(memberId);
// 현재 존재하는 파티원만 추가한다.
newParty.PartyMemberIds.Add(memberId);
}
}
// 이전채널에서 파티를 지운다.
preChannel.GetPartyManager().DeleteParty(hashKey, packet.PartyId, out preParty);
UpdatePartyPacket notify = new UpdatePartyPacket
{
PartyId = preParty!.PartyId,
Type = PartyUpdateType.DELETE,
LeaderId = preParty.LeaderId,
};
BroadcastToChannel(preChannelId,
PacketSerializer.Serialize<UpdatePartyPacket>((ushort)PacketCode.UPDATE_PARTY, notify)); // 채널 전체 파티 목록 갱신
// 새로운 채널에 파티원 넣기
foreach (int memberId in newParty.PartyMemberIds)
{
sessions.TryGetValue(memberId, out NetPeer? memberPeer);
if (memberPeer != null)
{
// 새 채널에 유저 추가
Player newPlayer = new Player
{
HashKey = memberId,
PlayerId = memberId,
Nickname = memberId.ToString()
};
cm.AddUser(packet.ChannelId, memberId, newPlayer, memberPeer);
// 접속된 모든 유저 정보 전달
SendIntoChannelPacket(memberPeer, memberId);
// 내 정보 전달
SendLoadGame(memberPeer, memberId);
}
}
// 새로운 채널에 파티를 추가한다.
newChannel.GetPartyManager().CreateParty(newParty.LeaderId, newParty.PartyName, out newParty, newParty.PartyMemberIds);
// 새 채널 기존 유저들에게 파티 생성 알림
UpdatePartyPacket createNotify = new UpdatePartyPacket
{
PartyId = newParty.PartyId,
Type = PartyUpdateType.CREATE,
LeaderId = newParty.LeaderId,
PartyName = newParty.PartyName,
};
BroadcastToChannel(packet.ChannelId, PacketSerializer.Serialize<UpdatePartyPacket>((ushort)PacketCode.UPDATE_PARTY, createNotify));
}
private void OnExitChannel(NetPeer peer, int hashKey, byte[] payload)
{
ExitChannelPacket packet = Serializer.Deserialize<ExitChannelPacket>(new ReadOnlyMemory<byte>(payload));