The InfinityEngine class is your primary interface for loading cores, discovering systems, and managing procedural generation workflows. This tutorial covers the essential patterns for working with the engine API effectively.
Engine Initialization and Core Loading
Basic Engine Creation
#include <Infinity/InfinityInit.h>
#include <Infinity/Engine/InfinityEngine.h>
Main entry point to the InfinityEngine API for procedural generation.
Definition InfinityEngine.hpp:26
INFINITY_API_PUBLIC void InfinityInit(void)
Initializes the Infinity Engine.
Loading Multiple Cores
The InfinityEngine can work with one core at a time. To switch between cores, create new engine instances:
void processMultipleCores() {
std::vector<std::string> coreFiles = {
"terrain/terrain_generation.infinitycore",
"buildings/building_system.infinitycore",
"vegetation/forest_generator.infinitycore"
};
std::vector<Infinity::Engine::InfinityEngine> engines;
for (const auto& coreFile : coreFiles) {
try {
}
catch (const std::exception& e) {
std::cerr << "Failed to load " << coreFile << ": " << e.what() << std::endl;
}
}
}
Discovering and Accessing Systems
Listing Available Systems
std::cout << "Root systems (" << rootSystems.size() << "):" << std::endl;
for (const auto& system : rootSystems) {
std::cout << " - " << system->id() << std::endl;
}
std::cout << "\\nAll systems (" << allSystems.size() << "):" << std::endl;
for (const auto& system : allSystems) {
std::cout << " - " << system->id() << std::endl;
}
}
std::vector< std::shared_ptr< Infinity::Procedural::ProceduralSystem > > rootSystems() const
Retrieves all root-level ProceduralSystems in the loaded core.
std::vector< std::shared_ptr< Infinity::Procedural::ProceduralSystem > > allSystems() const
Retrieves all ProceduralSystems in the loaded core.
Accessing Specific Systems
auto terrainSystem = engine.
system(
"TerrainGenerator");
if (terrainSystem) {
std::cout << "Found terrain system: " << terrainSystem->id() << std::endl;
}
auto nestedSystem = engine.
system(
"WorldGen/TerrainDetail/ErosionSimulation");
if (nestedSystem) {
std::cout << "Found nested system: " << nestedSystem->id() << std::endl;
}
for (const auto& system : allSystems) {
if (system->id().find("Terrain") != std::string::npos) {
std::cout << "Terrain-related system: " << system->id() << std::endl;
}
}
}
std::shared_ptr< Infinity::Procedural::ProceduralSystem > system(const std::string &path) const
Retrieves a specific ProceduralSystem by its path identifier.
Error Handling and Validation
Robust Core Loading
std::unique_ptr<Infinity::Engine::InfinityEngine> loadCoreRobustly(
const std::filesystem::path& corePath) {
if (!std::filesystem::exists(corePath)) {
throw std::runtime_error("Core file not found: " + corePath.string());
}
if (corePath.extension() != ".infinitycore") {
std::cerr << "Warning: Unexpected file extension for core: "
<< corePath.extension().string() << std::endl;
}
try {
auto engine = std::make_unique<Infinity::Engine::InfinityEngine>(corePath);
if (systems.empty()) {
std::cerr << "Warning: Core contains no systems" << std::endl;
}
std::cout << "Successfully loaded core with " << systems.size() << " systems" << std::endl;
return engine;
}
catch (const std::exception& e) {
throw std::runtime_error("Failed to load core: " + std::string(e.what()));
}
}
System Access Validation
const std::string& systemName) {
auto system = engine.
system(systemName);
if (!system) {
std::cerr << "System not found: " << systemName << std::endl;
std::cout << "Available systems:" << std::endl;
for (const auto& available : allSystems) {
std::cout << " - " << available->id() << std::endl;
}
return false;
}
std::cout << "System found: " << system->id() << std::endl;
return true;
}
Advanced Usage Patterns
Executing Multiple Systems in Sequence
std::vector<std::string> processingOrder = {
"TerrainBase",
"TerrainDetail",
"VegetationPlacement",
"FinalComposition"
};
struct ProcessingContext {
uint64_t seed = 12345;
float worldScale = 1000.0f;
} context;
for (const auto& systemName : processingOrder) {
auto system = engine.
system(systemName);
if (!system) {
std::cerr << "Skipping missing system: " << systemName << std::endl;
continue;
}
std::cout << "Processing: " << systemName << std::endl;
system->setSeed(context.seed);
system->setIn("worldScale", context.worldScale);
system->execute();
std::cout << "Completed: " << systemName << std::endl;
}
}
Parallel System Execution (Independent Systems)
#include <future>
#include <thread>
std::vector<std::string> independentSystems = {
"TreeGenerator",
"RockScatter",
"WaterGeneration",
"CloudSystem"
};
std::vector<std::future<void>> futures;
for (const auto& systemName : independentSystems) {
auto system = engine.
system(systemName);
if (!system) continue;
futures.emplace_back(std::async(std::launch::async, [system, systemName]() {
try {
std::cout << "Starting: " << systemName << std::endl;
system->setSeed(std::hash<std::string>{}(systemName));
system->execute();
std::cout << "Completed: " << systemName << std::endl;
}
catch (const std::exception& e) {
std::cerr << "Error in " << systemName << ": " << e.what() << std::endl;
}
}));
}
for (auto& future : futures) {
future.wait();
}
std::cout << "All independent systems completed" << std::endl;
}
Dynamic System Selection
auto selectSystemByPrefix = [&](const std::string& prefix) ->
std::shared_ptr<Infinity::Procedural::ProceduralSystem> {
for (const auto& system : allSystems) {
if (system->id().starts_with(prefix)) {
return system;
}
}
return nullptr;
};
std::string terrainType = "Mountain";
if (auto system = selectSystemByPrefix(terrainType)) {
std::cout << "Using terrain system: " << system->id() << std::endl;
system->execute();
} else {
std::cout << "No system found for terrain type: " << terrainType << std::endl;
if (
auto defaultSystem = engine.
system(
"DefaultTerrain")) {
std::cout << "Using default terrain system" << std::endl;
defaultSystem->execute();
}
}
}
Integration Patterns
Engine Wrapper Class
For larger applications, consider wrapping the engine in a higher-level interface:
class ProceduralGenerationManager {
private:
std::unique_ptr<Infinity::Engine::InfinityEngine> engine_;
std::filesystem::path currentCorePath_;
public:
bool loadCore(const std::filesystem::path& corePath) {
try {
engine_ = std::make_unique<Infinity::Engine::InfinityEngine>(corePath);
currentCorePath_ = corePath;
return true;
}
catch (const std::exception& e) {
std::cerr << "Failed to load core: " << e.what() << std::endl;
return false;
}
}
std::vector<std::string> getAvailableSystemNames() const {
if (!engine_) return {};
auto systems = engine_->allSystems();
std::vector<std::string> names;
names.reserve(systems.size());
for (const auto& system : systems) {
names.push_back(system->id());
}
return names;
}
bool executeSystem(const std::string& systemName, uint64_t seed = 0) {
if (!engine_) return false;
auto system = engine_->system(systemName);
if (!system) return false;
try {
if (seed != 0) {
system->setSeed(seed);
}
system->execute();
return true;
}
catch (const std::exception& e) {
std::cerr << "System execution failed: " << e.what() << std::endl;
return false;
}
}
std::shared_ptr<Infinity::Procedural::ProceduralSystem> getSystem(const std::string& name) const {
return engine_ ? engine_->system(name) : nullptr;
}
};
Best Practices
- Always call InfinityInit() before creating any engine instances
- Handle exceptions when loading cores or accessing systems
- Validate system existence before attempting operations
- Use descriptive system names in your cores for easier access
- Consider system dependencies when executing multiple systems
- Cache system references if you'll be using them repeatedly
- Use appropriate error logging to debug core loading issues
Troubleshooting
Engine creation fails:
- Ensure
InfinityInit() was called first
- Verify core file path and accessibility
- Check that all required component libraries are available
System not found:
- List all systems to verify exact naming
- Check for case sensitivity in system names
- Ensure the system wasn't filtered out during core loading
Performance issues:
- Avoid creating multiple engine instances unnecessarily
- Cache system references for repeated use
- Consider async execution for independent systems
Next Steps
Now that you understand the InfinityEngine API: