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.

Both Ruby and Python bindings are single-file wrappers that call the native livesplit_core shared library through their respective foreign-function-interface mechanisms. Generate them by running the binding generator:
cd capi/bind_gen
cargo run
# Ruby  → capi/bindings/LiveSplitCore.rb
# Python → capi/bindings/livesplit_core.py

Requirements

  • Ruby 2.0+
  • The ffi gem: gem install ffi
  • The livesplit_core native shared library

Library path

The generated file loads the native library with FFI::Library#ffi_lib. By default it resolves relative to the binding file itself:
ffi_lib File.expand_path('../liblivesplit_core.so', __FILE__)
You can override this at generation time with the --ruby-lib-path flag:
cargo run -- --ruby-lib-path /usr/local/lib/liblivesplit_core.so

Class structure

Each type has three Ruby classes:
  • LiveSplitCore::TimerRef — shared borrow (read-only methods)
  • LiveSplitCore::TimerRefMut < TimerRef — mutable borrow
  • LiveSplitCore::Timer < TimerRefMut — owned; dispose and with for cleanup
The owned class registers an ObjectSpace finalizer so the native drop function is called when the Ruby object is garbage-collected — but you should still call dispose explicitly for deterministic cleanup.

Naming conventions

Because new is a reserved Ruby method, the generator renames the _new static function to create:
run = LiveSplitCore::Run.create   # calls Run_new() in C
All other method names use snake_case.

Example

require_relative 'LiveSplitCore'

# Run.create → calls Run_new()
run = LiveSplitCore::Run.create
run.set_game_name('Minecraft')
run.set_category_name('Any%')

# Segment.create → calls Segment_new()
run.push_segment(LiveSplitCore::Segment.create('Enter World'))

# Timer.create → calls Timer_new(); returns nil if run has no segments
timer = LiveSplitCore::Timer.create(run)
raise 'Run must have at least one segment' if timer.nil?

timer.start
timer.split
timer.reset(true)   # true = update splits / save attempt

# Explicit cleanup
timer.dispose
Use with to scope cleanup automatically:
LiveSplitCore::Timer.create(run).with do |timer|
  timer.start
  timer.split
end
# timer.dispose is called here
Although ObjectSpace.define_finalizer is registered, do not rely on it for prompt cleanup. Call dispose or use the with block when you are done with an owned object.

Build docs developers (and LLMs) love