From f75d71c1ee0f740cd335ce4114df2110b40be766 Mon Sep 17 00:00:00 2001 From: qornwh1 Date: Tue, 3 Mar 2026 17:43:07 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20=EC=B1=84=EB=84=90=20=EB=A7=A4?= =?UTF-8?q?=EB=8B=88=EC=A0=80(=EA=B0=81=20=EC=B1=84=EB=84=90,=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=20=EA=B4=80=EB=A6=AC)=20=EA=B5=AC=ED=98=84=20/=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=A0=95=EB=B3=B4=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?/=20=ED=8C=A8=ED=82=B7=20=EC=9D=B4=EB=8F=99=20=EC=B1=84?= =?UTF-8?q?=EB=84=90=20=EC=A0=91=EC=86=8D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MMOserver/Game/Channel/Channel.cs | 82 +++++ .../MMOserver/Game/Channel/ChannelManager.cs | 84 +++++ .../MMOserver/Game/Channel/Maps/Robby.cs | 17 + .../MMOserver/Game/Engine/Vector3.cs | 36 ++ MMOTestServer/MMOserver/Game/GameServer.cs | 280 ++++++++++++++- MMOTestServer/MMOserver/Game/Player.cs | 77 ++++ MMOTestServer/MMOserver/Packet/PacketBody.cs | 333 ++++++++---------- .../MMOserver/Packet/PacketHeader.cs | 71 ++-- MMOTestServer/ServerLib/Service/ServerBase.cs | 2 +- 9 files changed, 748 insertions(+), 234 deletions(-) create mode 100644 MMOTestServer/MMOserver/Game/Channel/Channel.cs create mode 100644 MMOTestServer/MMOserver/Game/Channel/ChannelManager.cs create mode 100644 MMOTestServer/MMOserver/Game/Channel/Maps/Robby.cs create mode 100644 MMOTestServer/MMOserver/Game/Engine/Vector3.cs create mode 100644 MMOTestServer/MMOserver/Game/Player.cs diff --git a/MMOTestServer/MMOserver/Game/Channel/Channel.cs b/MMOTestServer/MMOserver/Game/Channel/Channel.cs new file mode 100644 index 0000000..a41e85e --- /dev/null +++ b/MMOTestServer/MMOserver/Game/Channel/Channel.cs @@ -0,0 +1,82 @@ +using MMOserver.Game.Channel.Maps; + +namespace MMOserver.Game.Channel; + +public class Channel +{ + // 로비 + private Robby robby = new Robby(); + + // 채널 내 유저 상태 (hashKey → Player) + private Dictionary connectUsers = new Dictionary(); + + public int ChannelId + { + get; + private set; + } + + public int UserCount + { + get; + private set; + } + + public int UserCountMax + { + get; + private set; + } = 100; + + public Channel(int channelId) + { + ChannelId = channelId; + } + + public void AddUser(long userId, Player player) + { + connectUsers[userId] = player; + UserCount++; + } + + public void RemoveUser(long userId) + { + connectUsers.Remove(userId); + UserCount--; + } + + // 채널 내 모든 유저의 hashKey 반환 + public IEnumerable GetConnectUsers() + { + return connectUsers.Keys; + } + + // 채널 내 모든 Player 반환 + public IEnumerable GetPlayers() + { + return connectUsers.Values; + } + + // 특정 유저의 Player 반환 + public Player? GetPlayer(long userId) + { + connectUsers.TryGetValue(userId, out Player? player); + return player; + } + + public int HasUser(long userId) + { + if (connectUsers.ContainsKey(userId)) + { + return ChannelId; + } + + return -1; + } + + // 로비 가져옴 + public Robby GetRobby() + { + return robby; + } +} diff --git a/MMOTestServer/MMOserver/Game/Channel/ChannelManager.cs b/MMOTestServer/MMOserver/Game/Channel/ChannelManager.cs new file mode 100644 index 0000000..2545d03 --- /dev/null +++ b/MMOTestServer/MMOserver/Game/Channel/ChannelManager.cs @@ -0,0 +1,84 @@ +namespace MMOserver.Game.Channel; + +public class ChannelManager +{ + // 일단은 채널은 서버 켤때 고정으로간다 1개 + public static ChannelManager Instance + { + get; + } = new ChannelManager(); + + // 채널 관리 + private List channels = new List(); + + // 채널별 유저 관리 (유저 key, 채널 val) + private Dictionary connectUsers = new Dictionary(); + + public ChannelManager() + { + Initializer(); + } + + public void Initializer(int channelSize = 1) + { + for (int i = 0; i < channelSize; i++) + { + channels.Add(new Channel(i)); + } + } + + public Channel GetChannel(int channelId) + { + return channels[channelId]; + } + + public List GetChannels() + { + return channels; + } + + public void AddUser(int channelId, long userId, Player player) + { + // 유저 추가 + connectUsers[userId] = channelId; + // 채널에 유저 추가 + channels[channelId].AddUser(userId, player); + } + + public bool RemoveUser(long userId) + { + // 채널 있으면 + int channelId = connectUsers[userId]; + + // 날린다. + if (channelId >= 0) + { + channels[channelId].RemoveUser(userId); + connectUsers.Remove(userId); + return true; + } + + return false; + } + + public int HasUser(long userId) + { + int channelId = -1; + if (connectUsers.ContainsKey(userId)) + { + channelId = connectUsers[userId]; + } + + if (channelId != -1) + { + return channels[channelId].HasUser(userId); + } + + return channelId; + } + + public Dictionary GetConnectUsers() + { + return connectUsers; + } +} diff --git a/MMOTestServer/MMOserver/Game/Channel/Maps/Robby.cs b/MMOTestServer/MMOserver/Game/Channel/Maps/Robby.cs new file mode 100644 index 0000000..14985d8 --- /dev/null +++ b/MMOTestServer/MMOserver/Game/Channel/Maps/Robby.cs @@ -0,0 +1,17 @@ +using MMOserver.Game.Engine; + +namespace MMOserver.Game.Channel.Maps; + +public class Robby +{ + // 마을 시작 지점 넣어 둔다. + public static Vector3 StartPosition + { + get; + set; + } = new Vector3(0, 0, 0); + + public Robby() + { + } +} diff --git a/MMOTestServer/MMOserver/Game/Engine/Vector3.cs b/MMOTestServer/MMOserver/Game/Engine/Vector3.cs new file mode 100644 index 0000000..f702748 --- /dev/null +++ b/MMOTestServer/MMOserver/Game/Engine/Vector3.cs @@ -0,0 +1,36 @@ +namespace MMOserver.Game.Engine; + +public class Vector3 +{ + public int X + { + get; + set; + } + + public int Y + { + get; + set; + } + + public int Z + { + get; + set; + } + + public Vector3() + { + X = 0; + Y = 0; + Z = 0; + } + + public Vector3(int x, int y, int z) + { + X = x; + Y = y; // 수직 사실상 안쓰겠다. + Z = z; + } +} diff --git a/MMOTestServer/MMOserver/Game/GameServer.cs b/MMOTestServer/MMOserver/Game/GameServer.cs index aa611d1..6ce238f 100644 --- a/MMOTestServer/MMOserver/Game/GameServer.cs +++ b/MMOTestServer/MMOserver/Game/GameServer.cs @@ -1,28 +1,300 @@ -using LiteNetLib; +using LiteNetLib; +using MMOserver.Game.Channel; +using MMOserver.Packet; +using ProtoBuf; using Serilog; +using ServerLib.Packet; using ServerLib.Service; namespace MMOserver.Game; public class GameServer : ServerBase { + private readonly Dictionary> _packetHandlers; + public GameServer(int port, string connectionString) : base(port, connectionString) { - + _packetHandlers = new Dictionary> + { + [(ushort)PacketCode.INTO_CHANNEL] = OnIntoChannel, + [(ushort)PacketCode.EXIT_CHANNEL] = OnExitChannel, + [(ushort)PacketCode.TRANSFORM_PLAYER] = OnTransformPlayer, + [(ushort)PacketCode.ACTION_PLAYER] = OnActionPlayer, + [(ushort)PacketCode.STATE_PLAYER] = OnStatePlayer, + }; } protected override void OnSessionConnected(NetPeer peer, long hashKey) { Log.Information("[GameServer] 세션 연결 HashKey={Key} PeerId={Id}", hashKey, peer.Id); + + // 만약 wifi-lte 로 바꿔졌다 이때 이미 로비에 들어가 있다면 넘긴다. + ChannelManager cm = ChannelManager.Instance; + int channelId = cm.HasUser(hashKey); + + if (channelId >= 0) + { + // 재연결: 채널 유저 목록 전송 (채널 선택 스킵, 바로 마을로) + SendIntoChannelPacket(peer, hashKey); + } + else + { + // 모든 채널 정보 던진다 + SendLoadChannelPacket(peer, hashKey); + } } protected override void OnSessionDisconnected(NetPeer peer, long hashKey, DisconnectInfo info) { - Log.Information("[GameServer] 세션 해제 HashKey={Key} Reason={Reason}", hashKey, info.Reason); + ChannelManager cm = ChannelManager.Instance; + if (cm.RemoveUser(hashKey)) + { + Log.Information("[GameServer] 세션 해제 HashKey={Key} Reason={Reason}", hashKey, info.Reason); + } } protected override void HandlePacket(NetPeer peer, long hashKey, ushort type, byte[] payload) { - Log.Debug("[GameServer] 패킷 수신 HashKey={Key} Type={Type} Size={Size}", hashKey, type, payload.Length); + if (_packetHandlers.TryGetValue(type, out Action? handler)) + { + handler(peer, hashKey, payload); + } + else + { + Log.Warning("[GameServer] 알 수 없는 패킷 Type={Type}", type); + } + } + + // ============================================================ + // 보내는 패킷 + // ============================================================ + + private void SendLoadChannelPacket(NetPeer peer, long hashKey) + { + LoadChannelPacket loadChannelPacket = new LoadChannelPacket(); + foreach (Channel.Channel channel in ChannelManager.Instance.GetChannels()) + { + ChannelInfo info = new ChannelInfo(); + info.ChannelId = channel.ChannelId; + info.ChannelUserConut = channel.UserCount; + info.ChannelUserMax = channel.UserCountMax; + loadChannelPacket.Channels.Add(info); + } + + byte[] data = PacketSerializer.Serialize((ushort)PacketCode.LOAD_CHANNEL, loadChannelPacket); + SendTo(peer, data); + } + + // 나간 유저를 같은 채널 유저들에게 알림 (UPDATE_CHANNEL_USER IsAdd=false) + private void SendExitChannelPacket(NetPeer peer, long hashKey, int channelId, Player player) + { + UpdateChannelUserPacket packet = new UpdateChannelUserPacket + { + Players = ToPlayerInfo(player), + IsAdd = false + }; + byte[] data = PacketSerializer.Serialize((ushort)PacketCode.UPDATE_CHANNEL_USER, packet); + // 이미 채널에서 제거된 후라 나간 본인에게는 전송되지 않음 + BroadcastToChannel(channelId, data); + } + + // 채널 입장 시 패킷 전송 + // - 새 유저에게 : 기존 채널 유저 목록 (INTO_CHANNEL) + // - 기존 유저들에게 : 새 유저 입장 알림 (UPDATE_CHANNEL_USER IsAdd=true) + private void SendIntoChannelPacket(NetPeer peer, long hashKey) + { + ChannelManager cm = ChannelManager.Instance; + int channelId = cm.HasUser(hashKey); + if (channelId < 0) + { + return; + } + + Channel.Channel channel = cm.GetChannel(channelId); + Player? myPlayer = channel.GetPlayer(hashKey); + + // 1. 새 유저에게: 자신을 제외한 기존 채널 유저 목록 전송 + IntoChannelPacket response = new IntoChannelPacket { ChannelId = channelId }; + foreach (long userId in channel.GetConnectUsers()) + { + if (userId == hashKey) + { + continue; + } + + Player? p = channel.GetPlayer(userId); + if (p != null) + { + response.Players.Add(ToPlayerInfo(p)); + } + } + + byte[] toNewUser = PacketSerializer.Serialize((ushort)PacketCode.INTO_CHANNEL, response); + SendTo(peer, toNewUser); + + // 2. 기존 유저들에게: 새 유저 입장 알림 + if (myPlayer != null) + { + UpdateChannelUserPacket notify = new UpdateChannelUserPacket + { + Players = ToPlayerInfo(myPlayer), + IsAdd = true + }; + byte[] toOthers = PacketSerializer.Serialize((ushort)PacketCode.UPDATE_CHANNEL_USER, notify); + BroadcastToChannel(channelId, toOthers, peer); + } + } + + // ============================================================ + // 채널 브로드캐스트 헬퍼 + // ============================================================ + + // 특정 채널의 모든 유저에게 전송 (exclude 지정 시 해당 피어 제외) + private void BroadcastToChannel(int channelId, byte[] data, NetPeer? exclude = null) + { + Channel.Channel channel = ChannelManager.Instance.GetChannel(channelId); + foreach (long userId in channel.GetConnectUsers()) + { + if (!sessions.TryGetValue(userId, out NetPeer? targetPeer)) + { + continue; + } + + if (exclude != null && targetPeer.Id == exclude.Id) + { + continue; + } + + SendTo(targetPeer, data); + } + } + + // ============================================================ + // Player ↔ PlayerInfo 변환 (패킷 전송 시에만 사용) + // ============================================================ + + private static PlayerInfo ToPlayerInfo(Player player) => new PlayerInfo + { + PlayerId = player.PlayerId, + Nickname = player.Nickname, + Level = player.Level, + Hp = player.Hp, + MaxHp = player.MaxHp, + Mp = player.Mp, + MaxMp = player.MaxMp, + Position = new MMOserver.Packet.Vector3 { X = player.PosX, Y = player.PosY, Z = player.PosZ }, + RotY = player.RotY, + }; + + // ============================================================ + // 패킷 핸들러 + // ============================================================ + + private void OnIntoChannel(NetPeer peer, long hashKey, byte[] payload) + { + IntoChannelPacket packet = Serializer.Deserialize(new ReadOnlyMemory(payload)); + + ChannelManager cm = ChannelManager.Instance; + + // TODO: 실제 서비스에서는 DB/세션에서 플레이어 정보 로드 필요 + Player newPlayer = new Player + { + HashKey = hashKey, + PlayerId = (int)(hashKey & 0x7FFFFFFF), + }; + + cm.AddUser(packet.ChannelId, hashKey, newPlayer); + Log.Debug("[GameServer] INTO_CHANNEL HashKey={Key} ChannelId={ChannelId}", hashKey, packet.ChannelId); + + // 접속된 모든 유저 정보 전달 + SendIntoChannelPacket(peer, hashKey); + } + + private void OnExitChannel(NetPeer peer, long hashKey, byte[] payload) + { + ExitChannelPacket packet = Serializer.Deserialize(new ReadOnlyMemory(payload)); + + ChannelManager cm = ChannelManager.Instance; + + // 제거 전에 채널/플레이어 정보 저장 (브로드캐스트에 필요) + int channelId = cm.HasUser(hashKey); + Player? player = channelId >= 0 ? cm.GetChannel(channelId).GetPlayer(hashKey) : null; + + cm.RemoveUser(hashKey); + Log.Debug("[GameServer] EXIT_CHANNEL HashKey={Key} PlayerId={PlayerId}", hashKey, packet.PlayerId); + + // 같은 채널 유저들에게 나갔다고 알림 + if (channelId >= 0 && player != null) + { + SendExitChannelPacket(peer, hashKey, channelId, player); + } + } + + private void OnTransformPlayer(NetPeer peer, long hashKey, byte[] payload) + { + TransformPlayerPacket packet = Serializer.Deserialize(new ReadOnlyMemory(payload)); + + ChannelManager cm = ChannelManager.Instance; + int channelId = cm.HasUser(hashKey); + if (channelId < 0) + { + return; + } + + // 채널 내 플레이어 위치/방향 상태 갱신 + Player? player = cm.GetChannel(channelId).GetPlayer(hashKey); + if (player != null) + { + player.PosX = packet.Position.X; + player.PosY = packet.Position.Y; + player.PosZ = packet.Position.Z; + player.RotY = packet.RotY; + } + + // 같은 채널 유저들에게 위치/방향 브로드캐스트 (나 제외) + byte[] data = PacketSerializer.Serialize((ushort)PacketCode.TRANSFORM_PLAYER, packet); + BroadcastToChannel(channelId, data, peer); + } + + private void OnActionPlayer(NetPeer peer, long hashKey, byte[] payload) + { + ActionPlayerPacket packet = Serializer.Deserialize(new ReadOnlyMemory(payload)); + + ChannelManager cm = ChannelManager.Instance; + int channelId = cm.HasUser(hashKey); + if (channelId < 0) + { + return; + } + + // 같은 채널 유저들에게 행동 브로드캐스트 (나 제외) + byte[] data = PacketSerializer.Serialize((ushort)PacketCode.ACTION_PLAYER, packet); + BroadcastToChannel(channelId, data, peer); + } + + private void OnStatePlayer(NetPeer peer, long hashKey, byte[] payload) + { + StatePlayerPacket packet = Serializer.Deserialize(new ReadOnlyMemory(payload)); + + ChannelManager cm = ChannelManager.Instance; + int channelId = cm.HasUser(hashKey); + if (channelId < 0) + { + return; + } + + // 채널 내 플레이어 HP/MP 상태 갱신 + Player? player = cm.GetChannel(channelId).GetPlayer(hashKey); + if (player != null) + { + player.Hp = packet.Hp; + player.MaxHp = packet.MaxHp; + player.Mp = packet.Mp; + player.MaxMp = packet.MaxMp; + } + + // 같은 채널 유저들에게 스테이트 브로드캐스트 (나 제외) + byte[] data = PacketSerializer.Serialize((ushort)PacketCode.STATE_PLAYER, packet); + BroadcastToChannel(channelId, data, peer); } } diff --git a/MMOTestServer/MMOserver/Game/Player.cs b/MMOTestServer/MMOserver/Game/Player.cs new file mode 100644 index 0000000..57a899f --- /dev/null +++ b/MMOTestServer/MMOserver/Game/Player.cs @@ -0,0 +1,77 @@ +namespace MMOserver.Game; + +public class Player +{ + public long HashKey + { + get; + set; + } + + public int PlayerId + { + get; + set; + } + + public string Nickname + { + get; + set; + } = string.Empty; + + public int Level + { + get; + set; + } + + public int Hp + { + get; + set; + } + + public int MaxHp + { + get; + set; + } + + public int Mp + { + get; + set; + } + + public int MaxMp + { + get; + set; + } + + // 위치/방향 (클라이언트 패킷과 동일하게 float) + public float PosX + { + get; + set; + } + + public float PosY + { + get; + set; + } + + public float PosZ + { + get; + set; + } + + public float RotY + { + get; + set; + } +} diff --git a/MMOTestServer/MMOserver/Packet/PacketBody.cs b/MMOTestServer/MMOserver/Packet/PacketBody.cs index 6cc4cac..5adc7ee 100644 --- a/MMOTestServer/MMOserver/Packet/PacketBody.cs +++ b/MMOTestServer/MMOserver/Packet/PacketBody.cs @@ -100,24 +100,6 @@ public class PlayerInfo } } -[ProtoContract] -public class ItemInfo -{ - [ProtoMember(1)] - public int ItemId - { - get; - set; - } - - [ProtoMember(2)] - public int Count - { - get; - set; - } -} - // ============================================================ // 인증 // ============================================================ @@ -134,7 +116,7 @@ public class RecvTokenPacket } } -// LOAD_GAME +// LOAD_GAME 내 정보 [ProtoContract] public class LoadGamePacket { @@ -151,27 +133,96 @@ public class LoadGamePacket get; set; } + + [ProtoMember(3)] + public int MaplId + { + get; + set; + } } // ============================================================ // 로비 // ============================================================ -// INTO_LOBBY [ProtoContract] -public class IntoLobbyPacket +public class ChannelInfo { [ProtoMember(1)] + public int ChannelId + { + get; + set; + } + + [ProtoMember(2)] + public int ChannelUserConut + { + get; + set; + } + + [ProtoMember(3)] + public int ChannelUserMax + { + get; + set; + } +} + +[ProtoContract] +public class LoadChannelPacket +{ + [ProtoMember(1)] + public List Channels + { + get; + set; + } = new List(); +} + +// INTO_CHANNEL 클라->서버: 입장할 채널 ID / 서버->클라: 채널 내 나 이외 플레이어 목록 +[ProtoContract] +public class IntoChannelPacket +{ + [ProtoMember(1)] + public int ChannelId + { + get; + set; + } // 클라->서버: 입장할 채널 ID + + [ProtoMember(2)] public List Players + { + get; + set; + } = new List(); // 서버->클라: 채널 내 플레이어 목록 +} + +// UPDATE_CHANNEL_USER 유저 접속/나감 +[ProtoContract] +public class UpdateChannelUserPacket +{ + [ProtoMember(1)] + public PlayerInfo Players + { + get; + set; + } + + [ProtoMember(2)] + public bool IsAdd { get; set; } } -// EXIT_LOBBY +// EXIT_CHANNEL 나가는 유저 [ProtoContract] -public class ExitLobbyPacket +public class ExitChannelPacket { [ProtoMember(1)] public int PlayerId @@ -181,174 +232,6 @@ public class ExitLobbyPacket } } -// ============================================================ -// 인스턴스 던전 -// ============================================================ - -public enum BossState -{ - START, - END, - PHASE_CHANGE -} - -public enum BossResult -{ - SUCCESS, - FAIL -} - -// INTO_INSTANCE -[ProtoContract] -public class IntoInstancePacket -{ - [ProtoMember(1)] - public int InstanceId - { - get; - set; - } - - [ProtoMember(2)] - public int BossId - { - get; - set; - } - - [ProtoMember(3)] - public List PlayerIds - { - get; - set; - } -} - -// UPDATE_BOSS -[ProtoContract] -public class UpdateBossPacket -{ - [ProtoMember(1)] - public BossState State - { - get; - set; - } - - [ProtoMember(2)] - public int Phase - { - get; - set; - } - - [ProtoMember(3)] - public BossResult Result - { - get; - set; - } // END일 때만 유효 -} - -// REWARD_INSTANCE -[ProtoContract] -public class RewardInstancePacket -{ - [ProtoMember(1)] - public int Exp - { - get; - set; - } - - [ProtoMember(2)] - public List Items - { - get; - set; - } -} - -// EXIT_INSTANCE -[ProtoContract] -public class ExitInstancePacket -{ - [ProtoMember(1)] - public int PlayerId - { - get; - set; - } -} - -// ============================================================ -// 파티 -// ============================================================ - -public enum PartyUpdateType -{ - CREATE, - DELETE -} - -public enum UserPartyUpdateType -{ - JOIN, - LEAVE -} - -// UPDATE_PARTY -[ProtoContract] -public class UpdatePartyPacket -{ - [ProtoMember(1)] - public int PartyId - { - get; - set; - } - - [ProtoMember(2)] - public PartyUpdateType Type - { - get; - set; - } - - [ProtoMember(3)] - public int LeaderId - { - get; - set; - } -} - -// UPDATE_USER_PARTY -[ProtoContract] -public class UpdateUserPartyPacket -{ - [ProtoMember(1)] - public int PartyId - { - get; - set; - } - - [ProtoMember(2)] - public int PlayerId - { - get; - set; - } - - [ProtoMember(3)] - public UserPartyUpdateType Type - { - get; - set; - } -} - // ============================================================ // 플레이어 // ============================================================ @@ -604,3 +487,71 @@ public class DamagePacket set; } } + +// ============================================================ +// 파티 +// ============================================================ + +public enum PartyUpdateType +{ + CREATE, + DELETE +} + +public enum UserPartyUpdateType +{ + JOIN, + LEAVE +} + +// UPDATE_PARTY +[ProtoContract] +public class UpdatePartyPacket +{ + [ProtoMember(1)] + public int PartyId + { + get; + set; + } + + [ProtoMember(2)] + public PartyUpdateType Type + { + get; + set; + } + + [ProtoMember(3)] + public int LeaderId + { + get; + set; + } +} + +// UPDATE_USER_PARTY +[ProtoContract] +public class UpdateUserPartyPacket +{ + [ProtoMember(1)] + public int PartyId + { + get; + set; + } + + [ProtoMember(2)] + public int PlayerId + { + get; + set; + } + + [ProtoMember(3)] + public UserPartyUpdateType Type + { + get; + set; + } +} diff --git a/MMOTestServer/MMOserver/Packet/PacketHeader.cs b/MMOTestServer/MMOserver/Packet/PacketHeader.cs index f0c927c..20905e9 100644 --- a/MMOTestServer/MMOserver/Packet/PacketHeader.cs +++ b/MMOTestServer/MMOserver/Packet/PacketHeader.cs @@ -1,61 +1,56 @@ namespace MMOserver.Packet; -public enum PacketCode : short +public enum PacketCode : ushort { - NONE, // 초기 클라이언트 시작시 jwt토큰 받아옴 RECV_TOKEN, - // jwt토큰 검증후 게임에 들어갈지 말지 (내 데이터도 전송) + + // 내 정보 로드 (서버 -> 클라) LOAD_GAME, - // 마을(로비)진입시 모든 데이터 로드 - INTO_LOBBY, + // 모든 채널 로드 - jwt토큰 검증후 게임에 들어갈지 말지 (내 데이터도 전송) + // (서버 -> 클라) + LOAD_CHANNEL, - // 로비 나가기 - EXIT_LOBBY, + // 나 채널 접속 (클라 -> 서버) + INTO_CHANNEL, - // 인스턴스 던전 입장 - INTO_INSTANCE, + // 새로운 유저 채널 접속 (서버 -> 클라) / 유저 채널 나감 (서버 -> 클라) + UPDATE_CHANNEL_USER, - // 결과 보상 - REWARD_INSTANCE, + // 채널 나가기 (클라 -> 서버) + EXIT_CHANNEL, - // 보스전 (시작, 종료) - UPDATE_BOSS, + // 플레이어 위치, 방향 (서버 -> 클라 \ 클라 -> 서버) + TRANSFORM_PLAYER, - // 인스턴스 던전 퇴장 - EXIT_INSTANCE, + // 플레이어 행동 업데이트 (서버 -> 클라 \ 클라 -> 서버) + ACTION_PLAYER, + + // 플레이어 스테이트 업데이트 (서버 -> 클라 \ 클라 -> 서버) + STATE_PLAYER, + + // NPC 위치, 방향 (서버 -> 클라) + TRANSFORM_NPC, + + // NPC 행동 업데이트 (서버 -> 클라) + ACTION_NPC, + + // NPC 스테이트 업데이트 (서버 -> 클라) + STATE_NPC, + + // 데미지 UI 전달 (서버 -> 클라) + DAMAGE, // 파티 (생성, 삭제) UPDATE_PARTY, // 파티 유저 업데이트(추가 삭제) - UPDATE_USER_PARTY, - - // 플레이어 위치, 방향 - TRANSFORM_PLAYER, - - // 플레이어 행동 업데이트 - ACTION_PLAYER, - - // 플레이어 스테이트 업데이트 - STATE_PLAYER, - - // NPC 위치, 방향 - TRANSFORM_NPC, - - // NPC 행동 업데이트 - ACTION_NPC, - - // NPC 스테이트 업데이트 - STATE_NPC, - - // 데미지 UI 전달 - DAMAGE + UPDATE_USER_PARTY } public class PacketHeader { public PacketCode Code; - public int BodyLength; + public ushort BodyLength; } diff --git a/MMOTestServer/ServerLib/Service/ServerBase.cs b/MMOTestServer/ServerLib/Service/ServerBase.cs index 08d7141..6c8b4de 100644 --- a/MMOTestServer/ServerLib/Service/ServerBase.cs +++ b/MMOTestServer/ServerLib/Service/ServerBase.cs @@ -34,7 +34,7 @@ public abstract class ServerBase : INetEventListener // 인증된 세션 (hashKey → NetPeer) 재연결 조회용 // peer → hashKey 역방향은 peer.Tag as Session 으로 대체 - private readonly Dictionary sessions = new(); + protected readonly Dictionary sessions = new(); // 재사용 NetDataWriter (단일 스레드 폴링이므로 안전) private readonly NetDataWriter cachedWriter = new();