羽々斬 Android SDK

はじめに

これは羽々斬 Android SDK のマニュアルです。
羽々斬は吉里吉里2互換エンジンのため多くの部分は吉里吉里2と同様に考えてもらって問題ありませんが、Android や Java によって発生する差分機能や仕様についてここで記述します。
また、Android アプリは apk ファイル化する必要があるので、その手順についても解説します。


Android アプリの作り方

現在、羽々斬 Android SDKを使用してアプリを作るには Android SDK と Eclipse、JDKを必要とします。
将来的にパッケージ化ツールを作り簡略化する可能性はありますが、しばらくはAndroidアプリを開発するのと同じような手順を踏む必要があります。
詳細は 羽々斬 Android SDKのセットアップとゲームの作成方法 を参照してください。
Androidアプリの開発手順については理解しているものとして話を進めています。
もし不明な場合は他のサイトや書籍等で調べて解決してください。

簡単に説明すると――

1. 羽々斬 Android SDKをDLして展開します。
2. habakiriフォルダをworkspaceにコピーして、プロジェクトをインポートします。
3. 開発するAndroidアプリプロジェクトをEclipseで作り、ライブラリにhabakiriを追加します。
4. 添付の AndroidManifest.xml を参考にしてプロジェクトの AndroidManifest.xml を書き換えます。
 AndroidManifest については AndroidManifestの書き換えポイント を参照してください。
5. assetsフォルダにlicense.txtをコピーします。
6. res/drawable類のアイコンをアプリのアイコンに置き換えます。
7. res/values/strings/xml の app_name をアプリのタイトルに書き換えます。
8. apk内にすべてのデータを入れる場合は、assetsフォルダにdataフォルダ内のファイルとフォルダをコピーします。
 データが50MBを超える場合など他の方法で組み込む場合は データの組み込み方 を参照してください。
9. Android端末にインストールして動作を確認します。
10. アプリを署名しリリースします。


エンジン設定

engine.properties を assets 内に配置する事で、このファイルの内容に従いエンジンの挙動を設定する事が可能です。
標準的な設定をデフォルト動作としているため、普通はこの設定ファイルを使用して挙動を設定する必要はありません。
「設定名 = 設定値」の形で記載します。
SDK に添付されている engine.properties 内にはコメントの形で各種設定の簡単な説明が記述されています。

target
初期読み込み対象フォルダを指定します。
未指定の場合は assets から読み込まれます。
セーブデータの保存先にある特殊文字列を使った指定が可能です。
xp3ファイルを指定する時は末尾に>を付けます。
例 : target = $(externalappdatapath)/data.xp3>
text_draw_method
文字の描画方法を指定します。
api か engine を指定します。
基本的にデフォルトの engine で問題ありません。
tjb_bytecode_loading
.tjs ファイル指定時に .tjb ファイルを自動的に読もうとするかどうかです
true/yes/false/no を指定します。
デフォルトは true です。
gclim
画像のキャッシュ制限です。
auto かサイズを直接指定します。
VM に管理を任せる構造に変更した場合、auto 以外は意味がなくなる可能性があります。
デフォルトは auto です。
gsplit
画像演算の分割処理方法を指定します。
yes/no/int/simple/bidi を指定します。
現在常に no 固定で、この値を指定しても意味はありません。
holdalpha
Layer.holdAlpha プロパティのデフォルトの値を true/yes/false/no で指定します。
デフォルトは false です。
datapath
データ保存フォルダ指定です。
デフォルトは $(externalappdatapath)\\savedata です。
セーブデータの保存先を参照してください。
modal_force_result_true
モーダル表示した時、指定メンバーに強制的に true を入れるかどうかを true/yes/false/no で指定します。
羽々斬はウィンドウをモーダル表示出来ないため Yes/No ダイアログなどで結果が常に false となり終了できないことが考えられるので、強制的に true を入れて終了可能にします。
デフォルトは true です。
modal_force_result_member_name
モーダル表示した時に true を入れるメンバ名を指定します。
デフォルトは result です。
result は KAG3 のYesNoダイアログの結果値です。
forcelog
ファイルへのログ出力を yes/no/clear で指定します。
デフォルトは no です。
設定値はそれぞれ以下の通りです。
yes : ファイルに追記する。
no : ファイルに出力しない。
clear : 前回起動時のログを消してログを出力する。
logerror
エラー時のファイルへのログを yes/no/clear で指定します。
デフォルトは yes です。
それぞれの設定値の意味は forcelog と同じです。
laxtimer
一度に蓄えられるタイマーイベントを制限するかどうかを yes/no で指定します
デフォルトは no です。
purge_on_hide
レイヤー非表示時に画像メモリを解放するか否かを yes/no/true/false で指定します。
デフォルトは true です。
late_image_allocate
画像メモリの確保を出来るだけ遅延させるか否かを yes/no/true/false で指定します。
デフォルトは true です。
log_queueing
ログをキューイングするか否かを yes/no/true/false で指定します。
デフォルトは true です。
エラー発生時少し前からエラーを出力するには必要です。
log_max_lines
ログを何件キューイングするかです。
多いとその分メモリを消費します。
デフォルトは 2048 です。
log_to_file_roll_back
エラー時にログをファイルに書き出す時、何件戻って書き出すかです。
デフォルトは 100 です。
log_timestamp
各ログにタイムスタンプを含めるか否かを yes/no/true/false で指定します。
タイムスタンプがない方が少し高速です。
タイムスタンプがない場合、ログの比較がしやすいですが、発生時期等がわからなくなります。
デフォルトは true です。


