Plugins
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). Note that you will not find these custom action parts in the action part selection dialog. They will only be added to the bottom of the action part list which is available after you added an action part (in its properties panel). So if you want to add one of the custom action parts to your action and you have the action part selection dialog pop up by default, select some random action part first and change its type afterwards.
Members of the Visionaire community shared some of the plugins they developed. You can download them from this wiki.
Install a plugin
- Get the plugin zip file (either download one or develop/create your own).
- In your project root folder (where the .ved/.veb is) add a folder called "plugins", if there isn't already one.
- Unzip the downloaded plugin file and copy the folder from it into the "plugins" folder.
- Open your project in Visionaire and click the jigsaw icon in the upper right.
- The list of available plugins opens up. Click "Install" next to the newly added entry.
- Save your project.
Develop a plugin
Thank you to users lehman and Chris_Dionous for providing details on how to create Visionaire Studio plugins. |
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
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:
- The number as well as the types of user input fields you can implement are limited.
- 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:
| |||
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:
| |||
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.
|
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:
| |||
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=2" or "use=3" for the Integers field. |
control (int) | Define the type of field to show:
| |||
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:
| |||
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:
| |||
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. For example, a string of "(4,1)" stands for a link to the scene with id=1 ("4" is the scenes table). |
use (int) | Define the type of field to show:
| |||
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'}