Lingara Lingara Dokumentasi Panduan API Pustaka Aplikasi Buat Sematkan Aplikasi web
Bahasa: Bahasa Indonesia

Godot

Halaman ini diterjemahkan dari bahasa Inggris. Jika keduanya berbeda, halaman bahasa Inggris yang benar. Baca halaman bahasa Inggris

Godot menawarkan dua bahasa, dan Lingara memiliki kit untuk masing-masing. Game GDScript menggunakan addon Lingara. Game Godot C# menggunakan Lingara.Embed, paket yang sama yang digunakan game Unity. Gunakan salah satunya dalam sebuah proyek, jangan pernah keduanya. Tab di bawah menunjukkan masing-masing.

Instal

GDScript. Instal addon Lingara dari Godot Asset Library, lalu aktifkan di Project Settings, Plugins. Mengaktifkannya menambahkan autoload bernama Lingara, yang dijangkau setiap scene di /root/Lingara.

C#. Tambahkan Lingara.Embed ke proyek Anda sebagai referensi paket. Node contoh di bawah, LingaraEmbedNode, bukan bagian dari paket: tambahkan sumbernya ke proyek Anda dan letakkan di sebuah scene.

Dapatkan token dari server Anda

Kedua kit tidak menyimpan secret. Saat inti membutuhkan token, inti meminta ke server Anda sendiri, yang mencetak token dengan kit server dan menjawab dengan token beserta waktu kedaluwarsanya.

Dengan addon, atur rute token server Anda di Project Settings dan Lingara memanggilnya di thread-nya sendiri. Jika rute membutuhkan sesi pemain, aturlah saat runtime, karena pengaturan proyek ikut dikirim di dalam ekspor Anda. Atau hubungkan token_needed dan jawab sendiri setiap permintaan. Dengan C#, node contoh mengirim ke rute token Anda setiap kali klien meminta token. Dengan cara mana pun, laporkan kegagalan dengan token_unavailable atau TokenUnavailable, agar panggilan yang sedang menunggu langsung gagal.

Proses event setiap frame

Inti menjalankan I/O jaringannya di thread-nya sendiri. Autoload addon mengosongkannya sekali per frame dan memancarkan satu sinyal per event, sehingga Anda menghubungkan sinyal yang dibutuhkan game Anda dan tidak pernah mengosongkan apa pun sendiri. Node C# mengosongkan di _process, paling banyak 256 event per frame, dan memancarkan ulang masing-masing sebagai sinyal Godot.

Sinyal yang sama membawa balasan NPC yang dialirkan (lihat dialog NPC) dan pembaruan latihan (lihat hasil latihan).

<PackageReference Include="Lingara.Embed" Version="0.1.0-alpha.6" />
Bahasa contoh kode

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])
Bahasa contoh kode

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"))