feat : GameServer 패킷 메시지 단위 분할 / 플레이어 정보 변환 기능 변경
This commit is contained in:
159
MMOTestServer/MMOserver/Game/Service/IntoChannelHandle.cs
Normal file
159
MMOTestServer/MMOserver/Game/Service/IntoChannelHandle.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using LiteNetLib;
|
||||
using MMOserver.Api;
|
||||
using MMOserver.Game.Channel;
|
||||
using MMOserver.Game.Channel.Maps;
|
||||
using MMOserver.Packet;
|
||||
using ProtoBuf;
|
||||
using Serilog;
|
||||
using ServerLib.Packet;
|
||||
using ServerLib.Service;
|
||||
|
||||
namespace MMOserver.Game.Service;
|
||||
|
||||
/*
|
||||
* 채널 접속 요청 메시지 핸들러
|
||||
*/
|
||||
public partial class GameServer : ServerBase
|
||||
{
|
||||
private async void OnIntoChannel(NetPeer peer, int hashKey, byte[] payload)
|
||||
{
|
||||
try
|
||||
{
|
||||
IntoChannelPacket packet = Serializer.Deserialize<IntoChannelPacket>(new ReadOnlyMemory<byte>(payload));
|
||||
|
||||
ChannelManager cm = ChannelManager.Instance;
|
||||
|
||||
// 이전에 다른 채널에 있었는지 체크
|
||||
int preChannelId = cm.HasUser(hashKey);
|
||||
Player? prevPlayer = preChannelId >= 0 ? cm.GetChannel(preChannelId).GetPlayer(hashKey) : null;
|
||||
if (preChannelId >= 0)
|
||||
{
|
||||
Player? player = prevPlayer;
|
||||
|
||||
// 파티 자동 탈퇴
|
||||
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 (newChannel.UserCount >= newChannel.UserCountMax)
|
||||
{
|
||||
Log.Warning("[GameServer] INTO_CHANNEL 채널 인원 초과 HashKey={Key} ChannelId={ChannelId} UserCount={Count}/{Max}",
|
||||
hashKey, packet.ChannelId, newChannel.UserCount, newChannel.UserCountMax);
|
||||
|
||||
// 이전 채널에서 이미 제거된 경우 → 이전 채널로 복귀
|
||||
if (preChannelId >= 0 && prevPlayer != null)
|
||||
{
|
||||
cm.AddUser(preChannelId, hashKey, prevPlayer, peer);
|
||||
Log.Information("[GameServer] INTO_CHANNEL 만석 → 이전 채널({ChannelId})로 복귀 HashKey={Key}", preChannelId, hashKey);
|
||||
}
|
||||
|
||||
byte[] full = PacketSerializer.Serialize((ushort)PacketCode.INTO_CHANNEL,
|
||||
new IntoChannelPacket { ChannelId = -1 });
|
||||
SendTo(peer, full);
|
||||
return;
|
||||
}
|
||||
|
||||
// API 서버에서 플레이어 프로필 로드
|
||||
Player newPlayer = new Player
|
||||
{
|
||||
HashKey = hashKey,
|
||||
PlayerId = hashKey,
|
||||
Nickname = ((Session)peer.Tag).Username ?? ""
|
||||
};
|
||||
|
||||
Session? session = peer.Tag as Session;
|
||||
string? username = session?.Username;
|
||||
if (!string.IsNullOrEmpty(username))
|
||||
{
|
||||
try
|
||||
{
|
||||
RestApi.PlayerProfileResponse? profile = await RestApi.Instance.GetPlayerProfileAsync(username);
|
||||
if (profile != null)
|
||||
{
|
||||
newPlayer.Nickname = string.IsNullOrEmpty(profile.Nickname) ? username : profile.Nickname;
|
||||
newPlayer.Level = profile.Level;
|
||||
newPlayer.MaxHp = (int)profile.MaxHp;
|
||||
newPlayer.Hp = (int)profile.MaxHp;
|
||||
newPlayer.MaxMp = (int)profile.MaxMp;
|
||||
newPlayer.Mp = (int)profile.MaxMp;
|
||||
newPlayer.Experience = profile.Experience;
|
||||
newPlayer.NextExp = profile.NextExp;
|
||||
newPlayer.AttackPower = (float)profile.AttackPower;
|
||||
newPlayer.AttackRange = (float)profile.AttackRange;
|
||||
newPlayer.SprintMultiplier = (float)profile.SprintMultiplier;
|
||||
newPlayer.PosX = (float)profile.LastPosX;
|
||||
newPlayer.PosY = (float)profile.LastPosY;
|
||||
newPlayer.PosZ = (float)profile.LastPosZ;
|
||||
newPlayer.RotY = (float)profile.LastRotY;
|
||||
Log.Information("[GameServer] 프로필 로드 완료 Username={Username} Level={Level} MaxHp={MaxHp}",
|
||||
username, profile.Level, profile.MaxHp);
|
||||
}
|
||||
else
|
||||
{
|
||||
newPlayer.Nickname = username;
|
||||
Log.Warning("[GameServer] 프로필 로드 실패 — 기본값 사용 Username={Username}", username);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
newPlayer.Nickname = username;
|
||||
Log.Error(ex, "[GameServer] 프로필 로드 예외 Username={Username}", username);
|
||||
}
|
||||
}
|
||||
|
||||
// 채널 입장 시각 기록 (플레이타임 계산용)
|
||||
((Session)peer.Tag).ChannelJoinedAt = DateTime.UtcNow;
|
||||
|
||||
// 채널에 추가
|
||||
cm.AddUser(packet.ChannelId, hashKey, newPlayer, peer);
|
||||
Log.Debug("[GameServer] INTO_CHANNEL HashKey={Key} ChannelId={ChannelId}", hashKey, packet.ChannelId);
|
||||
|
||||
// 접속된 모든 유저 정보 전달
|
||||
SendIntoChannelPacket(peer, hashKey);
|
||||
|
||||
// 내 정보 전달
|
||||
SendLoadGame(peer, hashKey);
|
||||
|
||||
// 초기 맵(로비 1번) 진입 알림
|
||||
// Channel.AddUser → ChangeMap(1) 에서 이미 맵에 추가됨
|
||||
PlayerInfo playerInfo = newPlayer.ToPlayerInfo();
|
||||
int initMapId = newPlayer.CurrentMapId;
|
||||
|
||||
// 기존 맵 유저들에게 입장 알림 (본인 제외)
|
||||
ChangeMapPacket enterNotify = new() { MapId = initMapId, IsAdd = true, Player = playerInfo };
|
||||
BroadcastToMap(packet.ChannelId, initMapId, PacketSerializer.Serialize((ushort)PacketCode.CHANGE_MAP, enterNotify), peer);
|
||||
|
||||
// 본인에게 현재 맵의 플레이어 목록 전달
|
||||
ChangeMapPacket response = new() { MapId = initMapId };
|
||||
AMap? initMap = newChannel.GetMap(initMapId);
|
||||
if (initMap != null)
|
||||
{
|
||||
foreach (var (userId, channelPlayer) in initMap.GetUsers())
|
||||
{
|
||||
if (userId == hashKey)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
response.Players.Add(channelPlayer.ToPlayerInfo());
|
||||
}
|
||||
}
|
||||
|
||||
SendTo(peer, PacketSerializer.Serialize((ushort)PacketCode.CHANGE_MAP, response));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warning($"[GameServer] Error : {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user