better NetworkBuffer/Packet stuff + some additional Physics+Network stuff + random fixes
authorterom
Thu, 04 Dec 2008 21:59:23 +0000
changeset 200 2dbf40661580
parent 199 f5c86420facd
child 201 135616467a0a
better NetworkBuffer/Packet stuff + some additional Physics+Network stuff + random fixes
src/GameState.cc
src/Network/Buffer.cc
src/Network/Buffer.hh
src/Network/Client.cc
src/Network/Client.hh
src/Network/Node.cc
src/Network/Node.hh
src/Network/Object.cc
src/Network/Object.hh
src/Network/Packet.cc
src/Network/Packet.hh
src/Network/Protocol.hh
src/Network/Server.cc
src/Network/Server.hh
src/Network/Session.cc
src/Network/Session.hh
src/Network/TCP.cc
src/Network/TCP.hh
src/Network/UDP.hh
src/PhysicsObject.cc
src/PhysicsObject.hh
src/Player.cc
src/Player.hh
src/Projectile.cc
--- a/src/GameState.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/GameState.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -17,7 +17,7 @@
     
     local_player = player;
 }
-
+    
 void GameState::newRemotePlayer (RemotePlayer *player) {
     player_list.push_back(player);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Network/Buffer.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -0,0 +1,211 @@
+
+#include "Buffer.hh"
+#include "Config.hh"
+
+#include <ClanLib/core.h>
+#include <cstdlib>
+
+/*
+ * NetworkBufferBase
+ */
+NetworkBufferBase::NetworkBufferBase (NetworkSocket &socket, size_t size_hint) :
+    socket(socket), buf(0), size(0), offset(0) {
+    
+    // allocate initial buffer
+    if ((buf = (char *) malloc(size_hint)) == NULL)
+       throw NetworkBufferError("malloc failed");
+    
+    // remember size
+    size = size_hint;
+}
+        
+NetworkBufferBase::~NetworkBufferBase (void) {
+    free(buf);
+}
+
+void NetworkBufferBase::resize (size_t item_size) {
+    size_t new_size = size;
+
+    // grow new_size until item_size fits
+    while (offset + item_size > new_size)
+        new_size *= 2;
+    
+    // grow if needed
+    if (new_size != size) {
+        // realloc buffer
+        if ((buf = (char *) realloc((void *) buf, new_size)) == NULL)
+            throw NetworkBufferError("realloc failed");
+
+        // update size
+        size = new_size;
+
+    } else if (new_size > (offset + item_size) * 4) {
+        // XXX: shrink?
+    }
+}
+        
+void NetworkBufferBase::trim (size_t prefix_size) {
+    // update offset
+    offset -= prefix_size;
+
+    // shift the buffer forwards from (buf + prefix) -> (buf), copying (old_offset - prefix) bytes
+    memmove(buf, buf + prefix_size, offset);
+}
+
+/*
+ * NetworkBufferInput
+ */
+NetworkBufferInput::NetworkBufferInput (NetworkSocket &socket, size_t size_hint) :
+    NetworkBufferBase(socket, size_hint)
+{
+
+}
+
+bool NetworkBufferInput::try_read (size_t item_size) {
+    int ret;
+    size_t to_read = item_size;
+
+    // keept reads at at least NETWORK_BUFFER_CHUNK_SIZE bytes
+    if (to_read < NETWORK_BUFFER_CHUNK_SIZE)
+        to_read = NETWORK_BUFFER_CHUNK_SIZE;
+
+    // resize buffer if needed
+    resize(to_read);
+
+    // read once
+    try {
+        ret = socket.recv(buf + offset, to_read);
+
+    } catch (CL_Error &e) {
+        if (errno == EAGAIN)
+            return false;
+
+        else
+            throw NetworkSocketOSError(socket, "recv");
+    }
+    
+    // handle EOF
+    if (ret == 0)
+        throw NetworkSocketEOFError(socket, "recv");
+
+    assert(ret >= 0);
+
+    // update offset
+    offset += ret;
+
+    // did we get enough?
+    if ((unsigned int) ret < item_size)
+        return false;
+    else
+        return true;
+} 
+        
+bool NetworkBufferInput::have_data (size_t data_size) {
+    return (offset >= data_size);
+}
+
+bool NetworkBufferInput::peek_prefix (uint16_t &val_ref) {
+    if (!have_data(sizeof(uint16_t)))
+        return false;
+
+    val_ref = ntohs(*((uint16_t *) (buf)));
+
+    return true;
+}
+    
+bool NetworkBufferInput::peek_prefix (uint32_t &val_ref) {
+    if (!have_data(sizeof(uint32_t)))
+        return false;
+
+    val_ref = ntohl(*((uint32_t *) (buf)));
+
+    return true;
+}
+   
+/*
+ * NetworkBufferOutput
+ */
+NetworkBufferOutput::NetworkBufferOutput (NetworkSocket &socket, size_t size_hint) :
+    NetworkBufferBase(socket, size_hint)
+{
+
+}
+
+
+void NetworkBufferOutput::push_write (char *buf_ptr, size_t buf_size) {
+    int ret;
+
+    // try and short-circuit writes unless we have already buffered data
+    if (offset == 0) {
+        try {
+            // attempt to send something
+            ret = socket.send(buf_ptr, buf_size);
+
+        } catch (CL_Error &e) {
+            // ignore EAGAIN, detect this by setting ret to -1
+            if (errno != EAGAIN)
+                throw NetworkSocketOSError(socket, "send");
+
+            ret = -1;
+        }
+        
+        // if we managed to send something, adjust buf/size and buffer
+        if (ret > 0) {
+            // sanity-check
+            assert(buf_size >= (unsigned int) ret);
+
+            buf_ptr += ret;
+            buf_size -= ret;
+
+            // if that was all, we're done
+            if (buf_size == 0)
+                return;
+        }
+    }
+    
+    // resize to fit buf_size more bytes
+    resize(buf_size);
+    
+    // copy into our internal buffer
+    memcpy(buf + offset, buf_ptr, buf_size);
+}
+        
+void NetworkBufferOutput::flush_write (void) {
+    int ret;
+
+    // ignore if we don't have any data buffered
+    if (offset == 0)
+        return;
+    
+    // attempt to write as much as possible
+    try {
+        ret = socket.send(buf, offset);
+
+    } catch (CL_Error &e) {
+        // ignore EAGAIN and just return
+        if (errno == EAGAIN)
+            return;
+
+        else
+            throw NetworkSocketOSError(socket, "send");
+    }
+
+    // trim the buffer
+    trim(ret);
+}
+        
+void NetworkBufferOutput::write_prefix (char *buf, uint16_t prefix) {
+    uint16_t nval = htons(prefix);
+
+    push_write((char*) &nval, sizeof(uint16_t)); 
+    push_write(buf, prefix);
+}
+
+void NetworkBufferOutput::write_prefix (char *buf, uint32_t prefix) {
+    uint32_t nval = htonl(prefix);
+
+    push_write((char*) &nval, sizeof(uint32_t)); 
+    push_write(buf, prefix);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Network/Buffer.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -0,0 +1,150 @@
+#ifndef NETWORK_BUFFER_HH
+#define NETWORK_BUFFER_HH
+
+#include "Socket.hh"
+#include "../Error.hh"
+
+#include <cassert>
+
+/*
+ * Minimum chunk size to avoid handling single bytes at a time (for resize, mainly)
+ */
+const size_t NETWORK_BUFFER_CHUNK_SIZE = 1024;
+
+class NetworkBufferError : public Error {
+    public:
+        NetworkBufferError (const std::string &message) : Error(message) { }
+};
+
+/*
+ * Base buffer operations for uffered socket send/recv
+ */
+class NetworkBufferBase {
+    protected:
+        // the socket that we use
+        NetworkSocket socket;
+
+        char *buf;
+        size_t size, offset;
+    
+    public:
+        NetworkBufferBase (NetworkSocket &socket, size_t size_hint);
+        ~NetworkBufferBase (void);
+    
+    private:
+        NetworkBufferBase (const NetworkBufferBase &copy);
+        NetworkBufferBase& operator= (const NetworkBufferBase &copy);
+    
+    protected:
+        void resize (size_t item_size);
+        void trim (size_t prefix_size);
+};
+
+/*
+ * Buffered prefix-len socket input
+ */
+class NetworkBufferInput : public NetworkBufferBase {
+    public:
+        NetworkBufferInput (NetworkSocket &socket, size_t size_hint);
+
+    private:
+        /*
+         * Attempts to recv the given number of bytes, returning true on success
+         */
+        bool try_read (size_t item_size);
+
+        /*
+         * Returns true if the buffer contains at least the given amount of data
+         */
+        bool have_data (size_t data_size);
+    
+    public:
+        /*
+         * Attempts to read the length prefix into val_ref, returning true on success
+         */
+        bool peek_prefix (uint16_t &val_ref);
+        bool peek_prefix (uint32_t &val_ref);
+        
+        /*
+         * This attempts to collect the prefix + data into our buffer, and then returns the length and a pointer to the
+         * internal memory buffer. Use flush_data when done with the data
+         */
+
+        // XXX: template definition moved here from .cc
+        template <typename PrefixType> bool peek_data (PrefixType &prefix, char *&buf_ref) {
+            size_t missing = 0;
+            
+            do {    
+                // do we have the prefix?
+                if (peek_prefix(prefix)) {
+                    // do we already have the payload?
+                    if (offset >= sizeof(PrefixType) + prefix) {
+                        break;
+
+                    } else {
+                        missing = (sizeof(PrefixType) + prefix) - offset;
+                    }
+
+                } else {
+                    missing = sizeof(PrefixType);
+                }
+
+                // sanity-check
+                // XXX: a zero-prefix will trigger this
+                assert(missing);
+                
+                // try and read the missing data
+                if (try_read(missing) == false) {
+                    // if unable to read what we need, return zero.
+                    return false;
+                }
+                
+                // assess the situation again
+            } while (true);
+            
+            // update the buf_ref to point past the prefix-length
+            buf_ref = buf + sizeof(PrefixType);
+
+            // return
+            return true;
+        }
+            
+        template <typename PrefixType> void flush_data (void) {
+            PrefixType prefix;
+            
+            // we *must* have a valid prefix
+            assert(peek_prefix(prefix));
+
+            // trim the bytes out
+            trim(sizeof(PrefixType) + prefix);
+        }
+};
+
+/*
+ * Buffered prefix-len socket output
+ */
+class NetworkBufferOutput : public NetworkBufferBase {
+    public:
+        NetworkBufferOutput (NetworkSocket &socket, size_t size_hint);
+
+    private:
+        /*
+         * If our buffer is empty, fast-path the given buf_ptr directly to send(), else copy the remaining
+         * portion to our buffer for later use with flush_write
+         */
+        void push_write (char *buf_ptr, size_t buf_size);
+   
+    public:    
+        /*
+         * Try and send() stuff out of our buffer, or ignore if it's empty
+         */
+        void flush_write (void);
+        
+        /*
+         * push_write, first the given prefix and then the buf (which contains <prefix> bytes of data)
+         */
+        void write_prefix (char *buf, uint16_t prefix);
+        void write_prefix (char *buf, uint32_t prefix);
+};
+
+#endif
--- a/src/Network/Client.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Client.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -16,7 +16,7 @@
     // XXX: sig_disconnected
 }
 
-void NetworkClient::on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacket &pkt) {
+void NetworkClient::on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacketInput &pkt) {
     switch (msg_id) {
         case NETMSG_SERVER_HELLO:
             on_server_hello(obj, pkt);
@@ -38,7 +38,7 @@
     }
 }
         
