Plugin25n.png

Mit dem Plugin-System von Visionaire Studio entwickelst du eigene Aktionsteile.

Plugins werden pro Projekt installiert. In einem neuen Projekt musst du sie also (erneut) installieren, auch wenn du sie schon in einem anderen Projekt verwendet hast. Über das Puzzle-Symbol in der Symbolleiste öffnest du den Plugin-Bereich und siehst alle installierten und installierbaren Plugins. Dort kannst du sie auch wieder deinstallieren.

Nach der Installation stehen dir die neuen Aktionsteile zur Verfügung: im Auswahldialog im Bereich „Custom“ und unten in der Liste der Aktionsteile in den Eigenschaften eines Aktionsteils.

Mitglieder der Visionaire-Community haben einige ihrer Plugins geteilt. Du kannst sie hier im Wiki herunterladen.


Ein Plugin installieren

  1. Besorge dir die ZIP-Datei des Plugins (zum Herunterladen oder selbst gebaut).
  2. Lege im Hauptordner deines Projekts (dort, wo die .ved- bzw. .veb-Datei liegt) einen Ordner „plugins“ an, falls es ihn noch nicht gibt.
  3. Entpacke die Datei und kopiere den Ordner darin in den Ordner „plugins“.
  4. Öffne dein Projekt in Visionaire und klicke oben rechts auf das Puzzle-Symbol.
  5. Die Liste der verfügbaren Plugins öffnet sich. Klicke beim neuen Eintrag auf „Install“.
  6. Speichere dein Projekt.


Ein Plugin entwickeln

Danke an lehman und Chris_Dionous für die Informationen, wie man Plugins für Visionaire Studio baut.
Aufbau eines Plugins

Jedes Plugin ist ein Ordner mit bis zu vier Dateien, meist als ZIP-Archiv weitergegeben (siehe Bild). Bei der Installation entpackt man das Archiv selbst und kopiert den Ordner in das Verzeichnis „plugins“ (siehe Anleitung oben). Du kannst weitere Dateien in den Ordner legen, etwa eine README oder Ressourcen, die du brauchst. Die folgenden Dateien benötigt Visionaire aber, nur das Bild ist optional:

  • Ordner Benenne den Ordner wie dein Plugin (so wie in der Datei config.ini angegeben).
  • config.ini Die INI-Datei sagt der Engine (und den Nutzern), worum es in deinem Plugin geht.
  • editor.lua Diese Lua-Datei richtet die Eingabefelder des Aktionsteils im Visionaire-Editor ein.
  • image.png Optional ein PNG-Bild mit 128 × 128 Pixeln, das dein Plugin im Plugin-Bereich des Editors darstellt.
  • player.lua Diese Lua-Datei enthält den Code, der läuft, wenn der Aktionsteil im Spiel ausgeführt wird.


config.ini

Hier eine Beispiel-INI aus dem Plugin „Hello World“ (Download unten). Sie enthält alle nötigen Einträge:

# config.ini

Name=Hello World
Author=Einzelkämpfer
Date=12.04.2023
Version=1.0
PluginVersion=1
Link=https://wiki.visionaire-tracker.net/wiki/Plugins
ActionParts=Print Hello World
Description=This plugin adds an action part to print the string "Hello, World!" to the log file.
  • Unter Name steht der Name des Plugins. Er muss mit dem Namen des Plugin-Ordners übereinstimmen.
  • Unter Author trägst du deinen Namen ein, unter Date das Datum der Erstellung oder Veröffentlichung (das Format wählst du selbst).
  • Unter Version steht die Versionsnummer deines Plugins.
  • PluginVersion gibt die Art des Plugins an. Der Wert muss „1“ sein, denn das ist derzeit die einzige Art in Visionaire Studio.
  • Unter Link kannst du auf deine Website verweisen.
  • Unter ActionParts stehen die Aktionsteile deines Plugins (durch Komma getrennt). Im Beispiel ist es nur einer namens „Print Hello World“, ein Plugin kann aber auch mehrere Aktionsteile anlegen. Der Name jedes Aktionsteils muss mit dem Namen in editor.lua und player.lua übereinstimmen. Unter diesem Namen erscheint er auch im Editor.
  • Unter Description kannst du beschreiben, was dein Plugin macht.


Die Grundlagen: „Hello, World!“

Nach der INI-Datei registrierst du den neuen Aktionsteil für den Editor und für den Player.

