Zum Inhalt springen
  • Dunkel
  • Hell
  • System

Globale Variablen: GetGlobalVar & SetGlobalVar

Eine Variable in deinem C#-Code lebt nur, solange das Execute() läuft. Nach dem return ist sie weg. Wenn du einen Zähler hochzählen oder dir den letzten Wert merken willst, brauchst du Speicher der über die Action hinaus bestehen bleibt. Dafür gibt es Globals: CPH.SetGlobalVar schreibt einen Wert, CPH.GetGlobalVar liest ihn später wieder. Das ist das C#-Pendant zu den No-Code-Globals aus dem Globals Pattern, nur eben direkt im Code.

Core C# Code Execute C# Code

Doku:

Zwei Methoden, ein Begriffspaar. Beim Setzen gibst du Name, Wert und das Persisted-Flag mit. Beim Lesen sagst du über den generischen Typ-Parameter, als was du den Wert zurückbekommen willst.

// schreiben
CPH.SetGlobalVar("hypeCount", 42, true);
// lesen, als int
int count = CPH.GetGlobalVar<int>("hypeCount", true);

Die Methode SetGlobalVar nimmt einen object-Wert an, du kannst also Zahlen, Strings oder Bools speichern. Beim Lesen legst du mit GetGlobalVar<T> den erwarteten Typ fest, etwa GetGlobalVar<int> oder GetGlobalVar<string>.

ParameterBei welcher MethodeBedeutung
varNamebeideName des Globals, ohne % oder ~. Exakt gleicher Name beim Schreiben und Lesen.
valueSetGlobalVarDer zu speichernde Wert. Typ object, also Zahl, String oder Bool.
persistedbeideDritter Parameter, bool. true = überlebt den Restart, false = nur im Arbeitsspeicher.
<T>GetGlobalVarGenerischer Typ-Parameter: als was der Wert zurückkommt, z.B. int, string, bool.

Der dritte Parameter entscheidet, wie lange ein Global lebt.

  • true (persisted): Streamer.bot schreibt den Wert auf die Festplatte. Er überlebt einen Neustart der App. Richtig für Zähler, Highscores oder gemerkte URLs.
  • false (non-persisted): Der Wert lebt nur im Arbeitsspeicher, bis Streamer.bot beendet wird. Praktisch für Werte die nur eine Session lang gelten sollen, etwa ein Rate-Limit pro Stream.

Im Zweifel true nehmen. Das ist auch die Logik hinter dem No-Code-Pendant, mehr dazu im Globals Pattern.

Hier lauert die häufigste Falle. Wenn der Global noch nie gesetzt wurde, gibt GetGlobalVar nicht etwa eine 0 oder einen leeren String zurück, sondern den Default des Typs: bei Referenztypen und Nullable-Typen ist das null.

Die Lösung ist der Null-Coalescing-Operator ??. Du liest in einen Nullable-Typ und gibst direkt einen Default an, falls null zurückkommt:

// liefert 0 statt null beim ersten Mal
int n = CPH.GetGlobalVar<int?>("count", true) ?? 0;
// das Gleiche für Strings
string name = CPH.GetGlobalVar<string>("lastWinner", true) ?? "noch niemand";

Wichtig ist GetGlobalVar<int?> (das Fragezeichen macht aus int einen nullable Typ), denn nur ein nullable Wert kann überhaupt null sein und damit den ??-Zweig auslösen. Schreibst du GetGlobalVar<int>, kommt beim ersten Mal eine 0 zurück, was bei einem reinen Zähler oft schon reicht. Mit int? und ?? 0 bist du aber explizit und auf der sicheren Seite.

Ein klassischer FPS-Use-Case: ein !aces-Command, der mitzählt wie viele Aces im Stream schon gefallen sind, und den Stand in den Chat postet.

public class CPHInline {
public bool Execute() {
// aktuellen Stand holen, null-sicher mit Default 0
int aces = CPH.GetGlobalVar<int?>("aceCount", true) ?? 0;
// hochzählen
aces += 1;
// zurückschreiben, persisted true damit es den Restart überlebt
CPH.SetGlobalVar("aceCount", aces, true);
// in den Chat posten
CPH.SendMessage($"🎯 Ace Nummer {aces} dieser Session. GG!");
return true;
}
}

Get mit ?? 0, plus eins, SetGlobalVar, fertig. Beim ersten Aufruf ist aceCount noch nicht gesetzt, der Default 0 greift, danach steht eine 1 im Global. Beim nächsten Mal liest er 1, macht 2 daraus, und so weiter. Weil persisted auf true steht, ist der Stand auch nach einem Neustart von Streamer.bot noch da.

Zum Löschen oder Zurücksetzen eines Globals gibt es CPH.UnsetGlobalVar. Praktisch für einen !resetaces-Command, der den Zähler wieder auf null bringt:

CPH.UnsetGlobalVar("aceCount", true);

Nach dem Entfernen verhält sich der Global wieder wie nie gesetzt: das nächste GetGlobalVar<int?>("aceCount", true) liefert null, und dein ?? 0 fängt das sauber ab. Der dritte Parameter ist auch hier das Persisted-Flag und sollte zum Speicher passen, in dem der Wert liegt.

  • Persisted-Flag vergessen oder auf false: Der Zähler steht nach einem Restart wieder bei null. Für dauerhafte Werte immer true als dritten Parameter setzen, beim Schreiben und beim Lesen.
  • GetGlobalVar ohne Null-Absicherung: Beim ersten Aufruf kommt null zurück und die Action wirft eine NullReferenceException. Immer GetGlobalVar<int?>(...) ?? 0 oder einen passenden Default nutzen.
  • Falscher Typ-Parameter: Einen Wert als int gespeichert, aber mit GetGlobalVar<string> gelesen (oder umgekehrt). Schreib- und Lese-Typ müssen zusammenpassen.
  • Name-Tippfehler: aceCount geschrieben, acecount gelesen. Globals sind exakte Strings. Ein vertippter Name zeigt auf einen leeren Global und du bekommst stillschweigend den Default. Am besten den Namen einmal in eine const string-Variable legen und überall verwenden.