Narazaka::Blog

奈良阪という人のなにか

2020年のVRSNSを比較してみた

VRSNS

VRChat基本毎日ログイン勢ですが、VRChat以外のVRSNS相当も結構増えてきました。だけど入り浸ってるとこ以外のVRSNSってなかなか行きづらいですよね。

ゴールデンタイムにはやはりVRChatにいたいけど、そうすると他VRSNSをやるのは当然人のいない時間帯になったりしちゃうし、あとアバターの変換が地味に面倒。操作もそれぞれ微妙に異なってそこも面倒。

しかしそんな中でも頑張ってちょいちょい各VRSNSに行ってみたんで、その感想をまとめてみます。 なんか行くモチベとかになれば幸い。

ただし以下記述の通りVRChat以外のプレイ時間が少ないので、まあ信憑性としては「そんなもの」だと思ってください。(結構ミスの指摘を受けていたりする)

他にもあるかもだけど、現状自分が一瞬でもログインしたやつ限定です。雰囲気人がいそう順。

VRChat

(プレイ時間2300時間)

特徴 内容
属性 VRSNS
もともとは企業の会議用とかを想定して作られたとの噂
状態 アーリーアクセス版
運営国 アメリ
動作環境 Windowsデスクトップ
Windows VRHMD
・Oculus Quest
Linuxデスクトップ(Proton利用 / VRは動作するのか情報未確認)
同時接続人口 8000人前後
同時接続人口(日本) 数百人
デイリーアクティブ(日本) 千~三千人程度
一部屋最大人数 数十人規模(ワールドによる)
実用的には80人くらいが上限感
言語コミュニケーション手段 ボイスチャット
外部連携 動画・ストリーミング再生・画像読み込み(全てインターネット上のもの)
アバター Unity2018による独自作成
アイテム なし
ワールド Unity2018による制作
・トリガーでイベント動作可能
・独自ランタイムでスクリプティング可能(α版)(C#で書けるようにするサードパーティー製アセット有)

いわずとしれたVRSNSの覇者。とにかく一番人が多いですね。

アバターもワールド(場所)もUnity2018でフルカスタム出来て自由度が非常に高いのが特徴です。人が多いことと相まって多様性が爆発しています。

VRSNSとしても使える、エモ景色めぐりもできる、いろんなイベントにも参加できる、友人とゲームも遊べる、ゲームで遊んだ後で駄弁れる、あげく寝られる、居酒屋雰囲気でVR飲みできる、すき焼き食べられる、定期開催のガールズボイスバー(?)や男装喫茶にもいける、かわいい・かっこいい・現実ではありえない姿の人々に囲まれる、VRで踊り狂える、VR特有の謎の感覚が芽生えたりもする、恋人のような関係も作れる、private部屋なら性生活さえできる、publicで一期一会の出会いもある、海外勢のカオスもあるし、仲良くなって言葉も学べる……。

VRという環境における「新しい体験」のほとんどはここで味わえると思います。

自由度故にVRChat内のワールドとして作れるVRゲームもかなり多岐にわたっていて、サッカーの変形ゲームのような球技(ペコペコバトル・溶岩ボール等)から同人ボードゲーム、カードゲーム、進行役が自動の人狼TRPG囲碁将棋麻雀、ホラーゲーム、謎解きゲーム、等身大RPG、等身大ボンバーマン他クローンゲーム、その他オリジナルゲーム等多岐にわたり実に様々なものがあります。

たぶん今複数人同時接続VRゲームを作るならVRChat上が一番簡単に作れるのでは……。

全体人口が多いことと同時に一部屋(インスタンス)への同時存在可能人口が多いのも地味に大きいファクターです。他にいってみると実にせいぜい十数人未満しか同時に集まれないところが、VRChatではするっと30人くらいが同じ場所にログインしてしまい、一段違った賑やかさと活気を感じることが出来ていると感じます。

一方VR体験という中での大きな制約としては、外部連携の手段が極めて限られていることがあります。このあたりVirtualCastとかの整備具合からすると不便だなと感じますね。

アーリーアクセスということを忘れるほどに基本は安定しているけれど、バグも基礎的なとこから結構あるのでノウハウを聞かないと初見殺しがあったりするのが玉に瑕。

VirtualCast

(プレイ時間8時間)

特徴 内容
属性 VRライブ・コミュニケーションサービス
元々は配信特化
状態 正式版
運営国 日本
動作環境 Windows VRHMD
Windowsデスクトップ(ただしアバターが存在せず音声のみの参加)
同時接続人口(日本) 数十人~せいぜい百人規模な気がする。(公式スタジオ)
配信含めるともっといるかも。
一部屋最大人数 16人
言語コミュニケーション手段 ボイスチャット
外部連携 ニコニコ動画再生・デスクトップキャプチャ・(動画配信・ニコニコ/Twitterコメントを降らせる・投げ銭で物を降らせる)
アバター VRM(THE SEED ONLINE・ニコニ立体)
アイテム Unity2019までで作成
Luaスクリプティング可能
ワールド 用意されたもののみ固定(公式スタジオ)
・個人スタジオでは作成可能(アイテムと同様)

V配信用プラットフォームがVRSNS機能を鋭意実装中といったステータスのところ。

「配信がなく常時存在している部屋」=公式スタジオを固定で用意することで、擬似的にVRSNS体感を実現しています。(ただしたまにニコ生クルーズという仕組みで一定時間動画配信されることがあります。)(またいちおう個人スタジオにも配信せずに他の人が入る手段はあり、プライベートインスタンス的な扱いには出来るそうです。)

アバターVRM、公式スタジオではワールドは変更不能ですが、アバターやワールドと切り離された「アイテム」を作成できます。

この「アイテム」(および個人スタジオで使えるワールド)機能はUnity C#と連携できるLuaスクリプトで任意のコードが記述できる余地があったりして実はかなり自由度が高いです。

凸してきた人(スタジオ入場者)一覧とか、VRChatのUdonが出る遥か前に実装できていたのが印象的。

またアバターも枠が有料にはなりますが、日本的なキャラデザのアバターメーカーであるVカツとカスタムキャストからニコニ立体とTHE SEED ONLINEにそのままアップロードできるため、VRChat等の海外VRSNSと比べるとかなり気軽にカスタムキャラクターで遊べます。

V配信メインゆえか外部連携が非常にしやすく便利ですね。特に外部ソフトなしに空間上にデスクトップ(各人ローカル画面)表示を置けるのが画期的で、VRで「暮らす」ならやはりこれは欲しいよなと言う気持ちになってきます。

およそVRChatのゴールデンタイムと同じような時間帯(夜中・深夜)には結構人がいる印象です。VRChatに人がいないときの第一選択肢はここ。

性質上人口の過半は配信者もしくは配信に凸(参加)している人が占めており、さながら控え室のような和気藹々とした雰囲気があるように感じます。

cluster

(プレイ時間数時間)

特徴 内容
属性 バーチャルSNS
元々はバーチャルイベントプラットフォーム
状態 正式版(明確に記載が無いので恐らく)
運営国 日本
動作環境 Windowsデスクトップ
Windows VRHMD
Mac
Android
iOS
同時接続人口(日本) VRSNSとしては数十人~せいぜい百人規模な気がする。
ただしイベントは一度に千人規模でやったりもしている。
一部屋最大人数 12人
言語コミュニケーション手段 ボイスチャット・テキストチャット
外部連携 動画・音楽再生・画像読み込み・スライド読み込み(ローカルファイル)
アバター VRM(自力アップロードまたはスマホV配信アプリREALITYからのインポート)(低スペな制約有)
アイテム なし
ワールド Unity2019による作成
・トリガーでイベント動作可能

ライブとかをやったりする場所という位置づけからバーチャルSNSという位置づけに転換したところ。

アバターVRMですがワールドはユーザーがUnity2019で作成可能で、VRChat程度とはいかないまでもそこそこ自由度の高い遊びが作れるようです。

ワールド移動やらフレンド機能やらVRSNSとして基礎的なとこが後発故けっこうまだ荒削りではありますが、声を出すのが苦手な日本人向けとしては地味にテキストチャットが標準であるのがありがたいところだったりします。

元々ライブやイベント用であるおかげか、ローカルファイルをワールド全員に見せる手段が充実しているのが特徴的。

また現状Mozilla Hubsと並んでスマートフォンからアクセス可能なVRSNSであり、かつ日本的なキャラクターデザインのアバターメーカーから無料でシームレスにアバターがインポートできる唯一のVRSNSです(スマホ向けV配信アプリREALITYのアバター機能を利用 有料だとVirtualCastカスタムキャスト連携も)。この圧倒的手軽さは素晴らしいの一言。

ambr

(プレイ時間46分)(ただし2019年初頭にVRユーザー意見交換会みたいなのがあってそこでもプレイしたことある)

特徴 内容
属性 VRSNS
状態 オープンアクセス(β)
運営国 日本
動作環境 Windows VRHMD
・Oculus Go
同時接続人口(日本) 数十人規模な気がする。
一部屋最大人数 4人(アバター全表示)
8人(部屋作成者だけアバター表示)
言語コミュニケーション手段 ボイスチャット
外部連携 なし
アバター VRM(VRoid Hub)(低スペな制約有)
アイテム 用意されたもののみ
ワールド 用意されたもののみ

最初からオープンなVRSNSとして制作され唯一おおまかな路線が変化していないと思われる日本発のVRSNSです。

元々Oculus Go向けプラットフォームで、現在もそこに対応しているものの、Oculus Go対応が今後厳しくなる的なことをほのめかしてもいます(まあそもそもハードが販売終了になるという報も出ましたし)。

総じてOculus Go由来の制約がかなりきつく、自由度はあまりない感じ。ユーザーアップロード可能なコンテンツもアバター以外存在しません。

ちなみに3DoFなOculus Go向け発ゆえなのか視界の動き方が他の全てのVRSNSと異なる独特の挙動をします。また「デスクトップ版」が存在しません。

他特筆すべきは、20:00~26:00しかプレイできないという時間制約がある点。たしかにそのへんがVRChatでもゴールデンタイムには含まれるけれど、ふとヒマなときに入れないし、2時に強制ログアウトかかるのはなかなか……。

ただ時間帯を絞ることでユーザーは集中するのかもしれません。実際クローズドβ時代に一部の熱心なユーザーコミュニティの形成には成功した模様で、VRChatにもambrオープンβ待ち部屋みたいなのができていたりしました。ワールドが固定なのも相まって案外人には会える印象。

「ログインボーナス」の仕組みを持っているなどどちらかといえばゲーム的な方向性を志向していそうではあるし、今後に期待と言ったところです。

NeosVR

(プレイ時間112分)

特徴 内容
属性 VRメタバース
状態 アーリーアクセス版
運営国 チェコ
動作環境 Windows VRHMD
Windowsデスクトップ(ただしプレリリース状態)
同時接続人口(日本) 数人~数十人規模な気がする。
一部屋最大人数 実用上十数人程度
言語コミュニケーション手段 ボイスチャット
外部連携 ローカルファイル何でも・他人のそれも同時に利用可能
アバター VR内でモデルファイル選択して独自作成
アイテム VR内で独自作成
ワールド VR内で独自作成

非Unity製(描画に部分的には使っているらしい)のVRメタバースです。

VRSNSという枠にもとらわれず、VR空間内で本格的な制作行為が行えるという凄いやつです。つまるところVR空間内に存在するもの全てをVR空間内で作成できることなどを志向しているっぽい?です。

たとえばアバターの導入でさえ、VR空間内からローカルのfbxファイルを探して選択し、空間内に置いてから手と足のマーカーを置いてセットアップするという手順になっていて、つまりモデリング以降の独自部分はUnity等の外部ツールなしに全てNeosVRのプレイ時間内で対応できるのです。

いわゆるワールドに置くものや、その動作などもVR内でプログラミング的な事をすることで設定可能で、恐らくVRChatより先の「未来だこれ!」という体感は唯一ここに存在すると思います。

ただしやはり人がすくないです……。未だにたまたま入ったワールドに居た3人くらいの外人以外誰にも会ってない……。全体では十数人~数十人は居るんですけど、部屋の絶対人数が少ない故にとりあえずjoinするかーという気持ちにもなりにくいので……。

一応熱心な日本人ユーザーグループは存在するので、そこの集まりの時間帯(22時~24時くらいらしい)に上手いこと合致すればよさそうではあります。(自分は午前2時とかに入ったりする民なので……)

Lavender

(プレイ時間3時間)

特徴 内容
属性 VRSNS
状態 アーリーアクセス版
運営国 アメリ
動作環境 Windows VRHMD
Windowsデスクトップ
同時接続人口(日本) 基本0人~数人規模な気がする。リリース当時は数十人いた気がする。
一部屋最大人数 おそらく数十人程度
言語コミュニケーション手段 ボイスチャット
外部連携 なし
アバター Unity2018で独自作成
アイテム Unity2018で独自作成
ワールド Unity2018で独自作成

作りがまだ荒いVRChatと言う体感の、Alt VRChat的なVRSNSです。

今回あげた中で唯一の基本プレイ有料(2000円ちょい)。恐らくそれゆえ基礎人口が少なく、現在日本人はおろかそもそも「人」に会うことが困難です。

VRChatより心なしか軽い気がする動作や、VRChatではネイティブでは不可能だった飛行移動(NeosVRでも可能)、ワールドから切り離されたアイテム機能、中央サーバーで全てをまかなうのではなくネットワークに繋がりつつもユーザーが個別に鯖立てしたりする仕組みがあるなど面白みはあったのですが……。

いかんせんコンセプトがそのまんまVRChatであり(故に居心地はそこそこ良かったんですが)、有料という枷も相まってVRChatにみんな引き上げたのか現状本当に人がいません。

今はいってみたら256fes関連っぽいワールドは存在したので、細々とログインしている人はいるのかも知れないです。

TECO

(プレイ時間20分くらい)

特徴 内容
属性 クローズドなVRSNS
元はもっと一般的なVRSNSを志向していた模様
状態 アーリーアクセス版
運営国 日本
動作環境 Windows/Mac
Oculus Rift / Rift S
・Oculus Quest
・Oculus Go
同時接続人口(日本) 不明
一部屋最大人数 30人まで(設定による)
言語コミュニケーション手段 ボイスチャット
外部連携 Discord音声と同期
アバター VRM(自力アップロード)(低スペ・ミドル・無制限という3種類のパフォーマンス別)
アイテム 用意された物のみ
ワールド 用意された物のみ

バージョン1.3からクローズドなコミュニティのVRSNSを目指しており、全ての部屋が非公開という特徴を持つプラットフォームです。

少なくともambrより開発は早かったらしいんですが、VRChatユーザーへのインタビューやバーチャルマーケットへの出展を行っていたambrと比べてほぼ全くVRChat民への露出がなく、プレスなどが大きくバズった感じもなさそうなので、今回あげた中で一番VR知名度が低そうです。 なお正式名称の「TECO」だけだとGoogle検索トップ域にWebサイトも出てきません。(この状況は他にLavenderが該当するが、あちらはLavenderVRと呼ばせることに成功していたのであまり問題が無かった。検索性最悪のclusterでさえ出てくるのに……。)

現状アバターのみがカスタム可能で、ワールドにはおおまかなマス目指定で家具がおけるなどの機能があります。ワールドに紐付かないアイテムはなぜか機関銃だけが唯一存在し、出すとメニューボタンを押すたびに連射することになるので地味にじわじわきます。

なお「自分のアバターは自分からは見えない」仕様です。ここらへんちょっとかわいいとかを求めるユーザーとは親和性が悪そう……。

公式にDiscord連携をうたっていることのが特徴的ではありますが……わざわざVRで入りつつ通話のみをするには機能が足りなさすぎる気はします。

起動したら説明なしに画面が出て別途ブラウザで説明を読むまで意味不明だったりするのも含めて、今後に期待枠です。

Mozilla Hubs

(プレイ時間20分くらい)

特徴 内容
属性 オープンソースネットワークWebVR
状態 正式版
運営国 アメリ
動作環境 ・ブラウザ
・VRHMD
同時接続人口(日本) 不明
一部屋最大人数 50人まで(設定による)
推奨は25人程度
言語コミュニケーション手段 ボイスチャット・ペン
外部連携 画面共有・画像・ビデオ・PDF共有(ローカルおよびURL)
アバター アバターメーカー or GLB自力アップロード(IKなし)
アイテム 各種3Dモデルをインポート可能
ワールド Web上の独自ツールで構築可能

Firefoxを出しているMozillaの運営するVRSNS的存在です。

用途的にはTECOと近く、部屋を立ててそのURLを共有した人とのみ一緒に居られる模様です。

一般のブラウザで動作するので地味に動作環境の広さは随一。無論スマホでもログインでき、ジャイロで視点が変えられるなど手が込んでいます。ただしその代償なのか、アバターは頭と手と位置のみが動かせる棒人間のような(IKは存在しない)簡易的なものになっています。

画面共有機能はclusterやVirtualCastなどにありそうでなかった機能だったりするのだけれど、そもそもアバターがかわいくない(自由度が低い)ので、VRChat民的には魅力をあまり感じないやつかも。

これと同じ仕組みで個別に鯖立てできるHubs Cloudというものを提供しているところからも、どっちかというとユーザー向けSNSというよりは、ビジネスミーティングとか向けである気はします。

このHubs Cloudは「(技術は必要にせよ)自分で立てられる」OSSなVRSNSクローンという非常に貴重な存在なので、アバター含めて今後発展していって天下取ってほしさはあります。

ブラウザで動作する故に、かのclusterをも凌駕する驚異的なレベルでの手軽さを有していて、インストールもログインも不要でぽちぽちボタン押せばスマホですぐ空間に入れてしまい、URLをDMで送ればそれだけで人に会えます。ここだけ群を抜いて未来という感じ。

なおこの記事公開後すぐにGREEの人が作ったドキュメントの日本語訳が公開されたりしています。

High Fidelity

(プレイ時間89分)

上手くいかず企業向け会議プラットフォームにシフトしてしまったとこです。

この中でアイテムが販売可能な仕組みが既にあったりするなど野心的ではありました。

Sansar

(プレイ時間19分)

昔ログインしようとしたが重くて実質起動不可でした。

その他

他把握しているところでは、複数人で遊べるミニゲームVRでやるというコンセプトのRec Room、つぶれたと思ったらMicrosoftに買収されたがアバターがバタ臭いのでやる気がいまいち起きないAltspaceVRなどが有る模様です。

スマホ限定で動作する故に「VRSNSではないが体感近そうなVirtual Droid 2とかもチェックすると良いかもしれません。

以上雑感

やっぱりVRChatはナンバーワン!というのはあって、人の多寡は如実に体感に作用すると言うことがはっきりわかります。他のVRSNSも人がいればもっと楽しいんだろうなあと思う所は多いです。

しかし一方VRChatでは成し得なかった様々な機能やその他美点が他VRSNSには散見され、将来のVR像の想像が捗る感じは有りますね。

ともかくよさげかなあと思ったところに一回行ってみると良いと思います。VRChat今日人おらんな~~~という時とかに是非。

追記事項

雑な記事を出したら各方面から知見(ツッコミ)をいただいたのでありがたすみません。

お金を払いたい「タイトル」「フレーズ」のメモ

タイトルだけに対してお金を払いたくなる素晴らしい価値を感じているタイトルのメモ 一応精一杯言語化した理由も記しておく。まあ、理解不能かも知れないが。

前のブログでも書いていたのだけど、今後はこちらを更新していく。 お金を払いたい「タイトル」のメモ-奈良北部のなにか

イリヤの空、UFOの夏

夏の空、彼方のUFO、そして不思議で澄んだ響きの「イリヤ」。

目にした背表紙、青色の背表紙、イリヤの空、UFOの夏

内容の名作感のバイアスはあるが、しかしやはりこのタイトルだけで、何処にも無い情景がありありと目に浮かぶ……。

キスよりさきに恋よりはやく

f:id:narazaka:20200320191643p:plain
a

これ以上に圧倒的に「速い」感覚を得る表現を自分は知らない。

キスより先に恋よりはやく(なんなのか)、というところが述べられておらず、しかも一意に想像も出来ないところがまた詩情を感じさせて良い。

オープニングの曲がまた最高に良く、あんばい良い映像とも相まって中身も途方もない名作なのではという(どう見ても錯覚である)印象を受けてしまうので困る。

18禁ゲームのサイトです→)キスよりさきに恋よりはやく

