公開できるmodを初めて作ったので大変だったところを書いておく

昨日、自作のmodについてのうすい記事を書いた。

naari.hatenablog.com

このmodを公開するに至って大変だったことをつらつらとかきます

fabricのMixinやInjectsの概念についてのドキュメントが少なすぎる

fabricにはMixinや、Injectsという概念がある。これは元々のMinecraftのコードに自分の好きな挙動を差し込むことができる。

たとえば以下のようなコードがあった場合、

class Example {
  void blah() {
    System.out.println("hogefuga");
  }
}

以下のようなコードを書くことができる。

@Mixin(Example.class)
abstract class ExampleMixin {
  @Inject(at = @At("HEAD"), method = "blah")
  void yo(ci CallbackInformation) {
    System.out.println("foobarbar");
  }
}

この状態で Example#blah() を実行すると foobarbarhogefuga がプリントされる。

また、以下のように処理のキャンセルを行うこともできる。

@Mixin(Example.class)
abstract class ExampleMixin {
  @Inject(at = @At("HEAD"), method = "blah")
  void yo(ci CallbackInformation) {
    System.out.println("foobarbar");
    ci.cancel();
  }
}

こうすることで、本来プリントされるはずの hogefuga はキャンセルされる。これは純粋にもとのメソッドの内容をすべてオーバライドするために使うこともできる上に、特定の条件下でのみバイパスする、といった処理も実現できる。

メソッドが呼ばれる際の引数を参照することもできるため、基本的にはこれを利用してmoddingを行うことになる。

検索して出る情報が少なすぎる

公式のドキュメントを含めて、純粋にこの@Mixinについての情報が少なすぎて大変に困っていた。最終的にはこの@Mixinを使っているmodのソースコードを参考にせざるを得なかった。

tutorial:mixin_injects [Fabric Wiki]

fabric-carpet/ServerPlayNetworkHandler_scarpetEventsMixin.java at af368a159d2c3c287acbd22d9a9c0f0094519c56 · gnembon/fabric-carpet · GitHub

結局実際の実装が一番参考になるのがドキュメントとしておかしい気がしていて、そのうち大きく手を入れることができそうに思った。日本語の情報もないし、もしそれが提供できたら喜ぶ人が結構いるのではないかと思う。

村人のgetOffers()を叩くだけだとダメ

元々のプランだと村人にフォーカスをあてた時にそのEntityの getOffers() を叩いて左上に表示しようかな~という気持ちだったが、そもそもこれが不充分だった。

用語: MerchantEntity について

村人などの「右クリック→画面が開いて取引開始」が実装されてるEntityはすべて MerchantEntity を継承している。

通信の流れ

プレイヤーが MerchantEntity に右クリックをした時、サーバー側に「このプレイヤーがこのEntityにinteractを行った」という趣旨のパケットを送信する。

サーバー側はこのパケットを受信した後、よしなにチェックを行い、最終的にはプレイヤーに「取引のウィンドウを開く」と「取引内容」のパケットを送信する。

この取引内容のパケットを元に MerchantEntity に最新の取引内容をセットするため、このパケットを掴まないとプレイヤーが望んだ情報を提供できない。

つまり、右クリックをしないと取引内容を取得することができない ということになる。

擬似的に右クリックする

これに対してどのような方針で進めるのが最適なのかはわからないが、今回は以下のような方針を取った。

  • フォーカスが MerchantEntity に当たった場合、サーバーにinteractを行うパケットを送信する
  • サーバー側から「取引のウィンドウを開く」のパケットが届く
    • キャンセルする
  • サーバー側から「取引内容」のパケットが届く
  • もし MerchantEntity を直接右クリックしていた場合は以上の処理をスキップする

正直筋が良い方法はわからないままだが、上述したMixinとInjectorsを使用してパケットハンドラーに直接処理を挟むことにした。

offers-hud/ReceiveTradeOfferPacket.java at main · naari3/offers-hud · GitHub

@Mixin(ClientPlayNetworkHandler.class)
abstract class ReceiveTradeOfferPacket {
    @Inject(at = @At("HEAD"), method = "onSetTradeOffers", cancellable = true)
    public void onSetTradeOffers(SetTradeOffersS2CPacket packet, CallbackInfo ci) {
        MerchantInfo.getInfo().setOffers(packet.getOffers()); // シングルトンなインスタンスに情報を流す
        if (!OffersHUD.getOpenWindow()) {
            ci.cancel();
        }
    }

