はかせるおむつ

ゴミ置き場

Slay the Spire MODの作り方(メモ)

はじめに

Default Mod BaseのWikiを足掛かりに、すべてを読めばSlay the SpireのMODは作れるようになるはずです。

github.com

すべてを説明するのは大変なので、私が悩んだ部分のみを書いておきます。

開発環境構築

Default Mod Baseの使用

Default Mod Baseを使用します。使用しなくても頑張ればMODは作れるでしょうが、すべて一からを用意するのは大変なので使わせてもらいます。

GitHub - Gremious/StS-DefaultModBase: (USE THIS AND BASEMOD IF YOU'RE NEW TO MODDING) This is a minimal, over-commented, "default clean slate" for jump-starting Slay the spire mods.

Default Mod Base Wikiの指示通り、Default Mod BaseのGitリポジトリをzip形式でダウンロードし、自分で用意した任意のディレクトリに展開しておきます。

3つのMODの導入

下記3つのMODをSteam Workshopからインストールしてください。Steamクライアント上でサブスクライブボタンをクリックするだけです。

各MODのGithubのReleaseページからインストールしないでください。

IntelliJでの既存プロジェクトのインポート

Maven開発環境上でMODのためのコードを編集するので、IntelliJを使用します。

Default Mod BaseのWikiでは、ダウンロードしたDefault Mod Baseのプロジェクトをインポートする際に、画面上のインポートボタンから進めています。しかし、IntelliJ IDEA 2022.2.3 (Community Edition)ではそのインポートボタンがありません。下記の通りインポートします。

プロジェクトのインポートとエクスポート

ウェルカム画面が開いたら、Ctrl+Shift+A を押し、project from existing sources と入力して、ポップアップで既存ソースのプロジェクトをインポートアクションをクリックします。

JDK

最新のJDKではMODのビルドに失敗しました。JDK 8が必要です。下記からOpen JDK 8をダウンロードしてインストールします。

www.openlogic.com

File -> Project Structure -> Project Settings -> Projectとたどり、SDKの設定をします。

Mavenプロジェクトとして認識させる

プロジェクトをインポートした後は、IntelliJMavenプロジェクトとして認識させて作業をする必要があります。

If you do not have a Maven tab, double-tap Shift to open the intelliJ search (your best friend!) and type "Maven" - you'll find it there.

Default Mod Base Wikiには上記のようにありますが、簡単に見つけられません。下記の手順でIntelliJMavenプロジェクトとして認識させます。

  1. pom.xmlを選択する。

  2. Shiftキーを2回連続で押して、IntelliJ検索画面を出す。
  3. その選択画面でAdd as Maven Projectを検索して選択する。

DefaultMod.javaの編集

DefaultMod.java内のTODO:から始まるコメント行の内容にしたがって編集します。

パッケージ名の設定

//TODO: FIRST THINGS FIRST: RENAME YOUR PACKAGE AND ID NAMES FIRST-THING!!!

左ペインの黒ドットがついたthe Defaultを自分のMOD名に変更します。

4か所の変更

DefaultMod()メソッド内に4か所を変更する指示があります。その通りに変更すればOKです。

パッケージ化

Mavenプロジェクト内のpackageをダブルクリックすれば、[yourmodname].jarが生成されてMODは完成です。cleanでそのパッケージを削除できます。

SpirePatchの使い方(一部)

Insertの使用

Insertメソッドを使用して、オリジナルのSlay the Spireのメソッドのコードの間に、自分のコードを挿入できます。

挿入箇所の指定の仕方は、locrloclocsrlocsをそれぞれ使用する方法もありますが、Matcherを使用した方法もあります。Matcherを使用した方法では、自分のコードを、任意のメソッドの実行の直前などで実行できます。

@SpirePatch(
    clz = ShopScreen.class,     //コードを挿入したいメソッドが含まれるクラスを指定
    method = "purchaseCard"     //コードを挿入したいメソッド名
)
public class ClickBuyCard {
    @SpireInsertPatch(
        locator= ClickBuyMod.ClickBuyCard.Locator.class     //[packagename].[thisclassname].Locator.class
    )
    public static void Insert(ShopScreen __instance) {
        AbstractDungeon.player.gold += 1;       //ここに挿入したい自分のコードを書く
    }

    private static class Locator extends SpireInsertLocator {
        public int[] Locate(CtBehavior ctMethodToPatch) throws CannotCompileException, PatchingException {
            //MethodCallMatcher()の1つ目に対象のメソッドが含まれるクラスを指定する。
            //MethodCallMatcher()の2つ目の引数に対象のメソッド名を渡す。
            //その関数の直前にInsert()で指定した自分のコードが実行される。
            Matcher finalMatcher = new Matcher.MethodCallMatcher(ShopScreen.class, "playCantBuySfx");

        return LineFinder.findInOrder(ctMethodToPatch, new ArrayList<Matcher>(), finalMatcher);
    }
}

フィールドにアクセスがあったときに自分のコードが実行されるようにするには、FieldAccessMatcher()を使用します。

また、オリジナルのコードの中で元のクラスのフィールドにアクセスしたいときは、localvarsにそのフィールドの名前を指定したうえで、Insertメソッドの引数にその引数を指定します。下記の例ではフィールドcardAtlasを読み書き可能です。

@SpirePatch2 (clz = AbstractCard.class, method ="initialize")
public class CardImgMod {
    @SpireInsertPatch (
            locator = Locator.class,
            localvars = {"cardAtlas"}
    )
    public static void Insert(TextureAtlas cardAtlas) {
        //ここに挿入したい自分のコードを書く。ここではフィールドcardAtlasにアクセス可能。
    }

    public static class Locator extends SpireInsertLocator {
        public int[] Locate(CtBehavior ctMethodToPatch) throws CannotCompileException, PatchingException {
            Matcher.FieldAccessMatcher fieldAccessMatcher = new Matcher.FieldAccessMatcher(AbstractCard.class, "cardAtlas");

            return LineFinder.findInOrder(ctMethodToPatch, new ArrayList<Matcher>(), fieldAccessMatcher);
        }
    }
}

質問は@hotpot774までお願いします。