ハイパーマッスルエンジニア

Vim、ShellScriptについてよく書く

Gather TownのWebSocket APIで入室時にslackに通知するようにした

 

バーチャルオフィス「Gather」ではWebSocketAPIがあり、

  • プレイヤー入退出のイベント
  • プレイヤーをテレポートさせる
  • プレイヤーのアバターを着せ替える

など自由度の高いAPIが多く用意されている。

これらのAPIを使って

  • 紙吹雪でプレイヤー吹き飛ばし
  • プレイヤー入退出時にslack通知
  • ゴーストモードで障害物すり抜け

を実装したリポジトリがこちら。

github.com

この記事ではGatherAPIを試せる最小の構成を解説していく。

環境

$ node -v
v16.10.0

nodeのv16.10.0環境が必要

ディレクトリ構成

$ tree
.
├── index.ts
├── package.json
└── tsconfig.json

package.json

必要なパッケージは@gathertown/gather-game-clientisomorphic-wsのみ。
package.json

{
  "name": "gather-api",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "node -r ts-node/register index.ts"
  },
  "devDependencies": {
    "ts-node": "^10.7.0",
    "typescript": "^4.6.2"
  },
  "dependencies": {
    "@gathertown/gather-game-client": "^38.0.1",
    "isomorphic-ws": "^4.0.1",
    "ws": "^8.2.1"
  }
}

とりあえずこれをコピペしてパッケージをインストールする

# パッケージインストール
$ yarn

tsconfig.json

Typescrtiptで書きたいので用意。

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "noEmit": false,
    "strict": true,
    "outDir": "./dist/",
    "sourceMap": true,
    "skipLibCheck": true
  },
  "exclude": ["node_modules"],
  "include": ["**/*.ts"]
}

index.ts

GatherAPIを利用する最小のソースコード

index.ts

import { Game } from "@gathertown/gather-game-client";
global.WebSocket = require("isomorphic-ws");

const GATHER_API_KEY = "YOUR_API_KEY";
const GATHER_SPACE_ID = "YOUR_SPACE\YOUR_SPACE_NAME";

const gather = new Game(GATHER_SPACE_ID, () =>
  Promise.resolve({ apiKey: GATHER_API_KEY })
);
gather.connect();

gather.subscribeToConnection((connected) => {
  console.log({ connected });
});

API_KEYやSPACE_IDは環境変数にするなどしてください。API_KEYとSPACE_IDの取得方法は次に記載します。

API KEYの取得

https://app.gather.town/apikeys

注意したいのは上のエンコードされた方ではなく、下の短い方がAPI KEYをコピーする

エンコードされたほうをAPI KEYとして入力すると下記のように接続はできるがすぐにUnauthorized: no uid foundエラーとなってしまう。

yarn run v1.22.17
$ node -r ts-node/register src/app.ts
connecting to SefvUrOwU9Omhw32\my_test_space
{ connected: true }
connection closed because user does not have access: Unauthorized: no uid found
t: 1876 : destroying connection
{ connected: false }

SPACE_ID の取得

ブラウザで開いたときの URL から取得できます。例えば下記のような URL の場合、
https://app.gather.town/app/SefvUrOwU9Omhw32/my_test_space

const GATHER_SPACE_ID='SefvUrOwU9Omhw32\my_test_space'

となる。スペース名の前の/\になることに注意。

空白を含むスペース名の場合は下記のようになる。
https://app.gather.town/app/SefvUrOwU9Omhw32/my%20test%20space

const GATHER_SPACE_ID='SefvUrOwU9Omhw32\my test space'

実行

API_KEYとSPACE_IDをindex.tsにコピペしたら下記コマンドで実行。

$ yarn dev

# yarn run v1.22.17
# warning package.json: No license field
# $ node -r ts-node/register index.ts
# connecting to PQKGZv1KxEzPzTG0\tanaka_test
# { connected: true }
# [warn from gs] event playerSetsStatus will soon be deprecated
# [warn from gs] event mapSetWalls will soon be deprecated
# [warn from gs] event mapSetFloors will soon be deprecated
# [warn from gs] event playerSetsWorkCondition will soon be deprecated
# [warn from gs] Invalid subscriptions mapSetCollisions,playerSetsCurrentDesk

{ connected: true }と出たら成功。下記のようなエラーが出たらSPACE_IDが間違っている可能性が高い。

$ yarn dev
#failed to fetch gameserver assignment: Invalid request to fetch game server assignment, {"message":"Request failed with status code 400","name":"Error","stack":"Error: Request failed with status code 400\n    at createError (/Users/me/Desktop/gather/node_modules/axios/lib/core/createError.js:16:15)\n    at settle (/Users/me
#t: 654 : destroying connection

プレイヤーの動きを検知する

index.tsに下記コードを追加することでプレイヤーが動きを検知できる。

import { Game } from "@gathertown/gather-game-client";
global.WebSocket = require("isomorphic-ws");

const GATHER_API_KEY = "Q4yoAawt8oHAsaG5";
const GATHER_SPACE_ID = "PQKGZv1KxEzPzTG0\tanaka_test";

const gather = new Game(GATHER_SPACE_ID, () =>
  Promise.resolve({ apiKey: GATHER_API_KEY })
);
gather.connect();

gather.subscribeToConnection((connected) => {
  console.log({ connected });

+  gather.subscribeToEvent("playerMoves", async (data, context) => {
+    console.log(context);
+  });
});

contextに動いたプレイヤーの情報が入ってくる。
このようにgather.subscribeToEvent("イベント名")で様々なイベントを検知できる。他のイベントを探す方法は定義ファイル/node_modules/@gathertown/gather-game-client/dist/src/Game.d.tsから辿っていくか、もしくはブラウザのコンソールから確認できる。
ブラウザのコンソールの確認方法は、まずGatherを開きコンソールタブでgameと入力する。

コンソールでgameと入力する

するとGameインスタンスの情報が見れるので、その中のeventSubscriptionsに全イベントが記載されている。なんのイベントかはイベント名から推測したり、ソースコードの中の処理をみながら確かめていく。
ブラウザのコンソールはメソッドを試すのに便利で、例えば/node_modules/@gathertown/gather-game-client/dist/src/Game.d.tsに定義されているメソッド

teleport(mapId: string, x: number, y: number, targetId?: string, direction?: SpriteDirection): void;

を試したいとする。
名前から推測するにおそらくプレイヤーをテレポートさせるメソッドで、必要な引数はmapId,x座標, y座標だ。(他の引数はオプショナルになっているので必須ではない)。
mapIdgame.partialMapsから取得ができる。

mapIdを取得するためにgame.partialMapsと入力

mapIdが取得できたらteleport()をコンソールで試してみる。

teleportをいざ実行
game.teleport("office-main", 10, 20)と入力し、実行

テレポートできた!

様々なメソッド、イベントが用意されている

このようにGame.d.tsを見ると様々なメソッド、イベントが用意されている。GatherAPIはドキュメントが少ないが、ソースコードにすべて書いてあるので裏技を見つける感覚でいくと楽しい。
今回の記事では紹介しなかったが、リポジトリの方では「プレイヤーの入退出時にSlackで通知する」などもやっているので興味がある方は見ていただきたい。

github.com

参考