LivesplitのScriptable Autosplitterの使い方から作り方までの総合的な説明

個別のゲームタイトルでは詳細な導入方法の説明を見かけるのですが、使い方だけでなく作り方も含んだ総合的な説明はあまり見ないなと思ったので、この記事を書いてみました。

Scriptable Autosplitter とは

Scriptable Autosplitter の概要

Scriptable Autosplitter は Livesplit の機能の一つで、スタート・ラップ・リセットといったタイマー操作を自動化することができます。
 また、計測するタイムからゲームのロード時間などを除いたロードタイムリムーバとしても利用されています。

Scriptable Autosplitter(以下、Autosplitter)は PC のメモリを監視して特定の場所にある値を読み取ってタイマー操作の種類やタイミングを判断しているため、タイムを計測するゲームは PC 上で動くゲームであるという前提条件があります。
Autosplitterの概要

家庭用ゲーム機でしか発売されていないゲームタイトルでも Autosplitter を動かすために必要な自動ラップスクリプト(拡張子 .asl のファイル。以下、asl ファイル)が存在することもありますが、おそらくは PC 上で動作するエミュレータ使用が前提のものだと思います。

メモリが読めないゲームで自動ラップをしたい場合

家庭用ゲーム機の映像をキャプチャして PC に取り込んでいる場合、画像認識を利用した自動ラップ支援ソフトの導入を検討しても良いと思います。

なお画像認識による自動ラップ機能を提供するソフトは複数ありますが、ここで説明している Autosplitter と合わせてそれぞれ似た名前をしているため混同に注意です。

VideoAutoSplitter

コンポーネントとして追加するタイプの画像認識による自動ラップで、Livesplit の中で追加して使用します。

Autosplit

海外製の自動ラップ支援ソフトで、Livesplit にホットキーを送信します。

導入例

マリオデAny%にAutoSplitを導入したのでやり方メモ
歌姫周回用 LiveSplit (RTA タイマー) と AutoSplit でのタイム計測の自動化

RunLeash(旧名称 Autosplit helper)

国産の自動ラップ支援ソフトで、Livesplit にホットキーを送信します。

導入例

Autosplit Helperの導入から実践利用までの設定方法
Autosplit Helper の導入例 - マリオテニス エースRTAを例に
QWOPのAutoSplit Helper導入手順 2021年改訂版

Livesplit の 2 種類のタイマー

Livesplit は内部に "Real Time" と "Game Time" の 2 種類のタイマーを持っていて、「自動ラップに使う」「ロードタイムリムーバに使う」など Autosplitter の用途に合わせて正いタイマーを選ばなければ、うまくラップを取れないなどトラブルが発生してしまうことがあります。
Real Time と Game Time

Layout Editor の Timer や Split に用意されている設定項目 "Timing Method" は、この 2 種類のタイマーのどちらを使用するかを指定するための項目で、Current Timing Method を指定した場合は右クリックメニューの Compare Against でチェックが付いている方が選択されます。

Real Time

普通にストップウォッチとして使う場合はこちら。
 デフォルト設定だと Real Time のタイマーを使用する設定になっています。

Autosplitter を使用してタイマーのスタートやラップ、ストップを自動化する場合でも、ロードタイムリムーバを利用しないのであれば Real Time で問題ありません。

Game Time

基本的には asl ファイルと組み合わせて使用するタイマーで、ロードタイムリムーバを使用する時のロード中にカウントを停止するタイマーがこの Game Time です。
 また、IGT 計測をする場合には、asl でゲーム内の時間を読み取ってその時間にタイマーを同期させることもできます。

通常は asl ファイル内に Game Time を操作するための記述がないと、ラップを取っても Game Time のラップは記録されません。(Real Time と Game Time が常に同じで、Game Time のラップが記録されない場合は、asl ファイル内に記述がない可能性が高いと思います)

asl ファイルに Game Time を操作するための記述がある場合は、手動でも自動でもラップを取れば Game Time のラップが記録されます。

Autosplitter の使い方

Livesplit 本体の他に、最低でも asl ファイルが必要です。
 asl ファイルによっては、asl ファイルの内容と Livesplit で設定する区間の数と名前とが一致している必要がある場合があり、対応した区間定義ファイル(拡張子 .lss のファイル)も配布されている場合はそれを使うのが無難です。

