diff --git a/index.js b/index.js
index 1d2ecbf..6fd0f11 100644
--- a/index.js
+++ b/index.js
@@ -24,6 +24,7 @@ function createServer(options) {
     options['server-port'] != null ?
       options['server-port'] :
       25565 ;
+  var maxPlayers = options['max-players'] || 20;
   var host = options.host || '0.0.0.0';
   var kickTimeout = options.kickTimeout || 10 * 1000;
   var checkTimeoutInterval = options.checkTimeoutInterval || 4 * 1000;
@@ -32,6 +33,7 @@ function createServer(options) {
   assert.ok(! onlineMode, "online mode for servers is not yet supported");
 
   var server = new Server(options);
+  server.maxPlayers = maxPlayers;
   server.on("connection", function(client) {
     client.once(0xfe, onPing);
     client.on(0x02, onHandshake);
@@ -87,7 +89,7 @@ function createServer(options) {
           protocol.minecraftVersion,
           motd,
           server.playerCount,
-          server.maxPlayers,
+          maxPlayers,
         ].join('\u0000')
       });
     }
@@ -118,9 +120,7 @@ function createClient(options) {
   var email = options.email;
   var password = options.password;
 
-  var client = new Client({
-    isServer: false
-  });
+  var client = new Client(false);
   client.username = options.username;
   client.on('connect', function() {
     client.write(0x02, {
diff --git a/lib/client.js b/lib/client.js
index cabe8a7..3166a6c 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -7,12 +7,10 @@ var net = require('net')
 
 module.exports = Client;
 
-function Client(options) {
+function Client(isServer) {
   EventEmitter.call(this);
 
-  options = options || {};
-
-  this.isServer = !!options.isServer;
+  this.isServer = !!isServer;
   this.socket = null;
   this.encryptionEnabled = false;
   this.cipher = null;
diff --git a/lib/protocol.js b/lib/protocol.js
index 9d35ded..132b9f7 100644
--- a/lib/protocol.js
+++ b/lib/protocol.js
@@ -2,15 +2,6 @@ var assert = require('assert');
 
 var STRING_MAX_LENGTH = 240;
 
-module.exports = {
-  version: 51,
-  minecraftVersion: '1.4.7',
-  sessionVersion: 13,
-  parsePacket: parsePacket,
-  createPacketBuffer: createPacketBuffer,
-  STRING_MAX_LENGTH: STRING_MAX_LENGTH,
-};
-
 var packets = {
   0x00: [
     { name: "keepAliveId", type: "int" }
@@ -459,10 +450,10 @@ var types = {
   'double': [readDouble, DoubleWriter],
   'float': [readFloat, FloatWriter],
   'slot': [readSlot, SlotWriter],
+  'long': [readLong, LongWriter],
+  'ascii': [readAscii, AsciiWriter],
 
-  'ascii': [readAscii],
   'byteArray32': [readByteArray32],
-  'long': [readLong],
   'slotArray': [readSlotArray],
   'mapChunkBulk': [readMapChunkBulk],
   'entityMetadata': [readEntityMetadata],
@@ -886,6 +877,22 @@ StringWriter.prototype.write = function(buffer, offset) {
   }
 };
 
+function AsciiWriter(value) {
+  this.value = value;
+  this.size = 2 + value.length;
+}
+
+AsciiWriter.prototype.write = function(buffer, offset) {
+  var cursor = offset;
+  buffer.writeInt16BE(this.value.length, cursor);
+  cursor += 2;
+
+  for (var i = 0; i < this.value.length; ++i) {
+    buffer.writeUInt8(this.value.charCodeAt(i), cursor);
+    cursor += 1;
+  }
+};
+
 function ByteArray16Writer(value) {
   assert.ok(Buffer.isBuffer(value), "non buffer passed to ByteArray16Writer");
   this.value = value;
@@ -969,6 +976,16 @@ IntWriter.prototype.write = function(buffer, offset) {
   buffer.writeInt32BE(this.value, offset);
 }
 
+function LongWriter(value) {
+  this.value = value;
+  this.size = 8;
+}
+
+LongWriter.prototype.write = function(buffer, offset) {
+  buffer.writeInt32BE(this.value[0], offset);
+  buffer.writeInt32BE(this.value[1], offset + 4);
+}
+
 function get(packetId, toServer) {
   var packetInfo = packets[packetId];
   return Array.isArray(packetInfo) ?
@@ -1025,3 +1042,14 @@ function parsePacket(buffer, isServer) {
     results: results,
   };
 }
+
+module.exports = {
+  version: 51,
+  minecraftVersion: '1.4.7',
+  sessionVersion: 13,
+  parsePacket: parsePacket,
+  createPacketBuffer: createPacketBuffer,
+  STRING_MAX_LENGTH: STRING_MAX_LENGTH,
+  packets: packets,
+  get: get,
+};
diff --git a/lib/server.js b/lib/server.js
index b78951f..fd40db2 100644
--- a/lib/server.js
+++ b/lib/server.js
@@ -6,10 +6,9 @@ var net = require('net')
 
 module.exports = Server;
 
-function Server(options) {
+function Server() {
   EventEmitter.call(this);
 
-  this.maxPlayers = options['max-players'] || 20;
   this.playerCount = 0
 
   this.socketServer = null;
@@ -24,9 +23,7 @@ Server.prototype.listen = function(port, host) {
   var nextId = 0;
   self.socketServer = net.createServer();
   self.socketServer.on('connection', function(socket) {
-    var client = new Client({
-      isServer: true,
-    });
+    var client = new Client(true);
     client.id = nextId++;
     self.clients[client.id] = client;
     client.on('error', function(err) {
diff --git a/package.json b/package.json
index 292921e..c1bf6b7 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,8 @@
   "devDependencies": {
     "mocha": "~1.7.4",
     "mkdirp": "~0.3.4",
-    "rimraf": "~2.1.1"
+    "rimraf": "~2.1.1",
+    "zfill": "0.0.1"
   },
   "dependencies": {
     "ursa": "~0.8.0",
diff --git a/test/test.js b/test/test.js
index cdd6d3a..0ca76dc 100644
--- a/test/test.js
+++ b/test/test.js
@@ -1,12 +1,16 @@
 var mc = require('../')
-  , protocol = require('../lib/protocol')
+  , protocol = mc.protocol
+  , Client = mc.Client
+  , Server = mc.Server
   , spawn = require('child_process').spawn
   , path = require('path')
   , fs = require('fs')
+  , net = require('net')
   , assert = require('assert')
   , mkdirp = require('mkdirp')
   , rimraf = require('rimraf')
   , Batch = require('batch')
+  , zfill = require('zfill')
   , MC_SERVER_JAR = process.env.MC_SERVER_JAR
   , SURVIVE_TIME = 10000
   , MC_SERVER_PATH = path.join(__dirname, 'server')
@@ -41,6 +45,125 @@ var defaultServerProps = {
   'motd': 'A Minecraft Server',
 };
 
+var values = {
+  'int': Math.floor(Math.random() * Math.pow(2, 16)),
+  'short': Math.floor(Math.random() * Math.pow(2, 8)),
+  'ushort': Math.floor(Math.random() * Math.pow(2, 16)),
+  'byte': Math.floor(Math.random() * Math.pow(2, 4)),
+  'ubyte': Math.floor(Math.random() * Math.pow(2, 8)),
+  'string': "hi hi this is my string",
+  'byteArray16': new Buffer(8),
+  'bool': Math.random() < 0.5,
+  'double': Math.random() * Math.pow(2, 64),
+  'float': Math.random() * Math.pow(2, 32),
+  'slot': {
+    id: 5,
+    itemCount: 56,
+    itemDamage: 2,
+    nbtData: new Buffer(90),
+  },
+
+  'ascii': "hello",
+  'byteArray32': new Buffer(10),
+  'long': [0, 1],
+  'slotArray': [{
+    id: 41,
+    itemCount: 2,
+    itemDamage: 3,
+    nbtData: new Buffer(0),
+  }],
+  'mapChunkBulk': {
+    skyLightSent: true,
+    compressedChunkData: new Buffer(1234),
+    meta: [{
+      x: 23,
+      z: 64,
+      bitMap: 3,
+      addBitMap: 10,
+    }],
+  },
+  'entityMetadata': {},
+  'objectData': {
+    intField: 9,
+    velocityX: 1,
+    velocityY: 2,
+    velocityZ: 3,
+  },
+  'intArray8': [1, 2, 3, 4],
+  'intVector': {x: 1, y: 2, z: 3},
+  'byteVector': {x: 1, y: 2, z: 3},
+  'byteVectorArray': [{x: 1, y: 2, z: 3}],
+}
+
+describe("packets", function() {
+  var client, server, serverClient;
+  before(function(done) {
+    server = new Server();
+    server.once('listening', function() {
+      server.once('connection', function(c) {
+        serverClient = c;
+        done();
+      });
+      client = new Client();
+      client.setSocket(net.connect(25565, 'localhost'));
+    });
+    server.listen(25565, 'localhost');
+  });
+  after(function(done) {
+    client.on('end', function() {
+      server.on('close', done);
+      server.close();
+    });
+    client.end();
+  });
+  var packetId, packetInfo, field;
+  for(packetId in protocol.packets) {
+    packetId = parseInt(packetId, 10);
+    packetInfo = protocol.packets[packetId];
+    it("0x" + zfill(parseInt(packetId, 10).toString(16), 2), callTestPacket(packetId, packetInfo));
+  }
+  function callTestPacket(packetId, packetInfo) {
+    return function(done) {
+      var batch = new Batch();
+      batch.push(function(done) {
+        testPacket(packetId, protocol.get(packetId, false), done);
+      });
+      batch.push(function(done) {
+        testPacket(packetId, protocol.get(packetId, true), done);
+      });
+      batch.end(done);
+    };
+  }
+  function testPacket(packetId, packetInfo, done) {
+    // empty object uses default values
+    var packet = {};
+    packetInfo.forEach(function(field) {
+      var value = field.type;
+      packet[field.name] = values[field.type];
+    });
+    serverClient.once(packetId, function(receivedPacket) {
+      delete receivedPacket.id;
+      assertPacketsMatch(packet, receivedPacket);
+      client.once(packetId, function(clientReceivedPacket) {
+        delete clientReceivedPacket.id;
+        assertPacketsMatch(receivedPacket, clientReceivedPacket);
+        done();
+      });
+      serverClient.write(packetId, receivedPacket);
+    });
+    client.write(packetId, packet);
+  }
+  function assertPacketsMatch(p1, p2) {
+    var field;
+    for (field in p1) {
+      assert.ok(field in p2, "field " + field + " missing in p2")
+    }
+    for (field in p2) {
+      assert.ok(field in p1, "field " + field + " missing in p1");
+    }
+  }
+});
+
 describe("client", function() {
   this.timeout(20000);