アプリ置き場

アプリ置き場

http://www.moreread.net/

Meltdown、Spectre、そしてJavaScript

CPUのOut Of Orderやら投機実行における脆弱性というところの仕組み(キャッシュに展開される)はなんとなくわかったのだけど、それはどうやって読み出すのだろう?JavaScriptからも可能ってのはどういうことなんだろう?
CPUのキャッシュに放り込むための投機実行のコードをJSで書けるのはわかるんだけども、

CPUキャッシュから情報を抜き出すための、FLUSH+RELOADなる方法が使われているようだ。サイドチャネルアタック(いろんな手段で観察して情報を推測したりする攻撃)らしいが。
読み取れないはずの領域のデータを添え字にしてメモリアクセスすると、
そこがキャッシュされるため、アクセス時間を正確にはかれば、データ内容が復元できる…?
 
JavaScript does not provide access to the rdtscp in-
struction, and Chrome intentionally degrades the accu-
racy of its high-resolution timer to dissuade timing at-
tacks using performance.now()[1].
However, the Web Workers feature of HTML5 makes it simple to cre-
ate a separate thread that repeatedly decrements a value
in a shared memory location [18, 32]. This approach
yielded a high-resolution timer that provided sufficient resolution
 
Javascriptからはperformance.now()といった高精度タイマーや、Workerを使うと再現でけると。
 
Jann Horn of Google Project Zero Security reported that speculative execution performed by modern CPUs could leak information through a timing side-channel attack. Microsoft Vulnerability Research extended this attack to browser JavaScript engines and demonstrated that code on a malicious web page could read data from other web sites (violating the same-origin policy) or private data from the browser itself.
Since this new class of attacks involves measuring precise time intervals, as a partial, short-term, mitigation we are disabling or reducing the precision of several time sources in Firefox. The precision of performance.now() has been reduced from 5μs to 20μs, and the SharedArrayBuffer feature has been disabled because it can be used to construct a high-resolution timer.
Mozillaはタイマーの制度を下げたのか。
SharedArrayBufferというのはWorker間でメモリを共有する仕組みで、高精度タイマーを作れちゃうのでこれをOffる対応も入ってると。
 

Webサイト リニューアル

レスポンシブルデザインとやらで、CSSFlexを使ってみた。
カードっぽいデザインでとにかくコンテンツを区切って全部表示しただけなんだけどね。ブラウザの幅を変えると表示がにゅっと動いて楽しい。