ホニャららMAGIC

「ららマジ」の「らら」が「ほにゃらら」の略だと知った時の衝撃たるや。

「ほにゃらら」をタイトルにつけ、「ららマジ」と略するセンス、底知れない天才の所業に思える。

「タイトルだけでお金を払いたくなる」という感情を発見する発端になった偉大なタイトル。

raramagi.wrightflyer.net

アリスと蔵六

この圧倒的にきれいな対比、かのシンプルでこれ以上無い的確なロゴ、タイトルだけで本質的な面白さを悟ったとさえ思える。

表紙も相まっていっそう極まる、素晴らしいタイトル。

www.comic-ryu.jp

暁に響く3 埼玉異動編

DLsiteで見つけた艦これギャグ系一般同人誌のタイトルなんだけども、一瞬で魅了された。

艦これのネタを分かっている前提の体感にはなるが、タイトルだけで中を確認せずにはいられないパワーがある。即DLした。

www.dlsite.com

(2018年1月追記)

この声好きかもよ?

f:id:narazaka:20200320185956p:plain
この声好きかもよ?

VTuber配信アプリREALITYのユーザーEMA氏が毎回つけている配信タイトル。

ようは新規視聴者への訴求文言なわけだが、配信で実質メインとなる声にフォーカスをあて、その中の配信から直接問いかけられているかのような軽妙で親しみのわく魅惑の言葉。

