ドーナドーナ いっしょにわるいことをしよう 感想 (ネタバレなし)

「稼いだ金を力に変えるハルウラレ系RPG」だそうです https://www.alicesoft.com/dohnadohna/ 。エロゲです。 一企業に支配されるディストピア的な街で主人公たちがヒトカリしたりハルウリしたりしながらその企業を倒そうとする物語。 たまたまこれをプレイしている配信を見て、絵が好みだし話は面白そうだしゲームとしても面白いかもと思って買った。 実際ハルウリパートもヒトカリパートも面白くてとても満足でした。人におすすめしたいレベル。

ユニークヒロインのイベント全部回収、全メインヒロインのフィーリングレベル10達成まではやった。エンディングの分岐は一部だけ。

ストーリー

全体的にテンポが良くてよかった。まぁゲーム紹介を見ての通りすごく感動するようなタイプの話ではないけど、常にバカゲー的な楽しさがあったし、その上で全体的なストーリーラインはしっかりしていて違和感はそんなに無かったと思う。

全部がエロシーンなわけではないけど、6人のメインヒロインに対して各フィーリングレベルにイベントを用意してあるの単純にボリュームがすごいと思う。魚介先生の仕事量もすごい。 ただ、エンディングの分岐はヒロイン毎に差分が小さいわりに周回が面倒 (フィーリング値の調整はいいんだけど、何度もラスボスマップ + ラスボス戦やるのが……) だったので、一部しかやってない。 ポルノ、菊千代、キラキラが好きです。

ヒトカリパー

さすがにペルソナや世界樹のような RPG と比べると雑だけど、RPG の楽しさがしっかり抑えられていて RPG の好みが二分しやすい自分にとっても十分楽しい側に入る出来だった。 ただのポチポチゲーではないけど、すごく考えて進めなければならないわけでもない、気軽にやるにはちょうどいいかんじ。 近接は主人公と菊千代がド安定、遠距離からアンテナがバフと全体攻撃、残り1枠はポルノでデバフかけたりキラキラでデバフ + 範囲攻撃だったりメディコで回復させたり。 アリスは使い所が難しいけど時々役に立つ。ザッパは優秀な壁。虎太郎とジョーカーは……

バフ・デバフの影響がわりと強い調整に感じた。とくにボス戦ではアイテムでバフ・デバフを入れると楽。TEC の高さの効果はよく分からん。 MP を使いきっても MP 値をマイナスにしながらスキルを使えて、でも一定以上マイナスになると段階的にデバフがかかっていくシステムは面白かったと思う。まぁ結局雑魚戦相手では MP がマイナスになっても大した影響はなく、ボス戦前には回復させておくというかんじで安定してしまったけど。

ハルウリパート

序盤はヒトカリで手に入るジンザイがしょぼいので初期キャラのメンタルをアイテムで維持していかに長持ちさせるかというゲームだったけど、アイテムやジンザイ枠が揃ってくる中盤以降は「有利な属性を手に入れてほぼメンタル変動しないエース枠」と「不利な属性付与相手にぶつけたり適当に使い潰したりする使い捨て枠」にはっきり分けるのが正解だと思った。 有利属性無しで全員のメンタルを維持するのつらいし、ピルを手に入れるのが地味に面倒 or 運ゲーだし…… こう言うと倫理観が終わってるけど、このゲームには倫理観を崩壊させて向き合うべき (?)。 最終的なエース枠はこんなかんじになった。とくに一番左はハルウリさせてもルックスもメンタルも一切下がらないスーパーエースとなった…… なのでメンタルをカンストさせてるのは完全におまけ。

ユニークヒロインについては高橋菜々実だけ条件を満たすのがやたら面倒だった (+ 自分の趣味とはとくに合わなかった) けど、それ以外は簡単だったのでまぁちょうどいいんじゃないだろうか。 個人的な好みは清水千晴です。


というわけでエロゲと RPG が好きな人にはおすすめです。FANZA や DLsite でダウンロード販売もあります。最後になぜかスクリーンショットをとっていた一場面を載せておきます。

f:id:eagletmt:20210119022000j:plain

