<liclass="toctree-l3"><aclass="reference internal"href="setup-tools.html#get-the-mobase-stubs">1. Get the <codeclass="docutils literal notranslate"><spanclass="pre">mobase</span></code> stubs</a></li>
<liclass="toctree-l3"><aclass="reference internal"href="setup-tools.html#configure-visual-studio-code-for-mobase">2. Configure Visual Studio Code for <codeclass="docutils literal notranslate"><spanclass="pre">mobase</span></code></a></li>
<liclass="toctree-l2"><aclass="reference internal"href="faq.html#why-is-mo2-throwing-an-exception-when-i-try-to-create-a-type-inheriting-one-of-mo2-class">1. Why is MO2 throwing an exception when I try to create a type inheriting one of MO2 class?</a></li>
<liclass="toctree-l2"><aclass="reference internal"href="faq.html#how-can-i-be-sure-to-implement-all-the-required-methods-when-creating-a-plugin">2. How can I be sure to implement all the required methods when creating a plugin?</a></li>
<liclass="toctree-l2"><aclass="reference internal"href="faq.html#why-are-my-isinstance-x-qobject-and-isinstance-y-qwidget-not-working">3. Why are my <codeclass="docutils literal notranslate"><spanclass="pre">isinstance(x,</span><spanclass="pre">QObject)</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">isinstance(y,</span><spanclass="pre">QWidget)</span></code> not working?</a></li>
<p>Now that you know which type of plugin you need, you can start writing your own plugin.
There is two way to write a Python plugin:</p>
<ulclass="simple">
<li><p><aclass="reference internal"href="#single-file-plugin"><spanclass="std std-ref">Single file plugins</span></a>: You use a single <codeclass="docutils literal notranslate"><spanclass="pre">.py</span></code> file that you put directly in the <codeclass="docutils literal notranslate"><spanclass="pre">plugins</span></code>
folder of the MO2 installation.</p></li>
<li><p><aclass="reference internal"href="#module-plugin"><spanclass="std std-ref">Module Plugins</span></a>: You create a Python package (folder) with a <codeclass="docutils literal notranslate"><spanclass="pre">__init__.py</span></code> file that you
put in the <codeclass="docutils literal notranslate"><spanclass="pre">plugins</span></code> folder of the MO2 installation.</p></li>
</ul>
<p>Most examples of plugins will be module plugins.</p>
<p>Prior to version 2.3, this was the only way of creating a Python plugin. You simply need
to create a <codeclass="docutils literal notranslate"><spanclass="pre">myplugin.py</span></code> file in the <codeclass="docutils literal notranslate"><spanclass="pre">plugins</span></code> folder of Mod Organizer 2 with a content
<p>We will see later on how to create the actual <codeclass="docutils literal notranslate"><spanclass="pre">MyPlugin</span></code> class.
The <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin</span></code> function is the function that is called by Mod Organizer 2 to instantiate
the plugin.</p>
<p>You can also provide multiple plugins by using <codeclass="docutils literal notranslate"><spanclass="pre">createPlugins</span></code> instead of <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin</span></code>:</p>
<p><strong>Note:</strong> If you provide neither <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin()</span></code> nor <codeclass="docutils literal notranslate"><spanclass="pre">createPlugins</span></code>, MO2 will display
an error message in the logs.</p>
<p><strong>Note:</strong> If you add a return type-hint to <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin()</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">createPlugins</span></code> (<codeclass="docutils literal notranslate"><spanclass="pre">-></span></code>), <codeclass="docutils literal notranslate"><spanclass="pre">mypy</span></code>
will type-check the function and warn you if one of your plugins is invalid, e.g. if you
forgot to implement a required method.</p>
<p>If you need to provide other files with your <codeclass="docutils literal notranslate"><spanclass="pre">.py</span></code> (assets or other Python files), you can
put them in the <codeclass="docutils literal notranslate"><spanclass="pre">plugins/data</span></code>, but this is deprecated since MO2 2.3, and you should instead
<p>Module plugins were introduced in MO2 2.3 and are shipped as whole folder containg a python module.
The minimum content of the folder is a <codeclass="docutils literal notranslate"><spanclass="pre">__init__.py</span></code> file with <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">createPlugins</span></code>
function.</p>
<p>A minimal module plugin could be as follows:</p>
<p>And in <codeclass="docutils literal notranslate"><spanclass="pre">__init__.py</span></code>, you should write <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin</span></code>:</p>
<spanclass="kn">from</span><spanclass="w"></span><spanclass="nn">.plugin</span><spanclass="w"></span><spanclass="kn">import</span><spanclass="n">MyPlugin</span><spanclass="c1"># Always use relative import:</span>
<p>Similar to single-file plugins, you can expose <codeclass="docutils literal notranslate"><spanclass="pre">createPlugins</span></code> instead of <codeclass="docutils literal notranslate"><spanclass="pre">createPlugin</span></code>
to instantiate multiple plugins.</p>
<p><strong>Note:</strong> The name of the folder does not have to be a valid python package, and you should
always use relative imports within the module (<codeclass="docutils literal notranslate"><spanclass="pre">import</span><spanclass="pre">.xxx</span></code>) instead of absolute ones.</p>
<h2>Writing the plugin<aclass="headerlink"href="#writing-the-plugin"title="Link to this heading"></a></h2>
<sectionid="iplugin-interface">
<h3><codeclass="docutils literal notranslate"><spanclass="pre">IPlugin</span></code> interface<aclass="headerlink"href="#iplugin-interface"title="Link to this heading"></a></h3>
<p>In the code snippets above, the <codeclass="docutils literal notranslate"><spanclass="pre">MyPlugin</span></code> class was not implemented.
Depending on the <aclass="reference internal"href="plugin-types.html#type-of-plugins"><spanclass="std std-ref">type of plugins</span></a> that you want to create, you will
<spanclass="k">class</span><spanclass="w"></span><spanclass="nc">MyPreview</span><spanclass="p">(</span><spanclass="n">mobase</span><spanclass="o">.</span><spanclass="n">IPluginPreview</span><spanclass="p">):</span><spanclass="c1"># Create a preview plugin</span>
also extend <codeclass="docutils literal notranslate"><spanclass="pre">IPlugin</span></code>, so you need to implement the methods from <aclass="reference internal"href="autoapi/mobase/index.html#mobase.IPlugin"title="mobase.IPlugin"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">IPlugin</span></code></a>:</p>
<spanclass="k">class</span><spanclass="w"></span><spanclass="nc">MyPlugin</span><spanclass="p">(</span><spanclass="o">...</span><spanclass="p">):</span><spanclass="c1"># The base class depends on the actual type of plugin</span>
<spanclass="nb">super</span><spanclass="p">()</span><spanclass="o">.</span><spanclass="fm">__init__</span><spanclass="p">()</span><spanclass="c1"># You need to call this manually.</span>
<spanclass="k">return</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">_tr</span><spanclass="p">(</span><spanclass="s2">"Gives a friendly greeting"</span><spanclass="p">)</span>
<spanclass="n">mobase</span><spanclass="o">.</span><spanclass="n">PluginSetting</span><spanclass="p">(</span><spanclass="s2">"enabled"</span><spanclass="p">,</span><spanclass="s2">"enable this plugin"</span><spanclass="p">,</span><spanclass="kc">True</span><spanclass="p">)</span>
<spanclass="p">]</span>
</pre></div>
</div>
<p>Most of these are pretty simple to understand:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">name</span></code>: Returns the name of the plugin. The name of the plugin is used to
fetch settings, and in many places, so this should not change between versions.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">author</span></code>: Returns the name of the plugin author (you!).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">description</span></code>: Returns the description of the plugin.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">version</span></code>: Returns the version of the plugin. See <aclass="reference internal"href="autoapi/mobase/index.html#mobase.VersionInfo"title="mobase.VersionInfo"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">VersionInfo</span></code></a> for
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">isActive</span></code>: Returns <codeclass="docutils literal notranslate"><spanclass="pre">True</span></code> if the plugin is active, <codeclass="docutils literal notranslate"><spanclass="pre">False</span></code> otherwise. This
usually returns <codeclass="docutils literal notranslate"><spanclass="pre">True</span></code>, unless you want to check for something to dynamically
enable the plugin. You can also use a plugin setting to allow users to disable
your plugins.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">settings</span></code>: Returns the list of settings (that user can modify) for this plugin.
Settings can be <codeclass="docutils literal notranslate"><spanclass="pre">int</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">bool</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> or list of <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code>. Here we indicate
that we have a “enabled” setting that user could use to disable the plugin (and
we use it in <codeclass="docutils literal notranslate"><spanclass="pre">isActive</span></code>).</p></li>
</ul>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">__init__</span></code> method is the normal Python constructor for our plugin, called when doing
You should always call <codeclass="docutils literal notranslate"><spanclass="pre">super().__init__()</span></code> explicitly when extending MO2 classes (due to
a “bug” in <codeclass="docutils literal notranslate"><spanclass="pre">boost.python</span></code>).</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">init</span></code> method is called by MO2 to initialize the plugin. The given argument, <codeclass="docutils literal notranslate"><spanclass="pre">organizer</span></code>,
is an instance of <aclass="reference internal"href="autoapi/mobase/index.html#mobase.IOrganizer"title="mobase.IOrganizer"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">IOrganizer</span></code></a> which is the class used to interface with MO2.
Here, we use it in the <codeclass="docutils literal notranslate"><spanclass="pre">isActive()</span></code> method to retrieve the “enabled” setting for our plugin.
See <aclass="reference internal"href="autoapi/mobase/index.html#mobase.IOrganizer"title="mobase.IOrganizer"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">IOrganizer</span></code></a> for more details.</p>
<p>These plugins are (or will be) included in MO2 releases and are usually maintain by some members of
the MO2 development teams.
These plugins are not as well documented as the ones in the repository above.</p>
<ulclass="simple">
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/ModOrganizer2/modorganizer-basic_games">Basic Games</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginGame</span></code>]</dt><dd><p>This is the meta-plugin for “basic” games. It is a complex
plugins and should mostly be investigated if you want to add a game to it.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/ModOrganizer2/modorganizer-fnistool">FNIS Tool</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginTool</span></code>]:</dt><dd><p>Plugin to integrate FNIS into MO2.</p>
<dt><aclass="reference external"href="https://github.com/ModOrganizer2/modorganizer-preview_dds">Preview DDS</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginPreview</span></code>]:</dt><dd><p>Plugin to preview DDS files. Quite complex due to the use
of OpenGL for display.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/ModOrganizer2/modorganizer-form43_checker">Form 43 Checker</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginDiagnose</span></code>]:</dt><dd><p>Plugin that warn users if there are form 43 ESPs (Skyrim ESPs)
enabled when managing a Skyrim SE instance.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/ModOrganizer2/modorganizer-tool_configurator">Tool Configurator</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginTool</span></code>]:</dt><dd><p>Plugin that allows easier modifications of game settings.
Mostly contains a complex GUI for managing INI files.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/ModOrganizer2/modorganizer-script_extender_plugin_checker">Script Extender Plugin Checker</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginDiagnose</span></code>]:</dt><dd><p>Plugin that checks Script Extender logs to see
if some plugins have failed to load and display information to the user if possible.</p>
<dt><aclass="reference external"href="https://github.com/deorder/mo2-plugins">Merge Plugins Hide</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginTool</span></code>]:</dt><dd><p>Hide / unhide plugins that were merged using <codeclass="docutils literal notranslate"><spanclass="pre">Merge</span><spanclass="pre">Plugins</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">zMerge</span></code>.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/AnyOldName3/ModOrganizer-to-OpenMW">OpenMW Exporter</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginTool</span></code>]:</dt><dd><p>A Mod Organizer plugin to export your VFS, plugin selection and load order to OpenMW.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/AnyOldName3/modorganizer-orphaned_script_extender_save_deleter">Orphaned Script Extender Save Deleter</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginTool</span></code>]:</dt><dd><p>Mod Organizer plugin to delete orphaned script extender co-saves.</p>
</dd>
</dl>
</li>
<li><dlclass="simple">
<dt><aclass="reference external"href="https://github.com/deorder/mo2-plugins">Sync Mod Order</a> [<codeclass="docutils literal notranslate"><spanclass="pre">IPluginTool</span></code>]:</dt><dd><p>Synchronize mod order from current profile to another while keeping the (enabled/disabled) state intact.</p>
</dd>
</dl>
</li>
</ul>
<p><em>Feel free to open an issue or a pull-request if you want to add your own plugin to the list.</em></p>
<p>Mod Organizer uses Qt translation system, so you need to adapt your plugin code to provide
translation strings.
To do this, you need two things:</p>
<olclass="arabic simple">
<li><p>In every class containing strings you need to translate, you must add a <codeclass="docutils literal notranslate"><spanclass="pre">__tr</span></code> function
that takes a <codeclass="docutils literal notranslate"><spanclass="pre">str</span></code> input and call <cite>QApplication.translate</cite> on it (see example below).</p></li>
<li><p>You need to wrap all translatable strings in a call to <codeclass="docutils literal notranslate"><spanclass="pre">self.__str("My</span><spanclass="pre">String")</span></code> (see
<p>Once your code is updated, you need to generate the Qt translation file <codeclass="docutils literal notranslate"><spanclass="pre">.ts</span></code>.
You can use <codeclass="docutils literal notranslate"><spanclass="pre">PyQt5.lupdate_main</span></code> for this:</p>
<p>You should generate a single translation file for your whole plugin even if it contains
multiple files by passing all Python file and Qt UI (<codeclass="docutils literal notranslate"><spanclass="pre">.ui</span></code>) file to the command above.</p>
<p>Now that you have the original <codeclass="docutils literal notranslate"><spanclass="pre">.ts</span></code> file, you need to translate it in order to obtain
translation files for other languages.
To do so, you can use online services such as <aclass="reference external"href="https://www.transifex.com">Transifex</a> or
<p>Once you have obtained translation files for another language, e.g. French, you need to
compile it into a <codeclass="docutils literal notranslate"><spanclass="pre">.qm</span></code> file and then ship it.</p>
<ulclass="simple">
<li><p>If you are using a single Python file plugin <codeclass="docutils literal notranslate"><spanclass="pre">myplugin.py</span></code>, the name of the compiled
translation must be <codeclass="docutils literal notranslate"><spanclass="pre">myplugin_fr.qm</span></code>.</p></li>
<li><p>If you are shipping a module <codeclass="docutils literal notranslate"><spanclass="pre">mymoduleplugin</span></code>, the name of the compiled translation
must be <codeclass="docutils literal notranslate"><spanclass="pre">mymoduleplugin</span></code>.</p></li>