Zum Hauptinhalt springen

Aktionen

Aktionen sind Code-Snippets, die ausgeführt werden, wenn ein Log-Ereignis vom Spielserver importiert wird. Verwende sie, um Daten zu verarbeiten und Reaktionen zu automatisieren.

Aktionen unterstützen jetzt sowohl einen server-spezifischen Workflow als auch einen Marktplatz-Workflow. Für das gemeinsame Modell hinter Marktplatz-, installierten und eigenen Aktionen siehe das Konzept Aktions-Marktplatz.

Hinweis zur Datenquelle: Aktionen hängen von importierten Server-Logs ab. Kommen Logs später an, wird die Aktionsausführung entsprechend verzögert. Vollständige Informationen zum Import-Verhalten findest du im Konzept des Log-Imports.

  • Server Admin -> Aktionen

Tabs

Die Aktionsansicht ist in drei Tabs aufgeteilt:

  • Marktplatz: öffentliche Creator-Aktionen durchsuchen und auf dem aktuellen Server installieren
  • Installiert: bereits auf diesem Server installierte Marktplatz-Aktionen verwalten
  • Eigene Aktionen: servereigene Aktionen mit lokalem Lua-Code erstellen und pflegen

Installierte Marktplatz-Aktionen übernehmen Code, Trigger-Ereignis und Konfigurationsschema aus der Creator-Definition. Server-Mitarbeiter verwalten nur den Aktiv-Status und die Konfigurationswerte für diesen Server.

Zugriffsvoraussetzungen

Aktionen haben jetzt drei Berechtigungsebenen:

  • actions.edit: Erlaubt das Bearbeiten serverseitiger Konfigurationswerte sowie das Aktivieren und Deaktivieren installierter oder eigener Aktionen
  • actions.manage_marketplace: Erlaubt das Installieren von Marktplatz-Aktionen sowie das Entfernen installierter Marktplatz-Aktionen
  • actions.edit_code: Erlaubt das Erstellen und Pflegen eigener Aktionen einschließlich Lua-Code und Konfigurationsschema

Diese Trennung ermöglicht es Serveradministratoren, operative Aktionsverwaltung, Marktplatz-Verwaltung und lokale Code-Erstellung getrennt zu vergeben.

Aktionssprache: Lua

Aktionen werden in Lua geschrieben, einer leichtgewichtigen, hochrangigen, multi-paradigmatischen Programmiersprache, die primär für den eingebetteten Einsatz in Anwendungen entwickelt wurde.

Aktionsskripte laufen direkt. Zwei globale Variablen sind verfügbar:

  • data: Ereignis-Payload des aktuellen Log-Ereignisses
  • config: Aufgelöste Aktionskonfigurationswerte

Um Werte beim Erstellen von Skripten zu prüfen, verwende die print-Funktion.

Hier ist ein Beispiel einer einfachen Aktion, die die Log-Ereignisdaten in die Konsole ausgibt:

print(data);

Konfigurationsfelder

Aktionen unterstützen benutzerdefinierte Konfigurationsfelder, mit denen du deine Lua-Skripte parametrisieren kannst, ohne den Code zu bearbeiten. Das ist nützlich für:

  • Moderatoren das Anpassen von Aktionsverhalten zu erlauben, ohne Code-Zugriff
  • Dieselbe Aktionsvorlage mit verschiedenen Einstellungen wiederzuverwenden
  • Sensible Werte (wie Kanal-IDs) vom Code zu trennen

Bei Marktplatz-Aktionen werden diese Felder vom Creator definiert. Server-Admins setzen nur die Werte in der installierten Server-Kopie.

Konfigurationsfelder definieren

Bei eigenen Aktionen werden Konfigurationsfelder im Code-Tab über den Konfigurationsschema-Builder definiert.

Bei Marktplatz-Aktionen werden Konfigurationsfelder im Creator Space vom Autor definiert und erscheinen anschließend auf jeder Server-Installation.

Jedes Feld hat:

  • Name: Schlüssel in Lua (config.<name>)
  • Typ: string, number oder boolean
  • Standard: Fallback-Wert, wenn kein Wert in den Einstellungen gespeichert ist
  • Beschreibung: Hilfetext, der im Einstellungs-Tab angezeigt wird

Empfohlene Benennung: camelCase oder snake_case ohne Leerzeichen.

Konfigurationswerte setzen

