Kepler. Documentation · Scripts 325 fonctions disponibles actuellement English

Sortie, journal et stockage

Ce que fait un script quand il ne parle pas au jeu : écrire ce qu'il voit, prévenir, et se souvenir d'une passe à la suivante.

Écrire dans la console

La console est le bloc sous l'éditeur, page Scripts. Elle affiche ce que votre script écrit, en direct.

FonctionRend
Print(...)rienÉcrit une ligne. Les arguments sont collés avec un espace.
print(...)rienLe même, sous son autre nom.
Printf(format, ...)rienÉcrit une ligne formatée, à la façon de fmt.Printf.
Print("cible", coord, "butin", butin)      // cible [P:1:64:6] butin 75
Printf("%d planetes, %d lunes", np, nl)

Une ligne de Print va à la fois dans la console et dans le journal du robot. Vous la retrouverez donc page Journaux, avec le nom de votre script en étiquette, ce qui est commode pour relire une nuit entière.

Journaliser par niveau

Quand un script tourne longtemps, tout écrire au même niveau rend le journal illisible. Ces fonctions écrivent avec un niveau, que la page Journaux sait filtrer.

FonctionNiveauQuand s'en servir
LogDebug(...) / LogDebugf(format, ...)InfoLe détail qui n'intéresse que vous, un jour de mise au point.
LogInfo(...) / LogInfof(format, ...)InfoLe déroulé normal : « campagne lancée », « douze cibles retenues ».
LogWarn(...) / LogWarnf(format, ...)WarnCe qui mérite un œil sans être grave : une cible perdue, une page illisible.
LogError(...) / LogErrorf(format, ...)ErrorCe qui a échoué.

LogDebug n'est pas un niveau à part. Elle écrit en Info, exactement comme LogInfo : router un « détail de mise au point » vers un vrai niveau Debug l'aurait fait disparaître des journaux d'une instance réglée sur Info, qui est le réglage par défaut. Une ligne LogDebug ne se filtre donc pas séparément de LogInfo sur la page Journaux.

LogInfof("%d cibles retenues sur %d", gardees, vues)
if err != nil { LogError("relevé impossible :", err) }

Les variantes en f prennent un format en premier argument, les autres collent leurs arguments. Toutes acceptent autant d'arguments que vous voulez.

Se souvenir entre deux passes

Un script qui redémarre repart de zéro. Ces cinq fonctions lui donnent une mémoire, rangée dans la base du robot, qui survit à un arrêt comme à une mise à jour.

FonctionRend
Put(clé, valeur)1 : une erreurRange une valeur.
Get(clé)2 : la valeur et une erreurRelit. Une clé absente rend la chaîne vide, sans erreur.
Has(clé)1 : un booléenDit si la clé existe.
Delete(clé)1 : un booléenEfface.
StorageKeys()1 : une listeToutes les clés rangées par ce script.
Put("dernier.systeme", 128)

sys, err = Get("dernier.systeme")     // ← DEUX cibles, voir le piège n°1
if err != nil { LogError(err) }
if sys == "" { sys = 1 }              // jamais écrite : chaîne vide

for cle in StorageKeys() {
	Print(cle)
}

Get est l'exemple type du premier piège : écrite sys = Get("dernier.systeme"), elle rend [128 <nil>] et toutes vos comparaisons échouent en silence.

Ce que la mémoire retient. Les valeurs sont rangées en JSON : un nombre revient nombre, un booléen revient booléen, une table revient table. Chaque script a la sienne, personne ne lit celle du voisin, et renommer un script emporte sa mémoire avec lui. Pour partager, voir plus bas.

Une clé jamais écrite rend la chaîne vide, et c'est un piège pour les listes

C'est le cas du premier lancement : la clé n'existe pas encore, Get rend "", et une chaîne ne se parcourt pas. Votre boucle s'arrête sur « for cannot loop over type string », et votre liste noire est vide de toute façon.

// Faux au premier lancement.
noirs, err = Get("liste.noire")
for d in noirs { ... }              // ← « for cannot loop over type string »

