feat(ugc): processing options per make, recorded per model with their times

Staff can make models again with other processing options than the UGC
settings' (ray backend, hidden-face method, denoising) and every make records
what made it, for comparing the options.

- migration mysql 99 / sqlite 82 (ugc_process_options): ugc.process_options
  (picked for the next make, cleared once made), ugc.made_options (what made
  the current files) and ugc_process_runs (every successful make: options,
  wall and CPU time, hidden faces', occlusion's and icon's time, bricks,
  triangles before and after)
- IUgc: ResetUgcModelProcessing and ResetPropertyUgcModelProcessing take the
  options; PendingModel carries them; RecordUgcModelRun, GetUgcRunSummaries;
  list entries have madeOptions and processOptions
- the UGC server applies a job's options over its settings and records the run
- /api/ugc/reprocess takes options ("embree fast oidn"); /api/ugc/options
  lists the choices, the settings' defaults and averages per combination
- /reprocessproperty [builtin|embree|hiprt] [toolbox|fast] [off|oidn], any
  order, all optional

Check: run the migration on MySQL and SQLite; /reprocessproperty embree fast
on a property, then the models' made_options and ugc_process_runs rows;
/api/ugc/options.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 11:28:52 -05:00
parent 06be40471b
commit ef3c74f715
22 changed files with 290 additions and 58 deletions

View File

@@ -79,6 +79,7 @@ public:
std::string lxfml;
uint32_t attempts{};
bool priority{}; // staff asked for it to be made again: before any other model
std::string options; // the processing options staff picked for this make (UgcProcessOptions), empty: the settings'
};
// Up to `limit` pending models whose quiet period is over (process_after): the priority ones first, then the least
@@ -91,7 +92,8 @@ public:
virtual void ExpediteUgcModels(const LWOOBJID characterId) = 0;
// Records an attempt: the new state, how many attempts there have been, why it failed (empty when it didn't) and
// whether lighting was baked in; processed_at becomes now
// whether lighting was baked in; processed_at becomes now. Once it isn't pending any more, the priority and the
// processing options staff picked for it are cleared.
virtual void SetUgcModelProcessed(const LWOOBJID id, const eProcessState state, const uint32_t attempts, const std::string_view error, const bool bakeAo) = 0;
// What the UGC server counted when it made a model: its bricks and the most detailed mesh's triangles, after and
@@ -106,15 +108,50 @@ public:
};
virtual void SetUgcModelProcessStats(const LWOOBJID id, const ProcessStats& stats) = 0;
// A successful make of a model with the processing options that made it (UgcProcessOptions, every choice filled)
// and what it took (stats.json's times), for comparing the options
struct ProcessRun {
LWOOBJID id{};
std::string options;
uint32_t milliseconds{};
uint32_t cpuMilliseconds{};
uint32_t hsrMilliseconds{}; // removing hidden faces, every level
uint32_t aoMilliseconds{}; // the occlusion bake, every level
uint32_t iconMilliseconds{};
uint32_t bricks{};
uint32_t trianglesBefore{}; // the most detailed level's, before and after hidden faces were removed
uint32_t triangles{};
};
// Records a run (ugc_process_runs) and that the options made the model's files (made_options)
virtual void RecordUgcModelRun(const ProcessRun& run) = 0;
// The runs summed per options, the most used first
struct RunSummary {
std::string options;
uint64_t runs{};
uint64_t models{}; // different models
uint64_t milliseconds{}; // summed, as the rest
uint64_t cpuMilliseconds{};
uint64_t hsrMilliseconds{};
uint64_t aoMilliseconds{};
uint64_t iconMilliseconds{};
uint64_t bricks{};
uint64_t trianglesBefore{};
uint64_t triangles{};
};
virtual std::vector<RunSummary> GetUgcRunSummaries() = 0;
virtual std::optional<ProcessInfo> GetUgcProcessInfo(const LWOOBJID id) = 0;
// Sets models back to pending with no attempts: one (`id`), or all of them (`id` nullopt; only the failed ones
// with `failedOnly`). Returns how many rows changed.
virtual uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly) = 0;
// with `failedOnly`). `options`: the processing options for the next make (UgcProcessOptions), empty: the
// settings'. Returns how many rows changed.
virtual uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly, const std::string_view options) = 0;
// Sets every model placed on a property back to pending with no attempts, as priority (staff asked for it). Returns
// how many rows changed.
virtual uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId) = 0;
// Sets every model placed on a property back to pending with no attempts, as priority (staff asked for it), with
// `options` for the next make as above. Returns how many rows changed.
virtual uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) = 0;
// A page of models (all, or those in `state`), the newest first; `search` (when not empty) matches the model's id
// exactly or part of its owner's name