Nachdem ein Feld im Code-Tab definiert wurde, können Benutzer mit actions.edit dessen Wert im Einstellungs-Tab setzen.

Zur Laufzeit werden Config-Werte wie folgt aufgelöst:

  1. Gespeicherter Wert aus dem Einstellungs-Tab (falls vorhanden)
  2. Andernfalls der Feld-Standard aus dem Schema
  3. Andernfalls nil

Nur im Schema definierte Felder werden in config verfügbar gemacht.

Typverhalten

Config-Werte werden vor der Skriptausführung nach Feldtyp umgewandelt:

  • string: Wert wird als Zeichenkette verwendet
  • number: Als Integer oder Float geparst
  • boolean: Als true/false geparst

Leere Werte werden als nil behandelt.

Neben den Basistypen gibt es Auswahltypen: discord_channel_select, discord_role_select, discord_category_select, discord_guild_select, player_select, faction_select und generic_select. Wähle den Typ danach, was das Feld bezeichnet, nicht nach dem Lua-Wert: Ein Discord-Kanal, eine Rolle, eine Kategorie oder eine Gilde → der passende discord_*_select; ein Spieler → player_select; eine Fraktion → faction_select; eine feste Auswahl → generic_select. Der Wert einer Auswahl ist bereits die ID (bzw. der Benutzername) als Zeichenkette, die die Action-Funktionen erwarten — ein reines string-Feld wäre dagegen ein fehleranfälliges Freitextfeld. Verwende string nur für echten Freitext.

Konfiguration in Lua verwenden

Konfigurationswerte sind über die config-Tabelle verfügbar:

-- Konfigurationswerte abrufen
discord.send_to_channel(config.channelId, "Spieler getötet: " .. data.victim.username);

if config.notifyOnHeadshot and data.weapon == "Mosin" then
discord.send_to_channel(config.channelId, "Mosin-Kill erkannt");
end

if data.distance > config.minDistanceForBonus then
player.change_balance(data.killer.username, config.bonusAmount, "Weitschuss-Bonus");
end

Beispielkonfiguration

Für eine Kill-Benachrichtigungsaktion könntest du folgendes definieren:

NameTypStandardBeschreibung
channelIddiscord_channel_selectDiscord-Kanal für Benachrichtigungen
notifyOnHeadshotbooleantrueZusätzliche Nachricht bei Kopfschüssen
minDistanceForBonusnumber200Mindestdistanz für Bonusbelohnung
bonusAmountnumber50Währungsbonus für Weitschuss-Kills

Moderatoren können diese Werte dann im Einstellungs-Tab anpassen, ohne Code-Zugriff zu benötigen.

Funktionen

Um die Aktion bei einem neuen Log-Eintrag anzupassen, bietet der Code-Editor durchsuchbare Autovervollständigung mit [STRG] + [LEERTASTE].

Folgende Funktionen stehen in Aktionen zur Verfügung:

Debug-Ausgabe

Gibt die Daten in die Konsole aus.

print({name = "John", age = 30}); -- wird als JSON ausgegeben
print("Hallo, Welt!");

Server-Namespace

Der Server-Namespace enthält alle serverbezogenen Funktionen.

server.name()

Gibt den Namen des Servers zurück.

print(server.name);

server.current_time()

Gibt die aktuelle Serverzeit zurück.

print(server.current_time);

server.ban_player(username: string, reason: string = "", length: string = "99 years")

Erstellt eine Bann-Einschränkung für den Spieler mit dem angegebenen Benutzernamen. Der Bann ist unter Admin → Einschränkungen sichtbar und verwaltbar.

server.ban_player("John");
server.ban_player("John", "Cheaten");
server.ban_player("John", "Cheaten", "1 day");

server.currency()

Gibt das Währungssymbol des Servers zurück, wie es unter Einstellungen → Wirtschaft konfiguriert ist.

print(server.currency); -- z.B. "Coins"
discord.send_to_channel(config.channelId, "Du hast 100 " .. server.currency .. " erhalten!");

Discord-Namespace

Der Discord-Namespace enthält alle Discord-bezogenen Funktionen.

Achtung: Alle Discord-IDs müssen als Zeichenketten (in Anführungszeichen) angegeben werden, da die Programmiersprache sie sonst als Zahlen interpretiert und mathematisch darstellt, was zu Fehlern führt.

discord.send_to_player(username: string, content: string)