// Juste : on part d'une liste, et on ne relit que si la clé existe.
noirs = []
if Has("liste.noire") {
	noirs, err = Get("liste.noire")
}

Et le message ne montrera pas la ligne fautive. Quand la faute est dans le corps d'une fonction, le moteur ne rend que la ligne de sa DÉCLARATION - et si cette fonction en appelle une autre, c'est encore la déclaration de l'appelante qui sort. Une boucle cassée au fond de votre dansLaListe() sera annoncée sur la ligne du func qui l'appelle. Le message le dit désormais, mais il ne peut pas nommer la vraie ligne : le moteur l'a jetée.

Partager entre robots

La mémoire de Put est à un seul script. Ces cinq fonctions-ci rangent dans une mémoire commune à tous les robots de votre Kepler : ce qu'un script écrit sur un compte, un autre script le relit sur un autre compte. Mêmes règles que ci-dessus : les valeurs sont rangées en JSON, une clé absente rend la chaîne vide, et la mémoire survit à un arrêt comme à une mise à jour.

FonctionRend
PutShared(clé, valeur)1 : une erreurRange une valeur, lisible par tous les robots.
GetShared(clé)2 : la valeur et une erreurRelit. Une clé absente rend la chaîne vide, sans erreur.
HasShared(clé)1 : un booléenDit si la clé existe.
DeleteShared(clé)1 : un booléenEfface.
SharedKeys()1 : une listeToutes les clés partagées.
// Sur le robot qui décide
PutShared("fs.cible", "4:120:8")

// Sur n'importe quel autre robot du même Kepler
cible, err = GetShared("fs.cible")      // ← DEUX cibles, comme Get
if err != nil { LogError(err) }
if HasShared("fs.fini") {
	DeleteShared("fs.fini")
}
for cle in SharedKeys() {
	Print(cle)
}

Tous les scripts de tous vos robots écrivent au même endroit. Préfixez vos clés - fs., ferme. - pour ne pas écraser celles d'un autre script : ici, personne ne vous en protège. Supprimer ou renommer un script ne touche jamais à cette mémoire, puisqu'elle n'appartient à aucun.

Le partage vaut pour un Kepler. Les robots d'une même installation se voient ; sur le Cloud, deux instances sont deux Kepler distincts, et ne partagent rien.

Prévenir dehors

FonctionRend
SendDiscord(webhook, message)1 : une erreurPublie sur un webhook Discord.
SendDiscordFile(webhook, nom, contenu)1 : une erreurPublie un fichier texte en pièce jointe.
SendTelegram(chatID, message)1 : une erreurÉcrit dans une conversation Telegram.
err = SendDiscord("https://discord.com/api/webhooks/…", "débris à " + coord)
if err != nil { LogError("Discord :", err) }

Les deux écrivent avec les réglages du robot. TELEGRAM_CHAT_ID et DISCORD_WEBHOOK portent ce que vous avez rempli dans la page Notifications : un script recopié de Ninja qui écrit SendDiscord(DISCORD_WEBHOOK, …) part donc au bon endroit, sans rien configurer de plus.

SendDiscord(DISCORD_WEBHOOK, "débris à " + coord)
SendTelegram(0, "débris à " + coord)     // 0 : la conversation des réglages

Ces deux constantes sont lues au démarrage du script. Si vous changez vos réglages pendant qu'il tourne, relancez-le. SendTelegram(0, …), elle, relit les siens à chaque appel.

Un tableau se envoie en fichier, pas en confettis

SendDiscord coupe à deux mille caractères et poste les morceaux. Pour une alerte c'est ce qu'on veut ; pour un tableau de trois cents lignes, ce n'est plus un tableau. SendDiscordFile l'envoie d'un bloc, en pièce jointe.

lignes = "coord;joueur;points\n"
for j in trouvés {
	lignes = lignes + j.Coord + ";" + j.Nom + ";" + Itoa(j.Points) + "\n"
}
err = SendDiscordFile(DISCORD_WEBHOOK, "inactifs.csv", lignes)
if err != nil { LogError("Discord :", err) }