API Gateway + Lambda + Rust で開発する (2021-01)

まとめ

この構成で Slack の interactive message や block kit で遊んだサンプルがこれ https://github.com/eagletmt/misc/tree/master/rust/slack-slash-command-sample

Rust 向けの Lambda Runtime

lambda-runtime という準(?)公式の crate がある https://github.com/awslabs/aws-lambda-rust-runtime が、リリースが滞っている。 現在リリースされている中での最新版では async/await の対応すら入っておらず、現在の Rust では正直使い物にならないレベルである。 master には async/await の対応が入ってるのでそれを使うという手もあるが、痺れを切らした Netlify の方が未マージの PR も一部取り込みつつ netlify_lambda という crate でリリースしている https://github.com/awslabs/aws-lambda-rust-runtime/issues/274 。 この netlify_lambda には v0.2 で Tokio v1.0 対応も入っている。 なので現時点では netlify_lambda を利用するのが一番手軽な上にコミュニティの恩恵を受けやすいと思われる。

Lambda の Docker イメージサポート

最初にこのリリースを見たときは zip が Docker イメージに変わっただけくらいの認識だったが、公式に提供されている public.ecr.aws/lambda/provided:al2 等のイメージには aws-lambda-rie というバイナリが含まれており、手元で Lambda を起動するのが手軽になっている点が非常に価値が高い。 https://docs.aws.amazon.com/lambda/latest/dg/images-create.html

これをベースイメージとして Docker イメージを作ることで、手元で docker run -p 9000:8080 my-awesome-app で起動すると curl -XPOST http://localhost:9000/2015-03-31/functions/function/invocations -d '{}' で Lambda のハンドラを動かすことができる https://docs.aws.amazon.com/lambda/latest/dg/images-test.html

これまでも Lambda にアップロードする zip を作るときにはどうせ Docker を使ってビルドしていたわけだし、開発やデプロイのことだけを考えれば Lambda の Docker イメージサポートを利用しない理由は無い気がする。 AWS CDK も既にこの機能をサポートしている。

手元での API Gateway 開発

API Gateway + Lambda で API サーバを作るときにも aws-lambda-rie のおかげで curlAPI Gatewayペイロードを流せば手元で動作確認ができる。 しかしその API Gateway は別のマイクロサービスだったりフロントエンドの JS だったりから呼ばれて使われることが多く、それらとの連携も合わせて手元で動作確認したい。 そこで普通の HTTP リクエストを API Gateway 用のペイロードに変換して aws-lambda-rie のエンドポイントに流すだけの小さいツール https://github.com/eagletmt/aws-lambda-rie-gateway を書いてみたところ、だいぶ便利になった。

cargo watch --shell 'docker build -t handler:dev . && docker run -p 9000:8080 handler:dev を起動しておけばコードを変更するたびに Docker イメージがリビルドされ、普通の HTTP リクエストでアクセスできる状態で開発できる。 普通の HTTP リクエストを処理できるので Slack アプリ開発のようなときには ngrok のプロキシ先にも指定できる。 aws-lambda-rie-gateway はとりあえず自分が必要になった範囲しかサポートしてないけど、API Gateway v1 (REST API) のサポートも入れたりしていくと結構実用的なツールになるかもしれない。 Lambda の Docker イメージサポートと aws-lambda-rie に感謝。

CHUNITHM の手元動画を撮る

チュウニズムと真剣に向き合いたいので手軽に手元動画を撮る方法を調べたらスマホホルダーに磁石をつけて筐体上部の鉄板につけて撮るのがよさそうに思ったので自分もやってみた。タイトーステーションのようなゲーセンだと手元撮影用にスマホアームスタンド的なものを備え付けてくれていたりするんだけど、アームの調整がかなり面倒という問題があったので別の方法を探していた。

とりあえずプロトタイプ的に https://www.daisonet.com/product/4549131357974 を買って足の部分を外して https://www.daisonet.com/product/4549131452815 をセロテープで貼りつけたのがこれ。

f:id:eagletmt:20210108004207j:plain

めっちゃ雑だけどこれでも結構よく撮れた。鉄板のわりと奥めにくっつけるのがポイント (この動画はちょっと手前すぎた)。

