C# スクリプトの利用

C#スクリプトを利用する #

マッチング処理の一部をC#スクリプトで記述することで、細やかな条件を設定できます。
基本的にLiveSplitとの併用が前提となります。


破壊的な仕様変更がなされる可能性があります。
スクリプトの扱い、特に第三者のものを使用する場合は十分に気をつけて使用してください。

大まかな流れ #

画面キャプチャ、類似度算出まではRunLeashが行い、類似度判定処理、タイマー操作などをスクリプトが行います。

使用方法 #

設定 → Otherタブを開き、「通常の監視の代わりにC#スクリプトを使用する」にチェックを入れてください。

スクリプトを編集する場合、
RunLeashを開いていない場合は
profile\対象のプロファイル\script.cs
RunLeashを開いている場合は
variousdata\current\script.cs
を編集してください。

スクリプトの記述は内臓のエディターか、Visual StudioなどのIDE、Visual Studio Codeなどのエディターを利用してください。

内蔵エディターについて #

Tool → C#スクリプトを編集 を選択するとスクリプト編集ウィンドウが開きます。

テンプレートを押すと、現在の表のパラメーターに応じたスクリプトが記述されます(同時監視など、考慮されないパラメーターがあります)。

記述が問題ないか確認したいときはエラー確認を押してください。スクリプトに問題があった場合は下の欄にエラーの場所と内容が表示されます。
何行目の何文字目にどんな問題があるかが表示されます。上の画像の場合、
5行目の20文字目、;の記述が望まれる
というメッセージが出ています(app.Reset(); の;が抜けている)。

チェックが終わったらSaveを押してスクリプトを保存してください(この時点ではプロファイルには保存されていません。メイン画面での保存処理を忘れないようにしてください)。

基本形 #

/* 外部dllを使用する場合は_Runleash.exeのある場所にdllを置き、#r と using 両方書く */
#r "OpenCvSharp.dll" // 外部ライブラリを参照する

using OpenCvSharp;

/* 各メソッドを横断して変数を使用したい場合は、メソッド外で宣言する */
int param; 

/// <summary>
/// 監視をスタートしたときに1回だけ行う処理
/// </summary>
public void Initialize() 
{
    param = 10;
    app.Print("初期化完了");
}

/// <summary>
/// 常に行う処理(類似度算出後に実行される)
/// </summary>
public void Update() 
{
    param ++;
    app.Print($"param: {param}");
}

/// <summary>
/// Split判定に関わるものはここに書く(類似度算出後に実行される)
/// </summary>
public void Split() 
{
    switch (currentSegment)
    {
        case 1:
            if (splitSimilarity[1] >= splitTable[1].threshold)
            {
                app.Split(1);
            }
            break;

        case 2:
            if (splitSimilarity[1] >= splitTable[1].threshold)
            {
                app.Split(1);
            }
            break;

        case 3:
            if (splitSimilarity[1] >= splitTable[1].threshold)
            {
                app.Split(1);
            }
            break;

        default:
            break;
    }
}

/// <summary>
/// Reset判定に関わるものはここに書く(類似度算出後に実行される)
/// </summary>
public void Reset() 
{
    if (splitSimilarity[0] >= splitTable[0].threshold) //splitxxx配列の最初([0])にはResetの値が格納されている。
    {
        app.Reset();
    }
}

/// <summary>
/// Loading判定に関わるものはここに書く(類似度算出後に実行される)
/// </summary>
public void Loading() 
{
    if (loadingSimilarity[1] >= loadingTable[1].threshold)
    {
        app.PauseGametime();
    }
    else
    {
        app.UnpauseGametime();
    }
}

public voidとは…

  • public: アクセス修飾子。このブロック(メソッド)のアクセスレベルを制限する。publicはどこからでも参照可能(RunLeashという外部からアクセスする必要があるため)。
  • void(何もないの意): 値を返さないブロックに付与する。このブロックはRunLeashから実行されるが、RunLeashに何も値を返さない(別の方法でRunLeashと値をやり取りしている)。

ブロック #

スクリプトはいくつかのブロックから成り立っています。

RunLeashの設定で自動化を有効にしている項目(Split/Reset/Loading)に応じてブロックを記述してください。

Initialize #

監視をスタートしたときに1回だけ行う処理はここに書きます。

Update #

監視中、常に行う処理はここに書きます(類似度算出後に実行されます)。

Split #

Split判定に関わるものはここに書きます(類似度算出後に実行されます)。
マッチング後、次の区間の監視が始まるまでの間(待機中)は実行されません。

Reset #

