add comments, move addPlayer/removePlayer to Player.cc, and refactor Network code to inherit from NetworkObject
authorterom
Mon, 08 Dec 2008 00:16:43 +0000
changeset 274 c35307e8645c
parent 273 eeb699e1d908
child 275 fa44b905bc2e
add comments, move addPlayer/removePlayer to Player.cc, and refactor Network code to inherit from NetworkObject
src/Engine.cc
src/GameState.cc
src/GameState.hh
src/Network/Client.cc
src/Network/Client.hh
src/Network/Server.cc
src/Network/Server.hh
src/Player.cc
src/Player.hh
--- a/src/Engine.cc	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Engine.cc	Mon Dec 08 00:16:43 2008 +0000
@@ -33,7 +33,7 @@
  	LocalPlayer* lp = new SinglePlayer(game_state);
 
     // add to gamestate
-	game_state.newLocalPlayer(lp);
+	game_state.setLocalPlayer(lp);
 }
 
 void Engine::stop (void) {
--- a/src/GameState.cc	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/GameState.cc	Mon Dec 08 00:16:43 2008 +0000
@@ -17,20 +17,21 @@
     return local_player;
 }
 
-void GameState::newLocalPlayer (LocalPlayer *player) {
+void GameState::setLocalPlayer (LocalPlayer *player) {
     if (local_player)
         throw std::logic_error("newLocalPlayer called even though we already have a local player");
     
-    newPlayer(player);
-    
     local_player = player;
 }
     
-void GameState::newPlayer (Player *player) {
+void GameState::addPlayer (Player *player) {
     player_list.push_back(player);
 }
 
 void GameState::removePlayer (Player *player) { 
+    if (player == local_player)
+        local_player = NULL;
+
     player_list.remove(player);
 }
     
--- a/src/GameState.hh	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/GameState.hh	Mon Dec 08 00:16:43 2008 +0000
@@ -21,23 +21,46 @@
     std::list<Projectile*> projectiles;
     PhysicsWorld world;
 
-    // only one local player is supported
+    /**
+     * The one LocalPlayer that *we* control
+     */
     LocalPlayer *local_player;
-
+    
+    /**
+     * ...
+     * 
+     * This should take some arguments
+     */
     GameState (void);
     
+    /**
+     * Adds projectile to our list of projectiles to draw
+     */
     void addProjectile(Projectile *projectile);
 
-    /*
-     * This will return NULL if we don't have a local player - yet
+    /**
+     * Get our current LocalPlayer if we have one, else return NULL (client hasn't connected yet)
      */
     LocalPlayer *getLocalPlayer (void);
+    
+    /**
+     * Check that local_player is NULL, and sets it to the given player
+     */
+    void setLocalPlayer (LocalPlayer *player);        
 
-    void newLocalPlayer (LocalPlayer *player);        
-    void newPlayer (Player *player);
-
+    /**
+     * Add the given player to our player_list
+     */
+    void addPlayer (Player *player);
+    
+    /**
+     * Removes the given player from player_list. If the given player was the local_player, set that to NULL
+     */
     void removePlayer (Player *player);
-
+    
+    /**
+     * Draws the terrain, players and projectiles
+     */
     virtual void draw (Graphics *g, PixelCoordinate camera, bool displayWeapon);
 };
 
--- a/src/Network/Client.cc	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Network/Client.cc	Mon Dec 08 00:16:43 2008 +0000
@@ -8,72 +8,14 @@
 #include <cassert>
 
 NetworkClient::NetworkClient (GameState &state, const NetworkAddress &connect_to) : 
-    state(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)), netobjs(netsession, NETCHAN_CORE, server) {
-    
+    state(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)), controller(*this)
+{
     // connect slots
-    slots.connect(netobjs.sig_create(NETMSG_SERVER_HELLO), this, &NetworkClient::on_server_hello);
-    slots.connect(netobjs.sig_create(NETMSG_PLAYER_INFO), this, &NetworkClient::on_player_info);
-    slots.connect(netobjs.sig_create(NETMSG_PLAYER_JOIN), this, &NetworkClient::on_player_join);
-    slots.connect(netobjs.sig_create(NETMSG_PROJECTILE_CREATE), this, &NetworkClient::on_projectile_create);
-
     slots.connect(netsession.sig_chan_message(NETCHAN_TERRAIN_ARRAY), this, &NetworkClient::on_terrain_array);
 
     // XXX: sig_disconnected
 }
         
