using LiteNetLib; using MMOserver.Game.Channel; using MMOserver.Game.Party; using MMOserver.Packet; using ProtoBuf; using Serilog; using ServerLib.Packet; using ServerLib.Service; namespace MMOserver.Game.Service; /* * 파티 안뒤 채널 이동 메시지 핸들러 */ public partial class GameServer : ServerBase { private void OnIntoChannelParty(NetPeer peer, int hashKey, byte[] payload) { IntoChannelPartyPacket packet = Serializer.Deserialize(new ReadOnlyMemory(payload)); ChannelManager cm = ChannelManager.Instance; int preChannelId = cm.HasUser(hashKey); // 이전에 다른 채널에 있었는지 체크 / 파티이동은 이미 접속한 상태여야 한다. if (preChannelId < 0) { Log.Warning("[GameServer] INTO_CHANNEL_PARTY 채널에 접속하지 않은 유저"); return; } Channel.Channel preChannel = cm.GetChannel(preChannelId); Channel.Channel newChannel = cm.GetChannel(packet.ChannelId); PartyInfo? preParty = preChannel.GetPartyManager().GetParty(packet.PartyId); if (preParty == null) { Log.Warning("[GameServer] INTO_CHANNEL_PARTY 해당 파티 없음"); return; } // 새로운 파티를 복사한다 PartyInfo tempParty = new(); tempParty.DeepCopySemi(preParty); // 최대 인원 체크 if (newChannel.UserCount + preParty.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((ushort)PacketCode.INTO_CHANNEL, new IntoChannelPacket { ChannelId = -1 }); SendTo(peer, full); return; } // 기존 채널에서 제거 전에 플레이어 정보 보존 Dictionary savedPlayers = new(); foreach (int memberId in preParty.PartyMemberIds) { Player? player = preChannel.GetPlayer(memberId); if (player != null) { savedPlayers[memberId] = player; UpdateChannelUserPacket exitNotify = new() { Players = player.ToPlayerInfo(), IsAdd = false }; byte[] exitData = PacketSerializer.Serialize((ushort)PacketCode.UPDATE_CHANNEL_USER, exitNotify); BroadcastToChannel(preChannelId, exitData); // 이전 채널에서 제거 preChannel.RemoveUser(memberId); // 현재 존재하는 파티원만 추가한다. tempParty.PartyMemberIds.Add(memberId); } } // 이전채널에서 파티를 지운다. preChannel.GetPartyManager().DeleteParty(hashKey, packet.PartyId, out preParty); UpdatePartyPacket notify = new() { PartyId = preParty!.PartyId, Type = PartyUpdateType.DELETE, LeaderId = preParty.LeaderId }; // 채널 전체 파티 목록 갱신 BroadcastToChannel(preChannelId, PacketSerializer.Serialize((ushort)PacketCode.UPDATE_PARTY, notify)); // 새로운 채널에 파티원 넣기 foreach (int memberId in tempParty.PartyMemberIds) { sessions.TryGetValue(memberId, out NetPeer? memberPeer); if (memberPeer != null) { // 새 채널에 유저 추가 (보존된 플레이어 정보 사용) string nickname = savedPlayers.TryGetValue(memberId, out Player? saved) ? saved.Nickname : memberId.ToString(); Player newPlayer = new() { HashKey = memberId, PlayerId = memberId, Nickname = nickname }; cm.AddUser(packet.ChannelId, memberId, newPlayer, memberPeer); // 접속된 모든 유저 정보 전달 SendIntoChannelPacket(memberPeer, memberId); // 내 정보 전달 SendLoadGame(memberPeer, memberId); } } // 새로운 채널에 파티를 추가한다. if (newChannel.GetPartyManager() .CreateParty(tempParty.LeaderId, tempParty.PartyName, out PartyInfo? createdParty, tempParty.PartyMemberIds) && createdParty != null) { // 새 채널 기존 유저들에게 파티 생성 알림 UpdatePartyPacket createNotify = new() { PartyId = createdParty.PartyId, Type = PartyUpdateType.CREATE, LeaderId = createdParty.LeaderId, PartyName = createdParty.PartyName }; BroadcastToChannel(packet.ChannelId, PacketSerializer.Serialize((ushort)PacketCode.UPDATE_PARTY, createNotify)); } else { Log.Warning("[GameServer] 파티생성 실패 !!!"); } } }