add --log-level option, improve Config/Logger documentation, fix NETWORK_EANBLED typos in Engine new_graphics
authorTero Marttila <terom@fixme.fi>
Thu, 22 Jan 2009 02:38:33 +0200
branchnew_graphics
changeset 418 194bc810a570
parent 417 c503e0c6a740
child 419 9cd4e54693b6
add --log-level option, improve Config/Logger documentation, fix NETWORK_EANBLED typos in Engine
src/Application.cc
src/Application.hh
src/Config.hh
src/Configuration.hh
src/Engine.cc
src/Engine.hh
src/Logger.cc
src/Logger.hh
src/Network/Socket.hh
src/Types.hh
--- a/src/Application.cc	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Application.cc	Thu Jan 22 02:38:33 2009 +0200
@@ -28,6 +28,7 @@
     ARG_VERSION         = 0xff02,
     ARG_TERRAIN_SEED    = 0xff03,
     ARG_TERRAIN_SIZE    = 0xff04,
+    ARG_LOG_LEVEL       = 0xff05,
 
 };
 
@@ -90,6 +91,9 @@
 
     
     args.add_group("General");
+    args.add_option(ARG_LOG_LEVEL, "log-level", "LEVEL",
+            "set maximum log level to one of FATAL/ERROR/WARN/INFO/DEBUG");
+
     args.add_option(ARG_HELP, "help", "",
             "display argument help and exit");
 
@@ -116,6 +120,10 @@
                 args.print_help();
                 return false;
 
+            case ARG_LOG_LEVEL:
+                engine.log_level = parse_arg_loglevel(args.get_argument(), "--log-level");
+                break;
+
 #if NETWORK_ENABLED                
             case ARG_PORT:
                 net_port = args.get_argument();
@@ -218,6 +226,27 @@
     return PixelDimensions(w, h);
 }
 
