Here are some other other stuff you can add:
0x600D is the Joymax MassiveMsg (as they call it) so rather than format packets that come in 0x600d through 0x600d, you can just have them as normal packets, then flag them as "massive". The logic of formatting any 0x600d packet is the same, so it'd help clear up the packets that can be sent through it.
For example, when the client ends 0x6100, which is the version information, the server responds with 0xA100. The 0xA100 packet comes in the 0x600d massive message packet since patch information can very well be a "huge packet". So instead of documenting packets through the 0x600d packet format, you should just do it normally.
Once you get 0xA100 added to your list, you can also add 0x2005 and 0x6005. The actual formats don't really matter since those packets are only used by the server processes, but a lot of people end up hard coding them in and they are not even needed. All the client needs is the 0xA100 packet which is in response to its 0x6100, so it's all balanced out. If you check my
project, you can grab the format of the 0xA100 version packet as well. The code isn't the greatest, but I'm working on a new version of all my stuff that properly implements everything as it should be.
One note about 0x600d packets is the client has 4kb buffers, so even though you can send larger packets with Silkroad, you should only send 0x600d packets that are no more than 4kb in side. That means 4089 bytes of data + 1 byte data flag + 6 byte regular header. Also, massive messages can be encrypted and the client doesn't seem to complain. However, you can't send
any packet through 0x600d, since the client and their server hard code which packets to process from it. I think it's a bad design flaw on their part, but my code does support it, even if it's not "valid'.
Now about the security flags. The first byte is actually a bitset of flags to use. This is the structure:
Code:
#pragma pack( push, 1 )
struct TFlags
{
uint8_t none : 1;
uint8_t blowfish : 1;
uint8_t security_bytes : 1;
uint8_t handshake : 1;
uint8_t handshake_response : 1;
uint8_t _6 : 1;
uint8_t _7 : 1;
uint8_t _8 : 1;
};
#pragma pack( pop )
Now, based on which bits are set, the security code only processes packets and logic specific to those features. So trying to hard code each different mode works, like I had in my previous code, but it's really ineffeicent since the concepts are much easier. You'll see in my new security code what I'm talking about. Here's a simple example of building the initial security packet for a server to a client:
Code:
void GenerateHandshake( uint8_t mode )
{
m_security_flag = mode;
m_client_security = true;
PacketContainer response;
response.opcode = 0x5000;
response.data.Write< uint8_t >( mode );
if( m_security_flags->blowfish )
{
m_initial_blowfish_key = rng();
m_blowfish.Initialize( &m_initial_blowfish_key, sizeof( m_initial_blowfish_key ) );
response.data.Write< uint64_t >( m_initial_blowfish_key );
}
if( m_security_flags->security_bytes )
{
m_seed_count = rng() % 0xFF;
SetupCountByte( m_seed_count );
m_crc_seed = rng() % 0xFF;
response.data.Write< uint32_t >( m_seed_count );
response.data.Write< uint32_t >( m_crc_seed );
}
if( m_security_flags->handshake )
{
m_handshake_blowfish_key = rng();
m_value_x = rng() & 0x7FFFFFFF;
m_value_g = rng() & 0x7FFFFFFF;
m_value_p = rng() & 0x7FFFFFFF;
m_value_A = G_pow_X_mod_P( m_value_p, m_value_x, m_value_g );
response.data.Write< uint64_t >( m_handshake_blowfish_key );
response.data.Write< uint32_t >( m_value_g );
response.data.Write< uint32_t >( m_value_p );
response.data.Write< uint32_t >( m_value_A );
}
m_outgoing_packets.push_back( response );
}
Here you can see the bitfields in action. If all flags are set, which is mode 0x0E, you get the full packet. If only some of the flags are set, you get a packet that the client expects based on the logic. If no flags are set, all you get is the actual mode, which is obviously correct since no security is simply the mode byte!
[Edit] Removed 0x2002 remarks since the packets are worthless by design. All they do is tell the server the last time a packet was received on the connection, but they can't be used for much more than that.
I think that's about it for now. Nice work!