mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 19:03:43 +00:00
- The client puts a shape in its sorted, blended pass only when its NiMaterialProperty alpha is under 0.99999 (ShaderCommon::GetAlphaFlags 0x0109f5a0; the NiAlphaProperty blend flag isn't read); at 1.0 it's drawn solid with blending off. Transparent (and transparent glitter) shapes now get a material with alpha 0.9999, as the S01_Alpha shapes of the game's own brick models (res/BrickModels/ndmade) do; opaque shapes keep 1.0. Models with a transparent brick change; the others are byte for byte the same. - dUgcServer's files move into Bricks/, Model/, Render/, Formats/ and Processing/ (the CMakeLists says what each holds); includes are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
2.5 KiB
C++
70 lines
2.5 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;
|
|
|
|
// Replaces some of an item's files in place (each written aside and renamed over the old one), keeping the others;
|
|
// the ones kept for comparing (icon.png...) are copied to previous.* first. The bytes written, nullopt when the item
|
|
// has no folder or a write fails.
|
|
std::optional<uint64_t> Update(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;
|
|
|
|
// An item's .nif (`name` model.nif, model.noao.nif or previous.model.nif): stored compressed (<name>.gz), or as it is
|
|
// (made by older versions); nullopt when there's neither
|
|
std::optional<std::string> ReadNif(Kind kind, LWOOBJID id, const std::string& name) const;
|
|
|
|
// Names the server writes (and serves); anything else is refused
|
|
static bool IsKnownFile(const std::string& name);
|
|
|
|
private:
|
|
std::filesystem::path m_Root;
|
|
};
|