.flex {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.flexchild {
  flex-basis: 250px;
  min-width: 0;   /*こうやるとうまく文章が折り返すらしい*/
  word-wrap: break-word;

  /*孫要素の配置を制御する場合は、子要素にさらにFlex指定するとよさげ*/
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

コンテンツの中身は別管理にして、ソートとかフィルタとかできるようにしたいな。
f:id:nazenaninadesico:20180103074829p:plain
http://www.moreread.net/

さくらインターネットはWebフォントを無料でいろいろ使えるらしいので、使ってみたのだが、
f:id:nazenaninadesico:20180103074833p:plain
JSで動的に挿入したコンテンツにWebフォントが適用されてないくさい。びみょ……。
画像の「品」の字は静的コンテンツ部分に登場しなかった文字。必要な文字だけフォントを取得する仕組みらしい。

あと改めてフォントいろいろ見比べたけど、Windowsではメイリオがブラウザの標準フォントになってるので、読みやすさの観点ではそのままでも特に問題ない気がしてきて、Webフォントを使うのやめた。

MaDotPaint V1.0.0公開

MaDotPaint V1.0.0
 
ペイントツールを作ってみました。自分ツール。

 
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/_/ MaDotPaint
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
 
[Description]
2Dゲーム開発のお供に最適なペイントツールです。
操作手順が少なくて済むように設計されており、基本的な処理が簡単に実行できます。
表示倍率や表示位置の変更、トリミングなどをマウス操作だけで行うことができるため、高い作業効率を実現します。
また、画像サイズや、グリッド線を画面上に表示するため、確認作業にも適しています。
シンプルで軽量(たぶん)、MSペイントの代わりにどうぞ。
 
<2018/01/01> V1.0.0
First Release
 
[How to use]
左クリック:点描
左ドラッグ:矩形塗りつぶし(Shift+で線描画)
右クリック:スポイト
右ドラッグ:範囲コピー(コピー後は左クリックでペースト)
ホイール:表示倍率の変更
中ドラッグ:画像の表示位置変更(Ctrl+右ドラッグでも可)
 
画像の外側をスポイトすると、透過色を取ることができます。
パレットの各色をダブルクリックすると色を編集することができます。
パレットはEDGE形式のものを読み込むことが可能です。
 
[System Requirements]
Windows7 or later
.NET FrameWork 4.5 or later
 
[Uninstall]
Delete this folder.
 
[HP]
 
[Author]
nazenaninadesico : nazenaninadesico@gmail.com
 
[Credit]
デフォルトのパレットはこちらのMizさんのパレットを参考にさせていただきました。
 
ダウンロード先
 
なぜに?
久しぶりにゲーム開発をして、その中でさまざまな画像周りのツールにお世話になりました。しかしながら、操作性に納得がいくものがなく、また機能によって複数のアプリにまたがって利用が必要で煩雑。思えば10年以上前からそうでした。微妙にストレス。
ということで一念発起して、自分用ペイントツールを作ると決心しました。車輪の再発明感はんぱないけどしょうがないね。どこかには望みのツールがあったりするのかもだけど、見つからないんだ。
 
そして突貫で3日で作った。
とりあえずVectorに登録(10年以上使ってないアカウントを発掘)しといたけど、正月休みぽい。
 
セールスポイント

・画像サイズの数字が画面上に表示されるガイド付き。
 2Dゲームではドット単位の調整が必要なためあると便利。
・いつでもはじっこ(■のとこ)を掴んでトリミングやサイズ拡張が可能。
・マウスホイールで一瞬でズームイン、ズームアウト。
 画像の細部や全体像をぱぱっと確認できます。
・0.1倍まで縮小表示化。大きな画像の全体像をサクッと確認。
・高倍率のときはグリッド表示可能(打ち間違いを低減)。
・ミドルボタンドラッグ(又はCtrl+左ドラッグ)で画像の位置を変更可能。
 拡大中の面倒なスクロールバー操作とはお別れ!
・右クリックスポイトで、パレットまで移動しなくよい。
・範囲外をスポイトすると透過色をスポイト。
 そのまま透過色で描画すれば透過画像を生成可能。
 塗りつぶし、色置換、許容値の設定なども透過画像作成をサポート。
・右ドラッグで範囲コピー(そのまま左クリックでスタンプ可能)。
 クリップボードにも自動でコピーされます。
・左ドラッグで矩形塗りつぶし、描画効率アップ、消しゴム替わりにも。
・問答無用で32ビットPNG保存(他フォーマットは必要になれば追加予定)。
・単一ウィンドウアプリで管理が楽(MDIが苦手なだけ!)。
・MSペイント替わりにサクッと立ち上げられる軽量さ。シンプル!(低機能なだけ)
 
ターゲットは主にゲーム開発者(プログラマ)です。
グラフィッカーさんは、描画まわりが高機能なソフトを使ったほうが良いでしょう。
ゲーム開発の過程で、素材をトリミングしたり、加工したり、コードに落とす際に画像のサイズを確認したり、ちょっとした絵や仮画像を描いたり、スクリーンショット加工したり…といった場面で、高い効率性を実現します。たぶん……。加工系ツールと、ペイント系ツールの中間ぽいのかな。足りていない機能は徐々に追加していくつもり。飽きなければ!
 

アプリ公開 つづき

とりあえず全プラットフォームで公開されました。
Xamarin+CocosSharpなクロスプラットフォーム開発アプリ。
 
Android版は相変わらずダウンロードほぼゼロ。iOS版は無事公開されたけど、言語が英語になってるわ、カテゴリがアドベンチャーだわでどうしたらいいんだ。
PC版は「ふりーむ!」でレビューが2件もついてる!うれぴ!
モンスターランドやビックリマンワールドのアレなのでレトロゲーすきな方は是非プレイしてくださいまし。
 
 
iOS
 
PC版
 

 
さて、忘れないうちにまた何か作りたいものだけど。うーむ。

アプリ公開

初のAppStore申請。
①VisualStudioでReleaseビルドでipaファイルを生成する
iTunes Connectでアプリ追加したりバンドルID発行したりする
XcodeのApplicationLoaderからipaファイルをアップロードする
はじめてでよくわかっておらず、アップロードしようとするとエラーが発生。
ERROR ITMS-90161: "Invalid Provisioning Profile. ~
 
Provisioningファイルとやらが何かイマイチ理解してないけど、VisualStudioからは下記のところをDistributionにしたらなんかうまくいった気がする。

他にもアイコンの透過PNGやめーや的なエラーとかも出た。
とりあえず無事に審査待ちに。
 
Androidのほうは公開してから1日以上たってるんだけど、自分以外ダウンロード数0!
新着アプリって紹介されたりしないの?

どこからもリンクされないんじゃダウンロードされんわ。
どうすればいんだー。
 

Xamarin + CocosSharp を使ってみたい ⑧

iPadで画面の向きが変わってしまう問題
 
Info.plist

にチェックを入れたらiPadでも向き変更抑制が効くようになった。めでたし。
public override bool ShouldAutorotate()
{
    return true;
}
 
public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
{
    return UIInterfaceOrientationMask.Landscape;
}
 
 
CocosSharpのフォント描画
 
フォントの読み込み方法がわからない。うぐぐ。
CCLabel label = new CCLabel(string, "/Resources/Fonts/hoge.ttf", font.size);
 
ふむ?
/Resource/Content/hoge.ttfとおいて、プロパティから「コンテンツ」を選択すればよさげ?
CCLabel label = new CCLabel(string, "hoge.ttf", font.size);
読み込めた!
 
が、読み込みがくっそ遅い。Labelの数が多いと使うのは不可能なレベル。
CCLabel生成すると、それぞれフォント読み込んでるくさいなぁ。
 
あとCCRenderTextureに描画しているんだけど、初回描画はアンチエイリアシングOFFにしてもぼやける。一度描画して文字列変えたらようやくOFFにある、なんじゃこりゃ。
 
文字列描画まわりもあやしいなぁ。
できるだけ画像リソースで文字列をもっておいて描画するしかないか。。。
 
 
ロケールの判断
 
iPhoneで常にen-USじゃねーか(怒)
CultureInfo.CurrentCulture //en-US
 
しょうがないのでiPhoneネイティブで取って渡す。
だんだん構造がきたなくなってくるぞお。
NSLocale.CurrentLocale.LocaleIdentifier //ja_JP
 
 
Android版のログ出力抑制
 
AndroidEnvironmentで設定すればいいらしい
MONO_LOG_LEVEL=message
 
 
広告対応
 
AdMob登録後、
をNuGetしてきて、適当にこのへん見たりして実装してみる。
 
must be called on the main UI thread.
っておこられた。RunOnUiThreadというのを使うらしい。
activity.RunOnUiThread(() =>
{
    if (interstitialAd != null && interstitialAd.IsLoaded)
    {
        interstitialAd.Show();
    }
});
 
Interstitial広告は閉じると再度ロードが必要らしい。
AdListener.OnAdClosedでもっかい作る。
public override void OnAdClosed()
{
    base.OnAdClosed();
    interstitialAd.Dispose();
    //requestInterstitialAd();
}
 
 
アプリ名(Android)
 
アプリ名がどこ設定していいかわからなくて悩む。Activityのラベルだった。
[Activity(Label = "ここ", MainLauncher = true, Icon = "@drawable/icon", AlwaysRetainTaskState = true, LaunchMode = LaunchMode.SingleInstance, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
public class MainActivity : Activity
 
 
アイコンの作成
 
必要なアイコンをまとめて作ってくれるWebアプリ。すばらっ!
 
パワポでシートを正方形にして、適当に高解像度の画像を作る。
それをPNG出力して、先ほどのサイトに食わせると、30種類くらいの画像ができました。まじか、そんなに使うのか……。
 

 
 
Androidアプリのライフサイクル
 
ライフサイクルとか全然きにしてなかったけど、ふと戻るボタン押したらActivity死ぬじゃないの。初代Xperia時代から久しぶりの開発で、完全に忘れてた。
とりあえず、下記で戻るボタンをHOMEボタン化できた。
public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e)
{
    if (keyCode == Keycode.Back)
    {
        Intent homeIntent = new Intent(Intent.ActionMain);
        homeIntent.AddCategory(Intent.CategoryHome);
        homeIntent.SetFlags(ActivityFlags.NewTask);
        StartActivity(homeIntent);
        return true;
    }
    return base.OnKeyDown(keyCode, e);
}
 
あとは、Sleepボタン押したとき、他のアプリが動いたときにたまにActivityは死ぬ。
死んだら、CCSpriteやCCLabelなど、CocosSharpのUIコンポーネントのバッファがおかしくなってる。作り直さないとだめぽい。
もう完全にプロセス死んで再起動したほうがましなんだが……。なんでこんなゾンビ状態で動いてるの。プロセス殺す命令はAndroid5.0かららしい。4.xで動かしたいしなぁ。
 
 
ようやく
公開できそうなくらいにはなってきた。
くっそー1週間で作ったゲームの移植に3週間かかったなー。
iPhoneAndroidの知識の不足分を除いても、なかなかの地雷原ぷりでイニシャルコストは結構高いんじゃないかな。でもメンテは楽だと信じてる。あとやっぱC#だけで書けるのが大きい。

Xamarin + CocosSharp を使ってみたい ⑦

AndroidGC発生しまくりでカクカク問題
 
nursery-sizeをでっかく指定しておけばとりあえずGCを我慢してくれるようだけど。。。いろいろパラメータ指定したら、なんかときどき実行中にエラーでて落ちるように。
MONO_GC_PARAMS=bridge-implementation=tarjan,nursery-size=128m,soft-heap-limit=512m
 
The Xamarin.Android garbage collector can be configured by setting the MONO_GC_PARAMS environment variable. Environment variables may be set with a Build action of AndroidEnvironment.
The MONO_GC_PARAMS environment variable is a comma-separated list of the following parameters:
  • nursery-size = size : Sets the size of the nursery. The size is specified in bytes and must be a power of two. The suffixes k , m and g can be used to specify kilo-, mega- and gigabytes, respectively. The nursery is the first generation (of two). A larger nursery will usually speed up the program but will obviously use more memory. The default nursery size 512 kb.
  • soft-heap-limit = size : The target maximum managed memory consumption for the app. When memory use is below the specified value, the GC is optimized for execution time (fewer collections). Above this limit, the GC is optimized for memory usage (more collections).
  • evacuation-threshold = threshold : Sets the evacuation threshold in percent. The value must be an integer in the range 0 to 100. The default is 66. If the sweep phase of the collection finds that the occupancy of a specific heap block type is less than this percentage, it will do a copying collection for that block type in the next major collection, thereby restoring occupancy to close to 100 percent. A value of 0 turns evacuation off.
  • bridge-implementation = bridge implementation : This will set the GC Bridge option to help address GC performance issues. There are three possible values: old , new , tarjan.
  • bridge-require-precise-merge: The Tarjan bridge contains an optimization which may, on rare occasions, cause an object to be collected one GC after it first becomes garbage. Including this option disables that optimization, making GCs more predictable but potentially slower.
For example, to configure the GC to have a heap size limit of 128MB, add a new file to your Project with a Build action of AndroidEnvironment with the contents:
MONO_GC_PARAMS=soft-heap-limit=128m
 
.Androidプロジェクトにテキストファイルを追加して、プロパティウィンドウからタイプを
AndroidEnvironment
にすればよいらしい。要調整。
 

音が鳴らなくなる問題①
 
iOSバイスでしばらく動作テストしてると、必ず音が鳴らなくなって、そのうちフリーズ。ホワッツ
うそやろ……1024回で打ち止めって、しかも2年以上前から直ってないの?
たしかに1024回で「Failed to generate OpenAL data buffer:」と吐き出して、それ以上の再生が不可能になる。何かリークしてるのか?再生途中でストップをかけた分は回収されていて、寿命が延びてる気がする。
CCAudioEngine.SharedEngine.End();
とかしてみたが、特に意味はなかった。
 
自前でAudioエンジンのインスタンスを作ってみる。
CCAudioEngine engine =new CCAudioEngine();
 
~略~
 
engine.End();
engine.Dispose();
engine = new CCAudioEngine();
1024回をカウントして作り直してみるが効果なし。
が、なんということでしょう。CCAudioEngineを作り直したあとにGCかけると復活する。
System.GC.Collect();
 
AudioEngine作り直す度にBGMが止まったらうんこすぎるので、AudioEngineをBGM用とSE用を分けて2個にしてみる。おし、いけた。
余裕のあるタイミングでときどき初期化しとくほうがいいかなー。自前でインスタンス作ったから、PauseとResumeの伝達も自前になるんよね、たぶん。はぁ……。
 

音が鳴らなくなる問題②
 
iOSバイスでBGMが鳴らなくなってフリーズするのは別件だった。Audioは地雷原か……。
MP3をループで再生したところ、終了時点でおかしくなった。ループせず、以降のBGMの再生できず。午後のこ~だをひっぱりだしてきて、MP3→WAV→MP3と再変換してみたが直らず。データが悪いわけではなく、やはり何か問題を抱えてそうだ。
いくつか試した感じだとビットレートなどは関係なく、短めのBGMをループさせると、ちょくちょく再生終了時に死ぬ。誰も使ってないのかよ。
しょうがないので自前でループ機構を作る。終了を検知できないから、曲の再生時間を覚えておいて、フレームカウントから経過時間算出だよ!
いまのところちゃんと動いてる気がする。スリープ、レジュームすると狂いそうだなぁ。
 

固有実装
 
いざとなったらごりごり書くのか?書くしかないのか?
  • OnPlatform (XF 1.0 ~)
  • DependecyService (XF 1.0 ~)
  • Plugins for Xamarin
  • Custom Renderer (XF 1.0 ~)
  • Effects (XF 2.1 ~)
  • Native Embedding (XF 2.2 ~)
 

ジョイパッド対応
 
手元のGPD XDでデバッグしやすいようにパッド対応しようと思った。
あっさりできてうれぴ。Xamarinとはあまり関係ないけど。
どこにマッピングするのか試行錯誤がしやすいように割り当てを辞書に入れた。
// MainActivity.cs
public override bool OnKeyDown([GeneratedEnum] Keycode keyCode, KeyEvent e)
{
    if (dicPadmap.ContainsKey(keyCode))
    {
        Pad.getInstance().dwButtons |= dicPadmap[keyCode];//Padは独自クラス
        return true;
    }
    return base.OnKeyDown(keyCode, e);
}
 
public override bool OnKeyUp([GeneratedEnum] Keycode keyCode, KeyEvent e)
{
    if (dicPadmap.ContainsKey(keyCode))
    {
        Pad.getInstance().dwButtons&= ~dicPadmap[keyCode];
        return true;
    }
    return base.OnKeyUp(keyCode, e);
}
 
あとAndroidでステータスバーなしのフルスクリーン。Activityでセット。
Window.AddFlags(WindowManagerFlags.Fullscreen);
 

FPS計測
 
CocosSharpって簡単にFPSとる方法ってあるんだろうか?
よくわからないから自前で実装してみる。
どういう構造になっているかいまだによく理解してないが、VisitRendererとやらが実際に描画されたときに呼ばれるようだ。ここでカウントすればよさげ。
 
protected override void VisitRenderer(ref CCAffineTransform worldTransform)
{
    base.VisitRenderer(ref worldTransform);
 
    frameCounter.nextFrame();
}
 

最適化
 
GCの発生頻度を抑えるべくAndroidEnvironmentに加えて、CCNode系のクラスの生成/破棄をフレームごとに行うのをやめた。さすがに無理があったようだ。
そしたらGPD XD(2015年のミドルクラスくらい?)でも60FPSでるようになったのでこれで十分かな?