Minecraft 1.16 RSG WR 9:38(とDivine Travel)についてのメモ

www.youtube.com

https://www.youtube.com/watch?v=iv5uKxCMEkM

今回の記録の特筆すべきところ

  • 世界初の10分切り
    • 9:38
    • 前回のWRが11:01
    • 初のsub10
    • 悲願とも言える大記録
    • 最初の1.16の記録から比べて半分ほどの時間で終了している
  • Divine Travel

流れ

  • 村スタート
    • ベッド
    • アイアンゴーレム -> バケツ1つ
    • 村のリソースを大活用、という感じではない
  • IGT 2:51 ネザーin
    • はやい
  • チャンク(0, 0)に化石があった
    • Divine Travelに使用できる
    • 詳しくは後述
  • 速攻で砦とネザー要塞を発見
    • ネザーinとほぼ同タイミング
  • かなり早い段階で (IGT 5:30) 必要資材 (エンパ, 黒曜石) が集まる
  • スポナー以前の自然湧きで充分量のブレイズ
    • IGT 7:00 で収集完了
  • ネザー -> 現世 で要塞に到着
    • IGT 8:06
    • Divine Travelによる恩恵もでかいが、それでも超豪運
    • 詳しくは後述
  • 隣にポータル部屋
  • ベッド5個で終了
  • IGT 9:38

Divine Travel

以下はほとんどこの動画の要約 https://www.youtube.com/watch?v=IKo-jrZSgWU

  • チャンク(0, 0) の生成物より、要塞の座標を推測する技
  • 今年の2月末、3月はじめ頃に実用化された
    • 実用されたrunとしては今回が初の記録更新 たぶん

要塞の生成方法

  • 初期スポーンより 半径 1280 - 2816 の輪に、 特定の角度 から120°ごとに1つずつ生成される
    • つまり3つ生成される
  • この時、 特定の角度 はシード値を元にした乱数生成器によって生成された最初の乱数を使用して決定される
  • また、それぞれの要塞の初期スポーンからの 特定の距離 も乱数によって決定される
    • 1つ目の要塞であれば、乱数生成器の三番目の乱数が 特定の距離 になる

乱数生成器と乱数について

  • シード値を元にした乱数生成器は複数存在し、乱数生成器ごとに生成される乱数の順番は同じ
    • どの乱数生成器であっても同じシード値を使用していれば、
      • 最初に生成される乱数は同じ
      • 二番目に生成される乱数は同じ
      • 三番目に生成される乱数は同じ
      • ・・・
      • n番目に生成される乱数は同じ

イデア

  • 別用途で使用される乱数を確認し、 角度距離 を特定する

化石を利用した乱数特定

  • 生成される化石の座標は以下のような関数によって決定される
  • Fossil Coord = ( f(rng1) * Chunk X ^ g(rng1) * Chunk Z ) ^ rng1
    • ^ は XOR
    • rng1 は乱数生成器によって生成される一番目の乱数
  • Chunk X = 0 かつ Chunk Z = 0 のとき、以下のようになる
    • Fossil Coord = ( f(rng1) * 0 ^ g(rng1) * 0 ) ^ rng1
    • Fossil Coord = ( 0 ^ 0 ) ^ rng1
    • Fossil Coord = 0 ^ rng1
    • Fossil Coord = rng1
  • → チャンク 0 0 に化石が生成された場合、この座標を確かめることで 遺跡の角度 が特定できる!!!!

その他の特定方法など

https://cdn.discordapp.com/attachments/405839885509984256/817167014484901908/pngdivinetravelmdpi.png

https://docs.google.com/presentation/d/1mm1YGcUCrrW4s7KIBn9v89MhHUMrtqSPeOuu0dy62NQ/edit#slide=id.gd438437599_0_70

Minecraft Java Edition SpeedrunningにてDivine Travelで検索するとよさそう

今回の場合

  • ネザーin時に見つかった化石がチャンク(0, 0)でfossil_8だった
    • (0, 0) から (-251, -50) の方向
  • これを決定する際に30秒ほど一時停止しており、これによって物議を醸しているらしい

6502のエミュを実装した

GitHub - naari3/emu6502: Implementation 6502 emulator in Rust for hobby

完全な状態かというと全くそうではなく、ただ単にここに書いてある情報を実装した*1

ファミコンのエミュというわけでもないので達成しなければならない要件はとてもシンプルで、そのため難易度は全然高くなく、全体を通してとてもすんなりと通った。

言うことのないレベルでシンプルだったが、現状使ったことのなかった割り込み処理の鱗片*2が見れたこと、各PSの正しい使われ方、ほか詳細な動きを知ることができたところだった。

