src/Application.cc
author Tero Marttila <terom@fixme.fi>
Wed, 21 Jan 2009 00:21:42 +0200
changeset 409 1a03ff151abc
parent 408 e6cfc44266af
child 411 106aaf6eadfe
permissions -rw-r--r--
add --terrain-seed and --terrain-size arguments, plus bugfixes

#include "Application.hh"

#include <stdexcept>
#include <sstream>
#include <cstdio>
#include <cassert>

enum ArgumentCodes {
    ARG_HELP        = 'h',
    ARG_PORT        = 'p',
    ARG_SERVER      = 's',
    ARG_CLIENT      = 'c',
    ARG_GRAPHICS    = 'g',
    ARG_FULLSCREEN  = 'F',
    ARG_RESOLUTION  = 'R',

    ARG_LIST_MODES      = 0xff01,
    ARG_VERSION         = 0xff02,
    ARG_TERRAIN_SEED    = 0xff03,
    ARG_TERRAIN_SIZE    = 0xff04,

};

        
Main::Main (void) :
    graphics_enabled(false),
    net_port(NETWORK_PORT_STR),
    net_server(false),
    net_connect("")
{

}

/**
 * Set the arg_* members
 */
bool Main::parse_args (int argc, char **argv) {
    // set up the options
    args.add_option(ARG_HELP, "help", "",
            "display argument help and exit");

    args.add_option(ARG_PORT, "port", "PORT",
            "set network port used");

    args.add_option(ARG_SERVER, "server", "",
            "act as a network server");

    args.add_option(ARG_CLIENT, "client", "SERVERHOST",
            "act as a network client");

    args.add_option(ARG_GRAPHICS, "graphics", "",        
            "run graphics/local input. Implied with --connect");

    args.add_option(ARG_FULLSCREEN, "fullscreen", "",
            "run graphics in fullscreen mode");

    args.add_option(ARG_RESOLUTION, "resolution", "WIDTHxHEIGHT",
            "set graphics resolution");
    
    args.add_option(ARG_LIST_MODES, "list-modes", "",
            "output a list of available display modes and exit");

    args.add_option(ARG_TERRAIN_SEED, "terrain-seed", "SEED",
            "set seed for terrain random generator");

    args.add_option(ARG_TERRAIN_SIZE, "terrain-size", "WIDTHxHEIGHT",
            "set terrain size for random generator");

    args.add_option(ARG_VERSION, "version", "",
            "output application version and exit");

    // extra state
    bool resolution_default = true;
    
    try {
        // parse args
        args.parse_args(argc, argv);

    } catch (CL_Error &e) {
        throw ArgumentError(e.message);
    }

    while (args.next()) {
        switch (args.get_key()) {
            case ARG_HELP:
                args.print_help();
                return false;

            case ARG_PORT:
                net_port = args.get_argument();
                break;

            case ARG_SERVER:
                net_server = true;
                break;

            case ARG_CLIENT:
                net_connect = args.get_argument();
                break;

            case ARG_GRAPHICS:
                graphics_enabled = true;
                break;

            case ARG_FULLSCREEN:
                graphics.fullscreen = true;
                
                // choose best resolution unless explicitly set
                if (resolution_default) {
                    const CL_DisplayMode best_mode = Graphics::getBestMode();
                    const CL_Size best_resolution = best_mode.get_resolution();

                    graphics.resolution = PixelCoordinate(best_resolution.width, best_resolution.height);
                }

                break;

            case ARG_RESOLUTION:
                graphics.resolution = parse_arg_dimensions(args.get_argument(), "--resolution");
                resolution_default = false;
                break;

            case ARG_LIST_MODES:
                dump_display_modes();
                return false;

            case ARG_VERSION:
                dump_version();
                return false;

            case ARG_TERRAIN_SEED:
                terrain.random_seed = parse_arg_int(args.get_argument(), "--terrain-seed");
                break;

            case ARG_TERRAIN_SIZE:
                terrain.dimensions = parse_arg_dimensions(args.get_argument(), "--terrain-size");
                break;

            case CL_CommandLine::REST_ARG:
                throw ArgumentError("Trailing arguments: " + args.get_argument());

            default:
                throw ArgumentError(std::string() + "Unknown argument key: " + (char) args.get_key());

        }
    }

    // check for invalid combinations of arugments
    if (net_server and !net_connect.empty())
        throw ArgumentError("cannot be both server and client");

    // enable graphics by default unless server
    if (!net_server)
        graphics_enabled = true;
    
    // continue
    return true;
}
        
int Main::parse_arg_int (const std::string &arg_val, const char *arg_name) {
    int int_val;
    
    // read using istringstream
    std::istringstream ss(arg_val);
    
    if (!(ss >> int_val))
        throw ArgumentError(std::string() + "invalid integer arugment for " + arg_name + ": " + arg_val);

    return int_val;
}

PixelCoordinate Main::parse_arg_dimensions (const std::string &arg_val, const char *arg_name) {
    unsigned int w, h;
    
    // sccanf as unsigned
    if (sscanf(arg_val.c_str(), "%ux%u", &w, &h) != 2)
        throw ArgumentError(std::string() + "invalid format for " + arg_name + ": " + arg_val);
    
    return PixelCoordinate(w, h);
}
        
void Main::dump_display_modes (void) {
    const std::vector<CL_DisplayMode> &modes = Graphics::getDisplayModes();
    
    std::cout << "Available display modes:" << std::endl;

    for (std::vector<CL_DisplayMode>::const_iterator it = modes.begin(); it != modes.end(); it++)
        std::cout << "\t" << it->get_resolution().width << "x" << it->get_resolution().height << std::endl;
}
        
void Main::dump_version (void) {
    std::cout << PROJECT_LONG_NAME << " version " << PROJECT_VERSION << " built " << PROJECT_BUILD_TIMESTAMP << std::endl;
}

/**
 * IT BEGAN IN AFRIKA
 */
int Main::main (int argc, char **argv) {
    // initialize the ClanLib components that we use
    CL_SetupCore setup_core;
    CL_SetupNetwork setup_network;
    CL_SetupDisplay setup_disp;
    CL_SetupGL setup_gl;

    try {
        // parse arugments, exit if false
        if (parse_args(argc, argv) == false)
            return 0;

        // our engine
        Engine engine;

        // setup game unless client
        if (net_connect.empty())
            engine.setupGame(terrain);
        
        // setup graphics
        if (graphics_enabled)
            engine.setupGraphics(graphics);

        // setup either network server, client or singleplayer
        if (net_server) {
            engine.setupNetworkServer(net_port);

        } else if (!net_connect.empty()) {
            engine.setupNetworkClient(net_connect, net_port);
        
        } else {
            engine.setupSinglePlayer();
        }

        // run the main loop
        engine.run();
        
        // succesful return
        return 0;
    
    } catch (ArgumentError &e) {
        std::cerr << e.what() << std::endl;
        args.print_help();

        // XXX: handle --help
        return 1;
    } catch (CL_Error &e) {
        std::cerr << "main: CL_Error:" << e.message << std::endl;

        return 1;

    } catch (std::exception &e) {
        std::cerr << "FATAL [uncaught_exception] " << e.what() << std::endl;

        return 1;
    }
}