AndroidManifestの書き換えポイント

詳細な意味は Android のマニュアル等で調べてください。
羽々斬で関係しそうな部分のみピックアップして以下に解説します。
sample/AndroidManifest.xml を参考にして書き換えると良いと思います。

パッケージ名とバージョン
manifestタグのパッケージ名とバージョンを書き換えます。
Eclipse で作った場合、適切なパッケージ名が設定されていると思います。
パッケージ名は保有しているドメイン名を逆にしたもの+アプリ名の組み合わせで指定します。
versionCode は連番で指定し、更新したときに数値を上げるとインストールしている端末で更新が通知されます。
versionName は人が読みやすいバージョン名なのでわかりやすい文字列を指定します。

動作対象とする Android のバージョンを指定します。
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="10" />
Android 1.6 以上で動作し、Android 2.3.4 での実行を想定し設計されていることになります。
targetSdkVersion を 11以上とした場合、Android 3.0以降でメニューボタンが表示されなくなります。
ただ、フルスクリーン等との兼ね合いからメニューボタンが表示が表示される事を想定して作るのは好ましくありません。
動作する最小レベルの指定はJIT等による速度、メモリ容量などの兼ね合いから Android 1.6 としてもまともに動作しないかもしれません。
どのバージョン以上なら問題ないかテストして、最小レベルを設定する必要があります。
ゲームにもよりますが Android 2.2 ( API Level 8 ) 辺りが現実的な最小レベルではないかと推測されます。

SD へのアクセスは必須です。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
この指定を入れる必要があります。

サーバー等からデータをダウンロードする必要がある場合は、ネットワークアクセスのパーミッションが必要です
<uses-permission android:name="android.permission.INTERNET" />

ラージヒープ指定
<application android:name="jp.kirikiri.tvp2env.ApplicationSystem" android:icon="@drawable/icon" android:label="@string/app_name" android:largeHeap="true">
3.0 以降でメモリを多く使う場合はラージヒープ指定 ( android:largeHeap="true" ) が必要です。
この指定を行うことで、Android 3.0 以降で 256MB 程度のメモリを使用可能になり、画像容量の心配ほとんどなくなります。
ただ、3.0 未満には効果がないので、3.0 未満も対象としているときはより少ないメモリ容量で動くようにする必要があります。
詳細は メモリ使用量 を参照してください。

横向き、縦向きの指定。
activity タグの android:screenOrientation="landscape" とすることで横向き固定に出来ます。
portrait を指定すると縦向き固定になります。
この方向に応じた画面サイズを指定して Window が作られるようにします。
画面表示 も参照してください。


データの組み込み方

assets フォルダの中に data フォルダの中身をすべておきます。
startup.tjs が assets/startup.tjs の位置になる形です。
assets フォルダは、Android 2.3 未満では1ファイル1MB制限があります。
現在のところデータは assets フォルダの中に置く方法のみとなっていますが、早期に SDへのデータのコピーやダウンロードを実装する予定です。
assets から SDへコピーして実行する。
SD へ直接ダウンロードして実行する。
APK Expansion Files を使用する。
スクリプトのみ assets へ置き、その他のデータは SDカードへ置くなどの使用方法が出来る形にする予定です。


セーブデータの保存先

デフォルトのセーブデータの保存先は"外部保存域のルート/Android/data/<package_name>/files/"に指定のパス(savedata)を加えた位置です。
エンジン設定ファイルを書き換える事で保存先を変更する事が出来ますが、Android 推奨のデータ保存先が上述の場所のため、基本的には変更しません。
デフォルトの保存先はAndroid 2.2以降の場合アプリのアンインストールと共に削除されます。
アンインストール時に削除される動作が好ましくない場合は、このデータ保存場所を別に指定する必要があります。
エンジン設定ファイルでのデータパスを指定する場合、以下の特殊な文字列を含めて指定します。

$(appdatapath)
アプリケーション固有の内部保存域をさします。
環境依存ですが、"/data/data/<package_name>/files"が一般的です。
これ以下のパスを指定するとアプリケーションのアンインストールと共に削除されます。
$(externalpath)
外部保存域をさします。 SDカードに保存されるのが一般的で、パスは環境依存ですが"/mnt/sdcard"などが使われます。
このパスを直接指定するとSDカードのルートに配置される事になるので、サブディレクトリも同時に指定します。
$(externalappdatapath)
デフォルトのアプリケーション固有の外部保存域をさします。
"外部保存域のルート/Android/data/<package_name>/files/"になります。
これ以下のパスを指定するとAndroid 2.2以降の場合アプリのアンインストールと共に削除されます。
$(package)
アプリケーションのパッケージ名が展開されます。
この指定単体ではなく、他のパス指定と共に使用します。


画面表示

AndroidManifest で指定した方向と生成した Window のサイズで表示されるサイズが決定されます。
現状、常にフルスクリーン表示となり、Window のサイズが内接するように拡大縮小が行われて表示されます。
拡大縮小で余った表示されない領域は黒で塗りつぶされます。
塗りつぶし色の指定はありません。
AndroidManifest に画面の向きを指定しない場合の動作は現在のところ不定です。
縦もしくは横固定を AndroidManifest で指定してください。
将来的には Window へのイベント等で画面の向き変更を通知する仕組みを組み込む予定です。


メモリ使用量

PC に比べて Android は使用可能メモリ量が大きく制限されています。
Android 3.0 未満の環境では顕著で、端末によりますが16MB〜70MBとかなり少なくなっています。
このような環境での動作を想定する場合、同時使用画像枚数等に十分注意しないとメモリ不足でアプリケーションが終了してしまいます。
KAG3 をそのまま使う場合、デフォルトで多くのメモリ量が必要なため特に注意が必要です。
Android 3.0 以降で AndroidManifest に android:largeHeap="true" を指定した場合は、256MB 程度は利用できるためほぼ気にせず作る事ができます。
調査した範囲での利用可能メモリ量を以下に記述しておきます。
Xperia 24MB
Galaxy TAB 48MB
Xperia arc 32MB
IS03 40MB
EeePad transformer TF101 48MB
Galaxy S2 70MB
MEDIAS N-06C 30MB
NEXUS ONE 24MB
NEXUS S 32MB
ATRIX 4G 32MB
IS01 24MB
Optimus chat (L-04C) 24MB
これらのサイズを参考にして同時使用枚数等を決定してください。

OpenGL ES 上のフレームバッファに画像を格納するとアプリごとのメモリ制限を超えられますが、吉里吉里2と同じようにCPUですべて処理する構造のためアプリケーションヒープの制約を受けています。
将来的には OpenGL ES 2.0 を利用して描画する事によってメモリ制限を緩和する機能も実装する可能性はありますが、その場合 Android 2.2 以降という制限が付きます。


アプリケーションの割り込み

