Hallo, das hier soll eine Anleitung sein, wie man Plugins für AntMe! erstellt. Auch die 2D- und 3D-Visualisierungen sind Plugins. Man kann solche Darstellungen der Simulation als Plugin schreiben, aber auch statistische Auswertungen können als Plugin AntMe! hinzugefügt werden.
Zum Pluginkonzept:
Plugins sind dazu gedacht, bestimmte Programme beliebig erweitern zu können. Dafür muss es bestimmte Regeln für alle Plugins eines Programms geben, damit das Programm mit den Plugins kommunizieren kann. Diese Regeln werden durch ein Interface bestimmt. Jedes Plugin muss dieses Interface erben, sonst erkennt das Programm es nicht. Auch bei AntMe! gibt es dieses Interface. Es heißt IPlugin und findet sich im Projekt SharedComponents. Außerdem gibt es noch die Interfaces IConsumerPlugin und IProducerPlugin, die aber beide von IPlugin erben. Für die Visualisierungen wurde das Interface IConsumerPlugin benutzt, die ich auch hier verwenden werde.
Verweis zu SharedComponents
Um ein Plugin für AntMe! zu schreiben, muss man einfach ein neues, leeres Projekt erstellen. Dann ist ganz wichtig, in den Eigenschaften des Projekts das Zielframework auf .NET Framework 2.0 zu stellen, sonst ist es nicht mit AntMe! kompatibel. Außerdem sollte der Ausgabetyp eine Klassenbibliotek sein, da die Anwendung keinen Einstiegspunkt hat und nicht ausführbar sein muss. Jetzt muss man noch einen Verweis zu SharedComponents erzeugen. Dazu klickt man im Projektmappen-Explorer mit der rechten Maustaste auf Verweise und wählt Verweis hinzufügen. Unter dem Reiter Durchsuchen sucht man nach der Datei AntMe.SharedComponents.dll, die im Ordner bin im AntMe!-Verzeichnis liegt. Diese Datei wählt man aus und schon hat man einen Verweis zu den SharedComponents von AntMe!.
Die Klasse Plugin
Um die Schnittstelle IConsumerPlugin auch benutzen zu können, muss man eine neue Klasse erstellen. Also rechtsklick auf das Projekt im Explorer, Hinzufügen -> Klasse und dann als Namen Plugin.cs wählen. Die Klasse muss public sein und soll von dem Interface IConsumerPlugin erben. Außerdem muss man noch die SharedComponents in die Klasse einbinden. Das Dokument muss also etwa so aussehen:
[cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AntMe.SharedComponents.Plugin;
namespace MyPlugin
{
public class Plugin : IConsumerPlugin
{
}
}
[/cs]
Die Schnittstelle implementieren
Die Schnittstelle können wir jetzt einfach implementieren, indem wir den Mauszeiger über IConsumerPlugin halten und auf den Tooltip-Text IConsumerPlugin-Schnittstelle implementieren klicken. Dann werden alle Methodenstubs generiert, die die Schnittstelle fordert, und das sind ganz schön viele. Es wird jetzt noch einen Fehler geben, da eine der Eigenschaften die System.Windows.Forms braucht. Wir müssen also unter Verweis hinzufügen und dann im Reiter .NET System.Windows.Forms auswählen, dann klappt es.
Jetzt wird es aber erst richtig interessant. Die Methoden werfen im Moment alle noch NotImplementedExceptions, aber das wird sich bald ändern.
Die Methoden deklarieren
Erstmal sollte man alle Ausnahme rauslöschen; die stören nur und niemand braucht sie im Moment. Die Datei sollte dann etwa so aussehen:
[cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AntMe.SharedComponents.Plugin;
namespace MyPlugin
{
public class Plugin : IConsumerPlugin
{
public void CreateState(ref AntMe.SharedComponents.States.SimulationState state)
{
}
public void CreatedState(ref AntMe.SharedComponents.States.SimulationState state)
{
}
public void CreatingState(ref AntMe.SharedComponents.States.SimulationState state)
{
}
public bool Interrupt
{
get { }
}
public System.Windows.Forms.Control Control
{
get { }
}
public string Description
{
get { }
}
public Guid Guid
{
get { }
}
public string Name
{
get { }
}
public void Pause()
{
}
public void SetVisibility(bool visible)
{
}
public byte[] Settings
{
get
{
}
set
{
}
}
public void Start()
{
}
public void StartupParameter(string[] parameter)
{
}
public PluginState State
{
get { }
}
public void Stop()
{
}
public void UpdateUI(AntMe.SharedComponents.States.SimulationState state)
{
}
public Version Version
{
get { }
}
}
}
[/cs]
Zunächst brauchen wir ein paar grundsätzliche Dinge wie z.B. den Namen oder die Beschreibung des Plugins.
[cs]
private readonly string name = "Tutorial-Plugin"; // Der Name des Plugins
private readonly string description = "Dies ist ein Testplugin"; // Eine Beschreibung des Plugins
private readonly Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; // Die Version des Plugins
private readonly Guid guid = new Guid("BBBD7C7A-FD3A-4656-B6DC-6A88463B2816"); // Die GUID, eine eindeutige Nummer im ganzen Programm, die aber mehr oder weniger zufällig gewählt werden kann.
private PluginState pluginState = PluginState.Ready; // Der Status des Plugins
[/cs]
Diese privaten Variablen verwenden wir in den vorgegebenen Eigenschaften:
[cs]
public string Name
{
get { return name; }
}
public string Description
{
get { return description; }
}
public Version Version
{
get { return version; }
}
public Guid Guid
{
get { return guid; }
}
public PluginState State
{
get { return pluginState; }
}
[/cs]
Bei den übrigen Eigenschaften geben wir null oder false zurück:
[cs]
public bool Interrupt // Gibt an, ob die Anwendung unterbrochen werden soll.
{
get { return false; }
}
public System.Windows.Forms.Control Control // Gibt ein Control zurück, das im Hauptprogramm angezeigt wird.
{
get { return null; }
}
public byte[] Settings // Die Settings des Plugins
{
get
{
return new byte[] { }; // Just no settings
}
set
{
}
}
[/cs]
In den drei Methoden Start, Stop und Pause ändern wir den PluginStatus:
[cs]
public void Start()
{
pluginState = PluginState.Running;
}
public void Stop()
{
pluginState = PluginState.Ready;
}
public void Pause()
{
pluginState = PluginState.Paused;
}
[/cs]
Jetzt fehlt vorallem noch die Methode UpdateUI, mit der wir die Informationen der Simulation bekommen.
Auf die Simulation reagieren
Damit wir auch mit dem Benutzer kommunizieren können, müssen wir noch ein Dialogfenster programmieren. Wir fügen dem Projekt also ein Windows Form hinzu (rechtsklick aufs Projekt im Explorer, Hinzufügen -> Windows Forms) und nennen es z.B. Window.cs. In dieses Form ziehen wir ein Label und nennen es lblRound.
In den Code des Forms schreiben wir folgende Methode. Dafür müssen wir ganz oben noch using AntMe.SharedComponents.States; einfügen.
[cs]
public void ShowRound(SimulationState state)
{
lblRound.Text = state.CurrentRound.ToString();
}
[/cs]
Die können wir in der Klasse Plugin benutzen. Wir müssen zuerst eine Variable window definieren und im Konstruktor aufrufen. Das Form öffnen wir in der Methode Start und in Stop schließen wir es.
[cs]
private Window window;
public Plugin()
{
window = new Window();
}
public void Start()
{
pluginState = PluginState.Running;
window.Show();
}
public void Stop()
{
pluginState = PluginState.Ready;
window.Hide();
}
[/cs]
Jetzt kommt die Methode UpdateUI zum Zuge. In ihr benutzen wir die Methode ShowRound.
[cs]
public void UpdateUI(AntMe.SharedComponents.States.SimulationState state)
{
window.ShowRound(state);
}
[/cs]
Wenn wir das Plugin jetzt benutzen wollen, müssen wir nur die Datei erstellen (F6) und dann im Ordner bin -> Release die Datei [Projektname].dll. Diese Datei kann man im AntMe!-Programm einbinden, wenn man unter Einstellungen -> Plugins auf Plugin hinzufügen klickt und dann die Datei auswählt. Die meisten Fehler treten erst hier auf, also dann bitte hier posten!
Im Anhang findet ihr eine DLL, die das Plugin enthält. Ihr könnt sie euch runterladen und genau so wie oben beschrieben, benutzen.
Somit haben wir ein einfaches Plugin geschaffen, das uns zumindest immer die aktuelle Rundenzahl anzeigt. Dieses Tutorial soll natürlich nur beispielhaft veranschaulichen, wie man ein Plugin programmiert. Es geht noch vieles mehr. Man denke nur an die Visualisierungs-Plugins, die bei AntMe! schon dabei sind...
EDIT: Das Plugin gibts jetzt direkt als DLL.
Zum Pluginkonzept:
Plugins sind dazu gedacht, bestimmte Programme beliebig erweitern zu können. Dafür muss es bestimmte Regeln für alle Plugins eines Programms geben, damit das Programm mit den Plugins kommunizieren kann. Diese Regeln werden durch ein Interface bestimmt. Jedes Plugin muss dieses Interface erben, sonst erkennt das Programm es nicht. Auch bei AntMe! gibt es dieses Interface. Es heißt IPlugin und findet sich im Projekt SharedComponents. Außerdem gibt es noch die Interfaces IConsumerPlugin und IProducerPlugin, die aber beide von IPlugin erben. Für die Visualisierungen wurde das Interface IConsumerPlugin benutzt, die ich auch hier verwenden werde.
Verweis zu SharedComponents
Um ein Plugin für AntMe! zu schreiben, muss man einfach ein neues, leeres Projekt erstellen. Dann ist ganz wichtig, in den Eigenschaften des Projekts das Zielframework auf .NET Framework 2.0 zu stellen, sonst ist es nicht mit AntMe! kompatibel. Außerdem sollte der Ausgabetyp eine Klassenbibliotek sein, da die Anwendung keinen Einstiegspunkt hat und nicht ausführbar sein muss. Jetzt muss man noch einen Verweis zu SharedComponents erzeugen. Dazu klickt man im Projektmappen-Explorer mit der rechten Maustaste auf Verweise und wählt Verweis hinzufügen. Unter dem Reiter Durchsuchen sucht man nach der Datei AntMe.SharedComponents.dll, die im Ordner bin im AntMe!-Verzeichnis liegt. Diese Datei wählt man aus und schon hat man einen Verweis zu den SharedComponents von AntMe!.
Die Klasse Plugin
Um die Schnittstelle IConsumerPlugin auch benutzen zu können, muss man eine neue Klasse erstellen. Also rechtsklick auf das Projekt im Explorer, Hinzufügen -> Klasse und dann als Namen Plugin.cs wählen. Die Klasse muss public sein und soll von dem Interface IConsumerPlugin erben. Außerdem muss man noch die SharedComponents in die Klasse einbinden. Das Dokument muss also etwa so aussehen:
[cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AntMe.SharedComponents.Plugin;
namespace MyPlugin
{
public class Plugin : IConsumerPlugin
{
}
}
[/cs]
Die Schnittstelle implementieren
Die Schnittstelle können wir jetzt einfach implementieren, indem wir den Mauszeiger über IConsumerPlugin halten und auf den Tooltip-Text IConsumerPlugin-Schnittstelle implementieren klicken. Dann werden alle Methodenstubs generiert, die die Schnittstelle fordert, und das sind ganz schön viele. Es wird jetzt noch einen Fehler geben, da eine der Eigenschaften die System.Windows.Forms braucht. Wir müssen also unter Verweis hinzufügen und dann im Reiter .NET System.Windows.Forms auswählen, dann klappt es.
Jetzt wird es aber erst richtig interessant. Die Methoden werfen im Moment alle noch NotImplementedExceptions, aber das wird sich bald ändern.
Die Methoden deklarieren
Erstmal sollte man alle Ausnahme rauslöschen; die stören nur und niemand braucht sie im Moment. Die Datei sollte dann etwa so aussehen:
[cs]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AntMe.SharedComponents.Plugin;
namespace MyPlugin
{
public class Plugin : IConsumerPlugin
{
public void CreateState(ref AntMe.SharedComponents.States.SimulationState state)
{
}
public void CreatedState(ref AntMe.SharedComponents.States.SimulationState state)
{
}
public void CreatingState(ref AntMe.SharedComponents.States.SimulationState state)
{
}
public bool Interrupt
{
get { }
}
public System.Windows.Forms.Control Control
{
get { }
}
public string Description
{
get { }
}
public Guid Guid
{
get { }
}
public string Name
{
get { }
}
public void Pause()
{
}
public void SetVisibility(bool visible)
{
}
public byte[] Settings
{
get
{
}
set
{
}
}
public void Start()
{
}
public void StartupParameter(string[] parameter)
{
}
public PluginState State
{
get { }
}
public void Stop()
{
}
public void UpdateUI(AntMe.SharedComponents.States.SimulationState state)
{
}
public Version Version
{
get { }
}
}
}
[/cs]
Zunächst brauchen wir ein paar grundsätzliche Dinge wie z.B. den Namen oder die Beschreibung des Plugins.
[cs]
private readonly string name = "Tutorial-Plugin"; // Der Name des Plugins
private readonly string description = "Dies ist ein Testplugin"; // Eine Beschreibung des Plugins
private readonly Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; // Die Version des Plugins
private readonly Guid guid = new Guid("BBBD7C7A-FD3A-4656-B6DC-6A88463B2816"); // Die GUID, eine eindeutige Nummer im ganzen Programm, die aber mehr oder weniger zufällig gewählt werden kann.
private PluginState pluginState = PluginState.Ready; // Der Status des Plugins
[/cs]
Diese privaten Variablen verwenden wir in den vorgegebenen Eigenschaften:
[cs]
public string Name
{
get { return name; }
}
public string Description
{
get { return description; }
}
public Version Version
{
get { return version; }
}
public Guid Guid
{
get { return guid; }
}
public PluginState State
{
get { return pluginState; }
}
[/cs]
Bei den übrigen Eigenschaften geben wir null oder false zurück:
[cs]
public bool Interrupt // Gibt an, ob die Anwendung unterbrochen werden soll.
{
get { return false; }
}
public System.Windows.Forms.Control Control // Gibt ein Control zurück, das im Hauptprogramm angezeigt wird.
{
get { return null; }
}
public byte[] Settings // Die Settings des Plugins
{
get
{
return new byte[] { }; // Just no settings
}
set
{
}
}
[/cs]
In den drei Methoden Start, Stop und Pause ändern wir den PluginStatus:
[cs]
public void Start()
{
pluginState = PluginState.Running;
}
public void Stop()
{
pluginState = PluginState.Ready;
}
public void Pause()
{
pluginState = PluginState.Paused;
}
[/cs]
Jetzt fehlt vorallem noch die Methode UpdateUI, mit der wir die Informationen der Simulation bekommen.
Auf die Simulation reagieren
Damit wir auch mit dem Benutzer kommunizieren können, müssen wir noch ein Dialogfenster programmieren. Wir fügen dem Projekt also ein Windows Form hinzu (rechtsklick aufs Projekt im Explorer, Hinzufügen -> Windows Forms) und nennen es z.B. Window.cs. In dieses Form ziehen wir ein Label und nennen es lblRound.
In den Code des Forms schreiben wir folgende Methode. Dafür müssen wir ganz oben noch using AntMe.SharedComponents.States; einfügen.
[cs]
public void ShowRound(SimulationState state)
{
lblRound.Text = state.CurrentRound.ToString();
}
[/cs]
Die können wir in der Klasse Plugin benutzen. Wir müssen zuerst eine Variable window definieren und im Konstruktor aufrufen. Das Form öffnen wir in der Methode Start und in Stop schließen wir es.
[cs]
private Window window;
public Plugin()
{
window = new Window();
}
public void Start()
{
pluginState = PluginState.Running;
window.Show();
}
public void Stop()
{
pluginState = PluginState.Ready;
window.Hide();
}
[/cs]
Jetzt kommt die Methode UpdateUI zum Zuge. In ihr benutzen wir die Methode ShowRound.
[cs]
public void UpdateUI(AntMe.SharedComponents.States.SimulationState state)
{
window.ShowRound(state);
}
[/cs]
Wenn wir das Plugin jetzt benutzen wollen, müssen wir nur die Datei erstellen (F6) und dann im Ordner bin -> Release die Datei [Projektname].dll. Diese Datei kann man im AntMe!-Programm einbinden, wenn man unter Einstellungen -> Plugins auf Plugin hinzufügen klickt und dann die Datei auswählt. Die meisten Fehler treten erst hier auf, also dann bitte hier posten!

Im Anhang findet ihr eine DLL, die das Plugin enthält. Ihr könnt sie euch runterladen und genau so wie oben beschrieben, benutzen.
Somit haben wir ein einfaches Plugin geschaffen, das uns zumindest immer die aktuelle Rundenzahl anzeigt. Dieses Tutorial soll natürlich nur beispielhaft veranschaulichen, wie man ein Plugin programmiert. Es geht noch vieles mehr. Man denke nur an die Visualisierungs-Plugins, die bei AntMe! schon dabei sind...
EDIT: Das Plugin gibts jetzt direkt als DLL.
Dieser Beitrag wurde bereits 11 mal editiert, zuletzt von Bmeise ()