中級LSLスクリプト TIPS その3 “極シンプルなSkybox向けセキュリティ

html_css_javascript_and_the_awesome_jquery_infographic_header

年末好例 セカンドライフ技術系 Advent Calendar 2016 の季節ですね。
今年は連載で新しいネタを投下します。 今日の記事は前座です。

なぜ今HUDをHTMLで作るか?

従来HUDというとノーマルプリムやMeshで組み立ててllSetColorで色を変えたり、 llSetTextやXyzzyTextで文字を表示する方法で開発されてきました。 この方法だとダンスHUDやアドベンチャーゲームのテキストウインドウなど、 テキストを大量に表示・書き換えする機能を実装するには文字数やボタンの数に応じてプリムを増やす必要があり、開発環境としては不便なものでした。

この問題への対処として、SharedMedia上にHTMLとJavaScriptなどを利用することで大量の文字列を処理して表示する方法が考えられます。
2011年にもKelly Lindenによる http-inとHTMLを使ったHUD開発手法 が提案されていましたが、当時のViewerだと内蔵WebブラウザがWebkitだったため、最新のWeb技術に準拠した手法が適用できず、いまいち使えない状態でした。

最近のアップデートで内蔵WebブラウザがWebkitからChrome Emmbded Framework(以下CEF)に置き換えられ、以前はSharedMediaに使えなかった新しい規格が利用できるようになりました。 CEFへの置き換えによりHTML5,CSS3,WebGLにいたり概ねなんでも使えるようになったので、SecondLifeのアプリ開発にWeb系のフロントエンドを取り込んでみようという試みを紹介するというのが今回の連載記事の趣旨です。

*CEFについてのLindenの記事
Second Life Improvements – What’s New & What’s Coming Soon!
*日本語での詳しい解説
http://sakuranoelfayray.blogspot.jp/2015/12/officialviewer400.html

HTMLでHUDを作るメリット

HTMLを利用するメリットはいくつか挙げられます。

  • LSLだけでは大変な手間がかかる文字表示や文字装飾が簡単に実装できる。
    floating textの文字数制限やxyzzytextに力技で改行を実装する煩わしさから開放!
  • CSSやSVG、あるいはフレームワークを使って簡単にグラフィカルなUIデザインを提供できる。
    ぶっちゃけフレームワーク使うと楽です
  • LSLの容量(64kbyte)でもcdnで配布されているjavascriptライブラリなどを呼び出すことで機能を補うことができる。
    個人的には jquery やGUIフレームワークなどは cdnjs から呼び出すことにしています。
  • http-inを併用することで外部サーバを用意しなくてもSecondLife内で完結してWebアプリを提供できる。
    LSLにはhttp通信も実装されているので、 ajaxなどphp製サーバーアプリなどに相当する通信機能もある程度実装できるのも有用です。

サーバサイドをhttp-inで実装すると、llSetContentTypeにOwnerが表示したときにしかtext/htmlを返さない(Owner以外からだとtext/plainになる)という制限があり、 実質的にHUDでしか実装できない=REZして使うことができないという制約がありますので注意してください。 REZして使うLSL-Webアプリを作りたい場合はWebサーバを外部に用意すれば可能ですが、 Webブラウザにおけるajaxのクロスドメイン制約が適用される場合があるので、 適宜JSONPを利用するなど制約を超える対策を施す必要があります。

ともあれ今回はSecondLife内で完結させたいので、http-inを併用するタイプで解説します。

前提として、今回紹介するHUDには下記の動作環境が必須となります。

  • Second Life 4.0.0 (307894) 以降
  • Firestorm 4.7.7 (48706) 以降
  • その他CEFに対応したTPV

基本的に公式Viewer・Firestorm共に最新版を使っていれば問題ありません。 古いバージョンだとWebkitで表示されるのでHTML5で記述しているページは表示が崩れたりします。 そのうち古いバージョンではログインできないようにブロックされるらしいので、 いずれはユーザのViewerのバージョンは気にせずHUDを配布できるようになることでしょう。

