mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
A new server (dUgcServer, started by master with enable_ugc_server=1) that takes unprocessed ugc and ugc_modular_build rows from the database and makes what the client downloads with UGCUSE3DSERVICES: an optimized NIF (hidden faces removed, ambient occlusion baked into vertex colors) and a 128px DDS icon for player models, rendered by a software rasterizer from the client's LDD brick primitives, and icons for cars and rockets assembled from their modules per ModularBuildComponent/ModuleComponent. It serves them, with the models' LXFML, over HTTP in the client's UGCC<dc>/3DOPTIMIZED and IMAGE128DDS layout with .gz and .checksum files, and keeps its folder under a size cap. Processing state lives in ugc.is_optimized plus new processed_at, process_attempts and process_error columns (and the same on ugc_modular_build). ServiceType::UGC is appended. NifFile moves to dCommon and records named node transforms for the modules' attach points. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
1.9 KiB
C++
61 lines
1.9 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <filesystem>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "dCommonVars.h"
|
|
|
|
/**
|
|
* Where the UGC server keeps what it makes: <root>/models/<id % 1000>/<id>/ for player models and
|
|
* <root>/modular/<id % 1000>/<id>/ for modular builds. An item's files are written to a temporary folder and renamed
|
|
* into place, so a request never sees half of them. Plain file operations, safe from any thread for different items.
|
|
*/
|
|
class UgcStorage {
|
|
public:
|
|
enum class Kind { MODEL, MODULAR };
|
|
|
|
// The files an item has, by name (see FileName)
|
|
using Files = std::map<std::string, std::string>;
|
|
|
|
explicit UgcStorage(std::filesystem::path root);
|
|
|
|
const std::filesystem::path& GetRoot() const { return m_Root; }
|
|
|
|
std::filesystem::path Folder(Kind kind, LWOOBJID id) const;
|
|
|
|
// A file of an item, if it is there; `name` must be one of the names the server writes
|
|
std::optional<std::filesystem::path> File(Kind kind, LWOOBJID id, const std::string& name) const;
|
|
|
|
// Replaces an item's files with `files`; the bytes written, nullopt (and `error`) on failure
|
|
std::optional<uint64_t> Write(Kind kind, LWOOBJID id, const Files& files, std::string& error) const;
|
|
|
|
// Deletes an item's files
|
|
void Remove(Kind kind, LWOOBJID id) const;
|
|
|
|
// Marks an item used now, for eviction
|
|
void Touch(Kind kind, LWOOBJID id) const;
|
|
|
|
struct Entry {
|
|
Kind kind{};
|
|
LWOOBJID id{};
|
|
uint64_t bytes{};
|
|
std::filesystem::file_time_type used{};
|
|
};
|
|
|
|
// Everything stored, with sizes and when it was last used
|
|
std::vector<Entry> List() const;
|
|
|
|
// Removes the least recently used items until the total is at most `maxBytes`; what was removed
|
|
std::vector<Entry> Evict(uint64_t maxBytes) const;
|
|
|
|
// Names the server writes (and serves); anything else is refused
|
|
static bool IsKnownFile(const std::string& name);
|
|
|
|
private:
|
|
std::filesystem::path m_Root;
|
|
};
|