Reset判定に関わるものはここに書きます(類似度算出後に実行されます)。
Resetしてから最初のSplitが実行されるまでは動作しません。

Loading、Gametime #

LiveSplitのGametimeを操作する処理はここに書きます(類似度算出後に実行されます)。
目的に応じてブロックを使い分けてください。

Exit #

監視を終了したときに1回だけ行う処理はここに書きます。

Split、Reset、Loading / Gametimeブロックが実行されるタイミング

  • Splitブロック
    app.Split() 後 ~ 設定された待機時間経過 間を除き常に実行
  • Resetブロック
    app.Reset() ~ 最初のapp.Split() 間を除き常に実行
  • Loading / Gametimeブロック
    常に実行

使用できるパラメーター #

RunLeashの表に記載されているパラメーターと現在の区間番号、現在の類似度、過去の類似度をスクリプトで使用できます。

この先、Splitに関連するパラメーター、メソッドにおいて、index: 現在の区間の画像番号という表現が使用されています。
例えば下の画像の場合、区間(Seg.)は区間1が1つ、区間2が3つ、区間3以降は1つずつ設定されています。区間2が参照されている時(currentSegment = 2)に2つめに関連する情報を得たい場合、indexに2を指定します。
いつでも表のすべてのパラメーターにアクセスできるわけではないことに注意してください(その必要がある場合、理由とともに作者へお問い合わせください)。

splitSimilarity[index] #

現在の類似度を返します(Split / Reset分)。

  • index: 現在の区間の画像番号
    0を指定した場合、Resetのそれを返します。
    戻り値の型: double

loadingSimilarity[index] #

現在の類似度を返します(Loading分)。

  • index: 表のNo列の値

currentSegment #

現在の区間番号を返します。

capturedImage #

最新のキャプチャ画像(使用するには設定を変更する必要があります)

OpenCVSharpのMat型が返ります。Bitmap型で扱いたい場合は、以下のようなコードを記述してください。

#r "OpenCvSharp.dll"
#r "OpenCvSharp.Extensions.dll"

using OpenCvSharp;
using OpenCvSharp.Extensions;

...
using Bitmap bmp = BitmapConverter.ToBitmap(capturedImage);

splitTable[index].xxx #

表のパラメーターを取得。RunLeashのSplit表のパラメーター情報が入っています。

  • index: 現在の区間の画像番号
    0を指定した場合、Resetのそれが返ります。
  • xxx: 列名(詳細は下記の対応表を参照してください)
対応表

xxx RunLeashの表示
comment1 Comment string
comment2 2 string
comment3 3 string
segment Seg. int
loop Loop int
andor And int
method 方式 int
key Key int
adjTable AdjTable int
adjTimer AdjTimer int
seek Seek double
mask M int
audio A int
threshold 閾値 double
pn PN string
sleepTime 待機時間 double
timing T int
delay 遅延時間 int
thresholdN 閾値N double
colorTolerance 色許容 int
filter Filter string
colorR R val int
colorG G val int
colorB B val int
akaze Akaze int
px PX int
py PY int
sx SX int
sy SY int
pxScene PX(S) int
pyScene PY(S) int
sxScene SX(S) int
syScene SY(S) int
ltx LTX int
lty LTY int
rbx RBX int
rby RBY int

loadingTable[index].xxx #

表のパラメーターを取得。RunLeashのLoading表のパラメーター情報が入っています。

  • index: 表のNo列の値
  • xxx: 列名(詳細は下記の対応表を参照してください)
対応表

xxx RunLeashの表示
no No int
enable Enable int
comment Comment string
inFlagNo InFlag_No int
inFlagStatus InFlag_S int
inFlagKeyNo InFlag_Key_No int
inFlagKeyStatus InFlag_Key_S int
inKey InKey int
inFlagLiveSplitNo InFlag_LS_No int
inFlagLiveSplitStatus InFlag_LS_S int
inLiveSplitNo InLS_No int
inLiveSplitTime InLS_Time double
outFlag OutFlag int
outFlagTpl OutFlag_Tpl int
outFlagNo OutFlag_No int
outFlagStatus OutFlag_S int
outFlagKeyNo OutFlag_Key_No int
outFlagKeyStatus OutFlag_Key_S int
outKey OutKey int
outFlagLiveSplitNo OutFlag_LS_No int
outFlagLiveSplitStatus OutFlag_LS_S int
outLiveSplitNo OutLS_No int
outLiveSplitTime OutLS_Time double
delay Delay int
init Init string
method Met. int
mask M int
threshold Thr. double
thresholdN ThrN double
pn PN string
colorTolerance C.Al. int
colorR R val int
colorG G val int
colorB B val int
filter Filter string
akaze Akaze int
px PX int
py PY int
sx SX int
sy SY int
pxScene PX(D) int
pyScene PY(D) int
sxScene SX(D) int
syScene SY(D) int
ltx LTX int
lty LTY int
rbx RBX int
rby RBY int