asl ファイルの内容によって、区間の数も名前も同じでなければダメなものもあれば、区間の順番を入替え可なものや、区間名は任意で可なものなど、ものによって必要な条件が異なっています。
 また、asl ファイルの内容によって、スタート・ラップ・リセット全てが自動化されているものや、一部操作は手動なものなど、自動化される範囲もものによって異なります。
 注意書きがある場合はよく読んでから導入するようにしましょう。

asl ファイルの入手場所

AutoSplitters.xml - GitHub

Livesplit には Splits Editor にゲームタイトルを入力すると Autosplitter の有無を検索してくれる機能があり、おそらくはここで公開されているものを参照していると思います。

Split Editor画面のAutosplitter検索の例01
Autosplitter と LoadRemover がある場合の例

Split Editor画面のAutosplitter検索の例02
Autosplitter がある場合の例

Split Editor画面のAutosplitter検索の例03
Autosplitter がない場合の例

ここで表示されなくても別の場所で配布されている場合もあるため、SRC など他の場所で配布されていないか確認してみましょう。

ASL List

上の AutoSplitters.xml から自動生成された一覧表、とのことです。

Speedrun.com

ゲームタイトルごとのページ内の "Resources" や "Guides"、"Forum" などで asl ファイルが配布されていたり、導入方法の説明が記載されている場合があります。

その他、個人配布・導入説明など

ざっくりと検索して見つけたページを掲載しており、これが全てという訳ではなくあくまで一例としての掲載です。ご了承ください。

CSRTAforLiveSplit
洞窟物語改造・解析サイト CSHackers

洞窟物語の asl ファイル配布、導入方法の説明。

livesplit用の自動でラップタイム記録してくれるやつ
wormのブロマガ

アイワナ系の asl ファイル配布、導入方法の説明。

NieR:Automata RTA 自動タイマー導入方法まとめ
toufoo1021のブロマガ

NieR:Automata の Autosplitter 導入方法の説明。

「クラッシュ・バンディクー ブッとび3段もり!」RTA用タイマーとLoad Remover/AutoSplitterの導入について
note

クラッシュ・バンディクー ブッとび3段もり! のLoad Remover、Autosplitter 導入方法の説明。
 このゲームタイトルの場合は asl ファイルではなく専用の dll が必要なので、他の Autosplitter と比べると特殊です。

Livesplit の導入

asl ファイルの内容によって実際に必要な設定内容が異なるため、私が一般的だと思う範囲での説明にとどまります。
 ゲームタイトルごとの詳細な設定については、配布ページなどの説明文を読んだり、そのゲームタイトルの Speedrun コミュニティ内で使い方を知っている人を探して聞いたり、自分で asl ファイルの内容を確認してください。

2 通りの導入手順

大きく分けて 2 通りの導入方法があり、Split Editor から導入する方法と、Layout Editor から導入する方法です。
 ゲームタイトルによってどちらか好きな方法で導入出来たり Layout Editor からしか導入できなかったりと利用できる方法が異なる場合がありますが、Split Editor から導入する方法が利用できるならこちらの方が楽だと思います。
aslを使うための2通りの方法

導入の際の注意

2通りの導入方法の両方が可能な Autosplitter の場合、どちらか片方の方法を選択してください。両方の方法で導入してしまうと、Autosplitter が正常に動かなくなる危険があります。

Split Editor からの導入

Split Editor に Game Name を入力するとデータベースから自動的に asl が検索され、データベースに asl が登録されていると Activate ボタンが有効になるのでそれを押すだけで OK。asl が自動的にダウンロードされて使用可能になります。
 必要に応じて Settings ボタンから Autosplitter の設定を行います。この方法で導入した場合、Autosplitter に関する情報は lss ファイルに保存されます。

Layout Editor からの導入

データベースに無い asl の場合はこちらの方法で導入する必要があります。配布されている asl や自作の asl の場合はこちらの方法で導入します。
 自分で用意した asl を任意の場所に保存し、Layout Editor に Scriptable Auto Splitter を追加して、Scriptable Auto Splitter の設定画面で用意した asl の場所を指定します。
 必要に応じて Scriptable Auto Splitter の設定画面で Autosplitter の設定を行います。この方法で導入した場合、Autosplitter に関する情報は lsl ファイルに保存されます。

  1. Livesplit の右クリックメニューから Layout Editor を開き、レイアウトに "Scriptable Auto Splitter" を追加します。(追加する場所はどこでも問題ないと思います)
    Layout Editor
  2. "Layout" ボタンを押して Layout Settings 画面を開き、Scriptable Auto Splitter タブの "Script Path" に asl ファイルの場所を指定します。