連載の中でいくつかサンプルコードを紹介しますが、一部の例外をのぞき下記の手法で組み立てます。

  1. ノーマルプリムでBOXをRezし、サイズを0.1m×0.8m×0.8mに設定する。
  2. TakeしてHUD中心1またはHUD中心2に装着する。
  3. 手前の面(面番号4, X- 側)を明るさ全開をOnに設定する。
  4. 環境設定のメディア再生を自動再生のチェックをOnにする。

サンプルコード1 (静的HTMLの表示)

お膳立てが済んだところでスクリプトのコードを見ていきます。
ここではHTML,CSS,javascript,jqueryなどの初歩的な解説は省略しますがあしからずご了承ください。(_ _;)

ws_0654

実行結果 (クリックでおおきい画像を表示します)

シンプルに静的HTMLを表示するだけのコードです。 HTMLを使ったスクリプトの基本形は多くの場合において上記のようになります。
一度取り外して再装着するとhttp-inのサーバーURLが無効になるので、サンプルコードではattach()でリセットを掛ける処理をいれてあります。
URLにアクセスするとサーバーにHTTPリクエストがGET Methodが送信され、http_request() イベントが発火するのでリクエストIDに対してデータを返す(レスポンス)するというのがWebアプリのアルゴリズムの基本形です。
それぞれのスクリプトで設計された機能により、 主にフロントエンドは string HTML_BODY の部分を、 バックエンドは http_request から返す情報を生成するためにLSLを実装していきます。 LSLではHTTP通信のmethodでは主にGETとPOSTが使われます。llRequestURL() でhttp-inのサーバーリクエストをした時とはじめにページのデータを返すときは必ずGET Methodでイベントが発火し、それ以降のクライアントアプリとのデータのやり取りは特に決まりはありませんが場合分けし易いようにPOST Methodで処理するのが一般的だと思います。

参考
Second Life Wiki > LSL HTTP/ja
http://wiki.secondlife.com/wiki/Category:LSL_HTTP/ja
Second Life Wiki > LSL HTTP server/examples/ja
http://wiki.secondlife.com/wiki/LSL_HTTP_server/examples/ja

サンプルコード2 (ajaxで動的ページ書き換え)

1つめのサンプルコードでは静的ページを表示しているだけですが、submitボタンでデータを送信して遷移先のページを動的に変更したり、さらにajaxとjavascriptまたはjqueryのDOM操作を利用すると、ページ遷移せずにページの一部のみを書き換えられるのでよりリッチなアプリケーションを手軽に設計できます。ページ遷移することのないサクサクとした操作感を得られるので、ユーザビリティの観点からも ajaxとDOM操作を基軸にアプリをデザインするのが良いと思います。

HTMLを表示したあとにajaxによる非同期通信とDOM操作で部分的にページを書き換えるサンプルを示します。
さきほどの解説のようにFormからajaxでデータ送信ときのMethodをPOSTとしてhttp_request() イベント側で場合分けし易いようにしてあります。

animation-0

実行結果 (クリックでおおきい画像を表示します)

javascript内で完結してももちろん同じことが出来ますが、ここではデモンストレーションのためにあえてサーバーを通してデータ送受信する処理で作っています。
テキストボックスに入力した内容とクリックしたボタンのidををJSONにしてhttp-inサーバーに送信、responseもJSONとしました。 JSONで複雑なデータも一度に送受信できるので便利です。 押したボタンのidでresponseするJSONの内容を振り分けています。 ここでは”text”は入力内容をそのまま使用、”style”は`赤で表示`を押した場合はCSSで”color”: “red”、`青で表示`を押した場合は”color”: “blue”を返すようにしました。

ボタンを押したときにHUDからhttp-inに送信されるJSON (`赤で表示`を押した場合)

処理が完了してhttp-inからHUDにresponseされるJSON (`赤で表示`を押した場合)

