/* core/application.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include #include #include #include #include #include "sys/sys.h" #include "math/mathlib.h" #include "filesystem/filesystem.h" #include "core/application.h" #include "core/cvar.h" #include "core/entity.h" #include "core/func.h" #include "core/netserver.h" namespace core { // return the global application object Application *application() { return Application::instance(); } // --------------- engine functions ------------------------------ void func_print(std::string const &args) { con_print << args << "\n"; } void func_help(std::string const &args) { con_print << "This is the help function\n"; } void func_quit(std::string const &args) { application()->shutdown(); application()->quit(0); } void func_connect(std::string const &args) { std::istringstream argstream(args); std::string host; if (!(argstream >> host)) host.clear(); application()->connect(host); } void func_disconnect(std::string const &args) { application()->disconnect(); } // FIXME this is a game function void func_say(std::string const &args) { if (application()->netserver) { std::ostringstream osstream; osstream << "msg public " << Player::local.name() << " " << args << "\n"; application()->netserver->broadcast(osstream.str()); con_print << Player::local.name() << ": " << args << "\n"; } else if (application()->netconnection.connected()) { std::ostringstream osstream; osstream << args << "\n"; application()->netconnection.send(args); } else if (game() && game()->connected) { con_print << args << "\n"; } else con_print << "Not connected."; } void func_name(std::string const &args) { std::istringstream argstream(args); std::string name; if (argstream >> name) { if (name.size() > 16) name = name.substr(0,16); } else { con_print << "name " << Player::local.name() << "\n"; return; } if (name == Player::local.name()) { con_print << "name " << name << "\n"; return; } if (application()->netserver) { std::ostringstream osstream; osstream << "msg info " << Player::local.name() << " renamed to " << name << "\n"; application()->netserver->broadcast(osstream.str()); con_print << "msg info " << Player::local.name() << " renamed to " << name << "\n"; } else if (application()->netconnection.connected()) { std::ostringstream osstream; osstream << "name " << name << "\n"; application()->netconnection.send(osstream.str()); con_print << "name " << name << "\n"; } else { con_print << "name " << name << "\n"; } Player::local.player_name = name; } // --------------- signal_handler ----------------------------------- extern "C" void signal_handler(int signum) { switch (signum) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGTERM: if (Application::instance()) { con_warn << "Received signal " << signum << ", shutting down...\n"; application()->shutdown(); application()->quit(0); } else { std::cerr << "Received signal " << signum << ", terminated...\n"; application()->quit(1); } break; default: std::cerr << "Received signal " << signum << ", terminated...\n"; application()->quit(1); break; } } // --------------- Application ----------------------------- Application *Application::application_instance = 0; Application::Application() { if (application_instance) { std::cerr << "multiple core::Application instances!\n"; sys::quit(2); } application_instance = this; netserver = 0; gameinterface_preload = 0; sys::signal(SIGHUP, signal_handler); sys::signal(SIGINT, signal_handler); sys::signal(SIGQUIT, signal_handler); sys::signal(SIGTERM, signal_handler); } Application::~Application() { application_instance = 0; } Application *Application::instance() { return application_instance; } float Application::time() const { return game_time; } bool Application::connected() const { return (Application::instance()->netconnection.connected() || (GameInterface::instance() && GameInterface::instance()->connected)); } void Application::init() { con_debug << "Debug messages enabled\n"; con_print << "Initializing core...\n"; filesystem::init(); CommandBuffer::init(); gameinterface_preload = core::GameInterface::gameinterface_instance; core::GameInterface::gameinterface_instance = 0; if (gameinterface_preload) { con_print << " preloaded game found: " << gameinterface_preload->name() << "\n"; } game_time = 0; // dedicated server should set this to 1 Cvar::sv_dedicated = Cvar::get("sv_dedicated", "0", Cvar::ReadOnly); // client can set this to 1 Cvar::sv_private = Cvar::get("sv_private", "0"); if (Cvar::sv_dedicated->value()) Player::local.player_name = "Console"; else Player::local.player_name = "Player0"; // network settings Cvar::net_host = Cvar::get("net_host", "0.0.0.0"); Cvar::net_port = Cvar::get("net_port", "8042"); // register our engine functions Func::add("print", func_print); Func::add("help", func_help); Func::add("quit", func_quit); Func::add("connect", func_connect); Func::add("disconnect", func_disconnect); Func::add("say", func_say); Func::add("name", func_name); } void Application::shutdown() { con_print << "Shutting down core...\n"; if (connected()) disconnect(); // remove our engine functions Func::remove("print"); Func::remove("help"); Func::remove("quit"); Func::remove("connect"); Func::remove("disconnect"); Func::remove("say"); Func::remove("name"); CommandBuffer::shutdown(); filesystem::shutdown(); } void Application::quit(int status) { sys::quit(status); } // clear all game realted objects void Application::clear() { // remove all entities for (std::map::iterator it = Entity::registry.begin(); it != Entity::registry.end(); it++) { delete (*it).second; } Entity::registry.clear(); // remove all game functions for (std::map::iterator it = Func::registry.begin(); it != Func::registry.end(); it++) { if ( ((*it).second->flags() & Func::Game) == Func::Game) { delete (*it).second; Func::registry.erase(it); } } // remove all game cvars for (std::map::iterator it = Cvar::registry.begin(); it != Cvar::registry.end(); it++) { if ( ((*it).second->flags() & Cvar::Game) == Cvar::Game) { delete (*it).second; Cvar::registry.erase(it); } } } void Application::connect(std::string const &host) { if (game() && game()->connected || netconnection.connected()) { con_warn << "Connected. Disconnect first.\n"; return; } if (game()) { // unload previous game if (game() != gameinterface_preload) delete core::GameInterface::gameinterface_instance; } clear(); if (host.size()) { // connect to remote core core::GameInterface::gameinterface_instance = 0; std::string remotehost(host); size_t found = remotehost.find(':'); unsigned int port = 8042; if (found != std::string::npos) { std::istringstream str(remotehost.substr(found+1)); if (str >> port) { remotehost.erase(found, std::string::npos); } else { con_print << "Invalid hostname '" << remotehost << "'\n"; return; } } netconnection.connect(remotehost, port); if (netconnection.connected()) { con_print << "Connected.\n"; } else { netconnection.disconnect(); con_warn << "Could not connect to '" << host << "'\n"; } } else { // use preloaded game core::GameInterface::gameinterface_instance = gameinterface_preload; // reset everything game_time = 0; if (game()->connected = game()->init()) { con_print << "Connected.\n"; } else { con_warn << "Could not connect.\n"; return; } if (!netserver && (Cvar::sv_dedicated->value() || Cvar::sv_private->value())) { netserver = new NetServer(Cvar::net_host->str(), (unsigned int)Cvar::net_port->value()); if (!netserver->valid()) { delete netserver; if (Cvar::sv_dedicated->value()) shutdown(); } } } } void Application::disconnect() { if (netserver) { delete netserver; netserver = 0; } if (netconnection.connected()) { netconnection.disconnect(); con_print << "Disconnected.\n"; return; } if (game()) { if (!game()->connected) { con_warn << "Not connected.\n"; return; } game()->shutdown(); game()->connected = false; game_time = 0; clear(); con_print << "Disconnected.\n"; } } void Application::frame(float seconds) { if (seconds == 0.0f) return; // execute commands in the buffer CommandBuffer::exec(); // update entities if (connected()) { std::map::iterator it; for (it=Entity::registry.begin(); it != Entity::registry.end(); it++) { Entity *entity = (*it).second; if ((entity->type() == Entity::Controlable) || (entity->type() == Entity::Dynamic)) { entity->frame(seconds); } } } // netstuff if (netconnection.connected()) { netconnection.frame(seconds); // TODO this should come from server game_time += seconds; } else { if (netserver) { // TODO limit netserver frames in local mode netserver->frame(seconds); } if (game() && game()->connected) { game_time += seconds; game()->frame(seconds); } } } }