既存視聴者にも「そう、その声が好きなんだ」という共感が毎回わく、素晴らしいセンスの最高タイトル。

twitter.com

(2020年3月追記)

(その他良いタイトル等)

VRChatボイチェン勢がOculus Questを出先で使う方法(雑

最高便利VRバイスであるOculus Quest。 年末年始に実家に帰るけどVRChat入りたいなーとかいうときにもこれ一台あれば完璧じゃん!と掛け値無しに言える無敵デバイスです。

ただし地声勢ならば。

Oculus Questは外部マイク入力がどうやらできない(イヤホン端子、USB OTGともに無理)ため、外部ボイチェンを使ってVRChat Questに突っ込むという手段が使えず、ボイチェン勢やゆかりねっと・ボイスロイド勢には厳しい環境です。

しかし色々調べた結果、Virtual Desktopを使ってマイク音声をPCにバイパスし、PC上でボイチェンをかけてPC上のVRChatをやるという方式が使えることが分かりました。

一時期 Oculus ストアから削除されるとかどうとかで話題になったご存じSteamVR環境をQuestでプレイできる「Virtual Desktop」ですが、

  • どうもインターネット越しにでもPCにつなげる
  • マイク音声をPC側にパススルーする機能がある

という感じの模様。

というわけで

  1. Oculus QuestでVirtual Desktopを購入
  2. PCにSideQuestを導入
  3. Oculus QuestにSideQuest経由でVirtual DesktopのSteamVR対応apkを突っ込む(ここまでVirtual Desktopで紹介されているインストール手段)
  4. Virtual DesktopでPC側Steamに繋がるように設定しておく
  5. 家のPCをつけっぱなしにしたまま実家に帰る
  6. 実家のWifi越しにVirtual DesktopでPCにつなぐ
  7. Virtual Desktopの設定項目にMicrophone passthroughという項目があるのでオンに……しようと思うけどできない
  8. PC側デスクトップ画面を見て設定→システム→サウンドサウンドコントロールパネルで録音側の項目を見ると「マイク(Virtual Desktop Audio)」というのが無効になっているのが見つかる
  9. それを右クリックなどから有効にすると設定項目のMicrophone passthroughがオンにできた
  10. 「マイク(Virtual Desktop Audio)」をマイク扱いしてボイスチェンジャーに通してからVRChatに出す設定をする(多分ボイチェンルーティング中のいつも使っているマイクデバイスを「マイク(Virtual Desktop Audio)」に変更するだけ)
  11. SteamVR画面に戻るとボイチェンできてる!やったね!
  12. しかしOculusのメニューを出したりデスクトップ画面に戻ったりするとなぜか「マイク(Virtual Desktop Audio)」が無効、「Microphone passthrough」もOFFになりONにできなくなっている。
  13. そうなったらまた9から手順を繰り返してボイチェンをオンにする

という感じで実家からボイチェンしつつVRChatに入れました。後半いちいち面倒くさい手順がありましたが、なんとかなりました。Virtual Desktopのおかげです。本当に良かった。

ALVRもマイクパススルー機能自体はあるらしいのでできるのかもしれません。ちょっと調べてないので分かりませんが、分かる方は記事とか書いていただけると。

とりあえず雑にできるよ~と言っただけでおわり(また実家帰るときに見直そう)。

ちなみにこれはQuest使いながらPC必要な方式ですが、そもそも家にPCないよ~と言う人は(元々ボイチェン勢では確実にないだろうけど)クラウドでPCを使うという手もあるらしいですね。別件ですがそういう記事を貼っておきます。

suna.hateblo.jp

Blazor+Electron.NETでクロスプラットフォームGUIを作った時のメモ

Blazor Advent Calendar 2019 の記事です。

今年VRChat Advent Calendarにしか参加してなかったのでソフトウェアっぽいやつも書いてみたくなったやつ。

WinForms(Mono)は衰退しました

最近MacがCatalinaになって32bit対応を切りましたよね。これにより、MonoのWinFormsでだましだまし動かしていた拙作OSSGUIが死亡しました。

f:id:narazaka:20191224003049p:plain
Macはクソ

やや試行錯誤したんですがMonoがそもそもWinFormsにやる気がなく64bit対応は死んでいる臭いので、Windows Formsワンソースでのクロスプラットフォーム対応はあえなく死亡しました。

今最高に面妖なGUIフレームワーク

というわけでせっかくだから.NET 4.6だったのを.NET Core 3.1にしたうえでLinuxMacで動くC#GUIライブラリを探してみたんですが、AvaloniaもEto Formsもドキュメントスカスカでハマったし、Xamarin FormsはLinux/Mac対応公式でなくてVisual Studioでやるの面倒そう……。

WebエンジニアなのでこれはElectronでCLIを叩いた方がましかなと思ったところで出会ったのがElectron.NET。なんでもASP.NETサーバーをローカルで立ち上げ、ページをElectronでレンダリングして無理矢理GUIにするという面妖な技術とのこと。

さらにSPAできたらな……と思ったところで行き当たったのがBlazor。こちらもASP.NETサーバーがレンダリングした結果をフロントHTMLにシームレスに反映することでサーバーサイドC#でSPAができるという面妖な技術とのこと。(wasmにしてクライアント動作というオプションもあるらしいですが、プレビューとのことだったのでいいかげんハマりたくない気持ちから今回は回避しました。)

ブラウザフロントエンドのビューにC#コードを書いてラップし、それをWebsocketで無理矢理通信してサーバーレンダリングSPAする黒魔術Blazorと、ASP.NETサーバーを一般ユーザーPCで動かしてかつChromeバイナリも.NET Coreランタイムもドーンと配る富豪の極みのようなElectron.NETの夢の共演。

そういう魔術的体感大好きなので、最高の面妖開発体験が得られると期待して開発して、……結果的にちょくちょくハマりつつも案外すんなりGUIができました。

これのseedtable-eguiというプロジェクトがそれです。

github.com

seedtableライブラリ(CLIとしても動く)を参照して、そこのインターフェースを叩くGUIフロントエンド的なアプリです。 Windows Forms製のseedtable-guiから設定画面を省いた感じの機能体系ですね。

f:id:narazaka:20191224030348p:plain
ElectronとASP.NETで動いている面妖な産物
f:id:narazaka:20191224030600p:plain
Macでも動くよ

Blazor+Electron.NETでクロスプラットフォームGUIを作った時のメモ

というわけで、Blazor+Electron.NETのアプリを作れたんですが、技術の見た目がヤバいせいか少なくとも日本語資料では「dotnet newしてElectron.NETの最低限コード書いて立ち上げてみたよ!」という感じの記事しかありませんでした。

……いや、そもそもElectron.NET単体についてのやつも少ないですね……。みんな面妖技術は嫌いなのかも……。

なので実際にBlazor+Electron.NETで小規模なクロスプラットフォームWindows/Linux/MacGUIアプリケーションを組んだときにぶち当たった事についていくつか書きます。

なお導入自体は以下の記事が示している通りです。意外にもとっても簡単お手軽。

qiita.com

ちなみにASP.NETがどう動かされているのかは分からないんですが、とくにファイヤーウォールの許可などは必要ありませんでした。 地味な懸念がなく普通のアプリと同じように配布できるのはうれしいですね。

Electronのファイルダイアログなどを使いたい

Electron.NETとBlazorの組み合わせで最も使うと思われる箇所ですね。

JavaScriptとのインターフェースとしてIJSRuntimeという物が用意されており、これを使います。

docs.microsoft.com

C#からJSの関数を呼ぶ時には、まずrazorファイルでIJSRuntimeをDIで注入し、

@inject IJSRuntime JSRuntime;

InvokeAsync()を呼べば良い模様。

JSRuntime.InvokeAsync<OpenDialogResult>("showOpenDialog", option);

オプションについてはこのようにclassを定義しておくと良い感じにJSのオブジェクトと相互変換してくれます。

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace seedtable_egui.Data.Electron {
    [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
    public class OpenDialogOption {
        public string Title { get; set; }
        public string DefaultPath { get; set; }
        public string ButtonLabel { get; set; }
        public IEnumerable<FileFilter> Filters { get; set; }
        public IEnumerable<string> Properties { get; set; }
    }

    [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
    public class OpenDialogResult {
        public bool Canceled { get; set; }
        public IEnumerable<string> FilePaths { get; set; }
    }
}

よく使う関数については拡張メソッドにシテオクと便利だと思います。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.JSInterop;

namespace seedtable_egui.Data.Electron {
    public static class JSRuntimeExtensions {
        public static ValueTask<OpenDialogResult> ShowOpenDialog(this IJSRuntime js, OpenDialogOption option) {
            return js.InvokeAsync<OpenDialogResult>("showOpenDialog", option);
        }

        public static ValueTask<SaveDialogResult> ShowSaveDialog(this IJSRuntime js, SaveDialogOption option) {
            return js.InvokeAsync<SaveDialogResult>("showSaveDialog", option);
        }

        public static ValueTask ShowErrorBox(this IJSRuntime js, string content = null, string title = "エラー") {
            return js.InvokeVoidAsync("showErrorBox", title, content);
        }
    }
}

こうすれば

@code {
    async void OpenSeedPath() {
        var result = await JSRuntime.ShowOpenDialog(new OpenDialogOption {
            Title = "seedフォルダを開く",
            ButtonLabel = "開く",
            DefaultPath = SeedPath,
            Properties = new string[] { "openDirectory" },
        });
        if (!result.Canceled) {
            SeedPath = result.FilePaths.FirstOrDefault();
            StateHasChanged(); // JSRuntimeを使った際にステートが変わる場合はこれを叩かないとビューが更新されないです(ハマりどころ)
        }
    }
}

という感じでJS意識せず気軽に呼べます。

_Host.cshtmlに呼ばれるJS側関数を書いておきます。

    <script>
        const { BrowserWindow, dialog } = require('electron').remote;
        function showOpenDialog(options) { // 「開く」ダイアログを呼ぶ
            return dialog.showOpenDialog(win(), defaultNull(options));
        }
        function showErrorBox(title, content) { // エラーダイアログを呼ぶ
            return dialog.showErrorBox(title || undefined, content || undefined);
        }
        function win() { // ダイアログに親ウインドウが必要なのでJS側でハンドリングする
            return BrowserWindow.getFocusedWindow();
        }
        function defaultNull(obj) { // C#側から渡ってくるオプションは存在しないプロパティにnullが入っているが、electronのAPIはキー無し(undefined)を期待しているのでエラーを吐く場合があります。それの回避。
            const newObj = { ...obj };
            for (const key of Object.keys(newObj)) {
                if (newObj[key] === null) delete newObj[key];
            }
            return newObj;
        }
    </script>

かなりシームレスにElectronと連携できます。

Macでアプリケーションが終了しない問題

クロスプラットフォームGUIを作るとき頻発する「Macで閉じるボタン押してもアプリケーション終了しない問題」。

閉じるボタン押したのにアプリケーションが残っている、かつそのアプリのアイコン押しても何も反応がない……という悲しい状態になってしまいます。

本家Electron的にはメインプロセス側でこの問題に対処するのですが、Electron.NETにはどうも正規っぽい対処法がなかったです。

Applicationのcloseをとる系の対処が全滅したので、Electronのウインドウが閉じるJavaScript側のイベントを拾うことにしました。

上記IJSRuntimeとは逆向きにJSからC#を呼ぶ方法としては、DotNet.invokeMethodAsync("アセンブリ名", "静的メソッド名");と言う方法があります。

いきなりアセンブリ名が出てくるあたり無理矢理感のあるAPIですが、とりあえずDotNetという定数がJSに自動で注入されており、そこから[JSInvoke]属性のついたpublicな静的メソッドを呼べるとのこと。

_Host.cshtmlに

    <script>
        const { BrowserWindow, dialog } = require('electron').remote;
        function win() {
            return BrowserWindow.getFocusedWindow();
        }
        win().on('close', function(e) { // Electronのウインドウが閉じるとき
            DotNet.invokeMethodAsync("seedtable-egui", "OnClose"); // C#側のseedtable-eguiアセンブリ内の静的メソッドOnCloseを呼ぶ
        });
    </script>

Index.razorに

@code {
    [JSInvokable]
    public static void OnClose() {
        ElectronNET.API.Electron.App.Quit();
    }
}

と書いて事なきを得ました。(たぶんOnCloseはビューではなく別の普通の静的クラスに書くのが本来だと思いますが、JSInvoke属性が定義されている箇所を見つけるのが面倒だったので……)

razorデバッグできない問題

electronize startで単純に立ち上げるとVisual Studioデバッグできないっぽいです。(アタッチの設定書いていないので当たり前ですが……)

正直今回は小さいアプリ&既存の移植品だったためそんなに必要なく、そのままカンとprintfで済ませてしまいました。

ここ何か方法あるようなら誰か知見を書いてください。

「アプリケーションのフォルダ」がresources/binになるかも

ユーザーに直接見えるのはElectronを立ち上げるexeですが、Blazorが動いているのはASP.NET Coreのサーバー側です。

.NET Coreの1ファイルexeパッケージングなどに備えたPath.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);等の手法では、サーバーDLLがあるresources/binになってしまう模様。

Application.StartupPathだとメインのexeパスになったり……するかな?(試していないです)

パッケージングの問題

electronize buildにまつわる問題

WindowsではMac OS X用ビルドができない

できないらしいです。これは回避不能っぽいのでMacを買うか、TravisMacビルドに投げましょう。

Linuxビルドだとサーバーしか吐かれない?

なぜかelectronize build /target linuxしてもresources配下のサーバー側しか吐かれず、electronのエントリポイントが吐かれないという現象に見舞われました。

electronizeから叩かれた時のelectron-builderだけなぜかそういう風に動いている模様だったので、

cd seedtable-egui
electronize build /target linux
cd obj/desktop/linux
npm install electron@7.1.2
npx electron-builder . --config=./bin/electron-builder.json --linux --x64 -c.electronVersion=7.1.2

と言う具合に、electronizeでサーバのpublishしてから、その中間フォルダで改めてelectron-builderを実行することでパッケージすることとしました。

原因はよく分からないのですが、応急処置は可能です。

パッケージングにめちゃくちゃ時間がかかる問題

デフォルトの設定だとWindowsインストーラー、LinuxがAppImage、Macdmgなどとなっているんですが、これがとにかく遅い。

圧縮あたりをJSでやってたりするのかもしれません。インストーラーなどが必須でないならば、ここは"dir"で出してzipコマンド等で固めるのが速くて良いです。

electron.manifest.jsonの"build"がそのままelectron-builderに渡されるオプションのJSONになるので書いてゆきましょう。

{
  "executable": "seedtable-egui",
  "splashscreen": {
    "imageFile": ""
  },
  "singleInstance": true,
  "build": {
    "appId": "net.narazaka.seedtable-egui.app",
    "productName": "seedtable-egui",
    "copyright": "Copyright © 2019 Narazaka",
    "buildVersion": "4.0.0-rc4",
    "compression": "maximum",
    "directories": {
      "output": "../../../bin/Desktop"
    },
    "extraResources": [
      {
        "from": "./bin",
        "to": "bin",
        "filter": ["**/*"]
      }
    ],
    "files": [
      {
        "from": "./ElectronHostHook/node_modules",
        "to": "ElectronHostHook/node_modules",
        "filter": ["**/*"]
      },
      "**/*"
    ],
    "win": {
      "target": "dir"
    },
    "linux": {
      "target": "dir"
    },
    "mac": {
      "target": "dir"
    }
  }
}

注意: electronize initなどのコマンドはプロジェクトのフォルダで実行すること

地味ですが、VisualStudioで作ったソリューションの中にElectron.NET環境を作る場合、electronizeコマンドはソリューションではなくプロジェクトのフォルダで実行してください。

でないとstartやらbuildやらがエラります。

まとめ

ちょくちょく問題はありましたが、正直ほとんどElectron.NETだけの問題で、特にBlazorは流石Microsoft謹製だけあってかなり隙のない作りで、正直予想外に安定感が感じられました。

Electron.NETはそういう意味でやや荒削りな所がありましたが、こちらもまあまあ回避可能です。

正直もっと手こずるかなと思っていたところ案外スムーズにいってしまったので、面妖技術に抵抗ない方には結構お勧めかもしれません。 見知らぬフレームワーク固有のXAMLタグいちいち使い方調べて書くより見知ったHTMLでバインディングできるのやっぱり良い。

github.com

ソースサンプルとしては、この中のseedtable-eguiプロジェクトが

  • サーバーサイドBlazor
  • Electron.NET
  • 他プロジェクト参照
  • Windows/Linux/MacのCIビルド

を含んだものなので、ざっくり参考になるかもしれません。

Blazor+Electron.NET、案外イケるよ!やっていこう!(雑

ついでに宣伝

github.com

seedtableは二次元データを格納したxlsxファイルとYAMLファイルの相互変換ツールです。 データはYAMLでgitフレンドリーにしつつ、その編集はExcelで快適にしたいというユースケースに使えます。

スマートフォンゲームの運用の辛みを救うために作ったツールで導入実績もあるので、興味があればどうぞ。

またBlazor+Electron.NETほどではないかもしれませんが、seedtableにはMotif*1の.NETバインディングWindows Forms仕立て)という面妖技術によるGUIもあります(漁港などに出没するらしいsazae657さんが作ったものです)。

github.com

Blazorのような心がわくわくする謎技術に興味がある方はこちらも触ってみても面白いかもしれません!(雑

*1:1989年から続くX Window System用のGUI規格およびウィジェットツールキット(GTKみたいなもの)