dirty implementation of compressed terrain array data
authorterom
Mon, 22 Dec 2008 02:37:43 +0000
changeset 387 294ce7ae8140
parent 386 2f019ecb4aa9
child 388 ecb243eebc25
dirty implementation of compressed terrain array data
src/Network/Client.cc
src/Network/Packet.cc
src/Network/Packet.hh
src/Network/Server.cc
--- a/src/Network/Client.cc	Mon Dec 22 02:37:28 2008 +0000
+++ b/src/Network/Client.cc	Mon Dec 22 02:37:43 2008 +0000
@@ -6,6 +6,7 @@
 #include "../Logger.hh"
 
 #include <cassert>
+#include <zlib.h>
 
 NetworkClient::NetworkClient (Engine &engine, GameState &state, const NetworkEndpoint &connect_to) : 
     engine(engine), state(state), netsession(NETWORK_MAGIC_ID), server(netsession.connect(connect_to)),
@@ -29,14 +30,30 @@
     Terrain &terrain = state.world;
 
     // read map width/height
-    // XXX: over 2**31?
     PixelDimension map_w = pkt.read_uint32();
     PixelDimension map_h = pkt.read_uint32();
 
-    // read map data
+    // the terrain byte array
+    size_t terrain_size = map_w * map_h;
+    uint8_t terrain_buf[map_w][map_h];
+    
+    // compressed packet data
+    unsigned long inflate_size = terrain_size;
+    unsigned long deflate_size = pkt.tell_remaining();
+    const uint8_t *deflate_ptr = (const uint8_t *) pkt.read_ptr(deflate_size);
+    
+    // uncompress the rest of the packet data
+    if (uncompress((uint8_t *) terrain_buf, &inflate_size, deflate_ptr, deflate_size) != Z_OK)
+        throw Error("uncompress");
+
+    // invalid data?
+    if (inflate_size != terrain_size)
+        throw Error("Corrupt terrain data");
+
+    // translate map data to terrain vector
     for (PixelDimension x = 0; x < map_w; x++) {
         for (PixelDimension y = 0; y < map_h; y++) {
-            terrain.terrain[x][y] = (TerrainType) pkt.read_uint8();
+            terrain.terrain[x][y] = (TerrainType) terrain_buf[x][y];
         }
     }
 
--- a/src/Network/Packet.cc	Mon Dec 22 02:37:28 2008 +0000
+++ b/src/Network/Packet.cc	Mon Dec 22 02:37:43 2008 +0000
@@ -135,28 +135,55 @@
     if (offset + item_size > data_size)
         throw NetworkPacketError("not enough data to read");
 }
