📜 ⬆️ ⬇️

How we unpacked the game automated

My hobby, in addition to programming, is the development of modifications to the STALKER game. We work in a team, where, as is customary, everyone is responsible for something different. I, in addition to entering the circle of developers, also carry out software development for the team. Under the cat, read how we automated the unpacking of game archives, what problems we encountered and how they were solved.

Game resources are packed in archives. Estimate how many archives we have in the current build you can below:



Developers have all these archives unpacked, and for testers we release cumulative updates that are distributed as a single archive.
')
In addition, there are also different sets of changes from the 4 lower archives. Sometimes there is a need to unpack them all. We have different tools for packing and unpacking, I know at least 2 sets - console and GUI version. Each of them has its drawbacks:

Console:
1. On unpacking archives over ~ 1.6 GB drops.

GUI:
1. Selection of the initial folder, archive, final directory - made by hand.
2. Only unpacking 1 archive at a time is possible.

Since we have archives and almost 2GB, we have to use the GUI. When I got tired of doing the same thing a hundred times, I decided to automate it.

The unpacker has this interface:







These are all dialog boxes. I was led to a thought by the field in which the file name is displayed. If it can be entered there by hand or selected, then the same can be repeated programmatically.

We will arm C ++ WinAPI and SPY ++ and for the time being we will work on the first window. Run the unpacker and SPY ++, find its process there:



And yes, in order to make it easier to search for the necessary fields on the screen, I advise you to fill them with information, I, for example, chose the archive. Well, we see the fields here. You can start writing code ...

When I first thought about the idea, I had the idea to create a convenient configuration file. Its structure was invented right away and never changed:

Unpacker.exe - even before the GUI unpacker
C: \ STALKER \ - let it play
D: \ Stalker SHOC \ 1 \ - let it be up to the folder to unpack
YES - get the list of archives recursively (NO) or from the list below
gamedata.db1 - a list with the names of the archives
/gamedata.db2 - commented line

I will not dwell on how the config is read. Let me just say that we have a structure with similar fields. In order to click on the buttons in another window, we need to get its handle. Next we need to get the handles of the controls we need. Moreover, getting them exactly in the sequence in which they are connected (the way they are connected can be seen from the drop-down lists for elements in SPY ++. Let's see:



We will receive it by the following code:

HWND hwnd = FindWindow(NULL, "Select file to unpack..."); HWND hbnd = FindWindowEx(hwnd, NULL, "Button", "&"); HWND hnd = FindWindowEx(hwnd, NULL, "ComboBoxEx32", ""); hnd = FindWindowEx(hnd, NULL, "ComboBox", NULL); hnd = FindWindowEx(hnd, NULL, "Edit", NULL); #ifdef _DEBUG BOOST_LOG_TRIVIAL(info) << "FindWindow(NULL, 'Select file to unpack...') " << hwnd; BOOST_LOG_TRIVIAL(info) << "FindWindow(NULL, 'Button', '&') " << hbnd; BOOST_LOG_TRIVIAL(info) << "FindWindow(NULL, 'Edit', '') " << hnd; #endif 

The FindWindow (Ex) function returns a handle by the object name. The second parameter can take the value of the object class, and the first one can pass the object in which to search (for example, we pass the window handle to search for the button).

After we receive the data, we need to send a message to the control. We will do it this way:

 if ((hwnd != NULL && hbnd != NULL ) && hnd != NULL) { //  SendMessage(hnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR(path_to_db.c_str()))); // SendMessage(hbnd, WM_LBUTTONDOWN, 0, 0); SendMessage(hbnd, WM_LBUTTONUP, 0, 0); #ifdef _DEBUG BOOST_LOG_TRIVIAL(info) << "Sended"; #endif } 

Here I will discuss in more detail, as there were difficulties in filling the ComboBox. Initially, the code was slightly different, and I only got:

 HWND hnd = FindWindowEx(hwnd, NULL, "ComboBoxEx32", ""); 

And tried to fill it using:

 SendMessage(hnd, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR(path_to_db.c_str()))); 

But nothing worked. Why - I do not know so far. Another problem was that I was embarrassed by the principle of operation of this window. In the screenshot above, you can see that when we select an archive, only its name gets into the ComboBox. The path does not appear anywhere. Hoping for a miracle, I passed there the full path to the archive and it all worked. Are there any miracles? I think that pressing the Ok button is obvious, and we will not consider it.

Now it's time to work with the second folder selection window. Immediately give the code and then comment.

 //  2  Sleep(time); hwnd = FindWindow(NULL, " "); hbnd = FindWindowEx(hwnd, NULL, "Button", ""); hnd = FindWindowEx(hwnd, NULL, "Edit", NULL); if ((hwnd != NULL && hbnd != NULL) && hnd != NULL) { //  SendMessage(hnd, WM_SETTEXT, 0, (LPARAM)(LPCTSTR(config.path_to_output.c_str()))); // SendMessage(hbnd, WM_LBUTTONDOWN, 0, 0); SendMessage(hbnd, WM_LBUTTONUP, 0, 0); #ifdef _DEBUG BOOST_LOG_TRIVIAL(info) << "Sended"; #endif } 

There are problems with this window too. It has no visible controls except buttons. Open SPY ++ and see what's inside:



I began to select different folders, and the directory name was entered into the Edit control, again, just the name (is there any thing that the mouse click handler adds to the line?). And I was completely desperate, because I could not imagine how to pass my way there. The first thought was to run all this under the debugger and find the memory address where the final path lies, inject a dll into the process and change the value in the memory (will DEP allow it to be done?).

This idea failed because I do not know how to work with a debugger and I never did this, and I have to start learning from the simpler. Hoping for a miracle again, I passed the full path to Edit - and it all worked! Joy was no chapel. Next was the routine writing code, which you can find here . We got a convenient and versatile tool for unpacking. I think that my solution to the problem is not the only one and I will be happy if something useful is told in the comments. Thanks for attention.

Source: https://habr.com/ru/post/273595/


All Articles