Lingara Lingara Dokumentasi Panduan API Pustaka Aplikasi Bina Benam Apl web
Bahasa: Bahasa Melayu

Godot

Halaman ini diterjemahkan daripada bahasa Inggeris. Jika kedua-duanya berbeza, halaman bahasa Inggeris adalah yang betul. Baca halaman bahasa Inggeris

Godot menawarkan dua bahasa, dan Lingara mempunyai kit untuk setiap satu. Permainan GDScript menggunakan addon Lingara. Permainan Godot C# menggunakan Lingara.Embed, pakej yang sama yang digunakan oleh permainan Unity. Gunakan salah satu dalam sesebuah projek, jangan sekali-kali kedua-duanya. Tab di bawah menunjukkan setiap satu.

Pasang

GDScript. Pasang addon Lingara daripada Godot Asset Library, kemudian dayakannya di bawah Project Settings, Plugins. Mendayakannya menambah autoload bernama Lingara, yang dicapai oleh setiap adegan di /root/Lingara.

C#. Tambahkan Lingara.Embed pada projek anda sebagai rujukan pakej. Nod sampel di bawah, LingaraEmbedNode, bukan sebahagian daripada pakej: tambahkan sumbernya pada projek anda dan letakkannya dalam adegan.

Dapatkan token daripada pelayan anda

Kedua-dua kit tidak menyimpan rahsia. Apabila teras memerlukan token, ia meminta daripada pelayan anda sendiri, yang mencetak token dengan kit pelayan dan menjawab dengan token serta tempoh tamatnya.

Dengan addon, tetapkan laluan token pelayan anda di bawah Project Settings dan Lingara memanggilnya pada benangnya sendiri. Jika laluan itu memerlukan sesi pemain, tetapkannya semasa masa jalan sebaliknya, kerana tetapan projek dihantar di dalam eksport anda. Atau sambungkan token_needed dan jawab setiap permintaan sendiri. Dengan C#, nod sampel menghantar ke laluan token anda setiap kali klien meminta token. Walau bagaimanapun, laporkan kegagalan dengan token_unavailable atau TokenUnavailable, supaya panggilan yang sedang menunggu gagal serta-merta.

Proses acara setiap bingkai

Teras menjalankan I/O rangkaiannya pada benangnya sendiri. Autoload addon mengosongkannya sekali setiap bingkai dan memancarkan satu isyarat bagi setiap acara, jadi anda menyambungkan isyarat yang diperlukan oleh permainan anda dan tidak pernah mengosongkan apa-apa sendiri. Nod C# mengosongkan dalam _process, paling banyak 256 acara satu bingkai, dan memancarkan semula setiap satu sebagai isyarat Godot.

Isyarat yang sama membawa balasan NPC yang distrim (lihat dialog NPC) dan kemas kini latihan (lihat hasil latihan).

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

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 kod

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