Page 2 of 2

Re: Using a very old game client?

Posted: Fri Nov 05, 2010 11:57 pm
by ilythor
Haha, thanks Sylaei for that explanation. I had a rough idea but now it makes sense. I think... :lol:

Re: Using a very old game client?

Posted: Sat Nov 06, 2010 3:21 pm
by John Adams
I'm in the middle of a ton of crap at home, but I'll try to sum up as best I can from what I know/remember.

Sylaei hit it right on, with how the client/server communicate. That's exactly what's going on. EQ2Emu is different than most others though, because LethalEncounter came up with an ingenious way for us to support multiple clients in the same code. These are done through "Structs and Opcodes lists", those xml files you see in the eq2world directory, and the opcodes table in the database.

The "Struct" (for World, Spawns and Items) is an xml data file that simple says "for opcode ____, client version ____, the data in this packet is <this type> and is <this long>.

Example:

Code: Select all

<Struct Name="WS_SpawnStruct" ClientVersion="1">
<Data ElementName="position" Substruct="Substruct_SpawnPositionStruct" Size="1" />
<Data ElementName="vis" Substruct="Substruct_SpawnVisualizationInfoStruct" Size="1" />
<Data ElementName="info" Substruct="Substruct_SpawnInfoStruct" Size="1" />
</Struct>
WS_SpawnStruct is the entry point for determining how to decipher the incoming packets relating to Spawns. The example is for client verion 1 (which merely means this is the struct in the very first client ever used to start EQ2Emu), and you see there are 3 substructs - position, vis and info. Sorry to start out with a confusing one, but this is the only one I actually (almost) understand ;) Substruct= tells the server to go find yet another struct by that name/client version and build the entire packet structure.

Code: Select all

<Struct Name="Substruct_SpawnPositionStruct" ClientVersion="1" >
<Data ElementName="pos_grid_id" Type="int32" Size="1" />
<Data ElementName="pos_x" Type="float" Size="1" />
.
.
etc...
then add to that:

Code: Select all

<Struct Name="Substruct_SpawnVisualizationInfoStruct" ClientVersion="1">
<Data ElementName="arrow_color" Type="int8" Size="1" />
<Data ElementName="locked_no_loot" Type="int8" Size="1" />
.
.
etc...
and finally:

Code: Select all

<Struct Name="Substruct_SpawnInfoStruct" ClientVersion="1" >
<Data ElementName="hp_remaining" Type="int8" Size="1" />
<Data ElementName="unknown2a" Type="int8" Size="3" />
<Data ElementName="power_percent" Type="int8" Size="1" />
.
.
etc...
In the end, the server has this huge amount of data elements, in a specific order, of specific types and lengths, and now knows that when client version "1" logs in, that client will understand the data from the server sent in that structure. Make sense? (there is of course a static header/footer added to the beginning and end - you will find this info in SpawnStructs.xml)

As for what this all means to you, it means when the world starts, it connects to a LoginServer. The LoginServer allows clients to connect to itself, where it identifies the version # of the client (client version 1, 863, 945, 1045 etc). The client tells Login what version it is. Login then looks in it's own list of supported clients (version_range1 through version_range2 in the `opcodes` table) and if the client matches one of those opcode ranges, Login allows the client through.

The client then picks what server it wants to log into - and though the LoginServer might have allowed the client to log in, if the server receiving the client data does not support client version 1045, then the client gets rejected.

If all the stars are aligned, and login+server allow the client entry, the client logs into a zone - and the zone startup wants to push Spawn data to the client - and it does so by looking at the client's version, building the list of recognizable opcodes based on version_rangeX, and then pushes the Spawn data it knows about to the client - and the client can see a spawn's position, visual appearance, and info (those 3 elements from above).

In order to get a very old client to work, you would probably need to disassemble the client and tear apart every opcode and build a version_rangeX from scratch. No small task, or we would have done it by now. Plus, not all of us have original clients ;) (though I do!)

How WE derive current client structs, is to collect data from EQ2 Live, open the file in an editor, and start comparing, byte by byte, whether something has changed or not (usually we only do that when something we know is broken or changed). Once we see SOE slipped a new INT32 in, we build a new struct xml to handle that specific client version #. If SOE changed opcodes (which they do all the time), we find out what the old packet was, and look for the same data and see what the new opcode is (usually opcode + 2 it seems in most cases and only for specific sets of functions - spawns, items, spells, achievements, etc) and build new opcode ranges for the client version in the `opcodes` table.

Almost sounds like I know what I'm talking about, huh? Zcoretri could answer better, he's the opcodes/structs guru around here.

I hope this is more helpful than my previous response ;) Good luck.

Re: Using a very old game client?

Posted: Sat Nov 06, 2010 3:28 pm
by John Adams
Let me add, the client actually has 2 versions; the Client Version is the one you see in the title bar when you launch the client - ie., 6128L or whatever.

The "data version" is the one LoginServer and World care about, and you cannot see that from outside the client - you can only see it by running the collector or wireshark and tapping into the stream to see what version the client is sending during login attempts.

Sorry for the confusion.

Re: Using a very old game client?

Posted: Sat Nov 06, 2010 8:14 pm
by Sylaei
Thanks John,
Lots of good info in that post, I didn't understand how that part worked until now.

Re: Using a very old game client?

Posted: Sat Nov 06, 2010 8:25 pm
by ilythor
I think I finally got used to how JA writes!

In all honesty this solution sounds incredibly ingenious, perhaps laborious, but none the less ingenious.

Re: Using a very old game client?

Posted: Sun Nov 07, 2010 6:55 pm
by Chrisworld
Well then, wow! Thanks for the info, John. I've finally got a basic understanding of how it all works. All this time i've been toying around with opcodes and client files to try to get that pesky TSO box to run with the latest Server Pack, to no avail. Now I know why, haha. I was way off. Well, at least, on top of knowing a little more about it, I also know I will never get it to work myself, so I can finally rest...lol. The Server pack 1.0 + my TSO box is more or less a gigantic Guild Hall now.

I do still have Client 6122 (Will of a Tyrant GU). It can no longer play music (for the life of me I DON'T know why, no files have changed) and It works perfectly with 1.2 & the emu project servers. I figured out that it's really not damaged aside from the music issue. That's about all I have up to this point related to project compatibility. Client 6170 does not work with the project yet, so that's something I'm going to hold onto for future use hopefully, haha.

Anyways, thanks again for that post.

Chris

Re: Using a very old game client?

Posted: Sun Nov 07, 2010 11:34 pm
by Zcoretri
How WE derive current client structs, is to collect data from EQ2 Live, open the file in an editor, and start comparing, byte by byte, whether something has changed or not (usually we only do that when something we know is broken or changed). Once we see SOE slipped a new INT32 in, we build a new struct xml to handle that specific client version #. If SOE changed opcodes (which they do all the time), we find out what the old packet was, and look for the same data and see what the new opcode is (usually opcode + 2 it seems in most cases and only for specific sets of functions - spawns, items, spells, achievements, etc) and build new opcode ranges for the client version in the `opcodes` table.

Almost sounds like I know what I'm talking about, huh? Zcoretri could answer better, he's the opcodes/structs guru around here.

I hope this is more helpful than my previous response ;) Good luck.
Not much I can add there, John pretty much covered how it works. If there any specific questions, I may be able to answer them.