Here is version 1.3 of this project. A few names have been changed, a few minor bugs have been fixed, and a new more complete Packet class has been added. The new readme goes over a few more useful examples for working with the new stuff as well.
Be sure to remove the old version complete and clean your files. You will also have to update a few things based on API changes but it is pretty simple. I will leave the older version in the first post for archive purposes.
Download: Attached (

)
Edit:
1 - The "public Packet(Packet rhs)" method has some bugs in it. The implementation was not fully updated to the new system I'm now using so it is not safe to use. A fix would be:
Code:
public Packet(Packet rhs)
{
lock (rhs.m_lock)
{
m_lock = new object();
m_opcode = rhs.m_opcode;
m_encrypted = rhs.m_encrypted;
m_massive = rhs.m_massive;
m_locked = rhs.m_locked;
if (!m_locked)
{
m_writer = new PacketWriter();
m_reader = null;
m_reader_bytes = null;
m_writer.Write(rhs.m_writer.GetBytes());
}
else
{
m_writer = null;
m_reader_bytes = rhs.m_reader_bytes;
m_reader = new PacketReader(m_reader_bytes);
}
}
}
Meaning, when the packet is locked, a new reader object is created for the new packet object so reading is thread safe for the new object. The underlying data is not copied, so creating a new packet to read from an existing one is efficient. Once a packet is locked, it cannot be unlocked so a writer object is never needed.
When the packet is not locked, no reader is created so the existing data is copied over into a new buffer so the packet is thread safe. "Copying" a non-locked packet is less efficient, but the point of doing so is that you need to modify the packet somehow, so it's the only thing you can do anyways.
Note, while you can write/read to the same object from different threads, the order of the operations is not actually defined, so it is not recommended to do. You should understand how C# works with references and threads before trying to do anything in those cases. For example, you should not ever have a global packet object that you write to from different threads. You may have a global locked packet that you read from through a new Packet copy, but you should never call the other member functions of the global packet in different threads.
Hopefully that makes more sense.