20250325

20250325

唐突に書きたくなる!雑多に色々!


書きたい話題とかたくさんあって、実際に下書きは増えてきているのだけど書き切ることが少なくなってきた!なんでだろう?根本としては単に自分の熱の移ろいだとは思うのだけど、その後ろ盾はたくさんありそう。まあ純粋に仕事も趣味も忙しい。ナートロ3があるのに、仕事が過去最高に忙しくて正直デスマーチというところ。やばい。助けてくれ!!!!

エレウィザも、そもそも誘われていたというのも含めてとても行きたいイベントだったんだよな。チケットまで買ってあったのに結局行けず、家で作業しているだけだった。その作業も結局ウニャウニャ言ってるだけで何も進まなかったし…


忙しさにかまけて部屋の掃除がまったくできておらず、机の上も床もすごくゴミだらけになってきた!!!誰かが家にくるような、なんらかのきっかけで掃除をしはじめたりはできるのだけど、そういうのもなく普段から部屋を綺麗にしている人はどういった理由でそれを維持できているのか教えてほしい。それが今年、ないしは来年のなありの目標となるだろう。


昨年末あたりにわんだふるぷりきゅあ!*1を見ていたのだけど、その時にリアタイするために数年ぶりに家でテレビを見る環境を整える必要があった。

どこかのタイミングで友人に買ってもらった Raspberry pi 4 model b が残ってたので、そいつに PX-Q1UD を繋げて録画鯖を立てた。むかーーーーーしこういった構成を立てていた時期と比べると、インターネット上の情報が整備されておりとても簡単に録画鯖が立てられるようだった。なんと docker-compose.yaml として転がっているので、USBで色々繋げておけばコマンド一発で全環境が整備される。チューニングの余地とかはめちゃくちゃあるのだけど、もはや2chの過去ログから謎の用語の正体を探す必要はなくなっていて、こういうのが「知識が開かれる」というのだよな〜と一人で嬉しくなっていた。

で、以後家でテレビをBGMとして流すタイミングがよくある。NHK総合・EテレはBGMとしてはかなり優秀。特に、夜中にやってるような風景を流してくれるやつとか、NHKが作るドラマとかはかなり良い。今は甲子園をやっているが、これはあまり興味がないんだよな。決勝とかになったら見てやるか、くらいの気持ち。民法は、アニメ以外のコンテンツだと自分が元気でなければ厳しいタイミングがある。ニュースですらバラエティノリをやっていて、元気でないときに何故か心が苦しくなるときがある。でも夜中にやってる番組は基本全部楽しいな。あとは「もうこの番組やってないんだ」とか「今こんな感じなんだ」とか、そう思ったりするくらい。

以下はNHKで見られる風景。感動するぜ。

抜かれたTSをEPGStation経由でm3u8のプレイリストにしてVLCで閲覧…という流れを経ているのだけど、EPGStationでチャンネルを選択するたびに新しいm3u8ファイルがダウンロードされる。これのせいでダウンロードフォルダがすごいことになるので、もうちょっとどうにかしたい。


なんか急にSerum 2が来てビビった。なんかexclusiveで配布されてるっぽい様子は見受けていたが、マジで事前告知なしで朝起きたら急にSerum 2がある、という感じだったので流石にビビった。しかも、Serum 1のライセンスを持っている人(つまり、全員)であれば無料でSerum 2にアップグレードできるとのことだった。(!?!?!?!?!?!?!?!?!?!?)

しかもアプグレ内容も本当に素晴らしかった。詳しく語らないが、Serum 1発売以後に増えていた新型シンセの音作りの部分みたいな機能がたくさん増えていて、しかも触り心地がかなり良い、みたいな。Serum 1を初めて触ったときのような、「なんかわからんけどツマミを動かしたらめっちゃいい音に変わる!」が、またやってきた感じ。

個人的には(もともとAbleton LiveのGranulator 2を触り続けていたものあるんだけど)Granularがめちゃ嬉しかった。ScanとOffsetをスイッチできるのが最高で、これまで自分が手元に持ち続けていたニューロベースの巨大リサンプルファイルがまた大きくなっていく方針。きっとCOPYCATTも喜んでいるだろうと思ってインスタを見に行ったら、なんとドンピシャで僕と全く同じことをやっていてすごく嬉しかった。

www.instagram.com

あとFXね、同一種類のものが複数刺せるようになって神。Bode楽しい、Splitterマジで神、Convolve超うれしい、DistortionのOverdriveのstack神、Utilityマジで嬉しい、といったところ。

また、Serum 1との完全互換を持っている。これは噂レベルの話なんだけど、同一プリセットでもSerum 2に刺すだけでCPU使用率が下がるらしい。凄すぎる。

