server-master/srcs/_plugins/Plugin.QuestImpl/Handlers/AddMainQuestEventHandler.cs
2026-02-10 18:21:30 +01:00

126 lines
No EOL
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using PhoenixLib.Events;
using PhoenixLib.Logging;
using PhoenixLib.Scheduler;
using WingsAPI.Game.Extensions.Quests;
using WingsEmu.DTOs.Quests;
using WingsEmu.Game._i18n;
using WingsEmu.Game.Characters.Events;
using WingsEmu.Game.Extensions;
using WingsEmu.Game.Networking;
using WingsEmu.Game.Quests;
using WingsEmu.Game.Quests.Event;
using WingsEmu.Packets.Enums;
using WingsEmu.Packets.Enums.Chat;
namespace Plugin.QuestImpl.Handlers
{
public class AddMainQuestEventHandler : IAsyncEventProcessor<AddQuestEvent>
{
private readonly IGameLanguageService _gameLanguageService;
private readonly IQuestFactory _questFactory;
private readonly IQuestManager _questManager;
private readonly IScheduler _scheduler;
public AddMainQuestEventHandler(IQuestManager questManager, IQuestFactory questFactory, IScheduler scheduler, IGameLanguageService gameLanguageService)
{
_questManager = questManager;
_questFactory = questFactory;
_scheduler = scheduler;
_gameLanguageService = gameLanguageService;
}
public async Task HandleAsync(AddQuestEvent e, CancellationToken cancellation)
{
IClientSession session = e.Sender;
int questId = e.QuestId;
if (e.QuestSlotType != QuestSlotType.MAIN)
{
return;
}
QuestDto quest = _questManager.GetQuestById(questId);
if (quest == null)
{
Log.Debug($"[ERROR] Quest not found: {questId.ToString()}");
return;
}
if (session.PlayerEntity.HasQuestWithId(quest.Id))
{
session.SendMsg(_gameLanguageService.GetLanguage(GameDialogKey.QUEST_SHOUTMESSAGE_ALREADY_HAVE_QUEST, session.UserLanguage), MsgMessageType.Middle);
return;
}
// Check for possible script exploit
if (IsPotentialMainQuestExploit(session, quest))
{
return;
}
if (session.GetEmptyQuestSlot(e.QuestSlotType) == -1)
{
session.SendMsg(_gameLanguageService.GetLanguage(GameDialogKey.QUEST_SHOUTMESSAGE_SLOT_FULL, session.UserLanguage), MsgMessageType.Middle);
return;
}
CharacterQuest characterQuest = _questFactory.NewQuest(session.PlayerEntity.Id, questId, e.QuestSlotType);
session.PlayerEntity.AddActiveQuest(characterQuest);
session.RefreshQuestList(_questManager, characterQuest.QuestId);
await session.EmitEventAsync(new QuestAddedEvent
{
QuestId = characterQuest.QuestId,
QuestSlotType = characterQuest.SlotType
});
if (characterQuest.Quest.QuestType != QuestType.COMPLETE_TIMESPACE && characterQuest.Quest.QuestType != QuestType.DROP_IN_TIMESPACE && quest.TargetMapId != 0)
{
session.SendTargetQuest(quest.TargetMapX, quest.TargetMapY, quest.TargetMapId, quest.Id);
}
// Still gotta be present for NOTHING type quests
_scheduler.Schedule(TimeSpan.FromSeconds(1), s => session.EmitEvent(new QuestCompletedEvent(characterQuest)));
}
private bool IsPotentialMainQuestExploit(IClientSession session, QuestDto quest)
{
CompletedScriptsDto lastCompletedScript = session.PlayerEntity.GetLastCompletedScript();
TutorialDto lastCompletedTutorial = _questManager.GetScriptTutorialByIndex(lastCompletedScript.ScriptId, lastCompletedScript.ScriptIndex);
IReadOnlyCollection<TutorialDto> questScripts = _questManager.GetScriptsTutorialByType(TutorialActionType.START_QUEST);
TutorialDto questScript = _questManager.GetScriptsTutorialByType(TutorialActionType.START_QUEST).FirstOrDefault(s => s.Data == quest.Id && s.Id > lastCompletedTutorial.Id);
if (questScript == null)
{
return false;
}
if (lastCompletedTutorial != null && lastCompletedTutorial.Id > questScript.Id)
{
session.NotifyStrangeBehavior(StrangeBehaviorSeverity.SEVERE_ABUSE,
$"Tried to send an already completed quest script! | ScriptId: {questScript.ScriptId}, ScriptIndex: {questScript.ScriptIndex}");
return true;
}
IEnumerable<TutorialDto> mustBeCompletedScripts =
questScripts.Where(s => s.ScriptId < questScript.ScriptId || s.ScriptId == questScript.ScriptId && s.ScriptIndex < questScript.ScriptIndex);
foreach (TutorialDto tutorialDto in mustBeCompletedScripts)
{
if (!session.PlayerEntity.HasCompletedScriptByIndex(tutorialDto.ScriptId, tutorialDto.ScriptIndex))
{
session.NotifyStrangeBehavior(StrangeBehaviorSeverity.SEVERE_ABUSE,
$"Tried to send a quest script without having completed previous ones! | ScriptId: {questScript.ScriptId}, ScriptIndex: {questScript.ScriptIndex} | "
+ $"The script that was incompleted and triggered this message was: ScriptId: {tutorialDto.ScriptId} ; ScriptIndex: {tutorialDto.ScriptIndex}");
return true; // Let's hope doesn't explode
}
}
return false;
}
}
}