-void NetworkClient::on_server_hello (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
-    // read the packet
-    Vector position = pkt.read_vector();
-    
-    Engine::log(INFO, "client.on_server_hello") << "obj=" << obj << ", pos=" << position;
-
-    // create the LocalPlayer object
-    NetworkClientLocalPlayer *player = new NetworkClientLocalPlayer(*this, obj, position);
-
-    // inform state
-    state.newLocalPlayer(player);
-}
-        
-void NetworkClient::on_player_info (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
-    // read the packet
-    Vector position = pkt.read_vector();
-    
-    Engine::log(INFO, "client.on_player_info") << "obj=" << obj << ", pos=" << position;
-
-    // create the LocalPlayer object
-    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position);
-
-    // inform state
-    state.newPlayer(player);
-
-}
-        
-void NetworkClient::on_player_join (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
-    // read the packet
-    Vector position = pkt.read_vector();
-    
-    Engine::log(INFO, "client.on_player_join") << "obj=" << obj << ", pos=" << position;
-    
-    // create the RemotePlayer object
-    NetworkClientRemotePlayer *player = new NetworkClientRemotePlayer(*this, obj, position);
-
-    // inform state
-    state.newPlayer(player);
-}
-        
-void NetworkClient::on_projectile_create (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
-    // read the packet
-    Vector position = pkt.read_vector();
-    Vector velocity = pkt.read_vector();
-    float explosionRadius = pkt.read_float32();
-    float radius = pkt.read_float32();
-
-    Engine::log(INFO, "client.on_projectile_create") << "obj=" << obj << ", pos=" << position << ", velocity=" << velocity;
-
-    // create the NetworkClientPorjectile object
-    new NetworkClientProjectile(*this, obj, position, velocity, explosionRadius, radius);
-}
-        
 void NetworkClient::on_terrain_array (NetworkPacketInput &pkt, NetworkNode *node) {
     // ignore if not from server
     if (node != server)
@@ -106,31 +48,105 @@
 }
 
 /*
- * NetworkClientObjectHelper
+ * NetworkClientController
+ */ 
+NetworkClientController::NetworkClientController (NetworkClient &client) :
+    NetworkObject_ClientController(client.netsession, NETCHAN_CORE, client.server), client(client)
+{
+
+}
+
+void NetworkClientController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node) {
+    switch (msg_id) {
+        case NETMSG_SERVER_HELLO:
+            on_server_hello(obj_id, pkt);
+            break;
+
+        case NETMSG_PLAYER_INFO:
+            on_player_info(obj_id, pkt);
+            break;
+
+        case NETMSG_PLAYER_JOIN:
+            on_player_join(obj_id, pkt);
+            break;
+
+        case NETMSG_PROJECTILE_CREATE:
+            on_projectile_create(obj_id, pkt);
+            break;
+
+        default:
+            Engine::log(WARN, "client.handle_create") << "Unknown object create message: obj_id=" << obj_id << ", msg_id=" << msg_id;
+    }
+}
+        
+void NetworkClientController::on_server_hello (NetworkObjectID obj_id, NetworkPacketInput &pkt) {
+    // read the packet
+    Vector position = pkt.read_vector();
+    
+    Engine::log(INFO, "client.on_server_hello") << this << ": pos=" << position;
+
+    // create the LocalPlayer object
+    new NetworkClientLocalPlayer(client, obj_id, position);
+}
+        
+void NetworkClientController::on_player_info (NetworkObjectID obj_id, NetworkPacketInput &pkt) {
+    // read the packet
+    Vector position = pkt.read_vector();
+    
+    Engine::log(INFO, "client.on_player_info") << this << ": pos=" << position;
+
+    // create the LocalPlayer object
+    new NetworkClientRemotePlayer(client, obj_id, position);
+}
+        
+void NetworkClientController::on_player_join (NetworkObjectID obj_id, NetworkPacketInput &pkt) {
+    // read the packet
+    Vector position = pkt.read_vector();
+    
+    Engine::log(INFO, "client.on_player_join") << this << ": pos=" << position;
+    
+    // create the RemotePlayer object
+    new NetworkClientRemotePlayer(client, obj_id, position);
+}
+        
+void NetworkClientController::on_projectile_create (NetworkObjectID obj_id, NetworkPacketInput &pkt) {
+    // read the packet
+    Vector position = pkt.read_vector();
+    Vector velocity = pkt.read_vector();
+    float explosionRadius = pkt.read_float32();
+    float radius = pkt.read_float32();
+
+    Engine::log(INFO, "client.on_projectile_create") << this << ": pos=" << position << ", velocity=" << velocity;
+
+    // create the NetworkClientPorjectile object
+    new NetworkClientProjectile(client, obj_id, position, velocity, explosionRadius, radius);
+}
+
+/*
+ * NetworkClientObject
  */
