Utiliser Loreline avec C#

Loreline fournit une bibliothèque C# compatible avec tout environnement C# prenant en charge .NET Standard 2.1 (y compris Unity). Ce guide montre comment configurer un projet, charger un script .lor, et gérer les dialogues, les choix et la fin du script.

Configuration pour les projets .NET

Téléchargez loreline-csharp.zip depuis la page des releases GitHub. L'archive contient :

Vous pouvez soit référencer la DLL directement dans votre .csproj :

<Reference Include="Loreline">
  <HintPath>chemin/vers/Loreline.dll</HintPath>
</Reference>

Ou ajouter le Loreline.csproj inclus à votre solution si vous préférez compiler depuis les sources :

<ProjectReference Include="chemin/vers/Loreline.csproj" />

Configuration pour Unity

Téléchargez loreline-unity.zip depuis la page des releases GitHub. L'archive contient un projet Unity complet avec le plugin Loreline, utilisable comme point de départ ou comme référence pour intégrer Loreline dans votre propre projet.

Pour ajouter Loreline à un projet Unity existant :

  1. Depuis l'archive, copiez le dossier Assets/Plugins/Loreline/ dans Assets/Plugins/Loreline/ de votre propre projet Unity
  2. Placez vos fichiers .lor dans Assets/Resources/ avec l'extension .lor.txt (Unity nécessite le suffixe .txt pour le chargement via TextAsset)

Charger un script

Utilisez Engine.Parse() pour analyser une chaîne .lor. Le troisième argument est un callback de fichier pour résoudre les instructions import :

using Loreline;
using System.IO;

string content = File.ReadAllText("story/CoffeeShop.lor");

void HandleFile(string path, Engine.ImportsFileCallback callback)
{
    string text = File.ReadAllText("story/" + path);
    callback(text);
}

Script script = Engine.Parse(content, "CoffeeShop.lor", HandleFile);
Engine.Play(script, OnDialogue, OnChoice, OnFinish);

Avec Unity, utilisez Resources.Load<TextAsset>() au lieu des E/S fichier :

using Loreline;
using UnityEngine;

TextAsset mainAsset = Resources.Load<TextAsset>("CoffeeShop.lor");

void HandleFile(string path, Engine.ImportsFileCallback callback)
{
    string name = Path.GetFileNameWithoutExtension(path) + ".lor";
    TextAsset asset = Resources.Load<TextAsset>(name);
    callback(asset != null ? asset.text : null);
}

Script script = Engine.Parse(mainAsset.text, "CoffeeShop.lor", HandleFile);
Engine.Play(script, OnDialogue, OnChoice, OnFinish);

Si votre script n'a pas d'instructions import, vous pouvez omettre le callback de fichier :

Script script = Engine.Parse(content);

Gérer les dialogues

Le callback de dialogue reçoit une struct Interpreter.Dialogue avec des propriétés pour le personnage, le texte, les tags, l'interpréteur et un callback pour faire avancer le script :

void OnDialogue(Interpreter.Dialogue dialogue)
{
    string character = dialogue.Character;

    if (character != null)
    {
        // Résoudre le nom d'affichage depuis la définition du personnage
        string displayName = (string)dialogue.Interpreter.GetCharacterField(character, "name");
        if (displayName != null) character = displayName;
        Console.WriteLine(character + " : " + dialogue.Text);
    }
    else
    {
        // Texte narratif (pas de personnage)
        Console.WriteLine(dialogue.Text);
    }

    dialogue.Callback();
}

Gérer les choix

Le callback de choix reçoit une struct Interpreter.Choice avec un tableau de ChoiceOption. Chaque option a un champ Text et un champ Enabled. Appelez le callback avec l'index du choix sélectionné :

void OnChoice(Interpreter.Choice choice)
{
    var enabled = new List<int>();
    for (int i = 0; i < choice.Options.Length; i++)
    {
        if (choice.Options[i].Enabled)
        {
            enabled.Add(i);
            Console.WriteLine("  [" + enabled.Count + "] " + choice.Options[i].Text);
        }
    }

    Console.Write("> ");
    int selected = int.Parse(Console.ReadLine());
    choice.Callback(enabled[selected - 1]);
}

Gérer la fin du script

Le callback de fin est appelé quand le script atteint sa fin :

void OnFinish(Interpreter.Finish finish)
{
    Console.WriteLine("--- Fin ---");
}

Démarrer depuis un beat spécifique

Par défaut, Play() démarre depuis le début du script. Pour démarrer depuis un beat spécifique, passez son nom :

Engine.Play(script, OnDialogue, OnChoice, OnFinish, "MorningScene");

Options de l'interpréteur

Vous pouvez passer des options supplémentaires à Play() pour enregistrer des fonctions personnalisées, appliquer des traductions ou activer l'accès strict aux variables :

var options = new Interpreter.InterpreterOptions
{
    Functions = new Dictionary<string, Interpreter.Function>
    {
        ["roll"] = (interp, args) => new Random().Next(1, (int)args[0] + 1)
    },
    Translations = Engine.ExtractTranslations(script),
    StrictAccess = true
};

Engine.Play(script, OnDialogue, OnChoice, OnFinish, null, options);

Exemple complet

Voici une application console .NET complète qui charge et exécute un script Loreline :

using System;
using System.Collections.Generic;
using System.IO;
using Loreline;

class Program
{
    static string storyDir = "story/";

    static void Main(string[] args)
    {
        string content = File.ReadAllText(storyDir + "CoffeeShop.lor");
        Script script = Engine.Parse(content, "CoffeeShop.lor", HandleFile);

        if (script != null)
        {
            Engine.Play(script, OnDialogue, OnChoice, OnFinish);
        }
    }

    static void HandleFile(string path, Engine.ImportsFileCallback callback)
    {
        try
        {
            callback(File.ReadAllText(storyDir + path));
        }
        catch
        {
            callback(null);
        }
    }

    static void OnDialogue(Interpreter.Dialogue dialogue)
    {
        string character = dialogue.Character;
        if (character != null)
        {
            string name = (string)dialogue.Interpreter.GetCharacterField(character, "name");
            if (name != null) character = name;
            Console.WriteLine(character + " : " + dialogue.Text);
        }
        else
        {
            Console.WriteLine(dialogue.Text);
        }
        Console.WriteLine();
        dialogue.Callback();
    }

    static void OnChoice(Interpreter.Choice choice)
    {
        var enabled = new List<int>();
        for (int i = 0; i < choice.Options.Length; i++)
        {
            if (choice.Options[i].Enabled)
            {
                enabled.Add(i);
                Console.WriteLine("  " + enabled.Count + ". " + choice.Options[i].Text);
            }
        }

        while (true)
        {
            Console.Write("\n> ");
            string input = Console.ReadLine();
            if (input == null) break;
            if (int.TryParse(input.Trim(), out int selected)
                && selected >= 1 && selected <= enabled.Count)
            {
                choice.Callback(enabled[selected - 1]);
                return;
            }
            Console.WriteLine("  Veuillez entrer un numéro de choix valide.");
        }
    }

    static void OnFinish(Interpreter.Finish finish)
    {
        Console.WriteLine("\n--- Fin ---");
    }
}

Aller plus loin

Pour un projet Unity complet avec UI Toolkit, animations et sortie stylisée, le téléchargement loreline-unity.zip depuis les releases GitHub inclut un exemple fonctionnel complet.