/* net/netconnection.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 "sys/sys.h" #include "net/net.h" #include "core/application.h" #include "core/gameconnection.h" #include "core/netconnection.h" #include "core/player.h" namespace core { NetConnection::NetConnection() { } NetConnection::~NetConnection() { } void NetConnection::connect(std::string const &to_host, int to_port) { TCPConnection::connect(to_host, to_port); if(connected()) { FD_ZERO(&clientset); FD_SET(fd(), &clientset); } std::ostringstream osstream; osstream << "pif "; game()->localplayer()->serialize_client_update(osstream); osstream << '\n'; send(osstream.str()); } void NetConnection::disconnect() { TCPConnection::disconnect(); FD_ZERO(&clientset); } bool NetConnection::has_messages() const { return (recvq.size() > 0); } void NetConnection::retreive(std::string & message) { if (recvq.size() > 0) { message.assign(recvq.front()); recvq.pop_front(); } else { message.clear(); } } // receive data and decode it into lines void NetConnection::receive() { // TODO: binary mode data transfer std::string datablock; TCPConnection::receive(datablock); if (error()) return; while (datablock.size() > 0) { // scan the datablock for enters if (datablock[0] == '\n' || datablock[0] == '\r') { if (messageblock.size() > 0) { recvq.push_back(messageblock); messageblock.clear(); } } else { if (messageblock.size() < net::FRAMESIZE) { messageblock.append(datablock.substr(0,1)); } else { con_warn << "Network message exceeds " << net::FRAMESIZE << " bytes!" << std::endl; messageblock.clear(); } } datablock.erase(0,1); } datablock.clear(); } void NetConnection::frame(float seconds) { timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; fd_set readset = clientset; int nb = select(fd()+1, &readset, NULL, NULL, &timeout); if (nb == 0) return; if (nb == -1) { con_error << "Network error on select()" << std::endl; //perror("select"); abort(); } if (FD_ISSET(this->fd(), &readset) && !error()) { receive(); while (has_messages()) { std::string message; retreive(message); parse_incoming_message(message); } } } // parse incoming client messages /** * The following incoming messages are parsed; * * msg info * msg public * die * ent * sup * pif */ void NetConnection::parse_incoming_message(const std::string & message) { std::istringstream msgstream(message); std::string command; msgstream >> command; if (command == "msg") { std::string level; if (msgstream >> level) { if (level =="info") { if (message.size() > 9) { con_print << message.substr(9) << std::endl; } } else if (level == "public") { // FIXME - separate sender nickname if (message.size() > 11) { con_print << message.substr(11) << std::endl; } } } } else if (command == "die") { unsigned int id; msgstream >> id; Entity *e = Entity::find(id); con_debug << "Received die entity id " << id << "\n"; if (localcontrol() == e) localplayer()->player_control = 0; if (e) Entity::remove(id); } else if (command == "ent") { unsigned int type; msgstream >> type; con_debug << "Received create entity type " << type << "\n"; switch (type) { case Entity::Default: new Entity(msgstream); break; case Entity::Dynamic: new EntityDynamic(msgstream); break; case Entity::Controlable: new EntityControlable(msgstream); break; default: break; } } else if (command == "sup") { unsigned int id; if (msgstream >> id) { Entity *entity = Entity::find(id); if (!entity) { con_warn << "Update for unknown entity " << id << "\n"; } else entity->recieve_server_update(msgstream); } return; } else if (command == "pif") { connection()->localplayer()->recieve_server_update(msgstream); } } }