are these packets correct?

12/15/2010 12:22 sjaakie100#16
Quote:
Originally Posted by bootdisk View Post
You don't need a reader for C++.
Having such a system would be like trying to code Python in C++.

Just take a look [Only registered and activated users can see links. Click Here To Register...]. And it's by far worth to read the whole thread... it was one the biggest threads I've seen about private server coding scene.

Hope it helps as it's more related to C++ than C#.
Thank you very much:) I've read the post and tried something with it and it seems to be working. I've made the first init packet with it and I can send it and I get a packet from the client back. thanks:D

But i've a little question. Do i have to define a new struct for every packet or do you reuse things? and can I use those structs for reading the packets because that post of you didn't say how to read it only writing. I'll try things by myself because I like to figure things out by myself but any help is welcome:)

edit:
Oke well I tried something an it seems to work with the reading.
Would this be a correct way to read is this just the way as I did before but now I save things structed?
Code:
#pragma pack(push)
#pragma pack(1)
	typedef struct sv_ReadPacketStruct
	{
		ushort Length;
		ushort OP;
		ushort SecurityBytes;

	} sv_ReadPacketStruct;
#pragma pack(pop)
	sv_ReadPacketStruct sv_ReadStruct;
	sv_ReadStruct.Length = *(short*)&data[0];
	sv_ReadStruct.OP = *(short*)&data[2];
	sv_ReadStruct.SecurityBytes = *(short*)&data[4];
12/16/2010 03:25 bootdisk#17
Oh so sorry about the delayed reply.
You don't need to set each element of the struct, just cast the array of bytes to it, so for example, at my PacketHandler cpp file I have:

Code:
#pragma pack(push)
#pragma pack(1)

typedef struct
{
	ushort	Length;
	ushort	OP;
	/// We will not take care of the security bytes
} CL_PacketHeaderStruct;

#pragma pack(pop)

CL_PacketHeaderStruct *cl_packetheader;
ubyte *cl_packetcontent;
And maybe you're asking yourself why? that's because you could receive more than 1 packet per communication between Client and Server. So in this case I just need to know where that packet ends and its OP code to call the corresponding Handler:

Code:
void PacketsHandler(CGameObject *go, uint totalBytes)
{
	ubyte *buffer = go->GetRecvBuffer();
	uint size;
	
	while (totalBytes > 0)
	{
		cl_packetheader = (CL_PacketHeaderStruct*)&buffer[0];
		size = 6 + cl_packetheader->Length;
		cl_packetcontent = buffer + 6;
		
		switch (cl_packetheader->OP)
		{
			case CL_PING:
			case CL_HANDSHAKE:
			{
				break;
			}
			
			case CL_WHOAMI:
			{
				Packet_WhoAmI(go, cl_packetcontent);
				break;
			}
			
			case CL_PATCH_INFO_REQUEST:
			{
				Packet_PatchInfo(go, cl_packetcontent);
				break;
			}
			
			case CL_SERVERLIST_REQUEST:
			{
				Packet_ServerList(go, cl_packetcontent);
				break;
			}
			
			case CL_LOGIN_REQUEST:
			{
				Packet_Login(go, cl_packetcontent);
				break;
			}
			
			case CL_CHARACTER_OPERATIONS:
			{
				Packet_Character(go, cl_packetcontent);
				break;
			}
			
			default:
			{
				std::cout << "Unknown packet: " << std::hex << cl_packetheader->OP << "\n";
				break;
			}
		}
		
		buffer += size;
		totalBytes -= size;
	}
}
See how I do cast the bytes here?

Quote:
cl_packetheader = (CL_PacketHeaderStruct*)&buffer[0]; <-- this does the work
So for fixed size packets you don't have any problems and most of the packets you're sending from your server are several times the same.

Remember what the #pragma pack directive says:

Quote:
Members of structures are aligned on the specified byte-alignment, or on their natural alignment boundary, whichever is less.
([Only registered and activated users can see links. Click Here To Register...])

If it wasn't because of this you couldn't use this method of 'parsing'. That's why it would make an emulator made in C++ faster than one in C# or any similar language.

But yes, here we've to face the fact that not all the packets from the client has the same size... well, I was thinking about a solution to that problem but for now I was using this (for the login packet):

Code:
ushort *namelen = (ushort*)&content[0]; content+=sizeof(ushort);
char *name = (char*)&content[0]; content+=*namelen;
Which is... not the best option in my opinion but maybe you could divide your packet into several structures and then plus the pointer to the previous structure size...

I couldn't find any free time to continue working on that because I was parsing all the skilldata files (that's how I got the complete list of flags of skills modifiers that you have seen further in that thread).

And that leads into another stuff I was thinking about... why do you have to fill up a database with those static values? I mean, you're not developing the new Silkroad Online... it's just an emu. (Edit2: deserialization/serialization is a waste of precious time).

Well, those are just thoughts about the development of an emu in C++.
I'll try to put more things in that thread when I try/test more things.

Edit: I didn't post source before as it's a WIP (work in progress) project.