add --log-level option, improve Config/Logger documentation, fix NETWORK_EANBLED typos in Engine
--- 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;