Autosplitter の設定

Split Editor の場合は Settings ボタンを押して開いた画面に、Layout Editor の場合は Scriptable Auto Solitter タブの中に Autosplitter の設定があります。
settings により利用できる設定項目

標準で start, split, reset の3つのチェックボックスがあり、asl ファイルによっては区間ごとのチェックボックスも表示されるものもあります。
 それぞれのチェックの有り無しによって、それぞれの動作が有効か無効かを切り替えることができます。

Autosplitter の作り方

公式ドキュメントに書いてあるけどこの記事には書いていないことも、この記事に書いてあるけど公式ドキュメントには書いていないこともあります。実際に作るならば公式ドキュメントも読んでください。

ここで説明する作り方は「私の作り方」であり、あくまで一例です。
 また、この記事では基本的な範囲の説明にとどまっています。応用編は別の記事で説明しているので、必要に応じてそちらをご確認ください。

注意事項

RTA の挑戦中にプレイヤーが本来知り得ないゲームの内部値を見る行為は、SRC では禁止行為であると明記されています。
 この記事は不正行為を推奨するものではなく、あくまで Autosplitter を作るための知識を広めるための記事であることをご承知ください。
 また、メモリアドレスの特定やスクリプトの実行においてゲームや PC に何らかの不具合が生じ得る場合もありますが、自己責任にてお願いします。

おおまかな工程

大きく分けて3つの工程があります。

  1. ポインタパスの特定
    • 利用するゲーム内の値を決める
    • そのゲーム内の値があるメモリアドレスを値のスキャンなどで調べる
    • その値のポインタパスをポインタスキャンなどで調べる
  2. スクリプトの記述
  3. 動作確認・デバッグ

基本的にこの順番で Autosplitter を作りますが、上手くいかない場合は前の工程に戻ることもあります。

ポインタパスの特定

最初の方に書いたように、Autosplitter はメモリ上の値を読み取ってタイマー操作の種類やタイミングを決めています。
 タイマーを操作するために自分が欲しい値・ゲームを動かすために存在しているハズの値を考えて、それが格納されているメモリアドレスを特定する必要があります。

ここでは主にポインタスキャンという手法について紹介します。

利用するゲーム内の値を決める

Autosplitter はメモリ上にあるゲーム内の値を利用します。

Autosplitter に都合の良いゲーム内の値に当たりを付けて、実際の値の変化を観察し、Autosplitter で利用できる値であるかを判断します。

当たりを付けた値に対して、値のスキャンが上手くいかない、ポインタスキャンが上手くいかない、など上手くいかない場合もあります。 そのような場合は他の値を検討するのもひとつの手です。

ポインタパス

基本的にゲームの値が書き込まれるメモリアドレスは固定されていません。
 ゲームを起動するたびに、あるいはステージを選択するたび、その他いろいろなタイミングで値が書き込まれる場所が変わってしまいます。

一方で、そのゲームのプロセスにおいて「特定の値が書き込まれるアドレスへのポインタ」が特定のアドレスに存在しており、この特定のアドレスをベースアドレスと言います。
 ベースアドレスはゲームプロセスから見ると必ず同じアドレスにあり、ゲームの再起動などをしても変わりません。

また、ベースアドレスが示すアドレスから特定の bit 数だけ移動した位置に目的のポインタや値がある場合があり、この特定の bit 数をオフセットと言います。
 オフセットは複数ある場合もありますが、ベースアドレスと同じく、どのオフセットもゲーム再起動などをしても変わりません。

メモリの値を書き換えている命令をさかのぼって解析することで「ベースアドレス+オフセット」の組み合わせを探し出すことができます。
 この「ベースアドレス+オフセット」の組み合わせをポインタパス、あるいはディープポインタと言い、これによって、値が書き込まれるアドレスが変わっても書き込み先のアドレスを追跡できるようになります。

