20210501のC#に関する記事は5件です。

ASP.NET Core MVC に Identity で認証機能を追加する

やること ASP.NET Core MVC の MVC アーキテクチャに Identity を組み込んで認証機能を追加します。 Visual Studio で提供される MVC + Identity のテンプレートでは MVC に Razor Pages を追加する形になっていて気持ち悪い...全部 MVC に組み込みたい!ということでこのようなことをやります。 開発環境は Visual Studio for Mac です。 作るもの 認証機能付きの簡単な ToDo アプリを作ってみます。 仕様は以下のようにします。 アカウントは名前とパスワードのみで登録 各アカウントが登録するタスクは独立している つまり、A さんが登録するタスクは B さんから見ることができない。逆も然り。 CRD だけ実装して、U は実装しない(別にしてもいいけど、省略) やっていくぞ 1. 新規プロジェクトを作成 web アプリケーション (MVC), .NET Core3.1, 認証なし, と選択していきます。 2. NuGet パッケージ 必要になるものをあらかじめインストールしてしまいましょう。 以下の 6 つをインストールします。.NET Core 3.1 でやってるので、各パッケージのバージョンも 3.1.x で設定しておきます。 AspNetCore.Identity AspNetCore.Identity.EntityFramework AspNetCore.Identity.UI EntityFrameworkCore EntityFrameworkCore.Design EntityFrameworkCore.Sqlite 3. データベースコンテキストの作成 各ユーザーの認証情報はデータベースに格納されるので、まずはデータベースを使えるようにするところから。 普通にデータベース作るだけなら、DbContext を継承したクラスを作ればいいのですが、Identity で使うデータベースコンテキストは IdentityDbContext を継承します。このクラスには Users とか、認証情報を格納する DbSet がすでにプロパティに入っているので、継承さえしてしまえば OK です。 ToDoContext.cs namespace ToDoIdentity.Data { public class ToDoContext : IdentityDbContext { public ToDoContext(DbContextOptions<ToDoContext> options) : base(options) { } } } 4. Identity を使うために Startup.cs を編集 ここがややこしい...ぶっちゃけおまじない状態 Startup.ConfigureServices やることは 3 つ。 データベースコンテキストを使えるようにする Identity を使えるようにする 認証機能の設定をする ConfigureServices に以下のようなコードを追加します。 Startup.cs services.AddDbContext<ToDoContext>(options => Configuration.GetConnectionString("DefaultConnection"))); // Identity を追加 services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false) .AddEntityFrameworkStores<ToDoContext>(); // Identity を設定 services.Configure<IdentityOptions>(options => { // Password settings. options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 6; options.Password.RequiredUniqueChars = 1; // Lockout settings. options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); options.Lockout.MaxFailedAccessAttempts = 5; options.Lockout.AllowedForNewUsers = true; // User settings. options.User.AllowedUserNameCharacters = null; // UserName に使える文字の制限をなしにする options.User.RequireUniqueEmail = false; }); services.ConfigureApplicationCookie(options => { // Cookie settings options.Cookie.HttpOnly = true; options.ExpireTimeSpan = TimeSpan.FromMinutes(5); options.LoginPath = "/Identity/Login"; options.AccessDeniedPath = "/Identity/AccessDenied"; //AccessDenied は未実装 options.SlidingExpiration = true; }); services.AddDefaultIdentity<IdentityUser> で、ユーザー情報として使うクラスを設定します。ここではデフォルトの IdentityUser を使っていますが、IdentityUser を継承したクラスでも設定できます(詳しくはこのへんを見ると良い) Identity の設定はこれを見れば良い。 Startup.Configure app.UseAuthentication()を app.UseRouting() と app.UseAuthorization() の間に入れます。 Starup.cs app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); これで、詳しいことはよくわからんが、HTTP リクエストが認証ミドルウェアを通るようになるらしい。 5. 認証機能の実装 さてここからバシバシとコードを書いていくわけですが、ここまでくれば普通の MVC の考え方を使っていけばいいです。 つまり、Identity の Model, View, Controller を作っていきます。 View ログイン画面とアカウント登録画面を作って、それぞれにフォームを追加するだけ。 例えばログイン画面はこんな感じ Login.cshtml @model IdentityInputModel @{ ViewData["Title"] = "Login"; } <h1>ログイン</h1> <div class="row"> <div class="col-md-4"> <form method="post"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="form-group"> <label asp-for="UserName" class="control-label"></label> <input asp-for="UserName" class="form-control" /> <span asp-validation-for="UserName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Password" class="control-label"></label> <input type="password" asp-for="Password" class="form-control" /> <span asp-validation-for="Password" class="text-danger"></span> </div> <div class="form-group"> <input formmethod="post" type="submit" value="ログイン" class="btn btn-primary" /> </div> </form> </div> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} } Model View からフォームで post されたものを格納できれば良いです。 IdentityInputModel.cs namespace ToDoIdentity.Models { public class IdentityInputModel { public string UserName { get; set; } public string Password { get; set; } } } Controller ここはちょっと普通の Controller と違う部分が出てきます。というのも、ここでログインしたりログアウトしたりという処理を行うからです。 まずはコンストラクタの引数で UserManager と SignInManager のインスタンスを受け取ります。これらはそれぞれ、リクエスト元のユーザー情報を取得するインスタンス、ログイン関係の処理を行うインスタンスです。 IdentityController.cs public IdentityController(UserManager<IdentityUser> _userManager, SignInManager<IdentityUser> _signInManager) { userManager = _userManager; signInManager = _signInManager; } これらを使って、ログイン、ログアウト、アカウント登録を行っていきましょう。 ログイン IdentityController.cs var result = await signInManager.PasswordSignInAsync(model.UserName, model.Password, true, false); これでログイン処理を行い、その結果が result に格納されます。ログインの成功・失敗によってリダイレクト先を変えたりできます。 ログアウト IdentityController.cs await signInManager.SignOutAsync(); これだけ! アカウント登録 IdentityController var user = new IdentityUser() { UserName = model.UserName }; var result = await userManager.CreateAsync(user, model.Password); こっちは userManager を使って行います。ユーザーインスタンスとパスワードを引数に入れて登録です。これも成功したかどうかが result に入れられます。 6. 普通に ToDo アプリを作っていく さて、これにて認証機能は実装できたので、あとは ToDo の CR(U)D を実装していくだけですね。 ところが、仕様をもう一度確認してみると 各アカウントが登録するタスクは独立している とあります。 これは、ToDo モデルにユーザー ID を持たせることで実装できそうです。 ToDoItem.cs namespace ToDoIdentity.Models { public class ToDoItem { [Key] public int Id { get; set; } public string ToDo { get; set; } public string UserId { get; set; } } } 本当は UserId を外部キーにした方がいいんですけど、ここでは省略。 さて、あとは Controller で ToDo モデルに UserId を渡すようにすれば OK です。Controller ではユーザーの情報を以下のようにして取得することができます。 ToDoItemController.cs var newItem = new ToDoItem() { UserId = userManager.GetUserId(User), ToDo = toDoName }; このように userManager からユーザーの情報を取得できます。UserManager インスタンスは、IdentityController でやったのと同様に、コンストラクタの引数で受け取れます。 完成!! できた〜! ということでコードをこちらにあげています。参考にしてみてください! おわり ぶっちゃけ Identity は高機能すぎて使いこなせてないです...ちゃんと勉強しなきゃー
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[C#] GEO座標変換ライブラリを作ってみた [.NET 5.0]

何作ったか .NET Core(.NET 5.0)で動作する座標変換ライブラリです。 GEO座標(緯度経度) ECEF座標 (地球中心座標) ENU座標 ローカル座標 を相互変換します。 作った動機 屋外をGNSSで自律運転するロボットの開発をしていて、開発の支援ツールを作ろうとしたけども.NET Coreでライセンス的にいい感じの座標変換ライブラリがなかった。 本気で探したらあるかも?でも勉強がてら作りました。 開発状況 まだまともにテストもしていないし、実装したい機能もたくさんあります。 とういうかまだ2次元座標にしか対応していないです。 間違っている可能性は大いにあるので、つっこみ(コメント issue)募集しています。 勉強がてら、内容についての記事もちょくちょく書いていければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Azure Cognitive Services】C#で作る「オウム返しナナミ」

はじめに しゃべった言葉をオウム返ししてくるぬいぐるみのことは知っていますか?遊んだことありますか? 「僕の名前は太郎!」としゃべったら、ぬいぐるみも「僕の名前は太郎!」と同じ言葉を言い返してきます。ぬいぐるみの電池が切れるまで、ずっとオウム返ししてくるわけです。 以前、このような仕組みをAzure Cognitive Servicesを使ってJava(以下の記事参照)で作ってみましたが、今回はC#で作っていきます。この記事では、Azure portal上でCognitive Servicesのリソース作成済みであることを前提として進めていきますが、詳しい手順が知りたい場合はぜひ、下記の記事をご参照ください。 【Azure Cognitive Services】Javaで作る「オウム返しナナミ」 前提・環境 Windows 10 home visual studio 2019 Azure portal上でCognitive Servicesのリソース作成済み キーを取得できる。 場所を取得できる。 NuGetパッケージ Microsoft.CognitiveServices.Speech v1.16.0 全体のソースコード using System; using System.Threading.Tasks; using Microsoft.CognitiveServices.Speech; using Microsoft.CognitiveServices.Speech.Audio; namespace AzureCognitiveServicesAPI { class Program { static string subscriptionKey = "YourSubscriptionKey"; static string serviceRegion = "YourServiceRegion"; static string speechRecognitionLanguage = "ja-JP"; static string speechName = "ja-JP-NanamiNeural"; static async Task Main(string[] args) { var speechConfig = SpeechConfig.FromSubscription(subscriptionKey, serviceRegion); speechConfig.SpeechRecognitionLanguage = speechRecognitionLanguage; var audioConfig = AudioConfig.FromDefaultMicrophoneInput(); var recognizer = new SpeechRecognizer(speechConfig, audioConfig); var synthesizer = new SpeechSynthesizer(speechConfig); var speakText = ""; while (speakText != "終了。") { speakText = await SpeechToText(recognizer); await TextToSpeech(synthesizer, speakText); } await TextToSpeech(synthesizer, "プログラムを終了させますね。"); } static async Task<string> SpeechToText(SpeechRecognizer recognizer) { var result = await recognizer.RecognizeOnceAsync(); Console.WriteLine($"話した内容: {result.Text}"); return result.Text; } static async Task TextToSpeech(SpeechSynthesizer synthesizer, string speakText) { await synthesizer.SpeakSsmlAsync(CreateTextReadOut(speakText)); } static string CreateTextReadOut(string text) { return $"<speak version='1.0' xmlns='https://www.w3.org/2001/10/synthesis' xml:lang='{speechRecognitionLanguage}'><voice name='{speechName}'>{text}</voice></speak>"; } } } フィールド変数のsubscriptionKeyとserviceRegionに前提で取得しておいたキーと場所に書き換えてください。 実行すると、話した内容がコンソール上に出力され、さらにNanamiがその内容を話してくれるかと思います。 「終了」と話すとNanamiから「プログラムを終了させますね。」と言われ、プログラムが終了になります。 以上になります。ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#のDebug/Releaseコンパイルはどう違うの?

はじめに  こんにちは、九島茶にゃです。  今回の記事は開発者向けになります。  ILかアセンブリ言語についての知識があるといいでしょう。 Debug/Releaseの違い  簡単に言えば、以下のコードがあったとします。 Sample.cs class Sample { static void Main() { int a = 10 * 5; System.Console.WriteLine(a); } }  次に、Sample.csと全く同じ動作をする、以下の様なコードがあるとします。 ImprovedSample.cs class Sample { static void Main() { System.Console.WriteLine(50); } }  もしコードに対し逐次的に処理が行われる(コンパイラ、仮想マシン、CPU等での改変がない)としたら、明らかに10 * 5の計算や変数aへのstore/loadを行っていないImprovedSample.csの方が速いに決まっていますよね?  ちなみに、Sample.csをDebug/Releaseでコンパイルするとこう解釈されます。(処理の部分のみ抽出します。assembly等の属性の付加も見たい人はこちら) Debugコンパイル DebugSample.cs using System; internal class Sample { private static void Main() { int value = 50; Console.WriteLine(value); } } Releaseコンパイル ReleaseSample.cs using System; internal class Sample { private static void Main() { Console.WriteLine(50); } }  以上のコードを見ると、Debugでは領域が確保され、代入の処理が行われるのに対し、Releaseでは領域が確保されず、WriteLineメソッドに直接値が渡されている(不要な処理が省かれている)事がわかります。そのため、Releaseでは一部ブレークポイントをつけても認識されない所があります。ただし、不要な処理が省かれるので明らかに速いです。 IL的な相違  一般的に、Debug/Releaseには最大スタック数(サイズ)、ローカル変数のサイズ、コードサイズにて以下のような関係性があります。 Debug・Releaseにおけるサイズの関係性 最大スタック数 Debug ≦ Release (Debug < Release のとき Release = 8) ローカル変数のサイズ Debug ≧ Release コードサイズ Debug > Release 関係性の理由  最大スタック数は基本的に同じです(1,2か引数の数だけ確保される)。しかし、ローカル変数を用いないときはデフォルトのサイズ(8 Bytes)が確保されるので、以上のようになります。  ローカル変数はReleaseSample.csの通り、最適化によって領域が確保されない可能性があるからです。  コードサイズは、DebugコンパイラはDebugSample.csのようにコードを逐次的にILに変換し、(ブレークポイントのため?)nopをいくつか追加します。Releaseコンパイラは出来るだけ軽く、短いコードを生成します。勿論、基本的にnopは生成しません。そのため、以上のようにDebugの方がコードサイズが大きくなります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Monobit Unity Networking 2.0(MUN)を使ってみた話

はじめに 仕事でMonobit Unity Networkingについて調べる機会があったので,備忘録がてら記事にしました。 チュートリアルの内容のまとめと,ちょっと使うときに便利かなと思った実装法を中心に書きます。 サーバとかの設定は公式が結構ちゃんとドキュメント出してくれてるので(参考),この記事では基本的にコードとかの実装方面をまとめていきます。 かなりふわふわしてる記事なので,間違い等あればコメントで指摘していただけると幸いです。 あと掲載コードについては申し訳ないんですが,全部について動くかの検証はしてないです。動いたコードに近いコードを載せるように努力してますが,動かなかったら文句言ってください。気力や時間があったら検証します。 Monobit Unity Networking とは Monobit Unity Networking(MUN)とは,モノビットエンジンが提供する国産Unity用通信ミドルウェアです。つまりUnityでマルチプレイとか通信とかをやるためのアセットです。 通信量に合わせて課金されるタイプなので,全機能を使うのにお金はかかりません。 基本的にはUnityで作ったクライアント間のP2P通信で,この記事では取り上げませんが,オンプレミス版も提供されています。 詳しくはここ 前提環境 Unity 2020.3.5f MUN 2.8.0 基本的な機能と実装 基礎的な用語 ルーム:プレイヤーが実際に通信している部屋 ロビー:ルームの集まり,ここではプレイヤー間の通信はできない MonoBehaviorの上書き Munを使う上で,MonoBehaviorの代替クラスがあります。主にMonobitEngine.MonoBehaviorとMonobitEngine.MunMonoBehaviorがあります。後者は接続やルームの入室のコールバックが定義されてます。 MonobitEngine.MonoBehaviorはMonobitEngine.MunMonoBehaviorを含めた大体のMonobitで定義されるコンポーネントの基底クラスになってるという特徴がありますが,多分ユーザで使う分にはMonobitEngine.MunMonoBehaviorを継承しとけば十分だと思います。だって継承されてるからMonobitEngine.MonoBehaviorの全機能使えるし。 サーバへの接続〜ルーム入室 ちなみにちょくちょく出てくるMonobitEngine.MonobitNetworkは静的クラスなのでMunを導入しておけばどこでも呼べます。 サーバへの接続・切断 公式記事(サーバへの接続) 公式記事(サーバからの切断) //サーバへの接続 //gameVersion:ゲームのバージョンを表す文字列 MonobitEngine.MonobitNetwork.ConnectServer(string gameVersion) //サーバからの切断 MonobitEngine.MonobitNetwork.DisconnectServer() この際,MonobitEngine.MonobitNetwork.autoJoinLobbyを事前にtrueにしておくとデフォルトのロビーに入ってくれます。 ロビーへの入室・退出・ほか操作 公式記事(ロビー入室) 公式記事(ロビー退出) 前述したMonobitEngine.MonobitNetwork.autoJoinLobbyのフラグを立てて入室してやるとここら辺の処理は省略できます。 //デフォルトロビーへの入室 MonobitEngine.MonobitNetwork.JoinLobby() //指定したロビーへの入室 //lobbyInfo:ロビー設定とか //ロビーがなかったら勝手に作るので注意 MonobitEngine.MonobitNetwork.JoinLobby(MonobitEngine.LobbyInfo lobbyInfo) //ロビーからの退出 MonobitEngine.MonobitNetwork.LeaveLobby() LobbyInfoにはNameとKindのプロパティがありますが,Kindはドキュメントにも詳しい仕様が書いてなかったので正直よくわかりません。誰か見つけたら教えてください(他力本願) //lobbyInfoの実装例 var info = new MonobitEngine.MonobitNetwork(); info.Kind = LobbyKind.Default; lobby.Name = "MyLobby"; MonobitEngine.MonobitNetwork.JoinLobby(info); 公式記事(ルーム一覧の取得) また,ロビーの中からは公開ルームの一覧を取得できます。 //公開ルームを全取得 //RoomData[]で帰ってきます MonobitEngine.MonobitNetwork.GetRoomData() ルーム作成・入室・退出 公式記事(ルーム作成) 公式記事(ルーム入室) 公式記事(ルーム退出) //ルーム作成 //roomName: ルーム名 //roomSettings: ルームの設定 //lobbyInfo:属するロビー MonobitEngine.MonobitNetwork.CreateRoom(string roomName, MonobitEngine.RoomSettings roomSettings, MonobitEngine.LobbyInfo lobbyInfo) //ルーム入室 //なかったらfalseが帰ってきます //roomName: 入りたいルーム名 MonobitEngine.MonobitNetwork.JoinRoom(string roomName) //ルーム入室,なかったら作成 //roomName: ルーム名 //roomSettings: ルームの設定 //lobbyInfo:属するロビー MonobitEngine.MonobitNetwork.JoinOrCreateRoom(string roomName, MonobitEngine.RoomSettings roomSettings, MonobitEngine.LobbyInfo lobbyInfo) //ランダム入室 MonobitEngine.MonobitNetwork.JoinRandomRoom() //条件に合うルームにランダム入室 //expectedCustomRoomProperties: 検索したいカスタムパラメータ,ルーム作成側はroomSettings.customParametersで設定できる(後述) //expectedMaxPlayers: 検索したいルームの入室人数を指定,0なら考慮しない MonobitEngine.MonobitNetwork.JoinRandomRoom(Hashtable expectedCustomRoomProperties, byte expectedMaxPlayers) //ルーム退出 MonobitEngine.MonobitNetwork.LeaveRoom() roomSettings周りが結構複雑です。これには次のプロパティを設定できます。 byte maxPlayers : 入室可能人数 bool isVisible : trueならロビーから検索用メソッド呼ぶと検索できる bool isOpen : 他プレイヤーの入室の可否 Hashtable customRoomParameters: カスタムパラメータ,JoinRandomRoomとかの検索条件に指定できる string[] customRoomParametersForLobby: ここに指定したカスタムパラメータはロビーから見えるようになり,検索用メソッドの条件に指定できる 特にcustomRoomParametersがよーわからないと思います。これはつまりHashtable型のいろんなタグパラメータをつけられるっていう感じで,JoinRandomRoomとかの絞り込みに影響します。 詳しくはこちら(公式記事) 例を示します。 var hashTable = new Hashtable(); hashTable["tag"] = "Unity"; var settings = new RoomSettings(); settings.roomParameters = hashTable; MonobitNetwork.CreateRoom("RoomFoo", settings, LobbyInfo.Default); というルームを作ると, var hashTable = new Hashtable(); hashTable["tag"] = "Unity"; MonobitEngine.MonobitNetwork.JoinRandomRoom(hashTable, 0); でそのルームにマッチングできるようになるはずです。 公式記事ではroomParametersに対してインデックスを指定して書き込む方法で例が示されていますが,自分の環境ではそれをやると「roomParametersの中身なんもねぇよ!」って怒られたので,こちらでは自分で作ったHashtableで上書きしています。こちらだと通ることも確認しています。 オブジェクトの位置とアニメーションの同期 参考公式記事 こちらはほぼスクリプトなしで実装できます。 同期したいオブジェクトにMonobit Viewを追加し, 位置ならばMonobit Transform View,アニメーションならMonobit Animation Viewのスクリプトを追加して, Monobit ViewのObserved Component Registration ListにMonobit Transform ViewやMonobit Animation Viewを追加します。 これでとりあえず位置の同期は完了です。 ネットワーク越しのオブジェクト生成・破棄 公式記事(オブジェクト生成) 公式記事(オブジェクト破棄) ネットワーク越しで生成や破棄を同期させたいオブジェクトに関しては,UnityEngine.Instantiateするとうまくいきません。(どううまくいかないかは検証して追記するかもしれないです) //ネットワーク越しにオブジェクト生成 //string prefabName: プレファブ名(内部的にはResources.Loadしてるので正確にはパス名?要検証) //positionとrotationはUnityEngine.Instantiateと同じなので略 //int group: 所属するグループ名(なんかわかったら追記します) MonobitEngine.MonobitNetwork.Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group) //ネットワーク越しに対象viewに所属するオブジェクトを全部破棄 //MonobitView monoView: 破棄する対象のMonobitView MonobitEngine.MonobitNetwork.Destroy(MonobitView monoView) //ネットワーク越しに対象オブジェクト破棄 //引数gameObjectは技術ドキュメントだとMonobitView型ですがGameObject型です。(検証済み,あとAPIリファレンスはそうなっています) MonobitEngine.MonobitNetwork.Destroy(GameObject gameObject) MonobitEngine.MonobitNetwork.InstantiateはResources.Loadを使ってるようなので,生成するプレファブはResourcesフォルダにないといけません。あと指定するのがプレファブのGameObjectではなくプレファブ名なのも注意。 操作キャラの位置同期(オブジェクトの所有権の処理) 公式記事(オブジェクトの所有権) 参考公式記事 さて,ここまでの作業でとりあえずオブジェクトの生成と位置やアニメーションの同期はできますが,操作キャラだけはもうちょっと作業が要ります。というのも,同期された相手のオブジェクトはこちらのシーンに召喚される都合上,何も対策をしないと同期されてきた相手のオブジェクトも操作できてしまうため,位置の同期とこちらの操作で干渉してなんか変なことになります。 そのため,自分が所有権をもつオブジェクト以外は操作しないというスクリプトを書いてやらないといけなくなります。 具体的には,自分がオブジェクトの所有権をもつかは,MonobitEngine.MonoBehavior(またはMunMonoBehavior)内のmonobitView.isMineプロパティで判定できます。これを使って操作スクリプトを無効化してやればいいです。実装例は下の方にあります。 ネットワーク越しのメソッド呼び出し 公式記事 MonobitEngine.MonoBehavior(またはMunMonoBehavior)なら,ネットワーク越しでRPCという手法によってメソッドを呼び出してやれます。 まず,呼び出したいメソッドに[MunRPC]を指定します。 MonobitViewを適当なオブジェクトにアタッチしてやり,MonobitViewIDを0以外の適当な正の整数値にしてやります。 それを[SerializedField]なりGetComponentなりで取得してやって,MonobitViewのRPC()メソッドを呼べばOKです。 なんのこっちゃってなってると思うので例を示します。 [MunRPC] void targetMethod(string message, int id){ Debug.Log(id + " says " + message); } void callRpc(){ var view = GetComponent<MonobitView>(); view.RPC( nameof(targetMethod) //関数の名前(string) , MonobitTargets.All //呼び出しの対象,公式ドキュメント参照 //(ここから呼び出し先の引数) , "Hi!" //message , 0 //id ); } コールバック サーバに繋いだ時や,ルームに入った時など,いろんな時に対してコールバックが用意されています。数が多いのでここでは紹介せずこちらを参照していただきたいですが,一つだけハマりそうな部分なんですが,コールバックの利用はMunMonoBehaviorを継承する必要があります。逆に言うと,MonobitEngine.MonoBehaviorではコールバックが利用できません。 理由はコールバックはMunMonoBehaviorのメソッドをオーバーライドする形で実装されてるため,MonobitEngine.MonoBehaviorではそもそものメソッドが定義されてないんですよね。もうMunMonoBehaviorだけでいいんじゃないかな。 ちょっと一工夫 オブジェクトの所有権の処理 公式のチュートリアルでは操作スクリプトに直接所有権の判定を組み込んでいますが,操作スクリプト一個一個に組み込んでるとキリがないですし,基本的にゲーム自体の開発してる時は通信のことなんて考えたくないと思うので,個別に管理してくれるコンポーネントを作った方が管理しやすいと思います。 OwnerHandler.cs /* OwnerHandler.cs Copyright (c) 2021 Dango This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ using System.Collections.Generic; using MonobitEngine; using UnityEngine; using MonoBehaviour = UnityEngine.MonoBehaviour; namespace MunCommunication { /// <summary> /// Configure MonoBehavior.enabled by ownership of attached object. /// </summary> public class OwnerHandler : MunMonoBehaviour { [SerializeField] private List<MonoBehaviour> enableIfOwner; [SerializeField] private List<MonoBehaviour> disableIfOwner; // Start is called before the first frame update void Start() { configComponents(); } /// <summary> /// Check ownership, and configure "enabled" property. /// </summary> void configComponents() { bool isOwner = monobitView.isMine; enableIfOwner.ForEach(behaviour => { behaviour.enabled = isOwner;}); disableIfOwner.ForEach(behaviour => { behaviour.enabled = !isOwner;}); } } } これでインスペクタに所有権があるときに有効/無効にするリストができてくれるので設定してやればいいです。 パスワードの設定 MUNはルームに対してパスワードを設定できたりはしないんですが,こちらのPhotonの記事のようにカスタムパラメータをつけて,RandomJoinをやってやればそれに近いことをできます。 簡易的な実装例 RoomSelector.cs /* RoomSelector.cs Copyright (c) 2021 Dango This software is released under the MIT License. http://opensource.org/licenses/mit-license.php */ using System.Collections; using System.Collections.Generic; using MonobitEngine; using UnityEngine; using UnityEngine.Events; using MonobitNetwork = MonobitEngine.MonobitNetwork; namespace MunCommunication { public class RoomSelector : MunMonoBehaviour { Hashtable generateAuthTable(string roomName, string password) { var customParam = new Hashtable(); customParam["name"] = roomName; customParam["password"] = password; return customParam; } public void createAuthorizedRoom(string roomName, string password) { var setting = generateAuthTable(roomName, password); var roomSetting = new RoomSettings { roomParameters = setting , isVisible = false }; //ランダム文字列生成 string randomLine = Guid.NewGuid().ToString("N").Substring(0, 10); MonobitNetwork.CreateRoom(randomLine, roomSetting, LobbyInfo.Default); } public void joinAuthorizedRoom(string roomName, string password) { var setting = generateAuthTable(roomName, password); MonobitNetwork.JoinRandomRoom(setting, 0); } } } ただ,これだと同じルーム名・パスワードが同時に発生した場合に対応ができないので,外部に認証サーバを設けてルーム名を管理してやらないと実用に足るものはおそらく作れないと思います。 まとめ MUNでできること ・ネットワーク越しのオブジェクトの位置やアニメーションの同期 ・ネットワーク越しでのメソッド呼び出し ちょっとよくわからない部分がなくもないですが,使ってる感じは問題ないような感じがします。 参考 MUNチュートリアル MUNのAPIリファレンス パスワードのかけかたとか:Photonのドキュメント ランダム文字列
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む