2018年12月30日日曜日

curlを使ってサーバーからファイルをダウンロードしようとしたらできなかった話

ネットワーク周りを調べ始めて一週間ほどたち、ローカルだけど自作ホームページを表示できたので、じゃやりたいことを本格的にするかと、curlを使ってサーバーからアップロードしたファイルをダウンロードしようとしたら違うものが保存された。
#失敗したもの
curl -X POST localhost/page/download > test.txt
サーバー側のログを見るとCan't verify CSRF token authenticityとでていて頭?である。
上のエラーメッセージで調べるとこちらのページに解決策があった。
要は、ブラウザが裏側で行っていたことをしてなかったのが、失敗の原因だった。 なので、そのページ通りにコマンドを実行したら無事できて、よかった(月並み)。
curl localhost/ --cokkie-jar cookie | grep csrf
curl localhost/page \
  -F "authenticty_token='上のgrepしたもの中のcsrf-tokenのcontentにある文字列を入れる'" --cookie cookie > test.txt

CSRFについて

CSRFはCross-Site Request Forgeries(クロスサイトリクエストフォージェリ)と呼ばれるWebアプリケーションの脆弱性の一つ。 Wikepediaを見ると「ぼくはまちちゃん」事件で利用されたそうだ。

いくつかサイトを調べているとサーバー側の不備が原因の脆弱性だそうだ。 ユーザー側の対策としては、使っていないときはログアウトする、怪しいURLにはアクセスしないがある。 (個人的にスマホで毎回ログイン/ログアウトしている人いるのかな?って。スマホに危機が迫っている。何者かに侵略されているぞ!)

リンク一覧

  1. IPA 3. CSRF (クロスサイト・リクエスト・フォージェリ)
  2. 大量の「はまちちゃん」を生み出したCSRFの脆弱性とは?
  3. 外部からPOSTできない?RailsのCSRF対策をまとめてみた

リンク最後のQiitaを読むと今回したいことはPOSTではなくGETリクエストを使用する方があっているのでは?と思ったので修正。(POSTにしていたのはなんていうか流れ、惰性、なんか変わったことをするにはPOSTみたいな思い込みですかね)

そういえばWebサービスにはRESTという設計モデルがあるって、どこかで聞いていた覚えがある。RESTに当てはめると今回の機能は取得(GET)にあたる機能だから、POSTはおかしい。別にサーバー内のデータを書き換える訳ではないし。 さらにいうと更新とか削除とかすべてPOSTで行っているので、PUT、DELETEに置き換えないと…。公開する前から修正するところだらけである。

さらにいうと、作っている間にみたサイトで、最近のWebサービスにはSSR(Server Side Rendering)を使ったAjaxで1ページだけで画面遷移を行うとかみて、Webの進歩の速さは速すぎると、毎度思う。(格好いいサイトは歓迎です!) SSRはWebページの不正コピーを防ぐため手段としても活用されているみたいでコンテンツを重要視しているサイトとかだと必須になるのかな?とか思ったり。

SSRなページを作るならVue.jsかなーって、思っていたり、Webページばかり作っていたら、オンラインゲームを作る余裕がないじゃんとか思ったり、そんな日々です。

とりあず、今回の件でRails使っていて良かったなぁと。セキュリティについてはさっぱりだから、フレームワーク側で対策してくれているのはありがたいです。

2018年12月28日金曜日

Rails Validatesまとめ

とりあえず、公式ガイドを見よう

  • Rubyのバージョンは2.5.1
  • Railsのバージョンは5.2.2

以下、使ったもの

メールアドレス

Rubyの標準ライブラリのURIにメールアドレスの正規表現が用意されているのでそれをformatwithオプションに指定してあげる。
# メールアドレスのバリデーション
validates :email, format: {with: URI::MailTo::EMAIL_REGEXP}
参考HP

バリデーションエラーの日本語化

デフォルトのままだとエラーメッセージが日本語のままだったので、こちらのサイトを参考に日本語化した。

