@@ -152,55 +152,103 @@ void QuestService::OnQuestUpdate(const NotifyQuestUpdate& aUpdate) noexcept
152152{
153153 m_world.GetRunner ().Queue ([this , update = aUpdate]()
154154 {
155- ModSystem& modSystem = World::Get ().GetModSystem ();
156- uint32_t formId = modSystem.GetGameId (update.Id );
157- TESQuest* pQuest = Cast<TESQuest>(TESForm::GetById (formId));
158- if (!pQuest)
155+ if (!TryApplyQuestUpdate (update))
159156 {
160- spdlog::error ( " Failed to find quest, base id: {:X}, mod id: {:X }" , update.Id .BaseId , update.Id . ModId );
161- return ;
157+ spdlog::debug ( " Quest update pending for {:X}, stage { }" , update.Id .LogFormat () , update.Stage );
158+ m_pendingUpdates. push_back (update) ;
162159 }
160+ });
161+ }
163162
164- if (pQuest->type == TESQuest::Type::None || pQuest->type == TESQuest::Type::Miscellaneous)
165- {
166- spdlog::info (__FUNCTION__ " : receiving type none/misc quest update gameId {:X} questStage {} questStatus {} questType {} formId {:X} name {}" ,
167- update.Id .LogFormat (), update.Stage , update.Status ,
168- update.ClientQuestType , formId, pQuest->fullName .value .AsAscii ());
169- }
163+ void QuestService::OnUpdate (const UpdateEvent&) noexcept
164+ {
165+ FlushPendingUpdates ();
166+ }
170167
171- bool bResult = false ;
172- switch (update.Status )
173- {
174- case NotifyQuestUpdate::Started:
175- {
176- pQuest->ScriptSetStage (update.Stage );
177- pQuest->SetActive (true );
178- bResult = true ;
179- spdlog::info (" Remote quest started: {:X}, stage: {}" , formId, update.Stage );
180- break ;
181- }
182- case NotifyQuestUpdate::StageUpdate:
183- pQuest->ScriptSetStage (update.Stage );
184- bResult = true ;
185- spdlog::info (" Remote quest updated: {:X}, stage: {}" , formId, update.Stage );
186- break ;
187- case NotifyQuestUpdate::Stopped:
188- bResult = StopQuest (formId);
189- spdlog::info (" Remote quest stopped: {:X}, stage: {}" , formId, update.Stage );
190- break ;
191- default : break ;
192- }
168+ void QuestService::FlushPendingUpdates () noexcept
169+ {
170+ if (m_pendingUpdates.empty ())
171+ return ;
193172
194- if (!bResult)
195- spdlog::error (" Failed to update the client quest state, quest: {:X}, stage: {}, status: {}" , formId, update.Stage , update.Status );
196- });
173+ TiltedPhoques::Vector<NotifyQuestUpdate> remaining;
174+ remaining.reserve (m_pendingUpdates.size ());
175+
176+ for (const auto & update : m_pendingUpdates)
177+ {
178+ if (!TryApplyQuestUpdate (update))
179+ remaining.push_back (update);
180+ }
181+
182+ m_pendingUpdates = std::move (remaining);
183+ }
184+
185+ bool QuestService::TryApplyQuestUpdate (const NotifyQuestUpdate& aUpdate) noexcept
186+ {
187+ ModSystem& modSystem = World::Get ().GetModSystem ();
188+ const uint32_t formId = modSystem.GetGameId (aUpdate.Id );
189+ if (formId == 0 )
190+ {
191+ spdlog::warn (" Quest update awaiting mod resolution, base id: {:X}, mod id: {:X}" , aUpdate.Id .BaseId , aUpdate.Id .ModId );
192+ return false ;
193+ }
194+
195+ TESQuest* pQuest = Cast<TESQuest>(TESForm::GetById (formId));
196+ if (!pQuest)
197+ {
198+ spdlog::warn (" Quest {:X} not loaded yet, deferring update" , formId);
199+ return false ;
200+ }
201+
202+ if (pQuest->type == TESQuest::Type::None || pQuest->type == TESQuest::Type::Miscellaneous)
203+ {
204+ spdlog::info (__FUNCTION__ " : receiving type none/misc quest update gameId {:X} questStage {} questStatus {} questType {} formId {:X} name {}" ,
205+ aUpdate.Id .LogFormat (), aUpdate.Stage , aUpdate.Status ,
206+ aUpdate.ClientQuestType , formId, pQuest->fullName .value .AsAscii ());
207+ }
208+
209+ bool bResult = false ;
210+
211+ ScopedQuestOverride questOverride;
212+
213+ switch (aUpdate.Status )
214+ {
215+ case NotifyQuestUpdate::Started:
216+ {
217+ bool startSuccess = false ;
218+ pQuest->EnsureQuestStarted (startSuccess, true );
219+ pQuest->SetActive (true );
220+ pQuest->ScriptSetStage (aUpdate.Stage );
221+ bResult = true ;
222+ spdlog::info (" Remote quest started: {:X}, stage: {}" , formId, aUpdate.Stage );
223+ break ;
224+ }
225+ case NotifyQuestUpdate::StageUpdate:
226+ pQuest->SetActive (true );
227+ pQuest->ScriptSetStage (aUpdate.Stage );
228+ bResult = true ;
229+ spdlog::info (" Remote quest updated: {:X}, stage: {}" , formId, aUpdate.Stage );
230+ break ;
231+ case NotifyQuestUpdate::Stopped:
232+ bResult = StopQuest (formId);
233+ spdlog::info (" Remote quest stopped: {:X}, stage: {}" , formId, aUpdate.Stage );
234+ break ;
235+ default :
236+ spdlog::warn (" Unhandled quest update status {} for quest {:X}" , aUpdate.Status , formId);
237+ break ;
238+ }
239+
240+ if (!bResult)
241+ spdlog::error (" Failed to update the client quest state, quest: {:X}, stage: {}, status: {}" , formId, aUpdate.Stage , aUpdate.Status );
242+
243+ return bResult;
197244}
198245
199246bool QuestService::StopQuest (uint32_t aformId)
200247{
201248 TESQuest* pQuest = Cast<TESQuest>(TESForm::GetById (aformId));
202249 if (pQuest)
203250 {
251+ ScopedQuestOverride _;
204252 pQuest->SetActive (false );
205253 pQuest->SetStopped ();
206254 return true ;
0 commit comments