Lingara Lingara Τεκμηρίωση Οδηγοί API Βιβλιοθήκες Εφαρμογές Δημιουργία Ενσωμάτωση Διαδικτυακή εφαρμογή
Γλώσσα: Ελληνικά

Godot

Αυτή η σελίδα έχει μεταφραστεί από τα αγγλικά. Αν οι δύο διαφέρουν, η αγγλική σελίδα είναι η σωστή. Διαβάστε την αγγλική σελίδα

Το Godot προσφέρει δύο γλώσσες, και το Lingara έχει ένα κιτ για την καθεμία. Ένα παιχνίδι GDScript χρησιμοποιεί το addon του Lingara. Ένα παιχνίδι Godot σε C# χρησιμοποιεί το Lingara.Embed, το ίδιο πακέτο που χρησιμοποιεί ένα παιχνίδι Unity. Χρησιμοποιήστε το ένα ή το άλλο σε ένα έργο, ποτέ και τα δύο. Οι καρτέλες παρακάτω δείχνουν το καθένα.

Εγκατάσταση

GDScript. Εγκαταστήστε το addon του Lingara από το Godot Asset Library και έπειτα ενεργοποιήστε το στα Project Settings, Plugins. Η ενεργοποίηση προσθέτει ένα autoload με όνομα Lingara, στο οποίο κάθε σκηνή φτάνει στο /root/Lingara.

C#. Προσθέστε το Lingara.Embed στο έργο σας ως αναφορά πακέτου. Ο κόμβος-παράδειγμα παρακάτω, LingaraEmbedNode, δεν αποτελεί μέρος του πακέτου: προσθέστε τον πηγαίο κώδικά του στο έργο σας και τοποθετήστε τον σε μια σκηνή.

Λήψη token από τον διακομιστή σας

Κανένα από τα δύο κιτ δεν κρατά μυστικό. Όταν ο πυρήνας χρειάζεται ένα token, το ζητά από τον δικό σας διακομιστή, ο οποίος εκδίδει ένα με ένα κιτ διακομιστή και απαντά με το token και τη λήξη του.

Με το addon, ορίστε τη διαδρομή token του διακομιστή σας στα Project Settings και το Lingara την καλεί στο δικό του νήμα. Αν η διαδρομή χρειάζεται τη συνεδρία του παίκτη, ορίστε την αντ’ αυτού κατά την εκτέλεση, επειδή οι ρυθμίσεις του έργου περιλαμβάνονται στην εξαγωγή σας. Ή συνδέστε το token_needed και απαντήστε εσείς σε κάθε αίτημα. Με C#, ο κόμβος-παράδειγμα στέλνει αίτημα στη διαδρομή token σας κάθε φορά που ο πελάτης ζητά token. Σε κάθε περίπτωση, αναφέρετε μια αποτυχία με token_unavailable ή TokenUnavailable, ώστε οι κλήσεις σε αναμονή να αποτύχουν αμέσως.

Επεξεργασία συμβάντων σε κάθε καρέ

Ο πυρήνας εκτελεί το δικτυακό του I/O στο δικό του νήμα. Το autoload του addon τον αδειάζει μία φορά ανά καρέ και εκπέμπει ένα σήμα ανά συμβάν, οπότε συνδέετε τα σήματα που χρειάζεται το παιχνίδι σας και δεν αδειάζετε ποτέ τίποτα μόνοι σας. Ο κόμβος C# αδειάζει στο _process, το πολύ 256 συμβάντα ανά καρέ, και επανεκπέμπει το καθένα ως σήμα του Godot.

Τα ίδια σήματα μεταφέρουν απαντήσεις NPC σε ροή (δείτε Διάλογοι με NPC) και ενημερώσεις εξάσκησης (δείτε αποτελέσματα εξάσκησης).

<PackageReference Include="Lingara.Embed" Version="0.1.0-alpha.6" />
Γλώσσα παραδείγματος κώδικα

Godot C#

