Skip to content

Commit 6c42af3

Browse files
committed
tweaks: attempt to fix quest related crashes
1 parent aba0fc5 commit 6c42af3

File tree

2 files changed

+94
-37
lines changed

2 files changed

+94
-37
lines changed

Code/client/Services/Generic/QuestService.cpp

Lines changed: 85 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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

199246
bool 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;

Code/client/Services/QuestService.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
#include <World.h>
44
#include <Events/EventDispatcher.h>
5+
#include <Events/UpdateEvent.h>
56
#include <Games/Events.h>
7+
#include <TiltedCore/Stl.hpp>
8+
#include <Messages/NotifyQuestUpdate.h>
69

710
struct NotifyQuestUpdate;
811

@@ -32,11 +35,17 @@ class QuestService final : public BSTEventSink<TESQuestStartStopEvent>, BSTEvent
3235

3336
// Network quest updates
3437
void OnQuestUpdate(const NotifyQuestUpdate&) noexcept;
38+
void OnUpdate(const UpdateEvent&) noexcept;
39+
bool TryApplyQuestUpdate(const NotifyQuestUpdate& aUpdate) noexcept;
40+
void FlushPendingUpdates() noexcept;
3541

3642
World& m_world;
3743

3844
// Existing connections
3945
entt::scoped_connection m_joinedConnection;
4046
entt::scoped_connection m_leftConnection;
4147
entt::scoped_connection m_questUpdateConnection;
48+
entt::scoped_connection m_updateConnection;
49+
50+
TiltedPhoques::Vector<NotifyQuestUpdate> m_pendingUpdates;
4251
};

0 commit comments

Comments
 (0)