値の検索とポインタスキャン

欲しい値へのポインタパスを特定するためのに、Cheat Engine というメモリ上の値の読み書きができるソフトが公式ドキュメントで紹介されています。

Cheat Engine の使い方についてこの記事では説明しません。
 公式のチュートリアルが用意されているので、各自で学んでください。次のブログ記事も参考になります。
Cheat Engineの使い方をマスターしよう! Step2 - 初期値がわかっている場合 - なんでもチート

値の検索でアドレスを見つけ、ポインタスキャンでポインタパスを見つける部分の実演をした動画も公開しておりますので、よろしければこちらも参考としてご覧ください。

Cheat Engine インストール時の注意点

チートエンジンをインストールしようとした時にエラーや警告が表示されて、インストールに失敗する場合があります。

そのような場合は次の記事を参考にしてみてください。
Cheat Engineがインストールできない場合の解決方法
Cheat Engine のインストール手順

値の検索

基本的には「自分が欲しい値」かつ「ゲーム内に存在しているハズの値」を考えて、その値で検索を行います。
 検索の際に値の型を指定する必要があります。型が分からない場合、型を予想して検索を行ってみて、ダメだったら別の型で検索すると見つかる場合があります。

値の検索結果の絞り込み

次の工程に進むにはアドレスをひとつに絞り込む必要がありますが、検索結果のアドレスが複数あることもあります。
その値が変わるようにゲームを操作して、変更後の値で絞り込み検索を行います。

間違いなくゲームで使用されている値だと確かめたいならば Cheat Engine で値の書き換えを行って、それがゲームに反映されるかを見ますが、場合によってはゲームに用意されているアンチチートプログラムが反応することがあります。
 確信が持てない場合は値の変化の仕方などを見てそれっぽいものに決めますが、他の候補も残しておくと後々役立つ場合もあります。

ポインタスキャン

絞り込んだアドレスを使ってポインタスキャンを行い、ポインタパスを探します。
 一度のポインタスキャンで絞り込めることはマレなので、ゲームを再起動するなどして値のアドレスを変えた状態で再度ポインタスキャンを行いながら絞り込みます。

経験的に、ポインタスキャンは値の検索以上に候補が絞り切れないことが多いです。
 オフセットの数が少なめのものをとりあえずで選んでみて、上手くいかなければ他のポインタパス候補で試してみる、というのを繰り返します。

最後に、ゲームを再起動したり、PC を再起動しても、メモリアドレスの追跡ができているかの確認を忘れないようにしましょう。

難しい場合は妥協するのも手

欲しい値のポインタパス特定が難しい場合もあります。
 ポインタパスが特定しやすい他の値を asl スクリプトと組み合わせて、直接的・間接的に解決できそうならそれで妥協するという手もありますが、スクリプト側で強引に解決することになり得るのでスクリプトが複雑になってしまうリスクがあります。

構造解析機能

Unity 製のゲームであれば、Cheat Engine の c# の構造解析機能を使ってクラス単位でポインタパスの特定ができます。
 別ページにて構造解析機能を使用したポインタスキャンの説明をしておりますので、よろしければこちらもご覧ください。

構造解析機能を使ってメモリアドレスを調べる部分の実演をした動画を公開しておりますので、よろしければこちらも参考としてご覧ください。

Signature scan

欲しい値があるメモリアドレスに「値を書き込んでいる命令」を探すことでそのメモリアドレスを特定する方法です。

メモリ内にあるゲームのプログラムそのものの特定の値の並び(signature)を使って検索を行い、そこに含まれているアドレスを特定します。
 ポインタスキャンではアドレスを特定できない場合などでも有効で、ゲームが頻繁にバージョンアップする場合などにも強いとされているようです。

別ページにてSignature scanの説明をしておりますので、よろしければこちらもご覧ください。

ポインタパスを見つけたら1日寝かす

経験的に、目的の値へのポインタパスを見つけたら1日寝かすと良いです。

ポインタパスを見つけたその日は問題なくても、時間をおいて次の日になるとダメだった、ということがあります。
 次の日まで待つなどして時間をおいて、改めてそのポインタパスが示す値が意図した通りの値かを確認すると良いです。

特殊な情報を利用する Autosplitter

