新機能
プラグインAPIのバージョンアップ
プラグインAPIアセンブリ(PhotonHivePlugin.dll)のバージョンが1.0.xから1.1.0に更新されました。
これは、Photon Server Plugins SDK (v5 RC1以降)を使用してPhotonHivePlugin.dll 1.1.xを含むカスタムプラグインを作成し、それをデプロイしてサーバー上で実行する場合、サーバーバイナリはプラグインAPIのバージョンに合わせる必要があることを意味します。
Enterpriseのお客様の場合、プライベートクラウドが少なくともPhoton Server v5 RC1にアップデートされている必要があります。
古いプライベートクラウドにプラグインをアップロードしようとすると、新しいルームを作成する際にプラグインをロードしようとするとエラーが発生します。
新しい個別の設定ファイル
プラグインは、自身のファイル上で個別に設定されるようになりました。
ファイルは、以前に使用された設定ファイルと同じフォルダーにある「plugin.config」です。
ただし、構成する構文は同じです。
新しいロギングインターフェース
プラグインからアクセスできるロギングインターフェースを追加しました。
以前の方法
v4では、IPluginHost
ロギングメソッドを直接呼び出していました。
C#
private IPluginHost pluginHost;
public bool SetupInstance(IPluginHost host, Dictionary<string, string> config, out string errorMsg)
{
pluginHost = host;
}
///...
this.pluginHost.LogDebug("debug");
this.pluginHost.LogWarning("warning");
this.pluginHost.LogError("error");
this.pluginHost.LogFatal("fatal");
新しい方法
IPluginHost
ロギングメソッドを呼び出すのではなく、プラグインインタンスごとに新しいIPluginLogger
オブジェクトを作成する必要があります。
このオブジェクトを利用して、プラグインからすべてをログします。
C#
public const string PluginName = "MyPlugin";
private IPluginLogger pluginLogger;
public override bool SetupInstance(IPluginHost host, Dictionary<string, string> config, out string errorMsg)
{
pluginLogger = host.CreateLogger(PluginName);
// ...
}
// ...
this.pluginLogger.LogDebug("debug");
this.pluginLogger.LogWarning("warning");
this.pluginLogger.LogError("error");
this.pluginLogger.LogFatal("fatal");
ロガー(IPluginHost.CreateLogger(loggerName)
に渡されます)の名前を設定する際、ロガー名にはPlugin.を付け加えます。このためMyPlugin.MyClass
を設定すると、これはPlugin.MyPlugin.MyClass
としてログされます。 たとえばログレベルが最大レベルに設定された場合に、上記のコードスニペットはこれらのログエントリーを生成します。
2020-01-31 17:10:07,394 [1] DEBUG Plugin.MyPLugin - debug
2020-01-31 17:10:07,901 [1] WARN Plugin.MyPLugin - warning
2020-01-31 17:10:08,152 [1] ERROR Plugin.MyPLugin - error
2020-01-31 17:10:08,724 [1] FATAL Plugin.MyPLugin - fatal
プラグインHook処理の向上
ICallInfo
はプラグインhookメソッド内で取得する引数で、メソッド呼び出しのコンテキストを表します。
このコンテキストオブジェクトは、ルーム内での通常のワークフローを保証するhook呼び出しが発生した後に制限時間内に処理される必要があります。
匿名関数
匿名関数(ラムダ表現または匿名メソッド)をHTTPリクエストのコールバックとして使用していた場合(以下の例を参照ください)には、今後も使用し続けることができます。
匿名メソッドとしてのHTTPコールバックの例:
C#
private void SendRequest(ICallInfo callInfo)
{
HttpRequest request = new HttpRequest
{
Callback = delegate
{
ProcessCallIfNeeded(callInfo);
},
ラムダ表現としてのHTTPコールバックの例:
C#
private void SendRequest(ICallInfo callInfo)
{
HttpRequest request = new HttpRequest()
{
Callback = (response, userObject) => ProcessCallIfNeeded(callInfo),
以前のHTTPメソッドコールの置換を推奨します:
C#
PluginHost.HttpRequest(request);
上記は、2つの引数をともなう新しい負荷メソッドに置換してください:
C#
PluginHost.HttpRequest(request, callInfo);
ld Way 以前の方法
これまでは、HTTPレスポンスコールバック内のICallInfo
オブジェクトを取得するには回避策を講じなければなりませんでした。
カスタムかつ任意のHttpRequest.UserState
を使用し、ICallInfo
オブジェクトを格納していました。
例:
C#
private void CallbackOldLogic(IHttpResponse response, object userObject)
{
ICallInfo callInfo = userObject as ICallInfo;
ProcessCallIfNeeded(callInfo);
}
private void SendRequest(string url, ICallInfo callInfo)
{
HttpRequest request = new HttpRequest
{
Url = url,
Callback = CallbackOldLogic,
UserState = callInfo
}
this.PluginHost.HttpRequest(request);
新しい方法
今後は、新しいPluginHost.HttpRequest負荷メソッド内のプラグインhookコンテキスト(ICallInfo
)を渡します。
その後、IHttpResponse
からそれを取得します。
例:
C#
private void CallbackNewLogic(IHttpResponse response, object userObject)
{
ICallInfo callInfo = response.CallInfo;
ProcessCall(callInfo);
}
private void SendRequest(string url, ICallInfo callInfo, object userObject = null)
{
HttpRequest request = new HttpRequest
{
Url = url,
Callback = CallbackNewLogic,
UserState = userObject,
CallInfo = callInfo
};
this.PluginHost.HttpRequest(request, callInfo);
新しい非同期の挙動
以前の方法
v4では、プラグインhookの処理を遅延させるには非同期HTTPリクエストまたはタイマー向けのICallInfo.Defer
を呼び出す必要がありました。
HTTPリクエストの例:
C#
private void SendRequest(string url, ICallInfo callInfo)
{
HttpRequest request = new HttpRequest
{
Url = url,
Async = true,
Callback = delegate { ProcessCallIfNeeded(callInfo); },
};
this.PluginHost.HttpRequest(request);
callInfo.Defer();
}
タイマーの例:
C#
private void DelayLogic(ICallInfo callInfo, Action logic, int delayMs)
{
PluginHost.CreateOneTimeTimer(
() =>
{
logic();
ProcessCallIfNeeded(callInfo);
},
delayMs);
callInfo.Defer();
}
新しい方法
ICallInfo.Defer
は削除され、その代わり、以下の場合にhookコンテキストの呼び出しが内部的に自動で延期されます:
httpRequest.Async = true
でHttpRequest
を送信している場合- タイマーを作成している場合
HTTPリクエストの例:
C#
private void SendRequest(string url, ICallInfo callInfo)
{
HttpRequest request = new HttpRequest
{
Url = url,
Async = true,
Callback = delegate { ProcessCallIfNeeded(callInfo); },
CallInfo = callInfo
};
this.PluginHost.HttpRequest(callInfo, request);
}
タイマーの例:
C#
private void DelayLogic(ICallInfo callInfo, Action logic, int delayMs)
{
PluginHost.CreateOneTimeTimer(
callInfo,
() =>
{
logic();
ProcessCallIfNeeded(callInfo);
},
delayMs);
}
ファイバーアクセス
ファイバーは、FIFO方式で1つずつ順番に実行されるタスクのリストです。
1つのスレッドで実行されることを意味するわけではありません。
実際には、複数のスレッドで実行されますが、1つずつ実行されます。
したがって、最初のタスクはスレッドAで実行され、終了すると、2番目のタスクはスレッドBで実行されます。
ただし、どんな時も、1つのスレッドだけがルームデータにアクセスします。
多くのファイバーが同じデータにアクセスしようとする場合、ロックを使用します。
プラグインからルームファイバーを取得するには:
C#
IPluginFiber fiber = this.PluginHost.GetRoomFiber();
キューへの追加
以下を使用して、ルームのファイバーへのアクションをキューに入れることができます:
C#
PluginHost.Enqueue(someAction);
または、上記で取得したファイバーを使用できます。
C#
int r = fiber.Enqueue(someAction);
if (r == 0)
{
// success
}
else
{
// error
}
タイマー
IPluginFiber
はIPluginHost
と同じメソッドを共有しますが、 ICallInfo
を必要とせず、hookコンテキスト外でスレッドセーフで実行できる点が異なります。
C#
object timer = fiber.CreateOneTimeTimer(someAction, executeAfterMs);
\\ ...
fiber.StopTimer(timer); // in case you want to abort before delay is expired and someAction is executed
C#
object timer = fiber.CreateTimer(someAction, firstExecutionAfterMs, repeatEachMs);
fiber.StopTimer(timer);
IFactoryHost
ルーム外でのロックのない処理も、新たにサポートされるようになりました。これは、アプリケーション全体へのサービスに使用できます(すなわち、チート対策サービス、ブロードキャスティングなど)。この処理は、IPluginFiber
メカニズムを使用して完全に構築されています。
プラグインファイバーはルームファイバーに類似したファイバーですが、ルーム外で作動します。
プラグインファイバーには任意の場所からキューに追加
でき、操作はサーバー時間にもとづいて実行されます。
IPluginFiber
を取得するには、IFactoryPlugin2
から提供されるIFactoryHost
のインスタンスが必要です。
IFactoryPlugin2
は標準のIPluginFactory
を1つのメソッドで拡張したインターフェースです:
C#
void SetFactoryHost(IFactoryHost factoryHost, FactoryParams factoryParams);
このメソッドは、プラグインのライフタイム中に1回、プラグインファクトリがインスタンス化されIFactoryHost
インスタンスを提供した直後に呼び出されます。IFactoryHost
インスタンスは
プラグインファイバーとプラグインロガーを提供します。
C#
IPluginFiber CreateFiber();
IPluginLogger CreateLogger(string loggerName);
FactoryHost
によって作成されたファイバーは、ルーム外(すなわち、新しいルームの作成時)でも、キューに追加するルーム内でも使用できます。
または、ルームコンテキスト外でタイマー操作にも使用できます。
新しい同期の挙動
「同期HTTPリクエスト」(httpRequest.Async = falseとともにHttpRequestを送信)を対象に、レスポンスまたはタイムアウトを取得するまでルームファイバー(すなわち、ルームメッセージは処理されません)を停止します。
以前のIPluginHost.HttpRequest
メソッドによるブロック中:HTTPレスポンスが受信されるかタイムアウトするまでは返しません。
このアプローチのおもな問題点は、スレッドがブロックされ、コールバック実行がこのスレッドのキューにプッシュされるということです。
スレッドがブロックされているため、このコールバックは実行されません。
結果として、タイムアウトを取得します。
新しいアプローチとの主な相違点は、新しいIPluginHost.HttpRequest
メソッドの性質上、ブロックしないという点です。
このメソッドはブロックしません。
つまり、ユーザーコードをリライトする必要があります。コールが作成されたプラグインhookと、使用されたHTTPリクエストの両方をアップデートする必要があります。
プラグインhookは、HTTPキューにリクエストをプッシュした直後に新しいIPluginHost.HttpRequest
を返す点を認識する必要があります。
コールバック内で、まだ完了していない場合にはICallInfo
オブジェクトを処理する必要があります(続行または操作を中断するには、 callInfo.Continue
、Fail
またはCancel
を
呼び出します。今後は、スレッドの代わりにルームファイバーをブロックします。 リクエストへのレスポンスを取得するか、タイムアウトするまでは、新たなタスクは処理されません。
グローバルな禁止
新しいRemoveActorReason.GlobalBanned
(2)を渡すと、マスターサーバーは認証トークンの有効期限の2倍(デフォルトは2×1時間)までUserIdをメモリに保持するので、グローバルに禁止されたユーザーはその間、新しいルームに参加できません。
その後、カスタム認証でそのユーザーを拒否することができます。
また、これは現在のルームに対して、RemoveActorReason.Banned
と同じ効果があります。つまり、UserIdはルームの状態のExcludedUsersに追加され、ユーザーは再参加できません。
AuthCookieの更新
このメソッドを使用して、アクターごとに安全な認証Cookieを更新できるようになりました。
void IActor.UpdateSecure(string key, object value)
すべてのキャッシュ操作への対応
これで、すべてのキャッシュ操作を実行できます。
クライアントへのイベント送信を伴わないすべてのキャッシュ操作では、新しいメソッドを使用します。
bool IPluginHost.ExecuteCacheOperation(CacheOp operation, out string errorMsg)
より柔軟で強力なHTTPリクエストAPI
- PUTメソッドへの対応が追加されました。
その他のHTTPメソッドにも対応する必要があります。 HttpRequest
プロパティ(Accept
,ContentType
)を使用して、いくつかの制限されたHTTPリクエストヘッダーを設定できます。- `IHttpResponse.Headersを使用してHTTPレスポンスヘッダーを取得できます。