Using Loreline with Godot
Loreline provides a GDExtension plugin for Godot 4.2+. This guide shows how to set up your project, load a .lor script, and handle dialogue, choices, and script completion using GDScript.
Setup
Download loreline-godot.zip from the GitHub releases page. The archive contains:
addons/loreline/: the GDExtension plugin with native binaries for all platforms (macOS, Windows, Linux, Android, iOS, Web)sample/: a complete Godot project demonstrating the integration with UI, animations, and styled output
To add Loreline to your project, copy the addons/loreline/ folder into the addons/ directory of your own Godot project.
Loading a script
Get the shared Loreline instance, then call loreline.parse() with the resource path to your .lor file:
var loreline: Loreline = Loreline.shared()
func _ready() -> void:
var script_data: LorelineScript = loreline.parse("res://story/CoffeeShop.lor")
Loreline handles file reading and import resolution automatically.
Custom loading
If you need to control how files are loaded (e.g. encrypted files, network resources), you can load the source yourself and pass it to parse(). The second argument is the file path (used to resolve relative import paths), and the third is a callback called to load each file imported by the script:
var file := FileAccess.open("res://story/CoffeeShop.lor", FileAccess.READ)
var source := file.get_as_text()
file.close()
script_data = loreline.parse(source, "res://story/CoffeeShop.lor", _handle_file)
The file handler is not used for the root file (which you load yourself), but for each file referenced via import in the script. It receives the resolved path and returns the content as a string:
func _handle_file(path: String) -> String:
var f := FileAccess.open(path, FileAccess.READ)
if f == null:
return ""
return f.get_as_text()
Handling dialogue
Start playback by calling loreline.play() with the parsed script and your handler functions:
loreline.play(script_data, _on_dialogue, _on_choice, _on_finished)
The dialogue handler receives the interpreter, the character identifier, the text, an array of tags, and a callable to advance the script. Call advance.call() to continue to the next line:
func _on_dialogue(interp: LorelineInterpreter, character: String, text: String, tags: Array, advance: Callable) -> void:
if character != "":
var display_name: String = interp.get_character_field(character, "name")
if display_name != "":
character = display_name
print(character + ": " + text)
else:
print(text)
advance.call()
Handling choices
The choice handler receives the interpreter, an array of option dictionaries, and a callable to select an option. Each option has a "text" field and an "enabled" field. Call select.call(index) with the index of the chosen option:
func _on_choice(_interp: LorelineInterpreter, options: Array, select: Callable) -> void:
var enabled_indices: Array[int] = []
for i in range(options.size()):
if options[i]["enabled"]:
enabled_indices.append(i)
print(" [" + str(enabled_indices.size()) + "] " + options[i]["text"])
# In a real project, wait for player input here.
# For this example, automatically select the first enabled choice:
select.call(enabled_indices[0])
Handling script completion
The finish handler is called when the script reaches its end:
func _on_finished(_interp: LorelineInterpreter) -> void:
print("--- 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:
loreline.play(script_data, _on_dialogue, _on_choice, _on_finished, "MorningScene")
Interpreter options
You can pass additional options to play() to register custom functions, apply translations, or enable strict variable access:
var options := LorelineOptions.new()
options.set_function("roll", func(interp, args): return randi_range(1, int(args[0])))
options.set_strict_access(true)
loreline.play(script_data, _on_dialogue, _on_choice, _on_finished, null, options)
Complete example
Here is a minimal GDScript that loads and plays a Loreline script, printing output to the console. Attach this script to any Node:
extends Node
var loreline: Loreline = Loreline.shared()
var awaiting_choice := false
var enabled_indices: Array[int] = []
var pending_select: Callable
func _ready() -> void:
var script_data := loreline.parse("res://story/CoffeeShop.lor")
if script_data:
loreline.play(script_data, _on_dialogue, _on_choice, _on_finished)
func _on_dialogue(interp: LorelineInterpreter, character: String, text: String, _tags: Array, advance: Callable) -> void:
if character != "":
var display_name: String = interp.get_character_field(character, "name")
if display_name != "":
character = display_name
print(character + ": " + text)
else:
print(text)
print("")
advance.call()
func _on_choice(_interp: LorelineInterpreter, options: Array, select: Callable) -> void:
enabled_indices.clear()
for i in range(options.size()):
if options[i]["enabled"]:
enabled_indices.append(i)
print(" " + str(enabled_indices.size()) + ". " + options[i]["text"])
pending_select = select
awaiting_choice = true
func _unhandled_input(event: InputEvent) -> void:
if not awaiting_choice:
return
if event is InputEventKey and event.pressed:
var num := event.keycode - KEY_1
if num >= 0 and num < enabled_indices.size():
awaiting_choice = false
pending_select.call(enabled_indices[num])
func _on_finished(_interp: LorelineInterpreter) -> void:
print("\n--- The End ---")
Going further
For a complete Godot project with UI, animations, and styled output, the sample/ folder included in the loreline-godot.zip download from the GitHub releases provides a full working example.