Serum 1がサウンドデザインの方面に与えた影響ってマジで絶大で、MASSIVEが展開したwavetable方式という考え方をSerum 1が無制限に拡充した過去は語らずにいられないトピックだろう。その後、PhaseplantとかVitalとかCurrentとか、次世代Serumなんて呼ばれるシンセがいくつか出て、その方面は完全に未来に託しているのだと思っていたのだけど、そのタイミングで最高の機能を持ってして現れたSerum 2。カッコ良すぎるって……。そもそもSerum 1の残したレガシーがデカすぎるが故にハードルも激烈に上がっていたのだろうに、ちゃんと "2" の威厳を持ってやってきてくれた。DubstepプロデューサーのOddprophetは、自身のチャンネルにアップロードしたチュートリアルで "Serum is back, Sound design is back" と言っていたが、これは本当にその通りだったと思う。自分のTLもその一色になっていた。こんなにかっこいいリリースって存在しないと思う。

…この事を考えるたびに MASSIVE X のことを思い出す。簡単に言えば、Serum 2 の真逆で、ぜんぜんおもんなかった。NIってデカい会社なのにこれなの…?とか思った記憶がある。でも、今思い返すと、クリエイティブ周辺の実装に対する完成度って会社の大きさに相関しないよなあとかも思う。もし無限の時間を持っていて、無限の資金を持っている個人が居るならば、そいつが無限にこだわり抜いた実装が最強だろう。そして、ことソフトウェアに関してはそのような状況が実現しうる。

ソフトウェアは他の物事と違ってコピーすれば動くので無限にスケールする。ここと商売がうまく結びつけば、その瞬間資金も無限になる*2。例えば、90年代後半に爆発的なシェアを誇っていたWinampを開発したJustin Frankelは、その莫大な富からREAPERを開発し*3、現在に渡ってかなり網羅的な実装を続けている。デザインとして微妙なDAWだとは思うが、できることの幅は世界で一番広いDAWで、自分の周りにもファンは多い。Serumもその一つで、Steve Dudaが少人数チームで作り上げたソフトウェアだ。これは爆発的な人気を誇ったので、きっと銀行口座も爆発的な数字を記録していたと思う。その資金をもって、なんの締め切りにも追われず、Stebe Duda本人が満足するまでSerumを正当進化させ続けていたのであればこの完成度も頷ける。超かっこいい。

このような、ソフトウェアの巨人たちに肩を並べることを将来の夢としつつ、Serum 2周辺でちょっとだけ数字を得た自分のツイートたちを下に並べて〆!

もう昔からずっとこういう音を作るのが大好きで…

*1:神アニメ。下書きにいろんなコンテンツの感想まとめがあり、そこに簡単に感想が書いてあった。

*2:ベストシナリオ

*3:語弊あり

Minecraftのエンダーパールは走りながら投げても飛距離に影響しない (1.9 ~ 1.20)

ダッシュジャンプでなければならないのである(1.9 ~ 1.20)

要約

Q. 1.16.1 において、ジャンプなし、ダッシュだけしている時にエンダーパールを投げても、棒立ち状態でエンダーパールを投げた時と比べて飛距離が変わらないのはなぜ?

A. ただ走っているだけではサーバーにプレイヤーの速さを伝えることができないから!

概要

エンダーパールの初速はプレイヤーの velocity によって決定されるはずだが、(1.20以前のバージョンでは)ダッシュしているだけではエンダーパールの初速に影響を与えられない事象が発生する理由を説明する

また、1.21 より、この挙動に一部変更が入り、ダッシュしているだけでもエンダーパールの初速に影響を与えられるようになったため、この旨についても説明する。

おことわり

  • FabricMC/yarn によるマッピングを使用してソースコードの動的/静的解析を行った
    • 1.16.1+build.21
    • 1.20.1+build.10
    • 1.21+build.9
  • これらの挙動は 1.9 以降のMinecraftで確認することができ、1.20 系まではある程度同じ挙動であることが確認できる
  • 1.21 での差分点については記事後半で説明する
  • この記事は以下の動画の最後、「バージョンごとの差異」についてのアンサーとしての立ち位置の記事となる
    • かなり素晴らしい動画なので是非見てみてください

www.youtube.com

サイドの説明

このゲームは、大きく分けてクライアント側とサーバー側で処理が分かれている。

サーバー側

基本的なゲームロジックに関わる計算はサーバー側で処理される。今回の議題であるエンダーパールの各挙動もサーバー側で計算される。

クライアント側

ピクセルの描画や、20fpsより高い分解能を得るための補完などはクライアント側で処理される。基本的には、サーバー側の挙動をコピーして描画するのが主な役割。