Autosplitter はポインタパスによってメモリの値を読み取ることでタイマー操作のタイミングを判定することが基本ですが、それ以外の情報を使ってタイマー操作をする Autosplitter もあります。

例えば Untitled Goose Game 用の asl ではゲームが出力するログファイルを利用しており、Apple Slash 用の asl ではレジストリの値を利用しています。

また、政剣マニフェスティア用の asl では必要な値のポインタパスを見つけることができなかったために、MOD によって「必要な値」を追加して Autosplitter を実現しているそうです。

スクリプトの記述 - 基礎

公式ドキュメント Auto Splitters Documentation を読みましょう。
基本的なことは、ここに書かれています。

スクリプトの編集に使うアプリケーション

asl ファイルの中身はテキストファイルなので、テキストエディタで編集できます。

もし Visual Studio Code を使用しているのであれば Auto Splitting Language という拡張機能があるので導入すると便利です。

この拡張機能の機能は以下の通りです。

  1. シンタックスハイライトを追加
  2. アクションのコードに C# のシンタックスハイライトが使用される
  3. 有効なアクションとオブジェクトに有用なスニペットを追加

参考のスクリプト

参考のスクリプトが欲しい場合は、ASL List などでたくさんの asl ファイルが公開されているので、その中から参考になりそうなスクリプトを探してみましょう。
 ASL List では asl のフィルタリングができ、ページ左上にある "behaviour" と "features" をクリックするとフィルタ設定ができます。

ほぼ必要最低限の記述のみを取り出した asl の記述例も作成したので、補足資料としてご利用ください。

asl のブロック

asl のスクリプトは複数のブロックから成り、Autosplitter やゲームの起動・終了タイミングに合わせて実行されるブロックと、ゲーム起動中は繰り返し実行されるブロックの2種類に分けることができます。
 繰り返し実行されるブロックは標準 60Hz で実行されますが、必要に応じて秒間の実行回数を指定することもできます。

繰り返し実行されるブロックの中にタイマーを操作するためのブロックがあり、これらのブロックが実行される順番を把握しておくと予期せぬ不具合を減らすことにつながるかもしれません。
タイマー操作アクションの実行順

必要最低限のブロック

作り込まれた asl ファイルほどしっかりとしたスクリプトを記述しなくても、最低限、次のブロックさえあれば Autosplitter を動かすことができます。

state

ポインタパスが示すメモリアドレスにある値を格納する変数をここで定義します。

ゲームのプロセス名をここで指定する必要があり、state{"ゲームのプロセス名"} のように記述します。
 ゲームのバージョンによってポインタパスが異なる場合、バージョンごとに state{"ゲームのプロセス名", "バージョン番号"} を記述します。

ポインタパスが示す値を格納する変数に使用できる型は、ドキュメントの State Descriptors を確認してください。

ここで定義した変数は 60Hz のループごとに毎回自動で更新され、current.変数名 とすればそのループでの値を、old.変数名 とすれば前のループでの値を取得することができます。

start

標準では 60Hz で繰り返し実行され、ここで true を返すとタイマースタートします。

スタートは手動にすることで asl ファイル作成の難易度を下げられる場合もあります。

split

標準では 60Hz で繰り返し実行され、ここで true を返すとラップを取ります。

タイマーが最後の区間だった場合はタイマーがストップします。
 ラップとストップの条件が同じにできず難しいときは、妥協してどちらかを手動にすると asl ファイル作成の難易度を下げられる場合もあります。

reset

標準では 60Hz で繰り返し実行され、ここで true を返すとタイマーをリセットします。
 実行順の図にあるように、rest ブロックによるリセットはタイマーが計測中かポーズ中しか働きません。タイマーストップ状態で自動リセットを行いたい場合は別の方法が必要です。

リセットは手動にすることで asl ファイル作成の難易度を下げられる場合もあります。

ロードタイムリムーバを作る場合

ゲームのロード時間をタイムから除くロードタイムリムーバを作る場合は、次のブロックの内、少なくとも一つは必要です。
 次のブロックを使用する場合、Livesplit の Timing Method を Game Time に設定するのを忘れないようにしましょう。

isLoading

標準では 60Hz で繰り返し実行され、ここで true を返している間は Game Time のカウントがストップします。