日本語化した後は、起動しているサーバーを再起動させれば適応される。

2018年12月27日木曜日

CSSを触っていてレイアウトが崩れたので、その対処方法メモ

floatプロパティを指定しているときそのまま親タグを閉じてしまうと、レイアウトが崩れてしまった。CSS初心者あるあるみたいで、その解決方法はこちらのサイトが詳しいので、そちらを見た方がいい。

目指しているレイアウト


崩れてしまった現実.下が崩れたのは別の原因なので関係ない。

結論


float指定したら、疑似要素を利用して最後にはclearプロパティを使ってfloatの効果を無効化しよう。

なぜ崩れるの?


floatを指定したら、親タグはそのタグを高さ計算に含めない仕様となっているから。
そう策定されているので従う他ないので、解決策を下に書いていく。

1.clearプロパティを使う


空タグをfloatを無効化したい部分(今回の場合は最後)に入れて、cssでclear:bothを指定して上げるとOK。
学習サイトではこちらの方法を教えていたので、はじめはこちらを使っていたが、下の方法がよりスマートである。

2.:afterを持つCSS要素を親タグにつけるとよりスマート


cssに.hogehoge:afterと書くと、そのcssを指定されたタグの末尾へ自動的に.hogehoge:afterでスタイルされたタグを追加してくれる。便利機能。
これを使うとHTMLに余計なタグを追加する必要がなくなってよりよい感じになる。

(下にあるタグの親の高さが0になっている状態…)
.clearfix::after {
  content: "";
  clear: both;
  display: block;
}


:afterは疑似要素と呼ばれるもので他にも:beforeとかある。もう一度上げるがこちらのサイトが詳しい。疑似要素を利用したテクニックを紹介しているので参考になる。


まとめ

floatプロパティを使うとCSSの仕様上、レイアウトが崩れてしまうケースがでてくるので、floatを適応させたい部分の末尾にはclearプロパティでfloatの効果を無効化しておく。
そのさい、htmlに空タグを追加するのではなく、疑似要素である:afterを使うとhtmlがきれいに保てる。

2018年12月16日日曜日

Direct3D12について雑記

Direct3D12について雑記


自分が作った自作Direct3D12ライブラリを公開したのも年単位で過ぎ去り、Direct3D12について結構忘れてきたので、忘れないようにBlogに書き留めておく。

数パートに分けて書くと思うが、Githubに公開してるDirect3D11の解説程かっちりしたものにはせず、箇条書きに申し訳程度の追記と簡素なものにするつもり。
それと、あやふやな記憶を頼りに書いているので(特に歴史とかは聞きかじった程度の物)誤りを指摘いただける大変助かります。

この記事で言いたいこと

  • Direct3D11からDirect3D12へのバージョンアップはJavaからC言語へバージョンアップするみたいなこと
  • 下手なDirect3D12実装よりDirect3D11を使った方がましであるということ
  • 速くするためのものではなく、無駄を削るものである

後、Direct3D12についてはこちらの記事の方が詳しいです

Direct3D12とは?


Direct3D12とは非常によくできたグラフィックスAPIであったDirect3D11を基盤に、CPUオーバーヘッドを限りなく減らすため修正されたグラフィックスAPIである。

Direct3D12が公開された当初はLow CPU Overheadだ!なんやらと宣言され、それに触発されてかOpenGLは昔からLow CPU Overheadだったぜと言っていたり、Low CPU OverheadのきっかけとなったMantleの影が薄くなったり、それよりマルチプラットフォームでLow CPU OverheadなVulkanがあればDirect3Dなんていらないしと、数年前はグラフィックAPI界隈は賑やかであったと思う。
(個人的には今から勉強するならVulkanだと思う)

Low CPU Overhead化するということは、コンシューマゲーム機のように生身のGPUにPC上から触ることができることである。ゲーム業界に詳しくないなら、Direct3D11からDirect3D12へのバージョンアップは、JavaからC言語に進化したものだと思ってほしい。