In der Datei editor.lua bekommt die Funktion registerActionPart() zwei Argumente: zuerst den Namen des Aktionsteils, wie er in der config.ini unter „ActionParts“ steht, dann eine Tabelle mit Optionen. Diese Optionen legen die Eingabefelder des Aktionsteils im Editor fest. „Hello World“ hat keine Eingaben, deshalb sind alle Optionen im Grunde leer. Übergib aber immer die vollständige Tabelle, damit nichts falsch eingestellt wird. Die einzelnen Optionen sind weiter unten beschrieben.

-- editor.lua

registerActionPart('Print Hello World', {
	isif = false,
	link1 = { text = '', use = false, control = 0 },
	link2 = { text = '', use = false, control = 0 },
	integers = { use = 0, useint3 = false, pointlabel = '', pointdialog = 0 },
	integer1 = { text = '', control = 0, min = 0, max = 0, val = 0, options = {} },
	integer2 = { text = '', control = 0, min = 0, max = 0, val = 0, options = {} },
	integer3 = { text = '', control = 0, min = 0, max = 0, val = 0, options = {} },
	path = { text = '', use = false, filter = 0 },
	string = { text = '', use = 0 },
	link1filter = {},
	link2filter = {},
	stringfilter = {}
})


In der Datei player.lua bekommt registerActionPart() ebenfalls zwei Argumente: wieder den Namen des Aktionsteils und dann die Callback-Funktion, die im Spiel läuft, wenn der Aktionsteil ausgeführt wird. Sie erhält zwei Parameter:

  • „activeAction“ ist die Aktion, zu der der Aktionsteil gehört,
  • „actionPart“ ist der Aktionsteil selbst mit allen Einstellungen, die im Editor gewählt wurden.


Die Funktion muss einen Wahrheitswert zurückgeben, normalerweise false, wenn sie fertig ist. Gibst du true zurück, wiederholt sich der Aktionsteil endlos.

-- player.lua

registerActionPart('Print Hello World', function(activeAction, actionPart)
    print("Hello, World!")
    return false
end
)


Über die Grundlagen hinaus: bewährte Vorgehensweisen

Text des Aktionsteils und Übersetzung

Eigener Aktionsteil

Standardmäßig wird der Name des Aktionsteils nicht nur in der Liste der Aktionsteile im Editor angezeigt, sondern auch in der Liste innerhalb einer Aktion. Du kannst beide Bezeichnungen aber getrennt festlegen und sogar die Eingaben des Nutzers über Parameter in den Text einbauen. Im Bild heißt der Aktionsteil „Log string“, in der Aktion erscheint er aber als „Print '___' to the log“, ergänzt um die Eingabe „Hello, World!“.

Dieser zusätzliche Text entsteht über die Übersetzungsfunktion in editor.lua<

-- editor.lua

registerActionPart('LOG_STRING',{
	isif = false,
	link1 = { text = '', use = false, control = 0 },
	link2 = { text = '', use = false, control = 0 },
	integers = { use = 0, useint3 = false, pointlabel = '', pointdialog = 0 },
	integer1 = { text = '', control = 0, min = 0, max = 0, val = 0, options = {} },
	integer2 = { text = '', control = 0, min = 0, max = 0, val = 0, options = {} },
	integer3 = { text = '', control = 0, min = 0, max = 0, val = 0, options = {} },
	path = { text = '', use = false, filter = 0 },
	string = { text = 'LOG_TEXT', use = 1 },
	link1filter = {},
	link2filter = {},
	stringfilter = {}
})

-- 1 = German translations
translation(1, 'LOG_STRING', 'Text loggen')
translation(1, 'LOG_STRING_Name', "Schreibe '%string' ins Log")
translation(1, 'LOG_TEXT', "Text")

-- 2 = English translations
translation(2, 'LOG_STRING', 'Log string')
translation(2, 'LOG_STRING_Name', "Print '%string' to the log")
translation(2, 'LOG_TEXT', "Text")


Mit der Funktion translation() gibst du dem Platzhalter dann den eigentlichen Text. Das erste Argument ist der Sprachcode: 1: Deutsch | 2: Englisch | 3: Spanisch | 4: Französisch | 5: Niederländisch | 6: Italienisch | 7: Russisch. Hängst du an den Platzhalter die Endung „_Name“ an, legst du den Text für die Liste innerhalb der Aktion fest.

Im Beispiel nutzen wir die Option „string“ aus der Optionstabelle für ein Textfeld. Es heißt „LOG_TEXT“, ebenfalls ein Platzhalter, der übersetzt wird. Im Text für die Aktion setzen wir den Parameter „%string“ dorthin, wo die Eingabe erscheinen soll („Print '%string' to the log“).


Mehrere Aktionsteile anlegen