Android では単一アプリケーションのみがアクティブになり全画面を占有し他のアプリケーションはバックグラウンドに移ります。
現在のところ羽々斬はバックグラウンドに移ったときアプリケーションを終了します。
このため電話の着信などでゲームが中断されるとセーブされずに終了してしまう危険性があります。
ゲームを実装するときはオートセーブのような機能を実装することが望ましいです。
この動作は将来的に変更される可能性がありますが、バックグラウンドに移ったアプリケーションのメモリは端末のメモリが不足したとき強制的に解放されていまう可能性があります。
このため終了動作ではなくバックグラウンドに残り、メモリが解放されていなければ継続可能に仕様を変更したとしても、メモリが強制解放されてしまっている場合はタイトル画面に戻るなどの動作をする事になります。
タイトルに戻った場合は当然バックグラウンドに移る前の状態は失われてしまうので、セーブされずにタイトルに飛ばされる事になります。
このような事情から終了する使用かどうかにかかわらず、ゲーム進行中にバックグラウンドで自動的にセーブする動作の組み込みは必要となります。
システムで現在の状態をディスクに書き出し、復元する事も不可能ではないですが、実装には時間を要します。


画像領域の遅延確保

羽々斬Androidでは実際にレイヤーの画像領域が必要となるまでメモリ確保されません。
また、単一色で塗りつぶされたレイヤーもピクセルデータは持たず、サイズと色のみ保有しています。
この遅延確保等の機能によってメモリ使用量の削減と起動の高速化を行っています。
遅延確保はエンジン設定で無効にする事も可能です。
描画がおかしい場合、無効にする事で解消される場合もあります


画像領域の明示的解放

吉里吉里2ではレイヤーの画像領域を明示的に解放することは出来ませんが、羽々斬Androidではメモリ節約のため明示的に解放するメソッドを追加しています(KAG3 の freeimage はレイヤーの画像を小さくする事で使用量を少なくする機能です)。
Layer.purgeImage をコールする事でそのレイヤーが保持する画像用メモリを解放します。
ただし、その画像が複数レイヤーで共有化されている場合は解放されません。


画像領域の自動解放

羽々斬Androidではレイヤーが非表示になる/すると保持している画像を自動的に解放してしまいます。
一度非表示にした後再び使用するときには再度読み込むと言う使い方が一般的であると思われるため、実際の動作にはあまり影響せずメモリを節約できます。
この動作が好ましくない場合、エンジン設定で無効にする事も可能です。


動作環境

羽々斬 Android は、Android 1.6以降を動作対象としています。
ただし、Android 2.2 未満では JIT がないため動作速度が遅い可能性があります。
また、メモリ使用量に記述したように Android 3.0 未満では使用可能メモリ量に大きな制約があります。


メニュー

Android のシステムのメニューは2階層までしかないため、羽々斬 Android では独自にメニューを実装しています。
これによって吉里吉里2と同じように2階層以上のメニューやチェックマーク、ラジオボタンが実現されています。
メニューは吉里吉里2のフルスクリーン時のように通常は非表示です。
メニューキーを押すか Window.showMenu() をコールする事によって表示/非表示されます。
Android 3.0 以降はメニューキーがなフルスクリーンの場合はメニューボタンも表示できないためゲームのどこかで Window.showMenu() をコールするボタンを配置するか、そもそも標準メニュー機能を使用せずにすべてゲーム内でメニューを実装してしまう必要があります。
ただ、将来的に画面外からのスワイプによってメニューを表示する機能を実装する可能性はあります。


バイトコード

スマートフォンの速度は年々倍増しますが PC に比べるとまだまだ圧倒的に遅いです。
TJS2 スクリプトを実行時にコンパイルすると多くの時間がかかり起動時の待ち時間が長くなるため事前にコンパイルしバイトコードとしておくことで高速化しておく事を推奨します。
コンパイルは、TJSスクリプトで Scripts.compileStorage("system/MainWindow.tjs"); のように記述します。
バイトコード化用のツール(スクリプト)を使う事で、Window に D&D でコンパイル出来ます。
compilerツール(スクリプト)は SDK に添付されています。
コンパイル後のバイトコードファイルはsavedataフォルダに出力されるので、これを再び system フォルダに入れる事でバイトコードが優先して読み込まれます。
実行時にコンパイルするのに比べて、バイトコードを読み込む場合は10倍程度高速です。


リリーサー

XP3 ファイルを利用する場合、リリーサーは吉里吉里2のものをそのまま使います。
ただ、動画や音声は圧縮して格納すると羽々斬Androidでは再生できなくなるので、それらは圧縮せずに格納してください(デフォルトでは無圧縮になっていると思います)。
また、OggVorbis コードブック共有化のチェックは入れないでください。
これを有効にすると再生できなくなってしまいます。