例外として、一部の座標や一部の velocity の計算など、このゲームの根幹だと判断されなかった処理についてはクライアント側で行われることもある。特に、今回はクライアントとサーバーの挙動の差異が起因してエンダーパールの挙動に影響を与えている。

エンダーパールの初速について

ref: net.minecraft.entity.projectile.ProjectileEntity#setProperties

要約する*1が、エンダーパールの初速は サーバー側のプレイヤーの velocity (速度) を元に決定される。プレイヤーの velocity がそのままエンダーパールの velocity に加算される。

あくまでクライアント側の velocity ではないことがポイントとなる。

サーバー側での velocity 更新の動き

ref: net.minecraft.server.network.ServerPlayNetworkHandler#onPlayerMove

サーバーがクライアントからプレイヤーの動きに関するパケットを受け取った時、基本的には*2以下のどちらかの場合で のみ velocity が設定/加算される。

  • ジャンプした時( ref: net.minecraft.entity.player.PlayerEntity#jump )
    • y 方向に 0.42 加算される
    • さらにダッシュしていた場合、定数と角度で計算した値が x, z 方向の velocity として加算される
      • 定数を元に計算されることが重要!
        • つまり、俊敏のポーションやソウルスピードなどの影響を受けることはなく、ダッシュジャンプ時の横方向の速さは常に一定!!!!
      • 実装としてはこんなかんじ
        • x += -sin(角度のラジアン) * 0.2
        • z += cos(角度のラジアン) * 0.2
  • 入力に関与しない自然な移動が発生した時(net.minecraft.entity.LivingEntity#travel 周辺、いろいろ )
    • 具体的には
      • 落下(重力)
        • 例: 落ちている間、y 方向の velocity は毎tick加算される
      • 別のなにかから動力を受ける
        • 例: TNT に吹き飛ばされる
      • 水流に触れ、流されている
      • ツタなどに触れている状態で下方向に降下している
      • など

そうでない場合、例えば単にダッシュしはじめた場合、クライアント側の velocity は適切に設定されるが、サーバー側の velocity は 0 のままになっている!!! velocity が 0 なのに、座標が連続的に変わっていくような挙動をみせることになる。

例えば、俊敏のポーションやソウルスピードによって速さを得ていたとしても、サーバー側の velocity は 0 のままである。

減衰について

ref: net.minecraft.entity.LivingEntity#travel

また、上述したベロシティ加算の動きをしていない場合、基本的にはサーバー側の velocity は 1 tick ごとに減衰し、(何もしなければ)最終的には 0 に収束する。

例えば、ダッシュジャンプを一回行った後にダッシュを継続していたとしても、サーバー側の velocity が高く設定されるのはジャンプを行ったタイミングのみで、その後はゆっくりと 0 に近づいていく。

また、1 tick ごとの減衰幅はその場の環境によって異なる。例えば氷の上では減衰幅は小さく、相対的に少しずつ velocity が減衰していく。

これらの事柄からわかる、エンダーパールの初速について

以上の事柄より、以下のようなことがわかる。

  • ただダッシュしているだけではサーバー側の velocity は設定されず、エンダーパールの初速にも影響しない
  • ジャンプしたタイミングでエンダーパールを投げると、ジャンプ時に設定される velocity がエンダーパールの初速に影響するようになる
    • この時にダッシュしていれば、追加で定数と角度で計算した値が velocity に加算される
  • 落下時や、爆風によって打ち上げられている時など、外部から velocity に関する影響を受けている時にエンダーパールを投げると、プレイヤーに掛かっている velocity はエンダーパールの初速に影響する
  • 俊敏のポーションやソウルスピードによって事前に大きなスピードを得ていたとしてもエンダーパールの初速への影響はない!!!
    • ジャンプ時に得られる横方向の velocity は定数と角度で計算した値と、サーバー側の velocity のみが影響するが、初回ダッシュジャンプ直前の横方向の velocity は 0 であるため、俊敏のポーションやソウルスピードの影響をここに与えることができない
  • 氷の上で何度もダッシュジャンプする例のように、連続してダッシュジャンプを行いスピードを稼ぐ場合はエンダーパールの初速に影響する
    • velocity が 0 になる前に次の加算を行うことがこの種類の加速の原理であるため、サーバー側の velocity にも適切に反映される

1.21 からの差分点: movement

……と、ここまでは従来の挙動について説明してきたが、1.21 からは movement という新しい概念が追加される。

movement について

ref: net.minecraft.server.network.ServerPlayNetworkHandler#onPlayerMove

ref: net. minecraft. server. network. ServerPlayerEntity#setOnGround

おそらく、今回挙げたものに類する不自然な挙動に対してのパッチとして導入された概念*3で、実質的にはプレイヤーに対してのみ存在する。

movement は、クライアントから送信されたパケットをサーバー側が受け取り処理する際にプレイヤーが移動した距離がそのままベクトルとして格納される。重要なのは、これがサーバー側で設定されること。

これが、これまで説明した物事に対して以下のように影響を与える。

エンダーパールの初速は サーバー側のプレイヤーの movement を元に決定される。プレイヤーの movement がそのままエンダーパールの velocity に加算される。

差分としては、velocity ではなく、 movement が使われるようになったこと。これにより、ただプレイヤーがダッシュしているだけでもそのベクトルはエンダーパールの初速に加算され、より自然な振る舞いを見せるようになる。

また、そのパケットで進んだ距離がそのまま movement として扱われるということは、俊敏のポーションやソウルスピードで得られた速度もそのままエンダーパールの初速に影響を与えることとなる。こちらの方が直感的な動作と言えるだろう。

まとめ

ダッシュしている時など、クライアント側で velocity を得ていたとしても、サーバー側にその値が反映されているとは限らず、直感に反した動きを見せることがある。エンダーパールの初速も、この事象の影響を受ける一例だった。クライアント側とサーバー側の挙動の差異について理解することで、説明しづらい事象に対しても理解を深めることができる。

また、Mojangがこのような問題に対してどのように対応するのかの一例を確認することができた。今回の場合、ダッシュしているだけでもサーバー側でプレイヤーの速度が適切に反映されるようになった。その結果、エンダーパールの初速にも影響を与え、より直感的な挙動となった。

*1:実際にはここに乱数ベクトルが加算される

*2:イレギュラーはいくつかあるが、通常のブロックの上で通常の振る舞いを行っている場合はおおよそここに記載のあるものが大半に見える

*3:たぶんこの修正 MC-273007 で導入された概念 ぜんぜん違うかもしれないけど

叙々苑に行った!!!

「高い」ということで有名な叙々苑に、人生で初めて叙々苑に行ったので記念に記事を書く!

経緯

2020年3月頃、Twitter上でその日のご飯を迷っていたところ、おそらく冗談で「叙々苑」という提案があった。自分もその人も含めて叙々苑に行ったことがない様子で、ふざけて次のようなツイートをした。

以後、ちょくちょく「叙々苑にみんなで行く」というアイデアが頭を過るようになる。上のツイートにも少し現れているが、巡らせているうちに「ファーストインプレッションという側面を大事にしたいよね」ということになり、以下の2つを大事にした会を開きたいと強く思うようになった。

  • 全員が叙々苑に行ったことないこと
    • 一回目の叙々苑の経験は、感想の邪魔になるだろう
  • 全員が自腹であること
    • 奢ってもらうご飯が美味しいのなんて当たり前だろう

普段高いご飯を食べる機会が少ない自分(や、もしかすると我々)にとって、一万円をゆうに超える食事なんてまったく経験がない。この会で「一万円超の食事」「叙々苑」の体験を得て、今後のなんらかの判断基準として活かしていきたい、というのが主な動機だった。

最初のツイートから約4年間、事あるごとに機会を伺うが、人は集まらない上に、そもそも自分の気持ちの波もあってなかなか開催に至らない。一時期は一人で向かうことも考えたが、流石にソロ叙々苑ディナーは寂しすぎるので避けたかった。

そんな中、最近よく話しているしくしくさんにこの話をしたら「やろう」という返事が返ってきた!乗ってくれそうな人で、なおかつ明確にOKの返事をもらえたのがおそらく初めてだったので、ここで一気に乗り気になった。

これをきっかけに再度ツイートしたところ、二人から直接連絡が来たのでもう開催せざるを得なくなった!

追加で誘いたい人を誘ったりして、店を決めて*1、7人で叙々苑に向かうことになった。これだけ集まってくれたのって本当にありがたい!

本編

かなり良かった!!!以下、褒める。

今回は「月会席」という14,000円のコースに3,000円の飲み放題を付けて一人17,000円という構成を組んだ。コースなので、焼肉屋なのにしっかり前菜とかが来る。

その前菜が美味しいので驚いた。普段だったら偏食で頼まないし食べないであろう「ホタテとクラゲの和え物」を*2、なんらかの信頼によってそのまま口に運べたのがとてもよかった。めっちゃやらかいホタテってやばい。これが素材の味か?

やけに優しい味がして食いやすい、叙々苑版のやみつきキャベツもよかった。この手のサラダって大体激しい味付けが多いと思うのだけど、多分金持ちの余裕というか、「高級」ってこういうことなんだろうなと思ったりする。コーネリアスの曲聞いてる時と同じ気持ちだった。

前菜について、最初は「肉以外で腹を満たさせる姑息な戦略」感があった*3のだけど、前菜自体がうまかったので完全にペイできたと思う。純粋にコースの体験価値を上げてくれた。

で、肉。凄かった!!カットのせいか、焼く前の生肉の時点でかなり美しかったし、実際焼いて食べてみてもしっかり激ウマ。なんて言えば良のだろうね、脂身の感じ?がかなり上品なのが良かった。あんまり良い感想が出てこないな、純粋に肉自体が良いのもあると思うんだけど、食べやすい形だしその肉が一番うまいような状態で出してくれてるんかな~みたいなそういう

提供方法もよかったな、大きな皿にみんなの肉がまとまって乗っかっているのではなくて、個人の皿に自分の分のみが乗っていた。ふつうの焼き肉の場合、基本誰かがずっと肉の管理をしたり、なんなら気を使って自分が率先して焼き続ける、みたいなこともあったりするのだけど、ああいう摩耗的なコミュニケーションが要らなかった。それだけで心地よいんだな~みたいに思った。これによって、各個人がある程度自分のペースで食えているように見えたのもよかった*4

あと、カシスオレンジがめちゃうまかった!!!!!!!!いい甘さだし、何より酒感が強くない!!!僕は「酒は飲みたいけど本当に苦手」というめんどくさい人なので、こういうスッと入ってくれる酒は本当にありがたかった。こういう酒が飲めるところに行きたいよ。あと、果肉入りなのもよかった。加点ポイントやね。

最終的にかなり満腹だった。最初、コース選択のときに花会席を見送ったんだけど、多分花でも満足できてたんだろうな~。

叙々苑に初めて来たわけだし、明らかに初々しさだけでやってる一行だったと思うんだけど、店員がちゃんと丁寧だったことも覚えてる。いやな舐められ方って結構分かると思うんだけど、そういうのが無くて終始いい感じで居てくれてたな。

今回はコースだったしお腹いっぱいだったのでやらんかったけど、単品での注文もやりたいよね。あのよく見る?すだれみたいになってる肉のことも気になってる。次また叙々苑に行く機会があると良いなー

という感じで、叙々苑会は終了。参加者のみなさまも良さそうにしていたので、きっと良い会だったのだと思う。個人的にもちゃんと17,000円分の価値を受け取った。褒めたくなるところがたくさんあったし、楽しかったし、少なくとも今回はそれだけ払う価値があったはず。

ほかの6人の感想は、その会に足を運んだ人の記事とか、各個別に聞いたりとかしてみてください。多分なにか言ってくれると思うので。

*1:この時知ったのだけど、同じコースでも店舗によって料金が違ったりするらしい。注意ね!

*2:ホタテがかなり嫌いという先入観があった

*3:叙々苑ってベースが高すぎるから尚更ね

*4:ずっと肉を焦がしてる人もいたけど

インターネットの人ってなんだ

タイトルは単なるキャッチーな文字列で、まともにタイトルを回収するつもりはない ごめんね

私の過ごすWebのソフトウェア業界でも「インターネットが好き」という合言葉のような共通価値観がある。これも現在からみたら「水道が好き」のような違和感のある言葉だとしばしば言われているが、この言葉の中にもWeb 2.0当時の時代感やその場を過ごしてきた自分たちを懐かしむような喪失感を覚えるような感覚が今となってはあるよねいや俺はある

まだ件の新刊は読んでないのだけど、このあたりのノスタルジーは自分にも多少なりとも残っているので書いておこうと思った。


最近ツイートがバズった!人生初の万バズだった。

見るのがめんどくさい方に向けてまとめると以下のような動画になっている

  • MinecraftのRTAの録画のクリップ
  • アイアンゴーレムを倒してドロップ品の鉄インゴットを頂くまでの過程で失敗するという内容
    • アイアンゴーレムへの攻撃を3回失敗する
    • 干草の俵を足場にしようとしていたところ、真下がコンポスターでそのまま吸われてしまう

実際おもしろいシーンではあったのでTwitterに投げて身内に共有したかったのだけど、意図せずバズってしまった。拡散経路も全くわからないが、なんらかレコメンドシステムに気に入られてレールに載せられ、そのままスコアを稼いでいったのだろう。

このツイートをきっかけに自分のことをフォローしてくれたアカウントが14個もあったのだけど、この人らが自分をフォローした理由は、別に「なあり/naari3/名有りさん」を見たいためではなく、情報のインプットを多くしたいだけだったのだろうと思っている。僕を人ではなくTwitter全体の一端として捉えているのだろう。

ただ、別に無理もないことだと思う。昔と比べて、コンテンツ供給側の人間が桁違いに増えてしまったことで、レコメンドシステムなどを用意して人間に機械的に良さそうなものを提供することが容易になった*1が、このような状態で、受け手側は無数に知らない人(制作側)の名前を見ることになる。そんな中で供給側の人間を人として覚えていられるケースはかなり稀だと思う。

あなたが見るYouTubeの動画でも、多分「この動画を見ている人のうち登録者は15%に満たないので、登録ボタンを押してくださいね」みたいなことを言っていると思う*2し、どのサービスでも基本的にはそんな感じで成り立っている。人と人ではなく、スケール感、みたいな。

どちらのサイドの人であっても、もうスケールのみが大事で、細かな数字は必要ない時代なのかもしれない

これは、Web 2.0と呼ばれる当時のインターネットの空気感とは異なる部分がある。これは引用した記事中でも言及されていることなのだけど、特別なアイデンティティを持つ人が活動者として振る舞いやすい雰囲気があった。これは今思えば規模感によるもので、また、今思えば僕が当時の空気感が好きだった理由の一つでもある。なんとな〜くインターネットの全貌を掴めたような気持ちになれるような、そういう流速だったと思う*3

(2008年が「もう既に遅い」とか言われたらまあそうなんだけど、それでも今とは違う時代だったでしょ?)

自分がブログを書き始めたのも、そういうWeb 2.0な人々に出会ったタイミングだったように記憶している*4。ブログを書いている人の名前とか、なんらか著名なソフト/パッチの作成者の名前とかは知っていたけど、それらがタグのようなものではなく、完全に「生きている人」と結びついたタイミングが自分の人生に存在しており、その頃に抱いた何らかのあこがれによってブログを開設して書き始めた気がしている。*5

当時から今まで、僕は個人の運営しているブログを見るのが好きなのだと思う。本当になんでもない記事であったとしても、それが集合になることで筆者の人間性のほんの少しだけ深いところをうかがい知ることができるからで、そこそこ長く運営されているブログであればあるほどその傾向は強まっていく。20年近く運営されているブログなんかはほとんど伝記みたいなものだ。Web 2.0で輝いていた人々も、そんな感じで僕を魅了してくれていたのだと思う。それこそ、今回引用した記事を書いている方とか、その記事で取り上げられている新刊の著者とか、僕のことを勝手に支えてくれた人は結構いる。

自分の周りでブログをやっている人はそんなに多くなくて、基本的にはツイッターをやっている。なんなら、偶発的なバズや不特定多数からの悪意を気にして、鍵垢として運用している人も少なくない。まあ、そういう曖昧な可観測性を持ったネットワークも案外悪くないもの*6なのだけど、Twitterが今後も存続するためにはこれまで以上にセルアウトしていく(レコメンドシステムの稼働率を高くしていく)必要があるように思うし、そうなると個人の繋がりはどんどん薄くなっていく。なにより僕はもっとみんなのことが知りたいので、もっとみんながドメインを持って、ちいさなものでも良いから記事を書いてくれるようになるとめちゃくちゃ嬉しい!

個人の考えがある程度まとまって記載されているというのは結構すごいことで、感想の持ち方一つであっても誰かにとっては知見になりうる。レコメンドシステムみたいな「前ならえ」ではなく、千差万別であってようやく意味を成すことはあるはず。140文字じゃ足りなくなったらブログを書いてみてほしいね!!!

*1:あんま関係ないけど、大量の人が常に振り続けているサイコロを口を開けて待っているような様が似合っているね

*2:そして、そのタイミングでYouTube上の登録ボタンが虹色に光るが、これは皮肉にしかなっていない

*3:これはマジで思っているだけの可能性があり、当時のインターネットは今ほどでなくともそれなりにはでかかった。が、実際そう思っているので仕方ない

*4:名有りの前に持っていた名前ではてなダイアリーをやっていた

*5:最近はあまりブログも書いてないね…

*6:自分がここで生かされているからね。ちょっと生存者バイアスすぎるかも

Fabricを使用したMinecraftのModを1.20.6に対応させようとしたらVSCodeがプロジェクトを読み込まなくなった(ミスリード注意)

tl;dr

Language support for Java ™ for Visual Studio Code の Gradle が使用するJDKは JAVA_HOME で指定できないので、指定したい場合は直接 java.import.gradle.java.home で指定すること!

流れ

  • 自作のModである offers-hud を Minecraft 1.20.6 に対応させたかった
  • 方法を調べた
  • fabric-loomを1.6に更新
    • Gradle用のプラグインで、主にyarn*1を使用した難読化の解除を行う
  • Gradleを8.6に更新
  • JDKを21に更新
    • JDK 21 インストール
    • 環境変数 JAVA_HOME 設定
    • コード上の変更
  • 各依存(Minecraft, fabric-api, fabric-loader)のバージョンを 1.20.6 向けに更新
    • ここで動かなくなった!!!!!

症状

少なくとも、どちらも1.20.4までは見たことがなかった

各Javaのソースコードの真上に以下のエラーが発生していた

Source.java is a non-project file, only syntax errors are reported
  • 読んだ通り、本当にシンタックスのチェックしか行ってくれない
  • Minecraftなどの巨大なゲームのModdingをする時、各種補完の力によってコーディングを進めていく他ない場面は多々あるため、これは本当に困る

また、Run and Debug で Minecraft Client を起動しようとした時に以下のようなエラーが発生さた

ConfigError: The project 'project-name' is not a valid java project.
  • validなプロジェクトではない……?

状況の確認

  • ターミナルで直接実行する ./gradlew build は問題なく実行可能
  • SourceSet は正しく指定されていることが確認できた*2
    • ここが正しく指定されていなければ各javaファイルはプロジェクトのものだと認識されない
  • つまり、VSCodeだけがプロジェクトを正しく読み込めていないっぽい

原因(推測込み)

  • Minecraft の 1.20.6 から要求されるJavaランタイムが21になった
  • Gradleのプラグインのfabric-loomがMinecraftの各classファイルをデコンパイルする段階で、使用しているJDKがclassファイルのmajor versionに対応しておらず終了した(推測)
    • が、なんとこれを利用者に伝えてくれないっぽい
    • 少なくともログを見てもエラーは出力されていなかった

どうすればよいか

  • .vscode/settings.json に次のようなエントリーを追加する
"java.import.gradle.java.home": "C:\\Program Files\\Java\\jdk-21",
  • を見るに、Gradleのデーモンが使用するJDKは別途指定する必要がありそうだった

なぜこれまでは発生していなかったのか

  • これまでのMinecraftのバージョンで期待されていたJavaのバージョンは17以下だった
  • https://github.com/redhat-developer/vscode-java/wiki/JDK-Requirements 曰く、何も指定していない場合は JDK 17 でGradleのデーモンを動かすらしい
  • classファイルのメジャーバージョン的には妥当なので問題なく動く

結果

動く

github.com

余談

  • 今回のMinecraftのアップデート、パッチバージョンのアップデートにしては巨大すぎてヤバい
    • 主に以下の2つ?
      • コンポーネントの概念をメインに使い始めるようになる
        • NBTの扱いがこれまでと変わるからそういうことやってる部分全部変えないといけなさそう
      • パケットのやり取りのより画一的な対応
      • とか
  • Modderのみんな、がんばれ

*1:JSのパッケージマネージャーと同名だが、両者に関係はない

*2:https://chat.openai.com/share/1c6ef71a-a287-40b8-a5b1-42fec87f7be7

ChatGPTの手を借りつつ、超簡単なWindowsネイティブアプリをRustでつくった

最近、おそらくは常駐させているなんかのアプリの影響で、急にウィンドウのフォーカスを奪われることがある。例えば、普通にVSCodeで何かを書いてる時、急にフォーカスが飛ぶと普通にびっくりするし、何度も繰り返されるとイライラする。

直接的な原因になりそうなアプリが思いつくわけでもなかったので、どうにかしてフォーカスを奪ってくるアプリを知る必要があると思った。

こういうニッチなケースに関しては、サクッとコードを書くのが良いとされているので、そういうコンソールアプリを作ろう!と思い立った。

WindowsのAPIをバリバリに叩くアプリだし、しかも今回の場合はフック先の関数とかも書かないといけなさそうなので気が重くなりそうなところだけど、今はChatGPTという対話型最高アプリが存在するので腰を上げることができた。

ChatGPTは枯れつつあるプログラミングの知識についてはかなり良いものを持っており、今回のような例に関してはまさに持って来いの話題なのでは?と考え、今回はこいつにスタートダッシュを共にしてもらい、アプリを完成させた。

github.com

以下のような感じで、フォーカスがあたっているアプリが変更されたらそれにフックしてアプリの概要をプリントする、という簡単なもの。

アプリの様子

リポジトリ用のディレクトリが作られ、最終更新が発生したタイミングまで全部で35分くらいしか使っておらず、とても素晴らしかったので良かった点を記事として残しておく。

前提として、自分は今回使われるスタックについてはプロレベルではないにせよすべて一度以上は使ったことがあり、かつプログラミングについての全般は慣れ親しんでいる。プログラミングができない初心者がChatGPTを使ってアプリを作り上げたという記事ではないことに注意。

全体像は 会話全文 を読んでもらえば良いが、良かった部分をいくつか抜き出す。

会話

まずは要件を伝えてみると、C#のコードを返してきた。C#で触るWin32のAPIやラッパーはかなり好感触なんだけど、C#を触るために最適な環境であろう Visual Studio を触りたくなさすぎる。純粋にIDEとしては動作が重すぎるし、依存の在り方が複雑だし、正直なところ、触るだけで気が滅入ってしまう類のプロダクトだと思う。

要件を伝えると、C#のコードが返ってきた

ので、今回はポータブル性に優れており、かつ現代的な構文やエコシステムを持ちながらも、C/C++と同レベルのレイヤーのコードを各ことができる、僕のイチオシ言語 Rust で進めてもらうことにした。すると、一発目からなんだか動きそうなコードを出してきた。

いい感じなんだけど、個人的には winapi よりも windows を使う方が好みなので、こちらを使うように変更する指示を出してみる。

(この下部に src/main.rs のコードあり)

現在のChatGPTのGPT-4のモデルは2023年6月までで知識が止まっているため、古いバージョンのクレートを提示してくるが、これは自分の方で新しいものになるように吸収していく。提示されたソースコードをコピペすると、まあ当然のようにビルドエラーが出る。インポートエラーは正しいものになるように解決したが、どうも GetWindowTextW の使い方が間違っている。そもそも、引数の数が違っており、ChatGPTの提示では3つ渡されているが、実際の引数は2つを期待している様子だった。

この場合、関数のシグネチャを直接教えてやると、それに従ったコードを提示するようになる。

この時点で充分動くコードができあがるが、実際に動かしてみたところ、タイトルが表示されるだけでは情報が足りないことに気づく。ここで要件を追加してみる。

なんか色々言ってるが、WindowsのAPIをうまく使ったコードが生成された。これを必要な部分だけコピペし、動かしてみる。VSCode側ではGitHub Copilotも動いたりしていい感じにできあがっていくが、一点だけ良くない点が生まれた。この時点で、既に指示から逸脱して自分流の書き方をいくつかしていたため、以下のように現在地点を伝えるつもりでソースコード全文を貼り付ける。

いい感じの解決策を提示してくれた。PROCESS_NAME_WIN320 に直されたのは情報が古い問題によるもので、これを治したければまた正しいシグネチャを教えることでどうにかなりそうだが、あえてそこまで教えてやる必要もなく、こちらで修正して完了させた。

また、リポジトリの名前も考えてもらった。自分はあまり気の利いた名前を考えるのが得意じゃないので、頻繁にChatGPTに頼っている。

今回は愚直な名前が返ってきた。いい感じ。GitHubにリポジトリをpushしておいて、作業終了。あとはこれを常駐させて、実際に犯人特定の手がかりになればよいな~というところ。

最終的な成果物は以下に存在する。(再掲)

github.com


こんな感じで、知ってることであっても大体最初のとっかかりはChatGPTに書いてもらうことが多い。これまではGoogleで検索し、それっぽい記事のそれっぽいコードをコピペしていたが、検索結果のノイズが激しくなってきたことと、GPT-4の精度の高さを見込んで最初からChatGPTを使うようになった。

特に今回のような「Windowsの特定のイベントフック( SetWinEventHook あたりのやつ )をRustで書く」というニッチなケースに対してもいい感じに、しかも日本語で提示してきた。以下に提示した event_callback 関数のインターフェイスと main 関数はほとんどコピペで作られている。event_callback の各引数や、unsafe extern "system" などのキーワードはある程度unsafe Rustの、しかもWindowsを相手取っていないとサッと出てこないコードだろうし、main 関数に至っては最初から最後まで一文字すら変更していない。実際、main 関数の書き方は自分が一番億劫に感じている部分でもあるので、これが一発で出てきてくれたのはとてもありがたいことだった。

unsafe extern "system" fn event_callback(
    _h_win_event_hook: HWINEVENTHOOK,
    _event: u32,
    hwnd: HWND,
    _id_object: i32,
    _id_child: i32,
    _id_event_thread: u32,
    _dwms_event_time: u32,
) {
    // snip
}

fn main() -> Result<()> {
    unsafe {
        let event_hook = SetWinEventHook(
            EVENT_SYSTEM_FOREGROUND,
            EVENT_SYSTEM_FOREGROUND,
            None,
            Some(event_callback),
            0,
            0,
            WINEVENT_OUTOFCONTEXT,
        );

        let mut msg: MSG = MSG::default();
        while GetMessageW(&mut msg, HWND(0), 0, 0).into() {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }

        UnhookWinEvent(event_hook);
    }
    Ok(())
}

WindowsのAPIを相手にするプログラミングは苦痛が多いことで知られているし、Rustの関数をWindowsが叩けるように渡す行為はさらに苦しいことが多いが、(もちろん要件の簡単さもあれど)テンプレートとしては最もすばらしいものを提示してくれたおかげで、実際に書きたいドメインロジック的な部分を超高速で仕上げることができた。とても嬉しい。