さすがに使っているGPU全てにアクセスできる訳ではないが、NVIDIAやAMDなどのGPUベンダーは独自拡張した機能をDirect3D12からアクセスできる拡張機能を提供している。
が、拡張機能を使うならVulkanの方が情報が多いのでやりやすい。
(やっぱり覚えるならVulkanじゃないかな…?)

Direct3D12を使うメリットは最新機能が比較的早く公開&触れる。(GPUは別売り)
それとWindowsという安定したプラットフォームで動作するので安心感がある、が挙げられる。
個人的にはDirect3Dのシェーダ言語、HLSLを気に入っているが、Vulkanでも使えるようになったので、昔のOpenGLとDirect3D9程の違いは現在のグラフィックスAPI間にはあまりない。

長々と書いたが、Direct3D12とはLow CPU Overhead化を実現するためにDirect3D11から省けるところを省いたグラフィックスAPIである。

省かれた部分


それでは省かれた部分はどういったものかというと、下のものになる。
  1. GPUへのコマンド発行
  2. メモリ管理
  3. パイプラインステート管理

Low CPU Overhead化と宣伝されていたので1.GPUへのコマンド発行と3.のパイプラインステート管理が注目を集めていたが、2.メモリ管理も大変重要なところで、アロケータからメモリの断片化対策までこちらで面倒を見る必要がでてきた。後、リソースの初期化も手順が増えている。

Direct3D11までの時代はメモリ管理はGPUドライバー側が面倒を見ていた。
が、それに不満を持った開発者側と肥大化していくGPU機能の管理に疲れたGPUドライバー開発者側の意見の一致でこうなったのである。(たぶん)
(汎用的なメモリアロケータではゲームやCAD、モデリングツールすべてで最適なものを提供できるかと言われたら無理でしょう。)

なので、Direct3D12は誰でも触るものではなく、本当にプロフェッショナルな人が扱うAPIである。

記事にでも出ていたが、下手なDirect3D12実装されたレンダラーとDirect3D11実装されたレンダラーではパフォーマンス的にみるとDirect3D11の方が速くなるし(=GPUドライバー製作者の上を行く必要が出てくる + Direct3D12専用の処理の流れにしないといけない)、使っているCPUが速いと両者で違いがでないので注意が必要だ。(Direct3D11で生じるコストをCPUが十分にカバーしている)

低性能なCPU上では速くなりやすいが、そんな環境ってスマフォの方が多いという現実がある。(Vulkanの方が活躍できる環境が多いといえる)

あと、GPUが原因のボトルネックはDirect3Dは関係ないのでどうしようもない。

Direct3D12で速くなる場面が限られているので注意が必要だ。

実際に体験してみたくて、時間に余裕がある人は、私の作ったライブラリにあるBetterDrawCallSceneを実行して一度に発行するDrawコールの数を調節してみると体験できると思う。

(色々コードをいじる必要がある+動かないかもしれないので、面倒です。
dx12Test/scene/IScene.cpp内のIScene::sGetStartSceneNo関数の戻り値をeSCENE_BETTER_DRAW_CALLに変えてもらえたら確認用シーンは実行できます。
実行したら後は矢印キーでDrawコールの数を調節してください。
リングバッファの上限を超えると落ちます。)

速くするというより最大限にGPUとCPUを稼働させるためには、互いに待ち時間を持たせないようにすることが大事です。

じゃ、どうなのDirect3D12って


手放しで喜べるものではないDirect3D12であるが、(関係者ではないので)個人的には過去のGPUとのお別れを告げたものだと思う。昔はいろいろなGPUベンダーがいて、なかなか共通化が大変だったのが、近年はNVIDIAとAMDぐらいとベンダーの減少、それとGPU機能も似たものになった+昔は固定機能をもつ頂点シェーダやピクセルシェーダを実行するだけだったGPUがGPGPUといった汎用計算が可能なアーキテクチャに変化していった背景もあり、関係会社にってもはや過去の遺物となったものを清算するのにいい機会だったのではないでしょうか?
(特に21世紀以前から現役のOpenGLからVulkanへの変化は判りやすいと)