View File

@@ -41,6 +41,8 @@ public:
uint32_t processMemoryKb{}; // the memory the UGC server estimated for it (not measured)
std::string modelName; // models: the name a player gave it where it is placed (empty: none)
uint32_t trianglesBefore{}; // models: the most detailed level's triangles before hidden faces were removed (0: unknown)
std::string madeOptions; // models: the processing options that made its files (UgcProcessOptions; empty: unknown)
std::string processOptions; // models: the options staff picked for its next make (empty: the settings')
};
// What SearchUgc matches. A number (when set) is matched against ids; text against names

View File

@@ -31,10 +31,11 @@ namespace UgcLookupSql {
return (modular
? "SELECT b.ugc_id AS id, b.character_id, c.name AS character_name, COALESCE(c.account_id, 0) AS account_id, a.name AS account_name, "
"b.is_optimized, b.process_error, b.ldf_config AS detail, b.process_attempts, b.processed_at, 0 AS process_after, 0 AS bake_ao, "
"0 AS brick_count, 0 AS triangle_count, b.process_ms, b.process_cpu_ms, b.process_memory_kb, '' AS model_name, 0 AS triangle_count_before "
"0 AS brick_count, 0 AS triangle_count, b.process_ms, b.process_cpu_ms, b.process_memory_kb, '' AS model_name, 0 AS triangle_count_before, "
"'' AS made_options, '' AS process_options "
: "SELECT u.id, u.character_id, c.name AS character_name, u.account_id, a.name AS account_name, "
"u.is_optimized, u.process_error, u.filename AS detail, u.process_attempts, u.processed_at, u.process_after, u.bake_ao, "
"u.brick_count, u.triangle_count, u.process_ms, u.process_cpu_ms, u.process_memory_kb, u.triangle_count_before, "
"u.brick_count, u.triangle_count, u.process_ms, u.process_cpu_ms, u.process_memory_kb, u.triangle_count_before, u.made_options, u.process_options, "
// The name a player gave the model where it is placed (empty: none)
"COALESCE((SELECT pc.model_name FROM properties_contents AS pc WHERE pc.ugc_id = u.id AND pc.model_name <> '' LIMIT 1), '') AS model_name ") + From(modular);
}

View File

@@ -460,8 +460,10 @@ public:
void SetModularBuildProcessStats(const LWOOBJID id, const IUgc::ProcessStats& stats) override;
std::vector<IUgcModularBuild::PendingBuild> GetModularBuildsWithoutCombination(const uint32_t limit) override;
std::optional<IUgc::ProcessInfo> GetUgcProcessInfo(const LWOOBJID id) override;
uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly) override;
uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId) override;
uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly, const std::string_view options) override;
uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) override;
void RecordUgcModelRun(const ProcessRun& run) override;
std::vector<IUgc::RunSummary> GetUgcRunSummaries() override;
IUgc::ProcessTotals GetUgcProcessTotals(const bool modular) override;
std::vector<IUgc::ProcessInfo> GetUgcProcessList(const std::optional<eProcessState> state, const std::string_view search, const uint32_t offset, const uint32_t limit) override;
std::vector<std::pair<IUgc::eProcessState, uint64_t>> GetUgcProcessCounts() override;

View File

