From 6172c221cd30986e978237e7a07027ce2f21c47a Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Thu, 21 Mar 2019 01:22:39 +0800 Subject: [PATCH] Add logger and support for querying CLI variables --- .../{console.cpp => command-interpreter.cpp} | 32 +-- .../{console.hpp => command-interpreter.hpp} | 14 +- src/debug/logger.cpp | 43 ++++ src/debug/logger.hpp | 48 +++++ src/game.cpp | 196 +++++++----------- src/game.hpp | 13 +- 6 files changed, 191 insertions(+), 155 deletions(-) rename src/debug/{console.cpp => command-interpreter.cpp} (80%) rename src/debug/{console.hpp => command-interpreter.hpp} (95%) create mode 100644 src/debug/logger.cpp create mode 100644 src/debug/logger.hpp diff --git a/src/debug/console.cpp b/src/debug/command-interpreter.cpp similarity index 80% rename from src/debug/console.cpp rename to src/debug/command-interpreter.cpp index e8cce02..4060637 100644 --- a/src/debug/console.cpp +++ b/src/debug/command-interpreter.cpp @@ -17,7 +17,7 @@ * along with Antkeeper Source Code. If not, see . */ -#include "console.hpp" +#include "command-interpreter.hpp" #include template<> @@ -64,15 +64,15 @@ std::string ArgumentParser::parse(const std::string& argument) void CommandInterpreter::set(const std::string& name, const std::string& value) { - variables[name] = value; + variableMap[name] = value; } void CommandInterpreter::unset(const std::string& name) { - auto it = variables.find(name); - if (it != variables.end()) + auto it = variableMap.find(name); + if (it != variableMap.end()) { - variables.erase(it); + variableMap.erase(it); } } @@ -81,6 +81,11 @@ const std::map& CommandInterpreter::help() const return helpStrings; } +const std::map& CommandInterpreter::variables() const +{ + return variableMap; +} + std::tuple, std::function> CommandInterpreter::interpret(const std::string& line) { // Split line into arguments @@ -103,7 +108,7 @@ std::tuple, std::function> Command if (!argument.empty() && argument[0] == '$') { std::string variableName = argument.substr(1); - std::string variableValue = variables[variableName]; + std::string variableValue = variableMap[variableName]; argument = variableValue; } } @@ -114,21 +119,6 @@ std::tuple, std::function> Command // Remove command name from arguments arguments.erase(arguments.begin()); - // Check command name for member access operator '.' - std::size_t dotOperatorPosition = commandName.find('.'); - if (dotOperatorPosition != std::string::npos) - { - // Get variable name and lookup value - std::string variableName = commandName.substr(0, dotOperatorPosition); - std::string variableValue = variables[variableName]; - - // Insert variable value at front of the argument vector - arguments.insert(arguments.begin(), variableValue); - - // Remove variable name from command name - commandName = commandName.substr(dotOperatorPosition + 1); - } - // Find command linker for this command auto linker = linkers.find(commandName); if (linker == linkers.end()) diff --git a/src/debug/console.hpp b/src/debug/command-interpreter.hpp similarity index 95% rename from src/debug/console.hpp rename to src/debug/command-interpreter.hpp index d13b4eb..a866e0a 100644 --- a/src/debug/console.hpp +++ b/src/debug/command-interpreter.hpp @@ -17,8 +17,8 @@ * along with Antkeeper Source Code. If not, see . */ -#ifndef CONSOLE_HPP -#define CONSOLE_HPP +#ifndef COMMAND_INTERPRETER_HPP +#define COMMAND_INTERPRETER_HPP #include #include @@ -139,6 +139,12 @@ public: */ const std::map& help() const; + /** + * Returns all variables and their values. + */ + const std::map& variables() const; + + /** * Interprets a line of text as a function call, returning the interpreted command name, argument vector, and callable function object. * @@ -153,7 +159,7 @@ private: // A command name-keyed map of command linkers std::unordered_map(const std::vector&)>> linkers; std::map helpStrings; - std::unordered_map variables; + std::map variableMap; }; template @@ -175,5 +181,5 @@ void CommandInterpreter::addCommandLinker(const std::string& name, const Functio linkers[name] = std::bind(linker, function, std::placeholders::_1); } -#endif // CONSOLE_HPP +#endif // COMMAND_INTERPRETER_HPP diff --git a/src/debug/logger.cpp b/src/debug/logger.cpp new file mode 100644 index 0000000..b0817ef --- /dev/null +++ b/src/debug/logger.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#include "logger.hpp" +#include + +Logger::Logger(): + os(&std::cout) +{} + +Logger::~Logger() +{} + +void Logger::redirect(std::ostream* stream) +{ + os = stream; +} + +void Logger::log(const std::string& text) +{ + if (os) + { + (*os) << text; + os->flush(); + } +} + diff --git a/src/debug/logger.hpp b/src/debug/logger.hpp new file mode 100644 index 0000000..3529568 --- /dev/null +++ b/src/debug/logger.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017-2019 Christopher J. Howard + * + * This file is part of Antkeeper Source Code. + * + * Antkeeper Source Code is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Antkeeper Source Code is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Antkeeper Source Code. If not, see . + */ + +#ifndef LOGGER_HPP +#define LOGGER_HPP + +#include +#include + +class Logger +{ +public: + Logger(); + ~Logger(); + + /** + * Redirects log output to the specified output stream. + * + * @param stream Output stream to which log text will be written. + */ + void redirect(std::ostream* stream); + /** + * Outputs text to the log. + */ + void log(const std::string& text); + +private: + std::ostream* os; +}; + +#endif // LOGGER_HPP + diff --git a/src/game.cpp b/src/game.cpp index 0f6b201..527bce2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -64,7 +64,8 @@ #include #include -#include "debug/console.hpp" +#include "debug/command-interpreter.hpp" +#include "debug/logger.hpp" template <> bool Game::readSetting(const std::string& name, std::string* value) const @@ -174,13 +175,11 @@ Game::Game(int argc, char* argv[]): dataPath = getDataPath(applicationName) + "data/"; configPath = getConfigPath(applicationName); controlsPath = configPath + "controls/"; - scriptsPath = configPath + "scripts/"; // Create nonexistent config directories std::vector configPaths; configPaths.push_back(configPath); configPaths.push_back(controlsPath); - configPaths.push_back(scriptsPath); for (const std::string& path: configPaths) { if (!pathExists(path)) @@ -189,18 +188,10 @@ Game::Game(int argc, char* argv[]): } } - // Setup logging - #if !defined(DEBUG) - std::string logFilename = configPath + "log.txt"; - logFileStream.open(logFilename.c_str()); - std::cout.rdbuf(logFileStream.rdbuf()); - #endif - // Setup resource manager resourceManager = new ResourceManager(); // Include resource search paths in order of priority - resourceManager->include(scriptsPath); resourceManager->include(controlsPath); resourceManager->include(configPath); resourceManager->include(dataPath); @@ -505,7 +496,6 @@ void Game::setup() screenshotQueued = false; paused = false; - // Load model resources try { @@ -516,14 +506,11 @@ void Game::setup() } catch (const std::exception& e) { - std::cerr << "Failed to load one or more models: \"" << e.what() << "\"" << std::endl; + logger->log("Failed to load one or more models: \"" + std::string(e.what()) + "\"\n"); close(EXIT_FAILURE); } - - time = 0.0f; - // Tools currentTool = nullptr; @@ -534,8 +521,6 @@ void Game::setup() worldScene->addObject(lens->getSpotlight()); lens->setSunDirection(-sunlightCamera.getForward()); - - // Forceps forceps = new Forceps(forcepsModel, &animator); forceps->setOrbitCam(orbitCam); @@ -590,45 +575,6 @@ void Game::setup() // Load navmesh TriangleMesh* navmesh = resourceManager->load("sidewalk.mesh"); - // Find surface - TriangleMesh::Triangle* surface = nullptr; - Vector3 barycentricPosition; - Ray ray; - ray.origin = Vector3(0, 100, 0); - ray.direction = Vector3(0, -1, 0); - auto intersection = ray.intersects(*navmesh); - if (std::get<0>(intersection)) - { - surface = (*navmesh->getTriangles())[std::get<3>(intersection)]; - - Vector3 position = ray.extrapolate(std::get<1>(intersection)); - Vector3 a = surface->edge->vertex->position; - Vector3 b = surface->edge->next->vertex->position; - Vector3 c = surface->edge->previous->vertex->position; - - barycentricPosition = barycentric(position, a, b, c); - } - - for (int i = 0; i < 0; ++i) - { - EntityID ant = createInstanceOf("worker-ant"); - setTranslation(ant, Vector3(0.0f, 0, 0.0f)); - - BehaviorComponent* behavior = new BehaviorComponent(); - SteeringComponent* steering = new SteeringComponent(); - LeggedLocomotionComponent* locomotion = new LeggedLocomotionComponent(); - componentManager->addComponent(ant, behavior); - componentManager->addComponent(ant, steering); - componentManager->addComponent(ant, locomotion); - - locomotion->surface = surface; - behavior->wanderTriangle = surface; - locomotion->barycentricPosition = barycentricPosition; - } - - - //EntityID tool0 = createInstanceOf("lens"); - int highResolutionDiameter = 3; int mediumResolutionDiameter = highResolutionDiameter + 2; int lowResolutionDiameter = 20; @@ -799,8 +745,11 @@ void Game::handleEvent(const ScheduledFunctionEvent& event) void Game::setupDebugging() { - // Setup performance sampling - performanceSampler.setSampleSize(30); + // Setup logging + logger = new Logger(); + std::string logFilename = configPath + "log.txt"; + logFileStream.open(logFilename.c_str()); + logger->redirect(&logFileStream); // Create CLI cli = new CommandInterpreter(); @@ -812,9 +761,15 @@ void Game::setupDebugging() std::function setScaleCommand = [this](int id, float x, float y, float z) { setScale(id, {x, y, z}); }; + std::function setTranslationCommand = [this](int id, float x, float y, float z) { + setTranslation(id, {x, y, z}); + }; + std::function createInstanceCommand = std::bind(&Game::createInstance, this); + std::function createNamedInstanceCommand = std::bind(&Game::createNamedInstance, this, std::placeholders::_1); std::function createInstanceOfCommand = std::bind(&Game::createInstanceOf, this, std::placeholders::_1); + std::function createNamedInstanceOfCommand = std::bind(&Game::createNamedInstanceOf, this, std::placeholders::_1, std::placeholders::_2); + std::function toggleWireframeCommand = [this](float width){ lightingPass->setWireframeLineWidth(width); }; - std::function shCommand = std::bind(&Game::executeShellScript, this, std::placeholders::_1); std::function helpCommand = [this]() { auto& helpStrings = cli->help(); @@ -828,28 +783,47 @@ void Game::setupDebugging() std::cout << it->second << std::endl; } }; + std::function variablesCommand = [this]() + { + auto& variables = cli->variables(); + for (auto it = variables.begin(); it != variables.end(); ++it) + { + std::cout << it->first << "=\"" << it->second << "\"" << std::endl; + } + }; + std::string exitHelp = "exit"; - std::string setHelp = "set "; - std::string unsetHelp = "unset "; + std::string setHelp = "set "; + std::string unsetHelp = "unset "; + std::string createInstanceHelp = "createinstance