Sendet eine Nachricht an den Spieler mit dem angegebenen Benutzernamen.

discord.send_to_player("John", "Hallo, John!");
discord.send_to_player("h3eh23ieuh3ei2he3", "Hallo, John!"); -- wirft eine "Spieler nicht gefunden"-Exception

discord.send_to_channel(channel: string, content: string)

Sendet eine Nachricht an den Kanal mit der angegebenen ID.

discord.send_to_channel("1234567890", "Hallo, Welt!");

discord.mention(username: string)

Gibt den Erwähnungs-String für den Spieler mit dem angegebenen Benutzernamen zurück. Kann in Discord-Nachrichten verwendet werden, um auf den Discord-Account zu verweisen. Wird kein Spieler gefunden, wird der Benutzername ohne Formatierung zurückgegeben.

print(discord.mention("John")); -- gibt "<@1234567890>" zurück
print(discord.mention("h3eh23ieuh3ei2he3")); -- gibt "h3eh23ieuh3ei" zurück

Player-Namespace

Der Player-Namespace enthält alle spielerbezogenen Funktionen.

player.change_balance(username: string, amount: number, description: string = "")

Ändert das Guthaben des Spielers mit dem angegebenen Benutzernamen.

player.change_balance("John", 100);
player.change_balance("John", 100, "Guter Schuss!");
player.change_balance("John", -100, "Schlechter Schuss!"); -- negativer Betrag zum Abziehen

player.get_balance(username: string)

Gibt das aktuelle Guthaben des Spielers mit dem angegebenen Benutzernamen zurück, oder nil, wenn kein passender Spieler gefunden wird.

local balance = player.get_balance("John");
if balance ~= nil then
print("Guthaben: " .. balance);
end

player.statistics(username: string)

Gibt ein Statistik-Objekt für den Spieler mit dem angegebenen Benutzernamen zurück. Gibt nil zurück, wenn kein passender Spieler gefunden wird.

local stats = player.statistics("John");
print(stats.online_streak); -- gibt die aktuelle Online-Tages-Serie aus

Rückgabefelder:

FeldTypBeschreibung
pvp_killsintGesamte PvP-Kills
last_pvp_killstring|nilZeitstempel des letzten Kills
pvp_deathsintGesamte PvP-Tode
last_pvp_deathstring|nilZeitstempel des letzten PvP-Todes
pvp_kdfloatKill/Death-Verhältnis
deathsintGesamte Tode (alle Ursachen)
kill_streakintKills seit dem letzten Tod
death_streakintTode seit dem letzten Kill
longest_killfloatGrößte Kill-Distanz in Metern
online_streakintAufeinanderfolgende Kalendertage mit mindestens einer Sitzung (einschließlich heute)

Beispielausgabe:

{
"pvp_kills": 8,
"last_pvp_kill": "2024-06-19 22:32:23",
"pvp_deaths": 23,
"last_pvp_death": "2024-06-19 22:49:19",
"pvp_kd": 0.35,
"deaths": 58,
"kill_streak": 0,
"death_streak": 2,
"longest_kill": 44.78,
"online_streak": 3
}
Beispiel: Online-Streak-Belohnung

Einen Bonus vergeben, der mit der Anzahl aufeinanderfolgender Online-Tage skaliert:

local stats = player.statistics(data.player.username);

if stats.online_streak >= 3 then
local bonus = config.base_reward + (stats.online_streak * config.streak_bonus);
player.change_balance(data.player.username, bonus, "Online-Streak: " .. stats.online_streak .. " Tage");
else
player.change_balance(data.player.username, config.base_reward, "Tägliche Belohnung");
end

player.get_faction(username: string)

Gibt ein Fraktions-Datenobjekt für die aktuelle Fraktion des Spielers zurück, oder nil, wenn der Spieler nicht gefunden wurde oder in keiner Fraktion ist.

local faction = player.get_faction("John");

if faction then
print(faction.id); -- z.B. 42
print(faction.name); -- z.B. "Wolves"
end

Rückgabefelder:

FeldTypBeschreibung
idintFraktions-ID
namestringFraktionsname
colorstring|nilFraktionsfarbe als Hex-Code
imagestring|nilFraktionsbild-Pfad
balanceint|nilAktuelles Fraktionskassen-Guthaben
discord_role_idstring|nilVerknüpfte Discord-Rollen-ID

Beispielausgabe:

