초기커밋
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user