Skip to content

Plugin Creation Tips

EQAditu edited this page Mar 29, 2022 · 5 revisions

Plugin Creation Tips

Plugins for ACT are normal .NET Framework(4.x) assemblies. They can either be pre-compiled (*.dll / *.exe), or ACT can compile plugin source code on-the-fly (*.cs / *.vb).

To be loaded by ACT, they must implement the plugin interface Advanced_Combat_Tracker.IActPluginV1. This interface consists of a main entry point, and a exit method to dispose resources in.

To create plugins I suggest you use an IDE like Visual Studio. Microsoft supplies, free of charge, Community versions of their Visual Studio suites. The only caveat is that you must link it to a Microsoft account so that it can activate/maintain the free license.

Documentation on ACT's API can be found here(archive). This contains the API in HTML format, and XML format. The HTML format should be obvious, the XML format can be specially used inside of IDEs to describe objects as you use them. Place the Advanced Combat Tracker.XML file with the ACT EXE file reference and Visual Studio will use it automatically.

Creating a new plugin

Once in the IDE, create a new project. A class library template is probably your best bet. Name the project whatever you want... it probably won't show up anywhere within ACT, but something identifiable to yourself would be good. Although when the plugin causes exceptions within ACT the Namespace and Class name will be shown. The new project creates ClassLibrary1.Class1, so you can go ahead and rename those things now if you wish. VS comes with handy abilities to rename objects without breaking references if you right-click them.

The first thing you will want to do is add ACT as an assembly reference. In the Solution Explorer, right-click References and Add Reference... browse to where ACT, and hopefully the documentation XML, and select "Advanced Combat Tracker.exe". This will allow you access to the Advanced_Combat_Tracker namespace. You can add a using Advanced_Combat_Tracker; line to the top of the file to make typing easier.

As said previously, you must implement the interface IActPluginV1. This is done by adding a colon after your class's name and typing out the interface name. When the IDE recognizes the interface it will make a box appear to allow you to automatically create the interface member stubs within your class. (Shift-Alt-F10 or Ctrl-. will open the option box)

Once these methods are created, the plugin is technically ready for use, however it won't do anything. Creating plugin contents should be another post.

Each plugin should have only one class that implements this interface. When ACT scans the plugin, it will use one implementing class it finds and ignores the rest.

Adding references not included by ACT

As previously mentioned, ACT plugins can come in two forms: DLLs and source files. If you make a *.dll plugin, no special considerations have to be made. If you make a source file plugin, you may find yourself needing to put everything in one file, or make special assembly references. For the case of assembly references, ACT can parse special comment tags at the beginning of the source file to add as references.

// reference:System.dll

This will add System.dll to the references from the Global Assembly Cache(GAC). If your reference is not in the GAC, you may need to supply a relative(from ACT) or absolute path. Assembly attributes will also be parsed from the source file to be shown in the plugin info panel when ACT loads them. You can see examples of them in the AssemblyInfo.cs file created in your project's Properties folder.

[assembly: AssemblyTitle("Sample Plugin")]
[assembly: AssemblyDescription("A sample of an ACT plugin that is a UserControl and uses a settings file")]
[assembly: AssemblyCompany("EQAditu")]
[assembly: AssemblyVersion("")]

If your referenced assembly is not in the GAC, you may have to do some extra work. You may find it easy to just put your referenced assembly in ACT's program folder but this is strongly discouraged as it can break other plugins looking for newer versions of common assemblies. The cleaner method is to subscribe to the AppDomain.AssemblyResolve event. This event will fire any time a plugin references an assembly that ACT or another plugin has not yet loaded. But be warned... if your plugin has a class-scope reference to the assembly, the event will fire before you can subscribe to it. To avoid this scenario, only use the referenced assemblies in inner-scopes such as sub-classes or methods. (not as class direct members)

How to debug plugin source using Visual Studio

The problem is that you cannot "start" a plugin within the IDE in order to debug it. The plugin must be loaded by ACT. Put those two together... you must have the IDE start ACT so that the plugin is executed within the IDE.

To enable this, go to the Properties of your project. In the Debug tab, select the Start action "Start external program" and browse to the copy of Advanced Combat Tracker you're referencing. Save the changes, and now when you run the project, Advanced Combat Tracker will start. Important: Visual Studio may no longer automatically compile your project when starting ACT... This is because your assembly is not depended upon by ACT to run. Make sure to compile your plugin before starting debugging.

Initially, there will be nothing to debug. You must go into the Plugins tab and enable your plugin. The easiest way is to add the DLL file that your project compiles. The Output window in Visual Studio should mention symbols being loaded and your breakpoints can be hit. If you point ACT at your source-code file as a plugin, understand that ACT will optimize the assembly it creates so that debugging will be more difficult. Visual Studio may also refuse to hit breakpoints or acknowledge that your source matches the assembly loaded in ACT if "Just My Code" is enabled in Visual Studio.

Thread Safety

One word of warning for creating plugins with GUIs. Most of the events that come from ACT will not come from a UI thread, therefore it is not safe to modify Windows.Forms.Controls within the event handler. It is not always disastrous to do so, but can occasionally stop rendering of that control until restart. Perhaps even cause an application crash.


Changing this boolean to true will cause all cross thread calls to raise an exception. By default this is off within ACT, but you can temporarily turn it on to test your plugin code. There is probably no code in ACT that still is written around this, but be aware it might affect ACT or other plugins.

ACT has a collection of static helper methods in the ThreadInvokes class. This is a throwback to when the C# language did not make it very easy to create an inline Form.Invoke(). But the helpers will detect if the Invoke is required before using that more expensive path.

void oFormActMain_AfterCombatAction(bool isImport, CombatActionEventArgs actionInfo)
		ActGlobals.oFormActMain.Invoke(new Action(() => { lblStatus.Text = "Hello world" }));
		// Faster if invoke is not needed
		lblStatus.Text = "Hello world";

	// OR (internally checks if invoke is required)
	ThreadInvokes.ControlSetText(ActGlobals.oFormActMain, lblStatus, "Hello world");

Demo sample

I added a download of a good starting point for creating a new ACT plugin. The plugin is an instance of a UserControl and saves a settings file. (Browse source)

Since it is a UserControl, you can double-click the .cs file in Visual Studio and change the UI in the designer. It comes with one sample TextBox that is saved to a configuration file... just use it as an example on how to add other controls to the XML settings file.

The *.csproj file comes pre-configured to start ACT as the debugging process as described above but only if ACT is in the default install location. If it is not, edit the project as described above. To make things easier, remember to copy the Advanced Combat Tracker.XML file to ACT's folder so that Visual Studio will load the Intellisense documentation. (As described earlier)

The sample .cs file can be distributed as-is. As long as Visual Studio does not force any long strings into a .resx file, the .cs file has no dependencies and can be loaded directly as a plugin instead of compiling to a DLL.