Skip to content

Latest commit

 

History

History
181 lines (149 loc) · 8.07 KB

File metadata and controls

181 lines (149 loc) · 8.07 KB

C++ Quick Start Guide

This guide provides a quick introduction to setting up and running a basic agent simulation using the C++ core of AgentSimMiddleware. It walks through the essential steps to initialize the simulation, add agents, and run a simulation loop.

Prerequisites

  • A C++ development environment (e.g., Visual Studio on Windows, GCC/Clang on Linux/macOS).
  • CMake (version 3.15 or newer).
  • The AgentSimMiddleware C++ core built as a static or dynamic library. Follow the C++ Core Build Instructions to build the project.
  • The data/actions_goals.json file, which defines the GOAP actions and goals for agents.

Project Setup

  1. Create a New C++ Project: Start a new C++ console application project in your preferred IDE.
  2. Link AgentSimMiddleware Library:
    • Include the necessary header files from src/cpp/agent_core/ (e.g., AgentContainer.h, WorldSnapshot.h, DataTypes.h).
    • Link against the compiled AgentSimMiddleware library (e.g., .lib, .a, .so, or .dylib). The exact linking steps will depend on your build system (e.g., CMake, Visual Studio project settings).
  3. Copy GOAP Data: Ensure data/actions_goals.json is accessible by your executable at runtime. You might need to copy it to your build output directory.

Example Code (main.cpp)

The following code snippet demonstrates a minimal C++ simulation setup. This example initializes an AgentContainer, adds a few agents, and runs a simple update loop.

#include <vector>
#include <chrono>
#include <thread>
#include <filesystem>
#include <numeric>
#include <algorithm>
#include <fstream>
#include <sstream>

// Include necessary AgentSimMiddleware headers
#include "AgentContainer.h"
#include "WorldSnapshot.h"
#include "DataTypes.h"
#include "AgentCommand.h"
#include "spdlog/spdlog.h" // For logging (optional, but recommended)
#include "spdlog/sinks/stdout_color_sinks.h"

// Define a simple logging callback for use with AgentSimApi's SetLogCallback
void LogCallback(LogLevel level, const char* message) {
    switch (level) {
        case LogLevel::Trace: spdlog::trace(message); break;
        case LogLevel::Debug: spdlog::debug(message); break;
        case LogLevel::Info: spdlog::info(message); break;
        case LogLevel::Warn: spdlog::warn(message); break;
        case LogLevel::Error: spdlog::error(message); break;
        case LogLevel::Critical: spdlog::critical(message); break;
        default: spdlog::info(message); break;
    }
}

