# HG changeset patch # User Tero Marttila # Date 1232584713 -7200 # Node ID 194bc810a570d19a24c6a0bde029ce671744976f # Parent c503e0c6a7406f9e8deaaca24b469fc53767dc84 add --log-level option, improve Config/Logger documentation, fix NETWORK_EANBLED typos in Engine diff -r c503e0c6a740 -r 194bc810a570 src/Application.cc --- 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()) diff -r c503e0c6a740 -r 194bc810a570 src/Application.hh --- 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 diff -r c503e0c6a740 -r 194bc810a570 src/Config.hh --- 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 /** - * 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 * @{ diff -r c503e0c6a740 -r 194bc810a570 src/Configuration.hh --- 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) { } }; diff -r c503e0c6a740 -r 194bc810a570 src/Engine.cc --- 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 #include -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); -} - diff -r c503e0c6a740 -r 194bc810a570 src/Engine.hh --- 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); + } }; diff -r c503e0c6a740 -r 194bc810a570 src/Logger.cc --- 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; } diff -r c503e0c6a740 -r 194bc810a570 src/Logger.hh --- 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 +#include "Types.hh" #include /** - * 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 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 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 +inline Logger& Logger::operator<< (const T val) { + if (show) + stream << val; + + // chaining + return *this; +} #endif /* LOGGER_HH */ diff -r c503e0c6a740 -r 194bc810a570 src/Network/Socket.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 + /** * 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. diff -r c503e0c6a740 -r 194bc810a570 src/Types.hh --- 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 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;