0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tauriでエンジンからゲームを作ってみるAdvent Calendar 2024

Day 16

【Day16】たうりちゃんはデータを保存したい!!【QAC24】

Last updated at Posted at 2024-12-15

結局のところデータ保存したいですよね。

前回にタイルエディターを作ったような気がするのですが、データ保存が出来なきゃ意味がないのですよ。
Node.js に同じみな人に言うならfsみたいなのが欲しいですよね。

fs-plugin でデータを保存する

Tauri の File System という機能は、Plugin という形で提供されています。
そのため、まずはインストールする必要があります。

$ pnpm tauri add fs

これで、fsのパッケージのインストールと Rust 側のコード調整が自動で行われます。

適当にコードを書いてお試ししてみましょう。

import { exists, BaseDirectory } from "@tauri-apps/api/fs";

console.log(await exists("test.txt", { baseDir: BaseDirectory.AppData }));

というようなコードが Docs で紹介されているので説明してみましょう。

今回はexistsBaseDirectoryというものをインポートしています。
existsはファイルが存在するかどうかを確認する関数なのですが、親ディレクトリを指定する必要があります。
また、セキュリティ上の理由からパスは後述のbaseDirからの相対パス(親ディレクトリに行くことは出来ない)で指定する必要があります。
(path.joinというものを使うことで指定しなくてもよい)

でそのbaseDirですが、BaseDirectoryから生える列挙型から選ぶことが出来ます。
ここら辺は、どこのフォルダにアクセスする必要があるのかで変わってきますね。

...で、なんとなくわかったかもしれないですが、あんまり自由度が高いわけではないというか...

好きな場所の好きなファイルを操作することはできないですね。多分。
また、セキュリティ上の理由からpermissionにパスを書き込まなければならず、少しそこらへんもめんどくさいです。

Rustで書けばいいじゃね?(原点回帰)

簡単な話、フロントエンドはセキュリティ上の理由から制限されています。
ですがバックエンドはそこまで制限されていないので、書くことが出来ます。
が、何のためにフロントエンドが制限されているのかだけは考えておく必要がありますよね...?

というわけで、Rust...よりTauri的な部分にフォーカスを当てていきましょう

tauri-spectaを使ってみる

tauri-spectaは、Rustで定義した関数...特にコマンドをフロントエンド上で勝手に定義してくれて、楽に呼び出せるようにするライブラリというかツールというかです。

という訳でインストールしていきましょう。

インストール

基本はドキュメントに従っていきます。

$ cd ./src-tauri
$ cargo add specta@=2.0.0-rc.20
$ cargo add specta-typescript@0.0.7
$ cargo add tauri-specta@=2.0.0-rc.20 --features derive,typescript

これでtauri-spectaとそれに必要なspectaspecta-typescriptがインストールされます。

使ってみる

TauriのRust側のコードはsrc-tauri/src/lib.rsに書かれています。

多分何も触ってなかったらこんな感じなのかな?

src-tauri/src/lib.rs
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_shell::init())
        .invoke_handler(tauri::generate_handler![greet])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

このgreet関数が、フロントエンドから呼び出されるコマンドなのは、だいぶ前に紹介しましたね。
まずはこの関数に新しいマクロとしてspecta::spectaを追加してみましょう。

src-tauri/src/lib.rs
#[tauri::command]
#[specta::specta]
fn greet(name: &str) -> String {
    format!("Hello, {}! You've been greeted from Rust!", name)
}

そのうえで、run関数の中でコマンドをなんか色々する処理を書きましょう。
全部でこんな感じです。

src-tauri/src/lib.rs
+ use specta_typescript::Typescript;
+ use tauri_specta;
  
  #[tauri::command]
+ #[specta::specta]
  fn greet(name: &str) -> String {
      format!("Hello, {}! You've been greeted from Rust!", name)
  }
  
  #[cfg_attr(mobile, tauri::mobile_entry_point)]
  pub fn run() {
+     let builder =
+         tauri_specta::Builder::<tauri::Wry>::new().commands(tauri_specta::collect_commands![greet]);
  
+     builder
+         .export(Typescript::default(), "../src/binding.ts")
+         .expect("failed to export typescript bindings");
  
      tauri::Builder::default()
          .plugin(tauri_plugin_shell::init())
-         .invoke_handler(tauri::generate_handler![greet])
+         .invoke_handler(builder.invoke_handler())
          .run(tauri::generate_context!())
          .expect("error while running tauri application");
}

これで、Tauri起動時に../src/binding.tsに TypeScript の型定義とかが書き出されるようになります。
(src-tauriからの相対パスなので、../がついている)

まぁまずはpnpm tauri devでTauriを起動してみましょう。
起動したら閉じても大丈夫です。

そうすると/src/binding.tsに TypeScript の型定義が書き出されているはずです。

/src/binding.ts
...

export const commands = {
async greet(name: string) : Promise<string> {
    return await TAURI_INVOKE("greet", { name });
}
}

...

大事なのはここですかね。

commandsの中で、Rustで定義したgreet関数があります。
中身はもちろんinvokeで呼び出しているのですが、関数に型などもついているので、TypeScript から呼び出すときに便利ですよね。

実際にこれを使うときは、こんな感じです。

import { commands } from "../binding.ts";

console.log(await commands.greet("Anonymouse"));

commandsをimportして、greet関数を呼び出しています。

ちなみに、RustにはResultという型がありますが、これもしっかり再現出来るようになっており、
TypeScriptではbinding.ts内にResult<T, E>という型が定義されています。

Resultstatusというプロパティがokerrorかで、okの場合はdataにTが入り、errorの場合はerrorにEが入ります。

というわけで、tauri-spectaを使ってみると、Rustのコマンドを簡単にフロントエンドから呼び出すことが出来るようになります。

コード紹介は?

しないのよ~

セキュリティ上の制限が突破された今、Rustでファイルを扱うコードについては普通に調べれば出てきちゃうので、省略します。
タイルのリストをコマンドに渡して後はそれをシリアライズしてファイルに書き込むとか、そういう感じですね。
特定のキーを押したときにそれを発動させればもう完璧ですもんね。

次回は、記事冒頭で紹介したようなプラグインと呼ばれるやつをいろいろ紹介してみたいと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?