-
Notifications
You must be signed in to change notification settings - Fork 1
App Lifecycle
Jede UserApp durchläuft einen definierten Lebenszyklus. Über Hooks reagierst du auf Ereignisse wie App-Start, Nutzer-Aktionen oder Nachrichten.
Jede UserApp muss ein globales App-Objekt definieren. Darin werden alle Hooks und Chat-Befehle registriert:
var App = {
// --- Hooks ---
onAppStart: function() {
// App wurde gestartet
},
// --- Chat-Befehle ---
chatCommands: {
hilfe: function(user, params, command) {
user.sendPrivateMessage('Verfügbare Befehle: /hilfe');
}
}
};
// --- Hilfsfunktionen ---
function meineHilfsfunktion() {
// ...
}Wichtig: Hooks und
chatCommandswerden als Eigenschaften desApp-Objekts definiert. Hilfsfunktionen stehen als normale Funktionen außerhalb des Objekts.
App installiert
│
▼
onAppStart() ← App wird initialisiert (einmalig)
│
▼
App läuft ← Events werden verarbeitet
│
▼
onShutdown() ← App wird gestoppt
Die App läuft, solange der Channel existiert und die App installiert ist. Bei einem Server-Neustart oder App-Update wird die App heruntergefahren und neu gestartet.
In den folgenden Beispielen wird nur der jeweilige Hook gezeigt. Alle Hooks gehören als Eigenschaften in das var App = { ... };-Objekt.
// Wird einmalig beim Start der App aufgerufen
onAppStart: function() {
KnuddelsServer.getDefaultLogger().info('App gestartet!');
},
// Wird beim Herunterfahren der App aufgerufen
onShutdown: function() {
KnuddelsServer.getDefaultLogger().info('App wird gestoppt...');
},// Nutzer betritt den Channel
onUserJoined: function(user) {
KnuddelsServer.getDefaultBotUser().sendPublicMessage(
'Willkommen, ' + user.getProfileLink() + '!'
);
},
// Nutzer verlässt den Channel
onUserLeft: function(user) {
KnuddelsServer.getDefaultLogger().info(user.getNick() + ' hat den Channel verlassen.');
},// Öffentliche Nachricht im Channel
onPublicMessage: function(publicMessage) {
var text = publicMessage.getText();
var author = publicMessage.getAuthor();
// Nachricht verarbeiten...
},
// Private Nachricht an den Bot
onPrivateMessage: function(privateMessage) {
var text = privateMessage.getText();
var author = privateMessage.getAuthor();
author.sendPrivateMessage('Du hast geschrieben: ' + text);
},
// Öffentliche Action-Nachricht (z.B. "/me tanzt")
onPublicActionMessage: function(publicActionMessage) {
// ...
},
// Öffentliche Event-Nachricht
onPublicEventMessage: function(publicEventMessage) {
// ...
},// Bevor ein Nutzer Knuddel an die App sendet
onBeforeKnuddelReceived: function(knuddelTransfer) {
// Transfer akzeptieren oder ablehnen
knuddelTransfer.accept();
// Oder: knuddelTransfer.reject('Grund für Ablehnung');
},
// Nachdem Knuddel empfangen wurden
onKnuddelReceived: function(sender, receiver, knuddelAmount, transferReason) {
sender.sendPrivateMessage('Danke für ' + knuddelAmount.asNumber() + ' Knuddel!');
},
// Wenn sich der Knuddel-Betrag eines Nutzers ändert
onKnuddelAmountChanged: function(user, knuddelAmountOld, knuddelAmountNew) {
// ...
},// Events vom Frontend empfangen
onEventReceived: function(user, type, data, appContentSession) {
if (type === "buttonClicked") {
// data enthält die vom Client gesendeten Daten
appContentSession.sendEvent('response', { status: 'ok' });
}
},Wenn ein Nutzer seinen Account löscht, wird dieser Hook aufgerufen. Hier solltest du alle gespeicherten Nutzerdaten bereinigen:
onUserDeleted: function(userId, userPersistence) {
// Nutzerdaten aus der UserPersistence entfernen
userPersistence.deleteAllNumbers();
userPersistence.deleteAllStrings();
userPersistence.deleteAllObjects();
KnuddelsServer.getDefaultLogger().info('Daten für User ' + userId + ' gelöscht.');
},Wichtig: Wenn deine App
onUserDeletedimplementiert, werden Persistence-Daten und der Zugriff auf gespeicherte Nutzerdaten gelöschter Nutzer automatisch bereinigt. Ohne diesen Hook wird die Bereinigung gedrosselt und erst beim nächsten App-Start nachgeholt.
// Event von einer anderen App empfangen
onAppEventReceived: function(appInstance, type, data) {
KnuddelsServer.getDefaultLogger().info(
'Event von ' + appInstance.getAppInfo().getAppName() + ': ' + type
);
},Chat-Befehle werden als Objekt auf chatCommands definiert:
chatCommands: {
// Befehl: /hilfe
hilfe: function(user, params, command) {
user.sendPrivateMessage('Verfügbare Befehle: /hilfe, /start, /stats');
},
// Befehl: /start mit Parametern
start: function(user, params, command) {
if (params.length === 0) {
user.sendPrivateMessage('Bitte gib einen Spielmodus an: /start schnell oder /start normal');
return;
}
user.sendPrivateMessage('Spiel startet im Modus: ' + params);
}
}Hinweis: Der Befehlsname wird automatisch kleingeschrieben.
/Hilfe,/hilfeund/HILFErufen alle dieselbe Funktion auf.
So sieht eine vollständige main.js mit mehreren Hooks und Chat-Befehlen aus:
var App = {
onAppStart: function() {
KnuddelsServer.getDefaultLogger().info('App gestartet!');
},
onShutdown: function() {
KnuddelsServer.getDefaultLogger().info('App wird gestoppt...');
},
onUserJoined: function(user) {
KnuddelsServer.getDefaultBotUser().sendPublicMessage(
'Willkommen, ' + user.getProfileLink() + '!'
);
},
onEventReceived: function(user, type, data, appContentSession) {
if (type === 'ping') {
appContentSession.sendEvent('pong', { success: true });
}
},
chatCommands: {
hilfe: function(user, params, command) {
user.sendPrivateMessage('Verfügbare Befehle: /hilfe');
}
}
};Ein großer Vorteil der Objekt-Schreibweise: Wenn du Code in mehrere Dateien aufteilst, kannst du aus jeder Datei direkt auf das App-Objekt zugreifen. Mit KnuddelsServer.require() lädst du zusätzliche Dateien:
// main.js
var App = {
onAppStart: function() {
KnuddelsServer.getDefaultLogger().info('App gestartet!');
},
chatCommands: {}
};
// Weitere Dateien laden – diese können auf App zugreifen
KnuddelsServer.require('commands.js');
KnuddelsServer.require('game.js');// commands.js – Chat-Befehle in eigener Datei
App.chatCommands.hilfe = function(user, params, command) {
user.sendPrivateMessage('Verfügbare Befehle: /hilfe, /start');
};
App.chatCommands.start = function(user, params, command) {
user.sendPrivateMessage('Spiel wird gestartet...');
};// game.js – Spiellogik in eigener Datei
App.onUserJoined = function(user) {
user.sendPrivateMessage('Willkommen! Gib /hilfe ein für Befehle.');
};Da App ein normales globales Objekt ist, können alle per require geladenen Dateien dessen Eigenschaften lesen und erweitern.
Neben der Objekt-Schreibweise gibt es auch das IIFE-Pattern (Immediately Invoked Function Expression). Es bietet echte Kapselung – interne Variablen und Funktionen sind von außen nicht erreichbar:
var App = (new function() {
// Private Variable – von außen nicht zugreifbar
var internerZaehler = 0;
this.onAppStart = function() {
internerZaehler++;
KnuddelsServer.getDefaultLogger().info('App gestartet! (Start #' + internerZaehler + ')');
};
this.chatCommands = {
hilfe: function(user, params, command) {
user.sendPrivateMessage('Verfügbare Befehle: /hilfe');
}
};
// Private Hilfsfunktion – von außen nicht aufrufbar
function interneBerechnung() {
return internerZaehler * 2;
}
}());| Objekt-Schreibweise | IIFE-Pattern | |
|---|---|---|
| Einfachheit | Einfach zu lesen und zu schreiben | Etwas komplexer durch den Wrapper |
| Mehrere Dateien | Sehr einfach – App ist direkt zugreifbar |
Aufwändiger – nur this.-Eigenschaften sind von außen sichtbar |
| Private Variablen | Nicht möglich – alles liegt offen am Objekt | Ja – Variablen und Funktionen ohne this. sind gekapselt |
| Sicherheit | Interner Zustand kann von außen manipuliert werden | Interner Zustand ist geschützt |
| Empfehlung | Für die meisten Apps ausreichend und empfohlen | Sinnvoll bei sicherheitskritischem Code oder komplexen internen Zuständen |
Empfehlung: Für die meisten UserApps ist die Objekt-Schreibweise der bessere Einstieg. Sie ist leichter verständlich und macht das Aufteilen in mehrere Dateien einfacher. Greife zum IIFE-Pattern, wenn du internen Zustand bewusst kapseln und vor Manipulation schützen möchtest.
Wenn ein Nutzer den Channel betritt und eine Nachricht schreibt, werden die Hooks in dieser Reihenfolge aufgerufen:
-
onUserJoined(user)– Nutzer ist dem Channel beigetreten -
onPublicMessage(message)– Wenn er eine öffentliche Nachricht schreibt -
onEventReceived(user, type, data, session)– Wenn er Events vom Frontend sendet -
onUserLeft(user)– Nutzer verlässt den Channel
Die vollständige Dokumentation aller Hooks und Methoden findest du in der App-Klasse der API-Dokumentation.
- Erste Schritte – Voraussetzungen, Einrichtung, deine erste App
-
Projektstruktur – Dateien, Ordner und
app.config - Dev-Server – Entwicklungsumgebung und Testen
-
App-Lifecycle und Hooks –
onAppStart,onUserJoinedund Co. -
Server-API Grundlagen –
KnuddelsServer,Channel,Logger - Client-Server-Kommunikation – Events zwischen Frontend und Backend
-
Benutzer und Nachrichten –
User,BotUser, Nachrichten senden - HTML-UI und AppContent – Popups, Overlays, Globale Apps-UI
-
Datenspeicherung –
AppPersistence,UserPersistence -
Knuddel und Zahlungen – Transfers, Käufe,
KnuddelAccount - Toplisten – Ranglisten und Highscores
- Globale Apps – Apps im "Apps & Spiele"-Menü
- Quests – Aufgaben für Nutzer
- Externe Server-Kommunikation – HTTP-Requests an externe APIs
- Tutorials – Übersicht aller Tutorials
- Tic-Tac-Toe – Multiplayer-Spiel mit Bestenliste
- Best Practices – Tipps, Limits und häufige Fehler
- FAQ – Häufig gestellte Fragen
- KCode-Formatierung – Nachrichten-Formatierung mit KCode