-NetworkClientObjectHelper::NetworkClientObjectHelper (NetworkClient &client, NetworkObject_Client *obj) :
-    client(client), obj(obj)
+NetworkClientObject::NetworkClientObject (NetworkClient &client, NetworkObjectID obj_id) :
+    NetworkObject_Client(client.controller, obj_id), client(client)
 {
 
 }
 
 /*
- * NetworkClientPlayerHelper
+ * NetworkClientPlayerBase
  */
-NetworkClientPlayerHelper::NetworkClientPlayerHelper (NetworkClient &client, Vector position, NetworkObject_Client *obj) :
-    NetworkClientObjectHelper(client, obj), Player(client.state, position, true) 
+NetworkClientPlayerBase::NetworkClientPlayerBase (NetworkClient &client, NetworkObjectID obj_id, Vector position) :
+    NetworkClientObject(client, obj_id), Player(client.state, position, true) 
 {
-    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION),         this,   &NetworkClientPlayerHelper::on_position         );
-    slots.connect(obj->sig_message(NETMSG_PLAYER_DIG),              this,   &NetworkClientPlayerHelper::on_dig              );
-    slots.connect(obj->sig_message(NETMSG_PLAYER_WEAPON_CHANGE),    this,   &NetworkClientPlayerHelper::on_weapon_change    );
-    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_THROW),       this,   &NetworkClientPlayerHelper::on_rope_throw       );
-    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_FIXED),       this,   &NetworkClientPlayerHelper::on_rope_fixed       );
-    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_RELEASED),    this,   &NetworkClientPlayerHelper::on_rope_released    );
-    slots.connect(obj->sig_message(NETMSG_PLAYER_ROPE_LENGTH),      this,   &NetworkClientPlayerHelper::on_rope_length      );
-
+    slots.connect(sig_message(NETMSG_PLAYER_POSITION),         this,   &NetworkClientPlayerBase::on_position         );
+    slots.connect(sig_message(NETMSG_PLAYER_DIG),              this,   &NetworkClientPlayerBase::on_dig              );
+    slots.connect(sig_message(NETMSG_PLAYER_WEAPON_CHANGE),    this,   &NetworkClientPlayerBase::on_weapon_change    );
+    slots.connect(sig_message(NETMSG_PLAYER_ROPE_THROW),       this,   &NetworkClientPlayerBase::on_rope_throw       );
+    slots.connect(sig_message(NETMSG_PLAYER_ROPE_FIXED),       this,   &NetworkClientPlayerBase::on_rope_fixed       );
+    slots.connect(sig_message(NETMSG_PLAYER_ROPE_RELEASED),    this,   &NetworkClientPlayerBase::on_rope_released    );
+    slots.connect(sig_message(NETMSG_PLAYER_ROPE_LENGTH),      this,   &NetworkClientPlayerBase::on_rope_length      );
 }
 
-void NetworkClientPlayerHelper::on_position (NetworkPacketInput &pkt) {
+void NetworkClientPlayerBase::on_position (NetworkPacketInput &pkt) {
     Vector position = pkt.read_vector();
     Vector velocity = pkt.read_vector();
     int flags = pkt.read_uint8();
@@ -146,61 +162,66 @@
     );
 }
 