-void NetworkClient::on_server_hello (NetworkObject_Client *obj, NetworkPacket &pkt) {
+void NetworkClient::on_server_hello (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
     // read the packet
     Vector position = pkt.read_vector();
     
@@ -51,7 +51,7 @@
     state.newLocalPlayer(player);
 }
         
-void NetworkClient::on_player_info (NetworkObject_Client *obj, NetworkPacket &pkt) {
+void NetworkClient::on_player_info (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
     // read the packet
     Vector position = pkt.read_vector();
     
@@ -65,7 +65,7 @@
 
 }
         
-void NetworkClient::on_player_join (NetworkObject_Client *obj, NetworkPacket &pkt) {
+void NetworkClient::on_player_join (NetworkObject_Client *obj, NetworkPacketInput &pkt) {
     // read the packet
     Vector position = pkt.read_vector();
     
@@ -87,11 +87,40 @@
     //  delete player;
 }
 
+NetworkClientPlayerHelper::NetworkClientPlayerHelper (NetworkClient &client, NetworkObject_Client *obj) :
+    client(client), obj(obj) {
+
+    // receive position updates
+    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION), this, &NetworkClientPlayerHelper::on_position);
+    slots.connect(obj->sig_message(NETMSG_PLAYER_DIG), this, &NetworkClientPlayerHelper::on_dig);
+}
+
+void NetworkClientPlayerHelper::on_position (NetworkPacketInput &pkt) {
+    Vector position = pkt.read_vector();
+    Vector velocity = pkt.read_vector();
+    int flags = pkt.read_uint8();
+    float aim = pkt.read_float32();
+
+    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity << ", aim=" << aim << ", [" << flags << "]";
+    
+    // just update... 
+    _handleUpdate(position, velocity, flags & NETWORK_PHYSICS_INAIR, flags & NETWORK_PHYSICS_FACE_RIGHT, aim);
+}
+
+void NetworkClientPlayerHelper::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;
+    
+    // just update... 
+    _handleDig(position, radius);
+}
+
+ 
 NetworkClientLocalPlayer::NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
-    LocalPlayer(client.state, position, true), client(client), obj(obj) {
+    LocalPlayer(client.state, position, true), NetworkClientPlayerHelper(client, obj) {
     
-    // receive messages
-    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION), this, &NetworkClientLocalPlayer::on_position);
 }
         
 void NetworkClientLocalPlayer::handleMove (PlayerInput_Move input) {
@@ -104,37 +133,22 @@
     // do not handle locally
 }
         
-void NetworkClientLocalPlayer::on_position (NetworkPacket &pkt) {
-    Vector position = pkt.read_vector();
-    Vector velocity = pkt.read_vector();
-    uint8_t flags = pkt.read_uint8();
-
-    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity;
-    
-    // just update... 
-    updatePhysics(position, velocity, flags & NETWORK_PHYSICS_INAIR);
+void NetworkClientLocalPlayer::_handleUpdate(Vector position, Vector velocity, bool inAir, bool facingRight, float aim) {
+    updatePhysics(position, velocity, inAir, facingRight, aim);
 }
         
+void NetworkClientLocalPlayer::_handleDig (Vector position, float radius) {
+    handleDig(position, radius);
+}
+       
 NetworkClientRemotePlayer::NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position) :
