mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-08 13:53:45 +00:00
A placed model's client (1.10.64, UGCUSE3DSERVICES=7:0) always loads its blueprint's NIF and HKX (its BlueprintComponent sets renderUserGen and physicsUserGen itself) and its LXFML, asks the world for each file's manifest first and waits for the answer with no timeout. With ugc_manifest=1 and the new ugc_manifest_models=1 (default 0) the world: - leaves the models whose mesh the UGC server made out of the LXFML it sends when a property loads, - answers their NIF with the UGC server's checksum, their LXFML with the stored LXFML's (worked out once and kept) and their HKX as not known, - sends a model that isn't made its LXFML (once for the three requests), so the client builds it itself and no model is left waiting. When the UGC server writes a model's mesh with a new checksum it sends UGC_MODELS_MADE (a new master message, appended) to the master, which passes it to every world; a world with that model placed sends its players the new NIF checksum and NotifyClientUGCModelReady (game message 909, the blueprint id), so clients switch to the served mesh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
68 lines
3.4 KiB
C++
68 lines
3.4 KiB
C++
#ifndef UGCMANIFEST_H
|
|
#define UGCMANIFEST_H
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "dCommonVars.h"
|
|
#include "eUgcResourceType.h"
|
|
#include "IUgc.h"
|
|
#include "RakNetTypes.h"
|
|
|
|
/**
|
|
* Answers the client's REQUEST_UGC_MANIFEST_INFO (sent when its UGCUSE3DSERVICES is off, the default): the MD5 and
|
|
* size of a blueprint's file, which the client needs before it uses or downloads the file from the UGC server
|
|
* (BrickModels/UserMade/<id % 1000>/<id>.<ext>.sd0). Nothing is answered unless `ugc_manifest` is 1.
|
|
*
|
|
* * Icons (DDS): the checksum the UGC server stored when it made the icon (ugc_file_checksums); one it hasn't made yet
|
|
* is answered once it has (Update looks again every few seconds for a while).
|
|
* * Player models (NIF, HKX, LXFML): a placed model's client always asks for all three (its BlueprintComponent loads the
|
|
* blueprint's NIF and HKX, its ModelBehaviorComponent the LXFML) and waits for the answers without a timeout. With
|
|
* `ugc_manifest_models` 1 and the model's mesh made, the NIF is answered with the UGC server's checksum (the client
|
|
* downloads the served mesh), the LXFML with the stored LXFML's and the HKX as not known (valid 0: the client uses
|
|
* one it has, else asks the UGC server, which answers 404). Otherwise the world sends that client the model's LXFML
|
|
* (BlueprintSaveResponse), the client builds the NIF and HKX itself and caches their checksums, which answers its
|
|
* own requests: a model is never left waiting.
|
|
*
|
|
* Main thread only: each lookup is one indexed query and the answers are sent from here. See docs/UgcServer.md.
|
|
*/
|
|
namespace UgcManifest {
|
|
// What a request gets
|
|
enum class eAction {
|
|
NONE, // not answered (ugc_manifest off, or not a UGC type)
|
|
ANSWER, // the stored (or, for LXFML, computed) checksum
|
|
ANSWER_UNKNOWN,// valid 0: the client uses the file it has, or downloads it
|
|
SEND_LXFML, // the model's LXFML, for the client to build the model itself
|
|
WAIT, // icons not made yet: answered once they are
|
|
};
|
|
|
|
// The rule, for a request of `type` when the UGC server has (`meshMade`) or hasn't made the blueprint's mesh
|
|
eAction Decide(eUgcResourceType type, bool manifestOn, bool modelsOn, bool meshMade);
|
|
|
|
// The MD5 (lowercase hex) and size of a stored LXFML (ugc.lxfml: sd0, or plain XML) as the client has it after
|
|
// downloading and inflating it; nothing when it can't be read
|
|
std::optional<IUgc::FileChecksum> LxfmlChecksum(const std::string& stored);
|
|
|
|
// ugc_manifest=1 and ugc_manifest_models=1: placed models' meshes come from the UGC server when made
|
|
bool ServesModels();
|
|
|
|
// Whether the client should get this model's LXFML when a property loads (it builds the model itself): not when
|
|
// ServesModels() and the UGC server made its mesh
|
|
bool ClientBuildsModel(LWOOBJID blueprintId);
|
|
|
|
void OnRequest(const SystemAddress& sysAddr, LWOOBJID blueprintId, eUgcResourceType resourceType);
|
|
|
|
// Answers the waiting requests whose files have been made since, and forgets the ones waited on too long
|
|
void Update();
|
|
|
|
// A client left: its waiting requests are dropped
|
|
void OnDisconnect(const SystemAddress& sysAddr);
|
|
|
|
// The UGC server made these models' meshes (again, with a new checksum): each one placed in this world is sent the
|
|
// new checksum and NotifyClientUGCModelReady, so clients load the served mesh
|
|
void OnModelsMade(const std::vector<LWOOBJID>& blueprintIds);
|
|
}
|
|
|
|
#endif //!UGCMANIFEST_H
|