{
"id": 42,
"name": "Wolves",
"color": "#ff0000",
"image": null,
"balance": 1500,
"discord_role_id": "1234567890"
}
Beispiel: Gesamte Fraktion bei einem Kill belohnen
local faction = player.get_faction(data.killer.username);

if faction then
faction.change_balance(faction.id, config.faction_reward, "Kill-Belohnung");
discord.send_to_channel(config.channel, faction.name .. " hat " .. config.faction_reward .. " für einen Kill erhalten!");
end
hinweis

player.get_faction hat früher die Fraktions-ID als einfachen String zurückgegeben. Es wird jetzt ein Objekt zurückgegeben — verwende .id, um auf die ID zuzugreifen.

player.get_name(username: string)

Löst den Anzeigenamen des Spielers auf. Wenn kein Name für den Benutzer gesetzt ist oder kein passender Benutzer gefunden wird, wird der eingegebene Benutzername zurückgegeben.

player.get_name("johnnyboy420"); -- gibt den Anzeigenamen des Spielers zurück: "John Doe"
player.get_name("nouserwiththatusername"); -- Benutzer nicht gefunden, gibt die Eingabe zurück: "nouserwiththatusername"

player.get_main_account(username: string)

Ermittelt den Haupt-Account-Benutzernamen zu einem Spieler. Geht alle Spieler durch, die mit dem angegebenen Spieler mindestens ein Gerät teilen, und liefert den Benutzernamen des ersten Spielers zurück, dem ein Benutzer-Account zugeordnet ist. Hat der Spieler selbst bereits einen verknüpften Benutzer-Account, wird dessen eigener Benutzername zurückgegeben. Kann kein verknüpfter Account gefunden werden oder ist der Spieler unbekannt, wird der eingegebene Benutzername unverändert zurückgegeben.

player.get_main_account("alt_account");   -- gibt "main_account" zurück, falls Alt und Main ein Gerät teilen
player.get_main_account("solo_player"); -- gibt "solo_player" zurück, wenn kein Haupt-Account verknüpft ist
Beispiel: Belohnungen dem Haupt-Account gutschreiben
local main = player.get_main_account(data.killer.username);
player.change_balance(main, config.reward or 50, "Kill-Belohnung (über " .. data.killer.username .. ")");

player.has_discord_role(username: string, role: string)

Prüft, ob der Spieler mit dem angegebenen Benutzernamen die angegebene Discord-Rolle hat. Akzeptiert sowohl den Rollennamen als auch die Rollen-ID.

player.has_discord_role("John", "6553535632356535564"); -- funktioniert mit Rollen-IDs
player.has_discord_role("John", "Admin"); -- funktioniert auch mit Rollennamen

player.ensure_discord_role(username: string, roleId: string)

Weist dem Spieler die angegebene Discord-Rolle zu. Falls der Spieler die Rolle bereits hat, passiert nichts. Die Rolle muss über ihre Discord-Rollen-ID angegeben werden.

player.ensure_discord_role("John", "1234567890123456789");

player.remove_discord_role(username: string, roleId: string)

Entfernt die angegebene Discord-Rolle vom Spieler. Falls der Spieler die Rolle nicht hat, passiert nichts. Die Rolle muss über ihre Discord-Rollen-ID angegeben werden.

player.remove_discord_role("John", "1234567890123456789");

player.list(filters?: table)

Gibt eine Liste aller Spieler auf dem Server zurück, optional gefiltert. Ohne Argumente werden alle Spieler zurückgegeben.

local players = player.list();

local vip_spieler = player.list({ group = "vip" });

local aktive_mit_discord = player.list({
has_discord = true,
last_online_after = "-7d",
});

Verfügbare Filter (alle optional):

FilterTypBeschreibung
groupstringNur Spieler, die Mitglied dieser Gruppe sind (nach Name)
whitelistedboolNur auf der Whitelist stehende / nicht stehende Spieler
bannedboolNur Spieler mit aktiver Bann-Einschränkung / Spieler ohne aktive Bann-Einschränkung
has_discordboolNur Spieler mit verknüpftem Discord-Konto
has_balance_abovenumberNur Spieler, deren Guthaben über diesem Wert liegt
has_balance_belownumberNur Spieler, deren Guthaben unter diesem Wert liegt
last_online_afterstringNur Spieler, die nach diesem Zeitpunkt zuletzt gesehen wurden. Unterstützt relative Formate wie "-7d", "-2h", "-1m", "-1y" oder einen absoluten Datums-String
last_online_beforestringNur Spieler, die vor diesem Zeitpunkt zuletzt gesehen wurden. Gleiches Format wie oben
in_factionbool oder stringtrue = in einer beliebigen Fraktion, false = in keiner Fraktion, oder Fraktionsname/-ID für eine bestimmte Fraktion
variablestring oder tableNur Spieler, bei denen eine Variable mit diesem Namen gesetzt ist. Als String wird nur der Name geprüft, als Tabelle { name = "...", value = "..." } zusätzlich der Wert