-    RemotePlayer(client.state, position, true), client(client), obj(obj) {
+    RemotePlayer(client.state, position, true), NetworkClientPlayerHelper(client, obj) {
     
     // receive messages
-    slots.connect(obj->sig_message(NETMSG_PLAYER_POSITION), this, &NetworkClientRemotePlayer::on_position);
     slots.connect(obj->sig_message(NETMSG_PLAYER_QUIT), this, &NetworkClientRemotePlayer::on_quit);
 }
 
-void NetworkClientRemotePlayer::on_position (NetworkPacket &pkt) {
-    Vector position = pkt.read_vector();
-    Vector velocity = pkt.read_vector();
-    uint8_t flags = pkt.read_uint8();
-
-    Engine::log(INFO, "client_player.on_position") << "obj=" << obj << ", position=" << position << ", velocity=" << velocity;
-    
-    // just update... 
-    updatePhysics(position, velocity, flags & NETWORK_PHYSICS_INAIR);
-}
-
-void NetworkClientRemotePlayer::on_quit (NetworkPacket &pkt) {
+void NetworkClientRemotePlayer::on_quit (NetworkPacketInput &pkt) {
     // pkt is empty
     (void) pkt;
 
@@ -143,3 +157,11 @@
     client.player_quit(this);
 }
 
+void NetworkClientRemotePlayer::_handleUpdate(Vector position, Vector velocity, bool inAir, bool facingRight, float aim) {
+    updatePhysics(position, velocity, inAir, facingRight, aim);
+}
+
+void NetworkClientRemotePlayer::_handleDig (Vector position, float radius) {
+    handleDig(position, radius);
+}
+
--- a/src/Network/Client.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Client.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -26,48 +26,57 @@
         NetworkClient (GameState &state, const NetworkAddress &connect_to);
 
     private:
-        void on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacket &pkt);
+        void on_create (NetworkObject_Client *obj, NetworkMessageID msg_id, NetworkPacketInput &pkt);
 
-        void on_server_hello (NetworkObject_Client *obj, NetworkPacket &pkt);
-        void on_player_info (NetworkObject_Client *obj, NetworkPacket &pkt);
-        void on_player_join (NetworkObject_Client *obj, NetworkPacket &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);
     
     public:
         void player_quit (NetworkClientRemotePlayer *player);
 };
 
-class NetworkClientLocalPlayer : public LocalPlayer {
-    private:
+class NetworkClientPlayerHelper {
+    protected:
         NetworkClient &client;
 
         CL_SlotContainer slots;
-        
+
         NetworkObject_Client *obj;
 
+    protected:
+        NetworkClientPlayerHelper (NetworkClient &client, NetworkObject_Client *obj);
+    
+    private:
+        void on_position (NetworkPacketInput &pkt);
+        void on_dig (NetworkPacketInput &pkt);
+
+    protected:
+        virtual void _handleUpdate (Vector position, Vector velocity, bool inAir, bool facingRight, float aim) = 0;
+        virtual void _handleDig (Vector position, float radius) = 0;
+};
+
+class NetworkClientLocalPlayer : public NetworkClientPlayerHelper, public LocalPlayer {
     public:
         NetworkClientLocalPlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position);
         
         virtual void handleMove (PlayerInput_Move input);
     
-    private:
-        void on_position (NetworkPacket &pkt);
+    protected:
+        virtual void _handleUpdate (Vector position, Vector velocity, bool inAir, bool facingRight, float aim);
+        virtual void _handleDig (Vector position, float radius);
 };
 
-class NetworkClientRemotePlayer : public RemotePlayer {
-    private:
-        NetworkClient &client;
-        
-        CL_SlotContainer slots;
-
-        NetworkObject_Client *obj;
-
+class NetworkClientRemotePlayer : public NetworkClientPlayerHelper, public RemotePlayer {
     public:
         NetworkClientRemotePlayer (NetworkClient &client, NetworkObject_Client *obj, Vector position);
     
     private:
-        void on_position (NetworkPacket &pkt);
-
-        void on_quit (NetworkPacket &pkt);
+        void on_quit (NetworkPacketInput &pkt);
+    
+    protected:
+        virtual void _handleUpdate (Vector position, Vector velocity, bool inAir, bool facingRight, float aim);
+        virtual void _handleDig (Vector position, float radius);
 };
 
 #endif
--- a/src/Network/Node.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Node.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -27,7 +27,7 @@
 //    delete this;
 }
 
-void NetworkNode::send (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable) {
+void NetworkNode::send (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable) {
     assert(channel_id > 0);
     
     // add our header
--- a/src/Network/Node.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Node.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -35,7 +35,7 @@
         CL_Signal_v0 _sig_disconnected;
 
     public:
-        void send (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable = true);
+        void send (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable = true);
 
         const NetworkAddress& getRemoteAddress (void);
         
--- a/src/Network/Object.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Object.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -13,7 +13,7 @@
     slot_message = session.sig_chan_message(channel_id).connect(this, &NetworkObjectController::on_message);
 }
 
-void NetworkObjectController::on_message (NetworkPacket &pkt, NetworkNode *node) {
+void NetworkObjectController::on_message (NetworkPacketInput &pkt, NetworkNode *node) {
     uint32_t obj_id = pkt.read_uint32();
     uint16_t msg_id = pkt.read_uint16();
     
@@ -40,7 +40,7 @@
     return ++id_pool;
 }
         
-void NetworkObject_ServerController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node) {
+void NetworkObject_ServerController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node) {
     (void) obj_id;
     (void) msg_id;
     (void) pkt;
@@ -59,7 +59,7 @@
 
 }
         
-void NetworkObject_ClientController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node) {
+void NetworkObject_ClientController::handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node) {
     // we only communicate with the server
     assert(node == server);
     
@@ -81,7 +81,7 @@
     controller.objects[obj_id] = this;
 }
         
-void NetworkObject::buildPacket (NetworkPacket &pkt, NetworkMessageID msg_id, const NetworkPacket &payload) {
+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);
@@ -99,11 +99,11 @@
     
 }
 
-void NetworkObject_Server::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt) {
+void NetworkObject_Server::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt) {
     _map_sig_message[msg_id](node, pkt);
 }
 
-void NetworkObject_Server::send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable) {
+void NetworkObject_Server::send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable) {
     NetworkPacket pkt_out;
 
     buildPacket(pkt_out, msg_id, pkt);
@@ -111,11 +111,11 @@
     dst->send(controller.channel_id, pkt_out, reliable);
 }
 
-void NetworkObject_Server::send_all (NetworkMessageID msg_id, const NetworkPacket &pkt, bool 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 NetworkPacket &pkt, NetworkNode *black_sheep, bool 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);
@@ -132,13 +132,13 @@
     // nothing
 }
 
-void NetworkObject_Client::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt) {
+void NetworkObject_Client::handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt) {
     assert(node == controller.server);
 
     _map_sig_message[msg_id](pkt);
 }
        
-void NetworkObject_Client::send (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable) {
+void NetworkObject_Client::send (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable) {
     NetworkPacket pkt_out;
 
     buildPacket(pkt_out, msg_id, pkt);
--- a/src/Network/Object.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Object.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -32,10 +32,10 @@
         NetworkObjectController (NetworkSession &session, NetworkChannelID channel_id);
     
     private:
-        void on_message (NetworkPacket &pkt, NetworkNode *node);
+        void on_message (NetworkPacketInput &pkt, NetworkNode *node);
 
     protected:
-        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node) = 0; 
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node) = 0; 
 };
 
 class NetworkObject_ServerController : public NetworkObjectController {
@@ -50,7 +50,7 @@
     protected:
         NetworkObjectID getObjectID (void);
 
-        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node);
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node);
 };
 
 class NetworkObject_ClientController : public NetworkObjectController {
@@ -59,16 +59,16 @@
     private:
         NetworkNode *server;
 
-        CL_Signal_v3<NetworkObject_Client*, NetworkMessageID, NetworkPacket&> _sig_create;
+        CL_Signal_v3<NetworkObject_Client*, NetworkMessageID, NetworkPacketInput&> _sig_create;
     
     public:
         NetworkObject_ClientController (NetworkSession &session, NetworkChannelID channel_id, NetworkNode *server);
 
     protected:
-        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacket &pkt, NetworkNode *node);
+        virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node);
     
     public:  