これでも十分満足な手元撮影ができるようになったけどスマートフォンにそこそこ強い磁石を近づけた状態になるのが心配なので、もうちょいホルダーと磁石を離して固定したい。あるいは使い捨てるつもりで安いカメラを買ってもよさそうだけど、現代のスマートフォン並の性能を持つ安くて小さいカメラとかあるんだろうか。

2020年の思い出

しゃかいじんななねんめ

去年は https://eagletmt.hateblo.jp/entry/2019/12/30/231206

仕事

立場としては引き続き SRE グループのグループ長として始まりつつ、SRE としての本懐であろうところの reliability に関する取り組みの目標決めを補助してもらう人を一人立て、更に SRE グループ内で reliability にメインで取り組むチームと productivity にメインで取り組むチームとに内部的に分けてみるということをした。これは去年の組織的な再編成により自分が SRE グループ長になったものの、自分が reliability の領域にほとんど興味を持てずリードするのが困難だと判断したというのが主な理由の1つだった。また別の理由として SRE グループが抱えている領域が広すぎて意思決定やレビューのサイクルが長くなってしまっているのを改善したい狙いもあった。しかしこれもあまりうまく機能せず、今年の下期からは内部的なチーム分けではなくはっきり組織上もグループを分けることにした。これが上手くいったかどうかは…… どうだろう、上期よりは改善したように思うが理想にはまだ遠いという感触だろうか。reliability と productivity で分けると結局去年の再編の前に戻しただけのように見えるけど、個人的には「reliability と productivity」で分け直せた点は良くなったかなと思う。以前は「本番と開発」みたいな分け方だった節があり、そのため開発側は本番環境のオンコールを持っていなかったんだけど、今はどちらも共通でオンコールを持つ自然な状態にできた点は大きいかなと思っている。

自分個人の仕事としては今年一年はひたすらレガシーを倒していくことを中心にした。ログ配送基盤を支える fluentd のバージョンを v0.12 系から最新まで上げたり、EC2 で動き続けていたコンポーネントを ECS やその他マネージドサービスに移行したり、自分が入社してから1年目かそれくらいのときから deprecate されていた VPC からの撤退を本格的に進めたり。まぁなんか地味な仕事ではあるんだけど普段の運用の中で「あのコンポーネントはまだ XX だから YY の機能・基盤を利用した改善ができなくて誤魔化すしかない」「不具合が判明したけどすべてが古くて修正が難しい」といったかんじでチクチクと生産性を落とされてる感触があり、そのへんを改善したかった。

今年の思い出を書く上で新型コロナの話は外せないだろう。2月末くらいからほぼフルリモートで働く状態になった。個人的には以前から午前中はリモートで仕事して午後からオフィスにきて仕事することが日常だったし、チーム内にはずっとフルリモートで働いているメンバーもいたので、リモートワークで開発を進めたりミーティングしたりといったことはほとんど苦ではなかった。とはいえ多人数での議論はしにくくなったなとは思っている。全社的には最初は全面的なリモートワークに振り切ったもののリモートワークはつらいという結論のようで、途中から週一での出社が命じられた。しかし自分は納得できなかったのでアンケート経由でフィードバックを書いたり人事の偉い人と話をしたりしてほぼフルリモートの状態を続けている。

趣味

2019年の思い出には色々なライブに行くようになったと書いていたけど、新型コロナにより激減することになった。1月にユニパレ (宮城公演)、リリカル☆ライブ、ノンストップ・ストーリーに行けたのはラッキーだった。その後は中止になったり無観客配信ライブになったりしていったけど、配信ライブだとだいぶ盛り上がりに欠けるなぁと感じている。ライブ会場同様に部屋を暗くして見ると多少気分が高まることは発見した。現地の抽選に落ちても配信ライブを見れるというのは新型コロナの影響がなくなった後にも続いてほしいなと思う。大きいコンテンツだと LV というのが元々あったけど、個人的には映画館で LV 見るのと自宅で配信ライブ見るのとでは大きな差はなく自宅で見れたほうが楽だなという気持ち。VTuber の楽しみ方は色々あると思うけど、3D モデルが動いて歌って踊るのを見るのが楽しいのでホロライブには技術面含めて進化していってほしいし、Bloom が終わってもオリジナル曲を出し続けていってほしいですね。

