1357 lines
57 KiB
C#
1357 lines
57 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using ServerCore;
|
|
using ServerBase;
|
|
using ServerCommon;
|
|
using MetaAssets;
|
|
|
|
|
|
namespace GameServer;
|
|
|
|
public class QuestCheckReferrence
|
|
{
|
|
public int m_quest_id { get; set; } = 0;
|
|
public QuestBaseInfo? m_quest_meta_info_nullable { get; set; } = null;
|
|
public ServerCommon.Quest? m_quest_nullable { get; set; } = null;
|
|
|
|
public List<Item> m_rewardable_items { get; set; } = new();
|
|
public List<Item> m_deletable_items { get; set; } = new();
|
|
|
|
public List<MetaAssets.Reward> m_rewared_money { get; set; } = new();
|
|
public List<Item> m_rewarded_items { get; set; } = new();
|
|
}
|
|
|
|
public class QuestManager : Singleton<QuestManager>
|
|
{
|
|
public QuestManager()
|
|
{
|
|
Load();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 퀘스트 활성화가 되기 위한 타입별로 저장
|
|
/// 캐릭터 생성시, 특정퀘스트 완료시
|
|
/// </summary>
|
|
public Dictionary<string, HashSet<UInt32>> _QuestReqTypeGroup = new();
|
|
|
|
/// <summary>
|
|
/// 퀘스트 활성화가 되기 위한 값별로 정보저장
|
|
/// 특정퀘스트 완료시에만 의미가 있으며 QuesId 기준으로 정리해서 저장
|
|
/// NORAM 은 반복수 행 처리를 위해 해당 리스트에서 제외
|
|
/// </summary>
|
|
public Dictionary<UInt32, HashSet<UInt32>> _QuestReqValueGroup = new();
|
|
|
|
/// <summary>
|
|
/// Normal 퀘스트만 저장. 반복 수행을 위함
|
|
/// </summary>
|
|
public Dictionary<UInt32, HashSet<UInt32>> _QuestNormalGroup = new();
|
|
|
|
/// <summary>
|
|
/// requirementType 이 DailyUniqueLogin 인것과 OncePeriodRange가 Daily 인것만 저장
|
|
/// </summary>
|
|
public HashSet<UInt32> _DailyQuestQuestGroup = new();
|
|
|
|
/// <summary>
|
|
/// OncePeriodRange가 Weekly 인것만 저장
|
|
/// </summary>
|
|
public HashSet<UInt32> _WeeklyQuestQuestGroup = new();
|
|
|
|
/// <summary>
|
|
/// OncePeriodRange가 Monthly 인것만 저장
|
|
/// </summary>
|
|
public HashSet<UInt32> _MonthlyQuestQuestGroup = new();
|
|
|
|
/// <summary>
|
|
/// Dialoque 에 따른 퀘스트 정보
|
|
/// </summary>
|
|
public Dictionary<(string, string), HashSet<UInt32>> _QuestDialogueGroup = new();
|
|
|
|
|
|
/// <summary>
|
|
/// 타이머 체크 필요한 유저
|
|
/// </summary>
|
|
public ConcurrentDictionary<string, string> m_timer_check_users { get; set; } = new();
|
|
|
|
public ConcurrentDictionary<string, int> m_normal_quest_check_users { get; set; } = new();
|
|
|
|
public void Load()
|
|
{
|
|
foreach (var questData in MetaData.Instance._QuestBaseinfoTable.Values)
|
|
{
|
|
if (_QuestReqTypeGroup.TryGetValue(questData.RequirementType, out var outTypeList) == false)
|
|
{
|
|
outTypeList = new HashSet<UInt32>();
|
|
}
|
|
|
|
outTypeList.Add(questData.QuestId);
|
|
_QuestReqTypeGroup.TryAdd(questData.RequirementType, outTypeList);
|
|
|
|
if (_QuestReqValueGroup.TryGetValue(questData.RequirementValue, out var outValueList) == false)
|
|
{
|
|
outValueList = new HashSet<UInt32>();
|
|
}
|
|
|
|
outValueList.Add(questData.QuestId);
|
|
if (!questData.QuestType.Equals(EQuestType.NORMAL.ToString()))
|
|
{
|
|
_QuestReqValueGroup.TryAdd(questData.RequirementValue, outValueList);
|
|
}
|
|
else
|
|
{
|
|
normalQuestLoad(questData);
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!questData.Dialogue.Equals(string.Empty))
|
|
{
|
|
if (_QuestDialogueGroup.TryGetValue((questData.Dialogue, questData.DialogueResult),
|
|
out var outDialugueQuestList) == false)
|
|
{
|
|
outDialugueQuestList = new();
|
|
}
|
|
|
|
outDialugueQuestList.Add(questData.QuestId);
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
private void normalQuestLoad(QuestBaseInfo questData)
|
|
{
|
|
|
|
UInt32 requireValue = 0;
|
|
if (questData.RequirementType.Equals(EAssignRequireType.PlayerInitial.ToString())) requireValue = 0;
|
|
else requireValue = questData.RequirementValue;
|
|
|
|
addNormalList(questData, requireValue);
|
|
|
|
addPeriodList(questData);
|
|
|
|
}
|
|
|
|
private void addPeriodList(QuestBaseInfo questData)
|
|
{
|
|
if (questData.OncePeriodRangeType.Equals(OncePeriodRangeType.Daily))
|
|
{
|
|
if (false == questData.NormalPoolActive)
|
|
{
|
|
_DailyQuestQuestGroup.Add(questData.QuestId);
|
|
}
|
|
}
|
|
else if(questData.OncePeriodRangeType.Equals(OncePeriodRangeType.Weekly) && questData.NormalPoolActive == false)
|
|
{
|
|
_WeeklyQuestQuestGroup.Add(questData.QuestId);
|
|
}
|
|
else if(questData.OncePeriodRangeType.Equals(OncePeriodRangeType.Monthly) && questData.NormalPoolActive == false)
|
|
{
|
|
_MonthlyQuestQuestGroup.Add(questData.QuestId);
|
|
}
|
|
}
|
|
|
|
private void addNormalList(QuestBaseInfo questData, UInt32 requireValue)
|
|
{
|
|
if (requireValue == 0) return;
|
|
|
|
if (_QuestNormalGroup.TryGetValue(requireValue, out var outNormalList) == false)
|
|
{
|
|
outNormalList = new HashSet<UInt32>();
|
|
}
|
|
|
|
if (questData.RequirementType.Equals(EAssignRequireType.PlayerInitial.ToString()))
|
|
{
|
|
if (questData.OncePeriodRangeType.Equals(OncePeriodRangeType.Nolimit))
|
|
{
|
|
outNormalList.Add(questData.QuestId);
|
|
_QuestNormalGroup.TryAdd(requireValue, outNormalList);
|
|
}
|
|
else
|
|
{
|
|
//기간 반복 메일인데 NormalPoolActive 가 true면 반복메일에서 제외하고 노멀 메일로 넣는다.
|
|
if (questData.NormalPoolActive)
|
|
{
|
|
outNormalList.Add(questData.QuestId);
|
|
_QuestNormalGroup.TryAdd(requireValue, outNormalList);
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (questData.RequirementType.Equals(EAssignRequireType.Quest_Complete.ToString()))
|
|
{
|
|
if (questData.OncePeriodRangeType.Equals(OncePeriodRangeType.Nolimit))
|
|
{
|
|
outNormalList.Add(questData.QuestId);
|
|
_QuestNormalGroup.TryAdd(requireValue, outNormalList);
|
|
}
|
|
else
|
|
{
|
|
//기간 반복 메일인데 NormalPoolActive 가 true면 반복메일에서 제외하고 노멀 메일로 넣는다.
|
|
if (questData.NormalPoolActive)
|
|
{
|
|
outNormalList.Add(questData.QuestId);
|
|
_QuestNormalGroup.TryAdd(requireValue, outNormalList);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public async Task<Result> QuestCheckOneByOne(Player player, IQuest quest_base, ServerCommon.Quest quest,
|
|
bool hasTransaction)
|
|
{
|
|
//todo : 성눙 안좋다. 바꾸는게 좋다...
|
|
var quest_attribute = quest.getEntityAttribute<QuestAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(quest_attribute, () => $"quest_attribute is null !!!");
|
|
var quest_id = quest_attribute.QuestId;
|
|
var quest_revision = quest_attribute.UgqInfo.QuestRevision;
|
|
QuestTaskUpdateHandler quest_update_handler = new(player, quest_id, quest_revision, "");
|
|
var result = await quest_update_handler.init(player, quest);
|
|
if (result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
result = await QuestCheckOne(player, quest_base, hasTransaction, quest_update_handler);
|
|
if (result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (quest_update_handler.m_need_counter_check)
|
|
{
|
|
QuestTaskUpdateHandler sequential_quest_update_handler = new(player, quest_id, quest_revision, $"{EQuestEventTargetType.COUNTER.ToString()}{EQuestEventNameType.MAX.ToString()}");
|
|
result = await sequential_quest_update_handler.init(player, quest);
|
|
if (result.isFail()) return result;
|
|
IQuest sequential_quest_base = new QuestCount(EQuestEventTargetType.COUNTER, EQuestEventNameType.MAX);
|
|
await QuestSequentialCheck(player, sequential_quest_base, hasTransaction,
|
|
sequential_quest_update_handler);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<Result> QuestSequentialCheck(Player player, IQuest quest_base, bool hasTransaction,
|
|
QuestTaskUpdateHandler questUpdateHandler)
|
|
{
|
|
var result = await QuestCheckOne(player, quest_base, hasTransaction, questUpdateHandler);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
public async Task<Result> QuestCheckOne(Player player, IQuest quest_base, bool hasTransaction,
|
|
QuestTaskUpdateHandler questUpdateHandler)
|
|
{
|
|
ArgumentNullReferenceCheckHelper.throwIfNull(questUpdateHandler.m_quest_meta_info, () => $"questUpdateHandler.m_quest_meta_info is null !!!");
|
|
|
|
var result = new Result();
|
|
NullReferenceCheckHelper.throwIfNull(questUpdateHandler.m_quest, () => $"questUpdateHandler.m_quest is null !!!");
|
|
var quest_attribute = questUpdateHandler.m_quest.getEntityAttribute<QuestAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(quest_attribute, () => $"quest_attribute is null !!!");
|
|
var quest_id = questUpdateHandler.m_quest_id;
|
|
var quest_revision = quest_attribute.UgqInfo.QuestRevision;
|
|
|
|
if (false == questUpdateHandler.m_quest_meta_info.QuestTaskGroupList.TryGetValue(
|
|
quest_attribute.CurrentTaskNum, out var quest_task_info))
|
|
{
|
|
var err_msg =
|
|
$"quest_task_info not found. quest_id : {quest_id}, quest_attribute.CurrentTaskNum : {quest_attribute.CurrentTaskNum}";
|
|
result.setFail(ServerErrorCode.QuestInvalidTaskNum, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
return result;
|
|
}
|
|
|
|
questUpdateHandler.m_quest_task_group = quest_task_info;
|
|
|
|
List<string> active_events = new();
|
|
active_events.AddRange(quest_attribute.ActiveEvents);
|
|
|
|
bool is_valid = false;
|
|
foreach (var active_event in active_events)
|
|
{
|
|
if (quest_attribute.IsComplete == 1) break;
|
|
|
|
questUpdateHandler.m_active_event = new(active_event);
|
|
|
|
if (false == quest_task_info.QuestEventGroupByEventString.TryGetValue(active_event,
|
|
out var quest_event_info))
|
|
{
|
|
var err_msg =
|
|
$"QuestEventGroupByEventString not found. quest_id : {quest_id}, event_str : {active_event}";
|
|
result.setFail(ServerErrorCode.QuestInvalidValue, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
break;
|
|
}
|
|
|
|
is_valid = quest_base.checkValidTaskScript(quest_attribute, questUpdateHandler);
|
|
if (is_valid)
|
|
{
|
|
if (hasTransaction)
|
|
{
|
|
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents,
|
|
"QuestCheckAndTaskUpdate", delegateQuestCheckAndTaskUpdate);
|
|
|
|
Task<Result> delegateQuestCheckAndTaskUpdate() =>
|
|
questCheckAndTaskUpdate(player, quest_base, questUpdateHandler, hasTransaction);
|
|
}
|
|
else
|
|
{
|
|
result = await questCheckAndTaskUpdate(player, quest_base, questUpdateHandler, hasTransaction);
|
|
}
|
|
|
|
if (result.isFail())
|
|
{
|
|
string err_msg =
|
|
$"Failed to questCheckAndTaskUpdate()!!! : {result.toBasicString()} - {player.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
return result;
|
|
}
|
|
|
|
await quest_base.postProcess(player, questUpdateHandler);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// rank 누적 ( ugcNpc 제공 ugq quest 만 )
|
|
if (is_valid && quest_attribute.UgqInfo.QuestRevision > 0 && quest_attribute.IsComplete == 1)
|
|
{
|
|
var ugq_info_action = player.getEntityAction<UgqInfoAction>();
|
|
|
|
(result, var quest_meta_all_base_info) = await QuestMetaManager.It.getQuestMeta(player,
|
|
quest_attribute.QuestId, quest_attribute.UgqInfo.QuestRevision, quest_attribute.UgqInfo.UqgState);
|
|
if (result.isFail()) return result;
|
|
var game_quest_data = quest_meta_all_base_info.m_quest_data_entity;
|
|
NullReferenceCheckHelper.throwIfNull(game_quest_data, () => $"game_quest_data is null !!!");
|
|
|
|
if (string.IsNullOrEmpty(game_quest_data.UgcBeaconGuid)) return result;
|
|
|
|
var rank_entity = GameServerApp.getServerLogic().findGlobalEntity<UgcNpcRankEntity>();
|
|
NullReferenceCheckHelper.throwIfNull(rank_entity, () => $"rank_entity is null !!!");
|
|
var quest_rank_action = rank_entity.getEntityAction<UgcNpcQuestRankAction>();
|
|
|
|
NullReferenceCheckHelper.throwIfNull(quest_rank_action, () => $"quest_rank_action is null !!!");
|
|
|
|
await quest_rank_action.setRankScore(player.getUserGuid(), game_quest_data.UserGuid,
|
|
game_quest_data.UgcBeaconGuid, true);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<Result> questCheckAndTaskUpdate(Player player, IQuest questBase,
|
|
QuestTaskUpdateHandler questTaskUpdateHandler, bool hasTransaction)
|
|
{
|
|
var quest = questTaskUpdateHandler.m_quest;
|
|
NullReferenceCheckHelper.throwIfNull(quest, () => $"quest is null !!!");
|
|
var quest_attribute = quest.getEntityAttribute<QuestAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(quest_attribute, () => $"quest_attribute is null !!!");
|
|
|
|
//해당 태스크 달성 했으므로 다음 펑션 처리
|
|
var result = questBase.questTaskFunctionProgress(player, ref questTaskUpdateHandler);
|
|
if (result.isFail()) return result;
|
|
|
|
if (quest_attribute.CurrentTaskComplete == 1)
|
|
{
|
|
result = QuestNextTaskUpdate(quest_attribute, ref questTaskUpdateHandler);
|
|
if (result.isFail()) return result;
|
|
}
|
|
|
|
quest_attribute.modifiedEntityAttribute();
|
|
|
|
//보상 줄게 있으면 보상처리
|
|
IReward reward_base = new RewardQuestTask(player, questTaskUpdateHandler);
|
|
//보상 주다 아이템 풀차면 풀찼다고 예외 처리 20240828
|
|
result = await RewardManager.It.proceedRewardProcess(reward_base);
|
|
if (result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var inventory_action = player.getEntityAction<InventoryActionBase>();
|
|
//삭제할게 있으면 삭체 처리
|
|
foreach (var delete_item in questTaskUpdateHandler.m_deletable_items)
|
|
{
|
|
var item_id = delete_item.Key;
|
|
var delete_count = delete_item.Value;
|
|
(result, var found_delete_item) =
|
|
await inventory_action.tryDeleteItemByMetaId((uint)item_id, (ushort)delete_count);
|
|
if (result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
questTaskUpdateHandler.m_deleted_items.AddRange(found_delete_item);
|
|
}
|
|
|
|
var common_result = new CommonResult();
|
|
if (hasTransaction)
|
|
{
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.QuestMainTask, server_logic.getDynamoDbClient());
|
|
{
|
|
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
|
}
|
|
questTaskUpdateHandler.m_log_invokers.Add(new QuestTaskUpdateBusinessLog(questTaskUpdateHandler));
|
|
batch.appendBusinessLogs(questTaskUpdateHandler.m_log_invokers);
|
|
|
|
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
|
if (result.isFail()) return result;
|
|
|
|
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
|
|
NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () =>
|
|
$"found_transaction_runner is null !!! - {player.toBasicString()}");
|
|
common_result = found_transaction_runner.getCommonResult();
|
|
}
|
|
|
|
//여기서 QuestUpdateNoti 보낸다.
|
|
await player.send_GS2C_NTF_QUEST_UPDATE(quest_attribute.QuestId, quest_attribute.UgqInfo.QuestRevision,
|
|
common_result, false);
|
|
|
|
|
|
await checkLastFunction(player, questTaskUpdateHandler);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
public async Task<Result> checkLastFunction(Player player, QuestTaskUpdateHandler questTaskUpdateHandler)
|
|
{
|
|
var result = new Result();
|
|
|
|
var quest_accep_action = player.getEntityAction<QuestAcceptAction>();
|
|
foreach (var last_check_func in questTaskUpdateHandler.m_last_check_functions)
|
|
{
|
|
if (last_check_func.FunctionTarget.Equals(nameof(EQuestFunctionTargetType.QUEST)) &&
|
|
last_check_func.FunctionName.Equals(nameof(EQuestFunctionNameType.ASSIGN)))
|
|
{
|
|
var new_quest_id = uint.Parse(last_check_func.FunctionCondition1);
|
|
|
|
(result, var quest) = await quest_accep_action.questAcceptWithTransaction(new_quest_id, 0, 0);
|
|
}
|
|
else if (last_check_func.FunctionTarget.Equals(nameof(EQuestFunctionTargetType.PROP)) &&
|
|
last_check_func.FunctionName.Equals(nameof(EQuestFunctionNameType.SWITCH)))
|
|
{
|
|
var prop_id = int.Parse(last_check_func.FunctionCondition1);
|
|
var prop_state = int.Parse(last_check_func.FunctionCondition2);
|
|
var switching_prop_action = player.getEntityAction<SwitchingPropAction>();
|
|
|
|
await switching_prop_action.updateSwitchingProp(questTaskUpdateHandler, prop_id, prop_state);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task checkNotifyByServerChange(Player player, QuestTaskUpdateHandler questTaskUpdateHandler,
|
|
string activeEvent)
|
|
{
|
|
if (activeEvent.Contains(EQuestEventTargetType.INTERIORMODE.ToString() +
|
|
EQuestEventNameType.STOPPED.ToString()))
|
|
{
|
|
await QuestNotifyHelper.sendRedisQuestNotifyRequest(player, questTaskUpdateHandler);
|
|
}
|
|
}
|
|
|
|
|
|
public async Task<Result> QuestCheck(Player player, IQuest quest)
|
|
{
|
|
var quest_action = player.getEntityAction<QuestAction>();
|
|
var quests = quest_action.getQuests();
|
|
|
|
var result = new Result();
|
|
foreach (var curr_quest in quests.Values)
|
|
{
|
|
result = await QuestCheckOneByOne(player, quest, curr_quest, true);
|
|
if (result.isFail())
|
|
{
|
|
var err_msg = $"quest fail : {JsonConvert.SerializeObject(curr_quest)}";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<Result> QuestCheckWithoutTransaction(Player player, IQuest quest)
|
|
{
|
|
var quest_action = player.getEntityAction<QuestAction>();
|
|
var quests = quest_action.getQuests();
|
|
|
|
var result = new Result();
|
|
foreach (var curr_quest in quests.Values)
|
|
{
|
|
result = await QuestCheckOneByOne(player, quest, curr_quest, false);
|
|
if (result.isFail())
|
|
{
|
|
var err_msg = $"quest fail : {JsonConvert.SerializeObject(curr_quest)}";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
private void collectQuestTaskLog(object player, IReward reward_proc, UserQuestInfo userQuest,
|
|
List<RewardMetaData> rewardDatas, Dictionary<string, string> deleteItem)
|
|
{
|
|
// int quest_id = userQuest.m_quest_id;
|
|
// int task_num = userQuest.m_current_task_num;
|
|
// int is_complete = userQuest.m_is_complete;
|
|
// collectQuestTaskLog(player, reward_proc, quest_id, task_num, is_complete, rewardDatas, deleteItem);
|
|
|
|
}
|
|
|
|
private void collectQuestTaskLog(object player, IReward reward_proc, int questId, int taskNum, int isComplete,
|
|
List<RewardMetaData> rewardData, Dictionary<string, string> deleteItem)
|
|
{
|
|
// List<ILogInvoker> logInvokers = new List<ILogInvoker>();
|
|
//
|
|
// if (!TableData.Instance._QuestBaseinfoTable.TryGetValue(questId, out var questBaseInfo))
|
|
// {
|
|
// Log.getLogger().error($"collectQuestTaskLogs _QuestScriptDataTable InvalidData questId : {questId}");
|
|
// return;
|
|
// }
|
|
//
|
|
// if (!questBaseInfo.QuestTaskGroupList.TryGetValue(taskNum, out var taskGroup))
|
|
// {
|
|
// Log.getLogger().error($"collectQuestTaskLogs QuestTaskGroupList InvalidData task_num : {taskNum}");
|
|
// return;
|
|
// }
|
|
//
|
|
// QuestMainRewardLogInfo loginfo = new QuestMainRewardLogInfo(questId, questBaseInfo.AssignableQuestsAfterEnd, taskNum, taskGroup.NextTaskNum, isComplete, rewardData, deleteItem);
|
|
// ILogInvoker questRewardInvoker = new QuestRewardBusinessLog(loginfo);
|
|
// logInvokers.Add(questRewardInvoker);
|
|
// logInvokers.AddRange(reward_proc.getCurrencyLogInvokers());
|
|
// logInvokers.AddRange(reward_proc.getItemLogInvokers());
|
|
// logInvokers.AddRange(reward_proc.getItemDeleteInvokers());
|
|
//
|
|
// var log_action = new LogAction(LogActionType.QuestMainTask);
|
|
// BusinessLogger.collectLogs(log_action, player, logInvokers);
|
|
|
|
}
|
|
|
|
|
|
|
|
//QuestCheck 랑 분리 (QuestTaskUpdateReq를 위한 코드 - 나중에 일반화 필요)
|
|
// internal ServerErrorCode QuestTaskCheck(object player, UserQuestInfo userQuestInfo, QuestBaseInfo dbQuestInfo, QuestTaskGroup questTaskInfo, int activeIdx, IQuest quest,
|
|
// ref QuestListEntity newQuestListEntity,
|
|
// ref ConcurrentDictionary<ERewardType, Document> rewardDocument,
|
|
// ref List<ItemEntity> itemEntityList,
|
|
// ref List<RewardData> rewards)
|
|
// {
|
|
// //내 퀘스트 정보에 현재 활성화 중인 태스크 돌면서 체크
|
|
// // ServerErrorCode errorCode = ServerErrorCode.Success;
|
|
// //
|
|
// // int quest_id = userQuestInfo.m_quest_id;
|
|
// //
|
|
// // //해당 태스크 달성 했으므로 다음 태스크 따라간다.
|
|
// // errorCode = quest.questTaskFunctionProgress(player.accountId, dbQuestInfo, ref userQuestInfo, questTaskInfo, activeIdx, out var rewardList, out var deletedItems);
|
|
// // if (errorCode != ServerErrorCode.Success)
|
|
// // {
|
|
// // Log.getLogger().error($"questTaskNextProgress return false accountId : {player.accountId}, questId : {quest_id}, idx : {activeIdx}");
|
|
// // return ServerErrorCode.QuestInvalidValue;
|
|
// // }
|
|
// //
|
|
// // rewards.AddRange(rewardList);
|
|
// //
|
|
// // if (userQuestInfo.m_is_current_task_complete == 1)
|
|
// // {
|
|
// // errorCode = QuestNextTaskUpdate(dbQuestInfo, userQuestInfo, quest_id, questTaskInfo);
|
|
// // if (errorCode != ServerErrorCode.Success) return errorCode;
|
|
// // }
|
|
// // Dictionary<int, Dictionary<string, string>> delete_items= new();
|
|
// // delete_items.TryAdd(quest_id, deletedItems);
|
|
// //
|
|
// // Dictionary<int, List<RewardData>> reward_dictionary = new();
|
|
// // reward_dictionary.TryAdd(quest_id, rewards);
|
|
// //
|
|
// // List<int> update_quest_ids = new() { quest_id };
|
|
// // (_, IReward reward_proc) = save(player, update_quest_ids, newQuestListEntity, reward_dictionary, delete_items);
|
|
// // itemEntityList = reward_proc.getItemEntities();
|
|
// //
|
|
// // collectQuestTaskLog(player, reward_proc, userQuestInfo, rewards, deletedItems);
|
|
//
|
|
// return ServerErrorCode.Success;
|
|
// }
|
|
|
|
// internal ServerErrorCode QuestTaskCheckWithEventString(object player, UserQuestInfo userQuestInfo, QuestBaseInfo dbQuestInfo, QuestTaskGroup questTaskInfo, string activeEvent, IQuest quest,
|
|
// ref QuestListEntity newQuestListEntity,
|
|
// ref ConcurrentDictionary<ERewardType, Document> rewardDocument,
|
|
// ref List<ItemEntity> itemEntityList,
|
|
// ref List<RewardData> rewards)
|
|
// {
|
|
// //내 퀘스트 정보에 현재 활성화 중인 태스크 돌면서 체크
|
|
// // ServerErrorCode errorCode = ServerErrorCode.Success;
|
|
// //
|
|
// // int quest_id = userQuestInfo.m_quest_id;
|
|
//
|
|
// //해당 태스크 달성 했으므로 다음 태스크 따라간다.
|
|
// // errorCode = quest.questTaskFunctionProgressWithEventString(player.accountId, dbQuestInfo, ref userQuestInfo, questTaskInfo, activeEvent, out var rewardList, out var deletedItems);
|
|
// // if (errorCode != ServerErrorCode.Success)
|
|
// // {
|
|
// // Log.getLogger().error($"questTaskNextProgress return false accountId : {player.accountId}, questId : {quest_id}, activeEvent : {activeEvent}");
|
|
// // return ServerErrorCode.QuestInvalidValue;
|
|
// // }
|
|
//
|
|
// rewards.AddRange(rewardList);
|
|
//
|
|
// if (userQuestInfo.m_is_current_task_complete == 1 && userQuestInfo.m_is_complete == 0)
|
|
// {
|
|
// errorCode = QuestNextTaskUpdate(dbQuestInfo, userQuestInfo, quest_id, questTaskInfo);
|
|
// if (errorCode != ServerErrorCode.Success) return errorCode;
|
|
// }
|
|
//
|
|
// Dictionary<int, Dictionary<string, string>> delete_items = new();
|
|
// delete_items.TryAdd(quest_id, deletedItems);
|
|
//
|
|
// Dictionary<int, List<RewardData>> reward_dictionary = new();
|
|
// reward_dictionary.TryAdd(quest_id, rewards);
|
|
//
|
|
// List<int> update_quest_ids = new() { quest_id };
|
|
// (_, IReward reward_proc) = save(player, update_quest_ids, newQuestListEntity, reward_dictionary, delete_items);
|
|
// itemEntityList = reward_proc.getItemEntities();
|
|
//
|
|
// collectQuestTaskLog(player, reward_proc, userQuestInfo, rewards, deletedItems);
|
|
//
|
|
// return ServerErrorCode.Success;
|
|
// }
|
|
|
|
|
|
// internal async Task cheatQuestCheck(object player, IQuest quest, int questId)
|
|
// {
|
|
|
|
// QuestListEntity newQuestListEntity = new QuestListEntity(player.ownedQuestList.questListEntity.DocumentForUpdate());
|
|
//
|
|
// List<RewardData> rewards = new List<RewardData>();
|
|
// ServerErrorCode error_code = ServerErrorCode.Success;
|
|
//
|
|
// if (!newQuestListEntity.Quests.TryGetValue(questId, out var userQuestInfo))
|
|
// {
|
|
// Log.getLogger().error($"userQuestInfo is null questId : {questId}, player : {player.accountId}");
|
|
// return;
|
|
// }
|
|
//
|
|
// if (!TableData.Instance._QuestBaseinfoTable.TryGetValue(questId, out var dbQuestInfo))
|
|
// {
|
|
// Log.getLogger().error($"_QuestScriptDataTable InvalidData questId : {questId}");
|
|
// return;
|
|
// }
|
|
// if (!dbQuestInfo.QuestTaskGroupList.TryGetValue(userQuestInfo.m_current_task_num, out var dbQuestTaskInfo))
|
|
// {
|
|
// Log.getLogger().error($"questTaskInfo InvalidData CurrentTaskNum : {userQuestInfo.m_current_task_num}, questId : {questId}");
|
|
// return;
|
|
// }
|
|
//
|
|
// if (userQuestInfo.m_active_idx_list.Count == 0)
|
|
// {
|
|
// Log.getLogger().error($"m_active_idx_list count zero : {userQuestInfo.m_current_task_num}, questId : {questId}");
|
|
// return;
|
|
// }
|
|
//
|
|
// //다음 태스크 따라간다.
|
|
// error_code = quest.questTaskFunctionProgress(player.accountId, dbQuestInfo, ref userQuestInfo, dbQuestTaskInfo, userQuestInfo.m_active_idx_list.First(), out var rewardList, out var deletedItems);
|
|
// if(error_code != ServerErrorCode.Success)
|
|
// {
|
|
// Log.getLogger().error($"chea questTaskFunctionProgress error : {userQuestInfo.m_current_task_num}, questId : {questId}");
|
|
// return;
|
|
// }
|
|
// rewards.AddRange(rewardList);
|
|
//
|
|
// if (userQuestInfo.m_is_current_task_complete == 1)
|
|
// {
|
|
// error_code = QuestNextTaskUpdate(dbQuestInfo, userQuestInfo, questId, dbQuestTaskInfo);
|
|
// if (error_code != ServerErrorCode.Success) return;
|
|
// }
|
|
//
|
|
// Dictionary<int, Dictionary<string, string>> delete_items = new();
|
|
// delete_items.TryAdd(questId, deletedItems);
|
|
// Dictionary<int, List<RewardData>> reward_dictionary = new();
|
|
// reward_dictionary.TryAdd(questId, rewards);
|
|
//
|
|
// List<int> update_quest_ids = new() { questId };
|
|
// (error_code, IReward reward_proc ) = save(player, update_quest_ids, newQuestListEntity, reward_dictionary, delete_items);
|
|
// if (error_code != ServerErrorCode.Success)
|
|
// {
|
|
// return;
|
|
// }
|
|
//
|
|
// if (userQuestInfo.m_is_complete == 1)
|
|
// {
|
|
|
|
// }
|
|
// }
|
|
|
|
// internal (ServerErrorCode, IReward) save(object player, List<int> updatedQuests, QuestListEntity questListEntity, Dictionary<int, List<RewardData>> rewards, Dictionary<int, Dictionary<string, string>> deleteItem)
|
|
// {
|
|
// ConcurrentDictionary<ERewardType, Document> rewardDocument = new();
|
|
//
|
|
// ServerErrorCode error_code = ServerErrorCode.Success;
|
|
// //IReward reward_proc = new QuestTaskSave(player, updatedQuests, questListEntity, rewards, deleteItem);
|
|
// //RewardManager.Instance.proceedRewardProcess(reward_proc).Wait();
|
|
// //RewardManager.Instance.postRewardProcess(reward_proc);
|
|
//
|
|
// //return (error_code, reward_proc);
|
|
// return (error_code, null);
|
|
// }
|
|
|
|
private Result QuestNextTaskUpdate(QuestAttribute questAttribute,
|
|
ref QuestTaskUpdateHandler questTaskUdateHandler)
|
|
{
|
|
var task_group = questTaskUdateHandler.m_quest_task_group;
|
|
var next_task_num = questTaskUdateHandler.m_next_task_number;
|
|
|
|
var result = new Result();
|
|
if (questAttribute.IsComplete == 1)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var quest_id = questTaskUdateHandler.m_quest_id;
|
|
|
|
var meta_info = questTaskUdateHandler.m_quest_meta_info;
|
|
NullReferenceCheckHelper.throwIfNull(meta_info, () => $"meta_info is null !!!");
|
|
if (!meta_info.QuestTaskGroupList.TryGetValue(next_task_num, out var next_quest_task))
|
|
{
|
|
var err_msg =
|
|
$"QuestNextTaskUpdate - QuestTaskGroupList not found. quest_id : {quest_id}, next_task_num : {next_task_num}";
|
|
result.setFail(ServerErrorCode.QuestInvalidValue, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
return result;
|
|
}
|
|
|
|
questAttribute.CurrentTaskNum = next_task_num;
|
|
questAttribute.CurrentTaskComplete = 0;
|
|
|
|
DateTime now = DateTime.UtcNow;
|
|
questAttribute.TaskStartTime = now;
|
|
questAttribute.ActiveEvents.Clear();
|
|
questAttribute.ActiveEvents.AddRange(next_quest_task.EventStringList);
|
|
questAttribute.HasTimer = 0;
|
|
questAttribute.TimerCompleteTime = now;
|
|
questAttribute.CompletedIdxStrings.Clear();
|
|
questAttribute.HasCounter = 0;
|
|
questAttribute.MaxCounter = 0;
|
|
questAttribute.MinCounter = 0;
|
|
questAttribute.CurrentCounter = 0;
|
|
|
|
if (next_quest_task.HasCounter)
|
|
{
|
|
questAttribute.HasCounter = 1;
|
|
questAttribute.MaxCounter = next_quest_task.MaxCounter;
|
|
questAttribute.MinCounter = next_quest_task.MinCounter;
|
|
questAttribute.CurrentCounter = next_quest_task.MinCounter;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
public List<string> getActiveEventStrings(QuestAttribute questAttribute, QuestTaskGroup questTaskInfo)
|
|
{
|
|
List<string> activeEventStrings = new List<string>();
|
|
if (questAttribute.IsComplete == 1) return activeEventStrings;
|
|
|
|
if (questTaskInfo.IsParallel)
|
|
{
|
|
foreach (var dbEventInfo in questTaskInfo.QuestEventGroupByEventString.Values)
|
|
{
|
|
string str = MetaData.Instance.makeEventScriptStringByEventInfo(dbEventInfo);
|
|
if (questAttribute.CompletedIdxStrings.Contains(str))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
activeEventStrings.Add(str);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (string eventString in questTaskInfo.EventStringList)
|
|
{
|
|
activeEventStrings.Add(eventString);
|
|
}
|
|
}
|
|
|
|
return activeEventStrings;
|
|
|
|
}
|
|
|
|
public List<string> getTimerCheckUser()
|
|
{
|
|
return m_timer_check_users.Keys.ToList();
|
|
}
|
|
|
|
public void deleteTimerCheckUser(List<string> deleteChecker)
|
|
{
|
|
foreach (string deleteUser in deleteChecker)
|
|
{
|
|
m_timer_check_users.TryRemove(deleteUser, out _);
|
|
}
|
|
}
|
|
|
|
public async Task questTimerEventCheck()
|
|
{
|
|
List<string> timer_check_user = m_timer_check_users.Keys.ToList();
|
|
List<string> delete_checker = new();
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var player_manager = server_logic.getPlayerManager();
|
|
foreach (string user_guid in timer_check_user)
|
|
{
|
|
if (false == player_manager.tryGetUserByPrimaryKey(user_guid, out var player))
|
|
{
|
|
delete_checker.Add(user_guid);
|
|
continue;
|
|
}
|
|
|
|
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
|
if (false == user_create_or_load_action.isCompletedLoadUser())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
await QuestCheck(player, new QuestTimer(EQuestEventTargetType.TIMER, EQuestEventNameType.ENDED));
|
|
}
|
|
|
|
foreach (string deleteUser in delete_checker)
|
|
{
|
|
m_timer_check_users.TryRemove(deleteUser, out _);
|
|
}
|
|
}
|
|
|
|
public async Task questNormalActiveCheck()
|
|
{
|
|
List<string> delete_checker = new();
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var player_manager = server_logic.getPlayerManager();
|
|
|
|
foreach (var user_guid in m_normal_quest_check_users.Keys)
|
|
{
|
|
if (false == player_manager.tryGetUserByPrimaryKey(user_guid, out var player))
|
|
{
|
|
delete_checker.Add(user_guid);
|
|
continue;
|
|
}
|
|
|
|
|
|
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
|
if (false == user_create_or_load_action.isCompletedLoadUser())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
await questNormalActiveCheckAndAssign(player);
|
|
}
|
|
|
|
foreach (var delete_user in delete_checker)
|
|
{
|
|
m_normal_quest_check_users.TryRemove(delete_user, out _);
|
|
Log.getLogger()
|
|
.debug($"setNormalMailTimer m_normal_quest_check_users remove accountId : {delete_user}");
|
|
}
|
|
}
|
|
|
|
|
|
private async Task questNormalActiveCheckAndAssign(Player player)
|
|
{
|
|
DateTime now_dt = DateTimeHelper.Current;
|
|
var repeat_quest_attribute = player.getEntityAttribute<RepeatQuestAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(repeat_quest_attribute, () => $"repeat_quest_attribute is null !!!");
|
|
|
|
if (repeat_quest_attribute.m_is_checking == 0) return;
|
|
if (now_dt < repeat_quest_attribute.m_next_allocate_time) return;
|
|
|
|
//플레이어 정보는 퀘스트 메일 보내기 전에 로드 된다. 메일이 로드 안되어 있으면 리턴 할수 있도록 처리 해줘야된다.
|
|
var quest_mail_action = player.getEntityAction<QuestMailAction>();
|
|
if (false == quest_mail_action.isMailLoadedAll()) return;
|
|
|
|
|
|
HashSet<UInt32> my_current_normal_mail_set = await quest_mail_action.getNormalMailSet();
|
|
int normal_mail_count = my_current_normal_mail_set.Count;
|
|
HashSet<UInt32> assignable_mail_set = await getAssignableMailSet(player, my_current_normal_mail_set);
|
|
|
|
|
|
//체크 대상이라 여기 들어왔는데 메일이 넘치면 미체크 대상으로 처리
|
|
if (MetaHelper.GameConfigMeta.MaxQuestSendMail <= normal_mail_count || assignable_mail_set.Count == 0)
|
|
{
|
|
m_normal_quest_check_users.TryRemove(player.getUserGuid(), out _);
|
|
return;
|
|
}
|
|
|
|
//여기까지 왔으면 메일 보낼게 있다는 얘기이므로 전송한다.
|
|
var assignable_quest_id = getAssignableQuestMailId(assignable_mail_set);
|
|
|
|
//여기서 normalMailSet + 1 의 개수가 최대 개수를 넘으면 비활성화 처리
|
|
var check_value = questCheckUserAssignableQuestMaxCheck(player, my_current_normal_mail_set);
|
|
|
|
var result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "updateRepeatQuest",
|
|
delegateSendQuestMailAndUpdateRepeatQuestInfo);
|
|
|
|
async Task<Result> delegateSendQuestMailAndUpdateRepeatQuestInfo() =>
|
|
await sendQuestMailAndUpdateRepeatQuestInfo(player, assignable_quest_id, check_value);
|
|
|
|
}
|
|
|
|
public UInt32 getAssignableQuestMailId(HashSet<UInt32> assignableMailSet)
|
|
{
|
|
//여기까지 왔으면 메일 보낼게 있다는 얘기이므로 전송한다.
|
|
Random random = new Random();
|
|
List<UInt32> assignableMailList = assignableMailSet.ToList();
|
|
var mails_count = assignableMailList.Count;
|
|
var idx = random.Next(mails_count);
|
|
var assign_quest_id = assignableMailList[idx];
|
|
|
|
return assign_quest_id;
|
|
}
|
|
|
|
public bool questCheckUserAssignableQuestMaxCheck(Player player, HashSet<UInt32> assignableMailSet)
|
|
{
|
|
bool check_value = true;
|
|
if (MetaHelper.GameConfigMeta.MaxQuestSendMail <= assignableMailSet.Count + 1)
|
|
{
|
|
m_normal_quest_check_users.TryRemove(player.getUserGuid(), out _);
|
|
check_value = false;
|
|
}
|
|
|
|
return check_value;
|
|
}
|
|
|
|
|
|
private async Task<Result> sendQuestMailAndUpdateRepeatQuestInfo(Player player, UInt32 questId, bool checkVlaue)
|
|
{
|
|
var quest_mail_action = player.getEntityAction<QuestMailAction>();
|
|
(var result, var quest_mail, var quest_mail_log_invoker) = await quest_mail_action.sendQuestMail(questId);
|
|
if (result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var repeat_quest_attribute = player.getEntityAttribute<RepeatQuestAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(repeat_quest_attribute, () => $"repeat_quest_attribute is null !!!");
|
|
|
|
repeat_quest_attribute.m_next_allocate_time =
|
|
repeat_quest_attribute.m_next_allocate_time.AddMinutes(MetaHelper.GameConfigMeta
|
|
.CooltimeNormalQuestSendMail);
|
|
if (false == checkVlaue)
|
|
{
|
|
repeat_quest_attribute.m_is_checking = 0;
|
|
}
|
|
|
|
repeat_quest_attribute.modifiedEntityAttribute();
|
|
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.QuestMailSend,
|
|
server_logic.getDynamoDbClient());
|
|
{
|
|
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
|
}
|
|
batch.appendBusinessLog(new RepeatQuestBusinessLog(repeat_quest_attribute.m_next_allocate_time, repeat_quest_attribute.m_is_checking));
|
|
batch.appendBusinessLog(quest_mail_log_invoker);
|
|
|
|
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
|
|
|
if (result.isFail())
|
|
{
|
|
Log.getLogger()
|
|
.error($"cheatSendQuestMail - QueryHelper.sendQueryAndBusinessLog Fail : {result.toBasicString()}");
|
|
return result;
|
|
}
|
|
|
|
await quest_mail_action.addNewQuestMails(new List<ServerCommon.QuestMail>() { quest_mail });
|
|
await quest_mail_action.send_NTF_RECEIVED_QUEST_MAIL(player, new List<UInt32>() { questId });
|
|
await QuestCheck(player, new QuestMail(EQuestEventTargetType.MAIL, EQuestEventNameType.RECEIVED, ""));
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
public async Task<HashSet<UInt32>> getAssignableMailSet(Player player, HashSet<UInt32> normalMailSet)
|
|
{
|
|
var quest_action = player.getEntityAction<QuestAction>();
|
|
var end_quest_action = player.getEntityAction<EndQuestAction>();
|
|
|
|
var end_quests = end_quest_action.getEndQuests();
|
|
var quest_ids = quest_action.getSystemQuestIds();
|
|
|
|
HashSet<UInt32> assignableMailSet = new();
|
|
foreach (var quest_group in _QuestNormalGroup)
|
|
{
|
|
if (quest_group.Key == 0 || end_quests.ContainsKey((quest_group.Key, 0)))
|
|
{
|
|
foreach (var quest_id in quest_group.Value.ToList())
|
|
{
|
|
(var result, var quest_meta_all_base_info) = await QuestMetaManager.It.getQuestMeta(quest_id);
|
|
if (result.isFail()) continue;
|
|
var quest_base_info = quest_meta_all_base_info.m_quest_base_info;
|
|
NullReferenceCheckHelper.throwIfNull(quest_base_info, () => $"quest_base_info is null !!!");
|
|
|
|
//noLimit가 아니면 메일 줄수 없다.
|
|
if(false == quest_base_info.OncePeriodRangeType.Equals(OncePeriodRangeType.Nolimit)) continue;
|
|
//메일에 있으니 continue
|
|
if (normalMailSet.Contains(quest_id)) continue;
|
|
if (quest_ids.Contains(quest_id)) continue;
|
|
assignableMailSet.Add(quest_id);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return assignableMailSet;
|
|
}
|
|
|
|
public async Task QuestCheckAtWarpRet(Player player, string roomString, int roomId)
|
|
{
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
if (server_logic.getServerType().toServerType() == ServerType.Channel) return;
|
|
|
|
var location_attribute = player.getEntityAttribute<LocationAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location_attribute is null !!!");
|
|
|
|
if (false == MetaData.Instance._IndunTable.TryGetValue(roomId, out var indun_data))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (roomString == string.Empty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (indun_data.ContentsType)
|
|
{
|
|
case ContentsType.MyHome:
|
|
{
|
|
var roomIdElemnet = roomString.Split(":");
|
|
if (roomIdElemnet.Length != ServerCommon.Constant.MYHOME_INSTANCE_ROOM_ID_ELEMENT_COUNT) return;
|
|
if (roomIdElemnet[1] == player.getUserGuid())
|
|
{
|
|
//await player.send_GS2CS_NTF_FRIEND_LEAVE_MYHOME();
|
|
await QuestCheckWithoutTransaction(player,
|
|
new QuestMyHome(EQuestEventTargetType.MYHOME, EQuestEventNameType.EXITED, "MYSELF"));
|
|
}
|
|
else
|
|
{
|
|
await QuestCheckWithoutTransaction(player,
|
|
new QuestMyHome(EQuestEventTargetType.MYHOME, EQuestEventNameType.EXITED, "OTHERS"));
|
|
}
|
|
}
|
|
break;
|
|
case ContentsType.DressRoom:
|
|
{
|
|
await QuestCheckWithoutTransaction(player,
|
|
new QuestDressRoom(EQuestEventTargetType.DRESSROOM, EQuestEventNameType.EXITED, "MYSELF"));
|
|
}
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private void send_NTF_UGQ_STATE_CHANGED(Player player, Result result, UInt32 questId, UInt32 questRevision)
|
|
{
|
|
if (result.getErrorCode() != ServerErrorCode.UgqQuestRevisionChanged &&
|
|
result.getErrorCode() != ServerErrorCode.UgqQuestShutdowned) return;
|
|
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
|
|
var ntf_packet = new ClientToGame();
|
|
ntf_packet.Message = new();
|
|
ntf_packet.Message.NtfUgqStateChanged = new();
|
|
ntf_packet.Message.NtfUgqStateChanged.ComposedQuestId =
|
|
QuestHelper.convertQuestIdAndRevisionToUgqQuestId(questId, questRevision);
|
|
|
|
ntf_packet.Message.NtfUgqStateChanged.State = UgqStateType.Shutdown;
|
|
if (result.getErrorCode() == ServerErrorCode.UgqQuestRevisionChanged)
|
|
{
|
|
ntf_packet.Message.NtfUgqStateChanged.State = UgqStateType.RevisionChanged;
|
|
}
|
|
|
|
server_logic.onSendPacket(player, ntf_packet);
|
|
}
|
|
|
|
public async Task<Result> PeriodRepeatQuestCheck(Player player)
|
|
{
|
|
await Task.CompletedTask;
|
|
var result = new Result();
|
|
|
|
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
|
NullReferenceCheckHelper.throwIfNull(user_create_or_load_action, () => $"user_create_or_load_action is null !!! - {player.toBasicString()}");
|
|
|
|
if(false == user_create_or_load_action.isCompletedLoadUser())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
|
|
List<ServerCommon.QuestMail> quest_mails = new();
|
|
List<ILogInvoker> log_invokers = new();
|
|
List<UInt32> sended_quest_ids = new();
|
|
Dictionary<UInt32, ServerCommon.Quest> assigned_quests = new();
|
|
var quest_mail_action = player.getEntityAction<QuestMailAction>();
|
|
var end_quest_action = player.getEntityAction<EndQuestAction>();
|
|
var quest_action = player.getEntityAction<QuestAction>();
|
|
var end_quests = end_quest_action.getEndQuests();
|
|
var now = DateTimeHelper.Current;
|
|
|
|
var fn_transaction_runner = async delegate()
|
|
{
|
|
//리프레시 하면서 바로 퀘스트 메일도 지급
|
|
var period_repeat_quest_attibute = player.getEntityAttribute<QuestPeriodRepeatCheckAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(period_repeat_quest_attibute, () => $"period_repeat_quest_attibute is null !!!");
|
|
|
|
if (period_repeat_quest_attibute.m_period_repeat_quests.Count == 0) makeDefaultPeriodRepeatQuests(period_repeat_quest_attibute);
|
|
|
|
bool need_update = false;
|
|
foreach (var info in period_repeat_quest_attibute.m_period_repeat_quests)
|
|
{
|
|
var periodRangeType = info.Key;
|
|
var periodSendedQuest = info.Value;
|
|
|
|
var all_sendable_mail_ids = getSendableMailIds(periodRangeType);
|
|
|
|
foreach (var id in all_sendable_mail_ids)
|
|
{
|
|
(result, var quest_meta_all_base_info) = await QuestMetaManager.It.getQuestMeta(id);
|
|
if (result.isFail()) continue;
|
|
|
|
var quest_base_info = quest_meta_all_base_info.m_quest_base_info;
|
|
NullReferenceCheckHelper.throwIfNull(quest_base_info, () => $"quest_base_info is null !!!");
|
|
|
|
if(quest_base_info.RequirementType.Equals(EAssignRequireType.Quest_Complete.ToString()))
|
|
{
|
|
//완료한 퀘스트가 없으면 daily에서 당장은 줄수 없다.
|
|
if (false == end_quests.ContainsKey((quest_base_info.RequirementValue, 0)))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (quest_base_info.NormalPoolActive) continue;
|
|
|
|
if (periodSendedQuest.m_sended_quest.TryGetValue(id, out var nextRefleshTime))
|
|
{
|
|
//아직 refleshTime이 시간이 안됐으면 continue
|
|
if (now < nextRefleshTime) continue;
|
|
}
|
|
|
|
if (quest_base_info.ForceAccept)
|
|
{
|
|
//이미 들고 있는 퀘스트면 continue;
|
|
result = quest_action.hasQuest(EQuestType.NORMAL, id, 0);
|
|
if (result.isSuccess()) continue;
|
|
|
|
|
|
//AcceptQuestVariable? accept_quest_var = null;
|
|
var quest_accept_action = player.getEntityAction<QuestAcceptAction>();
|
|
(result, var accept_quest_var) = await quest_accept_action.questAccept(id);
|
|
if (result.isFail() || accept_quest_var is null) return result;
|
|
|
|
var assigned_quest = accept_quest_var.m_new_quest_nullable;
|
|
NullReferenceCheckHelper.throwIfNull(assigned_quest, () => $"Quest is null !!!");
|
|
|
|
var assigned_quest_attribute = assigned_quest.getEntityAttribute<QuestAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(assigned_quest_attribute, () => "QuestAttribute is null !!!");
|
|
var assigned_quest_id = assigned_quest_attribute.QuestId;
|
|
|
|
assigned_quests.TryAdd(assigned_quest_id, assigned_quest);
|
|
}
|
|
else
|
|
{
|
|
//이미 받은 메일이 있다면 체크 안한다.
|
|
result = quest_mail_action.hasQuestMail(EQuestType.NORMAL, id, false);
|
|
if (result.isSuccess()) continue;
|
|
|
|
(result, var quest_mail, var quest_mail_log_invoker) = await quest_mail_action.sendQuestMail(id);
|
|
|
|
if (result.isFail())
|
|
{
|
|
Log.getLogger().error(result.toBasicString());
|
|
continue;
|
|
}
|
|
|
|
|
|
|
|
sended_quest_ids.Add(id);
|
|
|
|
quest_mails.Add(quest_mail);
|
|
log_invokers.Add(quest_mail_log_invoker);
|
|
}
|
|
var next_refresh_time = getNextRefreshTime(periodRangeType, now);
|
|
periodSendedQuest.m_sended_quest.AddOrUpdate(id, next_refresh_time, (key, value) => next_refresh_time);
|
|
need_update = true;
|
|
}
|
|
|
|
}
|
|
if (false == need_update) return result;
|
|
|
|
period_repeat_quest_attibute.modifiedEntityAttribute(true);
|
|
|
|
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.DailyQuestCheck,
|
|
server_logic.getDynamoDbClient());
|
|
{
|
|
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
|
}
|
|
|
|
foreach (var assigned_quest in assigned_quests)
|
|
{
|
|
batch.appendBusinessLog(new QuestAcceptBusinessLog(assigned_quest.Key, 0, EQuestType.NORMAL));
|
|
}
|
|
batch.appendBusinessLog(new QueatDailyCheckBusinessLog( period_repeat_quest_attibute.m_period_repeat_quests));
|
|
batch.appendBusinessLogs(log_invokers);
|
|
|
|
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
|
|
|
if (result.isFail())
|
|
{
|
|
Log.getLogger().error($"DailyQuestCheck - QueryHelper.sendQueryAndBusinessLog Fail : {result.toBasicString()}");
|
|
return result;
|
|
}
|
|
|
|
foreach (var assigned_quest in assigned_quests)
|
|
{
|
|
quest_action.addNewQuest(assigned_quest.Key, assigned_quest.Value);
|
|
await QuestNotifyHelper.makeQuestUpdateNotify(player, assigned_quest.Key, assigned_quest.Value, true);
|
|
}
|
|
await quest_mail_action.addNewQuestMails(quest_mails);
|
|
await quest_mail_action.send_NTF_RECEIVED_QUEST_MAIL(player, sended_quest_ids);
|
|
await QuestCheck(player, new QuestMail(EQuestEventTargetType.MAIL, EQuestEventNameType.RECEIVED, ""));
|
|
|
|
return result;
|
|
};
|
|
|
|
|
|
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "DailyQuestCheckRefresh", fn_transaction_runner);
|
|
if (result.isFail())
|
|
{
|
|
var err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
return result;
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
private void makeDefaultPeriodRepeatQuests(QuestPeriodRepeatCheckAttribute attribute)
|
|
{
|
|
attribute.m_period_repeat_quests.TryAdd(OncePeriodRangeType.Daily, new QuestPeriodRepeatInfo());
|
|
attribute.m_period_repeat_quests.TryAdd(OncePeriodRangeType.Weekly, new QuestPeriodRepeatInfo());
|
|
attribute.m_period_repeat_quests.TryAdd(OncePeriodRangeType.Monthly, new QuestPeriodRepeatInfo());
|
|
attribute.modifiedEntityAttribute(true);
|
|
}
|
|
|
|
private List<UInt32> getSendableMailIds(OncePeriodRangeType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case OncePeriodRangeType.Daily:
|
|
return _DailyQuestQuestGroup.ToList();
|
|
case OncePeriodRangeType.Weekly:
|
|
return _WeeklyQuestQuestGroup.ToList();
|
|
case OncePeriodRangeType.Monthly:
|
|
return _MonthlyQuestQuestGroup.ToList();
|
|
default:
|
|
return new();
|
|
}
|
|
|
|
}
|
|
|
|
private DateTime getNextRefreshTime(OncePeriodRangeType type, DateTime now)
|
|
{
|
|
var currentDate = now.Date;
|
|
switch (type)
|
|
{
|
|
case OncePeriodRangeType.Daily:
|
|
return currentDate.AddDays(1);
|
|
case OncePeriodRangeType.Weekly:
|
|
int daysUntilNextMonday = ((int)DayOfWeek.Monday - (int)currentDate.DayOfWeek + 7) % 7;
|
|
daysUntilNextMonday = daysUntilNextMonday == 0 ? 7 : daysUntilNextMonday; // 오늘이 월요일이면 다음 주 월요일로 설정
|
|
return currentDate.AddDays(daysUntilNextMonday);
|
|
case OncePeriodRangeType.Monthly:
|
|
// 다음 달 1일 0시로 설정
|
|
var currentMonth = DateTimeHelper.Current;
|
|
var nextMonth = new DateTime(currentMonth.Year, currentMonth.Month, 1).AddMonths(1);
|
|
return nextMonth;
|
|
default:
|
|
return currentDate;
|
|
}
|
|
}
|
|
|
|
public async Task newAssignableQuestCheck(Player player)
|
|
{
|
|
var result = new Result();
|
|
|
|
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
|
NullReferenceCheckHelper.throwIfNull(user_create_or_load_action, () => $"user_create_or_load_action is null !!! - {player.toBasicString()}");
|
|
|
|
if (false == user_create_or_load_action.isCompletedLoadUser())
|
|
{
|
|
return;
|
|
}
|
|
|
|
var quest_ids = _DailyQuestQuestGroup.ToList();
|
|
|
|
var end_quest_action = player.getEntityAction<EndQuestAction>();
|
|
var end_quests = end_quest_action.getEndQuests();
|
|
|
|
var quest_action = player.getEntityAction<QuestAction>();
|
|
var quest_mail_action = player.getEntityAction<QuestMailAction>();
|
|
|
|
List<UInt32> need_send_quest_mail_ids = new();
|
|
foreach (var end_quest in end_quests)
|
|
{
|
|
if (end_quest.Key.Item2 > 0) continue; //ugq 제외
|
|
var end_quest_id = end_quest.Key.Item1;
|
|
|
|
if (false == _QuestReqValueGroup.TryGetValue(end_quest_id, out var next_quests)) continue;
|
|
|
|
foreach (var next_quest_id in next_quests)
|
|
{
|
|
//이미 깬 퀘스트면 continue;
|
|
if(end_quests.ContainsKey((next_quest_id, 0)) ) continue;
|
|
|
|
//진행 중 퀘스트면 continue;
|
|
(result, var quest_meta_base_info) = await QuestMetaManager.It.getQuestMeta(next_quest_id);
|
|
if (result.isFail()) continue;
|
|
|
|
NullReferenceCheckHelper.throwIfNull(quest_meta_base_info.m_quest_base_info, () => $"quest_meta_base_info.m_quest_base_info is null !!!");
|
|
|
|
if (quest_meta_base_info.m_quest_base_info.QuestType.Equals(EQuestType.UGQ.ToString())) continue;
|
|
if (quest_meta_base_info.m_quest_base_info.QuestType.Equals(EQuestType.NORMAL.ToString())) continue;
|
|
|
|
result = quest_action.getQuest(quest_meta_base_info.m_quest_base_info.QuestType, next_quest_id, out _);
|
|
if (result.isSuccess()) continue;
|
|
|
|
var quest_type = EnumHelper.convertEnumTypeAndValueStringToEnum(quest_meta_base_info.m_quest_base_info.QuestType, EQuestType.NORMAL);
|
|
//메일에 있으면 continue;
|
|
result = quest_mail_action.hasQuestMail(quest_type, next_quest_id, false);
|
|
if (result.isSuccess()) continue;
|
|
|
|
need_send_quest_mail_ids.Add(next_quest_id);
|
|
}
|
|
}
|
|
|
|
if (need_send_quest_mail_ids.Count > 0)
|
|
{
|
|
await quest_mail_action.sendQuestMailsWithTransaction(need_send_quest_mail_ids);
|
|
}
|
|
}
|
|
}
|
|
|