📡 Komunikacja skrypt ↔ host
KitsuneScript oferuje bogaty system komunikacji dwukierunkowej między skryptem a aplikacją hosta (Kotlin/Android). Możesz wysyłać dane i eventy w obie strony.
💡 Kluczowe pojęcia
- emit() - Skrypt wysyła event do hosta
- on() - Skrypt nasłuchuje na eventy od hosta
- global.send() - Skrypt wysyła wartość do hosta
- global.params - Skrypt odczytuje parametry od hosta
- emitToScript() - Host wysyła event do skryptu
- onScriptEvent() - Host nasłuchuje na eventy ze skryptu
🔄 Przepływ danych
📤 Wysyłanie z skryptu do hosta
emit() - Emitowanie eventów
Funkcja emit(event, ...args) wysyła event do hosta z opcjonalnymi argumentami.
emit("started");
emit("userAction", "click", 100, 200);
emit("dataReady", {
status: "success",
data: [1, 2, 3],
timestamp: 1234567890
});
emit("result", "processed", 42, ["a", "b"], {key: "value"});
global.send() - Wysyłanie wartości
Funkcja global.send(value) wysyła pojedynczą wartość do hosta. Wszystkie wysłane wartości są zbierane w result.sendResults.
global.send("Hello from script!");
global.send(42);
global.send([1, 2, 3]);
global.send({name: "Alice", age: 25});
global.send({progress: 0, message: "Starting..."});
global.send({progress: 50, message: "Processing..."});
global.send({progress: 100, message: "Done!"});
📥 Odbieranie w skrypcie od hosta
global.params - Parametry wejściowe
Lista parametrów przekazanych z Kotlina przez runner.params.
let name = global.params[0];
let age = global.params[1];
let config = global.params[2];
let timeout = global.params[3] ?? 5000;
for (param in global.params) {
log("Param: " + param);
}
on() - Nasłuchiwanie na eventy
Konstrukcja on(event) { handler } rejestruje handler wywoływany gdy host wyśle event. Argumenty są dostępne przez obiekt event.
on("refresh") {
log("Host requested refresh!");
emit("refreshDone");
}
on("updateUser") {
let userId = event.args[0];
let newName = event.args[1];
log("Updating user " + userId + " to " + newName);
log("Event name: " + event.name);
}
on("start") { log("Starting..."); }
on("stop") { log("Stopping..."); }
on("pause") { log("Pausing..."); }
💡 Obiekt event
W handlerze on() dostępny jest obiekt event z polami:
event.args - lista argumentów przekazanych z hosta
event.name - nazwa eventu
🔧 Strona Kotlin (Host)
Konfiguracja i uruchomienie
import rip.nerd.kitsunescript.api.KitsuneScriptRunner
val runner = KitsuneScriptRunner.createInstance("myScript")
runner.register("log", HostFunction { args, _ ->
println(args.joinToString(" ") { it.asString() })
Value.Null
})
runner.params = listOf("Alice", 25, mapOf("role" to "admin"))
runner.onSend { value ->
println("Skrypt wysłał: ${value.asString()}")
}
runner.onScriptEvent("dataReady") { args ->
val status = args.getOrNull(0)?.asMap()?.get("status")
println("Dane gotowe, status: $status")
}
runner.onScriptEvent("userAction") { args ->
val action = args.getOrNull(0)?.asString()
val x = args.getOrNull(1)?.asDouble()
val y = args.getOrNull(2)?.asDouble()
println("Action: $action at ($x, $y)")
}
val result = runner.execute("""
log("Started with params: " + global.params);
on("refresh") {
emit("dataReady", {status: "refreshed"});
}
emit("dataReady", {status: "initial"});
"initialized";
""")
runner.emitToScript("refresh")
runner.emitToScript("customEvent", "arg1", 42)
println("Zwrócono: ${result.value}")
println("Sukces: ${result.success}")
println("Send results: ${result.sendResults}")
runner.dispose()
Wysyłanie eventów do skryptu - emitToScript()
runner.emitToScript("refresh")
runner.emitToScript("updateData", "newValue")
runner.emitToScript("setPosition", 100, 200)
runner.emitToScript("configure", mapOf("debug" to true))
Odbieranie eventów ze skryptu - onScriptEvent()
runner.onScriptEvent("started") { _ ->
println("Skrypt wystartował!")
}
runner.onScriptEvent("result") { args ->
val value = args.firstOrNull()?.asDouble() ?: 0.0
println("Wynik: $value")
}
runner.onScriptEvent("userData") { args ->
val data = args.firstOrNull()?.asMap()
val name = data?.get("name")?.asString()
val age = data?.get("age")?.asDouble()?.toInt()
println("User: $name ($age lat)")
}
runner.removeScriptEventHandlers("result")
💡 Praktyczne przykłady
Przykład 1: Kalkulator z UI
val runner = KitsuneScriptRunner.createInstance("calculator")
runner.onScriptEvent("result") { args ->
val result = args.firstOrNull()?.asDouble()
resultTextView.text = "Wynik: $result"
}
runner.onScriptEvent("error") { args ->
val message = args.firstOrNull()?.asString()
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
runner.execute("""
on("calculate") {
let a = global.params[0];
let op = global.params[1];
let b = global.params[2];
let result = 0;
if (op == "+") result = a + b;
else if (op == "-") result = a - b;
else if (op == "*") result = a * b;
else if (op == "/") {
if (b == 0) {
emit("error", "Nie można dzielić przez zero!");
return;
}
result = a / b;
}
emit("result", result);
}
""")
calculateButton.setOnClickListener {
runner.params = listOf(inputA.toDouble(), operator, inputB.toDouble())
runner.emitToScript("calculate")
}
Przykład 2: Pobieranie danych z raportem postępu
runner.onScriptEvent("progress") { args ->
val percent = args.getOrNull(0)?.asDouble()?.toInt() ?: 0
val message = args.getOrNull(1)?.asString() ?: ""
progressBar.progress = percent
statusText.text = message
}
runner.onScriptEvent("complete") { args ->
val data = args.firstOrNull()?.asList()
processData(data)
}
runner.execute("""
fn fetchData() {
emit("progress", 0, "Inicjalizacja...");
// Symulacja pracy
let items = [];
for (i in 0..10) {
emit("progress", i * 10, "Pobieranie elementu " + i + "...");
items.push({id: i, value: i * 2});
}
emit("progress", 100, "Gotowe!");
emit("complete", items);
}
on("start") {
fetchData();
}
""")
runner.emitToScript("start")
Przykład 3: Chat/Messaging
runner.onScriptEvent("messageFromScript") { args ->
val text = args.firstOrNull()?.asString() ?: ""
addMessageToUI("🦊 Skrypt", text)
}
runner.execute("""
log("Chat bot initialized");
on("userMessage") {
let message = global.params[0];
log("Otrzymano: " + message);
// Prosta logika chatbota
if (contains(toLowerCase(message), "cześć")) {
emit("messageFromScript", "Cześć! Jak mogę pomóc?");
} else if (contains(toLowerCase(message), "pomoc")) {
emit("messageFromScript", "Dostępne komendy: cześć, pomoc, czas, losuj");
} else if (contains(toLowerCase(message), "czas")) {
emit("messageFromScript", "Niestety nie mam dostępu do zegara 😅");
} else if (contains(toLowerCase(message), "losuj")) {
use "math";
let num = floor(random() * 100);
emit("messageFromScript", "Wylosowano: " + num);
} else {
emit("messageFromScript", "Nie rozumiem. Napisz 'pomoc'");
}
}
emit("messageFromScript", "Witaj! Jestem botem KitsuneScript 🦊");
""")
sendButton.setOnClickListener {
val text = inputField.text.toString()
runner.params = listOf(text)
runner.emitToScript("userMessage")
}
📋 Podsumowanie API
W skrypcie KitsuneScript
| Element | Kierunek | Opis |
emit(event, ...args) | Skrypt → Host | Wyślij event z argumentami |
global.send(value) | Skrypt → Host | Wyślij wartość (zbierana w sendResults) |
on(event) { handler } | Host → Skrypt | Nasłuchuj na event od hosta |
event.args | W handlerze on() | Lista argumentów z emitToScript() |
event.name | W handlerze on() | Nazwa eventu |
global.params | Host → Skrypt | Parametry wejściowe z Kotlina |
global.instanceId | Host → Skrypt | Unikalny ID instancji runnera |
W Kotlin (Host)
| Metoda | Kierunek | Opis |
runner.params = listOf(...) | Host → Skrypt | Ustaw parametry wejściowe |
runner.emitToScript(event, ...) | Host → Skrypt | Wyślij event do skryptu |
runner.withSourceLoader { } | Konfiguracja | Ustaw loader dla importów |
runner.onScriptEvent(event) { } | Skrypt → Host | Nasłuchuj na emit() ze skryptu |
runner.onSend { } | Skrypt → Host | Callback dla global.send() |
result.sendResults | Skrypt → Host | Lista wszystkich wysłanych wartości |
📦 Import modułów
Aby używać import w skryptach, skonfiguruj sourceLoader:
val runner = KitsuneScriptRunner.createInstance("myScript")
.withSourceLoader { path ->
context.assets.open("scripts/$path").bufferedReader().readText()
}
⚠️ Ważne
- Zawsze wywołuj
runner.dispose() po zakończeniu pracy aby zwolnić zasoby
- Handlery
on() są aktywne tylko podczas wykonania skryptu
- Każde wywołanie
execute() tworzy świeże środowisko - zmienne nie są zachowywane między wywołaniami
- Eventy wysłane przez
emitToScript() przed execute() nie zostaną obsłużone