13#include <entity2/entityclass.h>
14#include <entity2/entitysystem.h>
18#include <interfaces/interfaces.h>
19#include <schemasystem/schemasystem.h>
28static constexpr std::string_view
DumpPath =
"addons/voltmod/gamedata/dumps/schema.json";
31static std::string
DumpedBuild(
const std::filesystem::path& path)
33 std::ifstream
file(path, std::ios::binary);
39 std::string
head(256,
'\0');
40 file.read(
head.data(),
static_cast<std::streamsize
>(
head.size()));
41 head.resize(
static_cast<size_t>(
file.gcount()));
43 constexpr std::string_view
key =
"\"build\":";
45 if (
at == std::string::npos)
51 const size_t close =
open == std::string::npos ? std::string::npos :
head.find(
'"',
open + 1);
57 if (!schema || !schema->SchemaSystemIsReady())
62 return schema->FindTypeScopeForModule(
moduleName.c_str());
104 return std::unexpected(
Error::NotReady(
"the server schema scope is not ready"));
109 std::vector<std::string>
drift;
122 drift.push_back(std::format(
"{}::{}: gone",
want.Class,
want.Field));
126 if (
found->m_nSingleInheritanceOffset !=
want.Offset)
128 drift.push_back(std::format(
"{}::{}: offset {} -> {}",
want.Class,
want.Field,
want.Offset,
129 found->m_nSingleInheritanceOffset));
137 drift.push_back(std::format(
"{}::{}: size {} -> {}",
want.Class,
want.Field,
want.Size, size));
146 std::string
message = std::format(
147 "schema drift (accessors generated from game build {}, server is {}); "
148 "load a plugin into a running map to write the dump, then regenerate "
149 "with voltmod framework schemagen:",
172 _entitySystemOffset =
entry.Found ?
entry.Value : -1;
188void SchemaCheck::Check()
194 Log::Error(
"Schema: {}", verified.error().Detail);
206 if (_resources ==
nullptr || _entitySystemOffset < 0)
Typed read/write of engine fields at a base pointer + byte offset.
The loaded plugins and the engine events raised on them, one per process.
void SetSchemaLayout(uint64_t stamp, bool verified)
SchemaCheck(PluginRegistry ®istry, ISchemaSystem *schema, IGameResourceService *resources)
void Error(std::format_string< Args... > fmt, Args &&... args)
void Info(std::format_string< Args... > fmt, Args &&... args)
void Warn(std::format_string< Args... > fmt, Args &&... args)
static CSchemaSystemTypeScope * ServerScope(ISchemaSystem *schema)
const SchemaClassFieldData_t * FindField(const CSchemaClassInfo *klass, std::string_view field)
Status VerifySchemaLayout(ISchemaSystem *schema)
static std::string DumpedBuild(const std::filesystem::path &path)
static constexpr std::string_view DumpPath
std::string_view GeneratedFromBuild()
Status WriteDumpFile(CSchemaSystemTypeScope *global, CSchemaSystemTypeScope *server, const CNetworkSerializerCodeGenDatabase &network, std::string_view path, std::string_view gameBuild)
uint64_t GeneratedLayoutStamp()
A hash of everything GeneratedLayout holds.
std::span< const FieldLayout > GeneratedLayout()
void WriteSchemaDump(ISchemaSystem *schema, CGameEntitySystem *entities)
std::filesystem::path ResolvePath(std::string_view relativePath)
a relative path against the base directory. If the path is already absolute, returns it as-is.
static constexpr std::string_view EntitySystemOffset
@ NotReady
It exists but the subsystem behind it is not usable yet.
static std::string ReadFile(const std::filesystem::path &path)
std::string_view GameBuild()
std::expected< void, Error > Status
std::string PlatformModuleName(std::string_view moduleName)
static Error Invalid(std::string detail)
static Error NotReady(std::string detail)