Files
DarkflameServer/dDatabase/GameDatabase/ITables/IUgc.h
Aaron Kimbrell 1309000460 feat(ugc): models with no bricks are "empty", not failed
A model with no bricks has nothing to make: it gets its own state
(is_optimized = 3), isn't counted as a failure or retried, shows as Empty
on the UGC page (with its own filter and count), in the status and in
Prometheus, and its downloads answer 404 like HKX. State names come from
the enum (magic_enum). Migrations dlu/mysql/87 and dlu/sqlite/70 move the
rows that failed only because they had no bricks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 14:56:46 -05:00

109 lines
4.2 KiB
C++

#ifndef __IUGC__H__
#define __IUGC__H__
#include <cstdint>
#include <sstream>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "magic_enum.hpp"
class IUgc {
public:
struct Model {
std::stringstream lxfmlData;
LWOOBJID id{};
LWOOBJID modelID{};
};
// Gets all UGC models for the given property id.
virtual std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) = 0;
// Gets all Ugcs models.
virtual std::vector<IUgc::Model> GetAllUgcModels() = 0;
// Removes ugc models that are not referenced by any property.
virtual void RemoveUnreferencedUgcModels() = 0;
// Deletes the ugc model for the given model id.
virtual void DeleteUgcModelData(const LWOOBJID& modelId) = 0;
// Inserts a new UGC model into the database.
virtual void UpdateUgcModelData(const LWOOBJID& modelId, std::stringstream& lxfml, const int64_t processAfter) = 0;
virtual std::optional<IUgc::Model> GetUgcModel(const LWOOBJID ugcId) = 0;
// ---- Processing by the UGC server (is_optimized, processed_at, process_attempts, process_error) ----
// is_optimized's values
enum class eProcessState : int32_t {
PENDING = 0, // not made yet (or to be made again)
DONE = 1, // the UGC server's files are made
FAILED = 2, // gave up after the allowed attempts
EMPTY = 3, // nothing to make: the model has no bricks (not a failure; never retried)
};
// A state's name for the dashboard, the API and metrics ("pending", "done", "failed", "empty")
static std::string ProcessStateName(eProcessState state) {
std::string name(magic_enum::enum_name(state));
for (auto& c : name) c = static_cast<char>(c >= 'A' && c <= 'Z' ? c - 'A' + 'a' : c);
return name.empty() ? "unknown" : name;
}
static std::optional<eProcessState> ParseProcessState(std::string_view text) {
for (const auto state : magic_enum::enum_values<eProcessState>()) {
if (ProcessStateName(state) == text) return state;
}
return std::nullopt;
}
// A row's processing state, for the UGC server and the dashboard
struct ProcessInfo {
LWOOBJID id{};
LWOOBJID characterId{};
std::string characterName; // empty when the character is gone
eProcessState state{};
uint32_t attempts{};
int64_t processedAt{}; // Unix seconds of the last attempt, 0 for none
std::string error;
bool bakeAo{};
std::string details; // modular builds: the modules (ldf_config)
int64_t processAfter{}; // models: Unix seconds before which it isn't made (the quiet period after a save)
};
// A model waiting to be made: its id, stored LXFML (sd0) and the attempts so far
struct PendingModel {
LWOOBJID id{};
std::string lxfml;
uint32_t attempts{};
};
// Up to `limit` pending models whose quiet period is over (process_after), the least tried and then the newest first
virtual std::vector<PendingModel> GetUgcModelsToProcess(const uint32_t limit) = 0;
// Ends the quiet period of a waiting model (a client asked for it), or of all a character's waiting models (they
// left the property)
virtual void ExpediteUgcModel(const LWOOBJID id) = 0;
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
virtual void SetUgcModelProcessed(const LWOOBJID id, const eProcessState state, const uint32_t attempts, const std::string_view error, const bool bakeAo) = 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;
// 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
virtual std::vector<ProcessInfo> GetUgcProcessList(const std::optional<eProcessState> state, const std::string_view search, const uint32_t offset, const uint32_t limit) = 0;
// How many models are in each state
virtual std::vector<std::pair<eProcessState, uint64_t>> GetUgcProcessCounts() = 0;
};
#endif //!__IUGC__H__