今回は実装のための言語としてなんとなくRustを使用したが、

  • パターンマッチがかなりおいしかった(コンパイルエラーになってくれるのは精神衛生上良かった)
  • 静的コンパイラの推論がすごくよかった
  • 再束縛が良かった

くらいの恩恵を受けられた。あまりRustらしい使い方が出来たかというと正直微妙なところがある。

CPUみたいな名前のtraitを用意すれば、各所でimplを作ることで「コントローラーを受け付けるような特殊IOを用意したCPUを実装」、みたいなのもやりやすくなるんだろうなと妄想した。

実装として、

  • あまり処理の棲み分けが出来ていない
    • CPU structとInstructionの実装を行き来しているなど
  • 通化がちょっと微妙っぽい
  • &mut selfが多すぎる
    • そんなものなんでしょうか

などが上げられる気がする もっと綺麗にできそう

*1:BRKとResetの情報は他のサイトを確認したがどこだったかわすれました

*2:BRK, RTI

winapi-rsでCONTEXTを扱うと結構な確率で998(3E6)で落ちる

この記事ではCONTEXTとは (winapi::um::winnt::CONTEXT)https://docs.rs/winapi/0.3.9/winapi/um/winnt/struct.CONTEXT.html のことを指す

tl;dr

alignを気にする必要があった

#[derive(Default)]
#[repr(align(16))]
struct Context(CONTEXT);

または winapi の v0.4 がリリースされるのを待つ必要がある

いきさつ

最近ぷよぷよテトリスというゲームに悪さをしていて*1、特定のbreakpointに対して 0xCC を貼ったりしてプログラムの動きをこちらの都合の良いものに変える等のことをしている

今回の要件としてはbreakpointを貼った地点でのレジスタの値を取る必要があった

ぷよぷよテトリスのSteam版はWindowsで動くのだが、Windows上でこれを満たすためには通常 GetThreadContext を用いる

rustの winapi-rs での使い方を例に上げると、

use winapi::um::processthreadsapi::GetThreadContext;
use winapi::um::winnt::*;

// 0xCCやSuspendThreadでスレッドを停止させたあとに
let mut regs = CONTEXT::default();
regs.ContextFlags = CONTEXT_ALL;
GetThreadContext(thread, &mut regs)

こんな感じで各種レジスタが取得できる

また、任意の値をレジスタに格納するのも容易で、同じ雰囲気で SetThreadContext を用いることで解決する

998メモリ ロケーションへのアクセスが無効です。 が多発する

なんて便利なAPIを備えているのだろう、中学生の頃の自分がちゃんと勉強してれば喜んだだろうな等と思いながら実装していたが、ちょうどGetThreadContextを叩くタイミングで落ちることが多かった

GetLastErrorで確認してみると、 998 メモリ ロケーションへのアクセスが無効です。 のエラーで落ちているようだった

当時はあまり詳しくなかった(winapiに深入りするのを避けたかった)ので渡しているものの不備を信じてGetThreadContext前後をデバッグしていたところ、printlnをしたりしなかったりすると落ちたり落ちなかったりすることに気づいた

alignment requirements

色々調べた結果たどり着いたのが「データ構造アライメント」という概念だった

いつも高レベルAPIを触っている自分にはにわかに信じ難い話だが、構造体によってはメモリ上の開始位置が揃っていないとうまく動かない場合があるらしい
今回の例で言い換えると、 CONTEXT のアドレスの1の位が0でないとうまく動かなかった

先程のprintlnをつけ外しすることで確立的に落ちるように見えていた部分では、実際はprintlnによってアドレスの1の位が8にずれることで動かなくなっていた
rustのアーキテクチャに詳しくなく、かつ調べていないので予想でしかないが、メモリ管理を厳格にする上でprintlnによってメモリ位置的な副作用が生じてしまったのだろう

また、これは Microsoft Docs の GetThreadContext にも記載されている

The CONTEXT structure is highly processor specific. Refer to the WinNT.h header file for processor-specific definitions of this structures and any alignment requirements. (訳) CONTEXTの構造は非常にプロセッサに特異的です。この構造のプロセッサ固有の定義およびアライメント要件については、WinNT.hヘッダーファイルを参照してください。

winapi-rs での解決策

この問題を解決するには要求されている通りにアライメントをする必要がある

先程のコードの例を挙げるならば次のようにすることで安定して動くようになる

use winapi::um::processthreadsapi::GetThreadContext;
use winapi::um::winnt::*;

