14 : m_scheduler(scheduler)
15 , m_event_manager(event_manager)
16 , m_index(Kinesis::make_spatial_index_3d(cell_size))
17 , m_cell_size(cell_size)
24 if (!reg.task_name.empty()) {
27 if (!reg.chain_name.empty()) {
30 if (!reg.event_name.empty()) {
45 if (emitter->m_position.has_value()) {
46 reg.spatial_id =
m_index->insert(*emitter->m_position);
49 return Wiring { *
this,
id };
57 if (sensor->m_position.has_value()) {
58 reg.spatial_id =
m_index->insert(*sensor->m_position);
61 return Wiring { *
this,
id };
69 if (agent->m_position.has_value()) {
70 reg.spatial_id =
m_index->insert(*agent->m_position);
73 return Wiring { *
this,
id };
83 auto& reg = it->second;
85 if (!reg.task_name.empty()) {
88 if (!reg.chain_name.empty()) {
91 if (!reg.event_name.empty()) {
94 if (reg.spatial_id.has_value()) {
95 m_index->remove(*reg.spatial_id);
103 const uint32_t
id = expanse->id();
104 m_expanses.try_emplace(
id, std::move(expanse));
121 std::vector<uint32_t>
ids;
132 return std::visit([](
const auto&
ptr) ->
Kind {
133 using T = std::decay_t<
decltype(*ptr)>;
134 if constexpr (std::is_same_v<T, Emitter>) {
136 }
else if constexpr (std::is_same_v<T, Sensor>) {
150 if (
auto*
ptr = std::get_if<std::shared_ptr<Emitter>>(&it->second.member)) {
161 if (
auto*
ptr = std::get_if<std::shared_ptr<Sensor>>(&it->second.member)) {
172 if (
auto*
ptr = std::get_if<std::shared_ptr<Agent>>(&it->second.member)) {
185 std::visit([&](
const auto&
ptr) {
186 if (!
ptr->m_position.has_value()) {
189 if (reg.spatial_id.has_value()) {
190 m_index->update(*reg.spatial_id, *ptr->m_position);
192 reg.spatial_id = m_index->insert(*ptr->m_position);
201 std::unordered_map<uint32_t, uint32_t> entity_of;
204 if (reg.spatial_id.has_value()) {
205 entity_of.emplace(*reg.spatial_id,
id);
209 auto snapshot =
m_index->all();
210 for (
auto& [spatial_id,
position] : snapshot) {
211 if (
const auto it = entity_of.find(spatial_id); it != entity_of.end()) {
212 spatial_id = it->second;
221 if (reg.commit_driven) {
232 "Fabric::fire: id {} not registered",
id);
236 it->second.pending_cursor.reset();
244 const glm::vec3& center,
float radius)
const
250 const glm::vec3& center, uint32_t k)
const
252 return m_index->k_nearest(center, k);
261 return &*it->second.wiring;
271 std::visit([
id](
const auto&
ptr) {
280 std::visit([&](
const auto&
ptr) {
281 using T = std::decay_t<
decltype(*ptr)>;
283 if constexpr (std::is_same_v<T, Emitter>) {
284 ptr->follow_attachment();
286 if (
ptr->m_position.has_value()) {
296 }
else if constexpr (std::is_same_v<T, Sensor>) {
299 if (
ptr->m_position.has_value()) {
301 auto results =
m_index->within_radius(*
ptr->m_position,
ptr->m_query_radius);
306 }
else if constexpr (std::is_same_v<T, Agent>) {
307 ptr->follow_attachment();
308 if (
ptr->m_position.has_value()) {
309 auto results =
m_index->within_radius(*
ptr->m_position,
ptr->m_query_radius);
315 ptr->invoke_perception(pctx);
325 ptr->invoke_influence(ictx);
330 ptr->invoke_perception(pctx);
337 ptr->invoke_influence(ictx);
370 std::vector<uint32_t>
ids;
380 return it !=
m_expanses.end() ? it->second :
nullptr;
#define MF_WARN(comp, ctx,...)
std::optional< glm::vec3 > position
std::vector< uint64_t > ids
std::vector< Kinesis::QueryResult > k_nearest(const glm::vec3 ¢er, uint32_t k) const
Find the k nearest objects to a point.
std::shared_ptr< Sensor > get_sensor(uint32_t id) const
Get the Sensor registered under id.
std::vector< uint32_t > all_ids() const
List all registered entity ids in insertion order.
void remove_expanse(uint32_t id)
Remove a registered Expanse, firing its exit actions for everything inside it here.
std::unordered_map< std::string, std::shared_ptr< Expanse::CrossingFn > > m_crossing_fns
std::unordered_map< uint32_t, std::shared_ptr< Expanse > > m_expanses
std::shared_ptr< Emitter::InfluenceFn > resolve_influence_fn(std::string_view name) const
Look up a registered influence function by name.
std::shared_ptr< Presence::RadiateFn > resolve_radiate_fn(std::string_view name) const
Look up a registered radiation function by name.
std::shared_ptr< Expanse::CrossingFn > resolve_crossing_fn(std::string_view name) const
Look up a registered Expanse crossing function by name.
std::unique_ptr< Kinesis::SpatialIndex3D > m_index
std::unordered_map< std::string, std::shared_ptr< Expanse::ContainsFn > > m_expanse_fns
std::variant< std::shared_ptr< Emitter >, std::shared_ptr< Sensor >, std::shared_ptr< Agent > > Member
void fire(uint32_t id)
Fire a single object against the current snapshot without republishing.
void remove(uint32_t id)
Remove a registered object by id, cancelling any associated tasks.
std::shared_ptr< Expanse > get_expanse(uint32_t id) const
Look up a registered Expanse by id.
std::unordered_map< std::string, std::shared_ptr< Presence::RadiateFn > > m_radiate_fns
Fabric(Vruta::TaskScheduler &scheduler, Vruta::EventManager &event_manager, float cell_size=1.0F)
Construct with scheduler and event manager from the engine.
std::unordered_map< std::string, std::shared_ptr< Sensor::PerceptionFn > > m_perception_fns
std::shared_ptr< Sensor::PerceptionFn > resolve_perception_fn(std::string_view name) const
Look up a registered perception function by name.
uint32_t add_expanse(std::shared_ptr< Expanse > expanse)
Register an Expanse for per-commit crossing detection.
std::shared_ptr< Agent > get_agent(uint32_t id) const
Get the Agent registered under id.
const Wiring * wiring_for(uint32_t id) const
Access the finalised wiring for an entity for introspection.
const std::string & name() const
Assigned name, empty if the Fabric was constructed outside a Tapestry.
Kind kind(uint32_t id) const
Return the kind of entity registered under id.
std::vector< uint32_t > all_expanse_ids() const
Stable ids of all registered Expanses in insertion order.
uint32_t assign_id(Member &m)
Vruta::TaskScheduler & m_scheduler
uint32_t id() const
Stable id for this Fabric, assigned by Tapestry at construction.
std::vector< Kinesis::QueryResult > within_radius(const glm::vec3 ¢er, float radius) const
Find all objects within a radius of a point.
std::shared_ptr< Emitter > get_emitter(uint32_t id) const
Get the Emitter registered under id.
Wiring wire(std::shared_ptr< Emitter > emitter)
Begin wiring an Emitter into the Fabric.
std::unordered_map< uint32_t, Registration > m_registrations
void commit()
Update all positions, publish the snapshot, fire all registered objects.
std::unordered_map< std::string, std::shared_ptr< Emitter::InfluenceFn > > m_influence_fns
Vruta::EventManager & m_event_manager
std::shared_ptr< Expanse::ContainsFn > resolve_expanse_fn(std::string_view name) const
Look up a registered Expanse containment function by name.
Fluent builder that wires an entity into Fabric's scheduling infrastructure.
bool cancel_event(const std::shared_ptr< Event > &event)
Cancels and removes a event from the manager.
bool cancel_task(const std::shared_ptr< Routine > &routine)
Cancels and removes a task from the scheduler.
Token-based multimodal task scheduling system for unified coroutine processing.
@ Runtime
General runtime operations (default fallback)
@ Nexus
Spatial indexing and scheduling for user-defined behaviour.
std::optional< glm::vec2 > pending_cursor
glm::vec3 position
Position of the influence point in world space.
std::optional< glm::vec2 > cursor_pos
Optional cursor position for pending interactions, useful for real-time editing or previewing influen...
std::optional< glm::vec3 > color
Optional color hint for the influence, may be used for visualisation or shader effects.
std::optional< float > size
Optional size hint for the influence, may be used for visualisation or shader effects.
float intensity
Intensity of the influence, typically in the range [0, 1], but may exceed 1 for strong influences.
float radius
Radius of influence around the position, defining the area of effect for spatially-dependent influenc...
std::optional< glm::quat > orientation
Optional orientation of the influencer. Local +Z is its forward direction.
Data passed to an Emitter or Agent influence function on each commit.
std::optional< glm::quat > orientation
Optional orientation of the perceiver. Local +Z is its forward direction.
float radius
Query radius the spatial results were gathered with.
std::span< const Kinesis::QueryResult > spatial_results
Data passed to a Sensor or Agent perception function on each commit.