clusterのベータScriptで外部通信をするサンプル
clusterのベータScriptで外部通信
2023/12/19、ついにclusterでPOST通信が出来るようになりました。
そういうわけで早速使ってみました
分かる人向けの記事です
諸注意
・β機能です。正式版で仕様がかわる可能性があります
・サーバーサイドが分かる方向けです
・clusterのScriptもある程度わかる方向けです
・急いで作ったのでいろいろ汚いです
・非公式です
出来たモノ
Unity側の構成
まずはβ機能をオンにします
次に、呼び出すAPIのURLを登録します。
登録するとトークンが表示されるので、メモっておきましょう
オブジェクトを追加していく
アイテム全体のオブジェクトを作ります。
AddComponentでScriptable Itemを作成して、Source Code Assetsにjavascriptをドラッグ&ドロップします。このjavascriptについては次で書きます
そうしたら今作ったスロットの下にCreate Emptyします。
TextViewという名前(何でも良いがscript側の名前と合わせる必要がある)にして、さらにAdd ComponentからText Viewを追加します
Script
Source Code AssetsにD&Dするjavascriptは下記になります。
verifyTokenのところは、さっき登録した時にメモったモノを入れてください
const textView = $.subNode("TextView"); // 子オブジェクトのTextViewを取得
const verifyToken = "xxxxxxxxxxxx";
const reloadTime = 20; //20秒に1回自動更新
let playerName;
let reloadTimeCount = 1;
$.onInteract(player => {
player.requestTextInput("掲示板", "呟く");
playerName = player.userDisplayName;
});
$.onTextInput((text, meta, status) => {
switch(status) {
case TextInputStatus.Success:
param = {
"verifyToken": verifyToken,
"name": playerName,
"text": text
};
$.callExternal(JSON.stringify(param), "board");
break;
case TextInputStatus.Busy:
// 5秒後にretryする
$.state.should_retry = true;
$.state.retry_timer = 5;
break;
case TextInputStatus.Refused:
// 拒否された場合は諦める
$.state.should_retry = false;
break;
}
});
$.onExternalCallEnd((response, meta, errorReason) => {
let responseForJson = response.slice(1).slice(0, -1);
boardContent = JSON.parse(responseForJson);
renderText = "";
boardContent.forEach(element => {
renderText += element["n"]+" ("+ element["p"] +")"+"\n";
renderText += element["t"]+"\n";
renderText += "\n";
});
//表示テキストを更新
textView.setText(renderText);
reloadTimeCount = reloadTime;
});
//自動更新
$.onUpdate(deltaTime => {
reloadTimeCount = reloadTimeCount - deltaTime;
if (reloadTimeCount < 0.0) {
param = {
"verifyToken": verifyToken,
};
$.callExternal(JSON.stringify(param), "board");
reloadTimeCount = reloadTime;
}
});
サーバー側
次にサーバー側なんですが、今回はlaravelで書きました。
ちょっと説明がむずいのでcallbackの値だけ示しておきます。
(ソースコード自体はこちらです https://github.com/ginjake/clusterPost)
{
"verify": "xxxxxxxxx",
"response": "'[{\"n\":\"\\u9280\\u9bad\",\"t\":\"\\u3042\\u3042\\u3042\\u3042\",\"p\":\"cluster\"},{\"n\":\"\\u9280\\u9bad\",\"t\":\"\\u3042\\u3042\\u3042\\u3042\",\"p\":\"cluster\"},{\"n\":\"ginjake\",\"t\":\"aaaaa\",\"p\":\"resonite\"},{\"n\":\"\\u9280\\u9bad\",\"t\":\"\\u3066\\uff53\\uff54\\u3066\\uff53\\uff54\",\"p\":\"cluster\"},{\"n\":\"\\u9280\\u9bad\",\"t\":\"\\u3066\\uff53\\uff54\",\"p\":\"cluster\"}]'"
}
ここで大事なのが2点。
・verifyをcallbackのレスポンスに含める必要がある。
ここのverifyはAPIのURLを登録した時にメモったモノです。
ここが違うと失敗します
・responseの中に入れるのは文字列だけ
jsonを返そうとすると失敗します。そのためjsonの前後に`をつけて文字列に、script側で取り除く処理をしています
以上です
その他
・可能なのはPOST通信のみ。
さらに、通信できるURLは1アカウントにより1つ。
(新規にURLを登録しなおしても、前のは生きてるという情報もある)
今回は掲示板の更新と投稿で2つのAPIが欲しかったが、
分けることが出来ないのでrequestのパラメータを見て処理を分けてる。
多分$.callExternalの第二引数metaで、そのへんの振り分けをするのが良さそう
・送受信できる値は文字列のみ。jsonをそのまま送れない
・サーバーと送受信できるデータのサイズは 1kB以下となります。(公式より)
・callExternal は 1アイテムにつき、5回/分 まで実行できます(公式より)
参考になった資料
テキスト入力
テキスト出力
TextViewコンポーネント
callExternal
onExternalCallEnd
SubNode
追記
実際には排他処理が必要です
思いつく限りでは
・APIのコール上限数に達した場合の処理
・送信コメントに文字数上限をつける
・受信時に1kbを超えた場合の処理
また、onInteractのPlayer名を取得してる部分でも
複数ユーザーが同時にInteractした場合を考慮してないので
そのあたりの検証や考慮が必要だと思います
Discussion