Prototype MH:W companion app for Linux, inspired by SmartHunter.
- Supported Versions
- Usage
- UI
- Vulkan Overlay
- Screenshots
- Status
- How it works
- Linux differences
- Root access
- How to build
- How to run
- Credits
- Changelog
- 15.21.00 - This new version of the game has modified memory patterns holding players' names and damage values hence this utility is only partially working. No fix has been planned as of now
- 15.11.01 - Fully Supported
- 15.11.00 - Fully Supported (this is deprecated by CAPCOM)
- 15.10.00 - Fully Supported (this is deprecated by CAPCOM)
- 15.02.00 - Fully Supported (this is deprecated by CAPCOM)
- 15.01.00 - Fully Supported (this is deprecated by CAPCOM)
14.02.00 - Fully Supported14.01.00 - Fully Supported14.00.00 - Fully Supported13.50.01 - Fully Supported13.50.00 - Fully Supported
Running the application as ./linux-hunter --help
will produce the following:
Usage: ./linux-hunter [options]
Executes linux-hunter 0.1.3
-m, --show-monsters Shows HP monsters data (requires slightly more CPU usage)
-c, --show-crowns Shows information about crowns (Gold Small, Silver Large and Gold Large)
-s, --save dir Captures the specified pid into directory 'dir' and quits
-l, --load dir Loads the specified capture directory 'dir' and displays
info (static - useful for debugging)
--no-direct-mem Don't access MH:W memory directly and dynamically, use a local copy
via buffers - increase CPU usage (both u and s) at the advantage
of potentially slightly less inconsistencies
-f, --f-display f Writes the content of display on a file 'f', refreshing such file
every same iteration. The content of the file is a 'wchar_t' similar
to the UI, having special '#' as escape character to denote styles
and formats (see sources for usage of '#' escape sequances)
It is heavily suggested to have file 'f' under '/dev/shm' or '/tmp'
memory backed filesystem
--mhw-pid p Specifies which pid to scan memory for (usually main MH:W)
When not specified, linux-hunter will try to find it automatically
This is default behaviour
--debug-ptrs Prints the main AoB (Array of Bytes) pointers (useful for debugging)
--debug-all Prints all the AoB (Array of Bytes) partial and full matches
(useful for analysing AoB) and quits; implies setting debug-ptrs
--mem-dirty-opt Enable optimization to load memory pages just once per refresh;
this should be slightly less accurate but uses less system time
--no-lazy-alloc Disable optimization to reduce memory usage and always allocates memory
to copy MH:W process - minimize dynamic allocations at the expense of
memory usage; decrease calls to alloc/free functions
-r, --refresh i Specifies what is the UI/stats refresh interval in ms (default 1000)
--no-color Do not use colours when rendering text (useful on distro which can't
handle ncurses properly and end up not displaying text)
--compact-display Makes the output take up less vertical space by removing unnecessary
sections and line breaks. It comes in handy when pairing linux-hunter
with vkdto (see https://github.com/Emanem/linux-hunter#vulkan-overlay)
--help prints this help and exit
When linux-hunter is running:
'q' or 'ESC' Quits the application
'r' Force a refresh
The UI itself is relatively simple. The first row contains the version and timings, useful to observe performance of this app (with wall, user and system timings).
The second row displays the MH:W session id (if any) and the owner of such session (player name).
The following rows will represent the players and the absolute/relative damage (currently they may display NaN when not in a hunt).
If then you've enabled the -m
(or --show-monsters
), another pane will appear with the monsters currently tracked by the game and their current, total and % HP.
Another way to use linux-hunter is to create a status output display file (-f
or --f-display
) and have a utility such as vkdto to read such file and update the main MH:W window with overlay.
One could setup the MH:W launch window on Steam as following:
VKDTO_HUD=1 VKDTO_FILE=/dev/shm/linux-hunter %command%
and then, once the game is up and running, execute linux-hunter from the terminal with following options
sudo ./linux-hunter -m -f /dev/shm/linux-hunter
This way vkdto will dynamically display the overlay with the content from linux-hunter and you will see it without needing to keep the terminal window in foreground (see below a screenshot with both overlay in action in foreground and background linux-hunter in the terminal).
Please note that the status file should be created on a memory device (reccomended /dev/shm
or /tmp
) - otherwise this may overutilize the physical filesystem.
Currently vkdto is still in alpha stages and you can't modify some options such the text size - please refer to vkdto github page for more info about it.
Current code/logic is somehow prototype and partially optimized - please use it at your own risk.
linux-hunter primarily operates by loading the entire MH:W memory address space into its own; it then scans memory to find some magic patterns. When such patterns are found, it then goes into a loop and keeps on navigating those patterns by de-referencing memory addresses and interpreting those according to the MH:W memory layout (i.e. player, monsters and session information).
linux-hunter will perform such memory navigation every n time and then display on the terminal UI required information.
Following the main differences I had to overcome to port the logic of SmartHunter to Linux; considering the challenges below, I think I've been lucky so far.
Some AoB structures (Array of Bytes) that are used to lookup pointers are slightly different. For example, look at PlayerName AoB: that doesn't work on Linux, but then I had to modify it and a similar version PlayerNameLinux AoB does instead the trick.
Other AoBs such as PlayerDamage can be found straight away.
When reading the players' names I have to add one byte; compare the similar logic in SmartHunter.
I've also reached out to wine SMEs asking about the efforts of creating/porting such compation software. Their feedback has been:
What you are doing here is very fragile, even going from Windows to Windows. I realize it is a common thing
to do for game mods though if the game does not provide an API for such modifications.
How reliably memory patterns are replicated between Wine and Windows and even two different Windows versions
depends on how the allocations are made. If you are looking up pointers into the game's code in its DLLs and
EXE files they are very similar because the PE file is mmap'ed into the processes' address space. You have
good chances of the absolute addresses to be identical.
If the game allocates a big blob of Heap memory in one go and fills it with data you should also be lucky.
If there are multiple independent heap allocations done by the game the patterns will start to look
differently. Wine will not allocate smaller memory blobs than requested, but a heap allocation may be
slightly larger, placed in different areas of the address space, etc. The exact details not only depend on
Wine, but also on the Linux kernel, linux libs etc.
Things will get even more spotty if the actual memory allocations are done by some Windows API functions.
I don't know the string APIs in detail, so the following example is just a hypothetical one: If the game
loads data from an XML file we pass the heavy lifting to the Linux libxml2 library. Its internal workings
are different from microsoft's msxml.dll so the layout of the loaded file will not look alike at all.
You can try to look into some observable allocation properties with functions like HeapSize and
VirtualQuery. One thing worth exploring is finding memory allocations not by searching for magic patterns
in memory but hooking functions that the game uses to load the data. It may or may not work better.
Unforutnately looks like CAPCOM and/or wine/Proton are protecting memory, hence this requires sudo
access when running.
You need to have libncursesw5-dev
installed to compile (on Ubuntu is sudo apt install libncursesw5-dev
) and that's it.
Once done, make release
and you'll have your linux-hunter ready to be running.
The most optimized way to run linux-hunter would be sudo ./linux-hunter -m
; this way you would start it using both low CPU and memory, plus displaying monsters information. In this case linux-hunter will try to find MH:W pid (if this fails to find the pid, you can use the --pid <pid>
option).
Once running press Esc
or q
to quit.
There are some options to help out with debugging (such as --debug-ptrs
and --debug-all
), if you use those I suppose you have compiled it yourself hence should have knowledge of such options (you should have looked at the code by then).
This work couldn't have been possible w/o previous work of:
- 0.1.3
- Added support for Crown when avaiable (by pr3martins)
- 0.1.2
- Changes to support release 15.01.00 (Fatalis update)
- 0.1.1
- Added option to remove colors when drawing data
- 0.1.0
- Made by default
lazy-alloc
anddirect-mem
as true, this is the most optimized setup
- Made by default
- 0.0.8
- Added option (
-f
or-f-display
) to output the display as awchar_t
file so that can be read by other processes independently. This should work along the lines of /procfs filesystem and it's hevaily reccomended to set the value of this option to a ramfs type of directory (i.e. like '/dev/shm/linux-hunter.out' or '/tmp/linux-hunter.out')
- Added option (
- 0.0.7
- Added experimental option (
-d
) to stop copying memory segments from MH:W process to linux-hunter; the latter now queries and navigates MH:W memory on-the-fly
- Added experimental option (
- 0.0.6
- Support latest version of MH:W
- Lookup monster data via pointers (as HunterPie does) - should be better for Linux
- Improved UI elements and some fonts/colors
- Added 'LobbyStatus' lookup (works on Linux as it is)