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.

The C# binding is a single generated file (LiveSplitCore.cs) that lives in the LiveSplitCore namespace. It uses P/Invoke (Platform Invocation Services) to call into the native livesplit_core library without any C++/CLI or interop assemblies.

How the binding is structured

The generator produces three C# classes per livesplit-core type, mirroring the ownership model of the Rust C API:
ClassRust equivalentResponsibility
TimerRef&TimerShared borrow — no cleanup
TimerRefMut&mut TimerMutable borrow — no cleanup
TimerOwnedTimerOwned — must call Dispose()
Each owned class (Timer, Run, Segment, etc.) implements IDisposable and holds an IntPtr to the native object. The binding also provides an internal LiveSplitCoreNative static class that contains all the raw [DllImport] declarations:
[DllImport("livesplit_core", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr Timer_new(IntPtr run);

[DllImport("livesplit_core", CallingConvention = CallingConvention.Cdecl)]
public static extern void Timer_drop(IntPtr self);
A helper LSCoreString class (derived from SafeHandle) handles marshalling UTF-8 strings between managed and native memory automatically.

Setup

  1. Copy LiveSplitCore.cs into your project (any folder).
  2. Copy the native library next to your executable:
    • livesplit_core.dll on Windows
    • liblivesplit_core.so on Linux
    • liblivesplit_core.dylib on macOS
  3. No NuGet package or additional reference is required — just the two files.
The native library must be resolvable at runtime. Place it in the application directory, add its folder to PATH / LD_LIBRARY_PATH, or use NativeLibrary.SetDllImportResolver to control loading explicitly.

Example

using System;
using LiveSplitCore;

// Run_new is non-nullable so the generator emits a constructor
var run = new Run();
run.SetGameName("Hollow Knight");
run.SetCategoryName("Any%");

// Segment_new is also non-nullable → constructor
run.PushSegment(new Segment("Forgotten Crossroads"));
run.PushSegment(new Segment("Greenpath"));

// Timer_new returns a nullable pointer, so the generator emits a static factory
// method Timer.New() that returns Timer? (null when the run has no segments)
var timer = Timer.New(run) ?? throw new Exception("Run must have at least one segment");

// After New(), `run` is consumed — its ptr is zeroed in the binding
timer.Start();
timer.Split();
timer.Reset(true); // true = update splits / save attempt

// Dispose releases native memory and suppresses the finalizer
timer.Dispose();
Using using statements for automatic disposal:
using var run = new Run();
run.SetGameName("Celeste");
run.SetCategoryName("Any%");
run.PushSegment(new Segment("Prologue"));

using var timer = Timer.New(run)
    ?? throw new InvalidOperationException("Run must have segments");

timer.Start();
timer.Split();
// timer.Dispose() is called automatically at end of scope

Ownership rules

  • Every owned object (Run, Timer, Segment, …) has a finalizer that calls Drop() if you forget to dispose it, but relying on the finalizer delays cleanup indefinitely.
  • When you pass an owned object to a function (e.g. Timer.New(run)), the binding zeroes the pointer of the passed object immediately — you must not use it afterwards.
  • Ref and RefMut subclasses are references into another object’s lifetime; never dispose them directly.

Unity

  1. Build the native library for your target platform(s).
  2. Copy the platform-specific library to Assets/Plugins/ (or a platform subdirectory such as Assets/Plugins/x86_64/).
  3. Select the library asset in the Unity Editor and configure the Platform settings under the Inspector (OS, CPU architecture).
  4. Copy LiveSplitCore.cs anywhere inside Assets/.
  5. The [DllImport("livesplit_core")] attribute matches the asset name automatically on all desktop and Android platforms.

Build docs developers (and LLMs) love