    @Inject(at = @At("HEAD"), method = "onOpenScreen", cancellable = true)
    public void onOpenScreen(OpenScreenS2CPacket packet, CallbackInfo ci) {
        var type = packet.getScreenHandlerType();

        if (!OffersHUD.getOpenWindow() && type == ScreenHandlerType.MERCHANT) {
            ci.cancel();
            ClientPlayNetworking.getSender()
                    .sendPacket(new CloseHandledScreenC2SPacket(packet.getSyncId()));
        }
    }
}

このリポジトリを作ったのはおおよそ1年前だった気がするのだが、パケットハンドラーに手を出すという発想に至れたのはひとえにMinecraftのサーバーを1から作成したことによるものに思える。

画面上になにかを描画するのが難しい

これもドキュメントについての愚痴で、チュートリアル的なものが全くないためにどのような手段を踏むのが正攻法なのかが全く分かっていない。

幸いにも、今回の要件は「MerchantEntityの取引内容を描画する」という、既に同じような実装が存在するものだったのでこれを流用することでなんとかなった。

具体的には、 itemRenderer#renderInGui() を使うことでアイテムのテクスチャつきで描画をすることができる。テキストについても同じように textRenderer とその便利なメソッドが存在する。

もしもうちょっと踏み込んだレンダリングが必要になった場合、どうやって書けばよいのだろう。全くできる気がしない。

1.18になって何故か引数の順番が変わっててワロタ

Minecraftの画面上にテクスチャを描画するためには一般的に DrawableHelper.drawTexture が使われるようだが、この引数が1.17.x と 1.18.x で変更されていた。具体的には以下のように。

// 1.17
void DrawableHelper.drawTexture(MatrixStack matrices, int x, int y, int z, float u, float v, int width, int height, int textureHeight, int textureWidth);

//1.18
void DrawableHelper.drawTexture(MatrixStack matrices, int x, int y, int z, float u, float v, int width, int height, int textureWidth, int textureHeight);

こんなのに一発で気づくわけもなく、「なんで1.18では正しく描画されなくなっちゃったんだろう」とかなり困っていたが、fabricのためのDiscordサーバーで尋ねてみたところ、すぐにこの答えを返してくれた。本当にありがとうございました。

こちらから参加できるみたいです discuss | Fabric

modをCurseForgeにpublishする方法

今回、わりと使えるmodが作れたのではないかという自負があり、伴って一般的なmodの配布場所である CurseForge にも配布することにした。

CurseForge上にプロジェクトを作成する必要があった

ただ、そもそも会員登録すらしていなかったので、会員登録をし、さてどうやってmodを公開するのだろう、と3時間くらいサイト上を彷徨っていた。

  • authors のトップ画面にアクセスする
  • Start Your Project をクリックする
  • あとは流れで

ずっと Dashborad の上を見ていたが、このような新規作成系のボタンがひとつも存在しなかった。こういうのって普通ダッシュボードの上にあるんじゃないの?かなり難しい。

GitHub Actions を利用して公開する

その後、実際に実装した後はmodをプロジェクト上に公開する必要があるが、これがまた難しかった。

.jarファイルを生成した後にプロジェクト上に手動でアップロードする、ということもできるが、昨今のCI/CDの時代にそんなことをしていたら時間がもったいない。自動化するべきである。

これも人様の実装を参考にする

実際に、先程も参考として取り上げたgnembonのcarpetは GitHub Actions を使用してCurseForgeにmodの公開をしている。releaseを打つ度に発火されるようだった。

fabric-carpet/publish-release.yml at master · gnembon/fabric-carpet · GitHub

今回はこれをコピペし、自分のプロジェクトに向けてもう少しだけ調整したものを用意した。

具体的な実装はこれ → offers-hud/publish-release.yml at main · naari3/offers-hud · GitHub

コピペしました!だけだと味気がないので、もうちょっとだけ踏み込んでみる。↓

itsmeow/curseforge-upload を使用してCurseForgeに生成物をアップロードする

CurseForgeにファイルをアップロードするには、itsmeow/curseforge-upload という公開されている action を使用する。

github.com

