Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/LiveSplit/livesplit-core/llms.txt

Use this file to discover all available pages before exploring further.

livesplit-core ships two Java-family binding strategies. Both produce idiomatic class hierarchies (with Ref, RefMut, and owned variants), but they use different mechanisms to call the native library.
StrategyMechanismBest for
JNAcom.sun.jna.Native.loadLibraryDesktop Java — no JNI glue required
JNIJNI C++ bridge + System.loadLibraryAndroid; highest-performance path
The binding generator (capi/bind_gen) outputs both. Generated files live in capi/bindings/java/jna/ and capi/bindings/java/jni/, plus a shared LiveSplitCoreJNI.cpp bridge file. Kotlin bindings are JNI-only and live in capi/bindings/kotlin/jni/.

Dependencies

Add JNA to your project:
<!-- Maven -->
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.14.0</version>
</dependency>
// Gradle
implementation 'net.java.dev.jna:jna:5.14.0'

How the binding works

The generator produces a LiveSplitCoreNative interface that extends Library and loads the shared library by name:
import com.sun.jna.*;

public interface LiveSplitCoreNative extends Library {
    LiveSplitCoreNative INSTANCE = (LiveSplitCoreNative)
        Native.loadLibrary("livesplit_core", LiveSplitCoreNative.class);

    Pointer Run_new();
    void    Run_drop(Pointer self);
    // ... all other functions
}
Each livesplit-core type gets three classes — RunRef, RunRefMut, and Run — mirroring the ownership semantics of the Rust C API. Only the owned class (Run, Timer, …) has a drop() method.

Naming conventions

Because new, clone, close, and default are reserved or problematic in Java, the generator renames them:
Rust methodJava method
new (nullable)create()
new (non-nullable)constructor
clonecopy()
closefinish()
defaultcreateDefault()
All other method names are converted to lowerCamelCase.

Example

import livesplitcore.*;

// Run_new is non-nullable → Java constructor
Run run = new Run();
run.setGameName("Super Metroid");
run.setCategoryName("Any%");
run.pushSegment(new Segment("Ceres Station"));

// Timer_new is nullable → static factory Timer.create(run)
Timer timer = Timer.create(run);
if (timer == null) {
    throw new RuntimeException("Run must have at least one segment");
}

timer.start();
timer.split();
timer.reset(true); // true = update splits

// Free native memory
timer.drop();
Always call .drop() on every owned object when you are done with it. The JNA binding does not register a finalizer that guarantees cleanup.

Build docs developers (and LLMs) love