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?\!
--- 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);
--- /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 */
--- 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 <cassert>
/*
@@ -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
}
--- 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:
/**
--- /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<NetworkTarget*>(*it);
+
+ // exclude?
+ if (target == exclude)
+ continue;
+
+ // recurse
+ target->send_pkt(pkt, reliable);
+ }
+}
--- /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 <list>
+
+// 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<NetworkNode*>::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
--- /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);
+}
--- /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 */
--- 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;
--- 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).
*
--- 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 << "<NetworkObject #" << obj.obj_id << ">";
}
@@ -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);
-}
-
--- 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
--- 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_<object type>_<action>'
*/
-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
*
--- 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 <cassert>
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<NetworkServerPlayer*>::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<Projectile*>::iterator it = server.state.projectiles.begin(); it != server.state.projectiles.end(); it++) {
+ NetworkServerProjectile *proj = dynamic_cast<NetworkServerProjectile*>(*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<NetworkServerPlayer*>(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<NetworkServerPlayer*>(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);
--- 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
--- 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<NetworkAddress, NetworkNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) {
- if (it->second == node)
- continue;
- it->second->send(channel_id, pkt, reliable);
- }
-}
--- 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<NetworkAddress, NetworkNode*> nodes;
+ std::map<NetworkAddress, NetworkNode*> node_map;
+
+ /**
+ * A plain list of connected NetworkNode's
+ */
+ std::list<NetworkNode*> 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
--- 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);
--- /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 <cassert>
+
+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);
+}
+
--- /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 */