チュウニズムのレートは MAX 14.83 で終了。まだ虹まで距離がある。階段の精度が安定してきたり指押しや片手トリルが少しずつできるようになったりといった成長を感じてはいるが、なかなかレートに反映されるレベルにはならない。引き続き精進したい。オンゲキのレートは MAX 15.21 で終了ということで虹レにはなった。こっちはレートは大きく上がったものの上手くなった実感はあまりしていない…… 両手トリルが安定してきたのと、あとは譜面の認識力が上がってるかもしれない。緊急事態宣言の影響により長期間ゲーセンに行けない時期がつらかった。音ゲープレイヤーにとってゲーセンは密集でも密接でもない空間なんだが…… そういうこともあって Arcaea を再開したりしていたが、最近は自宅ではプロセカをやってる。ガルパのシステムでチュウニズムができる (誇張表現) のでまぁ楽しい。認識力や縦連力の練習にもなりそう。

今年はメインマシンを新調しつつ Windows に変えた https://eagletmt.hateblo.jp/entry/2020/07/06/025926 。この文章もこのマシンで書かれている。Ryzen は偉大だし WSL2 も一部発展途上ながらも既に十分偉大。これにより PC ゲーもできるようになったのでいくつか手を出してみたけど、結局最後まで続いたのは P4G くらい。緊急事態宣言の頃に Muse Dash をやったりもしたけどあんまり続いてない。一方でギャルゲやエロゲはやった。サマポケをやったり、あとはつい先日からドーナドーナを始めたり。このへんの趣味も復活させていきたい。

今年は特別ハマったような Switch のゲームはなかった。リメイクだと大神、幻影異聞録 #FE Encore、スーパーマリオ 3D コレクションあたりを買って楽しんだ。この中だと大神だけ初プレイだったけど良い作品でした。真・女神転生Ⅲのリメイクは処理落ちがひどすぎて手が止まった。ポケダン DX は買ったけどやはり合わなかった。セカダンも合わなかったし不思議のダンジョン系は致命的に合わないんだと思う。狐が僕を待っているは良かった。他のギャルゲやエロゲでも立ち絵が Live2D になってほしい。ポケモン剣盾 DLC やペーパーマリオオリガミキングは順当に楽しかった。

あとは Google Play Music 終了も個人的には大きな出来事だったかな…… 後継の YouTube Music は見限って Apple Music で生活し始めているが今後はどうなるか https://eagletmt.hateblo.jp/entry/2020/11/21/180331

hashicorp/go-plugin を理解して Terraform provider の情報を得る

人間が Terraform の設定を書くときにはどんなリソースがあるか、どんなアトリビュートやブロックがあるかはドキュメントを読めば分かるけど、機械が Terraform の設定をチェックするときには構造化されたスキーマが欲しくなる。 Terraform の provider はどれも実行可能なバイナリのプラグインとして本体から分離されており、Terraform 本体がそのバイナリからスキーマ情報を得て型チェック等をしているはずなので、プラグインからどうやって情報を得ているのか調べた。 プラグインを書く側のドキュメントはまぁまぁあるんだけど、プラグインを起動する側のドキュメントはまとまったものがなくて調べるのに意外と苦労した……

hashicorp/go-plugin

Terraform や Packer 等の Hashicorp プロダクトのプラグインシステムには https://github.com/hashicorp/go-plugin が採用されている。 ざっくり言うと、プラグインを実行可能なバイナリとして表現し、バイナリを子プロセスとして実行すると gRPC サーバ *1 が起動するので、親プロセスはその gRPC サーバを介してプラグインとやりとりするようなアーキテクチャになっている。

プラグインの起動

