Using Loreline with Java
Loreline provides a Java library packaged as a single JAR, compatible with Java 8+ and any JVM language. This guide uses Java for its examples, but the library works just as well with Kotlin or any other language that runs on the JVM. It covers how to set up a project, load a .lor script, and handle dialogue, choices, and script completion.
Setting up your project
Download loreline-jvm.zip from the GitHub releases page. The archive contains:
loreline.jar: the Loreline library (no external dependencies)- A complete Swing sample project you can use as a starting point
Add loreline.jar to your classpath. To compile and run a simple program:
javac -cp loreline.jar MyStory.java
java -cp loreline.jar:. MyStory
On Windows, use ; instead of : as the classpath separator:
java -cp loreline.jar;. MyStory
Loading a script
Use Loreline.parse() to parse a .lor string. The second and third arguments handle import statements in your script:
import loreline.*;
import java.nio.file.*;
String content = Files.readString(Path.of("story/CoffeeShop.lor"));
Script script = Loreline.parse(content, "CoffeeShop.lor",
path -> Files.readString(Path.of("story/" + path)));
Loreline.play(script, this::onDialogue, this::onChoice, this::onFinish);
If your script has no import statements, you can omit the file handler:
Script script = Loreline.parse(content);
Handling dialogue
The dialogue handler receives the interpreter, a character identifier (or null for narrative text), the dialogue text, any tags, and a Runnable to advance the script:
void onDialogue(Interpreter interpreter, String character, String text,
List<TextTag> tags, Runnable advance) {
if (character != null) {
// Resolve display name from character definition
Object nameObj = interpreter.getCharacterField(character, "name");
String name = nameObj != null ? nameObj.toString() : character;
System.out.println(name + ": " + text);
} else {
// Narrative text (no character)
System.out.println(text);
}
advance.run();
}
Handling choices
The choice handler receives a list of ChoiceOption items. Each option has a text field and an enabled field. Call the IntConsumer with the index of the selected choice:
void onChoice(Interpreter interpreter, List<ChoiceOption> options,
IntConsumer select) {
List<Integer> enabled = new ArrayList<>();
for (int i = 0; i < options.size(); i++) {
if (options.get(i).enabled) {
enabled.add(i);
System.out.println(" [" + enabled.size() + "] " + options.get(i).text);
}
}
// Read player input
Scanner scanner = new Scanner(System.in);
System.out.print("> ");
int choice = scanner.nextInt();
select.accept(enabled.get(choice - 1));
}
Handling script completion
The finish handler is called when the script reaches its end:
void onFinish(Interpreter interpreter) {
System.out.println("--- The End ---");
}
Starting from a specific beat
By default, play() starts from the beginning of the script. To start from a specific beat, pass its name:
Engine.play(script, onDialogue, onChoice, onFinish, "MorningScene", null);
Interpreter options
You can pass additional options to play() to register custom functions, apply translations, or enable strict variable access:
InterpreterOptions options = new InterpreterOptions();
options.functions = new HashMap<>();
options.functions.put("roll", (interp, args) ->
(int)(Math.random() * ((Number)args[0]).intValue()) + 1);
options.translations = Engine.extractTranslations(script);
options.strictAccess = true;
Engine.play(script, onDialogue, onChoice, onFinish, null, options);
Complete example
Here is a complete console application that loads and plays a Loreline script:
import loreline.*;
import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.function.IntConsumer;
public class MyStory {
static String storyDir = "story/";
static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) throws IOException {
String content = Files.readString(Path.of(storyDir + "CoffeeShop.lor"));
Script script = Loreline.parse(content, "CoffeeShop.lor",
path -> readFile(storyDir + path));
if (script != null) {
Loreline.play(script, MyStory::onDialogue, MyStory::onChoice, MyStory::onFinish);
}
}
static String readFile(String path) {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
return null;
}
}
static void onDialogue(Interpreter interpreter, String character, String text,
List<TextTag> tags, Runnable advance) {
if (character != null) {
Object nameObj = interpreter.getCharacterField(character, "name");
String name = nameObj != null ? nameObj.toString() : character;
System.out.println(name + ": " + text);
} else {
System.out.println(text);
}
System.out.println();
advance.run();
}
static void onChoice(Interpreter interpreter, List<ChoiceOption> options,
IntConsumer select) {
List<Integer> enabled = new ArrayList<>();
for (int i = 0; i < options.size(); i++) {
if (options.get(i).enabled) {
enabled.add(i);
System.out.println(" [" + enabled.size() + "] " + options.get(i).text);
}
}
System.out.print("> ");
int choice = scanner.nextInt();
select.accept(enabled.get(choice - 1));
}
static void onFinish(Interpreter interpreter) {
System.out.println("--- The End ---");
}
}
Going further
For a polished desktop example with Swing rendering, animations, and styled output, see the sample project included in loreline-jvm.zip from the GitHub releases page.