Skip to content

Astra 3.0.0

Choose a tag to compare

@T3mps T3mps released this 27 Feb 23:17

Astra ECS v3.0 - Resources, Runtime Reflection & Editor Integration

Major Release Highlights

Astra 3.0 introduces a singleton resource system for global state and a comprehensive runtime reflection system providing EnTT meta-style introspection, field enumeration, attribute decoration, and full ECS integration. This release enables editor tooling, runtime component inspection, and JSON schema generation.

New Capabilities

  • Resource system for singleton/global components with SBO optimization
  • Runtime type introspection with zero overhead when unused
  • Field enumeration with get/set accessors and attribute metadata
  • Entity inspection API for editor and debugging tools

New Features

Resource System (NEW)

Singleton resources for global state that exists outside the entity-component model:

// Add global resources
registry.AddResource<Time>(Time{ 0.0f, 0.016f });
registry.AddResource<InputState>();
registry.AddResource<RenderSettings>(width, height, vsync);

// Access resources
Time* time = registry.GetResource<Time>();
time->deltaTime = 0.016f;

// Check existence
if (registry.HasResource<InputState>()) { ... }

// Remove resources
registry.RemoveResource<RenderSettings>();

Storage Architecture

  • Sparse-dense pattern for O(1) access by ComponentID
  • Small Buffer Optimization - Resources ≤64 bytes stored inline (no heap allocation)
  • Swap-and-pop removal maintains cache locality
  • Automatic registration with ComponentRegistry

Type-Erased Operations

For command buffers and deferred execution:

// Set resource by ID (for CommandBuffer)
resourceStorage.SetByID(componentId, dataPtr, dataSize);

// Remove by ID
resourceStorage.RemoveByID(componentId);

// Get by ID
void* data = resourceStorage.GetByID(componentId);

Memory Efficiency

struct ResourceSlot {
    union Storage {
        alignas(64) std::byte inlineData[64];  // SBO: no allocation
        void* heapPtr;                          // Large resources
    };
    // ... metadata
};

// Memory usage tracking
size_t bytes = resourceStorage.GetMemoryUsage();

Runtime Reflection System (NEW)

TypeMeta - Complete Type Metadata

const TypeMeta* meta = GetMeta<Transform>();

// Introspect fields
meta->ForEachField([](const FieldInfo& field) {
    std::cout << field.name << " : " << field.typeName << "\n";
});

// Dynamic field access
meta->SetFieldValue(&transform, "x", 100.0f);
float x = meta->GetFieldValue<float>(&transform, "x").value();

FieldInfo - Field Descriptors with Accessors

  • Type-erased Get<T>() and Set<T>() methods
  • Offset, size, alignment metadata
  • Compile-time type trait detection (isConst, isPointer, isTrivial)
  • Attribute query support

Attribute System

Decorator metadata for fields and types:

ASTRA_REFLECT_TYPE(Transform)
    ASTRA_REFLECT_FIELD(Transform, x)
        ASTRA_REFLECT_ATTR(Range, -1000.0, 1000.0)
        ASTRA_REFLECT_ATTR(DisplayName, "X Position")
        ASTRA_REFLECT_ATTR(Tooltip, "Horizontal position in world space")
    ASTRA_REFLECT_FIELD(Transform, y)
    ASTRA_REFLECT_FIELD(Transform, z);

Built-in attributes:

  • Range - Min/max/step constraints
  • DisplayName - UI label override
  • Tooltip - Help text
  • Category - Property grouping
  • Hidden - Exclude from inspection
  • ReadOnly - Prevent modification
  • Serializable - Control persistence

Enum Reflection

ASTRA_REFLECT_ENUM(DamageType)
    ASTRA_REFLECT_ENUM_VALUE(DamageType, Physical)
    ASTRA_REFLECT_ENUM_VALUE_NAMED(DamageType, Fire, "Fire Damage")
    ASTRA_REFLECT_ENUM_FLAGS();  // Mark as bitmask

// Runtime conversion
auto name = enumInfo->ToString(DamageType::Fire);  // "Fire Damage"
auto value = enumInfo->FromString("Physical");      // DamageType::Physical

Container Traits Detection

Automatic detection of container types:

  • std::vector, std::array, std::span
  • std::map, std::unordered_map
  • std::set, std::unordered_set
  • Custom containers via trait specialization

ECS-Reflection Integration (NEW)

ComponentDescriptor ↔ TypeMeta Linking

Components registered with the ECS are automatically linked to their reflection metadata:

// ComponentDescriptor now includes:
const TypeMeta* meta;  // Auto-populated on registration

// Bidirectional lookup
const TypeMeta* meta = GetMeta(componentId);
ComponentID id = MetaRegistry::Instance().GetComponentId(typeHash);

Entity Inspection API

Runtime inspection of entity components for editors:

std::vector<ComponentInfo> components = registry.InspectEntity(entity);

for (const auto& info : components) {
    std::cout << "Component: " << info.descriptor->name << "\n";

    if (info.meta) {
        info.meta->ForEachField([&](const FieldInfo& field) {
            // Render field in editor UI
            RenderFieldWidget(field, info.data);
        });
    }
}

Resource Inspection API

std::vector<ResourceInfo> resources = registry.InspectResources();

for (const auto& res : resources) {
    std::cout << "Resource: " << res.descriptor->name << "\n";
    // Access via res.meta and res.data
}

Hash-Based Runtime Access

// Get components by type hash (runtime lookup)
void* component = registry.GetComponentByHash(entity, typeHash);
bool has = registry.HasComponentByHash(entity, typeHash);

// Get components by name
void* component = registry.GetComponentByName(entity, "Transform");

// Resources
void* resource = registry.GetResourceByHash(typeHash);
bool has = registry.HasResourceByHash(typeHash);

JSON Schema Generation (NEW)

Automatic JSON Schema generation for editor integration:

JsonSchemaGenerator generator;
std::string schema = generator.Generate(*GetMeta<Transform>());

Generates:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Transform",
  "type": "object",
  "properties": {
    "x": { "type": "number", "minimum": -1000, "maximum": 1000 },
    "y": { "type": "number" },
    "z": { "type": "number" }
  },
  "required": ["x", "y", "z"]
}

Architectural Improvements

MetaRegistry

Global singleton for reflection metadata:

  • O(1) lookup by type hash via FlatMap
  • Bidirectional component ID ↔ type hash mapping
  • Thread-safe registration (single-threaded lookup)
  • Lazy initialization via static builders

Reflection File Structure

include/Astra/Reflection/
  Reflection.hpp       # Main include
  TypeMeta.hpp         # Type metadata container
  FieldInfo.hpp        # Field descriptor with get/set
  EnumInfo.hpp         # Enum reflection
  Attribute.hpp        # Attribute base + common attributes
  MetaRegistry.hpp     # Global registry
  ContainerTraits.hpp  # Container type detection
  JsonSchema.hpp       # JSON schema generation
  Macros.hpp           # Registration macros

Requirements

  • C++20 compatible compiler (GCC 11+, Clang 13+, MSVC 2022+)
  • Premake5 for project generation
  • Optional: GoogleTest, Google Benchmark

License

MIT License - See LICENSE file for details


Full Changelog: v2.0.0...v3.0.0