// 追加
#[derive(Default)]
#[repr(align(16))]
struct Context(CONTEXT);

// 0xCCやSuspendThreadでスレッドを停止させたあとに
let mut regs = Context::default().0; // .0を追加している
regs.ContextFlags = CONTEXT_ALL;
GetThreadContext(thread, &mut regs)

CONTEXT を先頭に有する Context structをこちらで定義し、そのalignを16に固定することで先頭に存在する CONTEXT の align requirements を満たすことが出来た

この問題に対して既にissueは立てられているのだが、 2021/02/09 現在の winapi-rs ではまだopenのままになっている

github.com

winapi-rs の v0.3 が担保している Rust の最小バージョンでは先ほど説明した repr_align が実装されていないため未解決の状態になっているようだった
v0.4 に上げる際に repr_align に対応しているバージョンにまで引き上げることで解決を狙っているらしい

コード的には次のようになっている 解決されることに期待したい

https://github.com/retep998/winapi-rs/blob/785f7f30a69c70687864ac650aebc123e942c1b3/src/um/winnt.rs#L1040

STRUCT!{struct CONTEXT { // FIXME align 16
    P1Home: DWORD64,
    P2Home: DWORD64,
    P3Home: DWORD64,
    P4Home: DWORD64,
    P5Home: DWORD64,
    P6Home: DWORD64,
    ContextFlags: DWORD,

*1:undoの機構を設けたい

ループバック機能のないAIFでは愚直にOBSで音声キャプチャできない 

趣味でDTMをやっており、Twitterに共有したりDiscordに乗せる目的でDAWのキャプチャがしたくなる

だが、普通の作業風景のキャプチャと違って音声あたりで厳しさを感じたりする

例えばDiscordでゲームを配信するんだったらGo Liveボタンを押して今起動しているゲームを選択するだけでよいが、DAWの場合はうまくいかないことが多い

何故かと言うと(原因はたくさんあるように見えるが頻出なものとして)ASIO経由で音声を出力している所にあるらしい

ASIO経由で音声を出さなければ普通にキャプチャできるのだが、その場合の音声遅延はほんとうにひどいものになってしまう

指ドラムとかしたいときは本当にお粗末な結果になってしまうだろう

そこでobs-asioなどのプラグインを使ってASIO入力を取得できるようにするのが定石らしい

しかし、僕の環境ではうまく動かなかった

これはループバックの機能を使用することで成り立っているらしいのだが、僕が使用しているFORCSUITE Scarlett 2i2のようなAIFはループバックの機能を有していなかった

これは言わずもがな当たり前で、オーディオアウトプットが2ch(ステレオ)分しかないのだからルーティングもくそもないのだ

仕方がないのでOUTからINに直接線をつなぐことで解決させたのだが、これはこれで本当にお粗末だと思う

あと2つoutputがあるAIFを買いたいけど、お値段もちゃんと2倍なのでなかなか………

また、この場合の解決策としてVoicemeeter Bananaが使われることも多いが、これは遅延がひどかったりノイズが乗ったりでなかなか厳しいものがある

なにより元々ASIOを使用することでハードウェア完結だったところにソフトウェアが入り込むのだからいい結果が生まれるわけがない

テト譜を反転させる拡張機能を作った

これ

github.com

個人的に必要に迫られたので作った テンプレの練習する時に使ってる

あまりテト譜に詳しいわけじゃないので壊れてるかもしれない あと単にデバッグ不足によって

(TDDができればよかったけど気力が出なかった)

chrome extensionのはなし

発案から3時間強で作れたのだが、やはり環境を簡単に作れるのがとてもよかった

いいかんじボイラープレートがなかったのでコピペで土台を作ったが、その際にwebpackのconfigをtsで書けるという知見を獲得できた

f:id:naari_3:20210208134847p:plain
いいかんじに型つく

機能のはなし

テト譜を読み込んで反転するためのボタンを追加する、がやっていることのすべて

しかもテト譜の読み込みはknewjade大先生のライブラリがあったので一瞬で終わった

github.com

いい感じに書かれていてよかった

実際に反転させる機能は実装できたのだが、あまりキレイには書けなかった

https://github.com/naari3/tetofu-flip/blob/main/src/content_scripts.ts

見てもらうと分かる通り条件分岐ばかりになってしまった

まあ仕方ないと思える範囲ではある ステージ全体が反転することを考えた時、ミノの種類によって状態がばらばらになるのでifも多くなるであろう

もっと数学力(行列とか、考え方とか、あと(数学ではないけど)テトリスの地力とか)が備わってれば(もしかしたら)きれいに書けたのだろうが、今の自分の限界ということでひとつ。

GitHub Actionsが動かなかったことでちょっと迷ってたけど、デフォルトのブランチ名が変わったからだった

タイトルオチ

GitHub Actionsを動かしたかった

ざつに作ったアプリケーションでgh-pagesを使いたかったので、以下の記事から雑に引用してGitHub Actionsを使用したデプロイを試みた。

qiita.com

引用するとこう

name: github pages

# masterブランチにプッシュしたときjobsに記述した操作を行う
on:
  push:
    branches:
    - master

jobs:
  build-deploy:
    # ubuntu OS を仮想マシン上に用意する
    runs-on: ubuntu-18.04
    steps:
    - uses: actions/checkout@v2

    # Node.js環境のセットアップを行う
    - name: setup node
      uses: actions/setup-node@v1
      with:
        node-version: '12.x'

    # npm install の際にキャッシュを使うよう設定
    - name: Cache dependencies
      uses: actions/cache@v1
      with:
        path: ~/.npm
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-

    # package.jsonに基づき依存パッケージをインストールする
    - name: install
      run: npm install --frozen-lockfile

    # Next.jsアプリをビルドする
    # プロジェクトルート直下に.nextディレクトリができる
    - name: build
      run: npm run build

    # 静的なHTMLとしてNext.jsアプリを生成する
    # プロジェクトルート直下にoutディレクトリができる
    # そのなかに、HTMLファイル群と、それらが読み込むJSファイル群を収めた_nextディレクトリがある
    - name: export
      run: npm run export

    # しかしGitHub Pagesの仕様として_から始まるディレクトリが見えず404となる
    # つまりHTMLからJSを読み込めない
    # これを回避するために.nojekyllファイルをoutディレクトリに作る
    - name: add nojekyll
      run: touch ./out/.nojekyll

    # gh-pagesブランチにoutディレクトリの中身をプッシュする
    # gh-pagesブランチは自動的に作成される
    - name: deploy
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./out

俯瞰し、コピペでいけるやん!となってウキウキでpushしたが、そもそもGitHub Actionsが起動しない

github.com

f:id:naari_3:20201231004603p:plain
CIが走っていることを示す・が出てくれない…

まぁCIってそういうものだし…

結局数分くらい待っても動かなかった

マネージドでないCIを運用していた経験が多いこともあり、「CIって割とコミットを取り逃したりするよね、あるある~」とか言いながら、次は適当なコミットを追加することにした

本当はamendで良いのではとも思ってたが、workflowのファイルを追加したコミットでは反応しないのでは?という邪推もあったのでコミットを追加した

しかし、やはり起動しない

github.com

f:id:naari_3:20201231010749p:plain
意味のないコミット

原因

この時点で既にリポジトリActions タブにはworkflowが追加されていたので、yml自体の悪さではないということはわかっており、何が悪いのかよくわからず手詰まりになっていた

全体を俯瞰した時、「ちゃんと on: push: branches: - master になっているしなぁ~」と見直したタイミングでようやく

「あ!デフォルトブランチってもうmasterじゃないじゃん!!!」

となりました…

いつかのタイミング以降、リポジトリを新規で作成するとデフォルトブランチは master ではなく main になっているのでみなさんは注意してください…

github.com

f:id:naari_3:20201231010829p:plain
念願の✔

おわりに

今会社で使っているGH:eはまだデフォルトがmasterのままで、それに依存した実装とか存在している覚えがあるのでその対応をしなければならない気がする

多分他の人もこれで困ると思う(特に過去のコードをコピペだけで動かしたいという需要は絶対に存在する)し、各自が気をつける、サンプルを更新するなどしていただきたい

ARIB外字をVLCで表示するには

はじめに

VLCARIB外字の字幕を表示する方法

ろくに規格を見ずにソースコードと振る舞いの確認のみで終わらせてしまったので間違った情報かもしれません、まったく精査してません

tl;dr

drcs_conv.ini を育てる必要がある

nkoriyama/aribb24

詳細

VLCで撮り溜めたm2tsを見るとたまに次のようなものを見ることがある

f:id:naari_3:20201225024350p:plain

例では薩摩の という字が に置き換えられている

これは外字置換という事象が発生している

ARIB外字とは

ja.wikipedia.org

ひらたく言うと、放送データに添付される字幕データにはたまにShift_JISの範囲外になるような規格の文字も含まれている そのような字のことをARIB外字と呼ぶ
(ARIB外字制定後一部はShift_JISの範疇になったらしいが、それ以外については)同時にフォントのデータも送信される これはARIB STD-B24という規格によって定められた方法で送られるらしい
基本的にはJIS X 0208に収録されいてない文字が対象になっており、先程例としてあげた もその対象になっている

外字置換とは

外字置換とは、上記のデータが受信できなかった/送信されなかった/使用されなかった場合に代替として使われる文字に置換されることで、上で上げた例のようによく下駄文字が使われる

VLCでのARIB外字の扱い方をしらべる

例で上げた通りだが、そのまま表示するだけでは下駄になってしまう

検索すると出てくる情報

この件について検索すると https://github.com/nkoriyama/vlc-aribsub パッチをあてたVLCついての話が出てくる
特別な対応を当てる必要があることの記述があるが、結果としては確認せずスキップで良さそうだった

それ以外にもおすすめのフォントについての記述があるので、それだけは見ても良さそうに思う(がこれでは解決しなさそう) VLCでARIB字幕を見る · GitHub

また、このページで紹介されているパッチやビルドがskydriveの消滅とともにリンク切れになっており内容を推測する他ないのだが、nkoriyama/aribb24というARIB STD-B24を扱うライブラリを使うパッチなのではないかと思っている

根拠として、vlc-aribsubの説明はほとんどnkoriyama/aribb24の動作と同じであることが挙げられる

であるならば、パッチがあてられたVLCを使用している前提でvlc-aribsubのREADME.mdに従うことでARIB外字を扱うことができるのではないかと推測した

実際に解決できた方法

実は最新版(少なくとも3.0.11)のVLCではnkoriyama/aribb24を使用するパッチは既にマージされていて、残りは単に所定のディレクトリにしかるべきファイルを置くだけで動作する

このあたり参照 https://github.com/videolan/vlc/blob/95e01f73802460ec2374894cdb769888e23b108d/contrib/src/aribb24/rules.mak

aribb24のbasedirを指定している箇所 https://github.com/videolan/vlc/blob/95e01f73802460ec2374894cdb769888e23b108d/modules/codec/arib/aribsub.c#L134

aribb24に使用するbasedirを指定する箇所 https://github.com/videolan/vlc/blob/95e01f73802460ec2374894cdb769888e23b108d/modules/codec/arib/aribsub.c#L200

実際にそのようにしてみる

%APPDATA%\vlc\arib を確認してみると、既に data ディレクトリが存在している
中身を確認すると、次のような画像が存在していた

f:id:naari_3:20201225034248p:plain
b1d62062d089551469efaeb94466263e.png
これは https://github.com/nkoriyama/vlc-aribsub の説明どおりで、受信したビットマップのデータは保存するが、特に使用されることはない

一部外字については、ビットマップデータ自体がDRCS外字として伝送されます。 このデータを直接画面に表示することもできなくはないのですが、現状は既存の文字に置換して表示するようにしています。

(実装としてはこのあたり https://github.com/nkoriyama/aribb24/blob/5e9be272f96e00f15a2f3c5f8ba7e124862aec38/src/drcs.c )

そのため、ここで受信したような文字について、(おそらく)手動でマッピングをする必要がある

そのファイルが drcs_conv.ini となる

drcs_conv.init の記述方法

単純で、先程の保存されたビットマップのファイル名( b1d62062d089551469efaeb94466263e.pngb1d62062d089551469efaeb94466263 部分)と、それに対応するUnicode文字を記述すれば良い

https://github.com/nkoriyama/vlc-aribsub/blob/master/drcs_conv.ini が参考として優秀だったが、以下に具体的な追加例を示してみる

例えば次の通り

; ここ以上は https://github.com/nkoriyama/vlc-aribsub/blob/master/drcs_conv.ini そのままか何もなしの状態
; 薩
b1d62062d089551469efaeb94466263e=U+85A9

このようなファイルを次のパスに置いてからVLCを起動する

%APPDATA%\vlc\arib\drcs_conv.ini

すると、実際に表示される字幕も次のようになる

f:id:naari_3:20201225035025p:plain

また、このマッピングは好きな文字を割り当てることが出来るので、ミスったりすると次のような感じになる

f:id:naari_3:20201225035134p:plain
パソ摩

これで一旦対応されていないAIRB外字のマッピングに成功できた

基本的には下駄文字が表示されたときに %APPDATA%\vlc\arib\data を確認し、追加された画像を参考に置き換える文字を探せばよいのだともう

疑問

これ、インターネットの集合知を利用して更新された健全な drcs_conv.ini があれば良いと思うのですが、無いのでしょうか?

個人同士で管理するのはちょっと馬鹿げていると思います