ライセンス表示

本体のライセンスもそうですが、オープンソースのライブラリや吉里吉里2のソースコードからJavaに書き換えたソースコードを使用しているためどこかでライセンスを表示する必要があります。
スマートフォンはキーボードがない機種が大半である事から、吉里吉里2のようなショートカットで表示する方法は使えないため、羽々斬Androidではデータフォルダにライセンスファイルを出力する形になっています。
出力先は"外部保存域のルート/Android/data//files/license.txt"になります。
このため組み込み時にどこかでライセンスを表示する等はなくても問題ありません。


画像ファイルフォーマット

Android が読み込める画像 ( PNG, JPEG, BMP ) と TLG フォーマットをサポートします。
領域画像はパレットを持つ PNG のみ読み込み可能です。インターレース指定は対応しません。


音声ファイルフォーマット

Android が読み込める音声ファイルが使用可能です。
Ogg Vorbis と WAVE ファイルが推奨です。
MIDI と CD-DA には対応していません。


動画ファイルフォーマット

Android が読み込める動画ファイルが使用可能です。
対応端末を考慮すると MPEG4 になると思います。
MPEG4 を使用する場合ライセンスに注意してください。


メモリ管理の差異

吉里吉里2は、リファレンスカウント方式によってメモリ管理を行っていますが、羽々斬では Java の GC に頼ったメモリ管理を行っています。
Java の GC に頼るとリファレンスカウント方式の循環参照の回避などメリットがありますが、いくつかの問題とオリジナルと異なる挙動が発生すると言う問題があります。
吉里吉里2はリファレンスカウントなので、カウントが消えた瞬間に解放されますが、Java の GC の場合はJVM の GC タイミング依存になり、オリジナルとは異なったタイミングでオブジェクトが消えます。
TJS2 で参照が消えるのに任せた組み方をしていると、このタイミングの問題が顕在化する事がありえます。
顕在化するのはレイヤークラスくらいではないかと思っていますが、他のクラスでも起こりえます。
レイヤーの場合、ネイティブインスタンスの解放タイミングが異なるためにしばらく親子関係が解消されず、レイヤー階層に参照されなくなったレイヤーが残る事になります。
不要になったときに適切に invalidate していれば、このタイミング依存の問題に遭遇する事はありません。
TJS2 の仕様上は、オブジェクトがいつ解放されるかは不定となっているので、仕様は満たせていますが、使い方によっては異なる挙動をする事があるので少し注意した方がいいかもしれません。

Java の GC はと言うか、finalize メソッドは Finalizer スレッドでコールされます。
TJS2 の invalidate 処理は他のメソッドと同じスレッドで動作する必要があるため、Java の finalize メソッドで invalidate 処理をキューにいれ、TJS2 VM スレッドでそのキューに入った invalidate 処理を実行します。
リファレンスカウント方式だとカウントがなくなった時点、つまり TJS2 の処理の途中に解放処理が挟まる事になりますが、invalidate 処理をキューにいれて処理をする場合、TJS2 のメソッド呼び出しがすべて返って来るまで処理できません。
つまり、1回のメソッド呼び出しでクラス生成を行ってそのクラスの参照が切れる処理を何度もするとメモリがどんどん消費されてメモリ不足に陥ります。
ただ、ゲームのような用途でそのような処理を書く事はないと思われますので、問題は顕在化しないと考えられますが、バッチ処理を書いた場合ははまる可能性が高いです。


Window

Android は基本的に複数のウィンドウを持たず、切り替えて表示するような形になっています。
吉里吉里2 では複数のウィンドウを同時に生成して表示する事が出来るが、羽々斬Androidでは1つのウィンドウしか生成、表示できません。
最初に生成されたウィンドウがActivityと関連づけられ、そのウィンドウがメインとして動作します。
複数ウィンドウを表示しようとした場合の動作は不定です(単純に表示されないと考えられます)。
また、モーダルウィンドウは作る事はできず、表示しても無効になります。


TJS2定数