使用できるRunLeash専用コマンド(メソッド) #

app.XXX(); という形でメソッドを使用します。

ラップタイマーに影響を与えるメソッドについて、LiveSplitと連携させている場合はLiveSplitを直接操作し、それ以外の場合は設定されたホットキーを押下します。

app.Split(int index); #

ラップタイマーをSplitします。
index: 現在の区間の画像番号

マッチング後、次の区間までの待機や追加処理(ループ回数、指定時間待機、シーンチェンジ待機)などはRunLeash側のパラメーターが使用されるため、複数枚同時監視を使用している場合は適切な番号を指定してください。

ラップタイマーがスタートしていない場合、

  • LiveSplitと連携 → LiveSplitをStartさせます。
  • ホットキー押下 → ラップタイマーがStartするかはラップタイマーのホットキー処理の実装に依存します。

app.Reset(); #

ラップタイマーをResetします。

app.Pause(); #

ラップタイマーをPauseします。

app.Resume(); #

ラップタイマーをResumeします。

app.Undo(); #

ラップタイマーをUndoします。

app.Skip(); #

ラップタイマーをSkipします。

app.SendLiveSplitCommand(string command); #

LiveSplitを使用している場合、LiveSplitを操作するコマンドを送信します。
参考:https://github.com/LiveSplit/LiveSplit/tree/master?tab=readme-ov-file#commands

使用できるコマンド #

  • startorsplit
  • split
  • unsplit
  • skipsplit
  • pause
  • resume
  • reset
  • starttimer
  • setgametime TIME
  • setloadingtimes TIME
  • pausegametime
  • unpausegametime
  • alwayspausegametime
  • setcomparison COMPARISON
  • switchto realtime
  • switchto gametime
  • setsplitname INDEX NAME
  • setcurrentsplitname NAME

タイムの戻り値があるコマンド(string型で返ってきます)

  • getdelta
  • getdelta COMPARISON
  • getlastsplittime
  • getcomparisonsplittime
  • getcurrentrealtime
  • getcurrentgametime
  • getcurrenttime
  • getfinaltime
  • getfinaltime COMPARISON
  • getpredictedtime COMPARISON
  • getbestpossibletime

その他のコマンド(string型で返ってきます)

  • getsplitindex
  • getcurrentsplitname
  • getprevioussplitname
  • getcurrenttimerphase
app.Split/Reset/Pause/Resume/Undo/Skipとapp.SendLiveSplitCommandの使い分け

基本的にapp.XXX()のみ使用します。RunLeashと区間番号などの情報の同期を取るためにはこのメソッドを使用する必要があります。
SendLiveSplitCommandはロード時間の除外など、区間番号の変更をしない範囲でご利用ください。

app.GetCurrentGametime(); #

現在のGametimeを返します(使用頻度の高そうなコマンドをメソッド化しています)。
戻り値はTimeSpan型です(V1.97をダウンロードしたタイミングによってはdouble型が返ってきます)。

app.SetGametime(double or Timespan time); #

Gametimeを指定した時間にセットします。

app.PauseGametime(); #

GametimeをPauseします。

app.UnpauseGametime(); #

GametimeをUnpauseします。

app.SplitOldSimilarity(int index, double milliSecondsAgo); #

(Split / Reset用)過去の類似度を参照します。

  • index 現在の区間の画像番号
    0を指定するとResetのそれが返ります。
  • milliSecondsAgo: 何ミリ秒前の類似度か指定
    60fpsの監視で約60秒前まで遡れます。

app.LoadingOldSimilarity(int index, double milliSecondsAgo); #

(Loading用)過去の類似度を参照します。

  • index: 現在の区間の画像番号
  • milliSecondsAgo: 何ミリ秒前の類似度か指定
    60fpsの監視で約60秒前まで遡れます。

app.Print(string content); #

RunLeashのLogに指定された文字列や変数を表示します。

app.GetImage(); #

最新のキャプチャ画像を取得します。

OpenCVSharpのMat型が返ってきます。Bitmap型で扱いたい場合は、以下のようなコードを記述してください。

#r "OpenCvSharp.dll"
#r "OpenCvSharp.Extensions.dll"

