Zig bindings for Steamworks, compatible with v1.57 (March 2023).
The bindings are autogenerated from the C bindings and are compatible with
- macOS (both Apple Silicon and Intel)
- linux (x86_64)
- windows (x86_64)
This project uses Zig 0.11.0-dev
Due to licence agreements, you must bring your own SDK. This project assumes it is located in the ./steamworks folder. But you can have it anywhere else.
// build.zig
const zig_steamworks = @import("zig-steamworks/linker.zig");
fn main() !void {
// ...
const exe = b.addExecutable( ... );
// link steamworks to this executable
_ = try zig_steamworks.linkSteamLibrary(b, exe, "steamworks");
// relative path to steamworks ^^^^^^^^^^
// you must include the steam_appid.txt file in your final directory
try zig_steamworks.copy(comptime zig_steamworks.thisDir() ++ "/src", "zig-out/bin", "steam_appid.txt");
}
For convenience, this repository offers already built bindings for Zig in the src
folder. Until Zig modules and package manager are mature, the recommended course of action is to copy these files into your project.
To re-build the files run the following command
node generate.js path_to_steamworks/public/steam/steam_api.json
const std = @import("std");
const steam = @import("steam.zig");
/// callback hook for debug text emitted from the Steam API
pub fn SteamAPIDebugTextHook(nSeverity: c_int, pchDebugText: [*c]const u8) callconv(.C) void {
// if you're running in the debugger, only warnings (nSeverity >= 1) will be sent
// if you add -debug_steamapi to the command-line, a lot of extra informational messages will also be sent
std.debug.print("SteamAPIDebugTextHook sev:{} msg: {s}\n", .{ nSeverity, pchDebugText });
}
/// get an authentication ticket for our user
fn authTicket(identity: *steam.SteamNetworkingIdentity) !void {
var rgchToken: *[2048]u8 = try std.heap.c_allocator.create([2048]u8);
var unTokenLen: c_uint = 0;
var m_hAuthTicket = steam.SteamUser().GetAuthSessionTicket(rgchToken, 2048, &unTokenLen, identity);
std.debug.print("GetAuthSessionTicket={} len={} token={s}", .{ m_hAuthTicket, unTokenLen, rgchToken });
}
pub fn main() !void {
if (steam.SteamAPI_RestartAppIfNecessary(480)) {
// if Steam is not running or the game wasn't started through Steam, SteamAPI_RestartAppIfNecessary starts the
// local Steam client and also launches this game again.
// Once you get a public Steam AppID assigned for this game, you need to replace k_uAppIdInvalid with it and
// removed steam_appid.txt from the game depot.
@panic("SteamAPI_RestartAppIfNecessary");
}
if (steam.SteamAPI_Init()) {
std.debug.print("Steam initialized correctly. \n", .{});
} else {
@panic("Steam did not init\n");
}
steam.SteamClient().SetWarningMessageHook(SteamAPIDebugTextHook);
defer steam.SteamAPI_Shutdown();
std.debug.print("User {?}\n", .{steam.SteamUser().GetSteamID()});
var sock = steam.SteamNetworkingSockets_SteamAPI();
var pInfo: *steam.SteamNetworkingFakeIPResult_t = try std.heap.c_allocator.create(steam.SteamNetworkingFakeIPResult_t);
defer std.heap.c_allocator.destroy(pInfo);
sock.GetFakeIP(0, pInfo);
std.debug.print("GetFakeIP: {}\n", .{pInfo});
if (!pInfo.m_identity.IsEqualTo(pInfo.m_identity)) @panic("not equal");
var pDetails: *steam.SteamNetAuthenticationStatus_t = try std.heap.c_allocator.create(steam.SteamNetAuthenticationStatus_t);
defer std.heap.c_allocator.destroy(pDetails);
var connectionStatus = sock.GetAuthenticationStatus(pDetails);
std.debug.print("GetAuthenticationStatus: {} {}\n", .{ connectionStatus, pDetails });
var pIdentity: *steam.SteamNetworkingIdentity = try std.heap.c_allocator.create(steam.SteamNetworkingIdentity);
std.heap.c_allocator.destroy(pIdentity);
var r = sock.GetIdentity(pIdentity);
std.debug.print("GetIdentity={} {}\n", .{ r, pIdentity });
try authTicket(pIdentity);
}
Steamworks is packed with pragma packs
, I've tried dozens of approaches even brute forcing all structs, but getting the right alignment for every struct was impossible. So I took the good-enough-and-not-so-elegant path of delegating the alignment to the C compiler entirely and then forcing Zig to copy everything with the generated code. In effect, you will see a lot of align(...)
in the generated code.
In practice both Mac and Linux alignments are the same.
Please do the following steps for each steamworks release that is added to this repo. Mind the diff in the steamworks headers to remove the private fields (search for // ZIG:
).
# open a docker container using x86_64
docker run -v $(pwd):/mnt -w /mnt --rm -it --platform linux/amd64 mcr.microsoft.com/devcontainers/typescript-node:0-18 zsh
# install zig
sudo bash .devcontainer/install-zig.sh
# run the script and grab a coffee
bash ./create-align-info-linux.sh
# run the script
bash ./create-align-info-mac.sh
# run the script
.\create-align-info-mac.bat