セーブポイント

特にジャンルの決まってない雑記です。

Another Super Mario Bros. Wiiを日本版ディスクに対応させる

マリオWiiの有名な改造作品の中に、Another Super Mario Bros. Wiiというやつがあります。 以下からダウンロードできます。

newerteam.com

ただし、上の公式サイトには以下のような記載があります。

This mod is compatible with all US game discs, and version 1 of the European release. Japanese discs and European v2 are not supported.

「日本版に対応してないのかよ」と思うのですが、実は日本版もサポートされています。実際にダウンロードしたファイルに同梱されているマニュアルを読むと、以下のように記載されています。

同梱されているマニュアルより

どっちが正しいねん、と思うんですけどまあ同梱されているファイルの方がより最新版であると一般的には考えられるでしょう。

で、これで動いてくれるならいいのですが、改造まとめWikiに以下のような記載がある通り、2-城で進行不可能になるバグが存在します。

New スーパーマリオブラザーズ Wii 改造まとめ Wikiより

手っ取り早い処置は02-24.arcを削除してしまうことなのですが、それではもったいないです。なので、今回はこれを修正します。

パッチの修正

改造まとめWikiではステージを改変することによりバグを回避していますが、そもそもパッチが日本語版でもちゃんと適用されるようにすればいいはずです。そういうわけで、ここでは直接Riivolutionのパッチを修正することにします。

事前準備: RAMのダンプ

パッチを修正するにあたってメモリの中身を直接確認しながら作業する必要があるので、Geckoのコードを変換するときのようにマリオWiiのメモリダンプが必要です。

メモリダンプはどのように用意してもいいですが、自分はパソコン内で作業を完結させたかったのでDolphinの機能を利用しました。ここではその手順を載せておきます。

必要なものは以下の通りです。

まず、Dolphinを起動するときに"-d"というオプションを付けて起動します。Windowsの場合、以下のようなショートカットを作成すればよいです。

末尾に-dを付ける

Dolphinが起動したら、メニューから「表示」をクリックして「Memory」にチェックマークを付けます。この状態でゲームを起動してエミュレーションを一時停止し、Memoryウィンドウの右下にある「Dump MRAM」を押すことでMEM1領域、「Dump ExRAM」を押すことでMEM2領域をダンプできます。ダンプしたデータが保存される場所は設定の「フォルダ」タブから確認・変更できます。

以上でmem1.rawmem2.rawというファイルが入手できます。今回のケースではMEM1領域のデータしか使いませんが、他のゲームでMEM2領域のデータが必要になった場合はこの方法でメモリダンプを自分で準備することができます。

バイナリエディタmem1.rawを開き、最初の6バイトがゲームID(今回の場合はSMNJ01)になっていればおそらく正しくメモリのダンプができています。

メモリダンプを基にパッチを修正する

適当なテキストエディタAnother.xmlを開きます。自分はVS Codeを使います。

Another.xml

最初開いたときはインデントが崩れていたので、直しました。

今回問題となっているのは、patchというブロックの下の方にあるmemoryという要素です。Riivolutionは基本ファイルの置き換えをするツールという認識だと思いますが、メモリの書き換えも行うことができます。

memoryという要素はoffsetに指定されているアドレスの位置の値をvalueで指定されているものに書き換えるという処理を行う*1のですが、ここに問題があります。それは、offsetがディスクのリージョンごとに違うという問題です。

先ほどメモリダンプを用意しましたが、同じゲームでも日本版と海外版で異なるデータが得られます。まあ、当然と言えば当然なのですが、これが少し厄介です。本来これを修正しようと思ったら海外版のメモリダンプも必要になってしまうのですが、今回は日本版ディスクにも対応しているNewer Super Mario Bros. Wiiのパッチを参考にすることにします。

NewerSMBW.xmlを見てみます。Anotherと同じアドレスをしているものが無いかなと探してみると、ありました。

NewerSMBW.xml