起動方法は https://github.com/hashicorp/go-plugin/blob/master/docs/internals.md に書かれている…… と思いきや「You do not need to understand the internals of the handshake, unless you're building a go-plugin compatible plugin in another language」とのことで省略されている。 実装を読んでみると、handshake 用の特殊な環境変数と、プロトコルのバージョンを指定する環境変数を与えるとプラグインを起動できるようだった。 Terraform の場合は handshake 用の環境変数https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2@v2.3.0/plugin#pkg-variables で定義されている。この場合、TF_PLUGIN_MAGIC_COOKIE=d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2 という環境変数を指定すれば OK。 これだけでもプラグインの起動には成功するが、プロトコルのバージョンも指定しないとちゃんと通信できない。 Terraform の場合は https://github.com/hashicorp/terraform/tree/master/docs/plugin-protocol にあるように、現在のプロトコルバージョンは 5 である。 よって Terraform プラグインを起動するときに必要な環境変数PLUGIN_PROTOCOL_VERSIONS=5 TF_PLUGIN_MAGIC_COOKIE=d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2 になる。

プラグインとの通信

このように起動すると、プラグインは stdout に 1|5|unix|/tmp/plugin243689465|grpc| のような1行を出力する。 これの意味はちゃんと https://github.com/hashicorp/go-plugin/blob/master/docs/internals.md に書いてある。CORE-PROTOCOL-VERSION は1固定、APP-PROTOCOL-VERSION は PLUGIN_PROTOCOL_VERSIONS に指定した通りの5、NETWORK-TYPE はおそらく UNIX 環境では unix 固定、NETWORK-ADDR は UNIX 環境では UNIX domain socket のパス、PROTOCOL は Terraform プラグインでは grpc 固定である。 この UNIX domain socket が gRPC サーバになっているので、gRPC でプラグインと通信できるようになる。 Terraform の場合はどういう gRPC サーバになってるかは後述。

プラグインの終了

これもとくにドキュメントを見つけられなくて実装を読んだ。シェルからプラグインを起動すると C-c が潰されていて特殊な終了方法があると気付きやすくなっていて気が利いてる (?)。 実はプラグインが起動する gRPC サーバはプラグインの種類毎に実装されたサービスだけでなく、GRPCBroker と GRPCController と呼ばれるサービスも共通で実装している。 このうち GRPCController が Shutdown() という RPC を持ってるので、これを呼ぶと終了できる https://github.com/hashicorp/go-plugin/blob/v1.4.0/internal/plugin/grpc_controller.proto 。 retruns Empty になってるけど Shutdown() を呼ぶと gRPC サーバも終了するので Empty のレスポンスを正常に受け取れることは無い。 正常に処理が進めば Shutdown() でプラグインプロセスも終了するはずだけど、hashicorp/go-plugin の実装では一定のタイムアウト後にプロセスを kill しているみたい。

Terraform プラグインの gRPC サーバ

ドキュメントとしては https://github.com/hashicorp/terraform/tree/master/docs/plugin-protocol にあるんだけど、実際に実装で使われてるのはこっち https://github.com/hashicorp/terraform-plugin-go/blob/v0.2.0/tfprotov5/internal/tfplugin5/tfplugin5.proto 。 Provider の GetSchema() を呼ぶと resource、data source の一覧を取得することができるので、これでようやく目的を達成できる。

type のシリアライゼーション

上記の proto を見ていると、Attribute の type が bytes 型になっていることに気付く。 ここには Terraform 上の型 *2JSON 形式でシリアライズされた値が入っており、シリアライズの方法は https://github.com/hashicorp/terraform/blob/master/docs/plugin-protocol/object-wire-format.md#schemaattribute-mapping-rules-for-json に書かれている。 なので GetSchema() の結果からアトリビュートの型を知りたい場合はこれに従ってデシリアライズすると分かる。

Terraform の service discovery

ここまでで Terraform プラグインのバイナリがあればそこから情報を引き出すことができるようになったので、あとは Terraform プラグイン自体を手に入れる必要がある。 Terraform プラグインhttps://www.terraform.io/docs/internals/remote-service-discovery.html にある方法で見つけることができる。これはちゃんとドキュメントが書かれているのでその通りに実装すればいいだけ。 公式レジストリから手に入れるにはまず https://registry.terraform.io/.well-known/terraform.json にアクセスして providers.v1 のパスを知り、そこから https://www.terraform.io/docs/internals/provider-registry-protocol.htmlAPI で見つければいい。

