using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Google.Protobuf.WellKnownTypes; using Newtonsoft.Json; using ServerCore; using ServerBase; using ServerCommon; using static ServerMessage.Types; namespace GameServer; public class MyhomeInviteInfo { public string SenderId { get; set; } public string SenderGuid { get; set; } public string SenderNickName { get; set; } public DateTime ExpireTime { get; set; } public DateTime ReplyExpireTime { get; set; } public string UniqueKey { get; set; } public int ReplyValue { get; set; } = 0; public IndunLocation MyhomeLocation { get; set; } = new(); public MyhomeInviteInfo(string senderId, string senderGuid, string senderNickname, IndunLocation location, DateTime expireTime, DateTime replyExpireTime, string uniqueKey) { SenderId = senderId; SenderGuid = senderGuid; SenderNickName = senderNickname; MyhomeLocation = location; ExpireTime = expireTime; ReplyExpireTime = replyExpireTime; ReplyValue = 0; UniqueKey = uniqueKey; } public override string ToString() { return JsonConvert.SerializeObject(this); } } public class FriendInviteMyhomeAction : EntityActionBase { public FriendInviteMyhomeAction(Player owner) : base(owner) { } public override async Task onInit() { var result = new Result(); return await Task.FromResult(result); } public override void onClear() { return; } public async Task<(Result, List, List) > inviteFriendToMyhome(List infos) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var location_attribute = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location_attribute is null !!!"); var myhome_location = location_attribute.CurrentIndunLocation; var instance_meta_Id = myhome_location.InstanceMetaId; var result = isCurrentLocationMyHome(instance_meta_Id); if (result.isFail()){ return (result, new(), new()); } DateTime now = DateTime.UtcNow; string unique_key = now.ToString(); var expire_time = now.AddMilliseconds(MetaHelper.GameConfigMeta.FriendIntiveCoolTime * 1000); var reply_expire_time = now.AddMilliseconds(MetaHelper.GameConfigMeta.FriendInviteReplyTime * 1000); MyhomeInviteInfo invite_info = new MyhomeInviteInfo(owner.getAccountId(), owner.getUserGuid(), owner.getUserNickname(), myhome_location, expire_time, reply_expire_time, unique_key); List fail_infos = new(); List cond_check_success_infos = new(); foreach (var info in infos) { var cond_result = await conditionCheck(info); if (cond_result.isFail()) { var fail = FriendAgentAction.makeFriendMemberError(cond_result.getErrorCode(), info.TargetGuid); fail_infos.Add(fail); } else { cond_check_success_infos.Add(info); } } List cache_check_success_infos = new(); foreach (var info in cond_check_success_infos) { var cache_cond_result = await checkFriendsInviteCache(info, now); if (cache_cond_result.isFail()) { var fail = FriendAgentAction.makeFriendMemberError(cache_cond_result.getErrorCode(), info.TargetGuid); fail_infos.Add(fail); } else { cache_check_success_infos.Add(info); } } List success_guids = new(); foreach (var info in cache_check_success_infos) { var add_result = await addFriendsInviteCache(info, invite_info); if (add_result.isFail()) { var fail = FriendAgentAction.makeFriendMemberError(add_result.getErrorCode(), info.TargetGuid); fail_infos.Add(fail); } else { ReceiveInviteMyHomeNoti notiInfo = makeInviteMyhomeNoti(owner, info.TargetGuid, info.TargetNickName, invite_info); success_guids.Add(notiInfo); } } return (result, fail_infos, success_guids); } private ReceiveInviteMyHomeNoti makeInviteMyhomeNoti(Player owner, string targetGuid, string targetNickname, MyhomeInviteInfo inviteInfo) { ReceiveInviteMyHomeNoti info = new(); info.InviterMyHomeId = inviteInfo.MyhomeLocation.InstanceRoomId; info.ExpireTime = Timestamp.FromDateTime(inviteInfo.ExpireTime); info.ReplyExpireTime = Timestamp.FromDateTime(inviteInfo.ReplyExpireTime); info.UniqueKey = inviteInfo.UniqueKey; info.BaseInfo = new(); info.BaseInfo.ReceiverGuid = targetGuid; info.BaseInfo.ReceiverNickName = targetNickname; info.BaseInfo.ReceiverId = string.Empty;//내가 초대하려는 유저의 아이디. info.BaseInfo.SenderGuid = inviteInfo.SenderGuid; info.BaseInfo.SenderNickName = inviteInfo.SenderNickName; info.BaseInfo.SenderId = owner.getAccountId(); //내 아이디 return info; } private async Task addFriendsInviteCache(FriendNickNameInfo info, MyhomeInviteInfo inviteInfo) { var result = new Result(); var server_logic = GameServerApp.getServerLogic(); CharacterStorage characterStorage = new CharacterStorage(); characterStorage.Init(server_logic.getRedisDb(), string.Empty); ServerErrorCode error_code = await characterStorage.AddReceivedInviteInfo(info.TargetGuid, inviteInfo.ToString()); if (error_code != ServerErrorCode.Success) { result.setFail(error_code); return result; } return result; } private async Task checkFriendsInviteCache(FriendNickNameInfo info, DateTime now) { var result = new Result(); var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var server_logic = GameServerApp.getServerLogic(); CharacterStorage characterStorage = new CharacterStorage(); characterStorage.Init(server_logic.getRedisDb(), string.Empty); //내가 초대 하려고 하는 유저가 받은 초대 정보 var invited_infos = await characterStorage.GetReceivedInviteInfo(info.TargetGuid); if (invited_infos.Count > 0) { foreach (var invited_info in invited_infos) { var data = JsonConvert.DeserializeObject(invited_info); if (data is null) continue; //data 가 기본적으로 만료시간을 전부 지나면 삭제 처리 if (now > data.ExpireTime) { characterStorage.RemoveReceivedInviteInfo(info.TargetGuid, invited_info); continue; } //내가 보낸 정보가 남아있는 상태에서 보낸 시간이 아직 안지났으면 에러 처리 if (data.SenderGuid.Equals(owner.getUserGuid()) && now <= data.ExpireTime) { result.setFail(ServerErrorCode.FriendInviteExpireTimeRemain); break; } //내가 보낸 정보가 아닌 데이터인데 수락해야되는 시간이 남아 있는경우 if (!data.SenderGuid.Equals(owner.getUserGuid()) && now <= data.ReplyExpireTime) { //수락 시간이 남아 있는데 거절한 상태가 아니면 if (data.ReplyValue == (int)InviteFriendReplyType.Refuse) continue; result.setFail(ServerErrorCode.FriendInviteWaitingOtherInvite); break; } } } return result; } private async Task conditionCheck(FriendNickNameInfo info) { string target_guid = info.TargetGuid; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var login_cache_request = new LoginCacheOtherUserRequest(player, server_logic.getRedisConnector(), target_guid); var result = await login_cache_request.fetchLogin(); var friend_cache = login_cache_request.getLoginCache(); if (result.isFail()) { var err_msg = $"friend Login Cache error : target_guid - {target_guid}"; result.setFail(ServerErrorCode.TargetUserNotLogIn, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if (friend_cache is null) { result.setFail(ServerErrorCode.FriendInfoOffline); return result; } if (friend_cache.State == PlayerStateType.DontDistrub) { result.setFail(ServerErrorCode.FriendInviteDontDisturbState); return result; } if (friend_cache.InstanceRoomId.Contains(ServerCommon.Constant.PREFIX_MYHOME_INSTANCE_ROOM_ID)) { var err_msg = $"friend another myhome : friend_guid - {target_guid}, my_guid - {player.getUserGuid()}, currentRommonIntanceId - {friend_cache.InstanceRoomId}"; result.setFail(ServerErrorCode.FriendIsInAnotherMyhome, err_msg); //Log.getLogger().error(result.toBasicString()); return result; } return result; } public Result isCurrentLocationMyHome(Int32 instancMetaId) { var result = new Result(); if (!MetaData.Instance._IndunTable.TryGetValue(instancMetaId, out var indun_data)) { string err_msg = $"Not Found IndunData. instanceMetaId:{instancMetaId}"; result.setFail(ServerErrorCode.NotExistInstanceRoom, err_msg); Log.getLogger().error(err_msg); return result; } if (indun_data.ContentsType != ContentsType.MyHome) { string err_msg = $"my pos is not myhome InstanceRoom owner : {getOwner().toBasicString()}, intance_room : {instancMetaId}"; result.setFail(ServerErrorCode.FriendInviteMyPosIsNotMyHome, err_msg); Log.getLogger().error(err_msg); return result; } return result; } }