どうやら、0x802F118Cあたり(US版基準)の値を書き換えることでセーブデータファイルの名前を変更していて、0x80328130あたりの値を変えることで何か特殊なことをしているっぽいです。(記事下部に追記あり)実際、日本版のmem1.rawの0x2F0FACから8バイト先あたりまでの値を見てみると、以下のようにセーブデータファイルの名前の位置に対応しています。

wiimj2d.sav

AnotherとNewerのどちらも共通して0x80001800からの値を書き換えているのですが、Newerのパッチから察するにリージョンに依存しないのかなという感じなので、とりあえず放置です。

以上の方法で修正したAnotherのパッチは こちら に置いておきます。(パスはanotherです)

今実機環境がすぐに用意できないので動作チェックしてないのですが、多分動いてくれるはず…。

追記

パッチの仕組みをよく考えないまま記事を書いていました。すいません。

Anotherのパッチの本体は0x80001800の位置に挿入しているやつです(パッチの一番下に書いてある一番長いやつ)。これを日本版にも適用してあげれば、多分バグが直ってくれるはずです。

で、0x80327E98の位置に0x80001800という値を挿入していているわけです。これは完全に間接アドレス指定方式と同じ構図です。なんで気が付かなかったのか。エンジニア名乗るのやめたら?

というわけで、多分何らかの専用のプログラムをメモリ上の0x80001800の位置に展開していて、それを読み込ませているということなんでしょうね。

自分としても、もやもやがスッキリしました。別に書き換えたパッチ自体は正しいので、ファイルを新たに書き換える必要はないです。

*1:originalというパラメータはこれに合致しているものだけを置換するようにするということだと思います

サバイバルで岩盤をアイテムとして入手するテクについての理解 Pt.1 [Minecraft 1.12]

本当は解説記事として出したかったものなのですが、理論があまりにも自分にとって難解だったので、現時点での理解をまとめたメモです。
Minecraft 1.12における話であることに注意

はじめに

先日、以下の動画を見つけたのですが、謎の技術すぎた(当社比)ので色々調べました。が、元情報が英語ゆえあまり理解できていないので、このようにバラバラに記事にしていくことにしました。


www.youtube.com

この記事は、上の動画と以下の動画から得たざっくりした情報に加えて、自分のために補足した情報を記載しています。英語が出来る方なら、一次情報を当たった方が良いと思います。

ところで、ここまで読むとこの記事のタイトルと中身が若干一致してない?と思うかもしれません。タイトルからの内容の想像の容易さ・キャッチーさを優先してこのようなタイトルにしてしまったのですが、実際は後に説明する技術によって岩盤のみならずワールド上に存在すらしないブロックを入手できます。この点は申し訳ありません。

キーワード

  • Population Supression
  • Update Suppression
  • Instant Tile Tick / Instant Falling
  • Blockstate Corruption
  • マルチスレッド

岩盤についての前提知識

さて、あなたはMinecraftの岩盤というブロックについてどれくらい知っていますか?

minecraft.fandom.com基本的な情報については上記のMinecraft Wikiの通りで、サバイバルモードにおいては採掘不可能であるブロックのうちの1つです。ただし、これは破壊も不可能ということではないというのは皆さんが知っている通りで、バージョンごとに様々なバグが存在してサバイバルでも岩盤を破壊することができます。ですが、このようなバグを用いて岩盤を破壊しても、破壊した岩盤ブロックをアイテムとして入手することはできません。では、どうすれば岩盤をアイテム化できるでしょうか。岩盤についてもう少し詳しく見ていきましょう。

ソースコード中では岩盤は以下のようにゲームに登録されています。

registerBlock(7, "bedrock", (new BlockEmptyDrops(Material.ROCK)).setBlockUnbreakable().setResistance(6000000.0F).setSoundType(SoundType.STONE).setUnlocalizedName("bedrock").disableStats().setCreativeTab(CreativeTabs.BUILDING_BLOCKS));

色々な属性が付加されていますが、注目すべきはsetBlockUnbreakableメソッドです。メソッドの定義を辿ると、以下のように記述されています。

setBlockUnbreakable

