[Starlight] コードを読み解く

Starlightとは

超簡単にいえばリアルタイムでスプラトゥーン2のレジスタを弄れてしまうツール。

IPSwitchなど他にもスプラトゥーンを弄れるツールはあるけれど、恐らくこれが最強。

Starlightの仕組み

難しいことはわからんので、簡単に仕組みを理解していこう。

void render()

真っ先に飛び込んでくるのがこのvoid render()という関数だろう。

結論から言えば、このvoid render()は常に実行されていて情報を画面に表示している。

情報を表示

この左側に表示されている情報こそまさにvoid render()の役目というわけである。

 if(showMenu){
        drawBackground();
        
        textWriter->setScaleFromFontHeight(20);
        sead::TextWriter::setupGraphics(drawContext); // re-setup context

        textWriter->printf("Welcome to Starlight!\n");
        textWriter->printf("This is a demonstration of C/C++ code running in the context of a Switch game!\n");
        textWriter->printf("Credit to shibboleet, Khangaroo, Thog, Retr0id, and the libnx maintainers!\n");

ここはif文でメニューに入って、そこで文字を表示しているコードです。

この辺りはまだわかりやすいですね。

if(isTriggered(mController, Buttons::RStick))
            mode++;
        if(mode > Modes::END)
            mode = 0;
        textWriter->printf("Current mode: %s\n", modeToText((Modes)mode));

ここはトリガーに関する部分で、Rスティックを押し込むとモードが一つ後ろにズレることを意味しています。

で、その現在のモードを表示するというわけですね。

ちなみに、モードには以下のものが存在します。

モード内容紹介
NONE何も起こらない
FLY空が飛べる
EVENT_VIEWERモーションが切り替えられる
INPUT_VIEWERコントローラの入力が見れる
PLAYER_SWITCHERプレイヤーが切り替えられる
PAINT_ALL全塗りができる
Cmn::StaticMem *staticMem = Cmn::StaticMem::sInstance;
if(staticMem != NULL)
    handleStaticMem(staticMem);

Game::PlayerMgr *playerMgr = Game::PlayerMgr::sInstance;
if(playerMgr != NULL)
    handlePlayerMgr(playerMgr);

Cmn::PlayerCtrl *playerCtrl = Cmn::PlayerCtrl::sInstance;
if(playerCtrl != NULL)
    handlePlayerControl(playerCtrl);
else if(mode == Modes::INPUT_VIEWER){
    mTextWriter->printf("Information not available.\n");
}

Cmn::MushDataHolder* mushData = Cmn::MushDataHolder::sInstance;
if(mushData != NULL)
    handleMushDataHolder(mushData);

Game::MainMgr* mainMgr = Game::MainMgr::sInstance;
if(mainMgr != NULL){
    handleMainMgr(mainMgr);
}

どうやら何かが五回呼び出されているようですが、何が起こっているのかぶっちゃけわかっていません。

変数を定義する

なんか適当に数字を設定してそれを画面に表示させるコードを書きましょう。

今回は十字キーを入力すると値がランダムに変わっていくコードを想定します。

// 乱数を定義
static int random = 0;

// 十字キーを押されたとき
if (isTriggered(mController, Buttons::UpDpad))
    // 乱数を更新する処理

とまあ、コーディングの概要はわかったところで乱数を発生させるコードを書きましょう。

普通のC++なら” #include <random>” などで乱数生成のためのヘッダーを読み込めばいいのですが、Starlightで読み込むとコンパイルエラーが発生します。

sead::Random

Starlightで乱数を生成するにはこれを使います。

これ、何ていうんでしたっけ?クラスそれともコンスタンタ??

よくわからんのですが、これで乱数がつくれます。

sead::Random rand; // 乱数発生器を定義
rand.init(); // 乱数発生器を初期化

メンバ関数(メソッド?)であるinit()を宣言しないと乱数が発生しないので注意だゾ☆

あとはトリガーが発生したときに値を変更するようにかけば良いので、イカのようになります。

// 0 ~ 65535の間で乱数を発生する
if (isTriggered(mController, Buttons::UpDpad))
    random = rand.getU32() % 65536;

getU32()は32ビットまでの乱数生成に対応しているのですが、わけあってとあるサブルーチンでは65535くらいまでしか数が使えないので今回はここまでにしています。

実装してみた

「簡単にStarlightを適応する方法があるで」ってきいたので実践してみました。

まずは自分のスイッチのIPアドレスを確認します。今回は192.168.1.16ですね。

あと、FTPは有効化しておきましょう。これがないとダメです。

make clean
make send S2VER=310 S2ROMTYPE=US IP=192.168.1.16

こんな感じでコマンドを打ちます。

S2ROMTYPEのところは以下のものが利用できます。

パラメータ意味
JP国内版
US北米版
EU欧州版
EveJP前夜祭-国内版
EveUS前夜祭-北米版
EveEU前夜祭-欧州版
TrialUS特別体験版
ShowDL特別試射会

えっ、特別体験版って暗号化されてないんか…

じゃあこっちやればよかったな…

Makefile編集した

まあなんかこのままじゃめんどくさいので一気にインストールできるようにしました。

# TODO (Khangaroo): Make this process a lot less hacky (no, export did not work)
# See MakefileNSO

.PHONY: all clean starlight send

S2VER ?= 310
S2VERSTR ?= 3.1.0
S2ROMTYPE ?= US
IP ?= 192.168.1.16 # add this line

all: starlight

starlight:
	$(MAKE) all -f MakefileNSO S2VER=$(S2VER) S2VERSTR=$(S2VERSTR)
	$(MAKE) starlight_patch_$(S2VER)/*.ips

starlight_patch_$(S2VER)/*.ips: patches/*.slpatch patches/configs/$(S2VER).config patches/maps/$(S2VER)/*.map \
								build$(S2VER)/$(shell basename $(CURDIR))$(S2VER).map scripts/genPatch.py
	@rm -f starlight_patch_$(S2VER)/*.ips
	python3 scripts/genPatch.py $(S2VER)

install: all #Change the command
	python3 scripts/sendPatch.py $(IP) $(S2ROMTYPE) $(S2VER)

clean:
	$(MAKE) clean -f MakefileNSO
	@rm -fr starlight_patch_*

IPアドレスは各自自分の値に変更してください。

まあここは固定IPがいいでしょう。

(starlight) me@DESKTOP-AEBKONR:~/Starlight$ make install
make all -f MakefileNSO S2VER=310 S2VERSTR=3.1.0
make[1]: Entering directory '/home/me/Starlight'
make -C build310 -f /home/me/Starlight/MakefileNSO
make[2]: Entering directory '/home/me/Starlight/build310'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/home/me/Starlight/build310'
make[1]: Leaving directory '/home/me/Starlight'
make starlight_patch_310/*.ips
make[1]: Entering directory '/home/me/Starlight'
make[1]: 'starlight_patch_310/034C8FA7A63B7A87F96F408B2AEFFF6C.ips' is up to date.
make[1]: Leaving directory '/home/me/Starlight'
python3 scripts/sendPatch.py 192.168.1.16 US 310
Connecting to 192.168.1.16... Connected!
Ensuring atmosphere exists...
Ensuring /atmosphere/exefs_patches exists...
Ensuring /atmosphere/exefs_patches/starlight_patch_310 exists...
Sending /atmosphere/exefs_patches/starlight_patch_310/034C8FA7A63B7A87F96F408B2AEFFF6C.ips
Ensuring /atmosphere/titles exists...
Ensuring /atmosphere/titles/01003BC0000A0000 exists...
Ensuring /atmosphere/titles/01003BC0000A0000/exefs exists...
Sending /atmosphere/titles/01003BC0000A0000/exefs/subsdk0

“make install” とすればUS版のスプラトゥーンにStarlightが適応されます。

実際にやってみた

上手く乱数が生成されていることがわかりますね!