A generic modding framework for Hashlink, powered by Python. The spiritual successor to pyhl.
Astute observation! Although DCCM is fantastic and very well-developed, it exists specifically for Dead Cells. Although, with some work, DCCM could be generalized to other applications and games (think: Wartales, Northgard, Dune: Spice Wars, etc.), it's still just a Dead Cells modding tool.
hlmod aims to be a truly generic, easy-to-use Hashlink modding framework that Just Works everywhere Hashlink does. In the long run, it should be able to do everything that DCCM does, and possibly even more!
crashlink is written in Python already - it's a reimplementation of hlbc written from the ground up to be dynamically scriptable, as Rust is unfortunately not. hlmod uses Python because:
- It has a great C API that can integrate pretty nicely at a low level with HL, and an accessible and controllable GC (unlike .NET, which requires more marshalling)
- It's very metaprogrammable and you can define classes and types on the fly, which offers a great option for representing HL bytecode types
- It can reuse the existing crashlink classes and datastructures with its collection of tooling, which minimizes repeated code
- I already know it really well
- Basic Python mods as modules, resolve dependencies, mod metadata
- JIT hooking to Python
- Basic casting of primitives from HL -> Python and Python -> HL
- HNULL casting support
- Obj wrappers, metaclasses and Python interfaces for HL objects
- Hook a function by name
- String utilities
- Subclass an HL object from Python, or define a Python class and make it available as an HL Obj
- Types and intellisense for HL Objs?
- Common base lib mods for specific games:
- Dead Cells
- Bundled PAK loading
- Custom weapon subsystem
- More?
- Dead Cells
You'll need to first satisfy all the build requirements in HL's README:
HashLink is distributed with some graphics libraries allowing to develop various applications, you can manually disable the libraries you want to compile in Makefile. Here's the dependencies that you install in order to compile all the libraries:
- fmt: libpng-dev libturbojpeg-dev libvorbis-dev
- openal: libopenal-dev
- sdl: libsdl2-dev libglu1-mesa-dev
- ssl: libmbedtls-dev
- uv: libuv1-dev
- sqlite: libsqlite3-dev
To install all dependencies on the latest Ubuntu, for example:
sudo apt-get install libpng-dev libturbojpeg-dev libvorbis-dev libopenal-dev libsdl2-dev libglu1-mesa-dev libmbedtls-dev libuv1-dev libsqlite3-dev
For 16.04, see this note.
To install all dependencies on the latest Fedora, for example:
sudo dnf install libpng-devel turbojpeg-devel libvorbis-devel openal-soft-devel SDL2-devel mesa-libGLU-devel mbedtls-devel libuv-devel sqlite-devel
And on OSX:
brew bundle
to install the dependencies listed in Brewfile.
To build all of HashLink libraries it is required to download several additional distributions, read each library README file (in hashlink/libs/xxx/README.md) for additional information.
In short you'll probably need:
- SDL2-devel, extract to
<hashlink>/include/sdl
- openal-soft, extract to
<hashlink>/include/openal
You'll also need Ninja installed, do choco install ninja
or scoop install ninja
, depending on your package manage of choice. If you're a winget nerd, try winget install Ninja-build.Ninja
. As well as this, vcpkg
should be installed somewhere. I have mine at D:\vcpkg
, so the Windows Justfile recipe is configured to use that path by default - but this can point wherever you want.
Note
Building video.hdll
is disabled, since it depends on some weird ffmpeg stuff that I'm too lazy to actually get working. I haven't seen a game that actually depends on it yet, so it's Probably Fine™ to just leave alone.
Warning
MacOS is not supported yet. The only supported targets are Linux (glibc) and Windows (MSVC). musl should work, and so should Cygwin, but they are untested and unsupported.
The Justfile has recipes in it to handle this for you:
prepare
andbuild
on Linuxprepare-win
andbuild-win
on Windows
Basically, this boils down to:
# For linux
mkdir -p hlmod-hl/build
pushd hlmod-hl/build
cmake -G "Ninja" ..
cmake --build . --parallel
popd
or
mkdir hlmod-hl\build
"C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat" x64
@rem Make sure to change D:/vcpkg to wherever you installed vcpkg!
cmake -G "Ninja" .. -DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows
cmake --build . --parallel
cd ..
cd ..
Then, binaries will be at hlmod-hl/build/bin
, as normal.
Note
The hl
JIT VM binary built from hlmod-hl
expects there to be a directory ./mods
from the working dir, containing mods to be loaded! You should copy over hlmod.pyi
and modcore.py
from this repo's mods/
directory as the base library for other mods to reference.
- Modify the JIT compiler as LITTLE as possible. The more assembly we generate, the more unstable the VM becomes. Keep your ASM short, and write trampolines to C instead of full routines.
- The end user shouldn't have to memorize internal HL incantations to be able to write a basic mod. When in doubt, cast to and from a similar builtin Python class rather than write a full wrapper that may have incompatibilities with Python's std.
- Keep low-level APIs on the C side, then wrap them in nice Pythonic functions in
modcore
. For example,hlmod.register_hook
is wrapped by a Pythonic decorator inmodcore.hook
.