前回までは、ジウブが返ってきたところまで進んだ。
ゲーム内スクリプトのエンコード(トピックまで中国語になってた)を修正して、日本語版もしっかりスクリプト内のトピックを日本語にかえたことで、クエストがちゃんと進むようになった。
Morrowindの構造を理解すればするほど、英語以外の言語に対応させる気がさらさらないことがよくわかった。
フォント・エンジン戦争
文字が表示されない、消える問題

ゲームは起動した。日本語も出た。しかし、プレイしていると奇妙な現象に気づいた。
「立」「用」「方」などの常用漢字の一部が表示されず、空白になる。
ログにはエラーが出ていない。フォントファイルには文字が含まれている。
この問題は解決までに本当に時間がかかった。
原因は、OpenMWのGUIライブラリ(MyGUI)の仕様にあった。
MyGUIは、使用するフォントの全文字を1枚のテクスチャ(画像)に焼き込んでから描画する。
このテクスチャサイズの上限は16384px。
私が最初に選んだ「Noto Sans JP」(このブログでも採用でキレイ)はグリフが44,000以上あり、テクスチャに入り切らなかった文字が欠落していた。
解決策として、文字数をJIS第一・第二水準に絞った「Kosugi」フォント(約7,000グリフ)を採用することで、全文字の表示に成功した。まさかフォントにグリフ制限があるとは思ってもみなかった。
Daedricフォント問題
それと、デイドラ文字の仕様も少しハマった。
巻物を開くと、本来はデイドラ文字(架空の文字)で書かれるべき部分が、普通の英語で表示されていた。
本来は、デイドラ文字を英語に翻訳する作業が必要になる(アルファベットに対応している)が、これでは普通の本となってしまう。
(画像は撮り忘れたのでない)
調べると、翻訳データ内で <FONT FACE="Daedric"> タグの中身まで日本語に翻訳してしまっていた。
- Daedricフォントは英字(A-Z)しか持っていないため、日本語を表示しようとしてフォールバックが発生していた
- これは実プレイをしないと気付かないバグである。
ここは意図的にデータを英語に戻すことで、デイドラ文字の表示問題は解決した。
魔法効果の語順問題
この辺の問題は同時多発的に発生して、ひとつずつ直していったため、かなり時間がかかっている。
これは「日本語」特有の問題だった。
まずは下の画像を見てほしい。めちゃくちゃ分かりづらい効果説明。

このクソの原因はMorrowindの仕様にあった。
魔法の効果説明文は、エンジン側で以下のように「英単語のパーツ」を結合して生成されている。
String tooltip = EffectName + " " + Magnitude + " " + sPts + " " + sFor + " " + Duration + " " + sSecs + " " + sOn + " " + Target;エンジンは「英語の文法」に従って変数を並べているだけだ。
しかし、「日本語」は語順が違う。
つまり、本来は・・・
「5秒間の間、(Duration)」→「10ポイントの(Magnitude)」→「炎ダメージを与える(EffectName)」
という文章で表示したいが、ゲーム側の仕様で、各単語の表示順序が決まってしまっているため、どう翻訳しようが解決できない問題だった。
なのて解決しようとすると、ゲームエンジン自体に手を加えて、改造しなければならない。
この時点で、ソースコードの大規模な改修が確定した。しかもC++。
で、やるべきか?
いや、もっと賢い方法があるはずだ・・・たぶん。
GMST(Game Settings)の無効化で無理やり解決
幸い、これはゲームエンジンを弄くらなくても解決する方法を見つけた!
Morrowindには GMST (Game Setting) という、ゲーム内の定型文を定義するレコードがある。
ここに sFor(for)や sSeconds(secs)といった単語が定義されている。このクソが諸悪の根源である。
このGMSTを「翻訳」せず、単に無効化することにしてみた。
まず、
- 接続詞を消す
- sFor (“for”) → “”(空文字)
- sOn (“on”) → “”(空文字)
- 日本語には “for” や “on” に相当するスペース区切りの前置詞は不要。邪魔なだけなので消してしまう。
- 単位を日本語の接尾辞にする
- sSeconds (“secs”) → “秒間”
- sPts (“pts”) → “pt”(または「ポイント」)
- sTo (“to”) → “~”
- 語順の違和感は「雰囲気」で誤魔化す
そもそもこんな仕様なのに、自然な日本語として出力させよう、とするからおかしくなる。
情報を並列した「スペック表」みたいにしとけばおk!
GMSTを書き換えたESPを適用すると、

