Minecraft The HIVE PlayHIVE API を GASで呼び出す

# やってみたこと

マイクラのHIVEっていうゲーム（サーバ）がありますが、各種情報がとれるようにAPIが公開されています。
APIを叩くとJSONで返ってくるので、WEBで表示するプログラムをGASで作ってみました。

# Swagger

下記にAPIが公開されています。
ゲーム名やゲーマータグを入れればJSONが見えるので、わざわざ作る必要もないっちゃないのですが、GASをたまに作らないと忘れちゃうので作ってみました。

https://api.playhive.com/api/documentation?ref=support.playhive.com#/default

# 設計

GASでWEB画面を2つ作ることにしました。
* API呼び出し＆結果表示画面
* 入力画面

# API呼び出し＆結果表示用 Google Spread Sheet

まず、入力画面用のGASを書くために、スプレッドシートを作りました。
さらにいうと、今回はレベル計算をしたかったのでデータベース代わりにしています。

下記に自分のXPからレベルを出す表があるので、この表をスプレッドシートにコピペして、ウニョウニョ編集して、テーブル化しました。

https://support.playhive.com/level-based-unlocks/

![スクリーンショット 2024-01-04 19.19.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/030786d8-77a2-17c3-4aef-ae7d004109a8.png)

↓↓↓↓↓　こんな感じで・・

![スクリーンショット 2024-01-04 19.22.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/c678dd5f-f987-0953-c85f-40ecb6cf0e76.png)

## 取得できるJSONの確認

前記のSwaggerで全部のデータのJSONを取得してみて、このスプレッドシートにコピペして、内容を調べました。


## コード.gs

doGetでHTMLServiceを使います。
上記で調べた内容も反映します。このときも、スプレッドシートで関数を使って、GASのコードを生成しちゃえば、エディタでコピペするより簡単ですね。

例えば、
``html.activated = jsonData['activated'];``
だったら、A列に内容を並べておいて、
``="html."&A1&" = jsonData['"&A1&"'];"``
ってやれば、コードがスプレッドシート上で一発で完成！
なにげに、スプレッドシート＋GASの組み合わせって便利ですね。

### API仕様

doGet(e)　の e にパラメータで入れられますので、今回は下記な感じになります。
```
  var gamename = encodeURI(e.parameter.gamename);
  var gamertag = encodeURI(e.parameter.gamertag);
  var targetperiod = encodeURI(e.parameter.targetperiod);
```

PlayHIVE APIのURLを下記のように生成します。

全期間の場合：
``https://api.playhive.com/v0/game/all/[gamename]/[gamertag]``

月間の場合；
``https://api.playhive.com/v0/game/monthly/player/[gamename]/[gamertag]``


### APIはfetchで呼ぶ

```
  response = UrlFetchApp.fetch(url);
  responseCode = response.getResponseCode()
```
response にAPIの呼び出し結果が帰ってきます。

### JSON を Parse

```
jsonData = JSON.parse(response);
xp = jsonData['xp'];
```
これで、response内のJSONをperseしてくれて、値がとれるんです。
なんて便利なの！！　GAS！

### HTMLService

```
html = HtmlService.createTemplateFromFile("index");
```
これで、 ``index.html``と doGetを紐づけます。

htmlオブジェクトにとりあえず、全部の値をいれちゃいましょー。

```
例）
 html.xp = jsonData['xp'];
```
最後に下記でHTML化します。
ところで、Metaタグは、最初index.htmlに書いたんですが、反映されず、ググったところ、ここに書かないといけないという先人からの情報があり、ここに入れています。
```
  const htmlOutput = html.evaluate();
  htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
  return htmlOutput;
```


### レベルの計算
スプレッドシートの内容を、一旦data配列に読み込んじゃいます、
```
const sheet = SpreadsheetApp.getActive().getSheetByName('level');
const lastRow = sheet.getLastRow();
const lastColumn = sheet.getLastColumn();

data = sheet.getDataRange().getValues();
```
で、面倒なんで、なめちゃいました。
```
  lv=0;
  for(i=0;i<lastRow;i++) {
    if (data[i][0]==gamename) if (xp > data[i][1]) lv = data[i][2];
  }
  return lv;
```
でも、ほんとに、GAS便利だなぁ・・

### というわけで、「コード.gs」の完成です。

