/* core/gameconnection.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 "sys/sys.h" #include "filesystem/filesystem.h" #include "core/application.h" #include "core/cvar.h" #include "core/entityprojectile.h" #include "core/gameconnection.h" #include "core/net.h" namespace core { const unsigned long INFOTIMEOUT = 2500; // 2500ms info request timeout GameConnection* GameConnection::connection_instance = 0; GameConnection::GameConnection(std::string const &connectionstr) { connection_instance = this; connection_network = 0; connection_netframe = 0; // clear current guid localplayer()->guid().clear(); // read keys.ini std::string filename(filesystem::homedir()); filename.append("keys.ini"); std::ifstream ifs(filename.c_str()); if (ifs.is_open()) { filesystem::IniStream inistr; while(inistr.getline(ifs)) { if (inistr.in_section("client")) { std::string s; if (inistr.got_key_string("key", s)) { aux::to_lowercase(s); aux::trim(s); localplayer()->guid().assign(s); if (!localplayer()->guid().is_valid()) { con_warn << "keys.ini invalid client key '" << s << "' at line " << inistr.line() << std::endl; } } } } ifs.close(); } // if no valid key was found, generate one if (!localplayer()->guid().is_valid()) { localplayer()->guid().generate(); } // write keys.ini std::ofstream ofs(filename.c_str()); if (!ofs.is_open()) { con_warn << "Could not write " << filename << std::endl; } else { ofs << "; keys.ini" << std::endl; ofs << "; Project::OSiRiON client identification" << std::endl; ofs << "; DO NOT EDIT OR DELETE THIS FILE" << std::endl; ofs << "; If you do, you will not be able to use existing characters in multiplayer games" << std::endl; ofs << std::endl; ofs << "[client]" << std::endl; ofs << "key=" << localplayer()->guid().str() << std::endl; ofs.close(); } con_print << "Using client key " << localplayer()->guid().str() << std::endl; // split hostname into host and port unsigned int port = DEFAULTPORT; std::string host(connectionstr); size_t found = host.find(':'); if (found != std::string::npos) { std::istringstream str(host.substr(found + 1)); if (str >> port) { host.erase(found, std::string::npos); } else { con_print << "Invalid hostname '" << host << "'\n"; abort(); return; } } // initiate the network connection connection_network = new NetConnection(); connection_network->connect(host, port); if (!connection_network->connected()) { abort(); return; } // send connect request connection_network->send_connect(); connection_network->transmit(); if (!connection_network->connected()) { abort(); return; } game_players.push_back(localplayer()); set_playerlist_timestamp(timestamp()); set_interactive(true); set_running(true); } GameConnection::~GameConnection() { if (connection_network) { connection_network->disconnect(); delete connection_network; } connection_instance = 0; } Info *GameConnection::request_info(const unsigned int id) { if (!id) { con_warn << "Information requested for illegal id 0!" << std::endl; return 0; } // find the info record Info *info = Info::find(id); if (!info) { info = new Info(id); } if (info->type() || (timestamp() < info->timestamp() + INFOTIMEOUT) ) return info; // send an information request to the server if (connection_network) { connection_network->send_info_request(info); connection_network->transmit(); } else { info->add_text("^RNot connected."); info->set_timestamp(0); } return info; } Inventory *GameConnection::request_inventory(Entity *entity) { if (!entity) { con_warn << "Inventory request for NULL entity" << std::endl; return 0; } if (entity->inventory() && connection_network) { connection_network->send_inventory_request(entity); connection_network->transmit(); } return (entity->inventory()); } void GameConnection::forward(std::string const &cmdline) { if (!connection_network->connected()) return; connection_network->send_command(cmdline); } void GameConnection::rcon(std::string const &cmdline) { if (!connection_network->connected()) return; connection_network->send_rcon(cmdline); } void GameConnection::say(std::string const &args) { if (!connection_network->connected()) return; connection_network->send_say(args); } void GameConnection::shout(std::string const &args) { if (!connection_network->connected()) return; connection_network->send_shout(args); } void GameConnection::private_message(std::string const &args) { if (!connection_network->connected()) return; connection_network->send_private_message(args); } void GameConnection::frame(unsigned long timestamp) { if (!running()) return; if (!connection_network->connected()) { abort(); return; } // get incoming messages connection_network->frame(); // update client-sde state for (Entity::Registry::iterator it = Entity::registry().begin(); it != Entity::registry().end(); it++) { Entity *entity = (*it).second; if (entity->type() == Entity::Projectile) { EntityProjectile *projectile = static_cast(entity); if (projectile->state() == Entity::Normal) { unsigned long elapsed = application()->timestamp() - projectile->timestamp(); if (elapsed > 0) { projectile->set_location(projectile->location() + projectile->axis().forward() * projectile->speed() * ((float) elapsed / 1000.0f)); projectile->set_timestamp(application()->timestamp()); } } } } float f = 0; if (core::Cvar::net_framerate->value()) { f = 1000.0f / core::Cvar::net_framerate->value(); if (connection_netframe + f > timestamp) { return; } } connection_netframe = timestamp; if (connection_network->state() == NetConnection::Connected) { if (localcontrol() && localcontrol()->dirty()) { connection_network->send_client_update(localcontrol()); localcontrol()->set_dirty(false); } if (localplayer()->dirty()) { connection_network->send_playerinfo(); } } set_timestamp(connection_network->timestamp()); connection_network->transmit(); } }