// Your own server mints the token: never put a client secret in a game. The
// continuation may run off the main thread, which the client allows.
private async Task FetchToken()
{
    try
    {
        using var response = await Http.PostAsync(TokenUrl, new StringContent("{}"));
        response.EnsureSuccessStatusCode();
        using var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
        Client?.ProvideToken(body.RootElement.GetProperty("token").GetString(), body.RootElement.GetProperty("expires_at").GetString());
    }
    catch (Exception e) when (e is HttpRequestException || e is JsonException || e is KeyNotFoundException)
    {
        Client?.TokenUnavailable(e.Message); // fail the waiting calls now
    }
}

GDScript

# The common case: set Project Settings > lingara/token_url to your server's
# token route, which answers exactly {"token", "expires_at"}. Lingara POSTs to
# it on its own thread whenever it needs a token. If the route needs the
# player's session, set it at run time instead (never in ProjectSettings,
# which ships inside the export):
func use_my_session(session_cookie: String) -> void:
	lingara.set_token_endpoint("https://game.example.com/lingara-token", {"cookie": session_cookie})


# Or answer each token_needed yourself, with whatever login your game has.
func _on_token_needed(_request: int, _reason: String) -> void:
	var http := HTTPRequest.new()
	add_child(http)
	http.request("https://game.example.com/lingara-token", [], HTTPClient.METHOD_POST, "{}")
	var reply: Array = await http.request_completed
	http.queue_free()
	var body: Variant = JSON.parse_string((reply[3] as PackedByteArray).get_string_from_utf8())
	if reply[1] == 200 and body is Dictionary:
		lingara.provide_token(body["token"], body["expires_at"])
	else:
		lingara.token_unavailable("the token route answered %d" % reply[1])
Γλώσσα παραδείγματος κώδικα

Godot C#

public override void _Process(double delta)
{
    if (Client == null) return;
    events.Clear();
    Client.Drain(events); // at most 256 a frame; the rest wait for the next
    foreach (var e in events)
    {
        switch (e)
        {
            case EmbedEvent.TokenNeeded _: _ = FetchToken(); break;
            case EmbedEvent.NpcTurn { Update: NpcTurnUpdate.Fragment f } t:
                EmitSignal(SignalName.NpcTurnFragment, t.Dialogue.Value, t.Request.Value, f.Text); break;
            case EmbedEvent.NpcTurn { Update: NpcTurnUpdate.Finished f } t:
                EmitSignal(SignalName.NpcTurnFinished, t.Dialogue.Value, t.Request.Value, f.Text); break;
            case EmbedEvent.Practice p: EmitSignal(SignalName.PracticeChanged, p.Session.Value, p.Snapshot.Phase.ToString()); break;
            case EmbedEvent.Failed f: EmitSignal(SignalName.Failed, f.Error.KindName, f.Error.Message, f.Error.Request?.Value ?? 0); break;
            case EmbedEvent.Log log: GD.Print($"[lingara] {log.Level} {log.Target}: {log.Message}"); break;
        }
    }
}

GDScript

# The Lingara autoload the plugin adds, reached by path and typed, so every
# call and signal below is checked against LingaraEmbed.
@onready var lingara: LingaraEmbed = get_node("/root/Lingara")

# Enable the plugin (Project > Project Settings > Plugins): it adds the
# Lingara autoload, which drains the core once per frame and emits one signal
# per event. Connect the signals your game needs; you never call drain.
func _ready() -> void:
	lingara.token_needed.connect(_on_token_needed)
	lingara.event_received.connect(_on_event)
	lingara.error_raised.connect(func(error: Dictionary) -> void: push_warning(error.message))
	lingara.practice_changed.connect(_on_practice_changed)
	lingara.practice_finished.connect(_on_practice_finished)
	mei.replied.connect(_on_mei_replied)


func _on_event(_id: String, event_type: String, _created_at: String, data: Dictionary) -> void:
	if event_type == "lesson_plan.ready":
		print("a plan is ready: ", data.get("plan_id"))