@@ -112,7 +112,7 @@ std::optional<IUgc::Model> MySQLDatabase::GetUgcModel(const LWOOBJID ugcId) {
}
std::vector<IUgc::PendingModel> MySQLDatabase::GetUgcModelsToProcess(const uint32_t limit, const bool priorityOnly) {
auto result = ExecuteSelect("SELECT id, lxfml, process_attempts, priority FROM ugc WHERE is_optimized = 0 AND process_after <= ? AND (? = 0 OR priority = 1) "
auto result = ExecuteSelect("SELECT id, lxfml, process_attempts, priority, process_options FROM ugc WHERE is_optimized = 0 AND process_after <= ? AND (? = 0 OR priority = 1) "
"ORDER BY priority DESC, process_attempts ASC, id DESC LIMIT ?;", UnixNow(), priorityOnly ? 1 : 0, limit);
std::vector<IUgc::PendingModel> models;
while (result->next()) {
@@ -124,13 +124,15 @@ std::vector<IUgc::PendingModel> MySQLDatabase::GetUgcModelsToProcess(const uint3
model.lxfml = contents.str();
model.attempts = static_cast<uint32_t>(result->getInt("process_attempts"));
model.priority = result->getInt("priority") != 0;
model.options = std::string(result->getString("process_options").c_str());
}
return models;
}
void MySQLDatabase::SetUgcModelProcessed(const LWOOBJID id, const eProcessState state, const uint32_t attempts, const std::string_view error, const bool bakeAo) {
ExecuteUpdate("UPDATE ugc SET is_optimized = ?, process_attempts = ?, process_error = ?, bake_ao = ?, processed_at = ?, priority = CASE WHEN ? = 0 THEN priority ELSE 0 END WHERE id = ?;",
static_cast<int32_t>(state), attempts, error, bakeAo, UnixNow(), static_cast<int32_t>(state), id);
ExecuteUpdate("UPDATE ugc SET is_optimized = ?, process_attempts = ?, process_error = ?, bake_ao = ?, processed_at = ?, priority = CASE WHEN ? = 0 THEN priority ELSE 0 END, "
"process_options = CASE WHEN ? = 0 THEN process_options ELSE '' END WHERE id = ?;",
static_cast<int32_t>(state), attempts, error, bakeAo, UnixNow(), static_cast<int32_t>(state), static_cast<int32_t>(state), id);
}
std::optional<IUgc::ProcessInfo> MySQLDatabase::GetUgcProcessInfo(const LWOOBJID id) {
@@ -141,10 +143,10 @@ std::optional<IUgc::ProcessInfo> MySQLDatabase::GetUgcProcessInfo(const LWOOBJID
return ReadUgcProcessInfo(result, false);
}
uint64_t MySQLDatabase::ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly) {
if (id) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0 WHERE id = ?;", *id);
if (failedOnly) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0 WHERE is_optimized = 2;");
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0;");
uint64_t MySQLDatabase::ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly, const std::string_view options) {
if (id) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, process_options = ? WHERE id = ?;", options, *id);
if (failedOnly) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, process_options = ? WHERE is_optimized = 2;", options);
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, process_options = ?;", options);
}
IUgc::ProcessTotals MySQLDatabase::GetUgcProcessTotals(const bool modular) {
@@ -165,9 +167,29 @@ IUgc::ProcessTotals MySQLDatabase::GetUgcProcessTotals(const bool modular) {
return totals;
}
uint64_t MySQLDatabase::ResetPropertyUgcModelProcessing(const LWOOBJID propertyId) {
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, priority = 1 "
"WHERE id IN (SELECT ugc_id FROM properties_contents WHERE property_id = ? AND ugc_id IS NOT NULL);", propertyId);
uint64_t MySQLDatabase::ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) {
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, priority = 1, process_options = ? "
"WHERE id IN (SELECT ugc_id FROM properties_contents WHERE property_id = ? AND ugc_id IS NOT NULL);", options, propertyId);
}
void MySQLDatabase::RecordUgcModelRun(const ProcessRun& run) {
ExecuteInsert("INSERT INTO ugc_process_runs (ugc_id, options, made_at, process_ms, process_cpu_ms, hsr_ms, ao_ms, icon_ms, bricks, triangles_before, triangles) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", run.id, run.options, UnixNow(), run.milliseconds, run.cpuMilliseconds, run.hsrMilliseconds,
run.aoMilliseconds, run.iconMilliseconds, run.bricks, run.trianglesBefore, run.triangles);
ExecuteUpdate("UPDATE ugc SET made_options = ? WHERE id = ?;", run.options, run.id);
}
std::vector<IUgc::RunSummary> MySQLDatabase::GetUgcRunSummaries() {
auto result = ExecuteSelect("SELECT options, COUNT(*) AS runs, COUNT(DISTINCT ugc_id) AS models, SUM(process_ms) AS ms, SUM(process_cpu_ms) AS cpu, "
"SUM(hsr_ms) AS hsr, SUM(ao_ms) AS ao, SUM(icon_ms) AS icon, SUM(bricks) AS bricks, SUM(triangles_before) AS before_tris, SUM(triangles) AS tris "
"FROM ugc_process_runs GROUP BY options ORDER BY runs DESC, options;");
std::vector<RunSummary> summaries;
while (result->next()) {
const auto field = [&](const char* name) { return static_cast<uint64_t>(std::llround(result->getDouble(name))); };
summaries.push_back({ std::string(result->getString("options").c_str()), field("runs"), field("models"), field("ms"), field("cpu"), field("hsr"), field("ao"),
field("icon"), field("bricks"), field("before_tris"), field("tris") });
}
return summaries;
}
std::vector<IUgc::ProcessInfo> MySQLDatabase::GetUgcProcessList(const std::optional<eProcessState> state, const std::string_view search, const uint32_t offset, const uint32_t limit) {

View File

@@ -25,6 +25,8 @@ namespace {
entry.processMemoryKb = static_cast<uint32_t>(result->getInt64("process_memory_kb"));
entry.modelName = result->getString("model_name").c_str();
entry.trianglesBefore = static_cast<uint32_t>(result->getInt64("triangle_count_before"));
entry.madeOptions = std::string(result->getString("made_options").c_str());
entry.processOptions = std::string(result->getString("process_options").c_str());
return entry;
}
}

View File

@@ -444,8 +444,10 @@ public:
void SetModularBuildProcessStats(const LWOOBJID id, const IUgc::ProcessStats& stats) override;
std::vector<IUgcModularBuild::PendingBuild> GetModularBuildsWithoutCombination(const uint32_t limit) override;
std::optional<IUgc::ProcessInfo> GetUgcProcessInfo(const LWOOBJID id) override;
uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly) override;
uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId) override;
uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly, const std::string_view options) override;
uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) override;
void RecordUgcModelRun(const ProcessRun& run) override;
std::vector<IUgc::RunSummary> GetUgcRunSummaries() override;
IUgc::ProcessTotals GetUgcProcessTotals(const bool modular) override;
std::vector<IUgc::ProcessInfo> GetUgcProcessList(const std::optional<eProcessState> state, const std::string_view search, const uint32_t offset, const uint32_t limit) override;
std::vector<std::pair<IUgc::eProcessState, uint64_t>> GetUgcProcessCounts() override;

