-
Notifications
You must be signed in to change notification settings - Fork 19
Version Check
So what is the verChk protocol? Let's have a look:
- Install ILSpy from the following link:
-
Open the MQ -> game -> MQ_Data -> Managed folder as shown below.
-
Press control + A to select all games in the folder
-
Open ILSpy, delete everything in the "Assemblies" panel and drag the new assemblies into the application.

So, what are the functions of these assemblies? Let's have a rundown of the most important:
- For the game logic; Assembly-CSharp
- For the chat code; Crisp.AutoSuggest
- To handle incoming/outgoing game protocols; A2mCore
- For handing the socket connection that A2mCore relies on, as well as system protocols; SmartFoxClient
- For some specialised protocols like portals; Thrift
If we look into ILSpy, we can see that this protocol is handled in the SmartFox assembly (as is common for System protocols) by searching for it, by looking up "verChk" and switching the mode to "constant" (a string). Feel free to double-click this, and you'll exactly what goes into "building" this protocol:

As we want to respond to this 'verChk' protocol, which we can extrapolate is (likely) related to checking the version of the game (based on the majVersion etc variables in the code sending the protocol), what is the client looking to be returned by us to continue executing the game code? (i.e., so it isn't stuck on the loading screen).
Well... let's continue further!
First, how would the client process the protocol? Using the information we know about the assemblies, let's think about how these might work together to handle incoming data:
- SmartFoxClient receives the protocol from the server and processes it, finding the name and type of the protocol
- A2mCore is then handed the processed response, formatting incoming data specifically to that protocol's requirements
- Assembly-CSharp finally handles this formatted data, which it runs the game logic for.
As I previously mentioned, this is a system protocol. We can see this, as the message (msg) type (t) is set to system (sys). A lot of reverse engineering is guessing what these variables might mean. In this context, these variable names make sense.
Typically, protocols in this XML format are system protocols.

We can guess that SmartFox has something to do with handling this protocol. A couple of ways to find this mystery method to handle verChk's response can be found below:
- We could look through all the methods in SmartFox's assembly to find the method we might be after.
- In the search-mode "method", look for something in SmartFox relating to "XML" and "receive".
- A smarter way of doing this is to search for "msg t" in search mode "constant" (which are the arguments in the sent protocol), which the client might also look for as part of incoming protocols.
TLDR; There are countless ways to problem-solve your way to these methods! Doing so, we land on the method below:

From this, we can glean the following information:
- It first loads up the XML
- It gets the type of the protocol (sys for system, xt for external - we'll talk about this one later)
- It handles the message according to the type of protocol it is
If we look at the class, we can see a few other related methods. A protocol can either be in the format of:
- XML, likely if it's a system protocol, surrounded by '<' and '>'.
- JSON (unlikely), surrounded by '{' and '}'.
- STR, with each argument split by '%'.

For example, if we click on MSG_STR in the above screenshot, we can see this information listed at the top of the class.

We can see where these are used by right-clicking, pressing "Analyse", and opening the "Used by" tab. Alternatively, we can also find where XML Received is called by, using the same method.

So, what are these messageHandlers? Let's click on it and take a look.

As it seems to be a table/list, there must be some code that adds to this list. By right-clicking and pressing "Analyse", we can see, as this is a variable, it is both read and assigned. Assigning the list is unlikely to have any interesting information, as it's simply where the variable is created. What looks more interesting, is the 'AddMessageHandler' method.

If we open this up, we can see it takes a key and handler and adds it to this list.

Such, we might need to dig a layer deeper. By pressing the right arrow on your keyboard, or clicking the '+' button to the left, let's see where this method is called.

From here, we can see that it's used by SetupMessageHandlers. This looks more like it! Taking a peek into the method, we can tell two "message handlers" are added - sysHandler (system, sys) and extHandler (external, xt).

From the above image, we can see these are both of type IMessageHandler. If we look into this interface, we can find it has that initial HandleMessage method from XMLReceived!

Let's take a look at the HandleMessage from SysHandler. Here, we can see all the incoming system protocols. These are the most fundamental protocols for the game and are all in this one location. Often, the client will be expecting the same type of protocol to the server that it expects back. Taking a look at the list, what is the most likely protocol it wants received?

We can guess that, if it's running a version check where - if you've noticed - it contains a version 'v' of 154, it might be checking if the API version matches the game's.

This makes sense, given the error message of ApiKO (KO, being the inverse of OK)

Note, Nothing is done with the xml parameter in this method.
If we follow DispatchEvent (if we inspect/analyze runInQueueMode it's always false) to _DispatchEvent and search for that "OnConnection", we meet the following code.

We can further see if we analyze onConnection, it takes us to a delegate. Delegates are used to call code from other assemblies.

Investigating OnConnectionDelegate, we can see it calls code in A2M core. Given what we know about the assembly, this makes sense.

If we were to follow this all the way down, it would take us to the next protocol that's sent. We'll see this once we program this response for 'verChk'!
Before we start, I want to preface the information mentioned above as something you'll get used to over time. It is this process of reverse engineering that we'll use to understand this project. Simply, we are: searching for related methods/variables, analyzing them, and following their code down to find what we want. Understanding the specific variables/functions is key, but the basic implementation of this problem-solving will help you get to where you want to go.
Now, onto the programming!
To create a response to a protocol, we attach it to a class. Where the class goes depends on which type of protocol it is. For system protocols, this is the "Protocols.System" project, in the "[xml] System" folder.
Right-click this folder -> Add -> New Item -> Class
The class' name follows a specific template, to ensure consistency. This can be seen as follows:
[protocolName] SentProtocolMethod

For instance, based on the verChk's method, we'd call it:
[verChk] HandleSocketConnection
We then format the class as follows to clean it up. We:
- Change the class' name to what we set SentProtocolMethod to
- Set the class to public
- Remove unnecessary imports
As such, it goes from this:

To this:

Much cleaner! Now we can write our protocol.
If this is a system protocol, we need to extend the class by SystemProtocol. If this is an external protocol (xt), we extend it by ExternalProtocol.
In doing so, we see the class is now underlined in red. If we hover over it, we see it's missing some important methods I've written that are part of the class - similar to the HandleMessage method we saw earlier.

We can press the lightbulb icon and "Implement abstract class" to add what's missing.

Here, we need to set the ProtocolName - "verChk" - and in Run, we can write the code replying to the protocol.
What we know we need to reply with, from our analysis of ApiOK/KO:
- We need to check the version given to us through the protocol
- Then send a system XML with apiOK/KO based on whether the client's version matches the server's
One way we could do this is to always reply with "apiOK", if we know we're only going to use the same version of the client. As XMLs are always used for SYS protocols, using the SendXML method (part of the BaseProtocol class that SysProtocol extends - if you control + click on the class in Visual Studio, you can follow it down to this method.

Note: We saw above that the 'xml' passed into ApiOK isn't used anywhere, hence why 'message' is empty.
Let's run the game and see what happens next!

Here we can see:
- the incoming verChk protocol
- the outgoing apiOk protocol we just wrote
- a new protocol called rndK, also of type 'system'
As you might notice, this is new! Next, we'll look into how to implement this protocol.
No! We're given the version that we don't check, and it will never fail the version check as a result.
If we check how this is implemented on the 'main' branch, we see the following:

What does this do?
- Gets the version from the xmlDoc. XmlDocument is a class as part of the internal C# library. I won't explain how the node query is written, as there are plenty of resources online. For example, https://zetcode.com/csharp/xmldocument/
- Sends the XML, with the protocol type as apiOK if version equals SmartFoxClient.GetVersion().Replace(..), else; apiKO
Any class you need can be injected into your protocol by:
- Setting the variable to public
- Adding 'getters' and 'setters' ( {get;set;} )
- Note, The class has to first be added to the "service provider". I recommend looking into dependency injection if you want to learn more. For example, https://discordnet.dev/guides/dependency_injection/basics.html, https://discordnet.dev/guides/dependency_injection/injection.html and https://github.com/FeroxFoxxo/MQReawakened/wiki/Dependency-Injection.
This class is injected in Server.Reawakened -> Reawakened.cs in the AddServices method.

- The Server.Reawakened class is where the majority of the server's game logic is stored.
Why are we using GetVersion from the class?

If we see where the majVersion etc. variables from verChk's HandleSocketConnection are used, it's also found in GetVersion().

As these are very similar, if we remove the '.'s, the value of GetVersion will be the same as HandleSocketConnection. By checking against this, we can ensure that the SmartFoxClient and other dependencies of our server matches that of the game that's trying to connect.
Hopefully, that makes sense! Let's move on to the next protocol c:
- Setting up the development environment
- Getting started with dependency injection
- Creating your first pull request
- Troubleshooting
- Creating An Issue
- Init Data
- Sync Events
- Console Commands
- Timers
- XMLs
- Web