-        CL_Signal_v3<NetworkObject_Client*, NetworkMessageID, NetworkPacket&>& sig_create (void) { return _sig_create; }
+        CL_Signal_v3<NetworkObject_Client*, NetworkMessageID, NetworkPacketInput&>& sig_create (void) { return _sig_create; }
 };
 
 class NetworkObject {
@@ -81,9 +81,9 @@
     protected:
         NetworkObject (NetworkObjectController &controller, NetworkObjectID obj_id);
         
-        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt) = 0;
+        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt) = 0;
 
-        void buildPacket (NetworkPacket &pkt, NetworkMessageID msg_id, const NetworkPacket &payload);
+        void buildPacket (NetworkPacketOutput &pkt, NetworkMessageID msg_id, const NetworkPacketBuffer &payload);
 };
 
 std::ostream& operator<< (std::ostream &s, const NetworkObject &obj);
@@ -94,20 +94,20 @@
     private:
         NetworkObject_ServerController &controller;
 
-        std::map<NetworkMessageID, CL_Signal_v2<NetworkNode*, NetworkPacket&> > _map_sig_message;
+        std::map<NetworkMessageID, CL_Signal_v2<NetworkNode*, NetworkPacketInput&> > _map_sig_message;
 
     public:
         NetworkObject_Server (NetworkObject_ServerController &controller);
     
     protected:
-        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt);
+        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt);
 
     public:
-        void send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable = true);
-        void send_all (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable = true);
-        void send_all_except (NetworkMessageID msg_id, const NetworkPacket &pkt, NetworkNode *black_sheep, bool reliable = true);
+        void send_to (NetworkNode *dst, NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable = true);
+        void send_all (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable = true);
+        void send_all_except (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, NetworkNode *black_sheep, bool reliable = true);
     
-        CL_Signal_v2<NetworkNode*, NetworkPacket&>& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; }
+        CL_Signal_v2<NetworkNode*, NetworkPacketInput&>& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; }
 };
 
 class NetworkObject_Client : public NetworkObject {
@@ -116,17 +116,17 @@
     private:
         NetworkObject_ClientController &controller;
 
-        std::map<NetworkMessageID, CL_Signal_v1<NetworkPacket&> > _map_sig_message;
+        std::map<NetworkMessageID, CL_Signal_v1<NetworkPacketInput&> > _map_sig_message;
 
     protected:
         NetworkObject_Client (NetworkObject_ClientController &controller, NetworkObjectID id);
         
-        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacket &pkt);
+        virtual void handle_packet (NetworkNode *node, NetworkMessageID msg_id, NetworkPacketInput &pkt);
 
     public:
-        void send (NetworkMessageID msg_id, const NetworkPacket &pkt, bool reliable = true);
+        void send (NetworkMessageID msg_id, const NetworkPacketBuffer &pkt, bool reliable = true);
         
-        CL_Signal_v1<NetworkPacket&>& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; }
+        CL_Signal_v1<NetworkPacketInput&>& sig_message (NetworkMessageID msg_id) { return _map_sig_message[msg_id]; }
 };
 
 #endif /* NETWORK_OBJECT_HH */
--- a/src/Network/Packet.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Packet.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -4,48 +4,10 @@
 
 #include "Packet.hh"
 