+LogLevel Main::parse_arg_loglevel (const std::string &arg_val, const char *arg_name) {
+    // brute-force if-elseif
+    if (arg_val == "FATAL")
+        return FATAL;
+
+    else if (arg_val == "ERROR")
+        return ERROR;
+
+    else if (arg_val == "WARN")
+        return WARN;
+
+    else if (arg_val == "INFO")
+        return INFO;
+
+    else if (arg_val == "DEBUG")
+        return DEBUG;
+
+    else
+        throw ArgumentError(std::string() + "invalid log level for " + arg_name + ": " + arg_val);
+}
+
 #if GRAPHICS_ENABLED
 void Main::dump_display_modes (void) {
     // get the list of display modes from graphics
@@ -271,7 +300,7 @@
             return 0;
 
         // our engine
-        Engine engine;
+        Engine engine(this->engine);
 
         // setup game unless client
         if (net_connect.empty())
--- a/src/Application.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Application.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -36,6 +36,11 @@
         TerrainConfig terrain;
 
         /**
+         * --log-level
+         */
+        EngineConfig engine;
+
+        /**
          * --port
          */
         std::string net_port;
@@ -67,6 +72,11 @@
          * Parse unsigned WIDTHxHEIGHT argument
          */
         PixelDimensions parse_arg_dimensions (const std::string &arg_val, const char *arg_name);
+
+        /**
+         * Parse a LogLevel
+         */
+        LogLevel parse_arg_loglevel (const std::string &arg_val, const char *arg_name);
         
         /**
          * Print out a list of display modes
--- a/src/Config.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Config.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -17,39 +17,69 @@
 #include <ClanLib/display.h>
 
 /**
- * The value of pi used in physics/graphics calculations
+ * @name General
+ * @{
  */
-const float KG_PI = 3.14159265;
+
+// @}
 
 /**
- * Random generator seed to use for terrain generator
+ * @name Terrain
+ * @{
  */
+
+/** Default random generator seed to use for terrain generator */
 const int TERRAIN_RANDOM_SEED = 1337;
 
+/** Default terrain size, equal to physics simulation size */
+const PixelDimensions TERRAIN_DIMENSIONS (1000, 800);
+
+/** Base color of empty space (i.e. background color) */
+const CL_Color COLOR_EMPTY(86, 41, 0);
+
+/** Base color of dirt */
+const CL_Color COLOR_DIRT(144, 82, 23);
+
+/** Base color of rock */
+const CL_Color COLOR_ROCK(132, 136, 135);
+
+
+// @}
+
 /**
- * Terrain size, equal to physics simulation size
+ * @name Engine
+ * @{
  */
-const PixelDimension TERRAIN_WIDTH = 1000;
-const PixelDimension TERRAIN_HEIGHT = 800;
 
 /** Engine timeout, this determines our minimum tick rate */
 const TimeMS ENGINE_TIMEOUT_MS = 10;
 
+/** Default log output level */
+const LogLevel DEFAULT_LOG_LEVEL = DEBUG;
+
+// @}
+
+/**
+ * @name Physics
+ * @{
+ */
+
+/** The value of pi used in physics/graphics calculations */
+const float KG_PI = 3.14159265;
+
 /** Physics tick interval */
 const TimeMS PHYSICS_TICK_MS = 10;
 
-/** Input handling keyboard poll interval */
-const TimeMS INPUT_POLL_INTERVAL = 10;
+/** The force of gravity on objects, exerted on the Y axis */
+const float MAP_GRAVITY = 1500.0;
 
-/** How long to block INPUT_FLAG_NOREPEAT for */
-const TimeMS INPUT_REPEAT_DELAY = 250;
+// @}
 
 /**
- * The force of gravity on objects, exerted on the Y axis
+ * @name Player
+ * @{
  */
-const float MAP_GRAVITY = 1500.0;
 
-// Player properties
 const float PLAYER_MASS = 10.0;
 const float PLAYER_MOVE_FORCE = 1100.0;
 const float PLAYER_MIN_SPEED = 10.0;
@@ -61,16 +91,12 @@
 const float PLAYER_CROSSHAIR_DISTANCE = 20.0;
 const float PLAYER_CROSSHAIR_WIDTH = 4;
 const float CROSSHAIR_ANGLE_SPEED = PI/2000;
-
 const float PLAYER_MAX_SPEED = 43;
 const float PLAYER_WALK_SPEED = 33;
-
-const float PLAYER_COLLISION_ELASTICITY = 0.25; // TODO: This could be
-                                        // different for different
-                                        // objects
+const float PLAYER_COLLISION_ELASTICITY = 0.25;
 const float PLAYER_RADIUS = 10;
 
-/** What size of hole to dig */
+/** Radius if ground removed on digging */
 const float PLAYER_DIG_RADIUS = 15;
 
 /** Player's initial health */
@@ -79,17 +105,22 @@
 /** How long to wait after dying to respawn */
 const TimeMS PLAYER_RESPAWN_DELAY = 2500;
 
-/*
- * Projectiles
+// @}
+
+/**
+ * @name Projectile
+ * @{
  */
 
-// object mass...
+/** Projectiles mass is irrelevant */
 const float PROJECTILE_MASS = 10.0;
 
-// how far away from the player the projectile spawns
+/** How far away from the player the projectile spawns */
 const float PROJECTILE_START_DISTANCE = 10.0;
 
-/*
+// @}
+
+/**
  * @name Rope
  * @{
  */
@@ -117,23 +148,34 @@
 
 // @}
 
-// Graphical properties
-const CL_Color COLOR_EMPTY(86, 41, 0);
-const CL_Color COLOR_DIRT(144, 82, 23);
-const CL_Color COLOR_ROCK(132, 136, 135);
+/**
+ * @name Graphics/Input
+ * @{
+ */
 
-// graphics params
+/** Window title, XXX: PROJECT_VERSION is unreliable */
 const std::string GRAPHICS_WINDOW_TITLE = (std::string() + PROJECT_LONG_NAME + " : Version " + PROJECT_VERSION);
-const uint32_t GRAPHICS_RESOLUTION_WIDTH = 800;
-const uint32_t GRAPHICS_RESOLUTION_HEIGHT = 600;
-const uint16_t GRAPHICS_UPDATE_INTERVAL_MS = 20;
+
+/** Default resolution */
+const PixelDimensions GRAPHICS_RESOLUTION (800, 600);
+
+/** Interval between frames */
+const TimeMS GRAPHICS_UPDATE_INTERVAL_MS = 20;
+
+/** Default fullscreen mode? */
 const bool GRAPHICS_FULLSCREEN = false;
 
-/**
- * Number of pixels between lines
- */
+/** Number of pixels between lines */
 const PixelDimension GRAPHICS_INFO_TEXT_LINE_OFFSET = 5;
 
+/** Input handling keyboard poll interval */
+const TimeMS INPUT_POLL_INTERVAL = 10;
+
+/** How long to block INPUT_FLAG_NOREPEAT for */
+const TimeMS INPUT_REPEAT_DELAY = 250;
+
+// @}
+
 /**
  * @name Network
  * @{
--- a/src/Configuration.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Configuration.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -13,6 +13,20 @@
 #include "Config.hh"
 
 /**
+ * Engine configuration
+ */
+struct EngineConfig {
+    /** Path to the XML ClanLib resource file */
+    std::string resource_path;
+
+    /** Log output level */
+    enum LogLevel log_level;
+
+    /** Defaults */
+    EngineConfig (void) : resource_path(RESOURCE_XML_PATH), log_level(DEFAULT_LOG_LEVEL) { }
+};
+
+/**
  * Terrain configuration
  */
 struct TerrainConfig {
@@ -23,7 +37,7 @@
     int random_seed;
     
     /** Defaults */
-    TerrainConfig (void) : dimensions(TERRAIN_WIDTH, TERRAIN_HEIGHT), random_seed(TERRAIN_RANDOM_SEED) { }
+    TerrainConfig (void) : dimensions(TERRAIN_DIMENSIONS), random_seed(TERRAIN_RANDOM_SEED) { }
 };
 
 /**
@@ -37,7 +51,7 @@
     bool fullscreen;
 
     /** Defaults */
-    DisplayConfig (void) : resolution(GRAPHICS_RESOLUTION_WIDTH, GRAPHICS_RESOLUTION_HEIGHT), fullscreen(GRAPHICS_FULLSCREEN) { }
+    DisplayConfig (void) : resolution(GRAPHICS_RESOLUTION), fullscreen(GRAPHICS_FULLSCREEN) { }
 };
 
 