ロードリムーバでタイマーのカウントを停止したい場合や、IGT 計測のため常に Livesplit とゲーム内タイムとを同期させたい場合などに true を返します。

gameTime

標準では 60Hz で繰り返し実行され、ここで TimeSpan オブジェクトを返すと、Game Time をその時間に同期します。

IGT 計測などで使用するブロックです。

時間の同期は一定間隔で行われ、同期と次の同期までの間の時間は Real Time と同じように Game Time の時間がカウントされます。
 同期と同期の間に Game Time のタイマーが進んで欲しくない場合は、isLoading ブロックで常に true を返します。

TimeSpan オブジェクトは経過時間を表すためのオブジェクトで、Livesplit 内部でのタイム(つまりはタイマースタートからの経過時間)も TimeSpan です。
 そのため、ここでは時刻を表す DateTime ではなく経過時間である TimeSpan を使用します。

スクリプトの記述 - 発展

より柔軟・より高度な autosplitter を作りたいならば、Livesplit あるいは ゲームの起動・終了によって呼び出されるブロックを使用したり、Autosplitter の有効・無効を切り替えるための追加設定を増やすことなどができます。

Livesplit とゲームの起動・終了によって呼び出されるブロックの呼び出しタイミングは次の図のようになっています。
起動・終了に関連したアクション

タイマー操作と関係のあるブロック

update

標準では 60Hz で繰り返し実行され、start や split などのタイマーコントロールに直接関係のあるブロックの前に実行されるため、ループごとの変数の更新などに利用できます。

ここで false を返すと、そのループでの start, isLoading, gameTime, reset, split が実行されません。
 例えば、バージョン情報で条件分岐して、ポインタパスが特定できているバージョンでは true、それ以外では false を返すようにして、ポインタパスが分かっていないバージョンでは Autosplitter が動かないようにすることもできます。

初期化など

startup

スクリプトが最初にロードされたときに実行され、ゲームプロセスがない状態でも実行されます。
 settings の記述が行える唯一の場所です。

init

ゲームプロセスが見つかるたびに実行されます。
 ゲームの再起動などによっても実行され、ゲームのバージョンチェックなどにも利用できます。

イベント

ver1.8.17 からタイマー操作時のイベントが標準で利用できるようになりました。

onStart

タイマースタート時に実行されるブロックです。
 自動スタート時でも手動スタート時でも実行され、変数の初期化などに利用できます。

onSplit

ラップ時に実行されるブロックです。
 自動ラップ時でも手動ラップ時でも実行されます。

onReset

タイマーリセット時に実行されるブロックです。
 自動リセット時でも手動リセット時でも実行されます。

グローバル変数的な変数の利用

vars.変数名 のようにして任意の変数を定義でき、この方法で定義した変数は次のループに移っても値を保持しています。
 必ず値が代入されている状態で読み取りを行う必要があり、startup や init で初期化しておくと安心です。

自動操作の ON/OFF

Options

標準的な機能で、自動スタート、自動ラップ、自動リセットをそれぞれ ON/OFF できます。

このチェックボックスが操作可能になるかは、その .asl での start { }, split { }, reset { } それぞれのブロックの有無で決まります。

チェック ON の時はそのブロック内の条件分岐に従って true or false が返るのに対して、チェック OFF の時はそのブロックの戻り値は無視されて常に false が返ったものとして扱われます。(ソースを確認していないので、正確な挙動はこの通りでないかも)

この設定項目があることで注意が必要なのは、例えば start { } 内で自動スタートの条件を満たした時にその if 文の中で変数の初期化を行うような場合で、この場合、手動スタートすると変数の初期化が行われません。
 このような場合は、変数の初期化は onStart { } ブロックで行うようにします。

これらのチェックボックスの値は、それぞれ settings.StartEnabled, settings.SplitEnabled, settings.ResetEnabled で取得できます。

Advanced

startup { } に settings を記述することで、区間ごとにラップを取る・取らないを切り替えるための設定項目が利用できるようになります。
settings により利用できる設定項目

settings.Add で項目を追加して、追加済みの項目を親に指定して要素を追加することで親子構造にすることができます。
 親のチェックが OFF の時、子はチェックの状態によらず OFF として扱われます。

区間名がシンプルに連番の場合、Refunct の asl ファイルが参考になると思います。
 settings を複雑な階層構造にしたい場合、Katana ZERO の asl ファイルが参考になると思います。

