Repository navigation
Plugins development ja JP
ASFには、ランタイム中にロードできるカスタムプラグインのサポートが含まれています。プラグインを使用すると、カスタムコマンド、カスタム取引ロジック、サードパーティのサービスやAPIとの統合などでASFの動作をカスタマイズできます。
このページでは、作成、保守、公開など、開発者の視点から ASF プラグインについて説明します。ユーザー向けの観点を確認したい場合は、代わりに こちら に移動してください。
プラグインは、ASF で宣言されている共通の IPlugin インターフェースを継承するクラスを定義した、標準的な .NET ライブラリです。内部 ASF API の互換性が保たれている限り、プラグインはメインラインの ASF とは完全に独立して開発でき、現在および将来の ASF バージョンで再利用できます。 ASF で使用されているプラグインシステムは System.Composition をベースにしています。これは以前 Managed Extensibility Framework として知られていたもので、ASF が実行時にライブラリを検出して読み込めるようにします。
プラグインプロジェクトのベースとして使用できる(そして使用するべき) ASF-PluginTemplate を用意しています。テンプレートの使用は必須ではありません(すべてを一から作成することもできます)が、開発を大幅に加速し、すべてを正しく整えるために必要な時間を短縮できるため、使用することを強くおすすめします。テンプレートの README を確認するだけで、その先の手順を案内してくれます。とはいえ、一から始めたい場合や、プラグインテンプレートで使用されている概念をよりよく理解したい場合に備えて、以下で基本を説明します。通常、私たちのプラグインテンプレートを使用することにした場合は、これらを行う必要はありません。
プロジェクトは、コンパイル セクションで指定されている、対象の ASF バージョンに適したフレームワークをターゲットとする標準の .NET ライブラリである必要があります。
プロジェクトは、メインの ArchiSteamFarm アセンブリを参照する必要があります。参照先は、リリースの一部としてダウンロードしたビルド済みの ArchiSteamFarm.dll ライブラリ、またはソースプロジェクトのどちらでも構いません(たとえば、ASF ツリーをサブモジュールとして追加することにした場合など)。これにより、ASF の構造、メソッド、プロパティにアクセスして確認できるようになります。特に、次の手順で継承する必要がある中核的な IPlugin インターフェースを確認できます。プロジェクトは少なくとも System.Composition.AttributedModel も参照する必要があります。これにより、ASF が使用できるように IPlugin を [Export] できます。それに加えて、一部のインターフェースで渡されるデータ構造を解釈するために、他の共通ライブラリを参照したい、または参照する必要がある場合もあります。ただし、それらが明示的に必要でない限り、現時点ではこれで十分です。
すべて正しく行えていれば、csproj は以下のようになります:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- プラグインは ASF プロセス内に読み込まれ、そのプロセスにはこれらの依存関係がすでに含まれているため、IncludeAssets="compile" によって最終出力から省略できます -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" IncludeAssets="compile" Version="10.0.0" />
<PackageReference Include="System.Composition.AttributedModel" IncludeAssets="compile" Version="10.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="C:\\Path\To\ArchiSteamFarm\ArchiSteamFarm.csproj" ExcludeAssets="all" Private="false" />
<!-- ダウンロードした DLL バイナリを使ってビルドする場合は、上の <ProjectReference> の代わりにこちらを使用してください -->
<!-- <Reference Include="ArchiSteamFarm" HintPath="C:\\Path\To\Downloaded\ArchiSteamFarm.dll" /> -->
</ItemGroup>
</Project>コード側では、プラグインクラスは IPlugin インターフェースを継承し(明示的に継承するか、IASF などのより特化したインターフェースを継承することで暗黙的に継承します)、実行時に ASF に認識されるよう [Export(typeof(IPlugin))] を付ける必要があります。それを実現する最小限の例は、以下のようになります:
using System;
using System.Composition;
using System.Threading.Tasks;
using ArchiSteamFarm;
using ArchiSteamFarm.Plugins;
namespace YourNamespace.YourPluginName;
[Export(typeof(IPlugin))]
public sealed class YourPluginName : IPlugin {
public string Name => nameof(YourPluginName);
public Version Version => typeof(YourPluginName).Assembly.GetName().Version;
public Task OnLoaded() {
ASF.ArchiLogger.LogGenericInfo("Hello World!");
return Task.CompletedTask;
}
}プラグインを使用するには、まずコンパイルする必要があります。これは IDE から行うことも、プロジェクトのルートディレクトリ内で次のコマンドを使って行うこともできます:
# プロジェクトがスタンドアロンの場合(唯一のプロジェクトなので名前の指定は不要です)
dotnet publish -c "Release" -o "out"
# プロジェクトが ASF ソースツリーの一部である場合(不要な部分をコンパイルしないため)
dotnet publish YourPluginName -c "Release" -o "out"その後、プラグインをデプロイする準備は完了です。プラグインをどのように配布・公開するかはあなた次第ですが、コンパイル済みのプラグインをその 依存関係 と一緒に入れた zip アーカイブを作成することをおすすめします。この方法なら、ユーザーは zip アーカイブを自分の plugins ディレクトリ内の独立したサブディレクトリに展開するだけで済み、他に何もする必要はありません。
これは、まず始めるためのごく基本的な例にすぎません。独自のプラグイン内で使用できるインターフェースや実行できる操作の例を、役立つコメント付きで示した ExamplePlugin プロジェクトを用意しています。動作するコードから学びたい場合は、自由に確認してみてください。また、自分で ArchiSteamFarm.Plugins 名前空間を調べ、利用可能なすべてのオプションについて付属のドキュメントを参照することもできます。以下では、それらをより分かりやすく説明するために、いくつかの中核的な概念についてもさらに詳しく取り上げます。
サンプルプラグインではなく実際のプロジェクトから学びたい場合は、私たちが開発した公式プラグインがいくつかあります。たとえば、ItemsMatcher、MobileAuthenticator、SteamTokenDumper などです。それに加えて、サードパーティ セクションには、他の開発者によって開発されたプラグインもあります。
ASF は、インターフェース自体からアクセスできるものとは別に、機能を拡張するために利用できる多数の内部 API も公開しています。たとえば、Steam Web に何らかの新しいリクエストを送信したい場合でも、すべてを一から実装する必要はありません。特に、私たちがすでに対処してきたさまざまな問題に自分で対応する必要はありません。低レベルの処理、たとえば認証、セッション更新、Web 制限などはすべて処理してくれるため、利用可能な多数の UrlWithSession() メソッドをすでに公開している Bot.ArchiWebHandler をそのまま使用してください。同様に、Steam プラットフォーム外へ Web リクエストを送信する場合、標準の .NET HttpClient クラスを使用することもできますが、利用可能な Bot.ArchiWebHandler.WebBrowser を使用する方がはるかに適しています。これもまた、失敗したリクエストの再試行などで役立つ支援を提供してくれます。
API の利用可否については非常にオープンな方針を取っています。そのため、ASF のコードにすでに含まれているものを利用したい場合は、issue を開いて、ASF の内部 API をどのような用途で使う予定なのかを説明してください。使用目的が妥当である限り、私たちが反対することはまずないでしょう。これには、既存の機能を拡張するために追加するとよさそうな、新しい IPlugin インターフェースに関する提案もすべて含まれます。
ただし、ASF API の利用可否にかかわらず、たとえばアプリケーションに Discord.Net ライブラリを含めて、Discord ボットと ASF コマンドの間にブリッジを作成することを妨げるものはありません。プラグインは独自の依存関係を持つこともできるためです。可能性は無限にあります。私たちは、プラグイン内でできるだけ多くの自由度と柔軟性を提供できるよう最善を尽くしました。そのため、人為的な制限は何もありません。プラグインはメインの ASF プロセスに読み込まれ、C# コード内から現実的に実行可能なことは何でも行えます。
ASF はコンシューマーアプリケーションであり、無条件に依存できる固定された API サーフェスを持つ一般的なライブラリではない、という点を強調しておくことが重要です。つまり、一度コンパイルしたプラグインが、今後のすべての ASF リリースで必ず動作し続けるとは考えられない、ということです。プログラムの開発を続けていく以上、それは単純に不可能ですし、後方互換性のために絶えず続く Steam の変更へ対応できなくなることは、私たちのケースでは適切ではありません。これは当然のことと思われるかもしれませんが、その点を強調しておくことが重要です。
ASF の公開部分が動作し、安定した状態を保てるよう最善を尽くしますが、十分な理由が生じた場合には、非推奨 ポリシーに従いながら、互換性を破ることもためらいません。これは、ASF インフラストラクチャの一部として公開されている内部 ASF 構造 (例:ArchiWebHandler) に関して特に重要です。これらは将来のいずれかのバージョンで、ASF の改善の一環として改良される可能性があります (したがって、書き換えられる可能性もあります)。変更ログで適切にお知らせし、実行時にも廃止予定の機能について適切な警告を表示するよう最善を尽くします。私たちは、書き換えること自体を目的としてすべてを書き換えるつもりはありません。そのため、次の ASF マイナーバージョンが、バージョン番号が上がったという理由だけでプラグインを完全に壊してしまうことはまずないと考えてよいでしょう。ただし、変更ログを確認し、ときどきすべてが正常に動作しているか検証しておくことは、とても良い考えです。
プラグインにはデフォルトで少なくとも 2 つの依存関係が含まれます。内部 API 用の ArchiSteamFarm 参照(最低限 IPlugin)、そして最初から ASF プラグインとして認識されるために必要な System.Composition.AttributedModel の PackageReference([Export] 句)です。それに加えて、プラグインで何を行うことにしたかに応じて、さらに依存関係が含まれる場合があります(たとえば、Discord と連携することにした場合は Discord.Net ライブラリなど)。
ビルド出力には、メインの YourPluginName.dll ライブラリに加えて、参照したすべての依存関係が含まれます。プラグインはすでに動作しているプログラムに読み込まれるものなので、ASF がすでに含んでいる依存関係を含める必要はなく、むしろ含めるべきではありません。たとえば ArchiSteamFarm、SteamKit2、AngleSharp などです。 ASF と共有される依存関係をビルドから取り除くことは、プラグインを動作させるための絶対条件ではありません。しかし、そうすることで、ASF が自身の依存関係をプラグインと共有し、ASF 自身が知らないライブラリだけを読み込むようになるため、メモリ使用量とプラグインのサイズを大幅に削減でき、パフォーマンスも向上します。
一般的には、ASF に含まれていないライブラリ、または ASF に含まれていてもバージョンが間違っている、もしくは互換性がないライブラリだけを含めることが推奨されます。その例としては、当然 YourPluginName.dll が挙げられますが、たとえば Discord.Net.dll に依存することにした場合は、ASF 自体には含まれていないため、これも含める対象になります。 ASF と共有されるライブラリを同梱することにも意味がある場合があります。たとえば、API 互換性を確保したい場合です(例:プラグインで依存している AngleSharp が、ASF に同梱されているものではなく、常にバージョン X であることを保証したい場合)。ただし当然ながら、その場合はメモリ使用量やサイズの増加、パフォーマンスの低下という代償があるため、慎重に評価する必要があります。
必要な依存関係が ASF に含まれていることが分かっている場合は、上記の csproj の例で示したように、IncludeAssets="compile" を付けることができます。これにより、そのライブラリは ASF にすでに含まれているため、参照先のライブラリ自体を公開しないようコンパイラーに指示できます。同様に、ASF プロジェクトを ExcludeAssets="all" Private="false" 付きで参照している点にも注意してください。これは非常によく似た仕組みで動作し、ASF ファイルを生成しないようコンパイラーに指示します(ユーザーはすでにそれらを持っているためです)。これは ASF プロジェクトを参照している場合にのみ当てはまります。dll ライブラリを参照している場合は、プラグインの一部として ASF ファイルを生成しないためです。
上記の説明で混乱し、よく分からない場合は、ASF-generic.zip パッケージに含まれている dll ライブラリを確認し、プラグインにはまだそこに含まれていないものだけを含めるようにしてください。最も単純なプラグインでは、これは YourPluginName.dll だけになります。実行時に何らかのライブラリに関する問題が発生した場合は、影響を受けているライブラリも含めてください。どうしてもうまくいかない場合は、すべてを同梱することもできます。
ネイティブ依存関係は OS 固有ビルドの一部として生成されます。これは、ホスト上に .NET ランタイムが存在せず、ASF が OS 固有ビルドの一部として同梱されている独自の .NET ランタイムを通じて実行されるためです。ビルドサイズを最小限に抑えるため、ASF はネイティブ依存関係をトリミングし、プログラム内から到達する可能性があるコードのみを含めます。これにより、ランタイムの未使用部分が実質的に削減されます。これにより、プラグインに関して潜在的な問題が発生する可能性があります。プラグインが ASF では使用されていない .NET 機能に依存していることが突然判明した場合、OS 固有ビルドではそれを正しく実行できず、通常はその過程で System.MissingMethodException や System.Reflection.ReflectionTypeLoadException がスローされます。プラグインの規模が大きくなり、複雑さが増していくにつれて、遅かれ早かれ、OS 固有ビルドではカバーされていない領域に到達することになります。
generic ビルドでは、これが問題になることはありません。そもそも native 依存関係を扱わないためです(ASF を実行するホスト上に、完全に動作するランタイムが存在しているためです)。そのため、プラグインは generic ビルド専用で使用する ことが推奨されます。ただし当然ながら、ASF の OS 固有ビルドを実行しているユーザーがそのプラグインを利用できなくなるという欠点もあります。問題がネイティブ依存関係に関連しているかどうか分からない場合は、この方法で確認することもできます。ASF の generic ビルドでプラグインを読み込み、動作するか確認してください。動作する場合、プラグインの依存関係は満たされており、問題を引き起こしているのはネイティブ依存関係です。
残念ながら、OS 固有ビルドの一部としてランタイム全体を同梱するか、未使用の機能を削って完全版より 80 MB 以上小さいビルドにするか、難しい選択を迫られました。私たちは 2 つ目の選択肢を選びました。そのため残念ながら、不足しているランタイム機能をプラグインと一緒に含めることはできません。プロジェクトが除外されたランタイム機能へのアクセスを必要とする場合は、依存している完全な .NET ランタイムを含める必要があります。つまり、プラグインを generic ASF フレーバーで実行する必要があります。 OS 固有ビルドではプラグインを実行できません。これらのビルドには必要なランタイム機能が欠けており、現時点の .NET ランタイムでは、あなたが提供できたとしても、そのネイティブ依存関係を私たちのものと「マージ」できないためです。将来的には改善されるかもしれませんが、現時点では単純に不可能です。
ASF の OS 固有ビルドには、公式プラグインを実行するために必要な最小限の追加機能が含まれています。それを可能にするだけでなく、最も基本的なプラグインに必要な追加の依存関係まで、対象範囲もわずかに広がります。したがって、すべてのプラグインが最初からネイティブ依存関係を気にする必要があるわけではありません。対象となるのは、ASF と公式プラグインが直接必要とする範囲を超えるものだけです。これは追加対応として行っています。私たち自身の用途のために追加のネイティブ依存関係を含める必要がある場合は、ASF に直接同梱することもできるためです。そうすることで、それらが利用可能になり、結果としてあなたにとってもカバーしやすくなります。残念ながら、これで常に十分というわけではありません。プラグインが大きくなり、複雑になるほど、トリミングされた機能に遭遇する可能性は高くなります。したがって、通常はカスタムプラグインを generic ASF フレーバー専用で実行することをおすすめします。 ASF の OS 固有ビルドに、プラグインの機能に必要なものがすべて含まれているかを手動で確認することはできます。ただし、それはあなたの更新と私たちの更新の両方で変化するため、維持するのは難しいかもしれません。
場合によっては、代替手段を使用するか、プラグイン内で再実装することで、不足している機能を「回避」できる可能性があります。ただし、これが常に可能または現実的であるとは限りません。特に、不足している機能が、プラグインの一部として含めているサードパーティ依存関係に由来する場合はなおさらです。 OS 固有ビルドでプラグインを実行し、動作させようと試みることはいつでもできます。ただし長期的には、特に ASF の対応範囲と格闘するのではなく、コードをただ動作させたいだけの場合、手間がかかりすぎる可能性があります。
ASF は、プラグインで自動更新を実装するための 2 つのインターフェースを提供しています:
-
IGitHubPluginUpdates- 一般的な ASF 更新メカニズムと同様の、GitHub ベースの更新を簡単に実装する方法を提供します -
IPluginUpdates- より複雑なものが必要な場合に、カスタム更新メカニズムを可能にする低レベルの機能を提供します
更新を動作させるために必要な項目の最小チェックリスト:
- 更新の取得元を定義する
RepositoryNameを宣言する必要があります。 - GitHub が提供するタグとリリースを使用する必要があります。タグは、プラグインのバージョンとして解析できる形式である必要があります。例:
1.0.0.0。 - プラグインの
Versionプロパティは、そのプラグインの取得元であるタグと一致している必要があります。これは、タグ1.2.3.4で提供されるバイナリが、自身のバージョンを1.2.3.4として示す必要があるという意味です。 - 各タグには、プラグインのバイナリファイルを含む zip ファイルのリリースアセットを持つ、対応するリリースが GitHub 上に用意されている必要があります。
IPluginクラスを含むバイナリファイルは、zip ファイル内のルートディレクトリに配置されている必要があります。
これにより、ASF の仕組みは次のことを行えるようになります:
- プラグインの現在の
Versionを取得します。例:1.0.1。 - GitHub API を使用して、
RepositoryNameリポジトリで利用可能な最新のtagを取得します。例:1.0.2。 -
1.0.2>1.0.1であると判断し、1.0.2タグのリリースを確認して、プラグイン更新を含む.zipファイルを探します。 - その
.zipファイルをダウンロードして展開し、その内容を以前YourPlugin.dllが含まれていたディレクトリに配置します。 - ASF を再起動して、
1.0.2バージョンのプラグインを読み込みます。
補足事項:
- プラグインの更新には、適切な ASF 設定値、具体的には
PluginsUpdateModeおよび/またはPluginsUpdateListが必要になる場合があります。 - 私たちのプラグインテンプレートには必要なものがすべて含まれているため、プラグインを適切な値に リネーム するだけで、そのまま動作します。
- 最新リリースとプレリリースを組み合わせて使用できます。これらは、ユーザーが定義した
UpdateChannelに従って使用されます。 - プラグイン更新の無効化または有効化をプラグイン側で行うために、オーバーライド可能な
CanUpdateboolean プロパティがあります。たとえば、一時的に更新をスキップしたい場合や、その他の理由がある場合に使用できます。 - 異なる ASF バージョンを対象にしたい場合は、リリースに複数の zip ファイルを含めることもできます。
GetTargetReleaseAsset()の remarks を参照してください。たとえば、MyPlugin-V6-0.zipとMyPlugin.zipを使用すると、バージョンV6でASFが発生します。 .x.xは最初のものを選択し、他のすべてのASFバージョンは2番目のものを使用します。 - 上記で不十分で、正しい
.zipファイルを選択するためのカスタムロジックが必要な場合は、GetTargetReleaseAsset()関数をオーバーライドし、ASF が使用するアーティファクトを提供できます。 - プラグインが更新の前後に追加の処理を行う必要がある場合は、
OnPluginUpdateProceeding()および/またはOnPluginUpdateFinished()メソッドをオーバーライドできます。
このインターフェースを使用すると、何らかの理由で IGithubPluginUpdates では不十分な場合に、更新用のカスタムロジックを実装できます。たとえば、タグをバージョンとして解析できない場合や、GitHub プラットフォームをまったく使用していない場合などです。
オーバーライドできる GetTargetReleaseURL() 関数が 1 つあり、対象プラグイン更新場所の Uri? を返すことが求められます。 ASF は、その関数が呼び出された文脈に関連するいくつかの中核的な変数を提供しますが、それ以外については、その関数内で必要なものをすべて実装し、使用すべき URL、または更新が利用できない場合は null を ASF に返す責任があります。
それ以外は GitHub 更新と同様で、URL は、ルートディレクトリにバイナリファイルが配置された .zip ファイルを指している必要があります。 OnPluginUpdateProceeding() および OnPluginUpdateFinished() メソッドも利用できます。