View File

@@ -113,7 +113,7 @@ std::optional<IUgc::Model> SQLiteDatabase::GetUgcModel(const LWOOBJID ugcId) {
}
std::vector<IUgc::PendingModel> SQLiteDatabase::GetUgcModelsToProcess(const uint32_t limit, const bool priorityOnly) {
auto [_, result] = ExecuteSelect("SELECT id, lxfml, process_attempts, priority FROM ugc WHERE is_optimized = 0 AND process_after <= ? AND (? = 0 OR priority = 1) "
auto [_, result] = ExecuteSelect("SELECT id, lxfml, process_attempts, priority, process_options FROM ugc WHERE is_optimized = 0 AND process_after <= ? AND (? = 0 OR priority = 1) "
"ORDER BY priority DESC, process_attempts ASC, id DESC LIMIT ?;", UnixNow(), priorityOnly ? 1 : 0, limit);
std::vector<IUgc::PendingModel> models;
while (!result.eof()) {
@@ -124,14 +124,16 @@ std::vector<IUgc::PendingModel> SQLiteDatabase::GetUgcModelsToProcess(const uint
model.lxfml.assign(reinterpret_cast<const char*>(blob), blobSize);
model.attempts = static_cast<uint32_t>(result.getIntField("process_attempts"));
model.priority = result.getIntField("priority") != 0;
model.options = result.getStringField("process_options", "");
result.nextRow();
}
return models;
}
void SQLiteDatabase::SetUgcModelProcessed(const LWOOBJID id, const eProcessState state, const uint32_t attempts, const std::string_view error, const bool bakeAo) {
ExecuteUpdate("UPDATE ugc SET is_optimized = ?, process_attempts = ?, process_error = ?, bake_ao = ?, processed_at = ?, priority = CASE WHEN ? = 0 THEN priority ELSE 0 END WHERE id = ?;",
static_cast<int32_t>(state), attempts, error, bakeAo, UnixNow(), static_cast<int32_t>(state), id);
ExecuteUpdate("UPDATE ugc SET is_optimized = ?, process_attempts = ?, process_error = ?, bake_ao = ?, processed_at = ?, priority = CASE WHEN ? = 0 THEN priority ELSE 0 END, "
"process_options = CASE WHEN ? = 0 THEN process_options ELSE '' END WHERE id = ?;",
static_cast<int32_t>(state), attempts, error, bakeAo, UnixNow(), static_cast<int32_t>(state), static_cast<int32_t>(state), id);
}
std::optional<IUgc::ProcessInfo> SQLiteDatabase::GetUgcProcessInfo(const LWOOBJID id) {
@@ -142,10 +144,10 @@ std::optional<IUgc::ProcessInfo> SQLiteDatabase::GetUgcProcessInfo(const LWOOBJI
return ReadUgcProcessInfo(result, false);
}
uint64_t SQLiteDatabase::ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly) {
if (id) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0 WHERE id = ?;", *id);
if (failedOnly) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0 WHERE is_optimized = 2;");
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0;");
uint64_t SQLiteDatabase::ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly, const std::string_view options) {
if (id) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, process_options = ? WHERE id = ?;", options, *id);
if (failedOnly) return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, process_options = ? WHERE is_optimized = 2;", options);
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, process_options = ?;", options);
}
IUgc::ProcessTotals SQLiteDatabase::GetUgcProcessTotals(const bool modular) {
@@ -166,9 +168,30 @@ IUgc::ProcessTotals SQLiteDatabase::GetUgcProcessTotals(const bool modular) {
return totals;
}
uint64_t SQLiteDatabase::ResetPropertyUgcModelProcessing(const LWOOBJID propertyId) {
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, priority = 1 "
"WHERE id IN (SELECT ugc_id FROM properties_contents WHERE property_id = ? AND ugc_id IS NOT NULL);", propertyId);
uint64_t SQLiteDatabase::ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) {
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0, priority = 1, process_options = ? "
"WHERE id IN (SELECT ugc_id FROM properties_contents WHERE property_id = ? AND ugc_id IS NOT NULL);", options, propertyId);
}
void SQLiteDatabase::RecordUgcModelRun(const ProcessRun& run) {
ExecuteInsert("INSERT INTO ugc_process_runs (ugc_id, options, made_at, process_ms, process_cpu_ms, hsr_ms, ao_ms, icon_ms, bricks, triangles_before, triangles) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", run.id, run.options, UnixNow(), run.milliseconds, run.cpuMilliseconds, run.hsrMilliseconds,
run.aoMilliseconds, run.iconMilliseconds, run.bricks, run.trianglesBefore, run.triangles);
ExecuteUpdate("UPDATE ugc SET made_options = ? WHERE id = ?;", run.options, run.id);
}
std::vector<IUgc::RunSummary> SQLiteDatabase::GetUgcRunSummaries() {
auto [_, result] = ExecuteSelect("SELECT options, COUNT(*) AS runs, COUNT(DISTINCT ugc_id) AS models, SUM(process_ms) AS ms, SUM(process_cpu_ms) AS cpu, "
"SUM(hsr_ms) AS hsr, SUM(ao_ms) AS ao, SUM(icon_ms) AS icon, SUM(bricks) AS bricks, SUM(triangles_before) AS before_tris, SUM(triangles) AS tris "
"FROM ugc_process_runs GROUP BY options ORDER BY runs DESC, options;");
std::vector<RunSummary> summaries;
while (!result.eof()) {
const auto field = [&](const char* name) { return static_cast<uint64_t>(std::llround(result.getFloatField(name, 0.0))); };
summaries.push_back({ result.getStringField("options", ""), field("runs"), field("models"), field("ms"), field("cpu"), field("hsr"), field("ao"),
field("icon"), field("bricks"), field("before_tris"), field("tris") });
result.nextRow();
}
return summaries;
}
std::vector<IUgc::ProcessInfo> SQLiteDatabase::GetUgcProcessList(const std::optional<eProcessState> state, const std::string_view search, const uint32_t offset, const uint32_t limit) {

View File

@@ -25,6 +25,8 @@ namespace {
entry.processMemoryKb = static_cast<uint32_t>(result.getInt64Field("process_memory_kb"));
entry.modelName = result.getStringField("model_name", "");
entry.trianglesBefore = static_cast<uint32_t>(result.getInt64Field("triangle_count_before"));
entry.madeOptions = result.getStringField("made_options", "");
entry.processOptions = result.getStringField("process_options", "");
return entry;
}
}

View File

@@ -440,8 +440,10 @@ class TestSQLDatabase : public GameDatabase {
void SetModularBuildProcessStats(const LWOOBJID id, const IUgc::ProcessStats& stats) override {}
std::vector<IUgcModularBuild::PendingBuild> GetModularBuildsWithoutCombination(const uint32_t limit) override { return {}; }
std::optional<IUgc::ProcessInfo> GetUgcProcessInfo(const LWOOBJID id) override { return {}; }
uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly) override { return 0; }
uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId) override { return 0; }
uint64_t ResetUgcModelProcessing(const std::optional<LWOOBJID> id, const bool failedOnly, const std::string_view options) override { return 0; }
uint64_t ResetPropertyUgcModelProcessing(const LWOOBJID propertyId, const std::string_view options) override { return 0; }
void RecordUgcModelRun(const ProcessRun& run) override {}
std::vector<IUgc::RunSummary> GetUgcRunSummaries() override { return {}; }
IUgc::ProcessTotals GetUgcProcessTotals(const bool modular) override { return {}; }
std::vector<IUgc::ProcessInfo> GetUgcProcessList(const std::optional<eProcessState> state, const std::string_view search, const uint32_t offset, const uint32_t limit) override { return {}; }
std::vector<std::pair<IUgc::eProcessState, uint64_t>> GetUgcProcessCounts() override { return {}; }