Game client
The client is a C++ port of the original 0.97k main.exe, rebuilt through reverse engineering. It behaves like the original binary and, on top of that, includes everything the Main.dll injection used to do: windowed mode, resolutions, minimap, options menu, multiple languages and customs.
It runs on Windows and Linux, and the code is at EmanuelCatania/Mu-97k-Client-Source.
The DLL client is deprecated.
Main.dll, InfoEncoder andClientInfo.bmdare no longer used or distributed. If you are coming from that client, see Coming from the DLL client.
| Platform | Status |
|---|---|
| Windows x86 (Win32 or SDL3 backend) | Complete |
| Linux x86 (SDL3 backend) | Complete; X11 recommended with NVIDIA |
Each client version states in its Release which server version it works with. Always use the same version on both sides (for example, client 0.97.30 with server 0.97.30).
How the connection works
The server address and identity are compiled into the client, as in MU 5.2. There is no connection config file to distribute: each server builds its own client.
That is why the client Releases have no executables: a published executable would point to a server that is not yours.
1. Point the client at your server
Clone the repository and edit src/Config/ServerConfig.h:
git clone https://github.com/EmanuelCatania/Mu-97k-Client-Source.git
cd Mu-97k-Client-Source
constexpr char ConnectServerIP[] = "mu.your-domain.com";
constexpr unsigned short ConnectServerPort = 44405; // 0 = no ConnectServer
constexpr char GameServerIP[] = "mu.your-domain.com";
constexpr unsigned short GameServerPort = 55901;
constexpr char CustomerName[] = "MuLinux";
constexpr char ServerSerial[] = "TbYehR2hFUPBKgZj";
constexpr char ClientVersion[] = "0.97.11";
The address can be an IP or a host name. A name is better: the server can move to a new IP without rebuilding the client. If the domain is on Cloudflare, the record must be unproxied (“DNS only”): the proxy only lets web traffic through and cuts the game connections.
The ports are the server’s: 44405 for the ConnectServer (the server list) and 55901 for the GameServer. With ConnectServerPort = 0 the client connects straight to the GameServer.
The identity must match the server’s MuServer/GameServer/DATA/GameServerInfo - StartUp.dat. If any of these values does not match, the client connects but never gets in, without a useful error:
| Value | From the .dat |
If it does not match |
|---|---|---|
CustomerName |
CustomerName= |
Stays on “connecting to the GameServer” forever |
ServerSerial |
ServerSerial= |
Same, and login also answers “wrong version” |
ClientVersion |
ServerVersion= |
Login rejected with “wrong version” |
If you did not change those values on the server, the example values already match the Docker server.
2. Build
The client is always 32-bit (x86), even on 64-bit Windows or Linux: the port reproduces the memory layouts of the original binary.
Windows
Requires Visual Studio 2022 with “Desktop development with C++” (includes CMake). Open mu97k.sln, pick Release and platform Win32, and build. Or from a terminal:
cmake -S . -B build -A Win32 -T v143
cmake --build build --config Release
The executable ends up in bin/Client/main.exe, next to the assets.
Linux
You need CMake 3.25+, Ninja, GCC with -m32 support and the 32-bit development libraries. The package list for Arch, Debian/Ubuntu and Fedora is in the client README.
# Arch. Debian/Ubuntu: /usr/lib/i386-linux-gnu/pkgconfig. Fedora: /usr/lib/pkgconfig
export PKG_CONFIG_LIBDIR=/usr/lib32/pkgconfig:/usr/share/pkgconfig
cmake --preset linux-x86-release
cmake --build --preset linux-x86-release
To build the package you distribute (main, Data, launch.sh and licenses):
python3 .github/scripts/package_linux.py build/linux-x86-release dist
It creates dist/mu97k-0.97.30-linux-x86.tar.gz.
Without installing compilers
If you don’t want to set up a build environment, you can use GitHub Actions: fork the repository, enable Actions on your fork, edit src/Config/ServerConfig.h from the GitHub website and wait for the workflow to finish. In the Actions tab you will find the Windows main.exe and the full Linux package (mu97k-linux-release) as artifacts.
3. Distribute
Windows: zip the bin/Client folder (main.exe, the Data folder and Config.ini). You don’t need to include main.map or debug.log.
Linux: distribute the .tar.gz from the previous step. Players extract it on a Linux partition (NTFS loses the execute permissions) and run ./launch.sh, without sudo. They need the 32-bit system libraries listed in the client README.
If the server address changes, you have to rebuild and redistribute the executable. If you used a host name, pointing the DNS to the new IP is enough.
Player options
Preferences are stored in Config.ini, with the same sections Main.dll used, so an existing Config.ini keeps working. Most of them can be changed from the in-game options menu.
- Windows:
Config.ininext tomain.exe. - Linux:
~/.local/share/mu97k/Config.ini. The first start creates it in windowed mode at 1024×768.
| Key | What it does |
|---|---|
[Window] WindowMode |
1 = windowed, 0 = fullscreen |
[Window] Borderless |
1 = borderless window |
[Window] Resolution |
0 640×480, 1 800×600, 2 1024×768, 3 1280×1024, 4 1280×720, 5 1366×768, 6 1600×900, 7 1920×1080 |
[Sound] EnableSound, EnableMusic |
Sound effects and music (1 / 0) |
[Sound] SoundLevel, MusicLevel |
Volume from 0 to 9 |
[Language] LangSelection |
Interface language: Eng, Spn or Por |
[MiniMap] Alpha, ZoomLevel |
Minimap transparency and zoom |
[Font] FontName, FontHeight… |
Game font |
[Antilag] Delete… |
Turn off shadows, objects, effects, wings and other render parts on slow machines |
Linux with NVIDIA GPUs
With NVIDIA, run the client on X11:
SDL_VIDEODRIVER=x11 ./launch.sh
NVIDIA does not ship the 32-bit Wayland EGL platform: without it Wayland falls back to software rendering (the client detects it and switches to X11 on its own), and with it Wayland works but is much slower than X11. With Intel and AMD, native Wayland works fine.
Coming from the DLL client
| Before (DLL) | Now |
|---|---|
IP in MainInfo.ini + InfoEncoder → ClientInfo.bmd |
Address in src/Config/ServerConfig.h, compiled in |
Main.dll injected into main.exe |
Everything built into the client |
Customs in ClientInfo.bmd + regenerated item.bmd |
The server sends the definitions; the client only carries the models. See Customs |
The DLL’s Config.ini |
The same file, with the same keys |
| Windows only | Windows and Linux |
The Encoder tables you already had (CustomItem.txt, CustomGlow.txt, etc.) are still used, but they now live on the server.
Troubleshooting
The client connects but never gets in, or stays on “connecting”: check CustomerName, ServerSerial and ClientVersion against the server’s GameServerInfo - StartUp.dat. The client writes a debug.log (on Windows, in the client folder; on Linux, in ~/.local/share/mu97k/) with the address it used and the derived key:
ServerConfig: ConnectServer=mu.your-domain.com:44405 GameServer=mu.your-domain.com:55901 version='09711'
MuEmu: InitKeys CustomerName='MuLinux' Serial='TbYehR2hFUPBKgZj' -> EncDecKey1=0xC2 EncDecKey2=0x01
The server list does not show up: make sure port 44405/tcp is open and that the server’s PUBLIC_IP is the correct public IP. If the domain goes through Cloudflare, it must be “DNS only”.
Custom items look wrong or don’t show: client and server must be the same version, and the item models must be in the client’s Data folder.