--- 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);