更新回数

update, start, reset, split などのアクションは asl が有効でゲームが起動している間は 60Hz でループし、この秒間のループ回数を refreshRate と言います。

必要に応じて startup か init の中で refreshRate を指定することができ、例えば 30Hz にするなら refreshRate = 30; のように記述します。

timer

LiveSplitState 型の timer オブジェクトを使って、Livesplit の内部情報を取得することができます。

LiveSplitState には Livesplit の(おそらくは)ほぼ全ての情報が含まれていて、コンポーネント開発のための情報をまとめた記事の中で LiveSplitState に含まれているタイムに関する情報ついてより詳しく説明していますので、よろしければこちらもご覧ください。

使い勝手が良さそうだと私が思ったものをいくつか挙げておきます。

Time timer.CurrentTime

現在のタイマーのタイムを取得できます。

Time は RealTime や GameTime などをメンバに持つ構造体で、RealTime と GameTime はどちらも TimeSpan? 型。(TimeSpan 型の Null 許容型)

TimerPhase timer.CurrentPhase

計測中、ポーズ中など、現在のタイマーの状態を取得できます。
TimerPhase はタイマーの状態を定義した列挙型。

int timer.CurrentSplitIndex

現在の区間のインデックス番号を取得できます。

番号は 0 から始まるため、1 つ目の区間のインデックス番号が 0、2 つ目が 1、と値が 1 つズレているので注意が必要です。

ISegment timer.CurrentSplit

現在の区間名 string timer.CurrentSplit.Name などが取得できます。
ISegment は区間に関するインターフェース。

LiveSplitState を利用した例

情報表示

東方文花帖の asl ファイルでは asl から Text コンポーネントの表示内容を書き換えを行うことで統計情報を表示できるようになっています。

GameTime に切り替え

ロードタイムリムーバでロードタイムを除いたタイムを計測する場合は GameTime で使用することが前提となります。

Alpha Prime の asl ファイルには、Livesplit が RealTime に設定されている時に「Livesplit は現在 RealTime に設定されています。GameTime に切り替えますか?」というメッセージと Yes/No ボタンを出して、Yes だったら GameTime に切り替える機能が含まれています。

カテゴリ取得

Touhou Luna Nights の asl ファイルでは Livesplit に設定されているカテゴリを読み取って、タイマー操作のための条件を分岐しています。

その他

asl ファイルの記述例にて特殊な用途の asl サンプルをいくつか公開していますので、ご興味があればこちらも参考としてご覧ください。

文法エラーチェックの裏技

Livesplit が asl ファイルを読み込んだ際に文法エラーのチェックが行われ、その結果は後述の DebugWiew で見ることができます。

裏技的な使い方だと思いますが、Livesplit が asl ファイルを読み込んでいる状態で asl ファイルを上書き保存すると即座に再読み込みが行われ、その際に文法エラーチェックも行われるため、DebugWiew を起動して Livesplit が asl ファイルを読み込んでいる状態で上書き保存をしながらスクリプトを書くと即座に文法エラーに気付くことができます。

動作確認・デバッグ

作成した asl ファイルを Livesplit に読み込ませて実際にゲームを起動し、意図したタイミングで意図したタイマー操作ができているかを確認します。

コンマ秒以下の一瞬で値が書き換わっている場合もあり、Cheat Engine では問題なさそうに見えたのに実際に Livesplit に読み込ませるとうまくいかない、ということもあります。

そのように、何らかの原因により意図した通りの動作をしない場合、原因を探して対処するデバッグを行います。

DebugView を利用したデバッグ

デバッグは、いわゆる print デバッグという手法を使うので、asl ファイルの中にデバッグ用の記述をしておきます。print の使い方については こちらのサンプルスクリプトをご確認ください。
 print によるメッセージを表示するためのツールとして Microsoft 製のデバッグツール DebugView が、これまた公式ドキュメントで紹介されています。

DebugView の起動時にフィルタ設定画面が自動的に開いた場合、まずはそのまま "OK" を押します。
フィルタ設定画面

全てのソフトのメッセージを取得している状態なので、他のソフトのメッセージがジャマな時は Livesplit に対応した番号を確認してフィルタを設定すると見やすくなると思います。
 Livesplit のメッセージが表示されなくなった場合は番号が変わっている場合があるので、一旦フィルタをリセットして番号を確認して再度フィルタを設定します。