using OpenCvSharp;
using OpenCvSharp.Extensions;

...

using Mat src = app.GetImage();
using Bitmap bmp = BitmapConverter.ToBitmap(src);

app.ApplyFilter(string filter, Mat src, Mat dst); #

画像にフィルターを適用します。

  • filter: フィルター
  • src, dst: Mat型の画像データ

使用できるフィルターはこちらを参照してください。

使用例:

#r "OpenCvSharp.dll"
using OpenCvSharp;

...

using Mat src = app.GetImage();
app.ApplyFilter("{Grayscale}", src, src);
src.SaveImage("save.png");

app.CheckSplitThresholdP(int index, double value); #

(Split / Reset用)類似度が閾値以上となったかどうかチェックします。

  • index: 現在の区間の画像番号
    0を指定した場合、Resetのそれが返ります。
  • value: 閾値
    類似度が閾値以上となった時、1回だけtrueを返します。

    監視スタート時、既に類似度が閾値以上となっていた場合、一旦閾値を下回るまでfalseを返します。

app.CheckSplitThresholdN(int index, double value); #

(Split / Reset用)類似度が閾値未満となったかどうかチェックします。

  • index: 現在の区間の画像番号
    0を指定した場合、Resetのそれが返ります。
  • value: 閾値
    類似度が閾値未満となった時、1回だけtrueを返します。

    監視スタート時、既に類似度が閾値未満となっていた場合、一旦閾値以上となるまでfalseを返します。

app.GetSplitLastValue(int index); #

(Split / Reset用)(動作確認用)最新の類似度を返します。

  • index: 現在の区間の画像番号
    0を指定した場合、Resetのそれが返ります。

app.CheckLoadingThresholdP(int index, double value); #

(Loading用)類似度が閾値以上となったかどうかチェックします。

  • index: 画像番号
  • value: 閾値
    類似度が閾値以上となった時、1回だけtrueを返します。

    監視スタート時、既に類似度が閾値以上となっていた場合、一旦閾値を下回るまでfalseを返します。

app.CheckLoadingThresholdN(int index, double value); #

(Loading用)類似度が閾値未満となったかどうかチェックします。

  • index: 画像番号
  • value: 閾値
    類似度が閾値未満となった時、1回だけtrueを返します。

    監視スタート時、既に類似度が閾値未満となっていた場合、一旦閾値以上となるまでfalseを返します。

app.GetLoadingLastValue(int index); #

(Loading用)(動作確認用)最新の類似度を返します。

  • index: 画像番号

app.InitializeVariableMonitor(string variableName, double thresholdP, double thresholdN, double changeThreshold); #

独自変数をRunLeashに登録します。

  • variableName: 変数名
  • thresholdP: 上限閾値
  • thresholdN: 下限閾値
  • changeThreshold:変化量閾値

app.UpdateVariableValue(string variableName, double newValue); #

独自変数の値を更新し、閾値判定と変更検知を行います。

  • variableName: 変数名
  • newValue: 変数の値

    監視スタート時、既に類似度が閾値以上/未満となっていた場合、一旦閾値未満/以上となるまでfalseを返します。

使用方法 #

private int param;

public void Initialize()
{
    param = 1;
    app.InitializeVariableMonitor("someVariable", 98, 2, 80);
}

public void Update()
{
    Random r = new Random();
    param = r.Next(100); // 0以上100未満のランダム値を返す
    app.Print(param);

    // isUpper, isLower, isChangeはbool値。
    var (isUpper, isLower, isChange) = app.UpdateVariableValue("someVariable", param);

    if (isUpper == true)
    {
        app.Print($"someVariableが設定値以上となりました。 someVariable:{app.GetVariableValue("someVariable")}");
    }
    else if (isLower == true)
    {
        app.Print($"someVariableが設定値未満となりました。 someVariable:{app.GetVariableValue("someVariable")}");
    }
    else if (isChange == true)
    {
        app.Print($"someVariableの変化量が設定値以上となりました。 someVariable:{app.GetVariableValue("someVariable")}");
    }
}

app.ResetVariableMonitor(string variableName); #

独自変数のリセットを行います。

  • variableName: 変数名

app.ResetAllVariableMonitors(); #

全ての独自変数のリセットを行います。

app.GetVariableValue(string variableName); #

独自変数の最新の値を取得します。

  • variableName: 変数名

その他 #

C#の言語バージョンは11ですが、フレームワークが.NET Frameworkのため、使用できない機能があります。
参考:https://qiita.com/kenichiuda/items/fada6068ea265fd6a389