Plugins

From The Official Visionaire Studio: Adventure Game Engine Wiki
Plugin25n.png

Visionaire Studio features a plugin system which lets you develop your own custom action parts.

Plugins get installed per project, so when starting a new project you have to install plugins you wish to use (again), even if you used them before in another project. Open the plugin section through the jigsaw icon in the toolbar to see all plugins currently installed or ready to get installed. You can uninstall them here, too, of course.

Once you have installed a plugin you are ready to use the newly added action part(s). You will find these custom action parts in the "Custom" section of the action part selection dialog and at the the bottom of the action part list in the action part properties panel.

Members of the Visionaire community shared some of the plugins they developed. You can download them from this wiki.


Install a plugin

  1. Get the plugin zip file (either download one or develop/create your own).
  2. In your project root folder (where the .ved/.veb is) add a folder called "plugins", if there isn't already one.
  3. Unzip the downloaded plugin file and copy the folder from it into the "plugins" folder.
  4. Open your project in Visionaire and click the jigsaw icon in the upper right.
  5. The list of available plugins opens up. Click "Install" next to the newly added entry.
  6. Save your project.


Develop a plugin

Thank you to users lehman and Chris_Dionous for providing details on how to create Visionaire Studio plugins.
Plugin file structure

Each plugin consists of a folder containing up to four files, usually stored in a ZIP archive (see image). The user will unzip the archive by himself upon installation and copy the folder to the "plugins" directory (see installation guide above). You are free to add more files to the folder, e. g. a README or even resource files you wish to make use of, but the following files – except for the optional image – are required by Visionaire:

  • Folder Name the folder according to your plugin (as specified in the config.ini file).
  • config.ini The INI file tells the engine (and the user) what your plugin is all about.
  • editor.lua This Lua file sets up the action part controls for the Visionaire editor.
  • image.png You can optionally add a 128 x 128 px PNG image to represent your plugin in the editor's plugin section.
  • player.lua This Lua file contains the code to run when the action part(s) get(s) executed.


config.ini

This is an example INI file taken from the "Hello World" plugin linked below. It contains all necessary properties:

# 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.
  • Specify the Name of the plugin. This name has to match the name of the plugin folder.
  • Add your own name as Author and enter the Date of creation/release (the date format is up to you).
  • Add the Version number of your plugin.
  • The PluginVersion refers to what kind of plugin this is. It needs to be set to "1" as this is currently the only one available in Visionaire Studio.
  • You may add a Link to your own website.
  • Define the ActionParts your plugin provides (seperated by comma). In the example above, only one action part called "Print Hello World" is added, but it is possible to register multiple action parts through the same plugin. The name of each action part has to match the name used in editor.lua and player.lua. It is also the name that will appear in the editor.
  • You may add a Description to tell the user what your plugin does.


The basics: "Hello, World!"

Download the "Hello World" plugin

After setting up the INI file you have to register the new action part for the editor and for the player.

In the editor.lua file, the registerActionPart() function takes two arguments. The first one is the action part name as defined in the config.ini file under "ActionParts". The second argument is a table of options. These options define the control inputs for that action part in the editor. Since our "Hello World" example does not offer any input to the user, all the options are basically empty – but make sure to always pass the complete table to avoid any misconfigurations. The individual options are described later.

-- 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 the player.lua file, the registerActionPart() function also takes two arguments. The first one is again the action part name. The second argument is the callback function which runs when the action part gets executed during the game. It receives two parameters:

  • "activeAction" is the action to which the action part belongs,
  • "actionPart" is the action part itself, containing all the options the user chose in the editor when setting up the action part.


Note that the function must return a boolean value, usually false when it's done. If you return true, the action part will repeat forever.

-- player.lua

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


Beyond the basics: Some good practices

Download the "Log Me" plugin

Action part text & Translation

Custom action part

By default, the action part name is not only used to identify the part in the list of action parts in the editor, but also in the stack of action parts inside an action. You can define these two names separately though. It is even possible to include the user inputs in the stack text through parameters. See the image for an example: The name of the action part is "Log string", but in the action part stack it appears as "Print '___' to the log" – with the user input "Hello, World!" added to it.

That additional action part text is added through the translation feature in the editor.lua file. It is good practice to make your plugin ready for translation anyway, especially if you plan on releasing it to the public (remember that the Visionaire editor is available in seven different languages). So while in our first example we added the action part name ("Print Hello World") directly to the config.ini and to the functions, we now add a placeholder variable ("LOG_STRING") instead.

-- 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")


The translation() function is then used to add the actual text to that variable, with the first argument being the language code: 1: German | 2: English | 3: Spanish | 4: French | 5: Dutch | 6: Italian | 7: Russian. If we add the suffix "_Name" to the action part name variable, we can define the text for the action part stack.

In the example we use the "string" option from the options table to provide a text input field for the user. We named that field "LOG_TEXT" – another placeholder which gets translated. In the action part stack text we add the parameter "%string" to where that string input should be inserted ("Print '%string' to the log").


Add multiple action parts

If you have downloaded the "Log Me" plugin, you will notice that it adds not only one but two custom action parts: LOG_TIME and LOG_STRING. The editor.lua file above only shows one of them; additional action parts are added by simply inserting more registerActionPart() function calls. All action parts have to be defined in the config.ini file, too. Make sure to separate them by comma without adding any space character:

# config.ini

ActionParts=LOG_TIME,LOG_STRING


As for the player.lua file, it is good practice to put the actual action part code into a separate function instead of adding it directly inside the callback function.

While the "LOG_TIME" function does not receive any input from the user, the "LOG_STRING" function gets the string the user can enter. It can be accessed through the "actionPart" object. Note that the "String" property begins with a capital "S" here.

-- 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
)