--- a/src/Engine.cc	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Engine.cc	Thu Jan 22 02:38:33 2009 +0200
@@ -19,11 +19,17 @@
 #include <iostream>
 #include <cassert>
 
-Engine::Engine (const std::string resource_xml_path) : 
+/*
+ * Initialize static Engine global state
+ */
+LogLevel Engine::log_level = DEBUG;
+
+Engine::Engine (const EngineConfig &config) : 
     terrain(NULL), game_state(NULL), graphics(NULL), net_server(NULL), net_client_connect(NULL),
-    is_running(true), resources(resource_xml_path)
+    is_running(true), resources(config.resource_path)
 {
-    
+    // update global log_level
+    Engine::log_level = config.log_level;
 }
 
 GameState& Engine::setupGame (Terrain *terrain) {
@@ -81,7 +87,7 @@
 
 void Engine::setupNetworkServer (const std::string &listen_port) {
 
-#if NETWORK_EANBLED    
+#if NETWORK_ENABLED    
     NetworkEndpoint listen_addr(listen_port);
     
     assert(terrain && game_state);
@@ -103,7 +109,7 @@
 
 void Engine::setupNetworkClient (const std::string &connect_host, const std::string &connect_port) {
 
-#if NETWORK_EANBLED    
+#if NETWORK_ENABLED 
     // connect_to
     NetworkEndpoint connect_addr(connect_host, connect_port);
 
@@ -140,29 +146,28 @@
 }
 
 void Engine::run (void) {
+    // timeout for NetworkReactor
+    timeval timeout;
+
     while (is_running) {
         /*
          * Run internal ClanLib stuff (also includes our timers) until our timeout has elapsed
          */
         CL_System::keep_alive(ENGINE_TIMEOUT_MS);
         
-#if NETWORK_ENABLED       
+#if NETWORK_ENABLED 
+        // setup timeout to zero
+        timeout.tv_sec = 0;
+        timeout.tv_usec = 0;
+
         /*
          * Thursday came and went, I re-wrote clan-event.
          *
          * (actually, we only use it for zero-timeout polling now... not sure if this is better than using the above
          * CL_System::keep_alive)
          */
-        NetworkReactor::current->poll(NULL);
+        NetworkReactor::current->poll(&timeout);
 #endif        
     }
 }
 
-CL_ResourceManager* Engine::getResourceManager (void) {
-    return &resources;
-}
-
-Logger Engine::log (enum LogLevel level, const char *type) {
-    return Logger(level <= WARN ? std::cerr : std::cout, level, type);
-}
-
--- a/src/Engine.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Engine.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -20,27 +20,36 @@
  */
 class Engine {
     private:
-        // game state
+        /** The game's terrain */
         Terrain *terrain;
-        GameState *game_state;
-
-        // Graphics/Input
-        graphics::Graphics *graphics;
 
-        // network server/client
+        /** The game's state */
+        GameState *game_state;
+        
+        /** The graphics+input component */
+        graphics::Graphics *graphics;
+        
+        /** Network server */
         NetworkServer *net_server;
-        NetworkClientConnect *net_client_connect;
-        // XXX: currently unused: NetworkClient *net_client;
 
-        // to exit the mainloop
+        /** Network client connector */
+        NetworkClientConnect *net_client_connect;
+
+        /** Network client, currently unused */
+        NetworkClient *net_client;
+
+        /** Is the mainloop still running? */
         bool is_running;
+        
+        /** Used to load ClanLib resources */
+        CL_ResourceManager resources;
 
-        // ClanLib resources
-        CL_ResourceManager resources;
+        /** *Global* log level */
+        static LogLevel log_level;
     
     public:    
         // default constructor
-        Engine (const std::string resource_xml_path = RESOURCE_XML_PATH);
+        Engine (const EngineConfig &config);
 
         /**
          * Setup game world using the given terrain, returning the new GameState
@@ -97,11 +106,21 @@
         void startGameView (LocalPlayer *player);
 
     public:
-        // get a pointer to our resource manager
-        CL_ResourceManager* getResourceManager (void);
-
-        // logging utility
-        static Logger log (enum LogLevel level, const char *type);
+        /**
+         * Get a pointer to our resource manager, please don't break it.
+         *
+         * Guaranteed to never be NULL
+         */
+        CL_ResourceManager* getResourceManager (void) { return &resources; }
+        
+        /**
+         * Log output, see Logger for more info
+         *
+         * @see Logger
+         */
+        static inline Logger log (LogLevel level, const char *type) {
+            return Logger(level <= WARN ? std::cerr : std::cout, level, type, log_level);
+        }
 
 };
 
--- a/src/Logger.cc	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Logger.cc	Thu Jan 22 02:38:33 2009 +0200
@@ -1,8 +1,8 @@
 
 #include "Logger.hh"
 
-Logger::Logger (std::ostream &stream, enum LogLevel level, const char *module) : 
-    stream(stream), level(level), module(module) 
+Logger::Logger (std::ostream &stream, LogLevel level, const char *module, LogLevel max_level) : 
+    stream(stream), show(level <= max_level)
 {
     const char *l;
 
@@ -14,15 +14,13 @@
         case DEBUG: l = "DEBUG"; break;
         default: l = "???"; break;
     };
-
-#ifndef NDEBUG    
-    stream << l << " [" << module << "] ";
-#endif
+    
+    if (show)
+        stream << l << " [" << module << "] ";
 }
 
 Logger::~Logger (void) {
-#ifndef NDEBUG    
-    stream << std::endl;
-#endif
+    if (show)
+        stream << std::endl;
 }
 
--- a/src/Logger.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Logger.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -1,52 +1,69 @@
 #ifndef LOGGER_HH
 #define LOGGER_HH
 
-#include <ClanLib/network.h>
+#include "Types.hh"
 
 #include <iostream>
 
 /**
- * Message severity, WARN and above should go to stderr, INFO and DEBUG to stdout
+ * Utility class used for logging, use Engine::log() to construct these. Implements the same streaming behaviour as 
+ * std::ostream, but the construtor prints out a header, and the destructor a newline. 
  *
- * @see Engine::log
- */
-enum LogLevel {
-    FATAL,
-    ERROR,
-    WARN,
-    INFO,
-    DEBUG,
-};
-
-/**
- * Utility class used for logging, use Engine::log to construct these
+ * Useage example:
+ * 
+ * \code
+ *      Engine::log(INFO, "foo.bar") << "value of quux=" << quux;
+ *
+ * \endcode
+ *
+ * This will result in output like the following to stdout:
+ *
+ * \verbatim
+ * INFO [foo.bar] value of quux=5
+ * \endverbatim
  *
  * @see Engine::log
  */
 class Logger {
     private:
+        /**
+         * The stream we output to
+         */
         std::ostream &stream;
-        enum LogLevel level;
-        const char *module;
+
+        /**
+         * Do we even care?
+         */
+        bool show;
 
     public:
-        Logger (std::ostream &stream, enum LogLevel level, const char *module);
-
-        template <typename T> Logger& operator<< (const T val) {
-#ifndef NDEBUG
-            stream << val;
-#else
-            (void) val;            
-#endif
-
-            return *this;
-        }
-
+        /**
+         * If the given level is smaller than the given maximum level, output the header. Otherwise, act as a
+         * no-op.
+         */
+        Logger (std::ostream &stream, LogLevel level, const char *module, LogLevel max_level);
+        
+        /**
+         * Stream the given value to our output stream, just like with std::ostream, unless we're acting as a no-op.
+         */
+        template <typename T> Logger& operator<< (const T val);
+        
+        /**
+         * Output the final newline
+         */
         ~Logger (void);
 };
 
-std::ostream& operator<< (std::ostream &s, CL_NetComputer &c);
-std::ostream& operator<< (std::ostream &s, CL_NetObject_Server &obj);
-std::ostream& operator<< (std::ostream &s, CL_NetObject_Client &obj);
+/*
+ * Logger template method definition
+ */
+template <typename T> 
+inline Logger& Logger::operator<< (const T val) {
+    if (show)
+        stream << val;
+    
+    // chaining
+    return *this;
+}
 
 #endif /* LOGGER_HH */
--- a/src/Network/Socket.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Network/Socket.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -15,6 +15,8 @@
 #include "Address.hh"
 #include "Reactor.hh"
 
+#include <ClanLib/signals.h>
+
 /**
  * This is a socket class that wraps an OS socket filedescriptor and provides the more important socket operations
  * as methods. The implementation aims to be address-family agnostic, and should thence work with both IPv6 and IPv4.
--- a/src/Types.hh	Thu Jan 22 01:53:05 2009 +0200
+++ b/src/Types.hh	Thu Jan 22 02:38:33 2009 +0200
@@ -15,6 +15,21 @@
 typedef VectorType<float> Vector;
 
 /**
+ * Message severity, WARN and above should go to stderr, INFO and DEBUG to stdout
+ *
+ * @see Engine::log
+ * @see EngineConfig::log_level
+ * @see Logger
+ */
+enum LogLevel {
+    FATAL,
+    ERROR,
+    WARN,
+    INFO,
+    DEBUG,
+};
+
+/**
  * A player's health is measured in...
  */
 typedef int16_t Health;