自分の使い方は以下の通りで、action にトークンやプロジェクトの情報を渡したらあとはよしなに動いてくれる。チェンジログをreleaseのbodyに書けるのがかなり便利だと思った。

      - name: Upload to Curseforge
        uses: itsmeow/curseforge-upload@v3
        with:
          token: ${{ secrets.CF_API_TOKEN }}
          project_id: 566138
          game_endpoint: minecraft
          file_path: build/libs/${{ steps.findjar.outputs.jarname }}
          changelog_type: markdown
          changelog: ${{ github.event.release.body }}
          display_name: OffersHUD v${{ needs.Get-Properties.outputs.mod-version }} for ${{ steps.getbranchinfo.outputs.version }}
          game_versions: 7499,4458,${{ steps.getbranchinfo.outputs.curse-versions }} #Fabric,Java 8,[version (s) for the branch]
          release_type: ${{ needs.Get-Properties.outputs.release-type }}

game_version がすごく難しい

Game Versionというのは、CurseForge内で「そのプロジェクトがどのゲームのどのバージョンに対応したものか?」というのを表すためのもので、例えばこのプロジェクトだと fabricJava 8*11.181.18.1 に対応したmodなのでそれぞれを指定する必要がある。

  • fabric も Java 8 もゲームじゃなくない?と思ったけど、もうそうやって管理されているから仕方がないらしい。

これが結構曲者で、たとえば純粋に 1.18.1 という文字列を指定すると怒られる場合がある。例えば以下のように。

Publish Release · naari3/offers-hud@d02f693 · GitHub

{"errorCode":1009,"errorMessage":"Invalid game version ID: 8897 belongs to an invalid dependency."}

これは 1.18.1 という文字列に対応した Game Version が複数あることが原因で、この場合は全然知らない名前のゲームの1.18.1を指定してしまっていたらしい。

なので、正しくMinecraftの1.18.1に対応したGame Versionのidを発見し、そのidを直接指定する必要があった。

# これは Minecraft の 1.18.1 と 1.18 を指す
release-extra-curse-version = 8857,8830

さてこのidの対応表だが、どこかにドキュメントとしてまとまっているわけではなく、以下に存在するjsonから妥当なものを探し出す必要がある。