これなら読める!わかりやすい!
本当は、ターゲットに15秒間、◯ポイントの◯◯を与える みたいな感じが良いのだろうが、これでも十分伝わるし、これ以上のことはゲームエンジンの改修が必須なので、やめた。
でも結局ゲームエンジンを改修する羽目に…
基本的に、わたしの方針として、OpenMWのソースをいじくって日本語専用のフォーク版を作る、というのは想定していなかった。
まず、やりたくなかったし、自分の知識の範疇の外だから。
フォーク版を作ると、まずバグが起きたときの対応が面倒だし、もうすでにFF14のプラグインのフォーク版をいくつか抱えているので、これ以上アップデート対応を細かくやっていくのは難しい。 ひとりじゃむり。
ただ、どうしてもいじらざるを得ない状況になった。
1. フォントサイズのハードコード限界
4K解像度のモニタでMorrowindを起動すると、会話ウィンドウの文字が豆粒のように小さい。これはフォント依存の部分も大きいが、会話ウィンドウ内はとにかく文字が小さい。
でもOpenMWには、設定にFont Size という項目がある。
しかし、数値をいくら上げても、文字はある一定の大きさ(体感18px程度)で頭打ちになる。(.cfgファイルから変更してるのに!)
どうせハードコードされてんでしょ…とOpenMWのソースを調べると
// components/settings/categories/gui.hpp
SettingValue<int> mFontSize{ mIndex, "GUI", "font size", makeClampSanitizerInt(12, 18) };やっぱり上限が 18 にハードコードされていた。
サニタイザー(入力値チェック)が、設定ファイルの数値を強制的に18に丸めていたのだ。
これを突破するには、バイナリをデコンパイルしてアセンブラを書き換えるか、ソースコードを修正してビルドし直すしかない。
いくらC++を触りたくないといえど、圧倒的に後者の方がマシだ…
やることになった…
2. 特殊フォント「Magic Cards」の挙動
これも困った問題だった。

ゲーム内には「Magic Cards」という、デイドラ文字や暗号文を表示するための特殊フォント指定がある。
しかし、日本語フォントを強制適用すると、この特殊フォントが表示されるべき箇所までゴシック体になってしまい、雰囲気が台無しになる。
デイドラ文字の方は、専用フォントで指定されているので、テキストが英語であれば正常に表示される。
しかしこっちはデフォルトフォントを指定しているため、何もしないと日本語のフォントが勝手に使われる、ということが起きていた。
なお、中国語版ではシカトして中国語フォントのままにしていた。
それでもよかったのだが、一部の書籍では、雰囲気のいい「読めないことに意味がある」テキストに使われていた。
ロア的に意味のある表現に使用されていたので、「実装の面倒くささ」という理由で切り捨てるのは、なんだかもったいなかった。
なので、デイドラ文字と同じ仕様で実装することにした。
具体的には、fontloader.cppのロジックに 「フォント名が “Magic Cards” の場合のみ、別のTTFファイルを読み込む」という処理を追加した。

デフォルトで使われているフォントだし、諦めなくてよかった! こういう細かい(わたしの)配慮が、没入感を高めることに貢献するのです。
3. CJKの禁則処理と改行

これも大変だった。一番大変だったかもしれない。
主にスクリプトで表示されるダイアログや、字幕に使われる下部の枠だが、テキストが英語ベースの幅となっているため、文字が見切れていた。
この枠自体はエンジンのレイアウト設定から変更が効くが、幅を超える文字数のときに改行がされないという問題があった。
英語版(本家)は、これを単語と単語の間のスペースを利用して判定し、折り返し(改行)処理をすることで対応していた。
しか日本語には、文章の途中にスペースなんてものは無い。
結果として、既存のエンジンは日本語の文章を「超巨大な1つの単語」として認識してしまい、行末で強引に文字を切ったり、あるいは一行まるごと次の行に送ったりして、レイアウトが崩壊していた。
わたしのスキルが低く、中華フォーク版のOpenMWがどのようにこれを解決してるのかはわからなかったが、とにかく日本語文字(CJK)の境界判定を行い、適切な箇所で改行を挿入するロジックを追加する必要があった。
わたしはC++をつかったことがないので、この辺の仕様変更は本当に苦労した。
AIに聞きながら、なんとか
- 改行の本体対応はMyGUI本体の
MyGUI_TextView.cppへパッチを当てる方式で実装した。 - OpenMW側では
extern/CMakeLists.txtにPATCH_COMMANDを追加し、MyGUI取得時に自動でパッチを適用するようにした。
具体的には、ワードラップ処理を文字列置換で改変している。
- 前文字追跡を追加
lastCharを導入して、現在文字だけでなく直前文字も参照可能にした。
- 改行境界の判定を拡張
- 従来の「スペース/タブ境界」だけでなく、
character >= 0x2000またはlastChar >= 0x2000を改行候補として扱う。 - 目的は、CJK文字列でも単語区切りなしで折返せるようにすること。
- 従来の「スペース/タブ境界」だけでなく、
- 行頭崩れ対策
- 折返し判定に
width > 0条件を追加し、行頭での不正な折返しを防止。
- 折返し判定に
- ロールバック後の再読込処理
- 折返しロールバック後に
lastCharをリセットし、characterを再取得してインデックス調整する処理を追加。 - これでロールバック直後の文字取りこぼしや判定ずれを回避。
- 折返しロールバック後に

いい感じになった。

コメント