Checkpoint 1: implement native subsystems and begin the gameplay manual

This commit is contained in:
Emil
2026-09-18 03:01:30 +03:00
parent decf49084d
commit 903c97444b
73 changed files with 3932 additions and 6 deletions
+46
View File
@@ -0,0 +1,46 @@
#pragma once
#include <faset/core/json.hpp>
#include <faset/core/error.hpp>
#include <map>
#include <string>
#include <type_traits>
namespace faset::authoring {
class SchemaRegistry {
public:
void register_schema(const Json& schema);
void register_schemas(const Json& schemas);
bool contains(const std::string& type) const;
Json schema(const std::string& type) const;
Json manifest() const;
Json default_fields(const std::string& type) const;
// Unknown fields and absent schemas survive authoring. Known fields are validated.
void validate_component(const Json& component) const;
Json migrate_component(const Json& component) const;
void add_migration(const std::string& type, int from_version, Json field_rules);
private:
std::map<std::string,Json> schemas_;
std::map<std::pair<std::string,int>,Json> migrations_;
};
template<class T> class TypeRegistration {
public:
TypeRegistration(SchemaRegistry& registry, std::string id, std::string name, int version=1)
: registry_(registry),schema_{{"id",std::move(id)},{"name",std::move(name)},{"version",version},{"fields",Json::object()}} {}
template<class Value>
TypeRegistration& field(std::string id, std::string name, Value T::*member, Value default_value,
std::string kind, Json constraints=Json::object()) {
static_assert(std::is_member_object_pointer_v<decltype(member)>);
require(!schema_["fields"].contains(id),"schema.duplicate_field","Duplicate stable FieldId");
// Converting the typed default checks supported JSON serialization at compile time.
Json descriptor={{"id",id},{"name",std::move(name)},{"type",std::move(kind)},{"default",Json(default_value)}};
descriptor.update(constraints); schema_["fields"][id]=std::move(descriptor); return *this;
}
void commit() { registry_.register_schema(schema_); }
private:
SchemaRegistry& registry_;
Json schema_;
};
SchemaRegistry builtin_schemas();
void validate_field(const Json& value,const Json& descriptor);
}
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include <faset/authoring/schema.hpp>
#include <filesystem>
#include <map>
#include <mutex>
#include <string>
#include <vector>
namespace faset::authoring {
Json make_scene(std::string name,int dimension=3);
Json make_entity(const SchemaRegistry& schemas,std::string name,const std::string& parent="");
void validate_scene(const Json& scene,const SchemaRegistry& schemas);
class AuthoringService {
public:
explicit AuthoringService(std::filesystem::path project_root,SchemaRegistry schemas=builtin_schemas());
Json create(std::string name,int dimension=3);
Json open(const std::filesystem::path& relative,bool recover=false);
Json query(const std::string& document) const;
Json documents() const;
Json transact(const std::string& document,std::uint64_t expected_revision,const Json& operations,const std::string& idempotency_key="");
Json undo(const std::string& document,std::uint64_t expected_revision);
Json redo(const std::string& document,std::uint64_t expected_revision);
Json save(const std::string& document,const std::filesystem::path& relative={});
Json recovery_documents() const;
const SchemaRegistry& schemas() const {return schemas_;}
void register_schemas(const Json& manifest);
const std::filesystem::path& root() const {return root_;}
private:
struct State {
Json data;
std::uint64_t revision=0;
std::filesystem::path path;
std::string saved_hash,disk_hash;
std::vector<Json> undo,redo;
std::map<std::string,std::pair<std::string,Json>> requests;
};
Json summary(const State& state,bool include_data=true) const;
State& state(const std::string& document);
const State& state(const std::string& document) const;
void journal(const State& state) const;
void apply(Json& scene,const Json& operation);
Json history(const std::string& document,std::uint64_t revision,bool redo);
std::filesystem::path root_;
SchemaRegistry schemas_;
std::map<std::string,State> documents_;
mutable std::recursive_mutex mutex_;
};
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <faset/authoring/schema.hpp>
#include <functional>
#include <string>
namespace faset::authoring {
struct ResolvedScene {Json scene;Json conflicts=Json::array();};
using SceneLoader=std::function<Json(const std::string&)>;
// Source documents are immutable inputs. Conflicting records stay in the authoring file.
ResolvedScene resolve_templates(const Json& scene,const SchemaRegistry& schemas,const SceneLoader& loader);
}