dump-tf-schema

ここまでを実装したのがこれ。

github.com

Terraform プラグインの理解の参考にどうぞ。

*1:厳密には Go の net/rpc のサーバが起動するパターンもあるが、Terraform の場合は gRPC

*2:正確に言うと type constraint

Go のコードを Rust から呼び出す

近年のツールは Go で実装されていることが多く [要出典]、CLI だけでなくライブラリとして API も公開されていることも多くてそのツールを自作のツールに組み込むことも容易になっている。 しかしそれはあくまで自作のツールも Go で書いている場合で、言語の壁を超えることは難しい。

と思ってたんだけど、cgo を使えば Go でわりと手軽に C ライブラリを作ることができて、C ライブラリの呼び出しは色々な言語でサポートされているので、C のインターフェイスを経由すれば思ってたよりは手軽に他言語から Go のコードを呼び出せることに気付いた。

github.com

これは https://pkg.go.dev/cuelang.org/go/cue を使って cue export 相当を Rust からできるようにした例。 C の貧弱な表現に合わせたりメモリ管理の手間があったり Rust の文字列へのコピーのオーバーヘッドがあったりするけど、bindgen を使えば FFI の宣言を自動生成できるので、これくらいのコード量で Rust から Go のコードを呼び出せるようにできた。

やってることとしては、build.rs の中で go build -buildmode=c-archive を実行して .a と .h を生成し、.a を静的リンク対象に追加しつつ .h から bindgen で FFI の宣言を生成しているというかんじ。 Go の世界には C における const の概念が無いので、const char * を受け取るような関数を定義するときは typedef const char *const_string_t みたいな定義を preamble に書いておいて C.const_string_t を受け取る関数として定義して C の世界に export すればいい。 preamble とか export とかを特殊なコメントとしてやる設計もやはりあまり好きになれない……

ここまでで crate として動くものはできるんだけど、この crate を publish しようとすると docs.rs の環境でビルドできないという問題がある。docs.rs のビルド環境ではネットワークアクセスが禁止されていて、build.rs の中から Go module のダウンロードができないからだ。 これを回避するには go mod vendor で依存モジュールのコードも含めてパッケージングして publish するしかない、と思う。 あと地味な問題として go build がデフォルトでビルドに使うディレクトリが docs.rs の環境では書き込みを禁じられているので、if std::env::var("DOCS_RS").is_ok() { cmd.env("XDG_CACHE_HOME", "/tmp/.cache"); } みたいに XDG_CACHE_HOME を変えておく必要がある。

switch_point では ActiveRecord v6.1 以降をサポートしないことにした

switch_point を4年ぶりにリリースした。このリリースは主に ActiveRecord v6.1 以降をサポートしない意志を表明するためのものである。

github.com

switch_point は6年前に仕事で困ったことを解決するために書いた gem である。経緯は https://eagletmt.hateblo.jp/entry/2014/09/22/203819 を参照。この記事にある「Rails の激しい変更についていきやすい設計・実装」は成功したと思っていて、バージョンや respond_to? による分岐を一切せずに ActiveRecord v3.2 から v6.0 までサポートすることに成功している。

しかしまもなくリリースされるであろう ActiveRecord v6.1 では ActiveRecord::ConnectionAdapters::ConnectionPool#spec が消えて、ついに switch_point が壊れることが分かった。バージョン分岐を許容すれば直せそうな気がするが、しかし ActiveRecord v6.0 で本家に R/W Splitting 用の機能が入った https://guides.rubyonrails.org/active_record_multiple_databases.html 以上、switch_point を使えるようメンテする意味も無いと思い、ここで switch_point は終了させようと思った。

正直 v6.0 でこの機能が入った時点で switch_point は使えなくなるかと思っていたけど、運良く壊れずに済んでいた。よって ActiveRecord v6.0 では本家の機能と switch_point の両方を使えるので、switch_point からの移行パスとしてはまず ActiveRecord を v6.0 にし、この状態で switch_point から本家の機能へと移行することを想定している。