Checkpoint 1: implement native subsystems and begin the gameplay manual
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace faset::assets {
|
||||
using Json = nlohmann::json;
|
||||
inline constexpr const char* importer_version = "faset-gltf-1/cgltf-1.15";
|
||||
|
||||
struct Vertex {
|
||||
std::array<float, 3> position{};
|
||||
std::array<float, 3> normal{0, 0, 1};
|
||||
std::array<float, 2> uv{};
|
||||
};
|
||||
struct Primitive {
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<std::uint32_t> indices;
|
||||
int material = -1;
|
||||
};
|
||||
struct Mesh {
|
||||
std::string id, name;
|
||||
std::vector<Primitive> primitives;
|
||||
};
|
||||
struct Node {
|
||||
std::string id, name, parent_id;
|
||||
int mesh = -1;
|
||||
// glTF right-handed, Y-up, metres; column-major matrix.
|
||||
std::array<float, 16> local_transform{1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||||
bool stable_source_id = false;
|
||||
};
|
||||
struct Material {
|
||||
std::string id, name;
|
||||
std::array<float, 4> base_color{1,1,1,1};
|
||||
std::array<float, 3> emissive{};
|
||||
float metallic = 1, roughness = 1, alpha_cutoff = 0.5f;
|
||||
std::string alpha_mode = "OPAQUE";
|
||||
bool double_sided = false, unlit = false;
|
||||
int base_color_texture = -1, metallic_roughness_texture = -1;
|
||||
int normal_texture = -1, occlusion_texture = -1, emissive_texture = -1;
|
||||
};
|
||||
struct Texture {
|
||||
std::string id, name, mime_type;
|
||||
// Encoded image bytes, owned by this value. Renderer selects an image decoder.
|
||||
std::vector<std::byte> bytes;
|
||||
int wrap_s = 10497, wrap_t = 10497, min_filter = 0, mag_filter = 0;
|
||||
};
|
||||
struct CookedAsset {
|
||||
std::string asset_id, generation;
|
||||
std::vector<Mesh> meshes;
|
||||
std::vector<Node> nodes;
|
||||
std::vector<Material> materials;
|
||||
std::vector<Texture> textures;
|
||||
};
|
||||
|
||||
struct ImportProgress { float fraction = 0; std::string stage; };
|
||||
class ImportJob {
|
||||
public:
|
||||
using Observer = std::function<void(const ImportProgress&)>;
|
||||
explicit ImportJob(Observer observer = {});
|
||||
void cancel() noexcept;
|
||||
bool cancelled() const noexcept;
|
||||
ImportProgress progress() const;
|
||||
void report(float fraction, std::string stage);
|
||||
private:
|
||||
std::atomic<bool> cancelled_{false};
|
||||
mutable std::mutex mutex_;
|
||||
ImportProgress progress_;
|
||||
Observer observer_;
|
||||
};
|
||||
|
||||
enum class ImportStatus { succeeded, failed, cancelled, conflict };
|
||||
struct ImportRequest {
|
||||
std::filesystem::path source;
|
||||
std::string asset_id{}; // Empty: restore/create source.faset-import.json identity.
|
||||
Json settings = nullptr; // Null restores the sidecar recipe; an object replaces it.
|
||||
// Explicit conflict resolution; false keeps the previous generation active.
|
||||
bool allow_removed_outputs = false;
|
||||
};
|
||||
struct ImportResult {
|
||||
ImportStatus status = ImportStatus::failed;
|
||||
std::string asset_id, generation;
|
||||
std::vector<std::string> diagnostics;
|
||||
std::vector<std::string> removed_output_ids;
|
||||
Json manifest;
|
||||
bool cache_hit = false;
|
||||
bool ok() const noexcept { return status == ImportStatus::succeeded; }
|
||||
};
|
||||
|
||||
// A pipeline is an authoring service. Player only needs read-only cooked data.
|
||||
// Writers in one process serialize publication; a cache root has one service owner.
|
||||
class AssetPipeline {
|
||||
public:
|
||||
explicit AssetPipeline(std::filesystem::path cache_root);
|
||||
ImportResult import_asset(const ImportRequest& request, ImportJob& job);
|
||||
ImportResult import_asset(const ImportRequest& request);
|
||||
Json current_manifest(const std::string& asset_id) const;
|
||||
CookedAsset load_asset(const std::string& asset_id) const;
|
||||
// Overrides are authoring data beside the source, never generated cache contents.
|
||||
Json overrides(const std::string& asset_id) const;
|
||||
void set_overrides(const std::string& asset_id, const Json& overrides);
|
||||
std::filesystem::path generation_directory(const std::string& asset_id) const;
|
||||
const std::filesystem::path& cache_root() const noexcept { return cache_root_; }
|
||||
private:
|
||||
std::filesystem::path cache_root_;
|
||||
};
|
||||
} // namespace faset::assets
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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_;
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <faset/core/json.hpp>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace faset {
|
||||
class Error : public std::runtime_error {
|
||||
public:
|
||||
Error(std::string code, std::string message, Json details = Json::object())
|
||||
: std::runtime_error(std::move(message)), code_(std::move(code)), details_(std::move(details)) {}
|
||||
const std::string& code() const noexcept { return code_; }
|
||||
Json json() const { return {{"code", code_}, {"message", what()}, {"details", details_}}; }
|
||||
private:
|
||||
std::string code_;
|
||||
Json details_;
|
||||
};
|
||||
inline void require(bool condition, const std::string& code, const std::string& message) {
|
||||
if (!condition) throw Error(code, message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace faset {
|
||||
std::string sha256(std::span<const std::byte> bytes);
|
||||
inline std::string sha256(std::string_view text) {
|
||||
return sha256(std::as_bytes(std::span(text.data(), text.size())));
|
||||
}
|
||||
std::string sha256_file(const std::filesystem::path& path);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <faset/core/json.hpp>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace faset {
|
||||
std::string new_id();
|
||||
std::string read_text(const std::filesystem::path& path);
|
||||
Json read_json(const std::filesystem::path& path);
|
||||
void atomic_write(const std::filesystem::path& path, std::string_view bytes);
|
||||
void atomic_write_json(const std::filesystem::path& path, const Json& value);
|
||||
// Rejects traversal and symlink escapes before project-scoped file operations.
|
||||
std::filesystem::path project_path(const std::filesystem::path& root, const std::filesystem::path& relative);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
#include <nlohmann/json.hpp>
|
||||
namespace faset { using Json = nlohmann::json; }
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
namespace faset::render {
|
||||
// Ordered single-queue graph. Reads must be imported or produced by an earlier pass.
|
||||
// The Vulkan executor performs barriers at each resource state transition.
|
||||
class RenderGraph {
|
||||
public:
|
||||
using Callback = std::function<void()>;
|
||||
void import(std::string resource);
|
||||
void add(std::string name, std::vector<std::string> reads, std::vector<std::string> writes, Callback execute);
|
||||
void execute() const;
|
||||
std::vector<std::string> pass_names() const;
|
||||
private:
|
||||
struct Pass {std::string name; std::vector<std::string> reads, writes; Callback callback;};
|
||||
std::vector<std::string> imports_;
|
||||
std::vector<Pass> passes_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace faset::render {
|
||||
using Vec2 = std::array<float, 2>;
|
||||
using Vec3 = std::array<float, 3>;
|
||||
using Color = std::array<float, 4>;
|
||||
using Mat4 = std::array<float, 16>;
|
||||
inline constexpr Mat4 identity{1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
||||
// Matrices are column-major, vectors are columns; clip depth is Vulkan's [0,1].
|
||||
Mat4 multiply(const Mat4&, const Mat4&);
|
||||
Mat4 transform(Vec3 position, Vec3 rotation = {}, Vec3 scale = {1,1,1});
|
||||
Mat4 perspective(float vertical_fov_radians, float aspect, float near_plane, float far_plane);
|
||||
Mat4 orthographic(float left, float right, float bottom, float top, float near_plane, float far_plane);
|
||||
Mat4 look_at(Vec3 eye, Vec3 target, Vec3 up = {0,1,0});
|
||||
struct Vertex { Vec3 position{}; Vec3 normal{0,0,1}; Color color{1,1,1,1}; Vec2 uv{}; };
|
||||
struct Mesh { std::vector<Vertex> vertices; std::vector<std::uint32_t> indices; };
|
||||
std::shared_ptr<const Mesh> cube_mesh();
|
||||
struct Texture;
|
||||
struct DrawItem {
|
||||
std::shared_ptr<const Mesh> mesh;
|
||||
Mat4 model{identity};
|
||||
Color color{1,1,1,1};
|
||||
float roughness{0.65f};
|
||||
float metallic{0.0f};
|
||||
bool cast_shadow{true};
|
||||
std::shared_ptr<const Texture> texture;
|
||||
};
|
||||
struct Sprite { Vec3 position{}; Vec2 size{1,1}; Color color{1,1,1,1}; float rotation{}; std::shared_ptr<const Texture> texture; };
|
||||
struct Texture { std::uint32_t width{}, height{}; std::vector<std::uint8_t> rgba; std::uint64_t revision{}; bool srgb{false}; };
|
||||
struct Quad { float x{}, y{}, width{}, height{}; Color color{1,1,1,1}; std::shared_ptr<const Texture> texture; std::array<float,4> uv_rect{0,0,1,1}; };
|
||||
struct Text { float x{}, y{}; std::string value; Color color{0.85f,0.87f,0.90f,1}; float size{14}; };
|
||||
struct Snapshot {
|
||||
// Optional scene viewport in drawable pixels (x, y, width, height); zero size uses the full target.
|
||||
std::array<float,4> scene_rect{};
|
||||
Mat4 view_projection{identity};
|
||||
Vec3 eye{4,3,5};
|
||||
Vec3 light_direction{-0.5f,-1,-0.3f};
|
||||
Color clear_color{0.055f,0.065f,0.085f,1};
|
||||
std::vector<DrawItem> draws;
|
||||
std::vector<Sprite> sprites;
|
||||
// UI coordinates are drawable pixels, top-left origin. Order is preserved per list.
|
||||
std::vector<Quad> ui_quads;
|
||||
std::vector<Text> ui_text;
|
||||
};
|
||||
struct RendererConfig {
|
||||
std::uint32_t width{1280}, height{720};
|
||||
std::string title{"Faset Engine"};
|
||||
bool headless{false};
|
||||
bool validation{true};
|
||||
};
|
||||
struct Event {
|
||||
enum class Type { Quit, Resize, FocusGained, FocusLost, MouseMove, MouseDown, MouseUp, Wheel, KeyDown, KeyUp, TextInput, TextEditing };
|
||||
Type type{};
|
||||
float x{}, y{};
|
||||
int button{};
|
||||
std::string key;
|
||||
std::string text;
|
||||
bool control{}, shift{}, alt{}, repeat{};
|
||||
int edit_start{}, edit_length{};
|
||||
};
|
||||
struct FrameStats {
|
||||
std::uint64_t frame{};
|
||||
std::uint32_t vertices{}, draw_calls{}, culled_meshes{}, validation_errors{};
|
||||
double cpu_ms{}, gpu_ms{};
|
||||
std::string device;
|
||||
};
|
||||
class Renderer {
|
||||
public:
|
||||
explicit Renderer(const RendererConfig& = {});
|
||||
~Renderer();
|
||||
Renderer(Renderer&&) noexcept;
|
||||
Renderer& operator=(Renderer&&) noexcept;
|
||||
Renderer(const Renderer&) = delete;
|
||||
Renderer& operator=(const Renderer&) = delete;
|
||||
std::vector<Event> poll_events();
|
||||
void render(const Snapshot&);
|
||||
void resize(std::uint32_t width, std::uint32_t height);
|
||||
// Rebuilds graphics pipelines from SPIR-V; a failure preserves the current pipelines.
|
||||
bool reload_shaders(std::string& error);
|
||||
// Saves the latest completed frame as a portable RGB PPM image.
|
||||
void capture(const std::filesystem::path&);
|
||||
std::vector<std::uint8_t> pixels() const;
|
||||
std::uint32_t width() const;
|
||||
std::uint32_t height() const;
|
||||
bool should_close() const;
|
||||
const FrameStats& stats() const;
|
||||
void set_title(const std::string&);
|
||||
void set_text_input(bool enabled);
|
||||
void set_text_input_area(float x, float y, float width, float height);
|
||||
void set_clipboard(const std::string&);
|
||||
std::string clipboard() const;
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace faset::runtime {
|
||||
|
||||
using Vec2 = std::array<float, 2>;
|
||||
using Vec3 = std::array<float, 3>;
|
||||
using Vec4 = std::array<float, 4>;
|
||||
|
||||
struct Transform {
|
||||
Vec3 position{0, 0, 0};
|
||||
Vec3 rotation{0, 0, 0}; // Euler XYZ, radians.
|
||||
Vec3 scale{1, 1, 1};
|
||||
};
|
||||
|
||||
// Process-local identity. Never serialize this into an authoring scene.
|
||||
struct EntityHandle {
|
||||
std::uint64_t session{};
|
||||
std::uint32_t slot{};
|
||||
std::uint64_t generation{};
|
||||
explicit operator bool() const noexcept { return session != 0; }
|
||||
bool operator==(const EntityHandle&) const = default;
|
||||
};
|
||||
|
||||
struct InputState {
|
||||
float horizontal{};
|
||||
float vertical{};
|
||||
bool jumpPressed{};
|
||||
bool interactPressed{};
|
||||
};
|
||||
|
||||
struct Sprite { Vec4 color{1, 1, 1, 1}; Vec2 size{1, 1}; std::string texture; int layer{}; };
|
||||
struct Mesh { std::string asset; Vec4 color{1, 1, 1, 1}; std::string primitive{"cube"}; };
|
||||
struct RenderEntity {
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::optional<std::string> parent;
|
||||
Transform transform; // Presentation-space local transform; compose parent for rendering.
|
||||
std::optional<Sprite> sprite;
|
||||
std::optional<Mesh> mesh;
|
||||
};
|
||||
struct RuntimeSnapshot {
|
||||
int dimension{3};
|
||||
std::uint64_t tick{};
|
||||
double alpha{};
|
||||
std::vector<RenderEntity> entities;
|
||||
};
|
||||
struct FrameStats {
|
||||
unsigned fixedTicks{};
|
||||
double droppedTime{};
|
||||
double interpolationAlpha{};
|
||||
std::uint64_t tick{};
|
||||
};
|
||||
struct RuntimeConfig {
|
||||
double fixedDelta{1.0 / 60.0};
|
||||
unsigned maxCatchUpTicks{4};
|
||||
int physicsSubsteps{4};
|
||||
Vec3 gravity{0, -9.81f, 0};
|
||||
};
|
||||
|
||||
class Runtime;
|
||||
struct CollisionEvent;
|
||||
struct Behavior {
|
||||
using Callback = std::function<void(Runtime&, EntityHandle, double)>;
|
||||
Callback onStart;
|
||||
Callback fixedUpdate;
|
||||
Callback update;
|
||||
Callback lateUpdate;
|
||||
Callback onDestroy;
|
||||
std::function<void(Runtime&, EntityHandle, const CollisionEvent&)> onCollision;
|
||||
};
|
||||
struct CollisionEvent {
|
||||
EntityHandle first;
|
||||
EntityHandle second;
|
||||
bool began{};
|
||||
};
|
||||
|
||||
// Single-owner sequential runtime. Gameplay callbacks run on the caller's thread.
|
||||
// No Editor, MCP, renderer or platform service is linked by this API.
|
||||
class Runtime {
|
||||
public:
|
||||
explicit Runtime(RuntimeConfig config = {});
|
||||
~Runtime();
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime& operator=(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
Runtime& operator=(Runtime&&) = delete;
|
||||
|
||||
void registerBehavior(std::string componentType, Behavior behavior);
|
||||
// Validates and prepares a replacement world before destroying the old world.
|
||||
// Throws a validation/JSON exception on unsupported or invalid scene data.
|
||||
void load(const nlohmann::json& scene);
|
||||
void clear();
|
||||
FrameStats advance(double elapsedSeconds, InputState input = {});
|
||||
FrameStats singleStep(InputState input = {});
|
||||
void setPaused(bool paused);
|
||||
bool paused() const noexcept;
|
||||
|
||||
EntityHandle find(const std::string& persistentId) const;
|
||||
bool valid(EntityHandle handle) const noexcept;
|
||||
Transform transform(EntityHandle handle) const;
|
||||
Transform presentation(EntityHandle handle) const;
|
||||
// Configuration copy. Live poses and velocities have their own typed accessors.
|
||||
nlohmann::json fields(EntityHandle handle, const std::string& componentType) const;
|
||||
Vec3 velocity(EntityHandle handle) const;
|
||||
InputState input() const noexcept;
|
||||
// Valid until the next fixed tick or scene replacement. No native solver pointers.
|
||||
const std::vector<CollisionEvent>& collisions() const noexcept;
|
||||
|
||||
// Non-physical transforms may be changed in Update/FixedUpdate. Physics poses
|
||||
// are owned by the solver and require explicit teleport/velocity operations.
|
||||
void setTransform(EntityHandle handle, const Transform& transform);
|
||||
void setPresentation(EntityHandle handle, const Transform& transform);
|
||||
void teleport(EntityHandle handle, const Transform& transform);
|
||||
void setVelocity(EntityHandle handle, Vec3 velocity);
|
||||
void applyImpulse(EntityHandle handle, Vec3 impulse);
|
||||
|
||||
// All structural changes are applied in FIFO order at the NEXT fixed tick.
|
||||
// Returned handles, component copies and presentation snapshots are not pointers.
|
||||
void spawn(nlohmann::json entity);
|
||||
void destroy(EntityHandle handle);
|
||||
void addComponent(EntityHandle handle, nlohmann::json component);
|
||||
void removeComponent(EntityHandle handle, const std::string& componentType);
|
||||
|
||||
RuntimeSnapshot snapshot() const;
|
||||
nlohmann::json snapshotJson() const;
|
||||
std::uint64_t session() const noexcept;
|
||||
const std::vector<std::string>& diagnostics() const noexcept;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
} // namespace faset::runtime
|
||||
Reference in New Issue
Block a user