Im Plugin „Log Me“ siehst du, dass es zwei eigene Aktionsteile anlegt: LOG_TIME und LOG_STRING. Die Datei editor.lua oben zeigt nur einen davon; weitere fügst du einfach mit zusätzlichen Aufrufen von registerActionPart() hinzu. Alle Aktionsteile müssen außerdem in der config.ini stehen, durch Komma getrennt und ohne Leerzeichen:

# config.ini

ActionParts=LOG_TIME,LOG_STRING


In der Datei player.lua legst du den eigentlichen Code des Aktionsteils am besten in eine eigene Funktion, statt ihn direkt in die Callback-Funktion zu schreiben.

„LOG_TIME“ bekommt keine Eingabe, „LOG_STRING“ dagegen den Text, den der Nutzer eingibt. Du erreichst ihn über das Objekt „actionPart“. Achtung: Die Eigenschaft „String“ beginnt hier mit großem „S“.

-- player.lua

function print_time_to_log()
    local time = getTime()

    if(time == 0) then
        print("First execution of this action part.")
    else
        print(time .. "ms passed since the last execution of this action part.")
    end
    
    getTime( {flags = 1, reset = true} )
end

function print_string_to_log(text)
    print(text)
end

registerActionPart('LOG_TIME', function(activeAction, actionPart)
    print_time_to_log()
    return false
end
)

registerActionPart('LOG_STRING', function(activeAction, actionPart)
    print_string_to_log(actionPart.String)
    return false
end
)


Verfügbare Eingabefelder im Editor

Beim Bau von Visionaire-Plugins gibt es zwei Einschränkungen:

  1. Anzahl und Art der Eingabefelder sind begrenzt.
  2. Die Felder sind nicht einheitlich benannt und aufgebaut, weil das Datenmodell von Visionaire über die Jahre für Zwecke erweitert wurde, für die es ursprünglich nicht gedacht war.


Die folgende Tabelle zeigt alle Felder und wie du sie in den Optionen von editor.lua festlegst. Manche Felder heißen in player.lua anders, zum Beispiel wird „link2“ dort zu „actionPart.AltLink“.

Feldname Entspricht Eigenschaften Verwendung Hinweise
isif (bool) Dieses Feld wird derzeit nicht unterstützt, sollte aber trotzdem enthalten sein.
link1 actionPart.Link text (str) Name des Felds im Editor
use (bool) Auf true setzen, um das Feld zu aktivieren
control (int) Art des Felds:
  • 0: Auswahl eines Visionaire-Objekts aus der in link1filter angegebenen Tabelle (Dialogfenster)
  • 1: Auswahl eines Visionaire-Objekts aus der in link1filter angegebenen Tabelle (Ausklappliste)
  • 2: Mehrsprachiges Textfeld
link2 actionPart.AltLink text (str) Name des Felds im Editor
use (bool) Auf true setzen, um das Feld zu aktivieren
control (int) Art des Felds:
  • 0: Auswahl eines Visionaire-Objekts aus der in link2filter angegebenen Tabelle (Dialogfenster)
  • 1: Auswahl eines Visionaire-Objekts aus der in link2filter angegebenen Tabelle (Ausklappliste)
  • 2: Mehrsprachiges Textfeld
integers actionPart.Int (x)

actionPart.AltInt (y)

use (int) Legt fest, wie viele der folgenden Zahlenfelder verwendet werden, oder macht aus dem Feld integers eine Positionsauswahl.
  • 0: keine Zahlenfelder (außer integer3, das unabhängig über useint3 aktiviert wird)
  • 1: Positionsauswahl anzeigen
  • 2: nur das Feld integer1 verwenden
  • 3: die Felder integer1 und integer2 verwenden
Als Positionsauswahl („use=1“) werden x und y als zwei getrennte Werte übergeben: Int und AltInt.
useint3 (bool) Auf true setzen, um das Feld integer3 zu verwenden
pointlabel (str) Name der Positionsauswahl (nur bei „use=1“)
pointdialog (int) offenbar veraltet
integer1 actionPart.Int text (str) Name des Felds im Editor Für dieses Feld muss beim Feld integers „use=2“ oder „use=3“ gesetzt sein.
control (int) Art des Felds:
  • 0: Zahlenfeld (mit Pfeilen)
  • 1: Zahlenfeld (mit Pfeilen)
  • 2: Kontrollkästchen
  • 3: Optionsfelder (Optionen aus der Tabelle options)
  • 4: Ausklappliste (Optionen aus der Tabelle options)
  • 5: Kompass zur Wahl einer Richtung
  • 6: Regler in Dezibel (dB) für Audio