```
function doGet(e) {
  var gamename = encodeURI(e.parameter.gamename);
  var gamertag = encodeURI(e.parameter.gamertag);
  var targetperiod = encodeURI(e.parameter.targetperiod);

  url = "https://api.playhive.com/v0/game/all/"+gamename+"/"+gamertag; // デフォルトは「All（全期間）」
  if (targetperiod=="monthly")  url = "https://api.playhive.com/v0/game/monthly/player/"+gamename+"/"+gamertag; // 「monthly（月間）」

  response = UrlFetchApp.fetch(url);
  responseCode = response.getResponseCode()

  if (responseCode != 200) {
    return -1;
  }

  jsonData = JSON.parse(response);

  html = HtmlService.createTemplateFromFile("index");

  html.gamename = gamename;
  html.targetperiod = targetperiod;

  html.activated = jsonData['activated'];
  html.assists = jsonData['assists'];
  html.blocks_destroyed = jsonData['blocks_destroyed'];
  html.blocks_placed = jsonData['blocks_placed'];
  html.checkpoints = jsonData['checkpoints'];
  html.coins = jsonData['coins'];
  html.cows = jsonData['cows'];
  html.crates = jsonData['crates'];
  html.deathmatches = jsonData['deathmatches'];
  html.deaths = jsonData['deaths'];
  html.final_kills = jsonData['final_kills'];
  html.flags_captured = jsonData['flags_captured'];
  html.flags_returned = jsonData['flags_returned'];
  html.human_index = jsonData['human_index'];
  html.index = jsonData['index'];
  html.kills = jsonData['kills'];
  html.m_solo_deaths = jsonData['m_solo_deaths'];
  html.m_solo_goals = jsonData['m_solo_goals'];
  html.m_solo_kills = jsonData['m_solo_kills'];
  html.m_solo_played = jsonData['m_solo_played'];
  html.m_solo_victories = jsonData['m_solo_victories'];
  html.maps_completed = jsonData['maps_completed'];
  html.maps_completed_without_dying = jsonData['maps_completed_without_dying'];
  html.murderer_eliminations = jsonData['murderer_eliminations'];
  html.murders = jsonData['murders'];
  html.mystery_chests_destroyed = jsonData['mystery_chests_destroyed'];
  html.ores_mined = jsonData['ores_mined'];
  html.played = jsonData['played'];
  html.powerups_collected = jsonData['powerups_collected'];
  html.prestige = jsonData['prestige'];
  html.projectiles_fired = jsonData['projectiles_fired'];
  html.rating_good_received = jsonData['rating_good_received'];
  html.rounds_survived = jsonData['rounds_survived'];
  html.spells_used = jsonData['spells_used'];
  html.treasure_destroyed = jsonData['treasure_destroyed'];
  html.uncapped_xp = jsonData['uncapped_xp'];
  html.victories = jsonData['victories'];
  html.username = jsonData['username'];
  html.xp = jsonData['xp'];
  html.lv =getLevel(gamename,jsonData['xp']);

  const htmlOutput = html.evaluate();
  htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
  htmlOutput.setTitle("The HIVE Ranking");
  htmlOutput.setFaviconUrl("https://support.playhive.com/content/images/size/w256h256/2021/11/favicontest.png");
  return htmlOutput;
}

function getLevel(gamename,xp) {
  const sheet = SpreadsheetApp.getActive().getSheetByName('level');
  const lastRow = sheet.getLastRow();
  const lastColumn = sheet.getLastColumn();

  data = sheet.getDataRange().getValues();
  lv=0;
  for(i=0;i<lastRow;i++) {
    if (data[i][0]==gamename) if (xp > data[i][1]) lv = data[i][2];
  }
  return lv;
}
```

## index.html の作成
App Script の画面のファイルのところの「＋」を押すと、「HTML」があるので、選びます。「index」と入れて、「index.html」を書きます。
内容的には、PlayHIVEのAPIで取得した内容を表で表示しているだけです。
ちなみに、
``<?=gamename ?>`` みたいに書くと、「コード.gs」で、htmlオブジェクトに埋め込んだ内容が取り出せます。

```
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile("css").getContent(); ?>
  </head>
  <body>
    <div>
      <img src="https://support.playhive.com/content/images/2021/11/Hive---Yellow---Small.png" style="display: block; margin: auto;" />
    </div>
    <br>
    <div>
    <table>
      <tbody>
      <tr><td>　GameName　</td><td>　<?=gamename ?>　</td></tr>
      <tr><td>　UserName</td><td>　<?=username ?>　</td></tr>
      <tr></tr>
      <tr><td>　Prestige　</td><td>　<?=prestige ?>　</td></tr>
      <tr><td>　Level　</td><td>　<?=lv ?>　</td></tr>
      <tr><td>　Ranking　</td><td>　<?=human_index ?>　</td></tr>
      </tbody>
    </table>
    <br><br>
    </div>
  </body>
</html>
```

