using Google.Protobuf; using Google.Protobuf.WellKnownTypes; using Newtonsoft.Json; using ServerCore; using ServerBase; using ServerCommon; using ServerCommon.BusinessLogDomain; using MetaAssets; using USER_GUID = System.String; namespace GameServer; public class GlobalPartyDetailMemberAction : EntityActionBase { private readonly PartyMemberCacheRequest m_party_member_cache_request; public GlobalPartyDetailMemberAction(GlobalPartyDetail owner) : base(owner) { m_party_member_cache_request = new PartyMemberCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector()); } public override async Task onInit() { await Task.CompletedTask; var result = new Result(); return result; } public override void onClear() { } public async Task keep() { return await m_party_member_cache_request.keepPartyMemberCache(); } public PartyMemberInfo? getMember(USER_GUID user_guid) { var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); return party_member_attribute.getPartyMembers().GetValueOrDefault(user_guid); } public IEnumerable getMembers() { var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); return party_member_attribute.getPartyMembers().Select(member => member.Key).ToList(); } public bool isPartyMember(USER_GUID user_guid) { var attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); var member = attribute.getPartyMember(user_guid); return null != member; } public int getMemberCount() { var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); return party_member_attribute.getPartyMembers().Count; } public bool checkExistPartyMembers(USER_GUID except_member_user) { var attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); var player_manager = GameServerApp.getServerLogic().getPlayerManager(); foreach (var member in attribute.getPartyMembers()) { if (member.Key == except_member_user) continue; if (false == player_manager.tryGetUserByPrimaryKey(member.Key, out var player)) continue; return true; } return false; } public async Task loadPartyMember() { var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); var result = await m_party_member_cache_request.fetchPartyMemberCache(); if (result.isFail()) return result; result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_member_attribute, new List { m_party_member_cache_request.getPartyMemberCache()! }); if (result.isFail()) { Log.getLogger().error(result.toBasicString()); } return result; } public IEnumerable getMembers4PartyInfo() { var party = getOwner() as GlobalPartyDetail; NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!"); var party_member_attribute = party.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}"); var states = new List(); foreach (var member in party_member_attribute.getPartyMembers()) { var state = new PartyMemberState(); state.MemberGuid = member.Value.UserGuid; state.MemberNickname = member.Value.Nickname; state.MarkId = member.Value.MarkId; state.LocationInfo = member.Value.LocationInfo; states.Add(state); } return states; } public async Task<(Result result, bool? isAready)> addJoinMember(PartyMemberInfo user) { var change = await changeMember(user); if (change.result.isFail()) return (change.result, null); // 0. 데이터가 없으면, 기존 참가 인원으로 위치변경만 노티 if (null == change.info) { sendPartyMemberLocation(user); return (change.result, true); } var party = getOwner() as GlobalPartyDetail; ArgumentNullException.ThrowIfNull(party); // 1. 파티 참가 멤버 알림 ( to server ) var server_message = new ServerMessage { JoinPartyMemberNoti = new() { PartyGuid = party.PartyGuid, JoinPartyMemberInfo = JsonConvert.SerializeObject(change.info) } }; PartyHelper.BroadcastToServers(party, server_message, true); // 2. 파티 참가 멤버 알림 ( to client ) var client_message = new ClientToGame(); client_message.Message = new(); client_message.Message.JoinPartyMemberNoti = new(); client_message.Message.JoinPartyMemberNoti.JoinPartyMemberGuid = change.info.UserGuid; client_message.Message.JoinPartyMemberNoti.JoinMemberInfo = new PartyMemberState(); client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.MarkId = change.info.MarkId; client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.MemberGuid = change.info.UserGuid; client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.MemberNickname = change.info.Nickname; client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.LocationInfo = change.info.LocationInfo; PartyHelper.BroadcastToClients(party, client_message, new List { user.UserGuid }); return (change.result, false); } public async Task deletePartyMembers() { // 1. cache 제거 var result = await m_party_member_cache_request.deletePartyMemberCache(); if (result.isFail()) { Log.getLogger().error(result.toBasicString()); } // 2. attribute 수정 var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); party_member_attribute.onClear(); return result; } public async Task<(Result result, int party_member_count)> deleteJoinMember(USER_GUID delete_user_guid, bool is_upsert_cache) { var result = new Result(); var party = getOwner() as GlobalPartyDetail; NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!"); // 1. attribute 수정 var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}"); if (!party_member_attribute.deletePartyMember(delete_user_guid)) { var err_msg = $"Failed to delete party memeber !!! : {delete_user_guid}"; result.setFail(ServerErrorCode.NotPartyMember, err_msg); Log.getLogger().error(err_msg); return (result, party_member_attribute.getPartyMembers().Count); } // 2. cache 수정 var member_cache = m_party_member_cache_request.getPartyMemberCache(); NullReferenceCheckHelper.throwIfNull(member_cache, () => $"member cache is null !!! - user_guid:{delete_user_guid}"); member_cache.deleteJoinMember(delete_user_guid); if(is_upsert_cache) result = await m_party_member_cache_request.deleteJoinMember(delete_user_guid); return (result, party_member_attribute.getPartyMembers().Count); } public async Task changeMemberMaker(USER_GUID user_guid, int new_marker_id, bool is_cash_upsert) { var result = new Result(); string err_msg; var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); var exist_user = party_member_attribute.getPartyMember(user_guid); if (null == exist_user) { err_msg = $"Failed to get party member !!! : not party member - {user_guid}"; result.setFail(ServerErrorCode.NotPartyMember, err_msg); Log.getLogger().error(err_msg); return result; } // 1. cache 수정 var member_cache = m_party_member_cache_request.getPartyMemberCache(); NullReferenceCheckHelper.throwIfNull(member_cache, () => $"member cache is null !!! - userGuid:{user_guid}"); if (!member_cache.PartyMembers.TryGetValue(user_guid, out var member)) { err_msg = $"Failed to get party member !!! : not party member - {user_guid}"; result.setFail(ServerErrorCode.NotPartyMember, err_msg); Log.getLogger().error(err_msg); return result; } member.MarkId = new_marker_id; if (is_cash_upsert) { result = await m_party_member_cache_request.changeJoinMember(member); if (result.isFail()) return result; } // 2. attribute 수정 exist_user.MarkId = new_marker_id; return result; } public async Task<(Result result, PartyMemberInfo? info)> changeMember(PartyMemberInfo user) { var party_member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); var exist_user = party_member_attribute.getPartyMember(user.UserGuid); if (null != exist_user) { user.MarkId = exist_user.MarkId; user.JoinTime = exist_user.JoinTime; } // 1. cache 수정 var result = await m_party_member_cache_request.changeJoinMember(user); if (result.isFail()) return (result, null); // 2. attribute 데이터 수정 party_member_attribute.setPartyMember(user); // 3. exist_user 가 있으면, 기존 참가 유저 return null != exist_user ? (result, null) : (result, user); } public IEnumerable getSummonMembers() { var member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); return (from member in member_attribute.getPartyMembers() where member.Value.Summon.IsAlreadySummon select member.Key).ToList(); } public async Task<(Result result, Item? delete_item)> summonMemberAsync(USER_GUID summon_user_guid, SummonInfo summon) { var result = new Result(); string err_msg; var party = getOwner() as GlobalPartyDetail; NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !! "); var member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}"); // 1. summon user login_cache 조회 var server_logic = GameServerApp.getServerLogic(); var summon_user_login_cache_request = new LoginCacheOtherUserRequest(server_logic, server_logic.getRedisConnector(), summon_user_guid); result = await summon_user_login_cache_request.fetchLogin(); if (result.isFail()) return (result, null); var summon_user_login_cache = summon_user_login_cache_request.getLoginCache(); if (null == summon_user_login_cache) { err_msg = $"Failed to summon party member !!! : summon user not logged in - {summon_user_guid}"; result.setFail(ServerErrorCode.UserNotLogin, err_msg); Log.getLogger().error(err_msg); return (result, null); } var player_manager = server_logic.getPlayerManager(); // 2. 소환석 제거 var summon_result = await spentSummonItemAsync(player_manager, party); if (summon_result.result.isFail()) return (summon_result.result, null); // 3. summon 수정 var member = member_attribute.getPartyMember(summon_user_guid); NullReferenceCheckHelper.throwIfNull(member, () => $"party member is null !!! - userGuid:{summon_user_guid}"); member.Summon = summon; result = await m_party_member_cache_request.changeJoinMember(member); if (result.isFail()) { return (result, null); } // 4. 대상 에게 summon 전송 result = summon_user_login_cache.CurrentServer == server_logic.getServerName() ? sendSummonMessageToClient(player_manager, summon_user_guid) : sendSummonMessageToServer(party, player_manager, summon_user_guid, summon_user_login_cache.CurrentServer); if (result.isFail()) { return (result, null); } return (result, summon_result.delete_summon_item); } public async Task clearSummonMemberAsync(USER_GUID summon_user_guid, bool isNotify) { var result = new Result(); var party = getOwner() as GlobalPartyDetail; NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!!"); var member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}"); // 1. summon 수정 var member = member_attribute.getPartyMember(summon_user_guid); NullReferenceCheckHelper.throwIfNull(member, () => $"party member is null !!! - userGuid:{summon_user_guid}"); member.Summon = new(); result = await m_party_member_cache_request.changeJoinMember(member); if (result.isFail()) return result; // 2. 알림 처리 if (isNotify) { var message = new ServerMessage(); message.NtfClearPartySummon = new(); message.NtfClearPartySummon.PartyGuid = party.PartyGuid; message.NtfClearPartySummon.MemberUserGuid = summon_user_guid; PartyHelper.BroadcastToServers(party, message, true); } return result; } public async Task<(Result result, int cancelSummonCount)> cancelAllSummonAsync() { var result = new Result(); var owner = getOwner() as GlobalPartyDetail; NullReferenceCheckHelper.throwIfNull(owner, () => $"global party detail is null !!"); var member_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {owner.toBasicString()}"); var server_message = new ServerMessage { CancelSummonPartyMemberNoti = new ServerMessage.Types.CancelSummonPartyMemberNoti { PartyGuid = owner.PartyGuid } }; // 1. summon 수정 foreach (var member in member_attribute.getPartyMembers()) { if (!member.Value.Summon.IsAlreadySummon) continue; member.Value.Summon.clear(); server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Add(member.Key); result = await m_party_member_cache_request.changeJoinMember(member.Value); server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Add(member.Value.UserGuid); } // 2. notify 전송 if (server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Count > 0) { PartyHelper.BroadcastToServers(owner, server_message, false); } return (result, server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Count); } private Result sendSummonMessageToClient(PlayerManager player_manager, USER_GUID summon_user_guid) { var result = new Result(); // 1. summon user 조회 if (!player_manager.tryGetUserByPrimaryKey(summon_user_guid, out var summon_user)) { var err_msg = $"Failed to summon party member !!! : summon user not logged in - {summon_user_guid}"; result.setFail(ServerErrorCode.UserNotLogin, err_msg); Log.getLogger().error(err_msg); return result; } // 2. client 전송 var client_message = new ClientToGame(); client_message.Message = new ClientToGameMessage(); client_message.Message.SummonPartyMemberNoti = new ClientToGameMessage.Types.SummonPartyMemberNoti(); PartyHelper.sendToClient(client_message, summon_user.getHostId()); return result; } private Result sendSummonMessageToServer(GlobalPartyDetail party, PlayerManager player_manager, USER_GUID summon_user_guid, string target_server) { var result = new Result(); // 1. party leader 조회 var party_action = party.getEntityAction(); NullReferenceCheckHelper.throwIfNull(party_action, () => $"GlobalPartyDetailAction is null !! - {getOwner().toBasicString()}"); if (!player_manager.tryGetUserByPrimaryKey(party_action.getLeaderGuid(), out var leader)) { var err_msg = $"Failed to summon party member !!! : leader not logged in - {leader?.getUserGuid()}"; result.setFail(ServerErrorCode.UserNotLogin, err_msg); Log.getLogger().error(err_msg); return result; } // 2. leader 위치 조회 var leader_location = leader.getEntityAction()?.getCurrentPos(); if (null == leader_location) { var err_msg = $"Failed to summon party member !!! : leader not logged in - {leader.getUserGuid()}"; result.setFail(ServerErrorCode.UserNotLogin, err_msg); Log.getLogger().error(err_msg); return result; } // 3. server 전송 var server_message = new ServerMessage(); server_message.SummonPartyMemberNoti = new ServerMessage.Types.SummonPartyMemberNoti(); server_message.SummonPartyMemberNoti.SummonPartyGuid = party.PartyGuid; server_message.SummonPartyMemberNoti.SummonUserGuid = summon_user_guid; server_message.SummonPartyMemberNoti.SummonServerName = GameServerApp.getServerLogic().getServerName(); server_message.SummonPartyMemberNoti.SummonPos = leader_location; PartyHelper.sendToServer(server_message, target_server); return result; } private async Task<(Result result, Item? delete_summon_item)> spentSummonItemAsync(PlayerManager player_manager, GlobalPartyDetail party) { var result = new Result(); var party_action = party.getEntityAction(); NullReferenceCheckHelper.throwIfNull(party_action, () => $"GlobalPartyDetailAction is null !! - {getOwner().toBasicString()}"); if (!player_manager.tryGetUserByPrimaryKey(party_action.getLeaderGuid(), out var leader)) { var err_msg = $"Failed to summon party member !!! : leader not logged in - {party_action.getLeaderGuid()}"; result.setFail(ServerErrorCode.PartyLeaderLoggedOut, err_msg); Log.getLogger().error(err_msg); return (result, null); } var inventory_action = leader.getEntityAction(); NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"InventoryActionBase is null !! - {leader.toBasicString()}");; var delete_summon_item = await inventory_action.tryDeleteItemByMetaId((uint)MetaHelper.GameConfigMeta.SummonStoneItemMetaId, (ushort)MetaHelper.GameConfigMeta.ItemAmountPartySummon); if (delete_summon_item.Item1.isFail()) return (delete_summon_item.Item1, null); var delete_item = delete_summon_item.Item2.FirstOrDefault(); return (delete_summon_item.Item1, delete_item); } private void sendPartyMemberLocation(PartyMemberInfo user) { var party = getOwner() as GlobalPartyDetail; NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !! ");; // 1. 파티 참가 멤버 알림 ( to server ) var server_message = new ServerMessage { PartyMemberLocationNoti = new() { PartyGuid = party.PartyGuid, PartyMemberGuid = user.UserGuid } }; PartyHelper.BroadcastToServers(party, server_message, true); // 2. 파티 참가 멤버 알림 ( to client ) var client_message = new ClientToGame(); client_message.Message = new(); client_message.Message.PartyMemberLocationNoti = new(); client_message.Message.PartyMemberLocationNoti.MemberGuid = user.UserGuid; client_message.Message.PartyMemberLocationNoti.LocationInfo = user.LocationInfo; PartyHelper.BroadcastToClients(party, client_message, new List()); } }