Rust #
Rust is a very fast programming language which can be compiled into standalone binary files (in other words: executables; these are the files with .exe extension on Windows). This makes sharing simple Rust applications with others much easier than for example an equivalent Python application.
If you don’t have experience with programming in Rust, you should probably check out the Rust Book or the Interactive Rust Book first. There are also many beginner Youtube tutorials. For experienced developers who are not familiar with Rust, or for particularly impatient and savvy beginners, this blog post and the corresponding video are a decent overview of Rust syntax and features.
Setup (Windows) #
If you don’t have Rust installed on your computer yet, follow the guide for basic Rust installation first. If you already installed VSCodium for the purpose of editing Lua scripts, it can also be used for editing Rust source files. Make sure to install the rust-analyzer extension to be able to use type hints for Rust.
To create programs interacting with Dwarf Fortress in the Rust programming language, you can use the dfhack_remote crate. Once Rust is installed and you verified that building a basic Hello World! application is working correctly, add the following dependency in Cargo.toml file:
[dependencies]
dfhack-remote = { git = "https://github.com/plule/dfhack-remote.git" }
You should now be able to use dfhack_remote in your application!
Features of dfhack_remote #
The crate dfhack_remote reflects all functionalities available through DFHack remote interface, such as running commands. Don’t worry, you don’t have to figure out what protobuf messages are - the crate handles them all for you!
Connecting to Dwarf Fortress #
To connect to Dwarf Fortress create a client variable:
fn main() {
let mut client = dfhack_remote::connect().unwrap();
}
In this tutorial we call the variable a client after a client-server model since DFHack is running a server. However, it’s only a convention - you can replace that name with anything you wish, as long as it doesn’t collide with anything else.
Running commands / Lua scripts #
Create a command and receive a reply from it:
use dfhack_remote::CoreRunCommandRequest;
fn main() {
let mut client = dfhack_remote::connect().unwrap();
let mut command = CoreRunCommandRequest::new();
command.set_command("my-lua-script".to_string());
// Optional - only if the script / command requires extra arguments----
command.arguments.push("script-argument-1".to_string());
command.arguments.push("script-argument-2".to_string());
// --------------------------------------------------------------------
let reply = client.core().run_command(command).unwrap();
}
… #
(to do)
Example applications #
Developer’s examples #
The crate’s developer makes some examples available in the examples directory in the crate’s Github repository.
dfhack-run #
Simple application mimicking the original dfhack-run functionality of running commands and custom Lua scripts.
main.rs:
use dfhack_remote::CoreRunCommandRequest;
use std::env::args;
fn main() {
let args_count = args().count();
let mut input = args();
let mut client = dfhack_remote::connect().unwrap();
let mut command = CoreRunCommandRequest::new();
let lua_script = input.by_ref().skip(1).take(1).next().unwrap().to_string();
command.set_command(lua_script);
if args_count > 2 {
for _ in 1..args_count-1 {
let lua_argument = input.by_ref().take(1).next().unwrap().to_string();
command.arguments.push(lua_argument);
};
};
let reply = client.core().run_command(command).unwrap();
println!(
"{}",
reply.fragments[0].text().trim(),
);
}
You can run the built executable like this:
& "C:\...\target\debug\dfhack_run.exe" "my-lua-script" "script-argument-1" "script-argument-2"
Note that depending on whether you are using PowerShell or regular Windows Terminal, you might or might not need the & symbol in front of the executable’s path.