みらくるすいーぱーのSTEAM版での実績を導入した時の方法を備忘録として残そうと思ったので、
残しておきます。
環境
Visual Studio Code ver1.74.2 ・・・ここはそんなに影響はないと思う
electorn ver19.0.0-nightly.20220202
greanworks v97
steamworks SDK v1.55
そんなに頻繁に仕組みが変わるところでもないと思うので、バージョンが大きく違うとかじゃなければ、多少のバージョン違いは対応できると思います。
実装方法 メインプロセス側
実績部分の説明なので、基本の実装は、本家等のドキュメントを確認してください。
https://github.com/greenheartgames/greenworks/tree/master/docs#api-references
https://ics.media/entry/7298/
一応、ここのサイト参考にelectronのベースを作ってます。

electronの参考サイトでの createWindow(); の直前に上記のソースを記述。
initのエラー処理部分省いてますが、initが成功した直後にstoreStatsを呼び出します。
steamworks SDKでは、一度ローカルで実績等のデータをため込む機能があり、
起動時にため込んだデータをサーバーに反映させる処理を行う必要があります。
その後、storeStats内部で初期化が行われ、Stats関係の処理が有効になります。
次にゲーム(レンダラープロセス)部分から実績の反映方法。

appとBrowserWindowは、electronの基礎部分なので、ここでは省略
今回重要なのはipcMain。
簡単に言うと、ゲーム(レンダラープロセス)部分からは、greenworksのオブジェクトにアクセスすることができないので、メインプロセスとレンダラープロセスでデータをやり取りするために使用します。

前準備。
ipcMain.on は返り値なし、ipcMain.handle は返り値あり。
文字列として引数に渡している”setStat”とかは、関数起動のためのイベント名なので、
なんでも良いけど、わかりにくくなるのでgreenworksの関数名と同じにしています。
dat はゲーム部分から渡される引数(厳密には後述のipcRendererから渡される引数)。
注意点は greenworks.storeStats( ); の呼び出し。
setStatはローカルだけで済み非常に軽い処理なので、頻繁に呼び出すというような事も可能になっています。
ですが、storeStatsは通信を伴うため、頻繁に呼び出すことは禁止されています。
みらくるすいーぱーでは、Statがたまに(ゲームクリア時のみ)しか更新されないため、Statを変更するたびにstoreStatsを呼び出しています、ここはゲーム仕様によってはstoreStatsとsetStatを分けた方が良いでしょう。
greenworksの各関数の詳細は、公式ドキュメント参照。
preload.js側の対応

そしてもう一つ、BrowserWindow生成時に渡しているpreload.jsのファイル。

注 2023/1/29 追記 invoke回りの使い方ミスっていたので画像変更しました
今回、一番の肝と言ってもいい部分。
contextBridge は、レンダラープロセス(メインワールド)から呼びだされる関数を定義できる物です、これを使用することで、レンダラープロセスとpreload.jsでのやり取りを行う事ができるようになります。
ipcRendererは、ipcMainの対になるもので、セットで使うことで、preload.jsとmain.jsでやり取りを行う事ができるようになります。
レンダラープロセス ⇔ preload.js ⇔ メインプロセス
とpreload.jsを経由することでレンダラープロセスとメインプロセスのやり取りが可能になります。
”greenworks”は、レンダラープロセス上のオブジェクト名、文字列はなんでも良いけど、わかりやすくgreenworksに。
そしてゲーム部分(レンダラープロセス)から呼びだされる関数を定義し、
各関数の中でipcRendererを使用してメインプロセスへイベントを発火します。
ipcMain.on ipcRenderer.send が対応していて、メインプロセスへイベントを通知するだけの処理。
ipcMain.handle ipcRenderer.invoke が対応していて、メインプロセスへイベントを通知した後その返り値を受け取ります。
2023/1/29 追記
invoke がPromissの関数で即時値を得られるものではなかったため、
async await を追加しています。
ipcRendererから渡しているデータの名称は適当に命名しているので、ipcMainの受け取りと一致していればなんでも構いません。
これで、前準備は終了。
ゲーム部分の実装

ここまで来てしまえば、だいたい完了していてあと少しです。
みらくるすいーぱーのネタクリア時のソースを元に説明。
最初に、”stat_ach_neta” はsteamworksのデベロッパサイトでの データ設定 でのAPI名です。
設定はゲーム側から更新するので Client にしましょう。
”ACH_NETA_CLEAR” は同じくデベロッパサイトの 実績の設定 のAPI名です。
進行状況の箇所に対応するデータAPIの設定と、設定も Clientにしましょう。
さて、ソースに戻りまして、
window はグローバルの定義、ここでの greenworks のオブジェクトは、preload.jsのcontextBridgeで定義したもので、各関数もそこで定義したものになります。
declare var greenworks:any;
をどこかグローバルで定義するとbuild時にエラーが出なくなります。
最初にsetStatを呼び出します。
今回は1で達成した前提ですが、10個集めるとか数が必要であれば、ここで途中経過の数も指定します。
次にgetAchievemeを呼び出し実績が終わっているかどうかを確認し、未達成の場合だけ次の処理を行います。
indicateAchievementProgress は実績の途中経過の設定。
※steamSDKのドキュメントだと、setStatの値を使うともあったので呼ばなくても良い?ちょっとこれは現状未確認。
activateAchievement で最終的な実績の解放になります。
途中経過だけの更新で実績未達成なら、この関数だけ呼ばないようにすれば大丈夫です。
何か自分が忘れてなければこれで実績が解放されるはず。
なんだかんだ、情報集めるのに、3日ぐらい悩んでた気がする、、、。
コメント