- Joined
- Sep 30, 2023
- Messages
- 107
First of all, I would like to thank @darren.tran and @Lothbrok for their help. They answered my questions and tested the solution to make sure it works. This was a team effort. We will be using this client from the archive:
https://archive.openshaiya.org/shaiya-us/clients/ps0183-22-12-2011-game.exe
There used to be a language setting in the configuration file. A number was assigned to a global variable, depending on the key value.
See the following documentation to learn more:
MultiByteToWideChar
WideCharToMultiByte
https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
Depending on the language number, a switch returns a code page. The function can be found at address 0x40A550.
Case 3 (Vietnam) returns 65001 (UTF-8). Since we are using a US client, the number will be 6 (English). We will change the number at address 00708598 from 6 to 3.
Changing the number will affect several things. It appears they wrote features for particular regions. What is relevant to this guide is the fonts. Each language has its own fonts, which vary in height, weight, etc. The language value is compared to determine which block to execute. Follow the jump instructions until you see 3 (Vietnam).
Below the call to CreateFontA it creates 3 more fonts. The values 0x190 and 0x2BC are weight macros.
Now, we need to embed the manifest. Please see the following documentation:
https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page
https://devblogs.microsoft.com/oldnewthing/20220531-00/?p=106697
https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#activecodepage
If you've added additional sections to the file, embedding the manifest may break the executable. Embed the manifest before doing anything else. I'm sure there is more than one way to do this, so find something that works for you.
Put the following manifest file in the same directory as game.exe:
The Windows SDK includes a program named mt.exe, which can be used to embed the manifest. You will need to add the path to your system environment variables so the system can find the file. The path will look something like this:
Execute the following command to embed the manifest:
You can use Resource Hacker to check the result. It should also be able to embed the manifest, but I didn't test it.
Notes
Login input limit:
Japan (4): 12
Russia (11): 31
Default: 19
Chat input limit:
Taiwan (5): 70
Hong Kong (9): 70
Default: 120
Note: the chat color format is 8 characters.
https://archive.openshaiya.org/shaiya-us/clients/ps0183-22-12-2011-game.exe
There used to be a language setting in the configuration file. A number was assigned to a global variable, depending on the key value.
C++:
enum struct LoginVersion : UINT32
{
Korea = 1, //
China, //
Vietnam, // 65001 (UTF-8)
Japan, // 932
Taiwan, // 950
English, // CP_ACP
Germany, // CP_ACP
SingaMala, // 950
HongKong, //
France, // CP_ACP
Russia, // CP_ACP
Turkey, // 1254
Brazil, // CP_ACP
LatinAmerica, // CP_ACP
Poland, // 1250
Italy, // CP_ACP
Philippines // CP_ACP
};
Code:
// winnls.h.
#define CP_ACP 0 // default to ANSI code page
See the following documentation to learn more:
MultiByteToWideChar
WideCharToMultiByte
https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
Depending on the language number, a switch returns a code page. The function can be found at address 0x40A550.
Case 3 (Vietnam) returns 65001 (UTF-8). Since we are using a US client, the number will be 6 (English). We will change the number at address 00708598 from 6 to 3.
Changing the number will affect several things. It appears they wrote features for particular regions. What is relevant to this guide is the fonts. Each language has its own fonts, which vary in height, weight, etc. The language value is compared to determine which block to execute. Follow the jump instructions until you see 3 (Vietnam).
Below the call to CreateFontA it creates 3 more fonts. The values 0x190 and 0x2BC are weight macros.
C++:
// wingdi.h
/* Font Weights */
#define FW_DONTCARE 0
#define FW_THIN 100
#define FW_EXTRALIGHT 200
#define FW_LIGHT 300
#define FW_NORMAL 400 // 0x190
#define FW_MEDIUM 500
#define FW_SEMIBOLD 600
#define FW_BOLD 700 // 0x2BC
#define FW_EXTRABOLD 800
#define FW_HEAVY 900
Now, we need to embed the manifest. Please see the following documentation:
https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page
https://devblogs.microsoft.com/oldnewthing/20220531-00/?p=106697
https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#activecodepage
If you've added additional sections to the file, embedding the manifest may break the executable. Embed the manifest before doing anything else. I'm sure there is more than one way to do this, so find something that works for you.
Put the following manifest file in the same directory as game.exe:
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity type="win32" name="..." version="6.0.0.0"/>
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>
The Windows SDK includes a program named mt.exe, which can be used to embed the manifest. You will need to add the path to your system environment variables so the system can find the file. The path will look something like this:
Code:
C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\x86
Execute the following command to embed the manifest:
Code:
mt.exe -manifest utf-8.manifest -outputresource:game.exe;#1
You can use Resource Hacker to check the result. It should also be able to embed the manifest, but I didn't test it.
Notes
Login input limit:
Japan (4): 12
Russia (11): 31
Default: 19
Chat input limit:
Taiwan (5): 70
Hong Kong (9): 70
Default: 120
Note: the chat color format is 8 characters.
Last edited: