mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
feat(ugc): processing totals on the UGC page; no shared icon preset for player models
- IUgc::GetUgcProcessTotals sums what the UGC server made, for models and for car and rocket builds: count, time spent (and how many are timed), CPU time, average and slowest, average and most memory (estimate), bricks, triangles and triangles saved (models whose count before hidden face removal is known). /api/ugc returns them as totals and the UGC page shows a card for each kind. Parity tested. - Player models no longer have a shared icon preset: every one is a different size and shape, so its icon is fitted to it from the settings. The UGC server ignores a kind:model preset, the dashboard refuses to save one, and the icon editor hides the type buttons for models. One model's own icon values still work. Car and rocket build types keep theirs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -250,6 +250,13 @@ namespace {
|
||||
return GeneralUtils::TryParse<LWOOBJID>(it->is_string() ? it->get<std::string>() : it->dump());
|
||||
}
|
||||
|
||||
// Sums over what the UGC server has made (IUgc::GetUgcProcessTotals)
|
||||
nlohmann::json Totals(const IUgc::ProcessTotals& t) {
|
||||
return { { "made", t.made }, { "timed", t.timed }, { "ms", t.milliseconds }, { "cpuMs", t.cpuMilliseconds }, { "maxMs", t.maxMilliseconds },
|
||||
{ "averageMs", t.timed ? t.milliseconds / t.timed : 0 }, { "memoryKbAverage", t.memoryKbAverage }, { "memoryKbMax", t.memoryKbMax },
|
||||
{ "bricks", t.bricks }, { "triangles", t.triangles }, { "trianglesBefore", t.trianglesBefore }, { "trianglesAfter", t.trianglesAfter } };
|
||||
}
|
||||
|
||||
nlohmann::json Counts(const std::vector<std::pair<IUgc::eProcessState, uint64_t>>& counts) {
|
||||
nlohmann::json out = nlohmann::json::object();
|
||||
for (const auto state : magic_enum::enum_values<IUgc::eProcessState>()) out[IUgc::ProcessStateName(state)] = 0;
|
||||
@@ -351,6 +358,7 @@ namespace UgcRoutes {
|
||||
}
|
||||
}
|
||||
JsonSuccess(reply, { { "counts", { { "model", Counts(Database::Get()->GetUgcProcessCounts()) }, { "modular", Counts(Database::Get()->GetModularBuildProcessCounts()) } } },
|
||||
{ "totals", { { "model", Totals(Database::Get()->GetUgcProcessTotals(false)) }, { "modular", Totals(Database::Get()->GetUgcProcessTotals(true)) } } },
|
||||
{ "items", items }, { "total", total }, { "page", page }, { "size", size }, { "more", static_cast<uint64_t>(page + 1) * size < total }, { "kinds", kinds },
|
||||
{ "ugcPublicUrl", Game::config->GetValue("ugc_public_url") }, { "canManage", Can(context, "ugc_manage") } });
|
||||
});
|
||||
@@ -605,7 +613,8 @@ namespace UgcRoutes {
|
||||
const auto value = UgcSetting(param.setting);
|
||||
settings[param.key] = std::clamp(value ? GeneralUtils::TryParse<float>(*value).value_or(param.defaultValue) : param.defaultValue, param.min, param.max);
|
||||
}
|
||||
JsonSuccess(reply, { { "kind", kind }, { "target", target }, { "settings", settings }, { "preset", StoredValues(UgcIconParams::KindTarget(kind)) },
|
||||
JsonSuccess(reply, { { "kind", kind }, { "target", target }, { "settings", settings }, { "preset", kind == UgcIconParams::ModelKind() ? nlohmann::json() : StoredValues(UgcIconParams::KindTarget(kind)) },
|
||||
{ "presets", kind != UgcIconParams::ModelKind() },
|
||||
{ "own", target.empty() ? nlohmann::json(nullptr) : StoredValues(target) } });
|
||||
});
|
||||
|
||||
@@ -659,6 +668,9 @@ namespace UgcRoutes {
|
||||
bool known = false;
|
||||
for (const auto& entry : IconKinds()) known = known || entry["kind"] == kind;
|
||||
if (!known) return JsonError(reply, eHTTPStatusCode::BAD_REQUEST, "Unknown kind");
|
||||
if (kind == UgcIconParams::ModelKind()) {
|
||||
return JsonError(reply, eHTTPStatusCode::BAD_REQUEST, "Player models have no shared icon preset: each is fitted to its icon. Change one model's icon instead.");
|
||||
}
|
||||
target = UgcIconParams::KindTarget(kind);
|
||||
what = "the " + kind + " icon preset";
|
||||
} else if (body->value("kind", std::string()) == "modular") {
|
||||
|
||||
@@ -94,7 +94,11 @@
|
||||
if (!d.success) throw new Error(d.error || 'No settings');
|
||||
layers = { kind: d.kind, settings: d.settings, preset: d.preset, own: d.own };
|
||||
$('framingKind').textContent = kindLabel();
|
||||
setAll(layered(3), d.own ? 'This item has its own values.' : d.preset ? 'The type’s preset.' : 'The default settings.');
|
||||
// Player models have no shared preset: each is fitted to its icon; only its own values change it
|
||||
var shared = d.presets !== false;
|
||||
$('framingSaveType').classList.toggle('d-none', !shared);
|
||||
$('framingResetType').classList.toggle('d-none', !shared);
|
||||
setAll(layered(3), d.own ? 'This item has its own values.' : d.preset ? 'The type’s preset.' : shared ? 'The default settings.' : 'Fitted to the icon from the default settings.');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,23 @@
|
||||
fmt.badge(c.done + ' made', 'success') + ' ' + fmt.badge(c.pending + ' waiting', 'secondary') + ' ' + fmt.badge(c.failed + ' failed', c.failed ? 'danger' : 'secondary') +
|
||||
(c.empty ? ' ' + fmt.badge(c.empty + ' empty', 'light') : '') + '</div></div></div>';
|
||||
}
|
||||
// What making them all took, and what it saved (the rows' recorded stats; ones made before a stat existed don't count)
|
||||
function totalsCard(title, t) {
|
||||
if (!t || !t.made) return '';
|
||||
var saved = t.trianglesBefore ? t.trianglesBefore - t.trianglesAfter : 0;
|
||||
var rows = [
|
||||
['Time spent making', duration(t.ms) + (t.timed < t.made ? ' <span class="text-body-secondary">(' + esc(t.timed) + ' of ' + esc(t.made) + ' timed)</span>' : '')],
|
||||
['CPU time', duration(t.cpuMs)],
|
||||
['Average / slowest', duration(t.averageMs) + ' / ' + duration(t.maxMs)],
|
||||
['Memory (est.) average / most', mb(t.memoryKbAverage * 1024) + ' / ' + mb(t.memoryKbMax * 1024)]
|
||||
];
|
||||
if (t.bricks) rows.push(['Bricks', Number(t.bricks).toLocaleString()]);
|
||||
if (t.triangles) rows.push(['Triangles (most detailed level)', Number(t.triangles).toLocaleString()]);
|
||||
if (saved) rows.push(['Triangles saved', Number(saved).toLocaleString() + ' (' + (saved / t.trianglesBefore * 100).toFixed(1) + '% of ' + Number(t.trianglesBefore).toLocaleString() + ')']);
|
||||
return '<div class="col-md-6"><div class="card"><div class="card-body py-2"><div class="small text-body-secondary mb-1">' + esc(title) + ': totals</div>' +
|
||||
'<table class="table table-sm mb-0 small"><tbody>' + rows.map(function (r) { return '<tr><th class="fw-normal text-body-secondary">' + r[0] + '</th><td>' + r[1] + '</td></tr>'; }).join('') +
|
||||
'</tbody></table></div></div></div>';
|
||||
}
|
||||
function owner(i) {
|
||||
return i.characterName ? '<a href="/characters/' + esc(i.characterId) + '">' + esc(i.characterName) + '</a>' : '<span class="text-body-secondary">' + esc(i.characterId) + '</span>';
|
||||
}
|
||||
@@ -215,7 +232,8 @@
|
||||
}
|
||||
$('manageButtons').classList.toggle('d-none', !canManage);
|
||||
$('cacheCard').classList.toggle('d-none', !canManage);
|
||||
$('counts').innerHTML = countCard('Models', d.counts.model) + countCard('Cars and rockets (builds)', d.counts.modular);
|
||||
$('counts').innerHTML = countCard('Models', d.counts.model) + countCard('Cars and rockets (builds)', d.counts.modular) +
|
||||
(d.totals ? totalsCard('Models', d.totals.model) + totalsCard('Cars and rockets', d.totals.modular) : '');
|
||||
}
|
||||
function filterQuery() {
|
||||
return 'kind=' + list.kind + '&q=' + encodeURIComponent(list.q) + '&state=' + list.state + '&type=' + encodeURIComponent(list.kind === 'modular' ? list.type : '');
|
||||
@@ -646,6 +664,8 @@
|
||||
|
||||
function loadPresets() {
|
||||
UgcIconEditor.kinds().then(function (kinds) {
|
||||
// Player models have no shared preset (each is fitted to its icon): only cars and rockets have presets
|
||||
kinds = kinds.filter(function (k) { return k.kind !== 'model'; });
|
||||
$('presetsList').innerHTML = kinds.map(function (k) {
|
||||
var sample = k.sample ? (k.kind === 'model' ? 'model ' + k.sample : 'modules ' + k.sample + (k.sampleBuilds ? ' (' + k.sampleBuilds + ' builds)' : '')) : 'nothing made yet';
|
||||
return '<button type="button" class="btn btn-sm btn-outline-primary text-start" data-preset="' + esc(k.kind) + '"' + (k.sample ? '' : ' disabled') + '>' +
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
<details class="card mb-3" id="presetsCard">
|
||||
<summary class="card-header py-2 small fw-semibold">Icon presets per type</summary>
|
||||
<div class="card-body py-2 small">
|
||||
<p class="text-body-secondary mb-2">Each type of icon (player models, and each car or rocket build type in the client's data) has a preset over the
|
||||
default settings. Open one to set its camera, the model's turn, the light and the border on an example.</p>
|
||||
<p class="text-body-secondary mb-2">Each car or rocket build type in the client's data has a preset over the default settings. Open one to set
|
||||
its camera, the model's turn, the light and the border on an example. Player models have no preset: each one is a different size and
|
||||
shape, so its icon is fitted to it from the defaults; open a model to change just its icon.</p>
|
||||
<div class="d-flex flex-wrap gap-2" id="presetsList">Loading…</div>
|
||||
<div data-ugc-settings="UGC icons" data-title="Icon defaults (under every preset)"></div>
|
||||
</div>
|
||||
|
||||
@@ -123,6 +123,24 @@ public:
|
||||
// How many models are in each state
|
||||
virtual std::vector<std::pair<eProcessState, uint64_t>> GetUgcProcessCounts() = 0;
|
||||
|
||||
// Sums over the made items (is_optimized 1) of the model table, or of the car and rocket builds (`modular`; they
|
||||
// have no bricks or triangles). Items made before a stat was recorded have 0 for it and are left out of its averages
|
||||
// and of the triangles saved.
|
||||
struct ProcessTotals {
|
||||
uint64_t made{};
|
||||
uint64_t timed{}; // made ones with a recorded time
|
||||
uint64_t milliseconds{}; // wall time, summed
|
||||
uint64_t cpuMilliseconds{};
|
||||
uint64_t maxMilliseconds{};
|
||||
uint64_t memoryKbAverage{}; // estimate
|
||||
uint64_t memoryKbMax{};
|
||||
uint64_t bricks{};
|
||||
uint64_t triangles{};
|
||||
uint64_t trianglesBefore{}; // of the models whose count before hidden-face removal is known
|
||||
uint64_t trianglesAfter{}; // the same models' after
|
||||
};
|
||||
virtual ProcessTotals GetUgcProcessTotals(const bool modular) = 0;
|
||||
|
||||
// ---- Checksums of the files the UGC server made (ugc_file_checksums), for the client's manifest requests ----
|
||||
|
||||
// What the files are stored under: a player model's ugc id, or a combination of car or rocket modules
|
||||
|
||||
@@ -438,6 +438,7 @@ public:
|
||||
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;
|
||||
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;
|
||||
std::vector<IUgcModularBuild::PendingBuild> GetModularBuildsToProcess(const uint32_t limit) override;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "MySQLDatabase.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
IUgc::ProcessInfo ReadUgcProcessInfo(PreparedStmtResultSet& result, bool modular) {
|
||||
@@ -146,6 +147,24 @@ uint64_t MySQLDatabase::ResetUgcModelProcessing(const std::optional<LWOOBJID> id
|
||||
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0;");
|
||||
}
|
||||
|
||||
IUgc::ProcessTotals MySQLDatabase::GetUgcProcessTotals(const bool modular) {
|
||||
const std::string sql = modular
|
||||
? "SELECT COUNT(*) AS made, SUM(CASE WHEN process_ms > 0 THEN 1 ELSE 0 END) AS timed, COALESCE(SUM(process_ms), 0) AS ms, COALESCE(SUM(process_cpu_ms), 0) AS cpu, "
|
||||
"COALESCE(MAX(process_ms), 0) AS maxms, COALESCE(AVG(NULLIF(process_memory_kb, 0)), 0) AS memavg, COALESCE(MAX(process_memory_kb), 0) AS memmax, "
|
||||
"0 AS bricks, 0 AS tris, 0 AS before_tris, 0 AS after_tris FROM ugc_modular_build WHERE is_optimized = 1;"
|
||||
: "SELECT COUNT(*) AS made, SUM(CASE WHEN process_ms > 0 THEN 1 ELSE 0 END) AS timed, COALESCE(SUM(process_ms), 0) AS ms, COALESCE(SUM(process_cpu_ms), 0) AS cpu, "
|
||||
"COALESCE(MAX(process_ms), 0) AS maxms, COALESCE(AVG(NULLIF(process_memory_kb, 0)), 0) AS memavg, COALESCE(MAX(process_memory_kb), 0) AS memmax, "
|
||||
"COALESCE(SUM(brick_count), 0) AS bricks, COALESCE(SUM(triangle_count), 0) AS tris, "
|
||||
"COALESCE(SUM(CASE WHEN triangle_count_before > 0 THEN triangle_count_before ELSE 0 END), 0) AS before_tris, "
|
||||
"COALESCE(SUM(CASE WHEN triangle_count_before > 0 THEN triangle_count ELSE 0 END), 0) AS after_tris FROM ugc WHERE is_optimized = 1;";
|
||||
auto result = ExecuteSelect(sql);
|
||||
IUgc::ProcessTotals totals;
|
||||
if (!result->next()) return totals;
|
||||
const auto field = [&](const char* name) { return static_cast<uint64_t>(std::llround(result->getDouble(name))); };
|
||||
totals = { field("made"), field("timed"), field("ms"), field("cpu"), field("maxms"), field("memavg"), field("memmax"), field("bricks"), field("tris"), field("before_tris"), field("after_tris") };
|
||||
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);
|
||||
|
||||
@@ -422,6 +422,7 @@ public:
|
||||
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;
|
||||
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;
|
||||
std::vector<IUgcModularBuild::PendingBuild> GetModularBuildsToProcess(const uint32_t limit) override;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "SQLiteDatabase.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
IUgc::ProcessInfo ReadUgcProcessInfo(CppSQLite3Query& result, bool modular) {
|
||||
@@ -147,6 +148,24 @@ uint64_t SQLiteDatabase::ResetUgcModelProcessing(const std::optional<LWOOBJID> i
|
||||
return ExecuteUpdate("UPDATE ugc SET is_optimized = 0, process_attempts = 0, process_error = '', process_after = 0;");
|
||||
}
|
||||
|
||||
IUgc::ProcessTotals SQLiteDatabase::GetUgcProcessTotals(const bool modular) {
|
||||
const std::string sql = modular
|
||||
? "SELECT COUNT(*) AS made, SUM(CASE WHEN process_ms > 0 THEN 1 ELSE 0 END) AS timed, COALESCE(SUM(process_ms), 0) AS ms, COALESCE(SUM(process_cpu_ms), 0) AS cpu, "
|
||||
"COALESCE(MAX(process_ms), 0) AS maxms, COALESCE(AVG(NULLIF(process_memory_kb, 0)), 0) AS memavg, COALESCE(MAX(process_memory_kb), 0) AS memmax, "
|
||||
"0 AS bricks, 0 AS tris, 0 AS before_tris, 0 AS after_tris FROM ugc_modular_build WHERE is_optimized = 1;"
|
||||
: "SELECT COUNT(*) AS made, SUM(CASE WHEN process_ms > 0 THEN 1 ELSE 0 END) AS timed, COALESCE(SUM(process_ms), 0) AS ms, COALESCE(SUM(process_cpu_ms), 0) AS cpu, "
|
||||
"COALESCE(MAX(process_ms), 0) AS maxms, COALESCE(AVG(NULLIF(process_memory_kb, 0)), 0) AS memavg, COALESCE(MAX(process_memory_kb), 0) AS memmax, "
|
||||
"COALESCE(SUM(brick_count), 0) AS bricks, COALESCE(SUM(triangle_count), 0) AS tris, "
|
||||
"COALESCE(SUM(CASE WHEN triangle_count_before > 0 THEN triangle_count_before ELSE 0 END), 0) AS before_tris, "
|
||||
"COALESCE(SUM(CASE WHEN triangle_count_before > 0 THEN triangle_count ELSE 0 END), 0) AS after_tris FROM ugc WHERE is_optimized = 1;";
|
||||
auto [_, result] = ExecuteSelect(sql);
|
||||
IUgc::ProcessTotals totals;
|
||||
if (result.eof()) return totals;
|
||||
const auto field = [&](const char* name) { return static_cast<uint64_t>(std::llround(result.getFloatField(name, 0.0))); };
|
||||
totals = { field("made"), field("timed"), field("ms"), field("cpu"), field("maxms"), field("memavg"), field("memmax"), field("bricks"), field("tris"), field("before_tris"), field("after_tris") };
|
||||
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);
|
||||
|
||||
@@ -420,6 +420,7 @@ class TestSQLDatabase : public GameDatabase {
|
||||
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; }
|
||||
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 {}; }
|
||||
std::vector<IUgcModularBuild::PendingBuild> GetModularBuildsToProcess(const uint32_t limit) override { return {}; }
|
||||
|
||||
@@ -683,7 +683,11 @@ nlohmann::json UgcProcessor::Status() const {
|
||||
|
||||
UgcIconParams::Values UgcProcessor::IconValues(const std::string& kind, const std::string& itemTarget) {
|
||||
UgcIconParams::Values values;
|
||||
if (const auto preset = Database::Get()->GetUgcIconSettings(UgcIconParams::KindTarget(kind))) values = UgcIconParams::Parse(*preset);
|
||||
// Player models have no shared preset: every one is a different size and shape, so each is fitted to the icon from
|
||||
// the defaults, and only its own settings change it. Cars and rockets of a build type share a preset.
|
||||
if (kind != UgcIconParams::ModelKind()) {
|
||||
if (const auto preset = Database::Get()->GetUgcIconSettings(UgcIconParams::KindTarget(kind))) values = UgcIconParams::Parse(*preset);
|
||||
}
|
||||
if (const auto own = Database::Get()->GetUgcIconSettings(itemTarget)) {
|
||||
for (const auto& [key, value] : UgcIconParams::Parse(*own)) values[key] = value;
|
||||
}
|
||||
|
||||
@@ -174,8 +174,10 @@ and the notices (see Threads). Cars and rockets are made once per combination of
|
||||
`icon_ambient`, `icon_sun_strength` and `icon_shadows` lines of existing ugcconfig.ini files, with the darker
|
||||
values, are no longer read). Every framing and light value (key, `icon_*` setting, range, default) is listed once in `UgcIconParams`; the
|
||||
settings, the dashboard's settings page and its icon editor are built from that list. Values come from the settings,
|
||||
then the kind's preset (player models, or a car or rocket build type from the client's `ModularBuildComponent`),
|
||||
then the item's own (a model, or a combination of car or rocket modules), the last two in `ugc_icon_settings`.
|
||||
then the kind's preset (a car or rocket build type from the client's `ModularBuildComponent`; player models have none:
|
||||
each is a different size and shape, so its icon is fitted to it from the settings, and the dashboard refuses a player
|
||||
model preset), then the item's own (a model, or a combination of car or rocket modules), the last two in
|
||||
`ugc_icon_settings`.
|
||||
|
||||
**The pose.** The camera, the model's turn and the crop are worked out in `UgcIconPose` (shared with the
|
||||
dashboard's editor, see below), in this order: the model is turned about its origin by `modelYaw` (around +Y),
|
||||
|
||||
@@ -772,6 +772,17 @@ TEST_F(ParitySeeded, UgcModel) {
|
||||
db.SetUgcModelProcessed(1152921510000500001LL, IUgc::eProcessState::DONE, 1, "", true);
|
||||
return json{ changed, infoJson(db.GetUgcProcessInfo(1152921510000500001LL)), infoJson(db.GetUgcProcessInfo(1)) };
|
||||
});
|
||||
Both("GetUgcProcessTotals", [&](GameDatabase& db) {
|
||||
db.SetUgcModelProcessed(1152921510000500001LL, IUgc::eProcessState::DONE, 1, "", true);
|
||||
db.SetUgcModelStats(1152921510000500001LL, 12, 300, 500);
|
||||
db.SetUgcModelProcessStats(1152921510000500001LL, { 1500, 1200, 2048 });
|
||||
const auto totals = db.GetUgcProcessTotals(false);
|
||||
const auto modular = db.GetUgcProcessTotals(true);
|
||||
const auto json = [](const IUgc::ProcessTotals& t) {
|
||||
return nlohmann::json{ t.made, t.timed, t.milliseconds, t.cpuMilliseconds, t.maxMilliseconds, t.memoryKbAverage, t.memoryKbMax, t.bricks, t.triangles, t.trianglesBefore, t.trianglesAfter };
|
||||
};
|
||||
return nlohmann::json{ json(totals), json(modular) };
|
||||
});
|
||||
Both("ResetPropertyUgcModelProcessing", [&](GameDatabase& db) {
|
||||
IPropertyContents::Model model;
|
||||
model.id = 1152921510000400009LL; model.lot = 14; model.ugcId = 1152921510000500001LL;
|
||||
|
||||
Reference in New Issue
Block a user