int main() {
    // 1. Initialize Logging
    auto console = spdlog::stdout_color_mt("console");
    spdlog::set_default_logger(console);
    spdlog::set_level(spdlog::level::info); // Set default logging level
    spdlog::info("Starting C++ Quick Start Application...");

    // Set the logging callback for the AgentSimMiddleware core
    SetLogCallback(LogCallback);

    // 2. Load GOAP Data
    std::string goapJsonContent;
    try {
        // Assuming data/actions_goals.json is in the executable's directory or a known path
        std::ifstream goapFile("data/actions_goals.json");
        if (!goapFile.is_open()) {
            throw std::runtime_error("Failed to open data/actions_goals.json");
        }
        std::stringstream buffer;
        buffer << goapFile.rdbuf();
        goapJsonContent = buffer.str();
    } catch (const std::exception& e) {
        spdlog::critical("Error loading GOAP JSON: {}", e.what());
        return 1;
    }

    // 3. Create AgentContainer
    const int maxAgents = 100; // Define maximum agents
    // Use the public API call to create the agent container
    AgentContainer* agentContainer = CreateAgentContainer(maxAgents, goapJsonContent.c_str());

    if (!agentContainer) {
        spdlog::critical("Failed to create AgentContainer!");
        return 1;
    }
    spdlog::info("AgentContainer created with maxAgents: {}.", maxAgents);

    // Optional: Set LOD thresholds
    SetLODThresholds(agentContainer, 20.0f, 50.0f); // Example: Full sim up to 20m, Lite sim up to 50m

    // 4. Add Agents
    spdlog::info("Adding agents...");
    int numAgentsToAdd = 10;
    for (int i = 0; i < numAgentsToAdd; ++i) {
        Vector3 initialAgentPos = {static_cast<float>(i * 2), 0.0f, static_cast<float>(i * 2)};
        Quaternion initialAgentRot = {0.0f, 0.0f, 0.0f, 1.0f}; // Identity rotation
        int initialGoal = 0; // Assuming Goal ID 0 exists (e.g., GATHER_WOOD)
        int initialState = static_cast<int>(AgentState::IDLE); // Start agents as IDLE

        int agentId = AddAgent(agentContainer, initialAgentPos, initialAgentRot, initialGoal, initialState);
        if (agentId == -1) {
            spdlog::error("Failed to add agent {}.", i);
        } else {
            spdlog::info("Agent {} added at ({}, {}, {}).", agentId, initialAgentPos.x, initialAgentPos.y, initialAgentPos.z);
        }
    }
    spdlog::info("Total agents in simulation: {}.", GetAgentCount(agentContainer));

    // 5. Prepare World Snapshot (Minimal Example)
    // In a real application, this would come from the game engine
    std::vector<WorldObject> worldObjectsData;
    worldObjectsData.push_back({1001, WorldObjectType::TREE, {15.0f, 0.0f, 15.0f}, {0,0,0,1}});
    worldObjectsData.push_back({1002, WorldObjectType::ROCK, {25.0f, 0.0f, 25.0f}, {0,0,0,1}});
    worldObjectsData.push_back({1003, WorldObjectType::TREE, {5.0f, 0.0f, 5.0f}, {0,0,0,1}});

    WorldSnapshot currentWorldSnapshot;
    currentWorldSnapshot.timestamp = 0;
    currentWorldSnapshot.worldObjects = worldObjectsData.data();
    currentWorldSnapshot.numWorldObjects = static_cast<int>(worldObjectsData.size());
    currentWorldSnapshot.worldEvents = nullptr; // No events for this minimal example
    currentWorldSnapshot.numWorldEvents = 0;
    currentWorldSnapshot.sunDirection = {0.0f, -1.0f, 0.0f};
    currentWorldSnapshot.timeOfDay = 12.0f;

    // 6. Simulation Loop
    float deltaTime = 0.016f; // Approximately 60 FPS
    const int numTicks = 500;
    Vector3 cameraPosition = {0.0f, 10.0f, -20.0f}; // Example camera position

    std::vector<AgentCommand> agentCommands(maxAgents);
    int commandCount = 0;
    int maxCommandCapacity = maxAgents;

    spdlog::info("Starting simulation loop for {} ticks...", numTicks);
    for (int tick = 0; tick < numTicks; ++tick) {
        commandCount = 0; // Reset command count for each tick

        // Update the simulation using the public API
        Update(agentContainer, deltaTime, cameraPosition, &currentWorldSnapshot,
               agentCommands.data(), &commandCount, maxCommandCapacity);

        // Process AgentCommands (in a real scenario, these would be sent to the game engine)
        if (commandCount > 0) {
            spdlog::debug("Tick {}: Received {} agent commands.", tick, commandCount);
            // Example: Log commands for the first few agents
            for (int i = 0; i < std::min(commandCount, 3); ++i) {
                spdlog::debug("  Agent {}: Command Type {}", agentCommands[i].agentId, (int)agentCommands[i].commandType);
            }
        }

        // Optional: Get and log some agent data
        if (tick % 100 == 0) {
            spdlog::info("Tick {}: Agent 0 position: ({:.1f}, {:.1f}, {:.1f})", tick,
                         agentContainer->m_agentManager.getPosition(0).x,
                         agentContainer->m_agentManager.getPosition(0).y,
                         agentContainer->m_agentManager.getPosition(0).z);
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int>(deltaTime * 1000))); // Simulate real-time
    }

    // 7. Shutdown Simulation
    spdlog::info("Shutting down simulation...");
    DestroyAgentContainer(agentContainer);
    spdlog::info("Simulation shutdown complete.");

    return 0;
}

Running the Example

  1. Build your C++ project.
  2. Ensure data/actions_goals.json is in the same directory as your executable, or provide the correct path.
  3. Run the executable. You should see console output detailing the simulation's progress and agent activities.

This example provides a foundational understanding of how to interact with the AgentSimMiddleware C++ core in a standalone application.