Rückgabefelder (ein Eintrag pro passendem Spieler):

FeldTypBeschreibung
idintInterne Spieler-ID
usernamestringSpieler-Benutzername
balanceint|nilAktuelles Guthaben
last_onlinestring|nilZuletzt-gesehen-Zeitstempel (Y-m-d H:i:s)
whitelistedboolOb der Spieler auf der Whitelist steht
bannedboolOb der Spieler eine aktive Bann-Einschränkung hat
Beispiel: Tägliche Guthabenbelohnung für alle VIP-Mitglieder
local players = player.list({
group = "vip",
last_online_after = "-30d",
});

for _, p in ipairs(players) do
player.change_balance(p.username, 100, "Monatlicher VIP-Bonus");
end
Beispiel: Inaktive Spieler via Discord benachrichtigen
local inaktive = player.list({
has_discord = true,
last_online_before = "-14d",
banned = false,
});

for _, p in ipairs(inaktive) do
discord.send_to_player(p.username, "Wir vermissen dich auf dem Server! Komm bald wieder.");
end
Beispiel: Nach Variablenwert filtern
-- Alle Spieler, deren Variable "vip_tier" auf "gold" gesetzt ist
local gold_vips = player.list({ variable = { name = "vip_tier", value = "gold" } });

for _, p in ipairs(gold_vips) do
player.change_balance(p.username, 500, "Gold-VIP Tagesbonus");
end

player.get_variable(username: string, name: string)

Gibt den Wert einer Spieler-Variablen zurück oder nil, wenn die Variable nicht gesetzt ist.

local result = player.get_variable("John", "kill_count");
print(result.value); -- gibt den gespeicherten Wert aus, oder nil

Rückgabefelder:

FeldTypBeschreibung
namestringVariablenname
valuestring|nilGespeicherter Wert, oder nil wenn nicht gesetzt

player.set_variable(username: string, name: string, value: string|nil)

Erstellt oder aktualisiert eine Spieler-Variable. Mit nil als Wert wird die Variable gelöscht.

player.set_variable("John", "kill_count", "42");
player.set_variable("John", "vip_tier", "gold");
player.set_variable("John", "temp_flag", nil); -- löscht die Variable
Beispiel: Kill-Streaks mit Variablen verfolgen
local streak_result = player.get_variable(data.killer.username, "kill_streak");
local streak = tonumber(streak_result.value) or 0;
streak = streak + 1;

player.set_variable(data.killer.username, "kill_streak", tostring(streak));

if streak >= 5 then
player.change_balance(data.killer.username, 250, "Kill-Streak x" .. streak);
discord.send_to_channel(config.feedChannel, data.killer.username .. " hat einen " .. streak .. "-Kill-Streak!");
end

-- Streak des Opfers zurücksetzen
player.set_variable(data.victim.username, "kill_streak", "0");

player.last_position(username: string)

Gibt die letzte bekannte Ingame-Position des Spielers zurück, basierend auf seinem letzten Online-Ping (wird etwa alle 5 Minuten aufgezeichnet, während er online ist), oder nil, wenn der Spieler nicht gefunden wird oder keine Position aufgezeichnet wurde. Die Position kann Minuten oder Tage alt sein — prüfe das Feld time, wenn Aktualität wichtig ist.

local pos = player.last_position(data.target.username);
if pos then
discord.send_to_channel(config.channel, "Zuletzt gesehen bei " .. string.format("%.0f / %.0f", pos.x, pos.z));
end

Rückgabefelder:

FeldTypBeschreibung
xfloatOst/West-Weltkoordinate
yfloatHöhe
zfloatNord/Süd-Weltkoordinate
timestringZeitpunkt der Aufzeichnung (YYYY-MM-DD HH:MM:SS, UTC)

Fraktions-Namespace