今後のGPUはDirect3D12とVulkanという土台を元に発展していくでしょう。
なので、GPUにとってのC言語的な役割を果たしていくDirect3D12は今後長く使われていくと思う。

速くするためじゃない、無駄を削るため、より作り手の思い通りにGPUを操るためにDirect3D12は誕生したといえるかもしれない。

2018年11月30日金曜日

Zenject MonoBehaviourを継承しているオブジェクトを注入するときの注意点

Zenject MonoBehaviourを継承しているオブジェクトを注入するときの注意点

Zenjectを初めて触って[Inject]を使って注入しようとなんとなく動かしたらAssertが出たのでメモ

//丸写ししたコード
Container
  .Bind<Hoge>()    //Hogeが要求されたら
  .To<ConcreteHoge>();  //ConcreteHogeを注入する


表示されたアサートは以下のもの

ZenjectException: Assert hit! Error occurred while instantiating object of type 'Hoge'. Instantiator should not be used to create new mono behaviours.  Must use InstantiatePrefabForComponent, InstantiatePrefab, or InstantiateComponent

新しくMonoBehaviourを生成する形で注入することはしないでほしい。
代わりに下の関数を使ってねとのこと。

  • InstantiatePrefabForComponent関数
  • InstantiatePrefab関数
  • InstantiateComponent関数

ただ、今回はBind関数を使っているので上の関数は使えない。
公式ドキュメントのDiCOntainer.Bindに'See here'とあってそこを読んでいくと、ConstructionMethodという項目があり、これらの関数を使用すると上のアサートを解決できる。

ConstructionMethodにもいくつかのバリエーションがあり、自分はFromComponentInNewPrefab関数を利用した。引数にはプレハブを渡すようになっている。
これはプレハブに設定してあるコンポーネントを[Inject]指定されたところに注入するものだ。

実際に動かすと実行時に渡したプレハブのインスタンスが自動で生成されていて、無事目的を果たすことができた。

ConstructionMethodには
  • FromNew
  • FromInstance
  • FromMethod
  • FromMethodMultiple
  • FromFactory
  • FromIFactory
  • FromComponentInNewPrefab
  • FromComponentsInNewPrefab
  • FromComponentInNewPrefabResource
  • FromComponentsInNewPrefabResource
  • FromNewComponentOnNewGameObject
  • FromNewComponentOnNewPrefab
  • FromNewComponentOnNewPrefabResource
  • FromNewComponentOn
  • FromNewComponentSibling
  • FromComponentInHierarchy
  • FromComponentsInHierarchy
  • FromComponentSibling
  • FromComponentsSibling
  • FromComponentInParents
  • FromComponentsInParents
  • FromComponentInChildren
  • FromComponentsInChildren
  • FromNewComponentOnRoot
  • FromResource
  • FromResources
  • FromScriptableObjectResource
  • FromNewScriptableObjectResource
  • FromResolve
  • FromResolveAll
  • FromResolveGetter<ObjectType>
  • FromResolveAllGetter<ObjectType>
  • FromSubContainerResolve
  • FromSubContainerResolveAll
と様々な用途に対応している。(2018/11/30 確認) 公式ドキュメントはこちら
列挙している内に今回のケースだとFromNewComponentOnNewGameObject関数が一番いいと気が付いた。(パラメータを指定する必要があったわけではなかったので)
この関数を使うときはTo<>関数で型を指定する必要があるので注意。

Container
    .Bind<Hoge>()    //Hogeが要求されたら
    .To<ConcreteHoge>() //ConcreteHogeを注入する
    .FromNewComponentOnNewGameObject();


