A thin Java wrapper for the Steamworks C++ API.
About
Getting started
Build instructions
Known issues
Showcase
To add Steamworks support, you just have to download and add the appropriate JAR files to your Java project.
steamworks4j-1.10.0.jar is required to use the client API.steamworks4j-gdx-1.10.0.jar or steamworks4j-lwjgl-1.10.0.jar if you are using either libGDX or LWJGL3. These are optional dependencies. You won’t need them if you can provide your own method of loading native shared libraries.steamworks4j-server-1.10.0.jar if you need to support game servers or encrypted app tickets.Major updates are released on Maven Central, so the easiest way is to add the library as an external dependency, using your favorite build environment.
Maven:
<dependencies>
<!-- client API -->
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j</artifactId>
<version>1.10.0</version>
</dependency>
<!-- libGDX loader -->
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-gdx</artifactId>
<version>1.10.0</version>
</dependency>
<!-- LWJGL3 loader -->
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-lwjgl3</artifactId>
<version>1.10.0</version>
</dependency>
<!-- server API -->
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-server</artifactId>
<version>1.10.0</version>
</dependency>
</dependencies>Gradle:
apply plugin: 'java-library'
implementation "com.code-disaster.steamworks4j:steamworks4j:1.10.0"
implementation "com.code-disaster.steamworks4j:steamworks4j-gdx:1.10.0"
implementation "com.code-disaster.steamworks4j:steamworks4j-lwjgl3:1.10.0"
implementation "com.code-disaster.steamworks4j:steamworks4j-server:1.10.0"If you don’t use any build tools, direct downloads of .jar files are also available.
Snapshot builds of the latest version may be available on Maven Central too.
Maven:
<repositories>
<repository>
<url>https://central.sonatype.com/repository/maven-snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j</artifactId>
<version>1.10.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-gdx</artifactId>
<version>1.10.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-lwjgl3</artifactId>
<version>1.10.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.code-disaster.steamworks4j</groupId>
<artifactId>steamworks4j-server</artifactId>
<version>1.10.0-SNAPSHOT</version>
</dependency>
</dependencies>Gradle:
repositories {
maven {
url "https://central.sonatype.com/repository/maven-snapshots/"
}
}
apply plugin: 'java-library'
implementation "com.code-disaster.steamworks4j:steamworks4j:1.10.0-SNAPSHOT"
implementation "com.code-disaster.steamworks4j:steamworks4j-gdx:1.10.0-SNAPSHOT"
implementation "com.code-disaster.steamworks4j:steamworks4j-lwjgl3:1.10.0-SNAPSHOT"
implementation "com.code-disaster.steamworks4j:steamworks4j-server:1.10.0-SNAPSHOT"To learn how to build the library from source code, please refer to the build instructions.
You’ll notice that the library source code is documented very scarcely. That’s a deliberate choice. I assume that you are a registered Steam developer and have access to the Steamworks documentation as your primary source of information.
Please refer to the official documentation to learn about the steps needed to prepare your application for use with Steam. Here’s a very brief checklist:
As a first step, to load the native libraries, you need to call SteamAPI.loadLibraries(). Since steamworks4j 1.10.0, this function requires a SteamLibraryLoader parameter.
// with libGDX - requires steamworks4j-gdx
SteamLibraryLoader loader = new SteamLibraryLoaderGdx();
// .. or via LWJGL3 - requires steamworks4j-lwjgl3
SteamLibraryLoader loader = new SteamLibraryLoaderLwjgl3();
// optionally, tell the loader where to find binaries
loader.setLibraryPath("bin");
SteamAPI.loadLibraries(loader);If you already have a means of loading native libraries in your code, you can implement
SteamLibraryLoaderyourself, or “empty drive” this function withSteamAPI.loadLibraries(new SteamLibraryLoader()). In this case, you’ll need to locate and load the shared libraries (steam_api,steamworks4j) yourself. Please check the GDX and LWJGL3 loaders as a reference - their code is pretty small and simple.
After the native libraries have been loaded, call SteamAPI.init().
try {
SteamLibraryLoader loader = ...;
if (!SteamAPI.loadLibraries(loader)) {
// Failed to load native libraries
}
if (!SteamAPI.init()) {
// Steamworks initialization error, e.g. Steam client not running
}
} catch (SteamException e) {
// You probably messed up the call order somehow
}It’s legal to call some functions inbetween
SteamAPI.loadLibraries()andSteamAPI.init(). One prominent example would beSteamAPI.restartAppIfNecessary().
By default, both the GDX and LWJGl3 loaders auto-detect the operating system the game runs on, then extract and load the appropriate native libraries from your classpath. There’s a SteamLibraryLoader.setLibraryPath() function which allows to specify a folder containing the native libraries.
Add a call to SteamAPI.runCallbacks() to your game loop. The Steamworks docs recommend to call this at least 15 times per second, but I haven’t seen any performance impact if e.g. called each frame at 60 fps.
if (SteamAPI.isSteamRunning()) {
SteamAPI.runCallbacks();
}The steamworks4j library follows the Steamworks C++ API as close as feasible. In general, for each interface exposed by the C++ API, there’s an equivalent Java class (if implemented). For example, the SteamUserStats Java class provides access to the ISteamUserStats C++ API.
At present, not all interfaces are implemented by the Java library. Some of those which are, do not expose the full API. In general, I’ve added everything I needed for our own games, plus what I’ve been asked to. Feel free to send feature requests, or even better, pull requests on Github to add the functions and interfaces still missing.
If a C++ interface contains functions which trigger STEAM_CALLBACK() or CCallResult<> style callbacks (say, most of them), the Java class is accompanied by a callback interface which must be implemented by the user application.
public class MyAppUserStatsCallback
implements SteamUserStatsCallback {
// ... application-specific implementation
}
SteamUserStatsCallback callback = new MyAppUserStatsCallback();
SteamUserStats stats = new SteamUserStats(callback);It is only guaranteed that, at any time, each instance of an interface does only receive callbacks related to its latest respective API call. In practice this means that the application shouldn’t “batch-execute” the same API function, then wait for a bunch of callbacks. Instead, only one single API call should be issued. Then the application should wait for the callback, process it, then execute the next API call.
If you really want to execute more of the same callback-triggering function in parallel, you have to create and maintain multiple instances of that interface.
Every interface instance (each instance of a class derived from SteamInterface) may allocate a few bytes of native heap memory. You should call SteamInterface.dispose() on shutdown to prevent memory leaks.
stats.dispose();To shut down the Steamworks API, just call SteamAPI.shutdown(). This may flush (sync) any pending client data, e.g. achievements and user stats, so you should make sure your application exists gracefully.
SteamAPI.shutdown();Since steamworks4j v1.7.0, server functions reside in a separate Maven module, steamworks4j-server.
Basic API use is similar to the client wrapper, just with SteamGameServerAPI as the main entry point.
// initialization
try {
SteamLibraryLoader loader = ...;
if (!SteamGameServerAPI.loadLibraries(loader)) {
// Failed to load native libraries
}
if (!SteamGameServerAPI.init((127 << 24) + 1, (short) 27016, (short) 27017,
SteamGameServerAPI.ServerMode.NoAuthentication, "0.0.1")) {
// initialization error
}
} catch (SteamException e) {
// You probably messed up the call order somehow
}
// update ticks
while (serverIsAlive) {
SteamGameServerAPI.runCallbacks();
}
// shutdown
SteamGameServerAPI.shutdown();The SteamEncryptedAppTicket wrapper is part of the server module, but works as a stand-alone since it only depends on the sdkencryptedappticket shared library. Its use is simple - you just need to ensure that the native libraries are loaded first.
SteamLibraryLoader loader = ...;
if (!SteamEncryptedAppTicket.loadLibraries(loader)) {
// Failed to load native libraries
}
SteamEncryptedAppTicket encryptedAppTicket = new SteamEncryptedAppTicket();The steamworks-tests module contains some console applications which demonstrate use of the Java API and some of its interfaces.