Lingara Lingara مستندات رهنماها API کتابخانه‌ها اپلیکیشن‌ها ساختن جاسازی اپلیکیشن وب
زبان: دری

Godot

این صفحه از انگلیسی ترجمه شده است. اگر این دو با هم فرق داشته باشند، صفحهٔ انگلیسی درست است. صفحهٔ انگلیسی را بخوانید

Godot دو زبان ارائه می‌کند و Lingara برای هر کدام یک کیت دارد. یک بازی GDScript از افزونهٔ Lingara استفاده می‌کند. یک بازی Godot با C# از Lingara.Embed استفاده می‌کند، همان بسته‌ای که یک بازی Unity به کار می‌برد. در یک پروژه از یکی یا دیگری استفاده کنید، هرگز از هر دو. زبانه‌های پایین هر کدام را نشان می‌دهند.

نصب

GDScript. افزونهٔ Lingara را از Godot Asset Library نصب کنید، بعد آن را در Project Settings، بخش Plugins، فعال کنید. فعال کردن آن یک autoload به نام Lingara اضافه می‌کند که هر صحنه در /root/Lingara به آن دسترسی دارد.

C#. Lingara.Embed را به حیث ارجاع بسته به پروژهٔ خود اضافه کنید. گرهٔ نمونهٔ پایین، LingaraEmbedNode، بخشی از بسته نیست: کود منبع آن را به پروژهٔ خود اضافه کنید و آن را در یک صحنه بگذارید.

گرفتن توکن از سرور شما

هیچ‌کدام از دو کیت رمزی نگه نمی‌دارد. وقتی هسته به توکن ضرورت دارد، آن را از سرور خودتان درخواست می‌کند، که با یک کیت سرور توکنی صادر می‌کند و با توکن و زمان انقضای آن پاسخ می‌دهد.

با افزونه، مسیر توکن سرور خود را در Project Settings تنظیم کنید تا Lingara آن را روی رشتهٔ اجرایی خودش فراخوانی کند. اگر مسیر به نشست بازیکن ضرورت دارد، آن را به جای این در زمان اجرا تنظیم کنید، زیرا تنظیمات پروژه داخل خروجی شما منتشر می‌شوند. یا token_needed را وصل کنید و خودتان به هر درخواست پاسخ دهید. با C#، گرهٔ نمونه هر بار که کلاینت توکنی بخواهد به مسیر توکن شما درخواست می‌فرستد. در هر دو حالت، ناکامی را با token_unavailable یا TokenUnavailable گزارش دهید تا فراخوانی‌های منتظر فوراً ناکام شوند.

پردازش رویدادها در هر فریم

هسته ورودی/خروجی شبکهٔ خود را روی رشتهٔ اجرایی خودش اجرا می‌کند. autoload افزونه آن را یک بار در هر فریم خالی می‌کند و برای هر رویداد یک سیگنال منتشر می‌کند، پس شما سیگنال‌هایی را که بازی شما لازم دارد وصل می‌کنید و هرگز خودتان چیزی را خالی نمی‌کنید. گرهٔ 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"))