Rien n'est écrit sur le disque, ni chez vous ni sur le serveur : le contenu part directement dans la requête. C'est d'ailleurs la raison d'être de cette fonction plutôt que d'un accès aux fichiers - ce qu'un script veut en général n'est pas un fichier, c'est faire arriver son résultat à quelqu'un.

Le second usage est le déboguage. Quand une passe se passe mal, ce qu'il faut regarder est la réponse brute qui a égaré votre analyse, pas son résumé - et un message la tronque exactement là où c'est intéressant.

Le nom est nettoyé, jamais refusé : un chemin est ramené à son dernier morceau, un nom vide devient rapport.txt. Le script voulait envoyer son contenu, pas débattre du nom.

La taille dépend de votre serveur Discord, pas de nous : son plafond monte avec son niveau. Au-dessus de 25 Mio nous refusons d'emblée ; en dessous, si Discord refuse, c'est sa réponse à lui que vous recevez, et c'est elle qui dit la vraie limite.

Elle est propre à Kepler. L'outil de référence ne connaît que SendDiscord.

Rien ne vous oblige à passer par elles : une adresse écrite en clair marche aussi, et Put ou !global.ank la partagent entre vos scripts.

// dans !global.ank
MON_WEBHOOK = "https://discord.com/api/webhooks/…"

Telegram

SendTelegram(chatID, message) écrit avec le bot Telegram du robot, celui dont vous avez collé le jeton dans la page Notifications. Vous n'avez pas de jeton à recopier dans vos scripts, et rien de secret n'y traîne.

ÉcritureOù part le message
0La conversation de vos réglages. C'est le cas ordinaire.
Un nombre positifCette conversation-là.
Un nombre négatifUn groupe ou un canal — Telegram les numérote ainsi.

Sans jeton ni conversation dans vos réglages, l'appel rend une erreur et rien ne part : SendTelegram : Telegram n'est pas encore configuré. Testez son retour, comme pour Discord.

Le texte part tel quel, sans mise en forme. C'est délibéré : la sortie d'un script contient des coordonnées, des pseudos et des chevrons, et en mode HTML un seul d'entre eux ferait refuser tout le message par Telegram — l'alerte serait perdue au pire moment.

Un message de plus de 4 096 caractères est découpé plutôt que rejeté. Discord fait de même à 2 000.

Gouverner son propre script

FonctionRend
Exit()rienArrête le script proprement.
Terminate()rienLe même.
IsPaused()1 : un booléenDit si le joueur a mis le script en pause.

Exit et Terminate sont sans effet depuis !global.ank : ce fichier définit l'environnement commun, et l'arrêter n'aurait pas de sens. Un avertissement le rappelle au journal si vous essayez.

if IsPaused() { SleepSec(30); continue }

Quelques commodités

FonctionRend
Shuffle(liste)rienMélange une liste sur place.
Bytes2Str(octets)1 : une chaîneConvertit des octets en texte. Anko ne sait pas écrire un []byte littéral, d'où cette fonction.
cibles = [1, 2, 3, 4, 5]
Shuffle(cibles)          // l'ordre change, la liste reste la même

Shuffle mélange la liste que vous lui donnez et ne rend rien : n'écrivez pas l = Shuffle(l), vous perdriez la liste.

L'heure courante se lit avec Clock, Date et Now, page Temps et attente.

Prévenir

FonctionRend
Notify(titre, message)rienÉcrit au journal du compte, au niveau Warn.

Écart avec Ninja, et il vaut mieux le lire ici. Là-bas, Notify fait apparaître une bulle sur le bureau de la machine qui exécute le robot. Kepler tourne le plus souvent sur un serveur que personne ne regarde : une bulle y serait vue par personne, et prétendre le contraire serait mentir.

Elle écrit donc au niveau Warn dans le journal du compte — celui que la page Journal affiche et qui se relit après coup. Pour être prévenu sur votre téléphone, ce sont SendDiscord et SendTelegram qu'il faut appeler : elles partent vers l'extérieur, et c'est un geste délibéré plutôt qu'un effet de bord.