Der Fraktions-Namespace enthält alle fraktionsbezogenen Aktionsfunktionen.

faction.change_balance(id: string, amount: number, description: string = "")

Ändert das Guthaben der Fraktion mit der angegebenen ID.

faction.change_balance("123", 100);
faction.change_balance("123", 100, "Gute Leute!");
faction.change_balance("123", -100, "Regelverstoß!"); -- negativer Betrag zum Abziehen

Bounty-Namespace

Der Bounty-Namespace stellt die Kopfgelder des Hitman-Systems bereit.

bounty.list()

Gibt alle offenen Kopfgelder auf dem Server zurück, neueste zuerst. Abgeschlossene oder stornierte Kopfgelder sind nie enthalten. Gibt eine leere Liste zurück, wenn kein Kopfgeld offen ist — das Iterieren ist also immer sicher.

local bounties = bounty.list();
print("Offene Kopfgelder: " .. #bounties);

Rückgabefelder (ein Eintrag pro Kopfgeld):

FeldTypBeschreibung
idintInterne Kopfgeld-ID
targetstringBenutzername des Spielers, auf den das Kopfgeld ausgesetzt ist
created_bystringBenutzername des Spielers, der das Kopfgeld ausgesetzt hat
amountintKopfgeldbetrag
reasonstring|nilBeim Aussetzen angegebener Grund
target_all_accountsboolOb der Kill eines beliebigen mit dem Gerät des Ziels verknüpften Accounts ausgezahlt wird
created_atstringZeitpunkt des Aussetzens (YYYY-MM-DD HH:MM:SS, UTC)

Auf dasselbe Ziel können mehrere Kopfgelder existieren — gruppiere selbst nach target, wenn du einen Eintrag pro Spieler brauchst.

Beispiel: Geplanter Kopfgeld-Statusbericht

Poste die letzte bekannte Position jedes Spielers mit offenem Kopfgeld, z. B. aus einer geplanten benutzerdefinierten Aktion. Wenn kein Kopfgeld offen ist, wird keine Nachricht gesendet:

local bounties = bounty.list();
if #bounties > 0 then
local lines = {};
for _, b in ipairs(bounties) do
local pos = player.last_position(b.target);
local where = pos and string.format("%.0f / %.0f", pos.x, pos.z) or "unbekannt";
table.insert(lines, b.target .. " (" .. b.amount .. ") — zuletzt gesehen: " .. where);
end
discord.send_to_channel(config.channel, "**Offene Kopfgelder:**\n" .. table.concat(lines, "\n"));
end

Math-Namespace

Der Math-Namespace enthält Hilfsfunktionen für Berechnungen.

math.distance(x1: number, z1: number, x2: number, z2: number)

Berechnet die 2D-Distanz zwischen zwei Punkten. Nützlich, um zu prüfen, ob eine Position innerhalb eines bestimmten Radius einer anderen Position liegt.

-- Distanz zwischen zwei Koordinaten berechnen
local dist = math.distance(1000, 2000, 1500, 2500);
print("Distanz: " .. dist); -- gibt ungefähr 707.1 aus
Beispiel: Radius-Prüfung

Prüfen, ob ein Kill innerhalb eines bestimmten Radius einer Location stattgefunden hat (z.B. einer Safezone oder Basis):

local safezone_x = 5000;
local safezone_z = 5000;
local safezone_radius = 100;

local kill_distance = math.distance(data.x, data.z, safezone_x, safezone_z);

if kill_distance < safezone_radius then
discord.send_to_channel(config.alertChannel, "Kill innerhalb der Safezone erkannt!");
server.ban_player(data.killer, "Kill in Safezone", "1 day");
end
Beispiel: Weitschuss-Kills belohnen
-- Distanz zwischen Killer und Opfer berechnen
local kill_range = math.distance(data.killerX, data.killerZ, data.victimX, data.victimZ);

if kill_range > 500 then
player.change_balance(data.killer, 100, "Weitschuss-Bonus (" .. math.floor(kill_range) .. "m)");
discord.send_to_channel(config.feedChannel, data.killer .. " hat einen " .. math.floor(kill_range) .. "m-Kill erzielt!");
end

HTTP-Namespace

Der HTTP-Namespace ermöglicht es Aktionen, ausgehende HTTP-Anfragen an externe Dienste zu stellen. Anfragen haben ein Timeout von 5 Sekunden.

http.get(url: string, headers?: table)

Führt eine HTTP-GET-Anfrage durch. Gibt zwei Werte zurück: den HTTP-Statuscode und den Antwort-Body als String.

local status, body = http.get("https://api.example.com/data");
print(status); -- z.B. 200
print(body); -- roher Antwort-Body als String

Mit benutzerdefinierten Headern:

local status, body = http.get("https://api.example.com/data", {
["Authorization"] = "Bearer meintoken",
["Accept"] = "application/json",
});

http.post(url: string, body?: string, headers?: table)

Führt eine HTTP-POST-Anfrage durch. Gibt zwei Werte zurück: den HTTP-Statuscode und den Antwort-Body als String.

local status, body = http.post("https://api.example.com/webhook", "payload=hallo");

JSON-Body senden:

local payload = json.encode({ event = "kill", player = data.killer.username });
local status, body = http.post("https://api.example.com/events", payload, {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer meintoken",
});
Beispiel: Externen Webhook bei einem Kill-Event benachrichtigen
local payload = json.encode({
killer = data.killer.username,
victim = data.victim.username,
weapon = data.weapon,
});

local status, body = http.post(config.webhookUrl, payload, {
["Content-Type"] = "application/json",
});

if status ~= 200 then
print("Webhook fehlgeschlagen mit Status: " .. status);
end

JSON-Namespace

Der JSON-Namespace stellt JSON-Kodierung und -Dekodierung bereit, um mit API-Antworten und Payloads zu arbeiten.

json.encode(value)

Kodiert einen Lua-Wert (Tabelle, String, Zahl, Boolean) als JSON-String.

local encoded = json.encode({ name = "John", score = 42 });
print(encoded); -- {"name":"John","score":42}

json.decode(json: string)

Parst einen JSON-String und gibt eine Lua-Tabelle zurück.

local decoded = json.decode('{"name":"John","score":42}');
print(decoded.name); -- John
print(decoded.score); -- 42
Beispiel: JSON-API aufrufen und Antwort verarbeiten
local status, body = http.get("https://api.example.com/players/" .. data.player.username);

if status == 200 then
local result = json.decode(body);
if result.vip == true then
player.change_balance(data.player.username, config.vipBonus, "VIP-Bonus");
end
end

In-App-Events

Die meisten Action-Trigger stammen direkt aus den Spielserver-Logs (Kills, Verbindungen, Basisbau usw.). Eine kleine Anzahl von Events wird von dzbot selbst erzeugt, wenn etwas innerhalb der Plattform passiert. Diese synthetischen Events durchlaufen dieselbe Action-Pipeline wie Game-Log-Events.

bounty_placed

Wird ausgelöst, wenn ein Spieler über den Shop ein Kopfgeld auf einen anderen Spieler aussetzt. Verwende diesen Trigger, um das Ziel zu benachrichtigen, in einem Discord-Kanal zu posten oder eine andere Automatisierung zu starten, sobald ein Kopfgeld aktiv wird.

Event-Payload:

FeldTypBeschreibung
data.target.usernamestringBenutzername des Spielers, auf den das Kopfgeld ausgesetzt wurde
data.target.identifierstringSteam/DayZ-ID des Ziels
data.placedBy.usernamestringBenutzername des Spielers, der das Kopfgeld ausgesetzt hat
data.placedBy.identifierstringSteam/DayZ-ID des Auftraggebers
data.amountintHöhe des Kopfgelds in der Server-Währung
data.reasonstring|nilOptionale Begründung des Auftraggebers
data.bountyIdint|nilInterne Kopfgeld-ID

Beispiel — DM an den Ziel-Spieler senden:

local reason = data.reason or "Kein Grund angegeben";
discord.send_to_player(
data.target.username,
"Ein Kopfgeld von **" .. data.amount .. "** wurde von "
.. data.placedBy.username .. " auf dich ausgesetzt.\n> " .. reason
);

Beispiel — Nachricht in einen Kanal senden:

local channelId = config.channel or "";
if channelId == "" then return end;

local reason = data.reason or "Kein Grund angegeben";
discord.send_to_channel(
channelId,
"**Kopfgeld ausgesetzt!** " .. discord.mention(data.placedBy.username)
.. " hat ein Kopfgeld von **" .. data.amount .. "** auf "
.. discord.mention(data.target.username) .. " ausgesetzt.\n> *" .. reason .. "*"
);

Verwandte Dokumentation