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 OnChat(NetPeer peer, int hashKey, byte[] payload) { ChatPacket req = Serializer.Deserialize(new ReadOnlyMemory(payload)); ChannelManager cm = ChannelManager.Instance; int channelId = cm.HasUser(hashKey); if (channelId < 0) { return; } Player? sender = cm.GetChannel(channelId).GetPlayer(hashKey); if (sender == null) { return; } // 서버에서 발신자 정보 채워줌 (클라 위조 방지) ChatPacket res = new() { Type = req.Type, SenderId = sender.PlayerId, SenderNickname = sender.Nickname, TargetId = req.TargetId, Message = req.Message }; byte[] data = PacketSerializer.Serialize((ushort)PacketCode.CHAT, res); switch (req.Type) { case ChatType.GLOBAL: // 채널 내 모든 유저 (자신 포함) BroadcastToChannel(channelId, data); Log.Debug("[Chat] GLOBAL HashKey={Key} Message={Msg}", hashKey, req.Message); break; case ChatType.PARTY: // 파티 멤버에게만 (자신 포함) PartyManager pm = cm.GetChannel(channelId).GetPartyManager(); PartyInfo? party = pm.GetPartyByPlayer(hashKey); if (party == null) { Log.Warning("[Chat] PARTY 파티 없음 HashKey={Key}", hashKey); return; } BroadcastToUsers(party.PartyMemberIds, data); Log.Debug("[Chat] PARTY HashKey={Key} PartyId={PartyId} Message={Msg}", hashKey, party.PartyId, req.Message); break; case ChatType.WHISPER: // 대상 + 발신자에게만 if (sessions.TryGetValue(req.TargetId, out NetPeer? targetPeer)) { SendTo(targetPeer, data); } else { Log.Warning("[Chat] WHISPER 대상 없음 HashKey={Key} TargetId={TargetId}", hashKey, req.TargetId); } // 자신에게도 전송 (귓말 확인용) SendTo(peer, data); Log.Debug("[Chat] WHISPER HashKey={Key} TargetId={TargetId} Message={Msg}", hashKey, req.TargetId, req.Message); break; } } }