feat : 파티 구조 뼈대 완성
This commit is contained in:
@@ -2,6 +2,7 @@ using LiteNetLib;
|
||||
using LiteNetLib.Utils;
|
||||
using MMOserver.Api;
|
||||
using MMOserver.Game.Channel;
|
||||
using MMOserver.Game.Party;
|
||||
using MMOserver.Packet;
|
||||
using MMOserver.Utils;
|
||||
using ProtoBuf;
|
||||
@@ -25,6 +26,7 @@ public class GameServer : ServerBase
|
||||
[(ushort)PacketCode.TRANSFORM_PLAYER] = OnTransformPlayer,
|
||||
[(ushort)PacketCode.ACTION_PLAYER] = OnActionPlayer,
|
||||
[(ushort)PacketCode.STATE_PLAYER] = OnStatePlayer,
|
||||
[(ushort)PacketCode.REQUEST_PARTY] = OnRequestParty,
|
||||
};
|
||||
userUuidGenerator = new UuidGenerator();
|
||||
}
|
||||
@@ -462,4 +464,99 @@ public class GameServer : ServerBase
|
||||
byte[] data = PacketSerializer.Serialize<StatePlayerPacket>((ushort)PacketCode.STATE_PLAYER, packet);
|
||||
BroadcastToChannel(channelId, data, peer);
|
||||
}
|
||||
|
||||
private void OnRequestParty(NetPeer peer, int hashKey, byte[] payload)
|
||||
{
|
||||
RequestPartyPacket req = Serializer.Deserialize<RequestPartyPacket>(new ReadOnlyMemory<byte>(payload));
|
||||
PartyManager pm = PartyManager.Instance;
|
||||
|
||||
switch (req.Type)
|
||||
{
|
||||
case PartyUpdateType.CREATE:
|
||||
{
|
||||
if (!pm.CreateParty(hashKey, req.PartyName, out PartyInfo? party))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatePartyPacket notify = new UpdatePartyPacket
|
||||
{
|
||||
PartyId = party!.PartyId,
|
||||
Type = PartyUpdateType.CREATE,
|
||||
LeaderId = party.LeaderId,
|
||||
PlayerId = hashKey,
|
||||
PartyName = party.PartyName,
|
||||
};
|
||||
byte[] data = PacketSerializer.Serialize<UpdatePartyPacket>((ushort)PacketCode.UPDATE_PARTY, notify);
|
||||
SendTo(peer, data);
|
||||
break;
|
||||
}
|
||||
case PartyUpdateType.JOIN:
|
||||
{
|
||||
if (!pm.JoinParty(hashKey, req.PartyId, out PartyInfo? party))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatePartyPacket notify = new UpdatePartyPacket
|
||||
{
|
||||
PartyId = party!.PartyId,
|
||||
Type = PartyUpdateType.JOIN,
|
||||
LeaderId = party.LeaderId,
|
||||
PlayerId = hashKey,
|
||||
};
|
||||
byte[] data = PacketSerializer.Serialize<UpdatePartyPacket>((ushort)PacketCode.UPDATE_PARTY, notify);
|
||||
BroadcastToUsers(party.PartyMemberIds, data); // 새 멤버 포함 전원
|
||||
break;
|
||||
}
|
||||
case PartyUpdateType.LEAVE:
|
||||
{
|
||||
if (!pm.LeaveParty(hashKey, out PartyInfo? party))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatePartyPacket notify = new UpdatePartyPacket
|
||||
{
|
||||
PartyId = req.PartyId,
|
||||
Type = PartyUpdateType.LEAVE,
|
||||
LeaderId = party?.LeaderId ?? 0,
|
||||
PlayerId = hashKey,
|
||||
};
|
||||
byte[] data = PacketSerializer.Serialize<UpdatePartyPacket>((ushort)PacketCode.UPDATE_PARTY, notify);
|
||||
if (party != null)
|
||||
BroadcastToUsers(party.PartyMemberIds, data); // 남은 멤버들에게
|
||||
SendTo(peer, data); // 탈퇴자 본인에게
|
||||
break;
|
||||
}
|
||||
case PartyUpdateType.DELETE:
|
||||
{
|
||||
if (!pm.DeleteParty(hashKey, req.PartyId, out PartyInfo? party))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UpdatePartyPacket notify = new UpdatePartyPacket
|
||||
{
|
||||
PartyId = party!.PartyId,
|
||||
Type = PartyUpdateType.DELETE,
|
||||
LeaderId = party.LeaderId,
|
||||
};
|
||||
byte[] data = PacketSerializer.Serialize<UpdatePartyPacket>((ushort)PacketCode.UPDATE_PARTY, notify);
|
||||
BroadcastToUsers(party.PartyMemberIds, data); // 전원 (리더 포함)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void BroadcastToUsers(IEnumerable<int> userIds, byte[] data, DeliveryMethod method = DeliveryMethod.ReliableOrdered)
|
||||
{
|
||||
foreach (int userId in userIds)
|
||||
{
|
||||
if (sessions.TryGetValue(userId, out NetPeer? targetPeer))
|
||||
{
|
||||
SendTo(targetPeer, data, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
MMOTestServer/MMOserver/Game/Party/Party.cs
Normal file
35
MMOTestServer/MMOserver/Game/Party/Party.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace MMOserver.Game.Party;
|
||||
|
||||
public class PartyInfo
|
||||
{
|
||||
public static readonly int partyMemberMax = 3;
|
||||
|
||||
public int PartyId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int LeaderId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public List<int> PartyMemberIds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = new List<int>();
|
||||
|
||||
public string PartyName
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = "";
|
||||
|
||||
public int GetPartyMemberCount()
|
||||
{
|
||||
return PartyMemberIds.Count;
|
||||
}
|
||||
}
|
||||
152
MMOTestServer/MMOserver/Game/Party/PartyManager.cs
Normal file
152
MMOTestServer/MMOserver/Game/Party/PartyManager.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using MMOserver.Utils;
|
||||
|
||||
namespace MMOserver.Game.Party;
|
||||
|
||||
public class PartyManager : Singleton<PartyManager>
|
||||
{
|
||||
private readonly UuidGenerator partyUuidGenerator = new UuidGenerator();
|
||||
|
||||
// partyId → PartyInfo
|
||||
private readonly Dictionary<int, PartyInfo> parties = new();
|
||||
|
||||
// playerId → partyId (한 플레이어는 하나의 파티만)
|
||||
private readonly Dictionary<int, int> playerPartyMap = new();
|
||||
|
||||
// 파티 생성
|
||||
public bool CreateParty(int leaderId, string partyName, out PartyInfo? party)
|
||||
{
|
||||
party = null;
|
||||
|
||||
if (playerPartyMap.ContainsKey(leaderId))
|
||||
{
|
||||
return false; // 이미 파티에 속해있음
|
||||
}
|
||||
|
||||
int partyId = partyUuidGenerator.Create();
|
||||
party = new PartyInfo
|
||||
{
|
||||
PartyId = partyId,
|
||||
LeaderId = leaderId,
|
||||
PartyName = partyName,
|
||||
};
|
||||
party.PartyMemberIds.Add(leaderId);
|
||||
|
||||
parties[partyId] = party;
|
||||
playerPartyMap[leaderId] = partyId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 파티 참가
|
||||
public bool JoinParty(int playerId, int partyId, out PartyInfo? party)
|
||||
{
|
||||
party = null;
|
||||
|
||||
if (playerPartyMap.ContainsKey(playerId))
|
||||
{
|
||||
return false; // 이미 파티에 속해있음
|
||||
}
|
||||
|
||||
if (!parties.TryGetValue(partyId, out party))
|
||||
{
|
||||
return false; // 파티 없음
|
||||
}
|
||||
|
||||
if (party.GetPartyMemberCount() >= PartyInfo.partyMemberMax)
|
||||
{
|
||||
party = null;
|
||||
return false; // 파티 인원 초과
|
||||
}
|
||||
|
||||
party.PartyMemberIds.Add(playerId);
|
||||
playerPartyMap[playerId] = partyId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 파티 탈퇴
|
||||
public bool LeaveParty(int playerId, out PartyInfo? party)
|
||||
{
|
||||
party = null;
|
||||
|
||||
if (!playerPartyMap.TryGetValue(playerId, out int partyId))
|
||||
{
|
||||
return false; // 파티에 속해있지 않음
|
||||
}
|
||||
|
||||
if (!parties.TryGetValue(partyId, out party))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
party.PartyMemberIds.Remove(playerId);
|
||||
playerPartyMap.Remove(playerId);
|
||||
|
||||
// 마지막 멤버가 나가면 파티 해산
|
||||
if (party.PartyMemberIds.Count == 0)
|
||||
{
|
||||
DeletePartyInternal(partyId, party);
|
||||
party = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 리더가 나갔으면 남은 멤버 중 첫 번째를 리더로 승계
|
||||
if (party.LeaderId == playerId)
|
||||
{
|
||||
party.LeaderId = party.PartyMemberIds[0];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 파티 해산 (리더만)
|
||||
public bool DeleteParty(int leaderId, int partyId, out PartyInfo? party)
|
||||
{
|
||||
party = null;
|
||||
|
||||
if (!parties.TryGetValue(partyId, out party))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (party.LeaderId != leaderId)
|
||||
{
|
||||
party = null;
|
||||
return false; // 리더만 해산 가능
|
||||
}
|
||||
|
||||
DeletePartyInternal(partyId, party);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 조회
|
||||
public PartyInfo? GetParty(int partyId)
|
||||
{
|
||||
parties.TryGetValue(partyId, out PartyInfo? party);
|
||||
return party;
|
||||
}
|
||||
|
||||
public PartyInfo? GetPartyByPlayer(int playerId)
|
||||
{
|
||||
if (!playerPartyMap.TryGetValue(playerId, out int partyId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
parties.TryGetValue(partyId, out PartyInfo? party);
|
||||
return party;
|
||||
}
|
||||
|
||||
// 삭제
|
||||
private void DeletePartyInternal(int partyId, PartyInfo party)
|
||||
{
|
||||
// 남아 있는인원도 제거
|
||||
foreach (int memberId in party.PartyMemberIds)
|
||||
{
|
||||
playerPartyMap.Remove(memberId);
|
||||
}
|
||||
|
||||
parties.Remove(partyId);
|
||||
partyUuidGenerator.Release(partyId);
|
||||
}
|
||||
}
|
||||
@@ -540,7 +540,7 @@ public class RequestPartyPacket
|
||||
}
|
||||
|
||||
[ProtoMember(2)]
|
||||
public long PartyId
|
||||
public int PartyId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
@@ -559,7 +559,7 @@ public class RequestPartyPacket
|
||||
public class UpdatePartyPacket
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public long PartyId
|
||||
public int PartyId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
|
||||
Reference in New Issue
Block a user