Files
a301_mmo_game_server/MMOTestServer/MMOserver/Game/Party/PartyManager.cs
tolelom 7f2cd281da fix: MMO 서버 로직 버그 6건 수정
1. PlayerId 스푸핑 방지: OnTransformPlayer, OnActionPlayer, OnStatePlayer에서
   브로드캐스트 전 packet.PlayerId = hashKey로 강제 교체

2. HP/MP 클라이언트 조작 방지: OnStatePlayer에서 범위 클램핑
   (0 ≤ Hp ≤ MaxHp, 0 ≤ Mp ≤ MaxMp)

3. CreateParty 파티원 등록 누락 수정:
   - memberIds 파라미터 사용 시 모든 멤버를 playerPartyMap에 등록
   - 리더 중복 추가 방지 (Contains 체크)

4. OnIntoChannel 채널 만석 유령 상태 방지:
   이전 채널 제거 후 새 채널 입장 실패 시 이전 채널로 복귀

5. HandleAuth async 경합 방지:
   authenticatingTokens HashSet으로 동일 토큰 동시 인증 차단

6. 레이드 맵 미반환 수정:
   TryReleaseRaidMap 헬퍼 추가, OnChangeMap/OnSessionDisconnected에서
   레이드 맵(1001+) 유저 0명 시 인스턴스 맵 해제

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 00:34:40 +09:00

197 lines
4.8 KiB
C#

using MMOserver.Utils;
namespace MMOserver.Game.Party;
public class 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, List<int>? memeberIds = null)
{
if (playerPartyMap.ContainsKey(leaderId))
{
party = null;
return false; // 이미 파티에 속해있음
}
int partyId = partyUuidGenerator.Create();
if (memeberIds == null)
{
memeberIds = new List<int>();
}
// 리더 중복 방지: 기존 멤버 목록에 리더가 없을 때만 추가
if (!memeberIds.Contains(leaderId))
{
memeberIds.Add(leaderId);
}
party = new PartyInfo
{
PartyId = partyId,
LeaderId = leaderId,
PartyName = partyName,
PartyMemberIds = memeberIds
};
parties[partyId] = party;
// 모든 멤버를 playerPartyMap에 등록
foreach (int memberId in memeberIds)
{
playerPartyMap[memberId] = 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);
// id가 필요하다 그래서 참조해 둔다.
// 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 bool UpdateParty(int leaderId, int partyId, string newPartyName, out PartyInfo? party)
{
party = null;
if (!parties.TryGetValue(partyId, out party))
{
return false;
}
if (party.LeaderId != leaderId)
{
party = null;
return false; // 리더만 업데이트 가능
}
// 파티 이름 변경
party.PartyName = newPartyName;
return true;
}
// 전체 파티 목록 조회
public IEnumerable<PartyInfo> GetAllParties()
{
return parties.Values;
}
// 조회
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);
}
}