js側に返ってきたjsonを元にDOM操作で部分書き換えしています。
LSLとajax通信するタイプのアプリは基本的にこの流れでの実装になるかと思います。

ページを記述するためのhtmlやjavascriptは基本的に1つのstringにまとめる書き方とし、ページをデザインする段階では.htmlファイルとして別に作成しておいて、デザインが出来上がったらLSL側のstring HTML_BODYにコピー&ペーストする手順が効率的かと思います。 HTML部分だけを別ファイルで作ると、エディター内蔵のHTMLプレビューでレイアウトを確認したりブラウザの開発者ツールでデバッグできるのもいいところです。
※ATOMやSublimetextのようにのlsl, html, javascriptなど複数の言語に対応した外部エディターでの開発を想定しています。

phpのように複数のstringを文字列操作で結合・挿入などでページを生成する方法は処理が煩雑になり個人的にはあまりおすすめできません。 ただしはじめからLSLで動的にページ生成するという思想も考えられますので、そちらの手法は別のだれかに解説を委ねることにします。

LSL内にhtmlを記述するときのヒント

LSLのstring内にhtmlのコードを書いていて、私が気づいたノウハウを書いておきます。 ほかにもあればぜひ教えてください。

  • javascriptで扱う文字列データは””ではなく”で囲う。
    HTMLをstring変数のなかに書くことになるんで、文字列を””(ダブルクオート)で囲って記述すると.htmlのソースからlslのstringに貼り付けるときに、すべての”(ダブルクオート)にエスケープシーケンスをつけて\”に置き換える必要があります。 この手間をなくすために、はじめから文字列を”(シングルクオート)で囲って記述するのがおすすめです。
  • インデントは全て詰める。
    string HTML_BODY内はHTMLのページをレンダリングするためには必要ないので全て詰めます。 上述のサンプルコード2では可読性を優先してインデントを残しましたが、アプリが複雑化するほどインデントが食う容量が64kbの壁を圧迫しますので、基本的にHTMLのコードをstringに貼り付けたときにすべて詰めてしまいましょう。 さきほどのサンプルコード2の場合での例を示します。 可読性は損なわれますがHTMLのコードを確認するときは元の.htmlファイルをみるということで。
  • 類似処理は極力ユーザ関数にまとめる
    2回以上同じ処理を使う場合はユーザ関数にまとめて少しでも文字数を減らすようにコーディングします。 理由はおなじくLSLのメモリ節約のためです。
  • CSSによる複雑なUIデザインはではなく外部ファイルを使う
    ボタンのデザインを凝ったり複雑なUIを設計する場合は外部に.cssや.jsファイルをおいて読み込まるか、あるは公開cdnからフレームワークを読み込んで利用します。 同様にLSLのメモリ節約のためです。
  • HUDのアスペクト比は1:1, 1:2, 1:4, 2:1など1:2^nまたは2^n:1に限定される
    http://wiki.secondlife.com/wiki/LlSetLinkMedia#Caveats ※注意 日本語のページには書いていません
    PRIM_MEDIA_WIDTH_PIXELS (メディアの横ピクセル数)とPRIM_MEDIA_HEIGHT_PIXELS(メディアの縦ピクセル数)に制限があって、1024×1024、1024×256、512×1024などに制限されるため、それに合わせてプリムのサイズのアスペクト比も1:1、4:1、1:2などに制限されます。解像度をここから外れた設定にすると周りに白い枠ができてしまいます。

HTMLでのHUD開発 (勝手にMedia HUDと読んでいます) はHTML/CSS/javascript/jqueryさらにHTTP GET・POSTにはじまりajaxだとか色々とWeb技術について覚える事が多いですが、一度使い方がわかってしまえば圧倒的に効率的なHUDアプリ開発を進められます。 ぜひこの新しい開発方法を試してみてください。

次回はajaxややフレームワークを応用したHUDアプリの作例を紹介していきます。


2日め: Media HUD…HTMLでHUDを開発する(2/3)