min (int) Kleinster Wert des Zahlenfelds (nur bei „control=0“ oder „control=1“)
max (int) Größter Wert des Zahlenfelds (nur bei „control=0“ oder „control=1“)
val (int) Startwert
options (table) Die Optionen für Optionsfelder („control=3“) oder eine Ausklappliste („control=4“) als Tabelle von Texten. Sie bekommen automatisch fortlaufende Zahlen ab 0.
integer2 actionPart.AltInt text (str) Name des Felds im Editor Für dieses Feld muss beim Feld integers „use=3“ gesetzt sein.
control (int) Art des Felds:
  • 0: Zahlenfeld (mit Pfeilen)
  • 1: Zahlenfeld (mit Pfeilen)
  • 2: Kontrollkästchen
  • 3: Optionsfelder (Optionen aus der Tabelle options)
  • 4: Ausklappliste (Optionen aus der Tabelle options)
  • 5: Kompass zur Wahl einer Richtung
min (int) Kleinster Wert des Zahlenfelds (nur bei „control=0“ oder „control=1“)
max (int) Größter Wert des Zahlenfelds (nur bei „control=0“ oder „control=1“)
val (int) Startwert
options (table) Die Optionen für Optionsfelder („control=3“) oder eine Ausklappliste („control=4“) als Tabelle von Texten. Sie bekommen automatisch fortlaufende Zahlen ab 0.
integer3 actionPart.AltInt2 text (str) Name des Felds im Editor Für dieses Feld muss „useint3=true“ gesetzt sein.
control (int) Art des Felds:
  • 0: Zahlenfeld (mit Pfeilen)
  • 1: Zahlenfeld (mit Pfeilen)
  • 2: Kontrollkästchen
  • 3: Optionsfelder (Optionen aus der Tabelle options)
  • 4: Ausklappliste (Optionen aus der Tabelle options)
  • 5: Kompass zur Wahl einer Richtung
  • 6: Farbauswahl (liefert Hex-Farbcodes als Dezimalzahl)
min (int) Kleinster Wert des Zahlenfelds (nur bei „control=0“ oder „control=1“)
max (int) Größter Wert des Zahlenfelds (nur bei „control=0“ oder „control=1“)
val (int) Startwert
options (table) Die Optionen für Optionsfelder („control=3“) oder eine Ausklappliste („control=4“) als Tabelle von Texten. Sie bekommen automatisch fortlaufende Zahlen ab 0.
path actionPart.Path text (str) Name des Felds im Editor
use (bool) Auf true setzen, um das Feld zu aktivieren
filter (int) Art des Felds:
  • 0: Dialog zur Auswahl einer Bilddatei
  • 1: Dialog zur Auswahl einer Sounddatei
  • 2: Dialog zur Auswahl einer Videodatei
string actionPart.String text (str) Name des Felds im Editor Nutzt du dieses Feld zum Verknüpfen eines Objekts („use=4“ oder „use=5“), bekommst du einen Tupel-Text, den du in player.lua selbst in eine Verknüpfung umwandeln musst. Mit getObject(actionPart.String) holst du dir das Objekt.
use (int) Art des Felds:
  • 0: Feld nicht verwenden
  • 1: Textfeld
  • 2: mehrzeiliges Textfeld
  • 3: Skripteditor
  • 4: Auswahl eines Visionaire-Objekts aus der in stringfilter angegebenen Tabelle (Ausklappliste)
  • 5: Auswahl eines Visionaire-Objekts aus der in stringfilter angegebenen Tabelle (Dialogfenster)
link1filter (table) Die Visionaire-Tabellen, aus denen ein Objekt gewählt werden kann (für das Feld link1 mit „control=0“ oder „control=1“) Beispiele siehe unten
link2filter (table) Die Visionaire-Tabellen, aus denen ein Objekt gewählt werden kann (für das Feld link2 mit „control=0“ oder „control=1“) Beispiele siehe unten
stringfilter (table) Die Visionaire-Tabellen, aus denen ein Objekt gewählt werden kann (für das Feld string mit „use=4“ oder „use=5“) Beispiele siehe unten


Beispiele für Filter

Die Filter in link1filter, link2filter und stringfilter sind Tabellen von Texten, die wie folgt auf Visionaire-Tabellen verweisen. Ein Filter kann mehrere Tabellen enthalten, aber nur, wenn sie auf dieselbe Art von Objekten verweisen (siehe viertes Beispiel).

  • {'\\eScenes'}
  • {'\\eCharacters\\VCharacterOutfits\\eOutfits\\VOutfitTalkAnimations\\eAnimations'}
  • {'\\eCharacters\\VCharacterValues\\eValues'}
  • {'\\eScenes\\VSceneObjects\\eObjects', '\\eGame\\VGameItems\\eObjects'}