Available editor controls/fields

There are two drawbacks when developing a Visionaire plugin:

  1. The number as well as the types of user input fields you can implement are limited.
  2. The available fields are not consistently named and structured. This is due to the fact that the Visionaire data model has been tweaked and expanded over time to allow for usage it wasn't originally designed for.


The following table lists all available fields and how to define them in the editor.lua options. Note that some fields are named differently when passed to the player.lua file, e. g. "link2" becomes "actionPart.AltLink".

Field name Corresponds to Properties Usage Notes
isif (bool) This field is currently not supported, but please keep it.
link1 actionPart.Link text (str) Field name in the editor
use (bool) Set to true to enable that field
control (int) Define the type of field to show:
  • 0: Lets the user select a Visionaire object from the table defined in link1filter (dialog popup)
  • 1: Lets the user select a Visionaire object from the table defined in link1filter (dropdown list)
  • 2: Multi-language text field
link2 actionPart.AltLink text (str) Field name in the editor
use (bool) Set to true to enable that field
control (int) Define the type of field to show:
  • 0: Lets the user select a Visionaire object from the table defined in link2filter (dialog popup)
  • 1: Lets the user select a Visionaire object from the table defined in link2filter (dropdown list)
  • 2: Multi-language text field
integers actionPart.Int (x)

actionPart.AltInt (y)

use (int) This either defines how many of the following integer fields to use – or it turns the integers field into a position picker.
  • 0: Don't use any integer fields (except Integer3 which is independently activated through useint3)
  • 1: Show a position picker
  • 2: Use the integer1 field only
  • 3: Use the integer1 and the integer2 field
If you use this field as a position picker ("use=1"), the x and y coordinates are passed over as two separate values Int and AltInt.
useint3 (bool) Set to true to use the integer3 field
pointlabel (str) Field name of the position picker (only applicable if "use=1")
pointdialog (int) seems deprecated
integer1 actionPart.Int text (str) Field name in the editor If you want to use this field, you have to set "use=2" or "use=3" for the Integers field.
control (int) Define the type of field to show:
  • 0: Number field (spinner)
  • 1: Number field (spinner)
  • 2: Checkbox
  • 3: Radio buttons (options defined in the options table)
  • 4: Dropdown list (options defined in the options table)
  • 5: Compass widget to choose a direction
  • 6: Decibel (dB) widget for audio
min (int) Minimum value for the number field (only applicable if "control=0" or "control=1")
max (int) Maximum value for the number field (only applicable if "control=0" or "control=1")
val (int) Initial value
options (table) Defines the options for radio buttons ("control=3") or a dropdown list ("control=4"). Add a table of strings which represent the different options. They will have consecutive integer values assigned to them automatically, starting with 0.
integer2 actionPart.AltInt text (str) Field name in the editor If you want to use this field, you have to set "use=3" for the Integers field.
control (int) Define the type of field to show:
  • 0: Number field (spinner)
  • 1: Number field (spinner)
  • 2: Checkbox
  • 3: Radio buttons (options defined in the options table)
  • 4: Dropdown list (options defined in the options table)
  • 5: Compass widget to choose a direction
min (int) Minimum value for the number field (only applicable if "control=0" or "control=1")
max (int) Maximum value for the number field (only applicable if "control=0" or "control=1")
val (int) Initial value
options (table) Defines the options for radio buttons ("control=3") or a dropdown list ("control=4"). Add a table of strings which represent the different options. They will have consecutive integer values assigned to them automatically, starting with 0.
integer3 actionPart.AltInt2 text (str) Field name in the editor If you want to use this field, you have to set "useint3=true" for the Integers field.
control (int) Define the type of field to show:
  • 0: Number field (spinner)
  • 1: Number field (spinner)
  • 2: Checkbox
  • 3: Radio buttons (options defined in the options table)
  • 4: Dropdown list (options defined in the options table)
  • 5: Compass widget to choose a direction
  • 6: Color picker (returns hex color codes as decimal values)
min (int) Minimum value for the number field (only applicable if "control=0" or "control=1")
max (int) Maximum value for the number field (only applicable if "control=0" or "control=1")
val (int) Initial value
options (table) Defines the options for radio buttons ("control=3") or a dropdown list ("control=4"). Add a table of strings which represent the different options. They will have consecutive integer values assigned to them automatically, starting with 0.
path actionPart.Path text (str) Field name in the editor
use (bool) Set to true to enable that field
filter (int) Define the type of field to show:
  • 0: Dialog to choose an image file
  • 1: Dialog to choose a sound file
  • 2: Dialog to choose a video file
string actionPart.String text (str) Field name in the editor If you use this field for linking an object ("use=4" or "use=5"), be aware that you'll get a tuple string you have to convert into a link in player.lua by yourself. Use getObject(actionPart.String) to get the object.
use (int) Define the type of field to show:
  • 0: Don't use that field
  • 1: Text field
  • 2: Multiline text field
  • 3: Script editor
  • 4: Lets the user select a Visionaire object from the table defined in stringfilter (dropdown list)
  • 5: Lets the user select a Visionaire object from the table defined in stringfilter (dialog popup)
link1filter (table) Defines the Visionaire tables from which the user can choose an object (for Link1 field with "control=0" or "control=1") Find some examples below
link2filter (table) Defines the Visionaire tables from which the user can choose an object (for Link2 field with "control=0" or "control=1") Find some examples below
stringfilter (table) Defines the Visionaire tables from which the user can choose an object (for String field with "use=4" or "use=5") Find some examples below


Filter examples

The filters defined in link1filter, link2filter, and stringfilter are tables of strings that reference Visionaire tables as follows. It is possible to add more than one table to a filter, but only if they reference the same type of objects (see fourth example).

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