### css.html の作成
せっかくなので、cssも作ります。
App Script の画面のファイルのところの「＋」を押すと、「HTML」があるので、選びます。「css」と入れて、「css.html」を書きます。

「index.html」に、
```
<?!= HtmlService.createHtmlOutputFromFile("css").getContent(); ?>
```
を書くことで、cssのファイルも読み込みます。
cssの詳細は省略します。

```
<style>
  body {
     background-image: url(https://いい感じの背景画像ーほげほげ.jpg);
     background-size: cover;
     color: white;
     font-size: x-large;
     font-family: "Arial Black","ヒラギノ角ゴ ProN W3", HiraKakuProN-W3, 游ゴシック, "Yu Gothic", メイリオ, Meiryo, Verdana, Helvetica, Arial, sans-serif;
  }
  table {
    margin: auto;
    border-collapse: collapse;
  }
  th, td {
    border: solid 2px white;
  }
</style>
```

## デプロイ
画面右上のほうの「デプロイ」→「新規デプロイ」でデプロイします。
一応、これでAPI部分は完成。

### 補足
GASの画面構成が変わってわかってなかったのですが、下記画像のように「デプロイの管理」からデプロイすれば、URLを固定できるようです。めでたしめでたし。
![スクリーンショット 2024-01-05 11.36.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/f1346dbc-a6e9-ba5c-0df8-e07eb71c4066.png)


# 入力画面用 Google Spread Sheet
入力画面もGASで作っちゃいましょう。
WEBサーバを準備しないでよいので、便利です、URLは長いですが・・

## コード.js
HTML化するだけなので、簡単です。

```
function doGet(e) {
  html = HtmlService.createTemplateFromFile("index");
  const htmlOutput = html.evaluate();
  htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
  htmlOutput.setTitle("The HIVE Player Profile");
  htmlOutput.setFaviconUrl("https://support.playhive.com/content/images/size/w256h256/2021/11/favicontest.png");
  return htmlOutput;
}
```

## index.html
入力画面を作ります。ありがちなコードを書いて、GETで、API部分のデプロイ後のURLを書けばOK

```
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile("css").getContent(); ?>
  </head>
  <body>
    <div>
      <img src="https://support.playhive.com/content/images/2021/11/Hive---Yellow---Small.png" style="display: block; margin: auto;" />
    </div>
    <br>
    <div>
    <table>
      <tbody>
      <tr><td>　Please input your info　</td></tr>
      </tbody>
    </table>
    </div>
    <div>
    <form action="さっきデプロイしたGASのURL" method="get">
    <table>
      <tbody>
      <tr><td>
        <p>Game Name :
          <select name=gamename>
            <option value=sky>SKY</option>
            <option value=wars>Wars</option>
            <option value=murder>Murder</option>
            <option value=grav>Grav</option>
            <option value=party>Party</option>
            <option value=drop>Drop</option>
            <option value=dr>DR</option>
            <option value=hide>Hide</option>
            <option value=sg>SG</option>
            <option value=ctf>CTF</option>
            <option value=ground>Ground</option>
            <option value=bridge>Bridge</option>
            <option value=build>Build</option>
          </select>
        </p>
        <p>Gamer Tag :
          <input type="text" name=gamertag>
        </p>
        <p> Target Period:
          <select name=targetperiod>
            <option value=all>ALL</option>
            <option value=monthly>Monthly</option>
        </p>
      </td></tr>
      <tr><td>
        <input type="submit" value="Submit">
      </td></tr>
      </tbody>
    </table>
    </div>
    </form>    
  </body>
</html>
```
「css.html」は、API部分と同じです。

## デプロイ
画面右上のほうの「デプロイ」→「新規デプロイ」でデプロイします。２回目からは「デプロイの管理」で。
一応、これで入力画面部分も完成。

# 完成スクショ
下記な感じです。
（ゲーマータグはリーダーボードの乗っている方のゲーマータグをお借りしました。）
ちなみに、GASでHTML化すると、こんなメッセージがヘッダーにでます。

![スクリーンショット 2024-01-04 20.46.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/d96eb416-1288-2a1b-6296-f845e3cf3791.png)

↓

![スクリーンショット 2024-01-04 20.46.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186659/a0d8033d-8e51-cf88-7f0e-cd10568fcf9a.png)

なんか、バグってるかも・・
まぁ。いいか・・