-
-void NetworkPacketBuffer::write (const void *ptr, size_t len) {
+       
+const void* NetworkPacketBuffer::read_ptr (size_t len) {
     // check buffer overflow
     check_write_size(len);
 
-    // set value
-    memcpy(buf_ptr + offset, ptr, len);
+    // pointer value...
+    const void *ptr = buf_ptr + offset;
+    
+    // update offset
+    offset += len;
+    
+    // return pointer
+    return ptr;
+}
+        
+void* NetworkPacketBuffer::write_ptr (size_t len) {
+    // check buffer overflow
+    check_write_size(len);
+
+    // pointer value...
+    void *ptr = buf_ptr + offset;
 
     // update offset and size
     offset += len;
     data_size += len;
+    
+    // return pointer
+    return ptr;
 }
 
 void NetworkPacketBuffer::read (void *ptr, size_t len) {
-    // check buffer underflow
-    check_read_size(len);
+    // get input pointer...
+    const void *input_ptr = read_ptr(len);
 
-    // set value
-    memcpy(ptr, buf_ptr + offset, len);
+    // copy value out
+    memcpy(ptr, input_ptr, len);
+}
+ 
+void NetworkPacketBuffer::write (const void *ptr, size_t len) {
+    // get output pointer...
+    void *output_ptr = write_ptr(len);
 
-    // update offset
-    offset += len;
+    // copy value in
+    memcpy(output_ptr, ptr, len);
+}
+        
+size_t NetworkPacketBuffer::tell_remaining (void) {
+    // number of bytes in total - number of bytes read
+    return data_size - offset;
 }
 
 /*
--- a/src/Network/Packet.hh	Mon Dec 22 02:37:28 2008 +0000
+++ b/src/Network/Packet.hh	Mon Dec 22 02:37:43 2008 +0000
@@ -22,13 +22,20 @@
 class NetworkPacketInput {
     public:
         /**
+         * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the read offset
+         *
+         * @param len the number of bytes to consume
+         */
+        virtual const void* read_ptr (size_t len) = 0;
+ 
+        /**
          * Abstract method that copies len bytes from the packet to ptr, first testing that they exist
          */
         virtual void read (
                 void *ptr,      //<<< where to copy
                 size_t len      //<<< number of bytes to copy
         ) = 0;
-       
+      
         /**
          * Convenience function to read() and return the value of the given type
          *
@@ -72,6 +79,13 @@
          * @return Vector (vec_x, vec_y)
          */
         Vector read_vector (void);
+
+        /**
+         * Abstract method to get the number of input bytes remaining.
+         *
+         * @return number of input bytes still readable
+         */
+        virtual size_t tell_remaining (void) = 0;
 };
 
 /**
@@ -80,6 +94,13 @@
 class NetworkPacketOutput {
     public:    
         /**
+         * Abstract method to get a pointer to \a len bytes of raw in-memory binary data, advancing the write offset
+         *
+         * @param len number of bytes to commit
+         */
+        virtual void* write_ptr (size_t len) = 0;
+
+        /**
          * Abstract method that copies len bytes from ptr to the packet, first testing that they fit
          */
         virtual void write (
@@ -177,7 +198,23 @@
          * Construct the NetworkPacketBuffer using the given buf_ptr, buf_size and data_size
          */
         NetworkPacketBuffer (char *buf_ptr, size_t buf_size, size_t data_size);
-        
+ 
+        /**
+         * Returns a read-only pointer to \a len bytes of internal buffer memory, calling check_read_size first and
+         * updating offset
+         *
+         * @param len number of bytes from the buffer to consume
+         */
+        virtual const void* read_ptr (size_t len);
+
+        /**
+         * Returns a read-write pointer to \a len bytes of internal buffer memory, calling check_write_size first and
+         * updating offset+data_size
+         *
+         * @param len number of bytes in the buffer to commit
+         */
+        virtual void* write_ptr (size_t len);
+       
         /**
          * Copy bytes from the packet buffer to ptr using memcpy(), calling check_read_size first.
          *
@@ -193,6 +230,11 @@
          * @param len number of bytes to copy
          */
         virtual void write (const void *ptr, size_t len);
+        
+        /**
+         * Returns our data_size - read-offset
+         */
+        virtual size_t tell_remaining (void);
 
         /*
          * Accessor functions, used by the actual socket code to read/write the buffer
--- a/src/Network/Server.cc	Mon Dec 22 02:37:28 2008 +0000
+++ b/src/Network/Server.cc	Mon Dec 22 02:37:43 2008 +0000
@@ -6,6 +6,7 @@
 #include "../Logger.hh"
 
 #include <cassert>
+#include <zlib.h>
 
 NetworkServer::NetworkServer (GameState &state, const NetworkEndpoint &listen_addr) : 
     state(state), netsession(NETWORK_MAGIC_ID), controller(netsession, NETCHAN_CORE) {
@@ -235,26 +236,44 @@
 void NetworkServerPlayer::send_terrain_data (void) {
     Terrain &terrain = server.state.world;
     
-    // XXX: over 2**31?
-    PixelDimension map_w = terrain.terrain.size();
-    PixelDimension map_h = terrain.terrain[0].size();
+    // dimensions?
+    PixelCoordinate map = terrain.getDimensions();
 
+    // translate to a byte array
+    size_t terrain_size = map.x * map.y;
+    uint8_t terrain_buf[map.x][map.y];
+    
+    // copy over from terrain vector
+    for (PixelDimension x = 0; x < map.x; x++) {
+        for (PixelDimension y = 0; y < map.y; y++) {
+            terrain_buf[x][y] = (uint8_t) terrain.terrain[x][y];
+        }
+    }
+
+    // compress the terrain buffer
+    unsigned long deflate_size = compressBound(terrain_size);
+    uint8_t deflate_buf[deflate_size];
+
+    // and compress
+    if (compress(deflate_buf, &deflate_size, (const uint8_t *) terrain_buf, terrain_size) != Z_OK)
+       throw Error("compress failed"); 
+    
     // allocate our packet...
-    BigNetworkPacket pkt (NETWORK_SESSION_HEADER_SIZE + 2 * sizeof(uint32_t) + map_w * map_h);
+    BigNetworkPacket pkt (
+        NETWORK_SESSION_HEADER_SIZE     // NetworkChannel header
+        + 3 * sizeof(uint32_t)          // our own header
+        + deflate_size                  // compressed terrain buffer
+    );
     
     // write netsession header
     node->write_packet_header(pkt, NETCHAN_TERRAIN_ARRAY);
 
     // write terrain dimensions
-    pkt.write_uint32(map_w);
-    pkt.write_uint32(map_h);
+    pkt.write_uint32(map.x);
+    pkt.write_uint32(map.y);
 
-    // write out terrain data
-    for (PixelDimension x = 0; x < map_w; x++) {
-        for (PixelDimension y = 0; y < map_h; y++) {
-            pkt.write_uint8((uint8_t) terrain.terrain[x][y]);
-        }
-    }
+    // write compressed data
+    pkt.write(deflate_buf, deflate_size);
 
     // send
     node->send_raw(pkt, true);