<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-l3"><aclass="reference internal"href="setup-tools.html#configure-mypy-to-find-the-mobase-stubs">3. Configure <codeclass="docutils literal notranslate"><spanclass="pre">mypy</span></code> to find the <codeclass="docutils literal notranslate"><spanclass="pre">mobase</span></code> stubs</a></li>
</ul>
</li>
<liclass="toctree-l2"><aclass="reference internal"href="setup-tools.html#testing-the-setup">Testing the setup</a></li>
</ul>
</li>
<liclass="toctree-l1"><aclass="reference internal"href="plugin-types.html">Type of Plugins</a><ul>
<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>
<h1>Writing Plugins<aclass="headerlink"href="#writing-plugins"title="Permalink to this headline">¶</a></h1>
<divclass="section"id="getting-started">
<h2>Getting started<aclass="headerlink"href="#getting-started"title="Permalink to this headline">¶</a></h2>
<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>
<divclass="section"id="single-file-plugins">
<spanid="single-file-plugin"></span><h3>Single file plugins<aclass="headerlink"href="#single-file-plugins"title="Permalink to this headline">¶</a></h3>
<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
create a Python module plugin.</p>
</div>
<divclass="section"id="module-plugins">
<spanid="module-plugin"></span><h3>Module Plugins<aclass="headerlink"href="#module-plugins"title="Permalink to this headline">¶</a></h3>
<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">import</span><spanclass="nn">mobase</span><spanclass="c1"># For type-checking createPlugin().</span>
<spanclass="kn">from</span><spanclass="nn">.plugin</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>
</div>
</div>
<divclass="section"id="writing-the-plugin">
<h2>Writing the plugin<aclass="headerlink"href="#writing-the-plugin"title="Permalink to this headline">¶</a></h2>
<divclass="section"id="iplugin-interface">
<h3><codeclass="docutils literal notranslate"><spanclass="pre">IPlugin</span></code> interface<aclass="headerlink"href="#iplugin-interface"title="Permalink to this headline">¶</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
need to extend a different class.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="k">class</span><spanclass="nc">MyTool</span><spanclass="p">(</span><spanclass="n">mobase</span><spanclass="o">.</span><spanclass="n">IPluginTool</span><spanclass="p">):</span><spanclass="c1"># Create a Tool plugin</span>
<spanclass="o">...</span>
<spanclass="k">class</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>
<spanclass="o">...</span>
</pre></div>
</div>
<p>Each plugin class has its own abstract methods that you need to implement but all the classes
also extend <codeclass="docutils literal notranslate"><spanclass="pre">IPlugin</span></code>, so you need to implement the methods from <aclass="reference internal"href="api/mobase.IPlugin.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="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="api/mobase.VersionInfo.html#mobase.VersionInfo"title="mobase.VersionInfo"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">VersionInfo</span></code></a> for
more details.</p></li>
<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="api/mobase.IOrganizer.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="api/mobase.IOrganizer.html#mobase.IOrganizer"title="mobase.IOrganizer"><codeclass="xref py py-class docutils literal notranslate"><spanclass="pre">IOrganizer</span></code></a> for more details.</p>
<h2>Examples<aclass="headerlink"href="#examples"title="Permalink to this headline">¶</a></h2>
<p>This section contains (links to) examples of MO2 Python plugins.
Some of these plugins have been created for educational purpose and are thus very detailed and
easy to understand or get started from.</p>
<divclass="section"id="tutorial-plugins">
<h3>Tutorial Plugins<aclass="headerlink"href="#tutorial-plugins"title="Permalink to this headline">¶</a></h3>
<p><aclass="reference external"href="https://github.com/Holt59/modorganizer-python_plugins">This repository</a> contains examples of Python
plugins that were written only to help users write their own plugins.
If you want to start somewhere, this is the place to go.</p>
</div>
<divclass="section"id="official-plugins">
<h3>Official Plugins<aclass="headerlink"href="#official-plugins"title="Permalink to this headline">¶</a></h3>
<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>
</dd>
</dl>
</li>
<li><dlclass="simple">
<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>
</dd>
</dl>
</li>
</ul>
</div>
<divclass="section"id="unofficial-plugins">
<h3>Unofficial Plugins<aclass="headerlink"href="#unofficial-plugins"title="Permalink to this headline">¶</a></h3>
<p>These plugins have been created by developpers for MO2 and are usually distributed on Nexus.</p>
<ulclass="simple">
<li><dlclass="simple">
<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>