-
-NetworkPacket::NetworkPacket (void) :
-    buf_size(NETWORK_PACKET_SIZE), data_size(0), offset(0) {
-    
-    // nothing
-}
-
-void NetworkPacket::check_write_size (size_t item_size) {
-     if (offset + item_size > buf_size)
-        throw NetworkPacketError("not enough space to write");
-
-}
-        
-void NetworkPacket::check_read_size (size_t item_size) {
-    if (offset + item_size > data_size)
-        throw NetworkPacketError("not enough data to read");
-}
-
-void NetworkPacket::write (const void *ptr, size_t len) {
-    // check buffer overflow
-    check_write_size(len);
-
-    // set value
-    memcpy(buf + offset, ptr, len);
-
-    // update offset and size
-    offset += len;
-    data_size += len;
-}
-
-void NetworkPacket::read (void *ptr, size_t len) {
-    // check buffer underflow
-    check_read_size(len);
-
-    // set value
-    memcpy(ptr, buf + offset, len);
-
-    // update offset
-    offset += len;
-}
-
-template <typename T> T NetworkPacket::read_val (void) {
+/*
+ * NetworkPacketInput
+ */
+template <typename T> T NetworkPacketInput::read_val (void) {
     T val;
 
     // read
@@ -55,90 +17,150 @@
     return val;
 }
 
-template <typename T> void NetworkPacket::write_val (const T &val) {
-    // write
-    write(&val, sizeof(T));
-}
-
-uint32_t NetworkPacket::read_uint32 (void) {
+uint32_t NetworkPacketInput::read_uint32 (void) {
     return ntohl(read_val<uint32_t>());
 }
 
-uint16_t NetworkPacket::read_uint16 (void) {
+uint16_t NetworkPacketInput::read_uint16 (void) {
     return ntohs(read_val<uint16_t>());
 }
 
-uint8_t NetworkPacket::read_uint8 (void) {
+uint8_t NetworkPacketInput::read_uint8 (void) {
     return read_val<uint8_t>();
 }
 
-int32_t NetworkPacket::read_int32 (void) {
+int32_t NetworkPacketInput::read_int32 (void) {
     return ntohl(read_val<int32_t>());
 }
 
-int16_t NetworkPacket::read_int16 (void) {
+int16_t NetworkPacketInput::read_int16 (void) {
     return ntohs(read_val<int16_t>());
 }
 
-int8_t NetworkPacket::read_int8 (void) {
+int8_t NetworkPacketInput::read_int8 (void) {
     return read_val<int8_t>();
 }
         
-float NetworkPacket::read_float32 (void) {
+float NetworkPacketInput::read_float32 (void) {
     int32_t ival = read_int32();
 
     return *((float *) &ival);
 }
 
-Vector NetworkPacket::read_vector (void) {
+Vector NetworkPacketInput::read_vector (void) {
     float fx = read_float32();
     float fy = read_float32();
 
     return Vector(fx, fy);
 }
 
-void NetworkPacket::write_uint32 (uint32_t val) {
+/*
+ * NetworkPacketOutput
+ */
+template <typename T> void NetworkPacketOutput::write_val (const T &val) {
+    // write
+    write(&val, sizeof(T));
+}
+
+
+void NetworkPacketOutput::write_uint32 (uint32_t val) {
     write_val<uint32_t>(htonl(val));
 }
 
-void NetworkPacket::write_uint16 (uint16_t val) {
+void NetworkPacketOutput::write_uint16 (uint16_t val) {
     write_val<uint16_t>(htons(val));
 }
 
-void NetworkPacket::write_uint8 (uint8_t val) {
+void NetworkPacketOutput::write_uint8 (uint8_t val) {
     write_val<uint8_t>(val);
 }
 
-void NetworkPacket::write_int32 (int32_t val) {
+void NetworkPacketOutput::write_int32 (int32_t val) {
     write_val<int32_t>(htonl(val));
 }
 
-void NetworkPacket::write_int16 (int16_t val) {
+void NetworkPacketOutput::write_int16 (int16_t val) {
     write_val<int16_t>(htons(val));
 }
 
-void NetworkPacket::write_int8 (int8_t val) {
+void NetworkPacketOutput::write_int8 (int8_t val) {
     write_val<int8_t>(val);
 }
         
-void NetworkPacket::write_float32 (float val) {
+void NetworkPacketOutput::write_float32 (float val) {
     write_int32(*((int32_t *) &val));
 }
 
-void NetworkPacket::write_vector (const Vector &vec) {
+void NetworkPacketOutput::write_vector (const Vector &vec) {
     write_float32(vec.x);
     write_float32(vec.y);
 }
 
-void NetworkPacket::write_packet (const NetworkPacket &pkt) {
-    // check buffer size
-    check_write_size(pkt.get_data_size());
-
-    // copy
-    memcpy(buf + offset, pkt.get_buf(), pkt.get_data_size());
-
-    // update offset/data_size
-    offset += pkt.get_data_size();
-    data_size += pkt.get_data_size();
+void NetworkPacketOutput::write_packet (const NetworkPacketBuffer &pkt) {
+    // just write() it
+    write(pkt.get_buf(), pkt.get_data_size());
 }
 
+/*
+ * NetworkPacketBuffer
+ */
+NetworkPacketBuffer::NetworkPacketBuffer (char *buf_ptr, size_t buf_size, size_t data_size) :
+    buf_ptr(buf_ptr), buf_size(buf_size), data_size(data_size), offset(0) {
+    
+    // nothing
+    if (buf_ptr == NULL)
+        throw NetworkPacketError("buf_ptr may not be NULL");
+}
+
+void NetworkPacketBuffer::check_write_size (size_t item_size) {
+     if (offset + item_size > buf_size)
+        throw NetworkPacketError("not enough space to write");
+
+}
+        
+void NetworkPacketBuffer::check_read_size (size_t item_size) {
+    if (offset + item_size > data_size)
+        throw NetworkPacketError("not enough data to read");
+}
+
+void NetworkPacketBuffer::write (const void *ptr, size_t len) {
+    // check buffer overflow
+    check_write_size(len);
+
+    // set value
+    memcpy(buf_ptr + offset, ptr, len);
+
+    // update offset and size
+    offset += len;
+    data_size += len;
+}
+
+void NetworkPacketBuffer::read (void *ptr, size_t len) {
+    // check buffer underflow
+    check_read_size(len);
+
+    // set value
+    memcpy(ptr, buf_ptr + offset, len);
+
+    // update offset
+    offset += len;
+}
+
+/*
+ * NetworkPacket
+ */
+NetworkPacket::NetworkPacket (void) : 
+    NetworkPacketBuffer(_buf, NETWORK_PACKET_SIZE, 0) 
+{ 
+    
+}
+
+/*
+ * BigNetworkPacket
+ */
+BigNetworkPacket::BigNetworkPacket (size_t size) :
+    NetworkPacketBuffer((char *) malloc(size), size, 0)
+{
+
+}
+
--- a/src/Network/Packet.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Packet.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -10,32 +10,25 @@
         NetworkPacketError (const std::string &message) : Error(message) { }
 };
 
-class NetworkPacket {
-    private:
-        char buf[NETWORK_PACKET_SIZE];
-        size_t buf_size, data_size, offset;
-        
-        void check_write_size (size_t item_size);
-        void check_read_size (size_t item_size);
+// forward-declare for write_packet
+class NetworkPacketBuffer;
 
-        template <typename T> T read_val (void);
-        template <typename T> void write_val (const T &val);
- 
+/*
+ * Read-interface for network packets
+ */
+class NetworkPacketInput {
     public:
-        NetworkPacket (void);
-        
-        char* get_buf (void) { return buf; }
-        const char* get_buf (void) const { return buf; }
-        size_t get_data_size (void) const { return data_size; }
-        size_t get_buf_size (void) const { return buf_size; }
+        /*
+         * Copies len bytes from the packet to ptr, first testing that they exist
+         */
+        virtual void read (void *ptr, size_t len) = 0;
+       
+        /*
+         * Convenience function to read() and return the value of the given type
+         */
+        template <typename T> T read_val (void);
 
-        void set_data_size (size_t size) { offset = 0; data_size = size; }
-
-        // raw
-        void write (const void *ptr, size_t len);
-        void read (void *ptr, size_t len);
-       
-        // type-reads, handle network-endianlness
+        // thse handle network-endianlness
         uint32_t read_uint32 (void);
         uint16_t read_uint16 (void);
         uint8_t read_uint8 (void);
@@ -45,8 +38,26 @@
         int8_t read_int8 (void);
         
         float read_float32 (void);
+        
+        Vector read_vector (void);
+};
 
+/*
+ * Write-interface for network packets
+ */
+class NetworkPacketOutput {
+    public:    
+        /*
+         * Copies len bytes from ptr to the packet, first testing that they fit
+         */
+        virtual void write (const void *ptr, size_t len) = 0;
 
+        /*
+         * Convenience function to write() the value of the given type-value
+         */
+        template <typename T> void write_val (const T &val);
+
+        // thse handle network-endianlness
         void write_uint32 (uint32_t val);
         void write_uint16 (uint16_t val);
         void write_uint8 (uint8_t val);
@@ -57,10 +68,85 @@
         
         void write_float32 (float val);
 
-        // complex
-        Vector read_vector (void);
         void write_vector (const Vector &vec);
-        void write_packet (const NetworkPacket &pkt);
+        
+        /*
+         * This copies the contents of the given packet into this packet
+         */
+        void write_packet (const NetworkPacketBuffer &pkt);
+};
+
+/*
+ * Implements the in-memory seekable buffer used by NetworkPackets.
+ */
+class NetworkPacketBuffer : public NetworkPacketInput, public NetworkPacketOutput {
+    protected:
+        // the pointer to the buffer
+        char *buf_ptr;
+        
+        // the buffer size, the amount of data in the buffer, and the current read/write offset
+        size_t buf_size, data_size, offset;
+        
+        /*
+         * Assert that the given number of bytes fits into the buffer. Throws NetworkPacketError if not.
+         *
+         * The default implementation just checks offset and buf_size
+         */
+        virtual void check_write_size (size_t item_size);
+
+        /*
+         * Assert that the give number of bytes is available from the buffer. Throws NetworkPacketError if not
+         *
+         * The default implementation just checks offset and data_size
+         */
+        virtual void check_read_size (size_t item_size);
+         
+    public:
+        /*
+         * Construct the NetworkPacketBuffer using the given initial buf_ptr and buf_size
+         */
+        NetworkPacketBuffer (char *buf_ptr, size_t buf_size, size_t data_size);
+        
+        /*
+         * These memcpy() into/out of the buf_ptr, using ceck_read/write_size
+         */
+        virtual void read (void *ptr, size_t len);
+        virtual void write (const void *ptr, size_t len);
+
+        /*
+         * Accessor functions, used by the actual socket code to read/write the buffer
+         */
+        char* get_buf (void) { return buf_ptr; }
+        const char* get_buf (void) const { return buf_ptr; }
+        size_t get_data_size (void) const { return data_size; }
+        size_t get_buf_size (void) const { return buf_size; }
+        
+        /*
+         * Used by the socket code after recv() to mark how many bytes of data the buffer has
+         */
+        void set_data_size (size_t size) { offset = 0; data_size = size; }
+};
+
+/*
+ * The common case is a packet that fits in a single UDP packet, so this just uses a static buffer of a fixed size,
+ * NETWORK_PACKET_SIZE.
+ */
+class NetworkPacket : public NetworkPacketBuffer {
+    private:
+        char _buf[NETWORK_PACKET_SIZE];
+
+    public:
+        NetworkPacket (void);
+};
+
+/*
+ * This is intended for sending bigger packets via TCP; the buffer is allocated on the heap.
+ *
+ * XXX: let the buffer grow as well
+ */
+class BigNetworkPacket : public NetworkPacketBuffer {
+    public:
+        BigNetworkPacket (size_t size);
 };
 
 #endif /* NETWORK_PACKET_HH */
--- a/src/Network/Protocol.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Protocol.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -14,44 +14,45 @@
 
 enum NetworkPhysicsFlags {
     NETWORK_PHYSICS_INAIR      = 0x01,
+    NETWORK_PHYSICS_FACE_RIGHT = 0x02,
 };
 
 enum NetworkMessage {
-    NETMSG_PACKET_INVALID   = 0x00,
+    NETMSG_PACKET_INVALID   = 0x0000,
 
     /*
      * You have joined the game:
      *
      *  Vector      initial_position
      */
-    NETMSG_SERVER_HELLO = 0x0100,
+    NETMSG_SERVER_HELLO     = 0x0100,
 
     /*
      * New client has connected to server:
      *  
      *  Vector      initial_position
      */
-    NETMSG_PLAYER_JOIN  = 0x0101,
+    NETMSG_PLAYER_JOIN      = 0x0101,
 
     /*
      * Client has left server:
      *
      */
-    NETMSG_PLAYER_QUIT  = 0x0102,
+    NETMSG_PLAYER_QUIT      = 0x0102,
 
     /*
      * Client has moved
      *
      *  uint16_t    PlayerInput_Move
      */
-    NETMSG_CLIENT_MOVE  = 0x0201,
+    NETMSG_CLIENT_MOVE      = 0x0201,
     
     /*
      * Initial player info
      *
      *  Vector      initial_position
      */
-    NETMSG_PLAYER_INFO  = 0x0300,
+    NETMSG_PLAYER_INFO      = 0x0300,
 
     /*
      * Player position update
@@ -59,8 +60,17 @@
      * Vector   position
      * Vector   velocity
      * uint8_t  NetworkPhysicsFlags
+     * float32  aim
      */
     NETMSG_PLAYER_POSITION  = 0x0301,
+
+    /*
+     * Terrain update, removeGround
+     *
+     * Vector   position 
+     * float32  radius          
+     */
+    NETMSG_PLAYER_DIG       = 0x0302,
 };
 
 #endif
--- a/src/Network/Server.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Server.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -71,6 +71,21 @@
     obj.send_all_except(NETMSG_PLAYER_JOIN, hello_pkt, node, true);
 }
 
+void NetworkServerPlayer::handleDig (Vector position, float radius) {
+    NetworkPacket pkt;
+
+    pkt.write_vector(position);
+    pkt.write_float32(radius);
+
+    Engine::log(INFO, "server_player.handle_dig") << "position=" << position << ", radius=" << radius;
+    
+    // tell everyone... make this reliable... 
+    obj.send_all(NETMSG_PLAYER_DIG, pkt, true);
+
+    // and carry out the actual dig on the server as well
+    Player::handleDig(position, radius);
+}
+
 void NetworkServerPlayer::on_disconnected (void) {
     NetworkPacket pkt;
     
@@ -86,7 +101,7 @@
 //    delete this;
 }
 
-void NetworkServerPlayer::on_move (NetworkNode *src, NetworkPacket &pkt) {
+void NetworkServerPlayer::on_move (NetworkNode *src, NetworkPacketInput &pkt) {
     // sanity-check, other players shouldn't move
     if (src != node) {
         Engine::log(WARN, "server_player.on_move") << "packet from wrong src=" << src << ", node=" << node;
@@ -106,11 +121,15 @@
         
 void NetworkServerPlayer::send_position_update (void) {
     NetworkPacket pkt;
+    
+    int flags = (inAir & NETWORK_PHYSICS_INAIR) | (facingRight & NETWORK_PHYSICS_FACE_RIGHT);
+
     pkt.write_vector(position);
     pkt.write_vector(velocity);
-    pkt.write_uint8(inAir & NETWORK_PHYSICS_INAIR);
+    pkt.write_uint8(flags);
+    pkt.write_float32(aim);
 
-    Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position << "+" << velocity;
+    Engine::log(INFO, "server_player.send_position_update") << "obj=" << obj << " -> " << position << "+" << velocity << " [" << flags << "]";
 
     obj.send_all(NETMSG_PLAYER_POSITION, pkt, false);
 }
--- a/src/Network/Server.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Server.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -44,9 +44,11 @@
     public:
         NetworkServerPlayer (NetworkServer &server, NetworkNode *node);
 
+        virtual void handleDig (Vector position, float radius);
+
     private:
         void on_disconnected (void);
-        void on_move (NetworkNode *node, NetworkPacket &pkt);
+        void on_move (NetworkNode *node, NetworkPacketInput &pkt);
 
         void send_position_update (void);
 };
--- a/src/Network/Session.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Session.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -58,7 +58,7 @@
     nodes.erase(node->getRemoteAddress());
 }
         
-void NetworkSession::handle_message (NetworkPacket &pkt, NetworkNode *node) {
+void NetworkSession::handle_message (NetworkPacketInput &pkt, NetworkNode *node) {
     // read the channel id
     NetworkChannelID channel_id = pkt.read_uint16();
 
@@ -80,7 +80,7 @@
     _sig_node_connected(client_node);
 }
         
-void NetworkSession::on_udp_packet (NetworkPacket &pkt, const NetworkAddress &addr) {
+void NetworkSession::on_udp_packet (NetworkPacketInput &pkt, const NetworkAddress &addr) {
     NetworkNode *node = nodes[addr];
     
     // drop from unknown sources
@@ -93,11 +93,11 @@
     handle_message(pkt, node);
 }
        
-void NetworkSession::send_all (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable) {
+void NetworkSession::send_all (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable) {
     send_all_except(channel_id, pkt, NULL, reliable);
 }
         
-void NetworkSession::send_all_except (NetworkChannelID channel_id, const NetworkPacket &pkt, const NetworkNode *node, bool reliable) {
+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;
--- a/src/Network/Session.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/Session.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -27,7 +27,7 @@
         CL_SlotContainer slots;
 
         std::map<NetworkAddress, NetworkNode*> nodes;
-        std::map<NetworkChannelID, CL_Signal_v2<NetworkPacket&, NetworkNode *> > _map_sig_chan_message;
+        std::map<NetworkChannelID, CL_Signal_v2<NetworkPacketInput&, NetworkNode *> > _map_sig_chan_message;
     
     public:
         NetworkSession (uint64_t magic);
@@ -39,20 +39,20 @@
         virtual NetworkNode *build_node (NetworkTCPTransport *tcp, NetworkUDP *udp, const NetworkAddress &addr, enum NetworkNodeType type);
         
         void handle_disconnect (NetworkNode *node);
-        void handle_message (NetworkPacket &pkt, NetworkNode *node);
+        void handle_message (NetworkPacketInput &pkt, NetworkNode *node);
 
     private:
         void on_tcp_client (NetworkTCPTransport *client);
-        void on_udp_packet (NetworkPacket &pkt, const NetworkAddress &addr);
+        void on_udp_packet (NetworkPacketInput &pkt, const NetworkAddress &addr);
 
         CL_Signal_v1<NetworkNode*> _sig_node_connected;
 
     public:
-        void send_all (NetworkChannelID channel_id, const NetworkPacket &pkt, bool reliable = true);
-        void send_all_except (NetworkChannelID channel_id, const NetworkPacket &pkt, const NetworkNode *node, bool reliable = true);
+        void send_all (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, bool reliable = true);
+        void send_all_except (NetworkChannelID channel_id, const NetworkPacketBuffer &pkt, const NetworkNode *node, bool reliable = true);
 
         CL_Signal_v1<NetworkNode*>& sig_node_connected (void) { return _sig_node_connected; }
-        CL_Signal_v2<NetworkPacket&, NetworkNode *>& sig_chan_message (NetworkChannelID cid) { return _map_sig_chan_message[cid]; }
+        CL_Signal_v2<NetworkPacketInput&, NetworkNode *>& sig_chan_message (NetworkChannelID cid) { return _map_sig_chan_message[cid]; }
 };
 
 #endif /* NETWORK_SESSION_HH */
--- a/src/Network/TCP.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/TCP.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -2,236 +2,9 @@
 #include "TCP.hh"
 #include "../Engine.hh"
 
-#include <cstdlib>
-#include <cassert>
-
-NetworkBuffer::NetworkBuffer (NetworkSocket &socket, size_t size_hint) :
-    socket(socket), buf(0), size(0), offset(0) {
-    
-    // allocate initial buffer
-    if ((buf = (char *) malloc(size_hint)) == NULL)
-       throw NetworkBufferError("malloc failed");
-    
-    // remember size
-    size = size_hint;
-}
-        
-NetworkBuffer::~NetworkBuffer (void) {
-    free(buf);
-}
-
-void NetworkBuffer::resize (size_t item_size) {
-    size_t new_size = size;
-
-    // grow new_size until item_size fits
-    while (offset + item_size > new_size)
-        new_size *= 2;
-    
-    // grow if needed
-    if (new_size != size) {
-        // realloc buffer
-        if ((buf = (char *) realloc((void *) buf, new_size)) == NULL)
-            throw NetworkBufferError("realloc failed");
-
-        // update size
-        size = new_size;
-
-    } else if (new_size > (offset + item_size) * 4) {
-        // XXX: shrink?
-    }
-}
-        
-void NetworkBuffer::trim (size_t prefix_size) {
-    // update offset
-    offset -= prefix_size;
-
-    // shift the buffer forwards from (buf + prefix) -> (buf), copying (old_offset - prefix) bytes
-    memmove(buf, buf + prefix_size, offset);
-}
-     
-bool NetworkBuffer::try_read (size_t item_size) {
-    int ret;
-    size_t to_read = item_size;
-
-    // keept reads at at least NETWORK_CHUNK_SIZE bytes
-    if (to_read < NETWORK_TCP_CHUNK_SIZE)
-        to_read = NETWORK_TCP_CHUNK_SIZE;
-
-    // resize buffer if needed
-    resize(to_read);
-
-    // read once
-    try {
-        ret = socket.recv(buf + offset, to_read);
-
-    } catch (CL_Error &e) {
-        if (errno == EAGAIN)
-            return false;
-
-        else
-            throw NetworkSocketOSError(socket, "recv");
-    }
-    
-    // handle EOF
-    if (ret == 0)
-        throw NetworkSocketEOFError(socket, "recv");
-
-    assert(ret >= 0);
-
-    // update offset
-    offset += ret;
-
-    // did we get enough?
-    if ((unsigned int) ret < item_size)
-        return false;
-    else
-        return true;
-} 
-        
-bool NetworkBuffer::peek_prefix (uint16_t &ref) {
-    if (offset < sizeof(uint16_t))
-        return false;
-
-    ref = ntohs(*((uint16_t *) (buf)));
-
-    return true;
-}
-    
-bool NetworkBuffer::peek_prefix (uint32_t &ref) {
-    if (offset < sizeof(uint32_t))
-        return false;
-
-    ref = ntohl(*((uint32_t *) (buf)));
-
-    return true;
-}
-
-template <typename PrefixType> PrefixType NetworkBuffer::read_prefix (char *buf_ptr, size_t buf_max) {
-    PrefixType prefix = 0;
-    size_t missing = 0;
-    
-    do {    
-        // do we have the prefix?
-        if (peek_prefix(prefix)) {
-            // do we already have the payload?
-            if (offset >= sizeof(PrefixType) + prefix) {
-                break;
-
-            } else {
-                missing = (sizeof(PrefixType) + prefix) - offset;
-            }
-
-        } else {
-            missing = sizeof(PrefixType);
-        }
-
-        // sanity-check
-        assert(missing);
-        
-        // try and read the missing data
-        if (try_read(missing) == false) {
-            // if unable to read what we need, return zero.
-            return 0;
-        }
-        
-        // assess the situation again
-    } while (true);
-    
-    // copy the data over, unless it's too large
-    if (prefix <= buf_max) {
-        // ...don't copy the prefix, though
-        memcpy(buf_ptr, buf + sizeof(PrefixType), prefix);
-    
-        // trim the bytes out
-        trim(sizeof(PrefixType) + prefix);
-        
-        // return
-        return prefix;
-
-    } else {
-        // trim the bytes out
-        trim(sizeof(PrefixType) + prefix);
-        
-        throw NetworkBufferError("recv prefix overflow");   
-    }
-}
-   
-void NetworkBuffer::push_write (char *buf_ptr, size_t buf_size) {
-    int ret;
-
-    // try and short-circuit writes unless we have already buffered data
-    if (offset == 0) {
-        try {
-            // attempt to send something
-            ret = socket.send(buf_ptr, buf_size);
-
-        } catch (CL_Error &e) {
-            // ignore EAGAIN, detect this by setting ret to -1
-            if (errno != EAGAIN)
-                throw NetworkSocketOSError(socket, "send");
-
-            ret = -1;
-        }
-        
-        // if we managed to send something, adjust buf/size and buffer
-        if (ret > 0) {
-            // sanity-check
-            assert(buf_size >= (unsigned int) ret);
-
-            buf_ptr += ret;
-            buf_size -= ret;
-
-            // if that was all, we're done
-            if (buf_size == 0)
-                return;
-        }
-    }
-    
-    // resize to fit buf_size more bytes
-    resize(buf_size);
-    
-    // copy into our internal buffer
-    memcpy(buf + offset, buf_ptr, buf_size);
-}
-        
-void NetworkBuffer::flush_write (void) {
-    int ret;
-
-    // ignore if we don't have any data buffered
-    if (offset == 0)
-        return;
-    
-    // attempt to write as much as possible
-    try {
-        ret = socket.send(buf, offset);
-
-    } catch (CL_Error &e) {
-        // ignore EAGAIN and just return
-        if (errno == EAGAIN)
-            return;
-
-        else
-            throw NetworkSocketOSError(socket, "send");
-    }
-
-    // trim the buffer
-    trim(ret);
-}
-        
-void NetworkBuffer::write_prefix (char *buf, uint16_t prefix) {
-    uint16_t nval = htons(prefix);
-
-    push_write((char*) &nval, sizeof(uint16_t)); 
-    push_write(buf, prefix);
-}
-
-void NetworkBuffer::write_prefix (char *buf, uint32_t prefix) {
-    uint32_t nval = htonl(prefix);
-
-    push_write((char*) &nval, sizeof(uint32_t)); 
-    push_write(buf, prefix);
-}
-
+/*
+ * NetworkTCPTransport
+ */
 NetworkTCPTransport::NetworkTCPTransport (NetworkSocket socket) :
     socket(socket), in(socket, NETWORK_TCP_INITIAL_IN_BUF), out(socket, NETWORK_TCP_INITIAL_OUT_BUF) {
     
@@ -243,13 +16,19 @@
 
 
 void NetworkTCPTransport::on_read (void) {
-    uint16_t prefix;
-    NetworkPacket packet;
+    uint16_t length;
+    char *buf_ptr;
     
     // let the in stream read length-prefixed packets and pass them on to handle_packet
-    while ((prefix = in.read_prefix<uint16_t>(packet.get_buf(), packet.get_buf_size())) > 0) {
-        packet.set_data_size(prefix);
+    while (in.peek_data<uint16_t>(length, buf_ptr)) {
+        // allocate the NetworkPacketBuffer with the given buf_ptr/length
+        NetworkPacketBuffer packet(buf_ptr, length, length);
+        
+        // pass the packet on
         _sig_packet(packet);
+
+        // flush it
+        in.flush_data<uint16_t>();
     }
 }
 
@@ -263,7 +42,7 @@
     _sig_disconnect();
 }
         
-void NetworkTCPTransport::write_packet (const NetworkPacket &packet) {
+void NetworkTCPTransport::write_packet (const NetworkPacketBuffer &packet) {
     uint16_t prefix = packet.get_data_size();
     
     if (prefix != packet.get_data_size())
--- a/src/Network/TCP.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/TCP.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -6,52 +6,17 @@
 #include "Socket.hh"
 #include "Address.hh"
 #include "Packet.hh"
-#include "../Error.hh"
+#include "Buffer.hh"
 
-const size_t NETWORK_TCP_CHUNK_SIZE = 1024;
 const size_t NETWORK_TCP_INITIAL_IN_BUF = 4096;
 const size_t NETWORK_TCP_INITIAL_OUT_BUF = 0;
 
-class NetworkBufferError : public Error {
-    public:
-        NetworkBufferError (const std::string &message) : Error(message) { }
-};
-
-class NetworkBuffer {
-    private:
-        NetworkSocket socket;
-
-        char *buf;
-        size_t size, offset;
-    
-    public:
-        NetworkBuffer (NetworkSocket &socket, size_t size_hint);
-        ~NetworkBuffer (void);
-    
-    private:
-        NetworkBuffer (const NetworkBuffer &copy);
-        NetworkBuffer& operator= (const NetworkBuffer &copy);
-
-        void resize (size_t item_size);
-        void trim (size_t prefix_size);
-
-    public:    
-        void push_write (char *buf_ptr, size_t buf_size);
-        void flush_write (void);
-        void write_prefix (char *buf, uint16_t prefix);
-        void write_prefix (char *buf, uint32_t prefix);
-        
-        bool try_read (size_t item_size);
-        bool peek_prefix (uint16_t &ref);
-        bool peek_prefix (uint32_t &ref);
-        template <typename PrefixType> PrefixType read_prefix (char *buf_ptr, size_t buf_max);
-};
-
 class NetworkTCPTransport {
     protected:
         NetworkSocket socket;
 
-        NetworkBuffer in, out;
+        NetworkBufferInput in;
+        NetworkBufferOutput out;
     
         CL_SlotContainer slots; 
     
@@ -63,16 +28,16 @@
         void on_write (void);
         void on_disconnected (void);
 
-        CL_Signal_v1<NetworkPacket &> _sig_packet;
+        CL_Signal_v1<NetworkPacketInput&> _sig_packet;
         CL_Signal_v0 _sig_disconnect;
 
     public:
         NetworkAddress getLocalAddress (void) { return socket.get_source_address(); }
         NetworkAddress getRemoteAddress (void) { return socket.get_dest_address(); }
 
-        void write_packet (const NetworkPacket &packet);
+        void write_packet (const NetworkPacketBuffer &packet);
         
-        CL_Signal_v1<NetworkPacket&>& sig_packet (void) { return _sig_packet; }
+        CL_Signal_v1<NetworkPacketInput&>& sig_packet (void) { return _sig_packet; }
         CL_Signal_v0& sig_disconnect (void) { return _sig_disconnect; }
 };
 
--- a/src/Network/UDP.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Network/UDP.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -18,12 +18,12 @@
     private:
         void on_recv (void);
 
-        CL_Signal_v2<NetworkPacket &, const NetworkAddress&> _sig_packet;
+        CL_Signal_v2<NetworkPacketInput&, const NetworkAddress&> _sig_packet;
 
     public:
         bool sendto (const NetworkPacket &packet, const NetworkAddress &dst);
         
-        CL_Signal_v2<NetworkPacket &, const NetworkAddress&>& sig_packet (void) { return _sig_packet; }
+        CL_Signal_v2<NetworkPacketInput&, const NetworkAddress&>& sig_packet (void) { return _sig_packet; }
 };
 
 #endif /* NETWORK_UDP_HH */
--- a/src/PhysicsObject.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/PhysicsObject.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -306,12 +306,14 @@
     this->facingRight = facingRight;
 }
 
-void PhysicsObject::updatePhysics (Vector position, Vector velocity, bool inAir) {
+void PhysicsObject::updatePhysics (Vector position, Vector velocity, bool inAir, bool facingRight, float aim) {
     this->position = position;
     this->velocity = velocity;
     this->inAir = inAir;
+    this->facingRight = facingRight;
+    this->aim = aim;
 }
-    
+   
 Vector PhysicsObject::getPosition () {
     return this->position;
 }
--- a/src/PhysicsObject.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/PhysicsObject.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -83,8 +83,10 @@
      * @param position New position
      * @param velocity New velocity
      * @param inAir New inAir value
+     * @param facingRight New facingRight value
+     * @param aim New aim
      */
-    void updatePhysics(Vector position, Vector velocity, bool inAir);
+    virtual void updatePhysics(Vector position, Vector velocity, bool inAir, bool facingRight, float aim);
 
 private:
     // TODO: I'd be tempted to use some already made ClanLib structure
--- a/src/Player.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Player.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -64,7 +64,7 @@
         // But this now just segfaults
 //        world.addObject(new Shot(state, position, true));
 
-        world.removeGround(position, 15);
+        handleDig(position, 15);
     }
 
     if (input & INPUT_SHOOT) {
@@ -85,6 +85,10 @@
 
 }
 
+void Player::handleDig (Vector position, float radius) {
+    world.removeGround(position, radius);
+}
+
 void Player::debugInfo (void) {
     Engine::log(DEBUG, "Player.debugInfo") << "In air: " << this->inAir;
 }
--- a/src/Player.hh	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Player.hh	Thu Dec 04 21:59:23 2008 +0000
@@ -18,6 +18,7 @@
     
     void debugInfo ();
     virtual void handleMove (PlayerInput_Move input);
+    virtual void handleDig (Vector position, float radius);
     void shoot (void);
 
 };
--- a/src/Projectile.cc	Thu Dec 04 21:10:41 2008 +0000
+++ b/src/Projectile.cc	Thu Dec 04 21:59:23 2008 +0000
@@ -1,7 +1,7 @@
 #include "Projectile.hh"
 
 Shot::Shot(GameState &state, Vector position, Vector velocity, bool visible) :
-    PhysicsObject((PhysicsWorld &) state, PLAYER_MASS, position, velocity), state(state), visible(visible), destroyed(false) {
+    PhysicsObject(state.world, PLAYER_MASS, position, velocity), state(state), visible(visible), destroyed(false) {
     // Looks kind of dumb, for ammunition to have shape
     std::vector<Vector> shape(4);
     shape[0] = Vector(-1, -1);