초기커밋
This commit is contained in:
402
GameServer/Entity/Party/Action/GlobalPartyAction.cs
Normal file
402
GameServer/Entity/Party/Action/GlobalPartyAction.cs
Normal file
@@ -0,0 +1,402 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using PARTY_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyAction : EntityActionBase
|
||||
{
|
||||
private ConcurrentDictionary<string, GlobalPartyDetail> m_parties { get; set; } = new();
|
||||
|
||||
public GlobalPartyAction(GlobalParty owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public GlobalPartyDetail? getGlobalPartyDetail(PARTY_GUID party_guid)
|
||||
{
|
||||
if (string.IsNullOrEmpty(party_guid)) return null;
|
||||
|
||||
return m_parties.GetValueOrDefault(party_guid);
|
||||
}
|
||||
private void setGlobalPartyDetail(GlobalPartyDetail detail) => m_parties.TryAdd(detail.PartyGuid, detail);
|
||||
|
||||
public async Task<Result> createParty(PARTY_GUID party_guid, string leader_guid, string leader_nickname)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"GlobalParty is null !! - party_guid:{party_guid}");
|
||||
|
||||
var detail = new GlobalPartyDetail(owner, party_guid);
|
||||
await detail.onInit();
|
||||
|
||||
// redis 등록
|
||||
var detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_action, () => $"GlobalPartyDetailAction is null !! - party_guid:{party_guid}");
|
||||
|
||||
result = await detail_action.createPartyDetailInfo(leader_guid, leader_nickname);
|
||||
|
||||
// 메모리 등록
|
||||
setGlobalPartyDetail(detail);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadParty(PARTY_GUID party_guid)
|
||||
{
|
||||
var owner = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"global party is null !!! - party guid: {party_guid}");
|
||||
|
||||
var detail = new GlobalPartyDetail(owner, party_guid);
|
||||
await detail.onInit();
|
||||
|
||||
var detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_action, () => $"global party detail action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = await detail_action.loadAllFromCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
setGlobalPartyDetail(detail);
|
||||
|
||||
// 1-1. party server 정보에 server 추가
|
||||
var global_party_server_action = detail.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(global_party_server_action, () => $"global party detail server action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
result = await global_party_server_action.addPartyServer(GameServerApp.getServerLogic().getServerName());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 1-2. 서버 변경 알림
|
||||
result = await global_party_server_action.notifyChangePartyServerToServers(BoolType.True, GameServerApp.getServerLogic().getServerName());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(string? leader_guid, string? leader_nickname, int? member_count)> getPartyLeaderGuidAndMemberCount(PARTY_GUID party_guid)
|
||||
{
|
||||
var owner = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"global party is null !!! - party guid: {party_guid}");
|
||||
|
||||
var detail = getGlobalPartyDetail(party_guid);
|
||||
|
||||
// 메모리에 파티정보가 있으면, 활용
|
||||
if (null != detail)
|
||||
{
|
||||
var origin_detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_detail_action, () => $"global party detail action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var origin_detail_member_action = detail.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_detail_member_action, () => $"global party detail member action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return (origin_detail_action.getLeaderGuid(), origin_detail_action.getLeaderNickname(), origin_detail_member_action.getMemberCount());
|
||||
}
|
||||
|
||||
// 메모리에 파티 정보가 없으면, load 하여 활용 ( 단, 메모리 저장은 하지 않음 - 서버내 없는 파티 정보 조회 )
|
||||
detail = new GlobalPartyDetail(owner, party_guid);
|
||||
await detail.onInit();
|
||||
|
||||
var detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_action, () => $"global party detail action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var detail_member_action = detail.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_member_action, () => $"global party detail member action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = await detail_action.loadPartyCache();
|
||||
if (result.isFail()) return (null, null, null);
|
||||
|
||||
result = await detail_action.loadPartyMemberCache();
|
||||
if (result.isFail()) return (null, null, null);
|
||||
|
||||
return (detail_action.getLeaderGuid(), detail_action.getLeaderNickname(), detail_member_action.getMemberCount());
|
||||
}
|
||||
|
||||
public async Task<Result> joinParty(PARTY_GUID party_guid, PartyMemberInfo user)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as GlobalParty;
|
||||
if (null == owner)
|
||||
{
|
||||
var err_msg = $"Fail to find global entity !!! : {nameof(GlobalParty)}";
|
||||
result.setFail(ServerErrorCode.EntityBaseNotFound, err_msg );
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var party = getGlobalPartyDetail(party_guid);
|
||||
|
||||
// 1. 없으면, Redis 에서 Load 하여 채워 넣음
|
||||
if (null == party)
|
||||
{
|
||||
result = await loadParty(party_guid);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
party = getGlobalPartyDetail(party_guid);
|
||||
}
|
||||
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"GlobalDetailParty is null !! - party_guid:{party_guid}");
|
||||
|
||||
// 2. member 추가
|
||||
var global_party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(global_party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - party_guid:{party_guid}");
|
||||
|
||||
var add_member = await global_party_member_action.addJoinMember(user);
|
||||
if (add_member.result.isFail()) return add_member.result;
|
||||
|
||||
// 3. Party p2p group host 전달 ( to client )
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"global party detail action is null !!! - {party.toBasicString()}");
|
||||
|
||||
_ = await party_action.joinPartyP2PGroup(user.UserGuid);
|
||||
_ = await party_action.checkPartyP2PState(user.UserGuid, true, true);
|
||||
|
||||
if (add_member.isAready == true) return add_member.result;
|
||||
|
||||
// 4. 파티 정보 전달
|
||||
var send_party_members = new List<USER_GUID>();
|
||||
var member_count = global_party_member_action.getMemberCount();
|
||||
if (member_count == 2)
|
||||
{
|
||||
send_party_members.Add(party_action.getLeaderGuid());
|
||||
}
|
||||
send_party_members.Add(user.UserGuid);
|
||||
await party_action.sendPartyInfo(send_party_members, party_action.getLeaderGuid(), false);
|
||||
|
||||
// 5. Party Instance 정보 전달
|
||||
var party_instance_attribute = party.getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"party instance attribute is null !!! - {party.toBasicString()}");
|
||||
|
||||
if (party_instance_attribute.InstanceId > 0)
|
||||
{
|
||||
party_action.sendPartyInstance(user.UserGuid);
|
||||
}
|
||||
|
||||
return add_member.result;
|
||||
}
|
||||
|
||||
public async Task<Result> leaveParty(PARTY_GUID party_guid, USER_GUID leave_user_guid, BoolType is_ban)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var global_party = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(global_party, () => $"global party is null !!! - party guid: {party_guid}");
|
||||
|
||||
var party = global_party.getParty(party_guid);
|
||||
ArgumentNullException.ThrowIfNull(party);
|
||||
|
||||
// 1. 파티 멤버에서 삭제
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - party_guid:{party_guid}, {party.toBasicString()}");
|
||||
|
||||
var delete_party_member = await party_member_action.deleteJoinMember(leave_user_guid, true);
|
||||
if (delete_party_member.result.isFail()) return delete_party_member.result;
|
||||
|
||||
// 2. p2p 그룹에서 제외
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
ArgumentNullException.ThrowIfNull(party_action);
|
||||
_ = party_action.leavePartyP2PGroup(leave_user_guid);
|
||||
_ = party_action.checkPartyP2PState(leave_user_guid, false, false);
|
||||
|
||||
// 3. 파티 탈퇴 알림
|
||||
notifyLeavePartyMember(party, leave_user_guid, is_ban);
|
||||
|
||||
// 4. 초대 메시지 발송 체크 : 초대 메시지에 응답하여 Party 가 결정될 수 있기 때문에 파티원이 1명이어도 Party 를 파괴시키지 않음
|
||||
var invite_send_action = party.getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(invite_send_action, () => $"global party invite party send action is null !!! - {party.toBasicString()}");
|
||||
var sends = await invite_send_action.getInviteSendsCount();
|
||||
if (sends > 0 && delete_party_member.party_member_count >= 1)
|
||||
{
|
||||
Log.getLogger().debug($"Not Destory Party: Send Invite Count - {sends}");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 5. 파티원이 1명으로 파티 파괴
|
||||
if (delete_party_member.party_member_count <= 1)
|
||||
{
|
||||
result = await destroyParty(party_guid, true);
|
||||
}
|
||||
// 6. party server 체크
|
||||
else
|
||||
{
|
||||
result = await checkPartyServer(party, leave_user_guid);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> destroyParty(PARTY_GUID party_guid, bool is_notify_to_servers)
|
||||
{
|
||||
var global_party = getOwner() as GlobalParty;
|
||||
ArgumentNullException.ThrowIfNull(global_party);
|
||||
|
||||
var party = global_party.getParty(party_guid);
|
||||
if (null == party) return new Result();
|
||||
|
||||
// 0. business log 준비
|
||||
var party_log_data = PartyBusinessLogHelper.toPartyLogData(party_guid, false);
|
||||
var party_business_log = new PartyBusinessLog(new LogActionEx(LogActionType.DestroyParty), party_log_data);
|
||||
|
||||
// 1. party info 제거
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"global party detail info action is null !!! - {party.toBasicString()}");
|
||||
_ = await party_info_action.deleteParty();
|
||||
|
||||
// 2. party member 제거
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"global party detail member action is null !!! - {party.toBasicString()}");
|
||||
var members = party_member_action.getMembers();
|
||||
_ = await party_member_action.deletePartyMembers();
|
||||
|
||||
// 3. party server 제거
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"global party detail server action is null !!! - {party.toBasicString()}");
|
||||
var servers = party_server_action.getServers();
|
||||
_ = await party_server_action.deleteAllPartyServers();
|
||||
|
||||
// 4. invite party send 제거
|
||||
var party_invite_party_send_action = party.getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send_action, () => $"global party invite party send action is null !!! - {party.toBasicString()}");
|
||||
_ = await party_invite_party_send_action.deleteInvitePartySends();
|
||||
|
||||
// 5. instance 제거
|
||||
var party_instance_action = party.getEntityAction<GlobalPartyDetailInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_action, () => $"global party detail instance action is null !!! - {party.toBasicString()}");
|
||||
_ = await party_instance_action.deletePartyInstance();
|
||||
|
||||
// 5. p2pgroup 제거
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"global party detail action is null !!! - {party.toBasicString()}");
|
||||
_ = party_action.destroyPartyP2PGroup();
|
||||
|
||||
// 6. member 들의 Party 정보 제거
|
||||
await clearPersonalPartyWithMembers(members.ToList());
|
||||
|
||||
// 7. party 제거
|
||||
m_parties.Remove(party_guid, out _);
|
||||
|
||||
// 8. Server 에 알림
|
||||
if (is_notify_to_servers)
|
||||
{
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
NtfDestroyParty = new() { DestroyPartyGuid = party_guid }
|
||||
};
|
||||
|
||||
PartyHelper.BroadcastToServers(servers.ToList(), server_message, true);
|
||||
}
|
||||
|
||||
// 9. Client 에게 알림
|
||||
var client_message = new ClientToGame
|
||||
{
|
||||
Message = new()
|
||||
{
|
||||
DestroyPartyNoti = new()
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToClients(members.ToList(), client_message, new List<string>());
|
||||
|
||||
BusinessLogger.collectLog(party, party_business_log);
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
private void notifyLeavePartyMember(GlobalPartyDetail party, USER_GUID leave_user_guid, BoolType is_ban)
|
||||
{
|
||||
// 1. 파티원 탈퇴에 따른 알림 ( to server )
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
LeavePartyMemberNoti = new()
|
||||
{
|
||||
IsBan = is_ban,
|
||||
PartyGuid = party.PartyGuid,
|
||||
LeavePartyUserGuid = leave_user_guid
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 2. 파티원 탈퇴에 따른 알림 ( to client )
|
||||
var client_message = new ClientToGame
|
||||
{
|
||||
Message = new()
|
||||
{
|
||||
LeavePartyMemberNoti = new()
|
||||
{
|
||||
IsBan = is_ban,
|
||||
LeavePartyUserGuid = leave_user_guid
|
||||
}
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
}
|
||||
|
||||
public async Task<Result> checkPartyServer(GlobalPartyDetail party, USER_GUID leave_user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. 서버 내 파티원 체크
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !!! - {party.toBasicString()}");
|
||||
|
||||
var exist_members_without_me = party_member_action.checkExistPartyMembers(leave_user_guid);
|
||||
if (exist_members_without_me) return result;
|
||||
|
||||
// 2. 서버 정보 제거
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !!! - {party.toBasicString()}");
|
||||
|
||||
result = await party_server_action.deletePartyServer(GameServerApp.getServerLogic().getServerName());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 3. 서버 정보 제거 알림
|
||||
result = await party_server_action.notifyChangePartyServerToServers(BoolType.False, GameServerApp.getServerLogic().getServerName());
|
||||
|
||||
// 4. 파티 정보 제거
|
||||
m_parties.Remove(party.PartyGuid, out _);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task clearPersonalPartyWithMembers(IReadOnlyList<USER_GUID> members)
|
||||
{
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
|
||||
foreach (var user in members)
|
||||
{
|
||||
if (!player_manager.tryGetUserByPrimaryKey(user, out var member)) continue;
|
||||
if (null == member) continue;
|
||||
|
||||
var personal_party_action = member.getEntityAction<PersonalPartyAction>();
|
||||
if (null == personal_party_action) continue;
|
||||
|
||||
await personal_party_action.clearPersonalParty();
|
||||
}
|
||||
}
|
||||
}
|
||||
552
GameServer/Entity/Party/Action/GlobalPartyDetailAction.cs
Normal file
552
GameServer/Entity/Party/Action/GlobalPartyDetailAction.cs
Normal file
@@ -0,0 +1,552 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Nettention.Proud
|
||||
|
||||
;
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailAction : EntityActionBase
|
||||
{
|
||||
public GlobalPartyDetailAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keepParty()
|
||||
{
|
||||
// 1. party keep
|
||||
var party_action = getOwner().getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"GlobalPartyDetailInfoAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_action.keep();
|
||||
|
||||
// 2. party member keep
|
||||
var party_member_action = getOwner().getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_member_action.keep();
|
||||
|
||||
// 3. party server keep
|
||||
var party_server_action = getOwner().getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_server_action.keep();
|
||||
|
||||
// 4. party invite send keep
|
||||
var party_invite_send_action = getOwner().getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_send_action, () => $"GlobalPartyInvitePartySendAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_invite_send_action.keep();
|
||||
|
||||
// 5. party instance keep
|
||||
var party_instance_action = getOwner().getEntityAction<GlobalPartyDetailInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_action, () => $"GlobalPartyDetailInstanceAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_instance_action.keep();
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
public bool isLeader(USER_GUID user_guid)
|
||||
{
|
||||
var detail = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(detail, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_attribute = detail.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !!! - user guid:{user_guid}, {detail.toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderCharGuid == user_guid;
|
||||
}
|
||||
|
||||
public USER_GUID getLeaderGuid()
|
||||
{
|
||||
var detail = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(detail, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_attribute = detail.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !!! - {detail.toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderCharGuid;
|
||||
}
|
||||
|
||||
public string getLeaderNickname()
|
||||
{
|
||||
var detail = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(detail, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_attribute = detail.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !!! - {detail.toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderNickname;
|
||||
}
|
||||
|
||||
public async Task<(Result result, string change_leader_guid)> changePartyLeader()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_member_attribute = party.getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - party_guid:{party.PartyGuid}");
|
||||
|
||||
// 1. 파티장 자동 변경 ( 조건 1. jointime 이 가장 오래된 유저 )
|
||||
var origin_leader_guid = getLeaderGuid();
|
||||
var next_leader_guid = origin_leader_guid;
|
||||
var join_time = DateTime.UtcNow.ToTimestamp();
|
||||
|
||||
foreach (var member in party_member_attribute.getPartyMembers())
|
||||
{
|
||||
if (origin_leader_guid == member.Value.UserGuid) continue;
|
||||
if (join_time < member.Value.JoinTime) continue;
|
||||
|
||||
next_leader_guid = member.Value.UserGuid;
|
||||
join_time = member.Value.JoinTime;
|
||||
}
|
||||
|
||||
// 2. 파티장 변경 처리
|
||||
var party_detail_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_detail_info_action, () => $"GlobalPartyDetailInfoAction is null !! - party_guid:{party.PartyGuid}");
|
||||
result = await party_detail_info_action.changePartyLeader(next_leader_guid, true);
|
||||
|
||||
// 3. 파티장 변경 알림
|
||||
var message = new ServerMessage
|
||||
{
|
||||
ChangePartyLeaderNoti = new ServerMessage.Types.ChangePartyLeaderNoti()
|
||||
{
|
||||
PartyGuid = party.PartyGuid,
|
||||
NewPartyLeaderGuid = next_leader_guid
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToServers(party, message, false);
|
||||
|
||||
return (result, next_leader_guid);
|
||||
}
|
||||
|
||||
public HostID getP2PHostId()
|
||||
{
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(party_attribute);
|
||||
|
||||
return party_attribute.P2PGroup;
|
||||
}
|
||||
|
||||
public void sendPartyInstance(USER_GUID user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_instance_attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
if (party_instance_attribute.InstanceId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyInstanceInfoNoti = new();
|
||||
client_message.Message.PartyInstanceInfoNoti.InstanceId = party_instance_attribute.InstanceId;
|
||||
client_message.Message.PartyInstanceInfoNoti.StartTime = party_instance_attribute.StartTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.EndTime = party_instance_attribute.EndTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.JoinMemberCount = party_instance_attribute.JoinMemberCount;
|
||||
client_message.Message.PartyInstanceInfoNoti.IsEnd = party_instance_attribute.InstanceId == 0 ? BoolType.True : BoolType.False;
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (! player_manager.tryGetUserByPrimaryKey(user_guid, out var user_entity) || null == user_entity)
|
||||
{
|
||||
var err_msg = $"Failed to send party instance !!! : not logged in server - {user_guid}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin,err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PartyHelper.sendToClient(client_message, user_entity.getHostId());
|
||||
}
|
||||
|
||||
public async Task<Result> sendPartyInfo(IReadOnlyList<USER_GUID> sendUsers, USER_GUID leaderGuid, bool exceptAnotherServer)
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"party is null !!");
|
||||
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"GlobalPartyDetailInfoAction is null !! - {party.toBasicString()}");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
foreach (var send in sendUsers)
|
||||
{
|
||||
if (player_manager.tryGetUserByPrimaryKey(send, out var player))
|
||||
{
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.JoinPartyInfoNoti = new();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyName = party_info_action.getPartyName();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyLeaderGuid = getLeaderGuid();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyLeaderNickname = getLeaderNickname();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyMemberList.AddRange(party_member_action.getMembers4PartyInfo().ToList());
|
||||
|
||||
if (leaderGuid != send)
|
||||
{
|
||||
client_message.Message.JoinPartyInfoNoti.ServerConnectInfo = await tryMoveToLeaderServer(leaderGuid, send);
|
||||
}
|
||||
|
||||
if (null == player) continue;
|
||||
|
||||
PartyHelper.sendToClient(client_message, player.getHostId());
|
||||
|
||||
await QuestManager.It.QuestCheck(player, new QuestParty(EQuestEventTargetType.PARTY, EQuestEventNameType.ENTERED));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exceptAnotherServer) continue;
|
||||
|
||||
var server_message = new ServerMessage();
|
||||
server_message.NtfPartyInfo = new();
|
||||
server_message.NtfPartyInfo.PartyGuid = party.PartyGuid;
|
||||
server_message.NtfPartyInfo.PartyMemberGuids.Add(send);
|
||||
|
||||
await PartyHelper.sendToServerByTargetClient(send, server_message);
|
||||
}
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public async Task<Result> joinPartyP2PGroup(USER_GUID user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (! player_manager.tryGetUserByPrimaryKey(user_guid, out var user_entity))
|
||||
{
|
||||
var err_msg = $"Failed to join party p2p group !!! : not logged in server - {user_guid}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin,err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var p2p_group = getP2PHostId();
|
||||
GameServerApp.getServerLogic().getProudNetListener().getNetServer().JoinP2PGroup(user_entity.getHostId(), p2p_group);
|
||||
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyP2PGroupHostIdNoti = new();
|
||||
client_message.Message.PartyP2PGroupHostIdNoti.PartyP2PGroupHostId = (int)p2p_group;
|
||||
|
||||
PartyHelper.sendToClient(client_message, user_entity.getHostId());
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public async Task<Result> checkPartyP2PState(USER_GUID userGuid, bool isJoin, bool includeSendingMe)
|
||||
{
|
||||
// 1. 타 유저에게 내 정보 전송
|
||||
_ = await sendPartyP2PState(userGuid, isJoin);
|
||||
|
||||
if (!includeSendingMe) return await Task.FromResult(new Result());
|
||||
|
||||
// 2. 타 유저들의 정보를 내게 전송
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyMemberP2PStateNoti = new();
|
||||
|
||||
var members = party_member_action.getMembers();
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (member == userGuid) continue;
|
||||
client_message.Message.PartyMemberP2PStateNoti.MemberGuid = member;
|
||||
client_message.Message.PartyMemberP2PStateNoti.IsP2P = player_manager.tryGetUserByPrimaryKey(member, out _) ? BoolType.True : BoolType.False;
|
||||
PartyHelper.sendToClient(client_message, userGuid);
|
||||
}
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
private async Task<Result> sendPartyP2PState(USER_GUID userGuid, bool isJoin)
|
||||
{
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyMemberP2PStateNoti = new();
|
||||
client_message.Message.PartyMemberP2PStateNoti.MemberGuid = userGuid;
|
||||
client_message.Message.PartyMemberP2PStateNoti.IsP2P = isJoin ? BoolType.True : BoolType.False;
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<USER_GUID> { userGuid });
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public bool leavePartyP2PGroup(USER_GUID user_guid)
|
||||
{
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (player_manager.tryGetUserByPrimaryKey(user_guid, out var user))
|
||||
{
|
||||
return GameServerApp.getServerLogic().getProudNetListener().getNetServer().LeaveP2PGroup(user.getHostId(), getP2PHostId());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool destroyPartyP2PGroup()
|
||||
{
|
||||
var p2p_group = getP2PHostId();
|
||||
return GameServerApp.getServerLogic().getProudNetListener().getNetServer().DestroyP2PGroup(p2p_group);
|
||||
}
|
||||
|
||||
public async Task<Result> createPartyDetailInfo(string leader_guid, string leader_nickname)
|
||||
{
|
||||
var result = new Result();
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
if (null == party)
|
||||
{
|
||||
var err_msg = $"Fail to get entity base : {nameof(GlobalPartyDetail)}";
|
||||
result.setFail(ServerErrorCode.EntityBaseNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 1. party 정보 create
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"GlobalPartyDetailInfoAction is null !! - {party.toBasicString()}");
|
||||
result = await party_info_action.createParty(leader_guid, leader_nickname);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. leader member 정보 설정
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
var change = await party_member_action.changeMember(PartyHelper.makePartyMember(leader_guid, leader_nickname));
|
||||
if (change.result.isFail()) return result;
|
||||
|
||||
// 3. party server 정보 설정
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !! - {party.toBasicString()}");
|
||||
result = await party_server_action.addPartyServer(GameServerApp.getServerLogic().getServerName());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> loadAllFromCache()
|
||||
{
|
||||
var result = new Result();
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
ArgumentNullException.ThrowIfNull(party);
|
||||
|
||||
// 1. party 정보 Load
|
||||
result = await loadPartyCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. party member 정보 Load
|
||||
result = await loadPartyMemberCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 3. party server 정보 Load
|
||||
result = await loadPartyServerCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 4. party invite send 정보 load
|
||||
result = await loadPartyInvitePartySendCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 5. party instance 정보 load ( 없을 수 있으므로 result 무시 )
|
||||
_ = await loadPartyInstanceCache();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"GlobalPartyDetailInfoAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_info_action.loadParty();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyMemberCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_member_action.loadPartyMember();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadPartyServerCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_server_action.loadPartyServer();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadPartyInvitePartySendCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_invite_party_send_action = party.getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send_action, () => $"GlobalPartyInvitePartySendAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_invite_party_send_action.loadPartyInvitePartySend(party.PartyGuid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadPartyInstanceCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_instance_action = party.getEntityAction<GlobalPartyDetailInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_action, () => $"GlobalPartyDetailInstanceAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_instance_action.loadPartyInstance();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<ServerConnectInfo?> tryMoveToLeaderServer(USER_GUID leaderGuid, USER_GUID userGuid)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
// 1. party leader 세션 체크
|
||||
var leader_login_cache = await PartyHelper.getOtherUserLoginCache(leaderGuid);
|
||||
if (null == leader_login_cache)
|
||||
{
|
||||
err_msg = $"Failed to get party leader session !!! - {leaderGuid}";
|
||||
result.setFail(ServerErrorCode.NotFoundParty, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 조건 체크
|
||||
if (false == await checkConditionLeaderServer(leader_login_cache.CurrentServer)) return null;
|
||||
|
||||
// 3. 서버 정보 조회
|
||||
(result, var server_info) = await server_logic.getServerInfoByServerName(leader_login_cache.CurrentServer);
|
||||
if (null == server_info) return null;
|
||||
if (server_info.Sessions + server_info.Reservation + server_info.ReturnCount >= server_info.Capacity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4. 예약 요청
|
||||
var message = new ServerMessage.Types.GS2GS_REQ_RESERVATION_ENTER_TO_SERVER();
|
||||
message.MoveType = ServerMoveType.Force;
|
||||
message.RequestServerName = server_logic.getServerName();
|
||||
message.RequestUserGuid = userGuid;
|
||||
|
||||
var reserved = await server_logic.getReservationManager().registerReservationEnterToServer(message, server_info.Name);
|
||||
|
||||
// 5. 예약 실패 체크
|
||||
if (null == reserved)
|
||||
{
|
||||
err_msg = $"Failed to reservation enter to game server!!! - {server_info.Name}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.FailedToReservationEnter, err_msg);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 6. 이동 처리
|
||||
var player_manager = server_logic.getPlayerManager();
|
||||
if (!player_manager.tryGetUserByPrimaryKey(userGuid, out var player)) return null;
|
||||
|
||||
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "JoinParty", moveDelegate);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 7. 이동 정보 체크
|
||||
var account_attribute = player.getEntityAttribute<AccountAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(account_attribute);
|
||||
|
||||
var res = new ServerConnectInfo();
|
||||
res.ServerAddr = account_attribute.ToConnectGameServerAddress.IP;
|
||||
res.ServerPort = account_attribute.ToConnectGameServerAddress.Port;
|
||||
res.Otp = account_attribute.OtpForServerConnect;
|
||||
|
||||
return res;
|
||||
|
||||
async Task<Result> moveDelegate() => await moveAsync(player, server_info);
|
||||
}
|
||||
|
||||
private async Task<bool> checkConditionLeaderServer(string leaderServerName)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
(var result, var leader_server) = await server_logic.getServerInfoByServerName(leaderServerName);
|
||||
if (null == leader_server) return false;
|
||||
|
||||
// 1. join user 가 channel 에 있는지 확인
|
||||
if (server_logic.getServerType().toServerType() != ServerType.Channel) return false;
|
||||
|
||||
// 2. leader 와 동일한 channel 서버에 있는지 확인
|
||||
if (leaderServerName == server_logic.getServerName()) return false;
|
||||
|
||||
// 3. leader 가 channel 에 있는지 확인
|
||||
if (leaderServerName.toServerType() != ServerType.Channel) return false;
|
||||
|
||||
// 4. leader 와 동일한 world id 에 있는지 확인
|
||||
if (server_logic.getWorldId() != leader_server.WorldId) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<Result> moveAsync(Player player, ServerInfo serverInfo)
|
||||
{
|
||||
// 1. 파티 리더 위치로 이동 ( to Channel )
|
||||
var result = await GameZoneMoveHelper.moveToAnotherChannel(player, serverInfo, null);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.None, GameServerApp.getServerLogic().getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal());
|
||||
}
|
||||
|
||||
return await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
}
|
||||
}
|
||||
399
GameServer/Entity/Party/Action/GlobalPartyDetailInfoAction.cs
Normal file
399
GameServer/Entity/Party/Action/GlobalPartyDetailInfoAction.cs
Normal file
@@ -0,0 +1,399 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailInfoAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyCacheRequest m_party_cache_request;
|
||||
|
||||
private TaskCompletionSource m_vote_finish_task_source { get; set; } = new();
|
||||
|
||||
public GlobalPartyDetailInfoAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_cache_request =
|
||||
new PartyCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit() => await Task.FromResult(new Result());
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task keep()
|
||||
{
|
||||
await m_party_cache_request.keepPartyCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadParty()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
result = await m_party_cache_request.fetchPartyCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_attribute, new List<CacheBase> { m_party_cache_request.getPartyCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> createParty(USER_GUID leader_guid, string leader_nickname)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. cache 생성
|
||||
result = await m_party_cache_request.createPartyCache(leader_guid, leader_nickname);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 복사
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_attribute, new List<CacheBase> { m_party_cache_request.getPartyCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteParty()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_cache_request.deletePartyCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 제거
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> changePartyLeader(USER_GUID next_leader_guid, bool is_upsert_cache)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. attribute 수정
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_attribute.PartyLeaderCharGuid = next_leader_guid;
|
||||
|
||||
// 2. cache 수정
|
||||
var party_cache = m_party_cache_request.getPartyCache();
|
||||
NullReferenceCheckHelper.throwIfNull(party_cache, () => $"Party Cache is null !! - party name:{party_attribute.PartyName}");
|
||||
|
||||
party_cache.PartyLeaderCharGuid = next_leader_guid;
|
||||
|
||||
if(is_upsert_cache) result = await m_party_cache_request.upsertPartyCache();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> changePartyName(string new_party_name, bool is_upsert_cache)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. attribute 수정
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_attribute.PartyName = new_party_name;
|
||||
|
||||
// cache 수정
|
||||
var party_cache = m_party_cache_request.getPartyCache();
|
||||
NullReferenceCheckHelper.throwIfNull(party_cache, () => $"Party Cache is null !! - party name:{party_attribute.PartyName}");
|
||||
|
||||
party_cache.PartyName = new_party_name;
|
||||
|
||||
if(is_upsert_cache) result = await m_party_cache_request.upsertPartyCache();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string getPartyName()
|
||||
{
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_attribute.PartyName;
|
||||
}
|
||||
|
||||
public async Task<Result> VoteParty(VoteType vote, USER_GUID voter_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. 진행 중인 Vote 확인
|
||||
if (null == party_attribute.PartyVote)
|
||||
{
|
||||
err_msg = $"Failed to reply party vote !!! - not start party vote - {party.PartyGuid}";
|
||||
result.setFail(ServerErrorCode.NoStartPartyVote, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 투표 허용 시간 확인
|
||||
var allow_vote_time = DateTime.UtcNow.AddSeconds(-1 * MetaHelper.GameConfigMeta.VoteTimeLimitSec + 5 );
|
||||
if (party_attribute.PartyVote.StartVoteTime < allow_vote_time.ToTimestamp())
|
||||
{
|
||||
err_msg = $"Failed to reply party vote !!! - already passed party vote time - {party.PartyGuid}";
|
||||
result.setFail(ServerErrorCode.AlreadyPassPartyVoteTime, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. 기 투표 여부 체크
|
||||
if (party_attribute.PartyVote.Votes.TryGetValue(voter_guid, out var saved_vote) && saved_vote != VoteType.None)
|
||||
{
|
||||
err_msg = $"Failed to reply party vote !!! - already reply party vote - {voter_guid}";
|
||||
result.setFail(ServerErrorCode.AlreadyReplyPartyVote, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
party_attribute.PartyVote.Votes[voter_guid] = vote;
|
||||
|
||||
// 4. 투표 종료 체크 ( party leader 가 있는 서버만 )
|
||||
var player_message = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (player_message.tryGetUserByPrimaryKey(party_attribute.PartyLeaderCharGuid, out _))
|
||||
{
|
||||
var is_finished = party_attribute.PartyVote.Votes.All(voted_type => voted_type.Value != VoteType.None);
|
||||
if (is_finished) m_vote_finish_task_source.TrySetResult();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var message = new ServerMessage();
|
||||
message.ReplyPartyVoteNoti = new();
|
||||
message.ReplyPartyVoteNoti.PartyGuid = party.PartyGuid;
|
||||
message.ReplyPartyVoteNoti.PartyVoterGuid = voter_guid;
|
||||
message.ReplyPartyVoteNoti.Vote = vote;
|
||||
|
||||
await PartyHelper.sendToServerByTargetClient(party_attribute.PartyLeaderCharGuid, message);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public PartyVoteInfo? getPartyVoteInfo()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_attribute.PartyVote;
|
||||
}
|
||||
|
||||
public async Task<(Result result, PartyVoteInfo? vote)> registerPartyVote(string vote_title, Timestamp start_vote_time, bool is_start)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. vote condition 체크
|
||||
result = await checkVoteCondition(party, vote_title);
|
||||
if (result.isFail()) return (result, null);
|
||||
|
||||
// 2. vote 정보 저장 : 시작시점의 유저 리스트 등록 - 추가(제외) / 감소(기권)
|
||||
var members = party_member_action.getMembers();
|
||||
var vote = new PartyVoteInfo
|
||||
{
|
||||
VoteTitle = vote_title,
|
||||
StartVoteTime = start_vote_time
|
||||
};
|
||||
foreach (var member in members)
|
||||
{
|
||||
vote.Votes.Add(member, VoteType.None);
|
||||
}
|
||||
party_attribute.PartyVote = vote;
|
||||
|
||||
// 3. cache 저장
|
||||
var cache = m_party_cache_request.getPartyCache();
|
||||
NullReferenceCheckHelper.throwIfNull(cache, () => $"Party Cache is null !! - party name:{party_attribute.PartyName} / {party.toBasicString()}");
|
||||
|
||||
cache.LastVoteTime = start_vote_time;
|
||||
party_attribute.LastVoteTime = start_vote_time;
|
||||
|
||||
if (is_start)
|
||||
{
|
||||
result = await m_party_cache_request.upsertPartyCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
party_attribute.PartyVote = null;
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
// 4. Wait Vote Task 실행 ( fire and forget )
|
||||
_ = Task.Run(waitPartyVoteFinish);
|
||||
}
|
||||
|
||||
return (result, vote);
|
||||
}
|
||||
|
||||
private async Task<Result> checkVoteCondition(GlobalPartyDetail party, string vote_title)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. vote title 길이 체크
|
||||
if (vote_title.Length > MetaHelper.GameConfigMeta.MaxVoteAgendaInput)
|
||||
{
|
||||
err_msg = $"fail to start party vote !!! : invalid vote title length - {vote_title.Length}";
|
||||
result.setFail(ServerErrorCode.InvalidPartyStringLength, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 진행 중인 Vote 체크
|
||||
if (null != party_attribute.PartyVote)
|
||||
{
|
||||
err_msg = $"Failed to start party vote !!! : exist party vote - {party_attribute.PartyVote.VoteTitle}";
|
||||
result.setFail(ServerErrorCode.AlreadyStartPartyVote, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. Last Vote Time 체크
|
||||
var last_vote_time = party_attribute.LastVoteTime ?? DateTimeHelper.MinTime.ToTimestamp();
|
||||
if (last_vote_time > DateTime.UtcNow.AddSeconds(-1 * MetaHelper.GameConfigMeta.VoteCoolTimeSec).ToTimestamp())
|
||||
{
|
||||
err_msg = $"Failed to start party vote !!! : invalid party vote time - {vote_title}";
|
||||
result.setFail(ServerErrorCode.InvalidPartyVoteTime, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
private async Task waitPartyVoteFinish()
|
||||
{
|
||||
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(MetaHelper.GameConfigMeta.VoteTimeLimitSec + 1));
|
||||
m_vote_finish_task_source = new();
|
||||
|
||||
cts.Token.Register(() => { m_vote_finish_task_source.TrySetCanceled(); });
|
||||
try
|
||||
{
|
||||
await m_vote_finish_task_source.Task;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Ignore...
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.getLogger().error($"Failed to wait party vote !!! : exception finish task - {e}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 파티 정보 획득
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
// 2. 투표 결과 수집
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 3. 결과 수집
|
||||
var agreement = party_attribute.getVoteCount(VoteType.Agreement);
|
||||
var disAgreement = party_attribute.getVoteCount(VoteType.DisAgreement);
|
||||
var abstain = party_attribute.getVoteCount(VoteType.Abstain);
|
||||
abstain += party_attribute.getVoteCount(VoteType.None);
|
||||
|
||||
// 4. 결과 통보 ( to server )
|
||||
var server_message = new ServerMessage();
|
||||
server_message.PartyVoteResultNoti = new();
|
||||
server_message.PartyVoteResultNoti.PartyGuid = party.PartyGuid;
|
||||
server_message.PartyVoteResultNoti.VoteTitle = party_attribute.PartyVote?.VoteTitle ?? string.Empty;
|
||||
server_message.PartyVoteResultNoti.ResultTrue = agreement;
|
||||
server_message.PartyVoteResultNoti.ResultFalse = disAgreement;
|
||||
server_message.PartyVoteResultNoti.Abstain = abstain;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 4. 결과 통보 ( to client )
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyVoteResultNoti = new();
|
||||
client_message.Message.PartyVoteResultNoti.VoteTitle = party_attribute.PartyVote?.VoteTitle ?? string.Empty;
|
||||
client_message.Message.PartyVoteResultNoti.ResultTrue = agreement;
|
||||
client_message.Message.PartyVoteResultNoti.ResultFalse = disAgreement;
|
||||
client_message.Message.PartyVoteResultNoti.Abstain = abstain;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
|
||||
// 5. Business Log 기록
|
||||
writeBusinessLog(party);
|
||||
|
||||
// 6. 투표 데이터 삭제
|
||||
party_attribute.PartyVote = null;
|
||||
}
|
||||
|
||||
private void writeBusinessLog(GlobalPartyDetail party)
|
||||
{
|
||||
var log_invokers = new List<ILogInvoker>(2);
|
||||
|
||||
// 1. 파티정보
|
||||
var party_log_data = PartyBusinessLogHelper.toPartyLogData(party.PartyGuid, false);
|
||||
var party_business_log = new PartyBusinessLog(party_log_data);
|
||||
log_invokers.Add(party_business_log);
|
||||
|
||||
// 2. 파티 투표 정보
|
||||
var party_vote_log = PartyBusinessLogHelper.toPartyVoteLogData(party.PartyGuid, false);
|
||||
var party_vote_business_log = new PartyVoteBusinessLog(party_vote_log);
|
||||
log_invokers.Add(party_vote_business_log);
|
||||
|
||||
BusinessLogger.collectLogs(new LogActionEx(LogActionType.EndPartyVote), party, log_invokers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailInstanceAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyInstanceCacheRequest m_party_instance_cache_request;
|
||||
|
||||
public GlobalPartyDetailInstanceAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_instance_cache_request =
|
||||
new PartyInstanceCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_instance_cache_request.keepPartyInstanceCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyInstance()
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_instance_cache_request.fetchPartyInstanceCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(attribute,
|
||||
new List<CacheBase> { m_party_instance_cache_request.getPartyInstanceCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> registerPartyInstance(int instanceId, string roomId, Timestamp startTime, Timestamp endTime, int joinCount, bool isNotify)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "global party detail is null !!!");
|
||||
|
||||
var party_instance_attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"PartyInstanceAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. cache 생성
|
||||
result = await m_party_instance_cache_request.createPartyInstanceCache(instanceId, roomId, startTime, endTime, joinCount);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 복사
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_instance_attribute,
|
||||
new List<CacheBase> { m_party_instance_cache_request.getPartyInstanceCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
if (false == isNotify) return result;
|
||||
|
||||
// 8. instance 정보 알림 ( to Servers )
|
||||
var server_message = new ServerMessage();
|
||||
server_message.PartyInstanceInfoNoti = new();
|
||||
server_message.PartyInstanceInfoNoti.PartyGuid = party.PartyGuid;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 9. instance 정보 알림 ( to Clients )
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyInstanceInfoNoti = new();
|
||||
client_message.Message.PartyInstanceInfoNoti.InstanceId = instanceId;
|
||||
client_message.Message.PartyInstanceInfoNoti.StartTime = startTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.EndTime = endTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.JoinMemberCount = joinCount;
|
||||
client_message.Message.PartyInstanceInfoNoti.IsEnd = BoolType.False;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deletePartyInstance()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_instance_cache_request.deletePartyInstanceCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 제거
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool isExist()
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return attribute.InstanceId > 0;
|
||||
}
|
||||
|
||||
public Timestamp getStartTime()
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return attribute.StartTime;
|
||||
}
|
||||
|
||||
public async Task<Result> finishPartyInstance(int joinCount = 0)
|
||||
{
|
||||
return await changePartyInstance(DateTimeHelper.MinTime.ToTimestamp(), DateTimeHelper.MinTime.ToTimestamp(), joinCount, true, true);
|
||||
}
|
||||
|
||||
public async Task<Result> changePartyInstance(Timestamp startTime, Timestamp endTime, int joinCount, bool isFinish, bool notifyStartInstance)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. cache 수정
|
||||
var cache = m_party_instance_cache_request.getPartyInstanceCache();
|
||||
NullReferenceCheckHelper.throwIfNull(cache, () => $"Party Instance Cache is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
cache.JoinMemberCount = joinCount;
|
||||
cache.StartTime = startTime;
|
||||
cache.EndTime = endTime;
|
||||
|
||||
if (isFinish)
|
||||
{
|
||||
cache.InstanceId = 0;
|
||||
cache.RoomId = string.Empty;
|
||||
}
|
||||
|
||||
result = await m_party_instance_cache_request.upsertPartyInstanceCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 수정
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.JoinMemberCount = cache.JoinMemberCount;
|
||||
attribute.StartTime = startTime;
|
||||
attribute.EndTime = endTime;
|
||||
|
||||
if (isFinish)
|
||||
{
|
||||
attribute.InstanceId = 0;
|
||||
attribute.RoomId = string.Empty;
|
||||
}
|
||||
|
||||
if (notifyStartInstance)
|
||||
{
|
||||
sendPartyInstanceInfoToMembers();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task changeJoinMemberCount(int joinCount, bool notify)
|
||||
{
|
||||
// 1. cache 수정
|
||||
var cache = m_party_instance_cache_request.getPartyInstanceCache();
|
||||
NullReferenceCheckHelper.throwIfNull(cache, () => $"Party Instance Cache is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
cache.JoinMemberCount = joinCount;
|
||||
|
||||
await m_party_instance_cache_request.upsertPartyInstanceCache();
|
||||
|
||||
// 2. attribute 수정
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.JoinMemberCount = cache.JoinMemberCount;
|
||||
|
||||
if (notify)
|
||||
{
|
||||
sendPartyInstanceInfoToMembers();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPartyInstanceInfoToMembers()
|
||||
|
||||
{
|
||||
// 1. server message
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "Party Detail is null");
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var server_message = new ServerMessage();
|
||||
server_message.PartyInstanceInfoNoti = new();
|
||||
server_message.PartyInstanceInfoNoti.PartyGuid = party.PartyGuid;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 2. client message
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyInstanceInfoNoti = new();
|
||||
client_message.Message.PartyInstanceInfoNoti.InstanceId = attribute.InstanceId;
|
||||
client_message.Message.PartyInstanceInfoNoti.JoinMemberCount = attribute.JoinMemberCount;
|
||||
client_message.Message.PartyInstanceInfoNoti.StartTime = attribute.StartTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.EndTime = attribute.EndTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.IsEnd = attribute.InstanceId == 0 ? BoolType.True : BoolType.False;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
}
|
||||
}
|
||||
548
GameServer/Entity/Party/Action/GlobalPartyDetailMemberAction.cs
Normal file
548
GameServer/Entity/Party/Action/GlobalPartyDetailMemberAction.cs
Normal file
@@ -0,0 +1,548 @@
|
||||
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<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_member_cache_request.keepPartyMemberCache();
|
||||
}
|
||||
|
||||
public PartyMemberInfo? getMember(USER_GUID user_guid)
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_member_attribute.getPartyMembers().GetValueOrDefault(user_guid);
|
||||
}
|
||||
public IEnumerable<USER_GUID> getMembers()
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<Result> loadPartyMember()
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
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<CacheBase> { m_party_member_cache_request.getPartyMemberCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<PartyMemberState> getMembers4PartyInfo()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_member_attribute = party.getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var states = new List<PartyMemberState>();
|
||||
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<string> { user.UserGuid });
|
||||
|
||||
return (change.result, false);
|
||||
}
|
||||
|
||||
public async Task<Result> 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<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<Result> 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<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<string> getSummonMembers()
|
||||
{
|
||||
var member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<Result> 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<PartyMemberAttribute>();
|
||||
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<PartyMemberAttribute>();
|
||||
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<GlobalPartyDetailAction>();
|
||||
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<LocationAction>()?.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<GlobalPartyDetailAction>();
|
||||
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<InventoryActionBase>();
|
||||
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<string>());
|
||||
}
|
||||
}
|
||||
144
GameServer/Entity/Party/Action/GlobalPartyDetailServerAction.cs
Normal file
144
GameServer/Entity/Party/Action/GlobalPartyDetailServerAction.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailServerAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyServerCacheRequest m_party_server_cache_request;
|
||||
|
||||
public GlobalPartyDetailServerAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_server_cache_request =
|
||||
new PartyServerCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_server_cache_request.keepPartyServerCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyServer()
|
||||
{
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_server_cache_request.fetchPartyServerCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_server_attribute, new List<CacheBase> { m_party_server_cache_request.getPartyServerCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<string> getServers()
|
||||
{
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_server_attribute.getPartyServers().ToList();
|
||||
}
|
||||
|
||||
public async Task<Result> addPartyServer(string addServerName)
|
||||
{
|
||||
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_server_cache_request.addPartyServerCache(addServerName);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
party_server_attribute.addPartyServer(addServerName);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deletePartyServer(string delete_server_name)
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_server_cache_request.deletePartyServerCache(delete_server_name);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 수정
|
||||
var attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.deleteServer(delete_server_name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteAllPartyServers()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_server_cache_request.deleteAllPartyServerCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 수정
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_server_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> notifyChangePartyServerToServers(BoolType isAddition, string srcServerName)
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"party deltail is null !!!");
|
||||
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var rabbit_mq = GameServerApp.getServerLogic().getRabbitMqConnector() as RabbitMqConnector;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit mq is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var message = new ServerMessage
|
||||
{
|
||||
ChangePartyServerNameNoti = new()
|
||||
{
|
||||
PartyGuid = party.PartyGuid,
|
||||
IsAddition = isAddition,
|
||||
ServerName = srcServerName
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var dest_server in party_server_attribute.getPartyServers())
|
||||
{
|
||||
if (srcServerName == dest_server) continue;
|
||||
rabbit_mq.SendMessage(dest_server, message);
|
||||
}
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using PARTY_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyInvitePartySendAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyInvitePartySendCacheRequest m_party_invite_party_send_cache_request;
|
||||
|
||||
public GlobalPartyInvitePartySendAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_invite_party_send_cache_request =
|
||||
new PartyInvitePartySendCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_invite_party_send_cache_request.keepInvitePartySendCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyInvitePartySend(PARTY_GUID party_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
if (PARTY_GUID.IsNullOrEmpty(party_guid))
|
||||
{
|
||||
var err_msg = $"Fail to load party invite party send !!! : argument is null - {nameof(loadPartyInvitePartySend)}";
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
result = await m_party_invite_party_send_cache_request.fetchInvitePartySendCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_invite_party_send, new List<CacheBase> { m_party_invite_party_send_cache_request.getPartyInvitePartySendCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteInvitePartySends()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_invite_party_send_cache_request.deleteAllInvitePartySendCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 수정
|
||||
var party_invite_send_attribute = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_send_attribute, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_invite_send_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteInvitePartySend(USER_GUID invitee_guid)
|
||||
{
|
||||
// 1. attribute 수정
|
||||
var party_invite_send_attribute = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_send_attribute, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_invite_send_attribute.deleteInvitePartySend(invitee_guid);
|
||||
|
||||
// 2. cache 에서 제거
|
||||
var result = await m_party_invite_party_send_cache_request.deleteInvitePartySendCache(new List<string> { invitee_guid });
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> isExistCheck(string user_guid)
|
||||
{
|
||||
await organizeSendAttribute();
|
||||
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var sends = party_invite_party_send.getPartyInvitePartySends();
|
||||
return sends.Any(send => send.Key == user_guid);
|
||||
}
|
||||
|
||||
public async Task<int> getInviteSendsCount()
|
||||
{
|
||||
var list = await getPartyInvitePartySends();
|
||||
return list.Count;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, DateTime>> getPartyInvitePartySends()
|
||||
{
|
||||
await organizeSendAttribute();
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var sends = attribute.getPartyInvitePartySends();
|
||||
var list = sends.ToDictionary(send => send.Key, send => send.Value);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<Result> sendInviteParty(IReadOnlyDictionary<string, string>? invite_users)
|
||||
{
|
||||
var result = new Result();
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !! ");
|
||||
|
||||
var send_users = invite_users?.Select(invitee => invitee.Key).ToList();
|
||||
if (null == send_users)
|
||||
{
|
||||
var err_msg = $"Failed to send invite party !!! : invite_users is null - {nameof(sendInviteParty)}";
|
||||
result.setFail(ServerErrorCode.FailToSendInviteMember, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. redis 저장
|
||||
result = await m_party_invite_party_send_cache_request.addInvitePartySendCache(send_users);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. attribute 변경
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
party_invite_party_send.addInvitePartySends(send_users);
|
||||
|
||||
// 1. mq message 생성
|
||||
var message = new ServerMessage();
|
||||
message.InvitePartyNoti = new();
|
||||
message.InvitePartyNoti.InvitePartyLeaderGuid = getPartyLeaderGuid();
|
||||
message.InvitePartyNoti.InvitePartyGuid = party.PartyGuid;
|
||||
|
||||
var rabbit_mq = GameServerApp.getServerLogic().getRabbitMqConnector() as RabbitMqConnector;
|
||||
ArgumentNullException.ThrowIfNull(rabbit_mq);
|
||||
|
||||
// 4. invite 유저에게 메시지 전달
|
||||
NullReferenceCheckHelper.throwIfNull(invite_users, () => $"party invite users is null !!! - {party.toBasicString()}");
|
||||
foreach (var invitee in invite_users)
|
||||
{
|
||||
message.InvitePartyNoti.InviteUserGuid = invitee.Key;
|
||||
rabbit_mq.SendMessage(invitee.Value, message);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private USER_GUID getPartyLeaderGuid()
|
||||
{
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderCharGuid;
|
||||
}
|
||||
|
||||
private async Task organizeSendAttribute()
|
||||
{
|
||||
var delete_sends = await m_party_invite_party_send_cache_request.organizeInvitePartySendCache();
|
||||
if (null == delete_sends) return;
|
||||
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_invite_party_send.deleteInvitePartySends(delete_sends);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user