Repository navigation
✨ 文字幅計算Libを追加 - #2307
✨ 文字幅計算Libを追加#2307ChenCMD wants to merge 6 commits into
Conversation
b0ffdef to
2891f21
Compare
EllaCoat
left a comment
There was a problem hiding this comment.
文字幅計算 Lib のレビューです。Minecraft 1.20.4 のソース(デコンパイル)と照らし合わせながら、mcfunction を中心に読みました。
継続動作に影響する問題は見つかりませんでした。再帰する関数はどれも入力を消費してから自身を呼び出し、core/finish は成功・失敗のどちらの経路でも作業領域と一時スコアを片付けています。
軽量化の提案を 2 件、表の大きさについての相談を 1 件、テストと検証記録について 2 件、コメントしました。軽量化の効果は計測しておらず、コマンド数と件数から見積もった値です。
[テスト] シナリオで通っていない経路
- サロゲートペア: U+10000 以上の文字が無いため、
core/pairとcore/pair_key.m、core/nextで 2 コード単位を進める経路が実行されていません。uniform の表には絵文字が入っています。 - 負の幅と太字: 負の幅は太字なしの 1 ケースだけです。±65536px の文字(U+F300・U+F301)、合計が負になるときの切り上げ、オーバーフローの検出(
core/nextとcore/component/part)も通っていません。 - 途中結果の削除:
core/finishでのReturnの削除が効くのは、先頭の部分の結果を書いた後で、後ろの部分が失敗した場合です。失敗系のケースはどれも、収集の段階か先頭の部分で失敗しています。例えば{text:"A",extra:[{text:"한"}]}で確かめられます。 - 失敗後の片付け:
Workが片付いたかの検査は、成功したケースの後にしかありません。
| data remove storage lib:text Work.UniformGlyph | ||
| execute store success score $TextValid Temporary run function lib:text/core/glyph.m with storage lib:text Work | ||
| execute unless score $TextValid Temporary matches 1 run return fail | ||
| execute unless data storage lib:text Work.Glyph unless data storage lib:text Work.UniformGlyph run function lib:text/core/pair |
There was a problem hiding this comment.
[WANT] 日本語の文字でも毎回 2 コード単位のキーで引き直す
146 を省いたことで、ひらがな・カタカナ・漢字・和文の句読点は、default と uniform のどちらの表にも無くなりました。そのため日本語の文字は、文字列の末尾を除いて毎回この行で core/pair に入り、2 コード単位のキーで引き直します。表にある 2 コード単位のキーは補助文字(絵文字)の 13 件だけなので、日本語の文字ではこの検索は必ず外れます。
1 文字あたりの負担は次のとおりです。
| 表にある文字 | 表に無い文字 | |
|---|---|---|
| 実行するコマンド | 約 46 | 約 60 |
| マクロの展開 | glyph.m 1 回 |
glyph.m 2 回、pair_key.m 1 回 |
マクロの展開結果のキャッシュは関数ごとに 8 件で、LRU で捨てられます(1.20.4 の MacroFunction)。n 文字の日本語では、glyph.m を 1 文字のキーで n 回、2 文字のキーで n-1 回展開します。そのため、重複の無い 5 文字以上の文字列は、同じ文字列を測り直しても毎回すべて解析し直します。例えば「ボスが出現した」では、13 回の展開がすべて解析し直しになります。2 文字のキーで引かなければ、8 文字まではキャッシュに収まる計算です。
結果は正しいので、影響は時間だけです。測る頻度が低ければ問題になりませんが、ボスバーなどで tick ごとに測る場合は無視できなくなります。
改善案として、値 146 を補助文字の先頭の目印に使う方法があります。uniform の表は 146 を省いているので、今は表から 146 が返ることがありません。
- load の際に、表にある補助文字の先頭のコード単位(
D83C・D83D・D83Eの 3 種類)を、値 146 で uniform の表へ入れる。サロゲートは単独では関数ファイルに書けないので、表にある絵文字からset string ... 0 1で切り出し、マクロでキーにする。 - この行を、
UniformGlyphが 146 のときだけpairを呼ぶ形にする。
execute if data storage lib:text Work{UniformGlyph:146} run function lib:text/core/pair日本語の文字も、表にある文字と同じく 1 文字あたりのマクロの展開が 1 回で済み、今と同じく 146 で補われます。表に無い補助文字は、pair で見つからなければ目印の 146 が残るので、今と同じく 2 コード単位分の 146 になります。
なお今の経路では、表に無い文字の直後が " か \ だと、pair_key.m でエスケープが外れたキーができ、2 回目の glyph.m の展開が構文エラーになります。関数の中のエラーは表示されず、結果も 146 で補われるので正しいです。上の案にすれば、この経路も通らなくなります。
| function lib:text/core/tables.m {_:""} | ||
| data modify storage lib_text_fonts: Version set value "45ce851d4a644def5c8df7be1b9cf495e7dab15301250bdc6fad15eec4078029" |
There was a problem hiding this comment.
[WANT] 表の展開に失敗しても気付けない
tables.m のマクロ行に構文の誤りがあると、7 行目の展開は失敗します。それでも 8 行目で Version が書かれ、以降の /reload では 6 行目で戻るので、表の内容が変わるまで展開し直しません。
この失敗はどこにも表示されません。load の関数は出力を抑えた送信元で実行され、入れ子の関数のエラーはログにも出ません。tables.m は lint の対象外で、マクロ行は /reload でも解析されません。その結果、新しいワールドでは表が空のまま、既存のワールドでは古い表のまま、measure は 146 で補って成功を返します。新しいワールドでシナリオを実行すれば、最初のステップの tableLoaded で気付けます。
起きるのは生成した表が壊れていた場合だけなので、優先度は低めです。直すなら、展開の前に Version を消し、execute store success で展開の成否を受け取って、成功したときだけ書く形が考えられます。展開に失敗すると 0 が入ります。あわせて Version が無いときに measure を失敗させれば、壊れた表を 9px の成功ではなく失敗として受け取れます。
文字列や静的なTextComponentの送り幅を、通常フォントとUnicodeフォント強制時の両方で計算できるようにします。
lib:text/measureは文字列と太字指定を、lib:text/measure_componentは装飾と文章を直接指定したtranslateを受け取り、小数の送り幅と切り上げ幅を返します。両設定の幅は文字列を一度走査して計算します。default・uniformの未収録文字は、1 UTF-16コード単位あたり9px・太字加算0.5pxとして補完します。spaceの未収録文字、動的参照、未対応フォントや書式、計算範囲超過は失敗扱いです。成功・失敗にかかわらず作業領域と19個のTemporaryスコアを片付け、失敗時には途中の戻り値も削除します。
Minecraft 1.20.4と配布リソースパックから幅表を生成します。日本語、ラテン・ギリシャ・キリル文字、ルーン、ゲーム内文言に使う記号類と位置調整スペースを対象にし、共通値146を省略しました。表は7,935件・73,995バイトです。対象範囲外で補完値と幅が異なる文字には表の拡張が必要で、継続検査は #2312 で扱います。
幅表は
lib_text_fonts:に分離し、日常的に書き換えるlib:と同じ保存データに含めないようにします。core:load_onceで版が変わった場合だけ、dummy引数を持つmacroから表を展開します。展開後は次のreloadまでmacroキャッシュに残りますが、表を展開しないreloadでは巨大なSNBTの解析済みcompoundを作りません。生成済み表のlint除外は、引用符が必須のキーにも警告が出るため維持し、workflowに理由を記載しています。幅表の入力はTSB-ResourcePackの
feat/bossbar-fontsのフォントです。配布フォントを変更したときはscripts/text/README.mdの手順で再生成します。Assetから公開関数を使う際は、対応する公開宣言の生成が必要です。Minecraft 1.20.4の実サーバーで53項目が成功しました。補助文字、負の小数の丸め、±65,536px、各設定の文字列内・部分間の正負オーバーフロー、途中失敗時の後片付けを含みます。補助文字とオーバーフローの一部は幅表を一時的に差し替えるfixtureで確認しています。初期処理が長いため、検証runnerのRCON待ち時間をローカルで15秒から60秒へ変更して実行しました。静的解析はエラー・警告0件、生成結果の再現性も確認しています。検証の詳細と再実行シナリオは
docs/verification/text-measure.mdにあります。クライアントの画素やJavaのヒープ量は測定していません。