Minecraftのブロックは、それぞれ様々な硬さ(=採掘にかかる時間)を持ちます。これを設定するのが、Block#setHardnessです。で、上のコードに従うと岩盤の硬さは-1ということになります。「-1ってなんだよ」と思うかもしれませんが、マイクラ内では硬さが負の値であると採掘不可能という扱いになります*1。もし硬さが正の巨大な実数であれば理論上時間さえかければ破壊可能ですが、そうはなっていません。

ただ、なんらかの方法で岩盤が採掘できたとしても、岩盤をアイテムとして入手することはできません。これが岩盤アイテム化を難しくしている要因の1つです。先ほど岩盤の登録に用いられていたBlockEmptyDropsというクラスを見てみます。

public class BlockEmptyDrops extends Block
{
    public BlockEmptyDrops(Material materialIn)
    {
        super(materialIn);
    }

    /**
     * Returns the quantity of items to drop on block destruction.
     */
    public int quantityDropped(Random random)
    {
        return 0;
    }

    /**
     * Get the Item that this Block should drop when harvested.
     */
    public Item getItemDropped(IBlockState state, Random rand, int fortune)
    {
        return Items.AIR;
    }
}

上記のコードのように岩盤は採掘された際に何もアイテムをドロップしないようにハードコードされているため、真っ当に岩盤を採掘しても何も得られません。

ただし、実は岩盤を採掘したときに岩盤をアイテムとしてドロップさせることができる手法が存在します。それが、ツルハシにシルクタッチのエンチャントを付けることです。シルクタッチは上述したような設定を無視してブロックをドロップさせることができます*2

以上の内容は以下の動画においても解説されているので、動画で確認したい方は参考にしてください。

www.youtube.com

考えるべきこと

さて、シルクタッチのツルハシで岩盤を採掘すればいいということは分かったものの、じゃあどうやって岩盤を採掘するのという話です。実際は硬さ-1のブロックなわけですから、当然正攻法ではどうしようもありません。どうにかして、ゲームにシルクタッチ付きのツルハシで岩盤を採掘したと誤認させる必要があります。

考えられる解決策

プレイヤーがワールド上のブロックを左クリックしたときに発火する処理について見てみます。

PlayerInteractionManager#onBlockClicked

posはプレイヤーが左クリックしたブロックの座標、sideはクリックした面です。

1つ目のifブロック内でブロックが左クリックされたときの処理の呼び出し、および採掘スピードfの計算を行っています。2つ目のifブロックは、ブロックがInstant mining可能であるかの判定をしています。

ここがよくまだ分かっていないんですが、ブロックがInstant mining可能であるとき、ブロックが採掘されてからドロップされるまでの間にブロックをすり替えることが可能です。岩盤のアイテム化は、この特性を用いて行います。

実際にどうやってブロックをすり替えるかですが、上述したコード内を見ると2択で、燃えているブロックを消火する処理(195行目)をトリガーにするか、ブロックを左クリックしたこと(201行目)をトリガーにするかです。で、後者で今のところ上手くいった例は無いようで*3、参考にした動画では消火の処理を利用していました。

次回

思っていたよりも1つの記事が長くなってしまったので、ここで分割します。次回は、実際に消火の処理をトリガーにどうやって岩盤を採掘するかについて見ていきます。岩盤のアイテム化技術について解説が終わったら、Falling Block Swapに手をつけたいです。

*1:ちなみに、ツールの採掘速度を負の値にすると何も掘れないツールになります

*2:例外があり、FullCubeでないエンドポータルフレームなどのブロックはシルクタッチを利用しても入手できません

*3:レッドストーン鉱石を利用しようと考えていたようですが、レッドストーン鉱石をInstant mining可能にするには効率強化8が必要です

日記用のブログ作りました

数学用のブログも持ってるんですけど、もっと気軽に記事ポンポンと投げていける場所が欲しくなったので2つめのブログ作りました。はてなブログに感謝。
Twitterをよく使うようになる前はブログで交流していた世代なので、なんか懐かしい気分です。noteも使ってるじゃないかという話ですが、なんかnoteはお気持ち表明する用のサービスな気がするので、こういう形になりました。 そんなわけで、よろしくお願いします。