[https://minecraft.curseforge.com/api/game/versions?token=[API_TOKEN]]

このjson内で 1.18.1 を検索すると次の2つが発見できる。

{
  "id": 8897,
  "gameVersionTypeID": 1,
  "name": "1.18.1",
  "slug": "1-18-1"
},
// snip
{
  "id": 8857,
  "gameVersionTypeID": 73250,
  "name": "1.18.1",
  "slug": "1-18-1"
},

どちらがMinecraftのものか全くわからん…………………

解決方法としては、CurseForgeのmod検索ページの絞り込みで1.18.1を指定すると次のようなURLに遷移する。

https://www.curseforge.com/minecraft/modpacks?filter-game-version=2020709689%3A8857&filter-sort=4

このうち filter-game-version を確認することで解決できた。今回の場合は 8857 が正しかった。

また、これによって gameVersionTypeID: 73250Minecraft 1.18系 を指すことが分かったため、このidで検索すると Minecraft 1.18 や snapshot に相当する Game Version も発見できる。

{
  "id": 8633,
  "gameVersionTypeID": 73250,
  "name": "1.18-Snapshot",
  "slug": "1-18-snapshot"
},
// snip
{
  "id": 8830,
  "gameVersionTypeID": 73250,
  "name": "1.18",
  "slug": "1-18"
},

本当は一発でこのあたりが網羅的に確認できるのが嬉しいが、どうやらそういった対応表は存在しなさそうだった…

人のmodがオープンソースじゃなくて悲しい

とまあこんな感じで、人の実装を参考にしまくった結果このmodが完成した。

その中で、「そういえばこの処理ってあのmodで実現されていたな、どうやっているんだろう」と思い出し、そのmodのページにたどり着いたりするが、感覚でいうと半分くらいの確率でソースコードが公開されていない。

昨今の問題もあるのでこのあたりについてあまり強いことは言えないが、mod制作の参考に出来ないのはシンプルに悲しかった。もし公開状態であればPRを投げることも出来そうなのに。

おおよその場合において難読化が行われていないので、一応は JD-GUI などを使用することで確認を行える。

ただ、以下のようにMinecraftのdeobfuscatedなソースコードとのmappingは切られた状態でビルドされるため、具体的にどのクラスのどのメソッドと対応しているか?はfabricで使用されているMinecraftのdeobfuscatorである yarn と照らし合わせる必要がありそう。

むずい

Configを実装しなければならない

現状、機能のオン/オフすら出来ない。これだと他modとの競合があり、場合によってはまともに使うことができないだろう。

これについてもConfigを実現するための参考実装を探す必要があるが、どれを参考にすればよいのだろうか…

このあたりについてもチュートリアルは存在しないため、情報収集からデファクトを感じ取る必要があり、結構大変そうに思う。

ここから追記

ここ→ documentation:libraries [Fabric Wiki] に使えるライブラリ一覧がまとまっていて、それぞれ検索して良さそうなものを見繕った。

結果として、ClothConfigを使うのが良さそうに思った。どうやら過去デファクトになっていたAutoConfigも同梱しているらしい。

Classとしてプロパティを実装していくだけでConfigとmodmenuに対応したscreenを実装できる。

@Config(name = OffersHUD.MODID)
public class ModConfig implements ConfigData {
    public boolean enabled = true;
    public boolean ignoreNoProfession = true;
    public boolean suppressVillagerHeadRolling = false;
}

これとlangファイルで以下のようなスクリーンが生成される。嬉しいね

ここまで追記

まとめ

こんな感じで、全てにおいて他人の実装を参考にせざるを得ず、自分ひとりの力では実装しづらい部分が多々あることに気づけた。fabricのDiscordサーバーも存在するので、臆することなくどんどん利用していく必要があるように感じた。

*1:これ違くない??直さなきゃ…

村人の取引内容をHUDで表示できるmodを作った OffersHUD

OffersHUD

最初と最後にダウンロードリンクを貼っておきます。

CurseForgeGitHub からダウンロード出来ます。ぜひ

https://www.curseforge.com/minecraft/mc-mods/offershud

github.com

つくったよ

村人(など)にフォーカスを当てるだけで何を取り引きできるのか左上に出てくるようになるmodをつくった。

動機としては司書の厳選が主で、狙いのエンチャが出るまでやらなければならないこの作業をかなり簡略化出来るのではないかと思って作り始めた。

これは便利

まだexperimental版ということもあって、機能の切り替えとかGUIの位置調整とかそういう設定機能はひとつもない。僕の今後に期待。

今の所はfabricの 1.17.1, 1.18.1 に対してjarファイルをビルドしていて、つまり 1.17.1, 1.18, 1.18.1 がこのmodを使えることになるはず。

もし気になったら使ってみてください。バグがあったら必ず僕に教えて下さい。最悪条件とかが分からなくても良いので。お願いします。

既知の問題

GitHubのissues が最新の状況。今のところは

  • 英雄とかいろいろで価格の変動があった時、その価格がうまいこと反映されない
  • メニューがない 設定が弄れない
  • InventoryHUD+ のポーション表示モードとバッティングしてこのmodのそれが表示されない
    • まあ仕方ない節はあるけど

大変だった

「ほんのちょっとだけどmoddingやったことあるし、開発のための環境構築が出来たんだから余裕で作れるでしょ。たぶんVillagerEntityに取引一覧を取得するためのメソッドも生えてるだろうし。」と思って取り組んだが、実はそんなに簡単じゃなかった。

村人に対して右クリックをすると、サーバーに対して「私はこのエンティティに右クリックをした」という趣旨を伝えるリクエストが流れるが、それに対するレスポンスこそが信頼できる取引一覧であって、それを上手く掴む必要があった。

↑この一文だけで詳しい人なら「あーパケットを掴まないといけないのね」みたいな勘が働いて理解できるだろうし、開発→公開までの苦労についてはまた別の記事にしようかな。→した。

naari.hatenablog.com

きになったらこちらから

CurseForgeGitHub からダウンロード出来ます。ぜひ

https://www.curseforge.com/minecraft/mc-mods/offershud

github.com

きゅうりが本当にうまい

きゅうりまとめ

  • 昨日きゅうりをたべた
    • 洗って
    • 上下のヘタを切って
    • まるかじり
  • 九州のおじいちゃんが母親への仕送りとしてくれることが多々あり、その中に入っているきゅうりが大好きだった
    • おじいちゃんは農家でスーパーを介さずに仕入れられたきゅうりをもらってた
    • 形は不揃いだが、スーパーで買うものよりもうまかった記憶がある
  • このまえ見つけた近所の肉の直売所に立ち寄った際、ついでに野菜を買った
    • この野菜が東北の農家さんが直接持ってきたくれた野菜だった
    • つまりこれもスーパーを介さずに仕入れられたきゅうり
  • おじいちゃんの作ったきゅうりと同じような味でとてもよかった
    • これがオーガニックの味…
    • やっぱりスーパーに並ぶやつは農薬とかそういう味になるのだろうか
  • マヨネーズとか塩とかをかけてもいいけど、そのままもうまいのだ
  • なので、ヘタの部分だけ切り落としてしまえばいつでも食える
    • 最強の料理
  • 最高~

以上です。

GitHubで `git://` が使えなくなったので `https://` などに置き換える必要があった

tl;dr

  • git://GitHubで使えなくなった
  • git:// の変わりに https:// を使うようにした
  • パブリックなリポジトリ以外に対しての変更の可能性もある

The unauthenticated git protocol on port 9418 is no longer supported.

今朝からRubyのアプリをビルドするジョブが以下のようなエラーを吐くようになった。

Fetching git://github.com/sinatra/sinatra.git
fatal: remote error: 
  The unauthenticated git protocol on port 9418 is no longer supported.
Please see https://github.blog/2021-09-01-improving-git-protocol-security-github/ for more information.

既に趣旨を伝えるエラーの文言が見えるが、念の為に手元のマシンでも試してみる。

$ git clone git://github.com/sinatra/sinatra.git
Cloning into 'sinatra'...
fatal: remote error:
  The unauthenticated git protocol on port 9418 is no longer supported.
Please see https://github.blog/2021-09-01-improving-git-protocol-security-github/ for more information.

同じ結果だった。

原因としては GitHub が git プロトコルを明示的に使えないようにしたため。

github.blog

No more unauthenticated Git

On the Git protocol side, unencrypted git:// offers no integrity or authentication, making it subject to tampering. We expect very few people are still using this protocol, especially given that you can’t push (it’s read-only on GitHub). We’ll be disabling support for this protocol.

まだ使っていてすまん…使うのやめます…

ということで、置き換えることにした。

https:// に置き換える

まず、現状の手順で最小の変更手数になりそうな「ジョブランナー側を変更する」を検討した。unencrypted な git プロトコルと記述があったので、もしかして暗号化される git プロトコルも存在するのでは?と軽く調査したが、見る限りでは見当たらなかった。そのため、各個別の git:// を使用している箇所について対応をする方針で進める。

今回はpublicなリポジトリに対してのcloneの操作だったので、特に考えることもなく https:// に置き換えることで対応完了とした。

今回の場合、gitプロトコル経由でリポジトリを取得しているのはGemfile経由のbundle installだったので、Gemfileの先頭あたりに以下の行を追加した。

git_source(:github) { |repo| "https://github.com/#{repo}.git" }

その他にも

先程のgithubのblog曰く、sshプロトコルかつ鍵経由でやり取りをしている場合であっても古いタイプの鍵を使っている場合は影響を受けるらしい。

今回の削除方向の変更は具体的には以下の通り。

もし上記に当てはまる場合は以下の項目を参考にしたほうが良さそう。

https://github.blog/2021-09-01-improving-git-protocol-security-github/#how-do-i-prepare

【ネタバレなし】レヴュースタァライトのアニメと総集編と映画を見た

  • やべ~~~~~~~~すげ~~~~~~~~
  • 全部がメタファーすぎ
  • 自分ごとになってしまいすぎ
  • 曲すご 曲凄すぎ
  • 恐ろしい
  • すげー綺麗に締まったな
  • 超良かった~

これは余談で、モニタースピーカーのある知り合い宅で画面を暗くしてそれなりに大きな音を出して見たんですけど、音の大きさとか画面の感じとか、かなり良かったです。今できる個人規模として最も良かったかも。スピーカーほしすぎ。

アニメを見るのって難しくないですか?

自分の周りの人のアニメを見ている率って結構高くて、特定のアニメの話で盛り上がっているのを見る度に自分からも興味が湧いてくる。

が、しかしどうしても腰が重くて、見るまでに莫大な時間を要してしまう。去年見たアニメは1, 2本くらいしかなかった。

むかし実家に居た頃は弟が地上波で流れるアニメを録画しており、それが流れているので一緒に見る、続きが気になるので時間を合わせて一緒に見る、みたいなことをしていて、局所的にアニメをたくさん見ている時期があった(2016年くらい?)。その頃は凄く楽しく見ていたし、別にアニメが嫌いなわけではないはず。むしろ見てしまえば何でも好きになれるし*1、体験としても良かったと思う。

一人暮らしをしていると自分以外の生活は垂れ流しにならないので、巻き添えを食らうことがほとんどない状況にある。そうすると、自ずとアニメを見る必要があり、これが大変に大変だと思っている。

アニメを見るための術や環境は(今となっては)とても整備されるようになったはずで、dアニメストアなりに加入しておけばおおよそ見れると聞いているし、そうでなくてもニコニコチャンネルだとかアマプラだとかたくさんの手段が用意されているように見える。

そういう問題がクリアになった昨今、単にアニメを見るために「目と耳と頭をすべて使う」ことが大変なのだと思っていた。思っていたが、そうすると普段自分がYouTubeなどで見ているMinecraftの実況動画とか、DTMチュートリアルとかはすごく気軽に見ているので、これだけだと説明がつかない。

それでさっきツイキャスをして言葉に出しながら考えていたら、一旦次のような結論に落ち着いた。

自分がこの状況下に陥った前提で、他の人達が高い解像度を持ってアニメを見て、アニメの考察をし、それを共有する様子をリスペクトしすぎているのではないか?

こういったコンテンツって本来どんな体制で受け取っても良いはずで、例えばプログラミングをしながらとか、誰かと話をしながらとか、なんならMinecraftをしながら、とか。その上で、周りがあまりにもアニメについて愛をぶつけている様子を見ていたので、Minecraftをしながらアニメなんて見ていたらめちゃくちゃに怒られるのではないかと錯覚していた(さすがにMinecraftをしていたら怒る人はいるかもしれないけど、正直知ったことではない気がする)。僕は現状、専門性を持ってアニメを見る必要がない。

もしそのアニメが僕に合っていて続きが気になるようだったら優先度が変わってMinecraftをする手が勝手に止まるはずだし、そういうのは先に上げたYouTubeの動画で同じような体験をたくさんしている。アニメもYouTubeも括ってしまえば同じ動画作品なのだろう。つまり、ただ一人で勝手にアニメへのハードルを上げすぎていただけなのではないかと思った。

ここまで書いて映画館で見る映画のことを思い出した。あの環境はスマートフォンを切る必要があるので映画を見ざるを得なく、かつ最高画質最高音質であることも多いので、コンテンツを受け取るための場として最強すぎる気がする。

さらに他の人のアニメに対する姿勢が気になってきた。僕がYouTubeで雑に動画を見るのと同じ要領でアニメを見ているのだろうか?それとも、映画館とまではいかずとも姿勢を正してアニメを見ているのだろうか?

もし後者だとこの考えがちょっと揺らぎそうだけど、それでも楽しいコンテンツを全く見ないよりは幾分マシかなぁ。もうちょっとアニメが見たい。というか、個人的な時間の使い方として妥当なラインな気がする。

一昨日レヴュースタァライトを全話見たらとても楽しくて、その熱量のまま昨日総集編を見た。今日知り合い宅で劇場版を見てくる。きっと楽しいと思う。

追記

それで、アニメを見る時の姿勢について聞いてみたら、次みたいな回答が得られた。

  • ながら見をしている
    • 飯を食いながら
    • 作業をしながら
    • 仕事をしながら
    • 音MADを作りながら←マジ?
  • ただアニメを見ることに集中する

まあ二極化するよね~、それはそう。質の良いアニメ語りをする方のうち一人は何かの作業をしながらアニメを見たりするそうで、これは訓練によるものなのか、それとも素質なのか、わからないけど凄いなと思ってしまった。

また、この記事で自分が言いたいことはこれまでアニメを見てこなかったことに対する言い訳なのではないか?というのを考えた時に、インプットが大変なのではないか?というところまで辿り着きそう、という話をしている人もいた。アニメの1話はシンプルに概念の量が半端ではない、それを受け取るのはシンプルに大変だ、という話だった*2

そういった面を踏まえた上でもう一度この記事を見てみると、何やらアニメに対して質の良いアウトプットをする人に対して何か妬ましいようなものを向けているようなニュアンスを受け取ってしまった。

ので、ちゃんと明記しておくが、決して「リスペクトしすぎているのではないか?→そんなにリスペクトしないようにしよう!」ではなく、「そのリスペクトと自分の気楽さを両立しよう」という方向性で話を持っていきたい。

元々アニメのインプットを最近していなかったのは自分で勝手にハードルを上げるような気持ちの構え方をしていたからで、その理由としては確かに質の良いアニメ語りに囲まれていたことだが、これは勝手にそういう気持ちを持ってしまっただけで、ハードルを上げる必要なんてどこにもないですよね?

*1:見たアニメの本数が少ないだけで自分の中の水準が低いのかも

*2:そのツイートは消えてしまった、悲しい

2021年の振り返り テクい編

naari.hatenablog.com

やったるぞ

f:id:naari_3:20220102224744p:plain

つくったもの/やったこと (wip含む)

ppt-undo

GitHub - naari3/ppt-undo

個人的にやってるぷよテトで練習をしている時に「今パフェあったよね?」とか言われても時既に遅しでミノを置いてしまったりするんだけど、それを1手戻す(undoする)ためのツールを作ろうとしていた。

このために以下のことをやる必要があった。

  • 7bagの生成ロジックの特定
    • シードの特定
    • シードの使われ方を調べる
  • すべての生成ロジックの再実装
  • 以て「ひとつ戻る」を実装する

この再実装あたりについては、元々のゲームがあまり素晴らしい管理方法をしていない&自分が上書きしきる方法を思いつけなかったのでネクストミノの置き換えをはじめすべてをこちらの匙加減で書き換える方針で進めたためそうなった。全部の処理を追って実装するのが大変で、結局最後まで実装しきれなかった。一応戻るが、どこかのタイミングで壊れる、みたいな感じ。今だったら作り直せるかも。

これに使った要素はこんな感じ。

  • Windows API
    • きらい
  • Rust
    • すき
  • CheatEngine
    • ロジックを追うためデバッガーとして使った
    • かなりすき

skyish

GitHub - naari3/skyish

Minecraftのpluginで、生成されたチャンクのうち99%を削除してスカイブロックっぽく遊ぶために作ったもの。思いつきで作った。

最初はチャンク生成時のなにかに合わせて生成を阻害すれば良いかなと思ったんだけど、文献としてあまり妥当なものが見つからなかったのが大変だった気がする。特にpluginだとサーバー側のバニラの生成処理を上書きするのは大変そうだった。わざと同梱しないようにしているらしい。逆にそれも同梱しているものをnms(net.minecraft.serverの略)とか言うらしい。

阻害は出来ないが、その後の処理を加えることは出来る。Minecraftのチャンク生成後、追加で自前のpopulatorを挟み込むことが出来る。今回の方針としては、チャンク生成後、乱数をとって99%の確率でチャンク全体を空気ブロックで置き換えるようにした。このあたり

でもこれは作っただけになってしまって、結局これで遊ぶことはなかった。南無。

naanes

人生で一度は作りたいものランキング第一位のNESエミュレーターを今回ようやく作った。

GitHub - naari3/naanes: A NES emulator written in Rust.

状況としてはこんな感じ。SMB1だとタイトル、ステータスバーがおかしいのと、スクロールのなにかがおかしいのだけど、なにもわからん。

この前段階でCPUにあたる6502のエミュを作ったのだが、みなさんが御存知の通りNESのCPUのメモリマップのうちいくつかはCPUに繋がっている各種のIOポートに通じている。Rustは所有権に厳しい言語なのだが、このあたりでかなり苦しい思いをした覚えがある。可変参照が複数回作れないとか大変すぎた思い出。今だったらもうちょっとまともに作れるかも。

また、これに際してpistonという描画用ライブラリにPRを送った。

naari.hatenablog.com

エミュレータについて詳しいことは今後絶対に記事にする。

  • Rust
  • piston

tetofu-flip

GitHub - naari3/tetofu-flip: テト譜を左右反転させるchrome extension

以下に詳しい。

naari.hatenablog.com

  • TypeScript

spcy

身内のDiscord鯖用に、spcというSNESの曲で使われる音声ファイルをmp3に変換するbotを作った。

GitHub - naari3/spcy: Discord bot for converting spc to mp3

Rustで作る手前、インターネット上に転がっている数多ものCライブラリに火を吹いてもらう必要があった。pure Rustではなく、Rust用バインディングをたくさん作った。

これについても詳しく記事にしたいな~~

  • Rust
  • bindgen
    • いつでもRustバインドがつくれるぞ! *-sys !!みたいな気持ちになれた

video-distorter

GitHub - naari3/video-distorter

画像をDiscordの歪ませるやつが流行ってたので、それを動画でやるやつを作った。

magickのliquid_rescaleというのが該当するっぽかったので、Rustを使ってやってみた。並列実行がしたかったのかな、あまり覚えてない。

ppt2-sync

GitHub - naari3/ppt2-sync: ppt-sync that supported ppt2

元々ppt-syncというライブラリが存在する。これはMinusKelvinという方のもので、ColdClear(GitHub)という最強のテトリスbotが存在するのだがこれのぷよテト用実装のために使われているフレーム毎の同期用ライブラリとして位置づけられている。

これはデバッグ用プロセスを生成し、あらかじめ特定しておいた描画用バッファ切り替え処理のアドレスを 0xCC に置き換えることで処理に割り込みを入れるためフレームが進んだことを検知できる、というもの。

ぷよテト2が発売された時、同じくしてぷよテト2用のColdClearが制作されたが、こちらではフレーム毎の同期の機能が落とされていた。これはぷよテト2に「デバッグ用プロセスを生成するとゲームが落ちる」ような対策が入るようになり、単純にライブラリを作るのが難しくなったためだった。

そこで自分がCheatEngineでも使われているVEHを使うことでこの問題を回避、実装した、というもの。

VEHについてはかなり面白いことが書けそうなので別記事で詳しく。

bws_bgm

Baby Walking Simulatorというゲームのために作ったmodで、曲を任意のものに置き換えられるようにした。

GitHub - naari3/bws_bgm

某鯖で行われた合作中のコネクトパートが音源が差し替えられたBaby Walking Simulatorをプレイするというもので、そのために作った。つまり、BGMのピッチダウンや開始タイミング等は後から音声編集を使ったわけではなく、本物の実装を使って実現している。

チップチューン風アレンジBGMの制作とゲームプレイ担当はふーふーさん。ゲームプレイが下手くそなせいでパート分の尺を歩くのに2分半も掛かっててワロタ 7.5倍だぞ

ちなみにこのmodはさっきのGitHubへのリンクのReleasesからダウンロード出来ます。やりたい方は是非。

  • C#
  • dnSpy
    • 最高
  • NAudio-Unity
    • dnSpyのエディタでこのライブラリを使用するようにした。正攻法はどうやってやるのだろう。

bot-pool-manifest

個人用の非公開リポジトリ

k8sのためのSSOT用で、GitHub Actionsとかそれ用のbotとか色々用意してた。secretの管理方法がいまいちわからず、直接貼ってしまっているので非公開。

ingress-sg-validator

AWS LoadBalancer Controllerの機能として、ingressのリソースのannotationとしてSecurityGroupのidを列挙することが出来るが、これが存在する/しないの確認はReconcileまで待たないといけない。これが大変長く、いつ失敗したか分からなくなってしまうのでvalidationの段階でチェックしてしまおう!というもの。結局使わなかった。

GitHub - naari3/ingress-sg-validator

  • Golang
  • kubebuilder
    • いいね

gijiri

Discordの通話が文字起こしされると面白いんじゃね~~??というやつ。ぜんぶGCPのSpeech-to-Textを使っている。

GitHub - naari3/gijiri: This is a Discord bot for meeting minutes in voice channel

APIの使用料金が高くなったのでもうやめた。

villager-trading-list wip

Minecraftで村人にフォーカスを合わせただけで取引リストが表示されて欲しい、というやつ。村人の取引厳選に便利そうだったので。

GitHub - naari3/villager-trading-list

ただ、一点誤算があって、村人の取引リストはサーバー側にパケットを投げないといけなくて、そこで詰んでた。そしたらローカルから叩けるメソッドに getTradingList とか生やさないでくれ…

でも後述する体験をした今は結構なんとかなりそうな気持ち。今度やってみようかな。

kareki

自分の勉強用のMinecraftサーバー実装 in Rust

GitHub - naari3/kareki: My hobby Minecraft Server written in Rust

目的としてはRust、Minecraftと仲良くなることだけだが、各種ビジネスロジックを実装している途中から急にすべてがうまく動くようになったのがかなり快感だった。

でも実装した範囲としてはまだまだ。Minecraftとして遊ぶために最低限必要で実装する必要があるロジックが多すぎる。

これについても特に色々なことをする必要があったので別で記事を書く。

ReaScript

GitHub - naari3/ReaScripts: My ReaScripts

naari.hatenablog.com

まとめブログ

いろいろやってた。自分は割と趣味ドリブンの開発が多く、その上で手段としてプログラミングを身に着けてきた節があり、今年もそれを地で行ってた感がある。来年もこの調子で、あとできればもうちょっとSRE的な部分に興味を持てればな~