-void NetworkClientPlayerHelper::on_dig (NetworkPacketInput &pkt) {
+void NetworkClientPlayerBase::on_dig (NetworkPacketInput &pkt) {
     Vector position = pkt.read_vector();
     float radius = pkt.read_float32();
 
-    Engine::log(INFO, "client_player.on_dig") << "obj=" << obj << ", position=" << position << ", radius=" << radius;
+    Engine::log(INFO, "client_player.on_dig") << this << ": position=" << position << ", radius=" << radius;
     
     // just update... 
     handleDig(position, radius);
 }
         
-void NetworkClientPlayerHelper::on_weapon_change (NetworkPacketInput &pkt) {
+void NetworkClientPlayerBase::on_weapon_change (NetworkPacketInput &pkt) {
     uint8_t weapon_index = pkt.read_uint8();
 
-    Engine::log(INFO, "client_player.on_weapon_change") << "obj=" << obj << ", weapon_index=" << weapon_index;
+    Engine::log(INFO, "client_player.on_weapon_change") << this << ": weapon_index=" << weapon_index;
 
     handleChangeWeapon(weapon_index);
 }
 
-void NetworkClientPlayerHelper::on_rope_throw (NetworkPacketInput &pkt) {
+void NetworkClientPlayerBase::on_rope_throw (NetworkPacketInput &pkt) {
     Vector position = pkt.read_vector();
     Vector velocity = pkt.read_vector();
     float length = pkt.read_float32();
 
-    Engine::log(INFO, "client_player.on_rope_throw") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", length=" << length;
+    Engine::log(INFO, "client_player.on_rope_throw") << this << ": position=" << position << ", velocity=" << velocity << ", length=" << length;
 
     rope.updateState(ROPE_FLYING, position, velocity, length);
 }
 
-void NetworkClientPlayerHelper::on_rope_fixed (NetworkPacketInput &pkt) {
+void NetworkClientPlayerBase::on_rope_fixed (NetworkPacketInput &pkt) {
     Vector position = pkt.read_vector();
     float length = pkt.read_float32();
     
-    Engine::log(INFO, "client_player.on_rope_fixed") << "obj=" << obj << ", position=" << position << ", length=" << length;
+    Engine::log(INFO, "client_player.on_rope_fixed") << this << ": position=" << position << ", length=" << length;
 
     rope.updateState(ROPE_FIXED, position, Vector(0, 0), length);
 }
 
-void NetworkClientPlayerHelper::on_rope_released (NetworkPacketInput &pkt) {
-    Engine::log(INFO, "client_player.on_rope_released") << "obj=" << obj;
+void NetworkClientPlayerBase::on_rope_released (NetworkPacketInput &pkt) {
+    Engine::log(INFO, "client_player.on_rope_released") << this;
     
     // use rope.getPosition() instead of e.g. Vector(0, 0) because it will collide there...
     rope.updateState(ROPE_FOLDED, rope.getPosition(), Vector(0, 0), 0);
 }
 
-void NetworkClientPlayerHelper::on_rope_length (NetworkPacketInput &pkt) {
+void NetworkClientPlayerBase::on_rope_length (NetworkPacketInput &pkt) {
     float length = pkt.read_float32();
     
-    Engine::log(INFO, "client_player.on_rope_length") << "obj=" << obj << ", length=" << length;
+    Engine::log(INFO, "client_player.on_rope_length") << this << ": length=" << length;
 
     rope.updateLength(length);
 }
 
-NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
-    Player(client.state, position, true), NetworkClientPlayerHelper(client, position, obj) {
-    
+/*
+ * NetworkClientLocalPlayer
+ */
+NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, NetworkObjectID obj_id, Vector position) :
+    Player(client.state, position, true), NetworkClientPlayerBase(client, obj_id, position) 
+{
+    // set ourselves as the local player
+    state.setLocalPlayer(this);
 }
         
 void NetworkClientLocalPlayer::handleInput (PlayerInput input) {
@@ -208,33 +229,36 @@
     NetworkPacket pkt;
     pkt.write_uint16(input);
 
-    obj->send(NETMSG_CLIENT_INPUT, pkt, false);
+    send(NETMSG_CLIENT_INPUT, pkt, false);
     
     // do not handle locally
 }
         
-NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
-    Player(client.state, position, true), NetworkClientPlayerHelper(client, position, obj) {
+/*
+ * NetworkClientRemotePlayer
+ */
+NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, NetworkObjectID obj_id, Vector position) :
+    Player(client.state, position, true), NetworkClientPlayerBase(client, obj_id, position) {
     
     // receive messages
-    slots.connect(obj->sig_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit);
+    slots.connect(sig_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit);
 }
 
 void NetworkClientRemotePlayer::on_quit (NetworkPacketInput &pkt) {
     // pkt is empty
     (void) pkt;
 
-    Engine::log(INFO, "client_player.on_quit") << "obj=" << obj;
+    Engine::log(INFO, "client_player.on_quit") << this;
 
     client.player_quit(this);
 }
 
-NetworkClientProjectile::NetworkClientProjectile (NetworkClient &client, NetworkObject_Client *obj, Vector position,
+NetworkClientProjectile::NetworkClientProjectile (NetworkClient &client, NetworkObjectID obj_id, Vector position,
         Vector velocity, float explosionRadius, float radius) :
-    NetworkClientObjectHelper(client, obj), Projectile(client.state, position, velocity, true, explosionRadius, radius)
+    NetworkClientObject(client, obj_id), Projectile(client.state, position, velocity, explosionRadius, radius, 100 /* XXX */)
 {
     // hook up signals
-    slots.connect(obj->sig_message(NETMSG_PROJECTILE_DESTROY), this, &NetworkClientProjectile::on_destroy);
+    slots.connect(sig_message(NETMSG_PROJECTILE_DESTROY), this, &NetworkClientProjectile::on_destroy);
 }
 
 void NetworkClientProjectile::onDestroy (Vector position, bool removeGround) {
@@ -245,10 +269,11 @@
     Vector position = pkt.read_vector();
     uint8_t flags = pkt.read_uint8();
 
-    Engine::log(INFO, "client_projectile.on_destroy") << "obj=" << obj << ", position=" << position << ", flags=" << flags;
+    Engine::log(INFO, "client_projectile.on_destroy") << this << ": position=" << position << ", flags=" << flags;
     
     // XXX: leak obj, not yet implemented:  obj.destory();
 
     // pass on to super
     Projectile::onDestroy(position, flags & NETWORK_PROJECTILE_REMOVE_GROUND);
 }
+
--- a/src/Network/Client.hh	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Network/Client.hh	Mon Dec 08 00:16:43 2008 +0000
@@ -6,11 +6,34 @@
 #include "Object.hh"
 
 // forward-declare
+class NetworkClient;
 class NetworkClientLocalPlayer;
 class NetworkClientRemotePlayer;
 
+class NetworkClientController : public NetworkObject_ClientController {
+    protected:
+        NetworkClient &client;
+    
+    public:
+        NetworkClientController (NetworkClient &client);
+
+    protected:
+        /**
+         * We override handle_create from NetworkObject_ClientController to construct the correct
+         * NetworkClientObject-deriving object (LocalPlayer, RemotePlayer, Projectile) ourselves
+         */
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node);
+
+        void on_server_hello (NetworkObjectID obj_id, NetworkPacketInput &pkt);
+        void on_player_info (NetworkObjectID obj_id, NetworkPacketInput &pkt);
+        void on_player_join (NetworkObjectID obj_id, NetworkPacketInput &pkt);
+        void on_projectile_create (NetworkObjectID obj_id, NetworkPacketInput &pkt);
+};
+
 class NetworkClient {
-    friend class NetworkClientPlayerHelper;
+    friend class NetworkClientController;
+    friend class NetworkClientObject;
+    friend class NetworkClientPlayerBase;
     friend class NetworkClientLocalPlayer;
     friend class NetworkClientRemotePlayer;
     friend class NetworkClientProjectile;
@@ -21,40 +44,34 @@
 
         NetworkSession netsession;
         NetworkNode *server;
+        NetworkClientController controller;
 
-        NetworkObject_ClientController netobjs;
-        
     public:
         NetworkClient (GameState &state, const NetworkAddress &connect_to);
-
-    private:
-        void on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacketInput &pkt);
-
-        void on_server_hello (NetworkObject_Client *obj, NetworkPacketInput &pkt);
-        void on_player_info (NetworkObject_Client *obj, NetworkPacketInput &pkt);
-        void on_player_join (NetworkObject_Client *obj, NetworkPacketInput &pkt);
-        void on_projectile_create (NetworkObject_Client *obj, NetworkPacketInput &pkt);
-
+    
+    protected:
+        
+        /**
+         * Receive the terrain array from the server and apply it to the state.world's terrain
+         */
         void on_terrain_array (NetworkPacketInput &pkt, NetworkNode *node);
     
     public:
         void player_quit (NetworkClientRemotePlayer *player);
 };
 
-class NetworkClientObjectHelper {
+class NetworkClientObject : public NetworkObject_Client {
     protected:
         NetworkClient &client;
 
         CL_SlotContainer slots;
 
-        NetworkObject_Client *obj;
-
-        NetworkClientObjectHelper (NetworkClient &client, NetworkObject_Client *obj);
+        NetworkClientObject (NetworkClient &client, NetworkObjectID obj_id);
 };
 
-class NetworkClientPlayerHelper : public NetworkClientObjectHelper, public virtual Player {
+class NetworkClientPlayerBase : public NetworkClientObject, public virtual Player {
     protected:
-        NetworkClientPlayerHelper (NetworkClient &client, Vector position, NetworkObject_Client *obj);
+        NetworkClientPlayerBase (NetworkClient &client, NetworkObjectID obj_id, Vector position);
     
     private:
         void on_position (NetworkPacketInput &pkt);
@@ -66,25 +83,25 @@
         void on_rope_length (NetworkPacketInput &pkt);
 };
 
-class NetworkClientLocalPlayer : public NetworkClientPlayerHelper, public LocalPlayer {
+class NetworkClientLocalPlayer : public NetworkClientPlayerBase, public LocalPlayer {
     public:
-        NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position);
+        NetworkClientLocalPlayer (NetworkClient &client, NetworkObjectID obj_id, Vector position);
         
         virtual void handleInput (PlayerInput input);
 };
 
-class NetworkClientRemotePlayer : public NetworkClientPlayerHelper, public RemotePlayer {
+class NetworkClientRemotePlayer : public NetworkClientPlayerBase, public RemotePlayer {
     public:
-        NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position);
+        NetworkClientRemotePlayer (NetworkClient &client, NetworkObjectID obj_id, Vector position);
     
     private:
         void on_quit (NetworkPacketInput &pkt);
     
 };
 
-class NetworkClientProjectile : public NetworkClientObjectHelper, public Projectile {
+class NetworkClientProjectile : public NetworkClientObject, public Projectile {
     public:
-        NetworkClientProjectile (NetworkClient &client, NetworkObject_Client *obj, Vector position, Vector velocity,
+        NetworkClientProjectile (NetworkClient &client, NetworkObjectID obj_id, Vector position, Vector velocity,
                 float explosionRadius, float radius);
     
     protected:
--- a/src/Network/Server.cc	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Network/Server.cc	Mon Dec 08 00:16:43 2008 +0000
@@ -25,9 +25,6 @@
 
     // add to players
     players.push_back(player);
-    
-    // add to GameState
-    state.newPlayer(player);
 }
         
 void NetworkServer::handle_disconnect (NetworkServerPlayer *player) {
@@ -37,22 +34,34 @@
     // remove from list
     players.remove(player);
 }
-        
+
+/*
+ * NetworkServerObject
+ */
+NetworkServerObject::NetworkServerObject (NetworkServer &server) :
+    NetworkObject_Server(server.netobjs), server(server)
+{
+
+}
+
+/*
+ * NetworkServerPlayer
+ */
 NetworkServerPlayer::NetworkServerPlayer (NetworkServer &server, NetworkNode *node) : 
-    Player(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), server(server), obj(server.netobjs), node(node) {
-    
+    Player(server.state, Vector(PLAYER_INITIAL_X, PLAYER_INITIAL_Y), true), NetworkServerObject(server), node(node) 
+{
     // log
-    Engine::log(INFO, "server_player.connected") << "node=" << node << ", obj=" << obj;
+    Engine::log(INFO, "server_player.connected") << this << ": node=" << node;
 
     // messages
     slots.connect(node->sig_disconnected(), this, &NetworkServerPlayer::on_disconnected);
-    slots.connect(obj.sig_message(NETMSG_CLIENT_INPUT), this, &NetworkServerPlayer::on_input);
+    slots.connect(this->sig_message(NETMSG_CLIENT_INPUT), this, &NetworkServerPlayer::on_input);
 
     // the initial NETMSG_PLAYER_HELLO
     NetworkPacket hello_pkt;
     hello_pkt.write_vector(position);
 
-    obj.send_to(node, NETMSG_SERVER_HELLO, hello_pkt, true);
+    this->send_to(node, NETMSG_SERVER_HELLO, hello_pkt, true);
 
     // send other player objects
     for (std::list<NetworkServerPlayer*>::iterator it = server.players.begin(); it != server.players.end(); it++) {
@@ -64,11 +73,11 @@
         
         player_pkt.write_vector(player->position);
 
-        player->obj.send_to(node, NETMSG_PLAYER_INFO, player_pkt, true);
+        player->send_to(node, NETMSG_PLAYER_INFO, player_pkt, true);
     }
 
     // broadcast NETMSG_PLAYER_JOIN to all clients except current
-    obj.send_all_except(NETMSG_PLAYER_JOIN, hello_pkt, node, true);
+    this->send_all_except(NETMSG_PLAYER_JOIN, hello_pkt, node, true);
 
     // send terrain data...
     send_terrain_data();
@@ -83,7 +92,7 @@
     Engine::log(INFO, "server_player.handle_dig") << "position=" << position << ", radius=" << radius;
     
     // tell everyone... make this reliable... 
-    obj.send_all(NETMSG_PLAYER_DIG, pkt, true);
+    this->send_all(NETMSG_PLAYER_DIG, pkt, true);
 
     // and carry out the actual dig on the server as well
     Player::handleDig(position, radius);
@@ -93,7 +102,7 @@
     Engine::log(INFO, "server_player.create_projectile") << "weapon='" << weapon->getName() << "', position=" << position << ", velocity=" << velocity;
 
     // create new NetworkServerProjectile object
-    new NetworkServerProjectile(server, position, velocity, weapon->getExplosionRadius(), weapon->getRadius(), weapon->getExpire());
+    new NetworkServerProjectile(server, this, position, velocity, weapon);
 }
 
 void NetworkServerPlayer::handleChangeWeapon (unsigned int weaponIndex) {
@@ -105,7 +114,7 @@
     pkt.write_uint8(weaponIndex);
     
     // XXX: only tell the client itself?
-    obj.send_all(NETMSG_PLAYER_WEAPON_CHANGE, pkt, true);
+    send_all(NETMSG_PLAYER_WEAPON_CHANGE, pkt, true);
     
     // pass through
     Player::handleChangeWeapon(weaponIndex);
@@ -122,7 +131,7 @@
         pkt.write_vector(rope.getVelocity());
         pkt.write_float32(rope.getLength());
 
-        obj.send_all(NETMSG_PLAYER_ROPE_THROW, pkt, true);
+        send_all(NETMSG_PLAYER_ROPE_THROW, pkt, true);
         
         break;
 
@@ -130,12 +139,12 @@
         pkt.write_vector(rope.getPosition());
         pkt.write_float32(rope.getLength());
         
-        obj.send_all(NETMSG_PLAYER_ROPE_FIXED, pkt, true);
+        send_all(NETMSG_PLAYER_ROPE_FIXED, pkt, true);
 
         break;
     
     case ROPE_FOLDED:
-        obj.send_all(NETMSG_PLAYER_ROPE_RELEASED, pkt, true);
+        send_all(NETMSG_PLAYER_ROPE_RELEASED, pkt, true);
 
         break;
     }
@@ -146,19 +155,19 @@
 
     pkt.write_float32(length);
 
-    obj.send_all(NETMSG_PLAYER_ROPE_LENGTH, pkt, true);
+    send_all(NETMSG_PLAYER_ROPE_LENGTH, pkt, true);
 }
 
 void NetworkServerPlayer::on_disconnected (void) {
     NetworkPacket pkt;
     
-    Engine::log(INFO, "server_player.disconnected") << "node=" << node << ", obj=" << obj;
+    Engine::log(INFO, "server_player.disconnected") << this << ": node=" << node;
     
     // remove from server
     server.handle_disconnect(this);
     
     // tell other clients
-    obj.send_all(NETMSG_PLAYER_QUIT, pkt, true);
+    send_all(NETMSG_PLAYER_QUIT, pkt, true);
 
     // free
 //    delete this;
@@ -224,15 +233,15 @@
 
 //    Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position << "+" << velocity << " [" << flags << "]";
 
-    obj.send_all(NETMSG_PLAYER_POSITION, pkt, false);
+    send_all(NETMSG_PLAYER_POSITION, pkt, false);
 }
 
 /* 
  * NetworkServerProjectile
  */
-NetworkServerProjectile::NetworkServerProjectile (NetworkServer &server, Vector position, Vector velocity, 
-        float explosionRadius, float radius, TickCount age) :
-    Projectile(server.state, position, velocity, true, explosionRadius, radius, age), server(server), obj(server.netobjs)
+NetworkServerProjectile::NetworkServerProjectile (NetworkServer &server, NetworkServerPlayer *player, Vector position,
+        Vector velocity, Weapon *weapon) :
+    Projectile(server.state, position, velocity, weapon, true), NetworkServerObject(server)
 {
     NetworkPacket pkt;
 
@@ -241,7 +250,7 @@
     pkt.write_float32(explosionRadius);
     pkt.write_float32(radius);
 
-    obj.send_all(NETMSG_PROJECTILE_CREATE, pkt, true);
+    send_all(NETMSG_PROJECTILE_CREATE, pkt, true);
 }
 
 void NetworkServerProjectile::onDestroy (Vector position, bool removeGround) {
@@ -252,7 +261,7 @@
     pkt.write_vector(position);
     pkt.write_uint8(removeGround ? NETWORK_PROJECTILE_REMOVE_GROUND : 0);
 
-    obj.send_all(NETMSG_PROJECTILE_DESTROY, pkt, true);
+    send_all(NETMSG_PROJECTILE_DESTROY, pkt, true);
 
     // XXX: leak obj, not yet implemented:  obj.destory();
     
--- a/src/Network/Server.hh	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Network/Server.hh	Mon Dec 08 00:16:43 2008 +0000
@@ -13,6 +13,7 @@
 class NetworkServerPlayer;
 
 class NetworkServer {
+    friend class NetworkServerObject;
     friend class NetworkServerPlayer;
     friend class NetworkServerProjectile;
 
@@ -34,14 +35,18 @@
         void on_node_connected (NetworkNode *node);
 };
 
-class NetworkServerPlayer : public LocalPlayer {
-    private:
+class NetworkServerObject : public NetworkObject_Server {
+    protected:
         NetworkServer &server;
-        NetworkObject_Server obj;
+        CL_SlotContainer slots;
+
+        NetworkServerObject (NetworkServer &server);
+};
+
+class NetworkServerPlayer : public LocalPlayer, public NetworkServerObject {
+    protected:
         NetworkNode *node;
 
-        CL_SlotContainer slots;
-        
     public:
         NetworkServerPlayer (NetworkServer &server, NetworkNode *node);
     
@@ -61,13 +66,9 @@
         void send_position_update (void);
 };
 
-class NetworkServerProjectile : public Projectile {
-    private:
-        NetworkServer &server;
-        NetworkObject_Server obj;
-    
+class NetworkServerProjectile : public Projectile, public NetworkServerObject {
     public:
-        NetworkServerProjectile (NetworkServer &server, Vector position, Vector velocity, float explosionRadius, float radius, TickCount age);
+        NetworkServerProjectile (NetworkServer &server, NetworkServerPlayer *player, Vector position, Vector velocity, Weapon *weapon);
     
     protected:
         virtual void onDestroy (Vector position, bool removeGround);
--- a/src/Player.cc	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Player.cc	Mon Dec 08 00:16:43 2008 +0000
@@ -38,6 +38,13 @@
 
     // XXX: this should be a PhysicsObject constructor arg
     collision_elasticity = PLAYER_COLLISION_ELASTICITY;
+
+    // add to GameState players list
+    state.addPlayer(this);
+}
+
+Player::~Player (void) {
+    state.removePlayer(this);
 }
 
 void Player::handleDig (Vector pos, float radius) {
--- a/src/Player.hh	Mon Dec 08 00:05:45 2008 +0000
+++ b/src/Player.hh	Mon Dec 08 00:16:43 2008 +0000
@@ -35,9 +35,20 @@
         // XXX: hmm... updated where?
         int animation_step;
 
-        // default constructor for use with virtual inheritance... it's not defined
+        /**
+         * Default constructor for use with virtual inheritance... it's not defined, and must not be called
+         */
         Player (void);
+
+        /**
+         * Initialize params, and add ourselves to GameState
+         */
         Player (GameState &state, Vector position, bool visible); 
+        
+        /**
+         * Remove player from state players list
+         */
+        ~Player (void);
 
         /*
          *  Used by the network code to execute various actions