フィルタ設定例

メッセージ表示のたびに出力される "LiveSplit.exe Information" という文字が不要であれば、フィルタの Exclude 欄に "LiveSplit.exe Information*" と入力すればフィルタで除外できます。

ASL Var Viewer を利用したデバッグ

ASL Var Viewer というコンポーネントを Livesplit のレイアウトに追加すると、asl の中で定義されている変数の値を表示できます。
 変数の現在値を手軽に確認したい時に便利です。

あくまで、変数の現在値を表示するだけで、ログ機能などはありません。
 用途に合わせて DebugView と ASL Var Viewer を併用するのが良いと思います。

デバッグのヒント

特定したポインタパスが示す値が意図しない挙動をする場合、同じ値を持っている他のポインタパス候補を試してみる、挙動が安定している他の値を使えないか考える、などの対策をします。

不具合なく動作することが確認できれば、asl ファイルは完成です。
 ゲームのアップデートによって特定したポインタパスが使えなくなることもあるので、自動アップデートするゲームで Autosplitter がある日突然動かなくなった場合は要因として忘れないでおきましょう。

公開

皆に使ってもらうために、作った asl を公開してみましょう。

利用者にとって導入が楽なのは Livesplit の asl データベースに登録することだと思いますが、登録は任意であり、他の方法で公開することもでるため、好きな方法で公開してみましょう。

データベースへの登録

asl ファイルをデータベースに登録することで、asl を Livesplit の Splits Editor にある Activate ボタンから利用できるようになります。

GitHub の AutoSplitters.xml に必要な情報を追記することで、データベースへの登録が行われます。

登録申請の詳細については公式ドキュメントの "Adding an Auto Splitter" をご確認ください。

AutoSplitters.xml の書式
Game
ここで記述した文字列と、Livesplit の GameName 欄に入力されたゲームタイトルとが一致すると、Activate ボタンが押せるようになります。
Speedrun.com にゲームタイトルが登録されている場合は入力補完が働くので、その登録されたタイトルに合わせると良いです。
略称などでも一致させたい場合は、その数だけ Game タグを記述します。
URL
Autosplitter の動作に必要なファイルのダウンロード元。
asl-help など .asl の他にも必要なファイルがある場合は、その数だけ URL タグを記述します。
Type
Autosplitter の種類を指定します。
.asl の場合は「Script」
.dll の場合は「Component」
Description
Splits Editor に表示させる説明文です。
主に、どのような機能があるか、誰が作者かを書くのが一般的かと思います。
Website
Splits Editor の Website ボタンが押された時に表示させるページの URL です。
例:Speedrun.com のそのゲームタイトルのページ、その Autosplitter を公開している Github ページ、Discord の招待リンク。
Website は省略可。

Speedrun.com にリンクを貼る

各自で配布用のページを用意したうえで、Speedrun.com のゲームタイトルごとのページ内にある "Resources" の "Tools" に配布ページのリンクを貼り、利用者に手動で導入してもらいます。

利用者に手動で導入してもらう必要があるため、"Guides" や "Forum" などに asl 導入方法の説明を記載しておくと利用者の助けになることもあります。

(筆者は Speedrun.com のアカウントを持っておらず、そこにリンクを貼ったり記事を追加する具体的な操作内容を知りません。詳細については各自でご確認ください)

8 件のコメント:

  1. 全体的に読み直して、分かりにくい部分を修正しました

    返信削除
  2. 画像認識を利用した自動ラップ支援ソフトの導入例のリンクを追加しました

    返信削除
  3. reset に関する記述を少し追加

    返信削除
  4. Cheat Engine インストール時の注意点を追加

    返信削除
  5. LiveSplitState を利用した例を追加(GameTime に切り替え、カテゴリ取得)
    データベースへの登録についての説明を追加

    返信削除
  6. スクリプトのエディタについての説明を追加

    返信削除
  7. データベースへの登録についての説明を加筆
    おおまかな工程に加筆

    返信削除
  8. 標準オプションの説明を追加
    イベントの説明を追加
    AutoSplitters.xml の書式にて、Website の説明ヌケを修正

    返信削除