From a5eedb2fb2e117079116d219f40be2e678f4b731 Mon Sep 17 00:00:00 2001 From: tolelom <98kimsungmin@naver.com> Date: Tue, 17 Mar 2026 00:20:20 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=81=AC=EB=A1=9C=EC=8A=A4=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=EC=A0=9D=ED=8A=B8=20=ED=86=B5=EC=8B=A0=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tokens 타입 string? → Dictionary? (Go API JSON object 역직렬화 실패 수정) - 409 응답 핸들러 return false → return null (컴파일 에러 수정) - INTO_BOSS_RAID 파티원 각자에게 본인 토큰과 함께 전달 (기존: 파티장에게 N번 중복) - GetPlayer null 체크 추가 (NullReferenceException 방지) - BossId 하드코딩 1 → packet.RaidId 사용 - Player 클래스에 Experience/AttackPower 등 전투 스탯 필드 추가 - ToPlayerInfo에서 새 필드 매핑 추가 - OnIntoChannelParty Nickname을 Session.UserName에서 가져오도록 수정 Co-Authored-By: Claude Opus 4.6 (1M context) --- MMOTestServer/MMOserver/Api/BossRaidResult.cs | 2 +- MMOTestServer/MMOserver/Api/RestApi.cs | 13 ++++++-- MMOTestServer/MMOserver/Game/GameServer.cs | 32 +++++++++++++++---- MMOTestServer/MMOserver/Game/Player.cs | 32 +++++++++++++++++++ 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/MMOTestServer/MMOserver/Api/BossRaidResult.cs b/MMOTestServer/MMOserver/Api/BossRaidResult.cs index 4a9c629..24eeb53 100644 --- a/MMOTestServer/MMOserver/Api/BossRaidResult.cs +++ b/MMOTestServer/MMOserver/Api/BossRaidResult.cs @@ -9,5 +9,5 @@ public sealed class BossRaidResult public int BossId { get; init; } public List Players { get; init; } = new(); public string Status { get; init; } = string.Empty; - public string? Tokens { get; init; } + public Dictionary Tokens { get; init; } = new(); } diff --git a/MMOTestServer/MMOserver/Api/RestApi.cs b/MMOTestServer/MMOserver/Api/RestApi.cs index 7c418ec..017fce9 100644 --- a/MMOTestServer/MMOserver/Api/RestApi.cs +++ b/MMOTestServer/MMOserver/Api/RestApi.cs @@ -88,13 +88,20 @@ public class RestApi : Singleton return null; } - // 400: 입장 조건 미충족 (레벨 부족, 이미 진행중 등) + // 400: 입장 조건 미충족 (레벨 부족 등) if (response.StatusCode == HttpStatusCode.BadRequest) { Log.Warning("[RestApi] 보스 레이드 입장 거절 (400) BossId={BossId}", bossId); return null; } + // 409: 이미 진행 중이거나 슬롯 충돌 + if (response.StatusCode == HttpStatusCode.Conflict) + { + Log.Warning("[RestApi] 보스 레이드 충돌 (409) BossId={BossId} - 이미 진행 중이거나 슬롯 없음", bossId); + return null; + } + response.EnsureSuccessStatusCode(); BossRaidAccessResponse? raw = await response.Content.ReadFromJsonAsync(); @@ -111,7 +118,7 @@ public class RestApi : Singleton BossId = raw.BossId, Players = raw.Players, Status = raw.Status ?? string.Empty, - Tokens = raw.Tokens + Tokens = raw.Tokens ?? new() }; } catch (Exception ex) when (attempt < MAX_RETRY) @@ -166,7 +173,7 @@ public class RestApi : Singleton } [JsonPropertyName("tokens")] - public string? Tokens + public Dictionary? Tokens { get; set; diff --git a/MMOTestServer/MMOserver/Game/GameServer.cs b/MMOTestServer/MMOserver/Game/GameServer.cs index 4318702..f147541 100644 --- a/MMOTestServer/MMOserver/Game/GameServer.cs +++ b/MMOTestServer/MMOserver/Game/GameServer.cs @@ -406,7 +406,12 @@ public class GameServer : ServerBase Mp = player.Mp, MaxMp = player.MaxMp, Position = new Position { X = player.PosX, Y = player.PosY, Z = player.PosZ }, - RotY = player.RotY + RotY = player.RotY, + Experience = player.Experience, + NextExp = player.NextExp, + AttackPower = player.AttackPower, + AttackRange = player.AttackRange, + SprintMultiplier = player.SprintMultiplier }; } @@ -574,12 +579,17 @@ public class GameServer : ServerBase if (memberPeer != null) { + // 세션에서 username 조회 + string nickname = memberPeer.Tag is Session s && !string.IsNullOrEmpty(s.UserName) + ? s.UserName + : memberId.ToString(); + // 새 채널에 유저 추가 Player newPlayer = new() { HashKey = memberId, PlayerId = memberId, - Nickname = memberId.ToString() + Nickname = nickname }; cm.AddUser(packet.ChannelId, memberId, newPlayer, memberPeer); @@ -1073,10 +1083,16 @@ public class GameServer : ServerBase List userNames = new List(); foreach (int memberId in party.PartyMemberIds) { - userNames.Add(channel.GetPlayer(memberId).Nickname); + Player? member = channel.GetPlayer(memberId); + if (member == null) + { + continue; + } + + userNames.Add(member.Nickname); } - BossRaidResult? result = await RestApi.Instance.BossRaidAccesssAsync(userNames, 1); + BossRaidResult? result = await RestApi.Instance.BossRaidAccesssAsync(userNames, packet.RaidId); // 입장 실패 if (result == null || result.BossId <= 0) @@ -1143,11 +1159,13 @@ public class GameServer : ServerBase SendTo(memberPeer, PacketSerializer.Serialize((ushort)PacketCode.CHANGE_MAP, response)); - // 모두에게 레이드로 이동 (할당된 실제 레이드 맵 ID 전달) - SendTo(peer, + // 각 파티원에게 레이드 입장 정보 전달 (본인의 토큰 포함) + string? memberToken = null; + result.Tokens?.TryGetValue(memberPlayer.Nickname, out memberToken); + SendTo(memberPeer, PacketSerializer.Serialize((ushort)PacketCode.INTO_BOSS_RAID, new IntoBossRaidPacket - { RaidId = assignedRaidMapId, IsSuccess = true, Session = result.SessionName, Token = result.Tokens })); + { RaidId = assignedRaidMapId, IsSuccess = true, Session = result.SessionName, Token = memberToken })); } Log.Debug("[GameServer] INTO_BOSS_RAID HashKey={Key} PartyId={PartyId} AssignedRaidMapId={RaidId}", hashKey, party.PartyId, diff --git a/MMOTestServer/MMOserver/Game/Player.cs b/MMOTestServer/MMOserver/Game/Player.cs index 6f82814..020aa74 100644 --- a/MMOTestServer/MMOserver/Game/Player.cs +++ b/MMOTestServer/MMOserver/Game/Player.cs @@ -75,6 +75,38 @@ public class Player set; } + // 경험치 + public int Experience + { + get; + set; + } + + public int NextExp + { + get; + set; + } + + // 전투 스탯 + public float AttackPower + { + get; + set; + } + + public float AttackRange + { + get; + set; + } + + public float SprintMultiplier + { + get; + set; + } + // 현재 위치한 맵 ID public int CurrentMapId {