未定義のプリプロセッサ用定数は 0 として扱われるため、吉里吉里2で定義されている/いないに関わらず互換システムでは任意の定数が定義可能です。
これを利用して羽々斬ではいくつかの定数を定義しています。
これらの定数を利用する事で TJS2 スクリプトでスクリプトの切り替えが行え、単一のスクリプトで互換システム固有の機能を使用したり出来ます。

compatibleSystem : 1
environment 1 : android, 2 : Java application, 3 : Java applet

compatibleSystem が 1 かどうかで吉里吉里2か羽々斬かを識別して動作を切り替えられます。


整数型のサイズ

吉里吉里2ではTJS2の整数型は64bitですが、羽々斬では32bitになっています
そのため32bitを超える整数を扱う場合に挙動が異なります。
Date.getTime/setTime 等32bitの範囲を超える事がわかっているものについてはdouble値として保持され、問題が発生しないように対処しています。


音声/動画同時再生数制限

音声と動画を合わせた同時再生数はAndroid(のMediaPlayerクラス)の制限により4つまでに制限されています。


Add Alpha制限

Add Alphaのサポートは不完全です。
そのため期待よりも薄く合成されてしまう可能性があります。
Add Alphaではなく通常のAlphaを使用を推奨します。


データのダウンロード/コピー指定

データのサイズが大きすぎて apk に納めるのが難しい場合など、Web 上からファイルをダウンロードして実行することが出来ます。
ダウンロードして実行する場合、assets フォルダ内に datainitialize.txt と言う名前でテキストファイルを置き、この中にダウンロード先等の情報を記載します。
ダウンロード指定は、以下のように記載します。
download [URL] [destination] [file size] [MD5]
URL は、ダウンロード先のアドレスを記載します。
例 : http://your.address.com/data.xp3
destination は、Android 端末内のコピー先です。
指定したファイルはここにダウンロードされます。
このファイルから起動する場合は、engine.properties の target でこのファイルを指定します。
engine.properties の target についてはエンジン設定を参照してください。
セーブデータの保存先にある特殊文字列を使った指定も可能です。
例 : $(externalappdatapath)/data.xp3
file size は、指定したファイルのサイズを記述します。
ダウンロード時にすべて正しくダウンロードできたかどうかチェックするのに使用されます。
MD5 は、指定したファイルの MD5 を記述します。
この値はダウンロードしたファイルが化けていないか確認するために使用されます。
SDK に添付されている md5gen.jar を使用することで MD5 を得る事が出来ます(他の方法で計算しても問題ありません)。
md5gen.jar の使用方法は添付の md5gen.txt を参照してください。
md5gen.jar の出力には、以下のような文が含まれるので、この URL を変更することでほぼそのまま使用できます。
download http://your.address.com/data.xp3 $(externalappdatapath)/data.xp3 360 92651ed3625286dab9dc71baa4065a13

apk にすべて納めて問題ない場合でも、assets へのアクセスは遅いため、大量のファイルがあると起動に時間がかかってしまいます。
また、日本語ファイル名等も置くことが出来ないため、そのような場合は XP3 ファイルにして格納することになりますが、assets に置いた XP3 ファイルのアクセスはかなり遅くなってしまうため使いづらいです。
このような時のために SD にファイルをコピーしてそこから起動する事が出来ます。
SD にコピーして実行する場合、assets フォルダ内に datainitialize.txt と言う名前でテキストファイルを置き、この中にコピー先等の情報を記載します。
コピー指定は、以下のように記載します。
copy [source file] [destination file] [file size]
source file は、コピー元のファイルパスを記述します。
現状 asset:// からのみコピーできます。
例 : asset://data.xp3
destination file は、コピー先のファイルパスを記述します。
セーブデータの保存先にある特殊文字列を使った指定も可能です。
例 : $(externalappdatapath)/data.xp3
file size は、ファイルのサイズを記述します。
コピーが正常に行われたか確認するために使用されます。
ファイルサイズはコピー元ファイルからの取得でも問題ないため、将来的にはこのファイルサイズ指定は無視される可能性があります。

datainitialize.txt には以上のような指定が可能で、複数記述することも出来ます。
複数記述した場合は、上から順に実行されます。


既知の不具合




更新履歴

2012/08/08 : データのダウンロード/コピー指定の説明追加
    エンジン設定に詳細加筆。

2012/07/23 : 誤字修正

2012/07/23 : ドキュメント初版公開


 
Total : Today : Yesterday :