# HG changeset patch # User Tero Marttila # Date 1233003827 -7200 # Node ID c6d7272a164b20306be32d8bfd0c37aaf4e09dc2 # Parent 74e562e16399018058e8a78fba1631c5b7125998 rework Network send() code to use NetworkTarget/Node/Group::send classes, add a NetworkMessage class for sending NetworkObject messages, and fix a bug whereby the server's client TCP sockets weren't nonblocking.... I wonder how this has worked before?\! diff -r 74e562e16399 -r c6d7272a164b src/Engine.cc --- a/src/Engine.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Engine.cc Mon Jan 26 23:03:47 2009 +0200 @@ -144,7 +144,7 @@ GameState& Engine::onNetworkClientConnected (Terrain *terrain) { // sanity-check - assert(!terrain && !game_state && graphics); + assert(!this->terrain && !game_state && graphics); // setup the game setupGame(terrain); diff -r 74e562e16399 -r c6d7272a164b src/Network/Channel.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Channel.hh Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,15 @@ +#ifndef NETWORK_CHANNEL_HH +#define NETWORK_CHANNEL_HH + +#include "../Types.hh" + +/** + * A NetworkSession puts each packet onto a specific channel, which can the be used to run multiple different modules + * on top of a single session. + * + * NetworkChannelID zero is reserved for internal NetworkSession use + */ +typedef uint16_t NetworkChannelID; + + +#endif /* NETWORK_CHANNEL_HH */ diff -r 74e562e16399 -r c6d7272a164b src/Network/Client.cc --- a/src/Network/Client.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Client.cc Mon Jan 26 23:03:47 2009 +0200 @@ -5,6 +5,9 @@ #include "../Engine.hh" #include "../Logger.hh" +// XXX: move +#include "Message.hh" + #include /* @@ -66,13 +69,13 @@ Engine::log(INFO, "net.client") << "Got game data, creating player"; // create our new NetworkClient object - client = new NetworkClient(engine, gs, netsession, server); + client = new NetworkClient(engine, gs, netsession, *server); } /* * NetworkClient */ -NetworkClient::NetworkClient (Engine &engine, GameState &state, NetworkSession &netsession, NetworkNode *server) : +NetworkClient::NetworkClient (Engine &engine, GameState &state, NetworkSession &netsession, NetworkNode &server) : engine(engine), state(state), netsession(netsession), server(server), controller(*this) { @@ -108,9 +111,10 @@ case NETMSG_PLAYER_JOIN: on_player_join(obj_id, pkt); break; - + + case NETMSG_PROJECTILE_INFO: case NETMSG_PROJECTILE_PLAYER_FIRED: - on_projectile_player_fired(obj_id, pkt); + on_projectile_create(obj_id, pkt); break; default: @@ -155,7 +159,7 @@ Engine::log(INFO, "net.client") << "Player joined: " << player; } -void NetworkClientController::on_projectile_player_fired (NetworkObjectID obj_id, NetworkPacketInput &pkt) { +void NetworkClientController::on_projectile_create (NetworkObjectID obj_id, NetworkPacketInput &pkt) { // read the packet NetworkObject *player_obj = client.controller.read_object(pkt); Vector position = pkt.read_vector(); @@ -337,14 +341,14 @@ } void NetworkClientLocalPlayer::handleInput (PlayerInput input, TimeMS dt) { - NetworkPacket pkt; + NetworkMessage msg (*this, NETMSG_CLIENT_INPUT); // write packet - pkt.write_uint16(input); - pkt.write_uint32(dt); + msg.write_uint16(input); + msg.write_uint32(dt); - // send - send(NETMSG_CLIENT_INPUT, pkt, false); + // send to server + client.server.send_raw(msg); // do not handle locally } diff -r 74e562e16399 -r c6d7272a164b src/Network/Client.hh --- a/src/Network/Client.hh Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Client.hh Mon Jan 26 23:03:47 2009 +0200 @@ -60,9 +60,9 @@ void on_player_join (NetworkObjectID obj_id, NetworkPacketInput &pkt); /** - * Handle NETMSG_PROJECTILE_PLAYER_FIRED -> NetworkClientProjectile + * Handle NETMSG_PROJECTILE_{INFO/PLAYER_FIRED} -> NetworkClientProjectile */ - void on_projectile_player_fired (NetworkObjectID obj_id, NetworkPacketInput &pkt); + void on_projectile_create (NetworkObjectID obj_id, NetworkPacketInput &pkt); }; /** @@ -95,7 +95,7 @@ /** * The server NetworkNode from Netsession::connect */ - NetworkNode *server; + NetworkNode &server; /** * Our specialized NetworkObject_ClientController @@ -112,7 +112,7 @@ * @param state the GameState to use * @param connect_to the address to connect to */ - NetworkClient (Engine &engine, GameState &state, NetworkSession &netsession, NetworkNode *server); + NetworkClient (Engine &engine, GameState &state, NetworkSession &netsession, NetworkNode &server); public: /** diff -r 74e562e16399 -r c6d7272a164b src/Network/Group.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Group.cc Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,18 @@ + +#include "Group.hh" +#include "Node.hh" + +void NetworkGroup::send_pkt (const NetworkPacketBuffer &pkt, bool reliable) { + // iterate + recurse send_pkt + for (iterator_type it = targets_begin; it != targets_end; it++) { + // handle as NetworkTarget + NetworkTarget *target = static_cast(*it); + + // exclude? + if (target == exclude) + continue; + + // recurse + target->send_pkt(pkt, reliable); + } +} diff -r 74e562e16399 -r c6d7272a164b src/Network/Group.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Group.hh Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,46 @@ +#ifndef NETWORK_GROUP_HH +#define NETWORK_GROUP_HH + +#include "Target.hh" + +#include + +// XXX: ugly forward-declare hack +class NetworkNode; + +/** + * Implements group-multicast for groups of NetworkTargets, by having each target copy + send the packet + */ +class NetworkGroup : public NetworkTarget { + protected: + // XXX: only support NetworkNodes for now... + typedef std::list::iterator iterator_type; + + /** List of targets to send to */ + iterator_type targets_begin, targets_end; + + /** Special-case for single target to exclude */ + NetworkNode *exclude; + + public: + /** + * Construct a NetworkGroup with the given targets. + * + * This does not copy the iterated list contents - the list must remain valid for the lifetime of this object. + * + * @param targets the list of targets to send to + */ + NetworkGroup (iterator_type targets_begin, iterator_type targets_end, NetworkNode *except = NULL) : + targets_begin(targets_begin), targets_end(targets_end), exclude(except) + { + + } + + protected: + /** + * Implement NetworkTarget + */ + virtual void send_pkt (const NetworkPacketBuffer &pkt, bool reliable = true); +}; + +#endif diff -r 74e562e16399 -r c6d7272a164b src/Network/Message.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Message.cc Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,11 @@ + +#include "Message.hh" + +NetworkMessage::NetworkMessage (NetworkObject &obj, NetworkMessageID msg_id) { + // write the netsession channel ID header + obj.controller.session.write_packet_header(*this, obj.controller.channel_id); + + // write the NetworkObject header + write_uint32(obj.obj_id); + write_uint16(msg_id); +} diff -r 74e562e16399 -r c6d7272a164b src/Network/Message.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Message.hh Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,24 @@ +#ifndef NETWORK_MESSAGE_HH +#define NETWORK_MESSAGE_HH + +/** + * @file + * + * NetworkPacket for use with NetworkObjects + */ + +#include "Packet.hh" +#include "Object.hh" + +/** + * NetworkMessages are NetworkPackets that are related to some specfic NetworkObject and its NetworkObjectController. + */ +class NetworkMessage : public NetworkPacket { + public: + /** + * Create a message of the given type to be sent on the given object + */ + NetworkMessage (NetworkObject &obj, NetworkMessageID msg_id); +}; + +#endif /* NETWORK_MESSAGE_HH */ diff -r 74e562e16399 -r c6d7272a164b src/Network/Node.cc --- a/src/Network/Node.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Node.cc Mon Jan 26 23:03:47 2009 +0200 @@ -27,11 +27,7 @@ // delete this; } -void NetworkNode::write_packet_header (NetworkPacketOutput &pkt, NetworkChannelID channel_id) { - pkt.write_uint16(channel_id); -} - -void NetworkNode::send_raw (const NetworkPacketBuffer &pkt, bool reliable) { +void NetworkNode::send_pkt (const NetworkPacketBuffer &pkt, bool reliable) { // either tcp or udp if (reliable) { assert(tcp); @@ -43,19 +39,6 @@ } } - -void NetworkNode::send (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable) { - assert(channel_id > 0); - - // add our header - NetworkPacket pkt2; - - write_packet_header(pkt2, channel_id); - pkt2.write_packet(pkt); - - // send - send_raw(pkt2, reliable); -} const NetworkAddress& NetworkNode::getRemoteAddress (void) { return address; diff -r 74e562e16399 -r c6d7272a164b src/Network/Node.hh --- a/src/Network/Node.hh Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Node.hh Mon Jan 26 23:03:47 2009 +0200 @@ -23,13 +23,16 @@ #include "TCP.hh" #include "UDP.hh" #include "Session.hh" +#include "Target.hh" /** * A NetworkNode represents a remote NetworkSession connected to our NetworkSession. * * A NetworkNode has a tcp connection, plus an udp socket to us (either NetworkSession's udp_srv or udp_client) + * + * NetworkNode implements the NetworkTarget interface, so you can use send() */ -class NetworkNode { +class NetworkNode : public NetworkTarget { private: /** * Our local NetworkSession @@ -82,41 +85,13 @@ */ CL_Signal_v0 _sig_disconnected; - public: - /** - * Write to appropriate NetworkSession header to the given packet. Can be used to prepare packets for use with - * send_raw. The size of the header is equal to NETWORK_SESSION_HEADER_SIZE - * - * @param pkt the packet to write the header to - * @param channel_id the NetworkChannelID to use - * - * @see send_raw - * @see NETWORK_SESSION_HEADER_SIZE - */ - void write_packet_header (NetworkPacketOutput &pkt, NetworkChannelID channel_id); - + protected: /** - * Send a raw packet prepared using write_packet_header. This does not need to copy the packet data around. - * - * @param pkt the NetworkPacket prepared using write_packet_header - * @param reliable Whether to use TCP or UDP - * - * @see write_packet_header + * Send the given packet to this node, used by NetworkTarget */ - void send_raw (const NetworkPacketBuffer &pkt, bool reliable = true); - - /** - * Send the given packet to this node on the given channel. - * - * Note that this constructs a new *NetworkPacket* containing our header and the given packet, so there - * given packet must be small enough to fit. - * - * @param channel_id the NetworkChannelID to use - * @param pkt the NetworkPacket to send on the given channel - * @param reliable Whether to use TCP or UDP - */ - void send (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable = true); + virtual void send_pkt (const NetworkPacketBuffer &pkt, bool reliable = true); + public: /** * Get this node's remote address (both TCP and UDP). * diff -r 74e562e16399 -r c6d7272a164b src/Network/Object.cc --- a/src/Network/Object.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Object.cc Mon Jan 26 23:03:47 2009 +0200 @@ -67,15 +67,16 @@ /* * NetworkObject_ClientController * */ -NetworkObject_ClientController::NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode *server) : - NetworkObjectController(session, channel_id), server(server) { +NetworkObject_ClientController::NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode &server) : + NetworkObjectController(session, channel_id), server(server) +{ } void NetworkObject_ClientController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node) { // we only communicate with the server - if (node != server) + if (node != &server) assert(false); // create new object @@ -101,12 +102,6 @@ controller.objects.erase(obj_id); } -void NetworkObject::buildPacket (NetworkPacketOutput &pkt, NetworkMessageID msg_id, const NetworkPacketBuffer &payload) { - pkt.write_uint32(obj_id); - pkt.write_uint16(msg_id); - pkt.write_packet(payload); -} - std::ostream& operator<< (std::ostream &s, const NetworkObject &obj) { return s << ""; } @@ -123,26 +118,6 @@ _map_sig_message[msg_id](node, pkt); } -void NetworkObject_Server::send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable) { - NetworkPacket pkt_out; - - buildPacket(pkt_out, msg_id, pkt); - - dst->send(controller.channel_id, pkt_out, reliable); -} - -void NetworkObject_Server::send_all (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable) { - send_all_except(msg_id, pkt, NULL, reliable); -} - -void NetworkObject_Server::send_all_except (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, NetworkNode *black_sheep, bool reliable) { - NetworkPacket pkt_out; - - buildPacket(pkt_out, msg_id, pkt); - - controller.session.send_all_except(controller.channel_id, pkt_out, black_sheep, reliable); -} - /* * NetworkObject_Client */ @@ -153,17 +128,9 @@ } void NetworkObject_Client::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt) { - if (node != controller.server) - assert(false); + if (node != &controller.server) + throw Error("Reject NetworkObject packet from non-server"); _map_sig_message[msg_id](pkt); } - -void NetworkObject_Client::send (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable) { - NetworkPacket pkt_out; - buildPacket(pkt_out, msg_id, pkt); - - controller.server->send(controller.channel_id, pkt_out, reliable); -} - diff -r 74e562e16399 -r c6d7272a164b src/Network/Object.hh --- a/src/Network/Object.hh Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Object.hh Mon Jan 26 23:03:47 2009 +0200 @@ -38,6 +38,9 @@ friend class NetworkObject; friend class NetworkObject_Server; friend class NetworkObject_Client; + + // XXX: needs to access session and channel_id + friend class NetworkMessage; private: /** @@ -146,7 +149,7 @@ /** * The server node, as returned by NetworkSession::connect */ - NetworkNode *server; + NetworkNode &server; /** * A mapping of NetworkMessageID -> sig_create, used by the default handle_create @@ -160,7 +163,7 @@ * * @see NetworkObjectController */ - NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode *server); + NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode &server); protected: /** @@ -190,6 +193,9 @@ friend class NetworkObjectController; friend std::ostream& operator<< (std::ostream &s, const NetworkObject &obj); + // XXX: needs to access controller and obj_id + friend class NetworkMessage; + protected: /** * Generic controller @@ -223,15 +229,6 @@ * @param pkt the packet itself, with the headers read */ virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt) = 0; - - /** - * Prepare an outgoing packet, writing the header and the payload - * - * @param pkt the packet to prepare - * @param msg_id the packet's message id - * @param payload the packet's payload - */ - void buildPacket (NetworkPacketOutput &pkt, NetworkMessageID msg_id, const NetworkPacketBuffer &payload); }; /** @@ -272,35 +269,6 @@ public: /** - * Send a message on this object to the given node - * - * @param dst the NetworkNode to send the message to - * @param msg_id the type of message to send - * @param pkt the packet payload - * @param reliable Whether to use TCP or UDP - */ - void send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable = true); - - /** - * Send a message on this object to all nodes on our controller's NetworkSession - * - * @param msg_id the type of message to send - * @param pkt the packet payload - * @param reliable Whether to use TCP or UDP - */ - void send_all (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable = true); - - /** - * Send a message on this object to all nodes on our controller's NetworkSession, except the given node - * - * @param msg_id the type of message to send - * @param pkt the packet payload - * @param black_sheep the node to *NOT* send the message to - * @param reliable Whether to use TCP or UDP - */ - void send_all_except (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, NetworkNode *black_sheep, bool reliable = true); - - /** * Triggered whenever we receive a message of the given type on this object, giving the node that sent it and the * packet itself * @@ -343,15 +311,6 @@ public: /** - * Send a message on this object to the server - * - * @param msg_id the type of message to send - * @param pkt the packet payload - * @param reliable Whether to use TCP or UDP - */ - void send (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable = true); - - /** * Triggered whenever we receive a message of the given type on this object from the server. * * @param msg_id the NetworkMessageID to handle diff -r 74e562e16399 -r c6d7272a164b src/Network/Protocol.hh --- a/src/Network/Protocol.hh Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Protocol.hh Mon Jan 26 23:03:47 2009 +0200 @@ -47,9 +47,10 @@ * * Message names are of the form 'NETMSG__' */ -enum NetworkMessage { +enum NetworkMessageID_ { NETMSG_PACKET_INVALID = 0x0000, +// Server -> Client: Handshake /* * You have joined the game: * @@ -57,6 +58,7 @@ */ NETMSG_SERVER_HELLO = 0x0100, +// Server -> Client: Player state /* * New client has connected to server: * @@ -70,6 +72,7 @@ */ NETMSG_PLAYER_QUIT = 0x0102, +// Client -> Server: Player /* * Client has input to process * @@ -78,6 +81,7 @@ */ NETMSG_CLIENT_INPUT = 0x0201, +// Server -> Client: Player /* * Initial player info * @@ -153,7 +157,15 @@ * float length */ NETMSG_PLAYER_ROPE_LENGTH = 0x0334, - + +// Server -> Client: Projectiles + /** + * Projectile object sync + * + * @see NETMSG_PROJECTILE_PLAYER_FIRED + */ + NETMSG_PROJECTILE_INFO = 0x0410, + /* * Player has fired a weapon, creating this projectile * diff -r 74e562e16399 -r c6d7272a164b src/Network/Server.cc --- a/src/Network/Server.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Server.cc Mon Jan 26 23:03:47 2009 +0200 @@ -5,6 +5,9 @@ #include "../Engine.hh" #include "../Logger.hh" +// XXX: move +#include "Message.hh" + #include NetworkServer::NetworkServer (GameState &state, const NetworkEndpoint &listen_addr) : @@ -23,16 +26,16 @@ Engine::log(INFO, "net.server") << "Client connected, sending terrain data: " << node->getRemoteAddress(); // send the terrain data - send_terrain_data(node); + send_terrain_data(*node); // create the player object (it logs it) - NetworkServerPlayer *player = new NetworkServerPlayer(*this, node); + NetworkServerPlayer *player = new NetworkServerPlayer(*this, *node); // add to players players.push_back(player); } -void NetworkServer::send_terrain_data (NetworkNode *node) { +void NetworkServer::send_terrain_data (NetworkNode &node) { Terrain &terrain = state.world.terrain; // dimensions? @@ -57,7 +60,7 @@ ); // write netsession header - node->write_packet_header(pkt, NETCHAN_TERRAIN_ARRAY); + netsession.write_packet_header(pkt, NETCHAN_TERRAIN_ARRAY); // write terrain dimensions pkt.write_uint32(map.x); @@ -67,7 +70,7 @@ pkt.write_compressed(terrain_buf, terrain_size); // send - node->send_raw(pkt, true); + node.send_raw(pkt, true); } @@ -88,53 +91,64 @@ /* * NetworkServerPlayer */ -NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, NetworkNode *node) : +NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, NetworkNode &node) : Player(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), NetworkServerObject(server), node(node) { // messages - slots.connect(node->sig_disconnected(), this, &NetworkServerPlayer::on_disconnected); + slots.connect(node.sig_disconnected(), this, &NetworkServerPlayer::on_disconnected); slots.connect(this->sig_message(NETMSG_CLIENT_INPUT), this, &NetworkServerPlayer::on_input); // the initial NETMSG_PLAYER_HELLO - NetworkPacket hello_pkt; - hello_pkt.write_vector(getPosition()); + NetworkMessage hello_msg(*this, NETMSG_SERVER_HELLO); + hello_msg.write_vector(getPosition()); + node.send_raw(hello_msg); - this->send_to(node, NETMSG_SERVER_HELLO, hello_pkt, true); - - // send other player objects + // sync other players for (std::list::iterator it = server.players.begin(); it != server.players.end(); it++) { - NetworkPacket player_pkt; + NetworkMessage player_msg(*this, NETMSG_PLAYER_INFO); NetworkServerPlayer *player = *it; // player is not in players list yet assert(player != this); // write packet - player_pkt.write_vector(player->getPosition()); - - player->send_to(node, NETMSG_PLAYER_INFO, player_pkt, true); + player_msg.write_vector(player->getPosition()); + + // send message to client + node.send_raw(player_msg); // XXX: send rope info... } - // XXX: send projectiles? Or let the client handle the events that the unknown projectiles generate? + // sync projectiles + for (std::list::iterator it = server.state.projectiles.begin(); it != server.state.projectiles.end(); it++) { + NetworkServerProjectile *proj = dynamic_cast(*it); + + // all projectiles should be under the control of the server + assert(proj); + + // XXX: send info + } // broadcast NETMSG_PLAYER_JOIN to all clients except current - this->send_all_except(NETMSG_PLAYER_JOIN, hello_pkt, node, true); - - Engine::log(INFO, "net.server") << "Player joined: " << this << " from " << node->getRemoteAddress(); -} + NetworkMessage join_msg(*this, NETMSG_PLAYER_JOIN); + join_msg.write_vector(getPosition()); + server.netsession.all_nodes_except(node).send_raw(join_msg); + Engine::log(INFO, "net.server") << "Player joined: " << this << " from " << node.getRemoteAddress(); +} + void NetworkServerPlayer::handleDig (Vector position, float radius) { - NetworkPacket pkt; - - pkt.write_vector(position); - pkt.write_float32(radius); + NetworkMessage msg(*this, NETMSG_PLAYER_DIG); Engine::log(DEBUG, "server_player.handle_dig") << "position=" << position << ", radius=" << radius; + + // write packet + msg.write_vector(position); + msg.write_float32(radius); - // tell everyone... make this reliable... - this->send_all(NETMSG_PLAYER_DIG, pkt, true); + // broadcast packet + server.netsession.all_nodes().send_raw(msg); // and carry out the actual dig on the server as well Player::handleDig(position, radius); @@ -151,94 +165,100 @@ } void NetworkServerPlayer::handleChangeWeapon (unsigned int weaponIndex) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PLAYER_WEAPON_CHANGE); Engine::log(DEBUG, "server_player.change_weapon") << "weaponIndex=" << weaponIndex; // write packet - pkt.write_uint8(weaponIndex); + msg.write_uint8(weaponIndex); // XXX: only tell the client itself? - send_all(NETMSG_PLAYER_WEAPON_CHANGE, pkt, true); + server.netsession.all_nodes().send_raw(msg); // pass through Player::handleChangeWeapon(weaponIndex); } void NetworkServerPlayer::handleRopeState (RopeState state) { - NetworkPacket pkt; - Engine::log(DEBUG, "server_player.rope_state") << "state=" << rope.getState() << ", position=" << rope.getPosition() << ", velocity=" << rope.getVelocity() << ", length=" << rope.getLength() << ", pivotPlayer=" << rope.getPivotPlayer(); switch (state) { - case ROPE_FLYING: - pkt.write_vector(rope.getPosition()); - pkt.write_vector(rope.getVelocity()); - pkt.write_float32(rope.getLength()); + case ROPE_FLYING: { + NetworkMessage msg(*this, NETMSG_PLAYER_ROPE_THROW); - send_all(NETMSG_PLAYER_ROPE_THROW, pkt, true); + msg.write_vector(rope.getPosition()); + msg.write_vector(rope.getVelocity()); + msg.write_float32(rope.getLength()); - break; + server.netsession.all_nodes().send_raw(msg); + + } break; case ROPE_FIXED: { + NetworkMessage msg(*this, NETMSG_PLAYER_ROPE_FIXED); + Player *player_base = rope.getPivotPlayer(); NetworkServerPlayer *player = NULL; if (player_base != NULL && (player = dynamic_cast(player_base)) == NULL) throw Error("NetworkServerPlayer::handleRopeState: rope's pivotPlayer is not a NetworkServerPlayer"); - pkt.write_vector(rope.getPosition()); - pkt.write_float32(rope.getLength()); - controller.write_object(pkt, player); // may be NULL + msg.write_vector(rope.getPosition()); + msg.write_float32(rope.getLength()); + controller.write_object(msg, player); // may be NULL - send_all(NETMSG_PLAYER_ROPE_FIXED, pkt, true); + server.netsession.all_nodes().send_raw(msg); - } break; + } break; - case ROPE_FOLDED: - send_all(NETMSG_PLAYER_ROPE_RELEASED, pkt, true); + case ROPE_FOLDED: { + NetworkMessage msg(*this, NETMSG_PLAYER_ROPE_RELEASED); - break; + server.netsession.all_nodes().send_raw(msg); + + } break; } } void NetworkServerPlayer::handleRopeLength (float length) { - NetworkPacket pkt; - - pkt.write_float32(length); - - send_all(NETMSG_PLAYER_ROPE_LENGTH, pkt, true); + NetworkMessage msg(*this, NETMSG_PLAYER_ROPE_LENGTH); + + // write packet + msg.write_float32(length); + + // send packet + server.netsession.all_nodes().send_raw(msg); } void NetworkServerPlayer::spawn (Vector position) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PLAYER_SPAWN); // write packet - pkt.write_vector(position); + msg.write_vector(position); Engine::log(DEBUG, "server_player.spawn") << this << ": position=" << position; - // send - send_all(NETMSG_PLAYER_SPAWN, pkt, true); + // send packet + server.netsession.all_nodes().send_raw(msg); // super Player::spawn(position); } void NetworkServerPlayer::die (bool start_timer) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PLAYER_DIE); Engine::log(DEBUG, "server_player.die") << this; - // send - send_all(NETMSG_PLAYER_DIE, pkt, true); + // send packet + server.netsession.all_nodes().send_raw(msg); // super Player::die(start_timer); } void NetworkServerPlayer::on_disconnected (void) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PLAYER_QUIT); Engine::log(INFO, "net.server") << "Player disconnected: " << this; @@ -246,16 +266,16 @@ server.handle_disconnect(this); // tell other clients - send_all(NETMSG_PLAYER_QUIT, pkt, true); + server.netsession.all_nodes().send_raw(msg); - // free + // XXX: free // delete this; } void NetworkServerPlayer::on_input (NetworkNode *src, NetworkPacketInput &pkt) { // sanity-check, other players shouldn't move - if (src != node) { - Engine::log(WARN, "server_player.on_input") << "packet from wrong src=" << src << ", node=" << node; + if (src != &node) { + Engine::log(WARN, "server_player.on_input") << "packet from wrong src=" << src << ", node=" << &node; return; } @@ -273,20 +293,20 @@ } void NetworkServerPlayer::send_position_update (void) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PLAYER_POSITION); int flags = (inAir ? NETWORK_PHYSICS_INAIR : 0) | (facing == FACING_RIGHT ? NETWORK_PHYSICS_FACE_RIGHT : 0); - pkt.write_vector(getPosition()); - pkt.write_vector(getVelocity()); - pkt.write_uint8(flags); - pkt.write_float32(aim); + msg.write_vector(getPosition()); + msg.write_vector(getVelocity()); + msg.write_uint8(flags); + msg.write_float32(aim); // Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position << "+" << velocity << " [" << flags << "]"; - send_all(NETMSG_PLAYER_POSITION, pkt, false); + server.netsession.all_nodes().send_raw(msg); } /* @@ -296,25 +316,29 @@ Vector velocity, Weapon *weapon) : Projectile(player, position, velocity, weapon, true), NetworkServerObject(server) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PROJECTILE_PLAYER_FIRED); + + // write out packet + server.controller.write_object(msg, player); + msg.write_vector(getPosition()); + msg.write_vector(getVelocity()); + msg.write_uint8(weapon->getID()); - server.controller.write_object(pkt, player); - pkt.write_vector(position); - pkt.write_vector(velocity); - pkt.write_uint8(weapon->getID()); - - send_all(NETMSG_PROJECTILE_PLAYER_FIRED, pkt, true); + // send to given target + server.netsession.all_nodes().send_raw(msg); } void NetworkServerProjectile::onDestroy (Vector position, bool removeGround) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PROJECTILE_DESTROY); Engine::log(DEBUG, "server_projectile.destroy") << this << "position=" << position << ", removeGround=" << removeGround; - pkt.write_vector(position); - pkt.write_uint8(removeGround ? NETWORK_PROJECTILE_REMOVE_GROUND : 0); - - send_all(NETMSG_PROJECTILE_DESTROY, pkt, true); + // write packet + msg.write_vector(position); + msg.write_uint8(removeGround ? NETWORK_PROJECTILE_REMOVE_GROUND : 0); + + // broadcast packet + server.netsession.all_nodes().send_raw(msg); // XXX: leak obj, not yet implemented: obj.destory(); @@ -323,7 +347,7 @@ } void NetworkServerProjectile::onHitPlayer (Player *player_ptr) { - NetworkPacket pkt; + NetworkMessage msg(*this, NETMSG_PROJECTILE_HIT_PLAYER); NetworkServerPlayer *player = dynamic_cast(player_ptr); if (player == NULL) @@ -332,10 +356,10 @@ Engine::log(DEBUG, "server_projectile.hit_player") << this << ": player=" << player; // write packet - controller.write_object(pkt, player); + controller.write_object(msg, player); - // send - send_all(NETMSG_PROJECTILE_HIT_PLAYER, pkt, true); + // send packet + server.netsession.all_nodes().send_raw(msg); // super Projectile::onHitPlayer(player_ptr); diff -r 74e562e16399 -r c6d7272a164b src/Network/Server.hh --- a/src/Network/Server.hh Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Server.hh Mon Jan 26 23:03:47 2009 +0200 @@ -72,7 +72,7 @@ * Called from on_node_connected to send the initial Terrain data using the NETCHAN_TERRAIN_ARRAY channel to * the given node. */ - void send_terrain_data (NetworkNode *node); + void send_terrain_data (NetworkNode &node); }; /** @@ -101,7 +101,7 @@ /** * The remote node that represents this actual player */ - NetworkNode *node; + NetworkNode &node; public: /** @@ -113,7 +113,7 @@ * * @see NetworkServerObject */ - NetworkServerPlayer (NetworkServer &server, NetworkNode *node); + NetworkServerPlayer (NetworkServer &server, NetworkNode &node); protected: // @{ @@ -167,7 +167,7 @@ * @param weapon the Player's Weapon that was fired */ NetworkServerProjectile (NetworkServer &server, NetworkServerPlayer *player, Vector position, Vector velocity, Weapon *weapon); - + protected: /** * Overriden from Projectile to send a NETMSG_PROJECTILE_DESTROY with the given position and flags diff -r 74e562e16399 -r c6d7272a164b src/Network/Session.cc --- a/src/Network/Session.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Session.cc Mon Jan 26 23:03:47 2009 +0200 @@ -47,7 +47,8 @@ NetworkNode *client_node = build_node(tcp_client, udp_client, remote_address, NETWORK_NODE_CLIENT_SERVER); // add to nodes - nodes[remote_address] = client_node; + node_map[remote_address] = client_node; + node_list.push_back(client_node); // connect signals slots.connect(udp_client->sig_packet(), this, &NetworkSession::on_udp_packet); @@ -58,7 +59,8 @@ void NetworkSession::handle_disconnect (NetworkNode *node) { // remove from nodes - nodes.erase(node->getRemoteAddress()); + node_map.erase(node->getRemoteAddress()); + node_list.remove(node); } void NetworkSession::handle_message (NetworkPacketInput &pkt, NetworkNode *node) { @@ -77,14 +79,15 @@ NetworkNode *client_node = build_node(tcp_client, udp_srv, addr, NETWORK_NODE_SERVER_CLIENT); // add to nodes - nodes[addr] = client_node; + node_map[addr] = client_node; + node_list.push_back(client_node); // fire signals _sig_node_connected(client_node); } void NetworkSession::on_udp_packet (NetworkPacketInput &pkt, const NetworkAddress &addr) { - NetworkNode *node = nodes[addr]; + NetworkNode *node = node_map[addr]; // drop from unknown sources if (!node) { @@ -95,16 +98,8 @@ // handle handle_message(pkt, node); } - -void NetworkSession::send_all (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable) { - send_all_except(channel_id, pkt, NULL, reliable); + +void NetworkSession::write_packet_header (NetworkPacketOutput &pkt, NetworkChannelID channel_id) { + pkt.write_uint16(channel_id); } - -void NetworkSession::send_all_except (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, const NetworkNode *node, bool reliable) { - for (std::map::iterator it = nodes.begin(); it != nodes.end(); it++) { - if (it->second == node) - continue; - it->second->send(channel_id, pkt, reliable); - } -} diff -r 74e562e16399 -r c6d7272a164b src/Network/Session.hh --- a/src/Network/Session.hh Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/Session.hh Mon Jan 26 23:03:47 2009 +0200 @@ -14,14 +14,6 @@ class NetworkSession; /** - * A NetworkSession puts each packet onto a specific channel, which can the be used to run multiple different modules - * on top of a single session. - * - * NetworkChannelID zero is reserved for internal NetworkSession use - */ -typedef uint16_t NetworkChannelID; - -/** * Size of a NetworkSession's packet header: * uint16 channel_id */ @@ -30,6 +22,9 @@ #include "TCP.hh" #include "UDP.hh" #include "Node.hh" +#include "Group.hh" +#include "Packet.hh" +#include "Channel.hh" /** * A NetworkSession provides TCP/UDP Server and Client functionality, representing remote NetworkSessions with @@ -65,7 +60,12 @@ * A map of NetworkAddress -> NetworkNode, manipulated when TCP connections are established/broken down, * and used to map UDP packets to their NetworkNode */ - std::map nodes; + std::map node_map; + + /** + * A plain list of connected NetworkNode's + */ + std::list node_list; /** * A map of NetworkChannelID -> signal, used to signal our users when we receieve packets @@ -146,21 +146,32 @@ public: /** - * Send the given NetworkPacket to all our nodes using the given NetworkChannelID, using TCP if reliable, UDP otherwise. - * - * @param channel_id the NetworkChannelID to use - * @param pkt the NetworkPacket to send - * @param reliable Whether to use TCP or UDP + * Get a NetworkGroup containing all connected nodes */ - void send_all (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable = true); + NetworkGroup all_nodes (void) { + return NetworkGroup(node_list.begin(), node_list.end(), NULL); + } /** - * Like send_all, but do not send the packet to the specified node. If node is NULL, this behaves like - * send_all. + * Get a NetworkGroup containing all connected nodes, but excluding the given one + */ + NetworkGroup all_nodes_except (NetworkNode &node) { + return NetworkGroup(node_list.begin(), node_list.end(), &node); + } + + /** + * Write the appropriate NetworkSession header to the given packet. Can be used to prepare packets for use with + * NetworkTarget::send_raw(). The size of the header is equal to NETWORK_SESSION_HEADER_SIZE * - * @see send_all + * XXX: this interface needs fixing to be less procedural + * + * @param pkt the packet to write the header to + * @param channel_id the NetworkChannelID to use + * + * @see NetworkTarget::send_raw() + * @see NETWORK_SESSION_HEADER_SIZE */ - void send_all_except (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, const NetworkNode *node, bool reliable = true); + void write_packet_header (NetworkPacketOutput &pkt, NetworkChannelID channel_id); /** * A new node has connected to us diff -r 74e562e16399 -r c6d7272a164b src/Network/TCP.cc --- a/src/Network/TCP.cc Mon Jan 26 19:52:52 2009 +0200 +++ b/src/Network/TCP.cc Mon Jan 26 23:03:47 2009 +0200 @@ -120,6 +120,9 @@ // accept a new socket NetworkSocket *client_sock = socket.accept(NULL); + // make it nonblocking + client_sock->set_nonblocking(true); + // create a new NetworkTCPTransport NetworkTCPTransport *client = buildTransport(client_sock); diff -r 74e562e16399 -r c6d7272a164b src/Network/Target.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Target.cc Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,24 @@ + +#include "Target.hh" + +#include + +void NetworkTarget::send_raw (const NetworkPacketBuffer &pkt, bool reliable) { + // currently this is the same as send_pkt + send_pkt(pkt, reliable); +} + +void NetworkTarget::send (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable) { + assert(channel_id > 0); + + // add our header + NetworkPacket pkt2; + + // XXX: not using NetworkSession::write_packet_header + pkt2.write_uint16(channel_id); + pkt2.write_packet(pkt); + + // send + send_pkt(pkt2, reliable); +} + diff -r 74e562e16399 -r c6d7272a164b src/Network/Target.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Network/Target.hh Mon Jan 26 23:03:47 2009 +0200 @@ -0,0 +1,52 @@ +#ifndef NETWORK_TARGET_HH +#define NETWORK_TARGET_HH + +/** + * @file + * + * Abstract NetworkTarget definition + */ + +#include "Channel.hh" +#include "Packet.hh" + +/** + * Abstract interface for sending NetworkPackets to some NetworkSession-related destination, either a single + * NetworkNode or a NetworkGroup of nodes. + */ +class NetworkTarget { + friend class NetworkGroup; + + protected: + /** + * Send the given packet directly + */ + virtual void send_pkt (const NetworkPacketBuffer &pkt, bool reliable = true) = 0; + + public: + /** + * Send a raw packet prepared using write_packet_header. This does not need to copy the packet data around. + * + * XXX: this interface needs fixing to be less procedural + * + * @param pkt the NetworkPacket prepared using write_packet_header + * @param reliable whether to use TCP or UDP + * + * @see write_packet_header + */ + void send_raw (const NetworkPacketBuffer &pkt, bool reliable = true); + + /** + * Send the given packet on the given channel to this destination. + * + * Note that this constructs a new *NetworkPacket* containing our header and the given packet, so there + * given packet must be small enough to fit. + * + * @param channel_id the NetworkChannelID to use + * @param pkt the NetworkPacket to send on the given channel + * @param reliable Whether to use TCP or UDP + */ + void send (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable = true); +}; + +#endif /* NETWORK_TARGET_HH */