Skip to content

Commit 5574d52

Browse files
3vcloudclaude
andcommitted
style(dat): tighten async-read comments and trim LOC
Condense the doc comments and fold ProcessPendingReads' deferred-trigger vector back into the loop (fire the tickle under the lock - it's just a game-thread enqueue). No behaviour change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e868a58 commit 5574d52

3 files changed

Lines changed: 22 additions & 44 deletions

File tree

GWToolboxdll/Modules/GwDatTextureModule.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,8 @@
1818

1919
namespace {
2020

21-
// Game file-request trigger: asks the client to load a file id from its dat/network. Anchored on
22-
// the request function's unique DOWNLOAD_FLAG assertion string, so it survives client updates
23-
// (unlike a raw byte pattern). It's the enqueue entry; the client pumps its download queue on its
24-
// own, so no explicit "kick" is needed, and it's safe to call in-game (the requests-suspended flag
25-
// it asserts on is only toggled from the client's Main).
21+
// Asks the client to fetch a file id (dat or network). Found via its unique DOWNLOAD_FLAG assert
22+
// string (survives client updates); safe in-game and enqueue-only - the client pumps its own queue.
2623
using RequestFiles_pt = void(__cdecl*)(uint32_t count, const uint32_t* file_ids, uint32_t flags);
2724
constexpr uint32_t kTriggerFlags = 0; // normal priority, non-cancelable
2825
RequestFiles_pt RequestFiles_Func = nullptr;
@@ -37,8 +34,7 @@ namespace {
3734
}
3835
Log::Log("[GwDat] game file-request trigger resolved at %p", reinterpret_cast<void*>(RequestFiles_Func));
3936
GwDatArchive::Instance().SetTrigger([](uint32_t file_id) {
40-
// The request function touches client state, so issue it on the game thread.
41-
GW::GameThread::Enqueue([file_id] {
37+
GW::GameThread::Enqueue([file_id] { // touches client state; run on the game thread
4238
if (RequestFiles_Func)
4339
RequestFiles_Func(1, &file_id, kTriggerFlags);
4440
});
@@ -350,8 +346,7 @@ void GwDatTextureModule::Initialize()
350346
ToolboxModule::Initialize();
351347
// The dat is indexed lazily on the first read; start its dedicated read/decode worker.
352348
GwDatArchive::Instance().StartWorker();
353-
// Let async reads prompt the client to fetch a streamed-only file (best-effort; see the helper).
354-
WireGameFileTrigger();
349+
WireGameFileTrigger(); // lets async reads tickle the client to fetch streamed-only files
355350
}
356351

357352
IDirect3DTexture9** GwDatTextureModule::LoadTextureFromFileId(uint32_t file_id, uint32_t stream_id)

GWToolboxdll/Utils/GwDat/GwDatArchive.cpp

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,8 @@ void GwDatArchive::StopWorker()
181181
std::scoped_lock<std::mutex> lock(m_task_mutex);
182182
m_worker_running = false;
183183
}
184-
// Drop any undelivered async reads; callers tolerate non-delivery across a worker stop.
185184
std::scoped_lock<std::mutex> lock(m_pending_mutex);
186-
m_pending_reads.clear();
185+
m_pending_reads.clear(); // undelivered async reads are dropped on stop
187186
}
188187

189188
void GwDatArchive::EnqueueTask(std::function<void()> task)
@@ -418,10 +417,10 @@ void GwDatArchive::ReadFileAsync(uint32_t file_id, ReadCallback callback, uint32
418417
return;
419418
if (!file_id) {
420419
std::vector<uint8_t> empty;
421-
callback(empty); // nothing to look up
420+
callback(empty);
422421
return;
423422
}
424-
StartWorker(); // the poll loop must be running to deliver
423+
StartWorker(); // the poll loop delivers
425424
const uint32_t deadline = GetTickCount() + kAsyncReadTimeoutMs;
426425
std::scoped_lock<std::mutex> lock(m_pending_mutex);
427426
m_pending_reads.push_back({file_id, stream_id, deadline, std::move(callback), false});
@@ -433,41 +432,30 @@ void GwDatArchive::SetTrigger(TriggerFn trigger)
433432
m_trigger = std::move(trigger);
434433
}
435434

436-
// Worker-thread pass over the pending async reads: deliver any that now resolve, expire any past
437-
// their deadline. Callbacks fire outside the lock so they can't stall other ReadFileAsync callers.
435+
// Worker pass: deliver resolved reads, time out stale ones, tickle the client once per pending file.
438436
void GwDatArchive::ProcessPendingReads()
439437
{
440-
std::vector<std::pair<ReadCallback, std::vector<uint8_t>>> ready;
441-
std::vector<uint32_t> to_trigger; // file ids to ask the client to load, fired outside the lock
442-
TriggerFn trigger;
438+
std::vector<std::pair<ReadCallback, std::vector<uint8_t>>> ready; // callbacks fire outside the lock
443439
{
444440
std::scoped_lock<std::mutex> lock(m_pending_mutex);
445-
if (m_pending_reads.empty())
446-
return;
447-
trigger = m_trigger; // copy so we can call it after releasing the lock
448441
const uint32_t now = GetTickCount();
449442
for (auto it = m_pending_reads.begin(); it != m_pending_reads.end();) {
450443
std::vector<uint8_t> data;
451-
if (ReadFile(it->file_id, data, it->stream_id)) {
444+
if (ReadFile(it->file_id, data, it->stream_id))
452445
ready.emplace_back(std::move(it->callback), std::move(data));
453-
it = m_pending_reads.erase(it);
454-
}
455-
else if (static_cast<int32_t>(now - it->deadline_ms) >= 0) { // deadline passed (wrap-safe)
446+
else if (static_cast<int32_t>(now - it->deadline_ms) >= 0) // deadline passed (wrap-safe)
456447
ready.emplace_back(std::move(it->callback), std::vector<uint8_t>{});
457-
it = m_pending_reads.erase(it);
458-
}
459448
else {
460-
// Not resident yet: ask the client to fetch it, but only once per request.
461-
if (trigger && !it->triggered) {
462-
to_trigger.push_back(it->file_id);
449+
if (m_trigger && !it->triggered) { // ask the client to fetch it, once
450+
m_trigger(it->file_id);
463451
it->triggered = true;
464452
}
465453
++it;
454+
continue;
466455
}
456+
it = m_pending_reads.erase(it);
467457
}
468458
}
469-
for (uint32_t file_id : to_trigger)
470-
trigger(file_id);
471459
for (auto& [callback, data] : ready)
472460
callback(data);
473461
}

GWToolboxdll/Utils/GwDat/GwDatArchive.h

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,14 @@ class GwDatArchive {
3737
// Decompressed bytes for a GW file id; stream_id picks a stream (0 = the file's own data). False if absent.
3838
bool ReadFile(uint32_t file_id, std::vector<uint8_t>& out, uint32_t stream_id = 0);
3939

40-
// Async variant of ReadFile: the worker retries the read until the file appears in the dat, then
41-
// invokes `callback` (on the worker thread) with the decompressed bytes; if it hasn't shown up
42-
// within ~1 minute the callback fires once with an empty vector. Lets callers wait for files the
43-
// client streams in on demand (e.g. Steam .snapshot installs) without blocking. Starts the worker
44-
// if needed. Undelivered requests are dropped (callback not called) if the worker is stopped.
40+
// Async ReadFile: the worker retries until the file resolves, then calls `callback` (worker
41+
// thread) with the bytes, or with an empty vector after ~1 min; dropped if the worker stops.
42+
// For files the client streams in on demand (e.g. a Steam .snapshot).
4543
using ReadCallback = std::function<void(std::vector<uint8_t>&)>;
4644
void ReadFileAsync(uint32_t file_id, ReadCallback callback, uint32_t stream_id = 0);
4745

48-
// Optional hook that asks the running client to load a file id (from the dat or the network). When
49-
// set, ReadFileAsync calls it once per pending file that isn't resident yet, so streamed-only files
50-
// (e.g. a Steam .snapshot) get fetched instead of only waited for. Wired by the GWCA layer, which
51-
// owns the game-function lookup; the pure reader here works with or without it.
46+
// Optional hook to ask the client to fetch a file id; ReadFileAsync calls it once per pending
47+
// file not yet resident. Wired by the GWCA layer; the reader works with or without it.
5248
using TriggerFn = std::function<void(uint32_t file_id)>;
5349
void SetTrigger(TriggerFn trigger);
5450

@@ -112,13 +108,12 @@ class GwDatArchive {
112108
bool m_worker_running = false;
113109
bool m_worker_stop = false;
114110

115-
// Async ReadFile requests, retried by the worker until the file appears or the deadline passes.
116111
struct PendingRead {
117112
uint32_t file_id;
118113
uint32_t stream_id;
119-
uint32_t deadline_ms; // GetTickCount() value at which this request gives up
114+
uint32_t deadline_ms; // GetTickCount() at which the request gives up
120115
ReadCallback callback;
121-
bool triggered = false; // whether we've already asked the client to load this file
116+
bool triggered = false; // whether we've asked the client to fetch it yet
122117
};
123118
std::mutex m_pending_mutex; // guards m_pending_reads + m_trigger
124119
std::vector<PendingRead> m_pending_reads;

0 commit comments

Comments
 (0)