以上、深く調べるきっかけを与えた方へお礼申し上げます。
そのままだと気が付かないままでした。

2018年11月28日水曜日

unity-simple-rankingで複数のランキングを扱えるようにした話

unity-simple-rankingで複数のランキングを扱えるようにした話


naichiさんがGitHubで公開しているunity-simple-rankingを使用すると自作ゲームに簡単にランキング機能を付けることができます。

自分も試してあっさりできたので本当に素晴らしいライブラリですのでおすすめです。

で、自作したゲーム3Dアミダクジに組み込んでみたのですが、このゲームには複数のモード(NormalとEndless)がありまして、それぞれにランキング機能をつけたいなと思いました。ただ、unity-simple-rankingはそのままだと単一のランキングしか扱えないので、少し改造してこちらが指定したランキングにアクセスできるようにしました。

使い方
var loader = naichilab.RankingLoader.Instance;
loader.info.Set("使いたいNCMBクラスの名前", "画面に表示する名前");
loader.SendScoreAndShowRanking(1000); //ランキングを表示
naichilab.RankingLoader.Instance.infoが新しく追加したRankingInfoクラスのインスタンスになります。

[Serializable]
public class RankingInfo
{
    ///     /// サーバーとやり取りするときの名前
    ///     public string className = "";

    ///     /// 画面に表示する名前
    ///     public string displayName = "";

    public RankingInfo()
    { }

    public RankingInfo(string className, string displayName)
    {
        this.className = className;
        this.displayName = displayName;
    }

    public void Set(string className, string displayName)
    {
        this.className = className;
        this.displayName = displayName;
    }
}

クラス自体はとても単純なものになります。
あとはRankingSceneManagerクラスの中でNCMBクラスを指定している部分を上のクラスに設定されている値を使うように変更しました。

注意点としてはRankingInfoに何も設定しなかったとき(空文字列を指定したとき)は以前のNCMBクラスを使うようになっています。

既存のunity_simple_rankingを使っているコードは壊さないように(たぶん)作りましたので、一つのゲームに複数のランキングを欲しいなと考えている人はよかったら使ってください。
https://github.com/tositeru/unity-simple-ranking

テンピーポーテンカラー プレイ感想

テンピーポーテンカラー プレイ感想
11/30 追記 ゲーム内容が更新されていたので、書いている内容と微妙に異なるかもしれないのでご注意

ゲームはこちらから

十個の色をした人型(非常扉に書かれている奴)をゴールまで導く2Dゲーム
(レミングスと同じジャンルなのかな?)



何もしないでゴールには到着するわけではなく、阻むように障害物が配置されている。
その障害物を取り除いてゴールまで導くわけだが、その取り除き方がこのゲームの特徴を成している。

左クリックを押しっぱなしにすると円形に色見本のようなものが出てきて、
押しっぱなしのままで各色にカーソルを合わせると背景色がその色になる。
そうするとステージ上にある同じ色をしたものが人型、障害物関係なく消える。
というより同化して認識できない状態になって、これを利用してゴールまで導く感じである。
(左クリック押しっぱなしで色見本が出てくる)












(赤を選択すると赤色の障害物が消えて、人型が下まで落ちるようになる)


















ゲーム自体は物理演算を利用しており、これを利用したステージも存在する。
レベルデザインも大変よく、プレイヤーにこのゲームでできることを一つずつ教えてくれる親切なゲーム。もちろん、パズルゲームのように頭を使わないとクリアーできないものもあるが、
音遊び的なステージもあって、いいアクセントとなっていた。

(障害物を消すのではなく留め具を消すといった発想も必要だった)

テンポよくプレイでき、ステージ数が物足りないかな?と感じ、
もっと遊びたいなと思わせてくれた大変できたゲームでした。

Unityroomによると、UnityAnima2Dというアセットを使用しているようだ。
画像にボーンを付けられ、スキニングとIKまで対応と非常に多機能なAssetなので、今度使ってみたい。