今日『アークナイツ:エンドフィールド』が正式にサービス開始となりました。少しプレイした後、ガチャデータをガチャ分析アプリに取り込みたいと思いました。しかし、ゲームがリリースされたばかりのせいか、ガチャデータをエクスポートするツールを探しても見つからず、結局自分で実装するに至りました。この記事では主な考え方を共有します。同じ機能を実装したい方の参考になれば幸いです。
URLに何が含まれているか
まず、他のゲームと同様に、パケットキャプチャツールやより便利な方法[^1]で以下のようなガチャ履歴リンクを取得できます。
https://ef-webview.hypergryph.com/api/record/char?lang=zh-cn&seq_id={seqId}&pool_type={poolType}&token={token}&server_id={serverId}

ガチャ履歴リンク
キャラクターピックアップ
キャラクターピックアップでは、主に pool_type と seq_id の2つのパラメータに注目します。
pool_type はガチャの種類を示す列挙値で、現在は以下のいずれかを指定できます。
- 旅立ちガチャ(初心者ガチャ):
E_CharacterGachaPoolType_Beginner - 基本ガチャ(常設ガチャ):
E_CharacterGachaPoolType_Standard - 限定ガチャ(期間限定ガチャ):
E_CharacterGachaPoolType_Special
また、原神や鳴潮などのゲームとは異なり、エンドフィールドのガチャ履歴リンクには通常 seq_id パラメータが付いています。
// seq_id=26&pool_type=E_CharacterGachaPoolType_Standard
{
"code": 0,
"data": {
"list": [
//...
{
"poolId": "standard",
"poolName": "基礎ガチャ",
"charId": "chr_0019_karin",
"charName": "秋栗",
"rarity": 4,
"isFree": false,
"isNew": false,
"gachaTs": "1769073164712",
"seqId": "21"
}
],
"hasMore": false
},
"msg": ""
}
// pool_type=E_CharacterGachaPoolType_Beginner
{
"code": 0,
"data": {
"list": [
{
"poolId": "beginner",
"poolName": "旅立ちガチャ",
"charId": "chr_0022_bounda",
"charName": "蛍石",
"rarity": 4,
"isFree": false,
"isNew": false,
"gachaTs": "1769072324787",
"seqId": "20" //このガチャの最新の履歴
},
// ...
],
"hasMore": true
},
"msg": ""
}
上記の2つの異なるガチャの履歴を見ると、seq_id パラメータの特徴がいくつかわかります。
seq_id (seqId)は アカウント単位の、サブガチャをまたいだ、ガチャ種別ごとに独立した 通し番号であり、キャラクターガチャ全種の履歴は同じseq_id (seqId)の系列を共有します。一方、武器ガチャの履歴は別のseq_id (seqId)の系列を共有します。同じガチャ種別(キャラクターガチャ全種または武器ガチャ全種)内であれば、サブガチャを切り替えてもseq_id (seqId)がリセットされることはありません。seq_id (seqId)の数字が大きいほど、時間的に新しい、つまりデータが新しいことを意味します。- リクエストURLに
seq_idパラメータを含めない場合、そのガチャの最新の5件(つまりseqIdが最大の5件)が返されます。
これらの特徴から、ゲーム内のガチャ履歴表示ページで1ページ目から順にめくっていく(新しい履歴から古い履歴へ)過程は、ガチャ履歴リンクの seq_id パラメータが減少していく過程と同じであることがわかります。
リンクが返すガチャ履歴には、hasMore パラメータも含まれています。これは、現在の返却結果の最小 seqId より下にまだデータがあるかどうかを示し、次のページに進めるかどうかを反映しています。
武器ガチャ
武器ガチャのAPIはキャラクターガチャとは異なります。武器ガチャのデータを取得するには、2つのAPIを呼び出す必要があります。
武器ガチャのリストを取得する
まず、以下のリンクでユーザーの履歴が存在する武器ガチャのリストを取得します。
https://ef-webview.hypergryph.com/api/record/weapon/pool?lang=zh-cn&token={token}&server_id={serverId}
返されるデータ構造は以下の通りです。
{
"code": 0,
"data": [
{ "poolId": "weponbox_1_0_1", "poolName": "鋳造ガチャ" },
{ "poolId": "weaponbox_constant_2", "poolName": "星声ガチャ" }
// ...
],
"msg": ""
}
ここで、武器ガチャは2つのタイプに分かれていることがわかります。
- 武器限定ガチャ:
poolIdの形式がweponbox_*(例:weponbox_1_0_1)で、期間中のピックアップ武器に対応します - 武器常設ガチャ:
poolIdの形式がweaponbox_constant_*(例:weaponbox_constant_2)です
余談ですが、武器限定ガチャの
poolIdのプレフィックスがweponとスペルミスされているのが面白いですね。歴史的な遺産かもしれません。
武器ガチャの履歴を取得する
特定の武器ガチャの履歴を取得するリンクは、キャラクターガチャの履歴リンクとは形式が異なります。武器ガチャの履歴リンクでは、pool_type パラメータの代わりに pool_id パラメータを使用します。
https://ef-webview.hypergryph.com/api/record/weapon?lang=zh-cn&seq_id={seqId}&pool_id={poolId}&token={token}&server_id={serverId}
返されるデータ構造は以下の通りです。
{
"code": 0,
"data": {
"list": [
{
"poolId": "weponbox_1_0_1",
"poolName": "鋳造ガチャ",
"weaponId": "wpn_funnel_0010",
"weaponName": "騎士道精神",
"weaponType": "E_WeaponType_Wand",
"rarity": 6,
"isNew": true,
"gachaTs": "1769238381938",
"seqId": "47"
},
// ...
],
"hasMore": true
},
"msg": ""
}
武器の履歴のフィールドはキャラクターの履歴とは少し異なります。
weaponId:武器IDweaponName:武器名weaponType:武器タイプ(E_WeaponType_Sword、E_WeaponType_Wandなど)
武器ガチャの seq_id の特性はキャラクターガチャと同じで、すべての武器サブガチャが同じ seqId の系列を共有します。
これで、『アークナイツ:エンドフィールド』のガチャ履歴リンクの仕組みをほぼ理解できました。
主な考え方
上記の説明に基づいて、有効なエンドフィールドのガチャ履歴リンクが1つあれば、そこからすべてのガチャの全履歴を導き出せます。
キャラクターガチャ
- まず、任意のガチャの
pool_typeを指定し、seq_idを含めずにリクエストを1回送信して、そのガチャの最大seqIdの最新履歴を取得します。 - 次に、返されたデータの最小
seqIdをカーソルとして使用し、そのガチャの全履歴を走査します。サーバー側で履歴が削除されるか、そのガチャの最初のガチャ履歴に到達してhasMore === falseになるまで続けます。 - 別のガチャの
pool_typeに切り替えて、手順1を繰り返します。
武器ガチャ
- まず、武器ガチャリストAPIを呼び出して、ユーザーの履歴が存在する武器ガチャを取得します。
- 各武器ガチャを走査し、
pool_idパラメータを使用して履歴を取得します。 poolIdに基づいてガチャのタイプを判断します。constantを含むものは常設ガチャ、それ以外は限定ガチャです。
コード実装
// キャラクターガチャの履歴を取得
async function fetchCharacterRecords(token: string, serverId: string) {
const poolTypes = [
"E_CharacterGachaPoolType_Beginner",
"E_CharacterGachaPoolType_Standard",
"E_CharacterGachaPoolType_Special",
];
const allRecords = [];
for (const poolType of poolTypes) {
let cursor = null;
let hasMore = true;
while (hasMore) {
const seqIdParam = cursor !== null ? `&seq_id=${cursor}` : "";
const url = `https://ef-webview.hypergryph.com/api/record/char?lang=zh-cn${seqIdParam}&pool_type=${poolType}&token=${encodeURIComponent(token)}&server_id=${serverId}`;
const response = await fetch(url);
const { data } = await response.json();
if (data?.list?.length > 0) {
allRecords.push(...data.list);
hasMore = data.hasMore;
if (hasMore) {
const seqIds = data.list.map(item => Number(item.seqId));
cursor = Math.min(...seqIds);
await new Promise(resolve => setTimeout(resolve, 300));
}
} else {
hasMore = false;
}
}
}
return allRecords;
}
// 武器ガチャの履歴を取得
async function fetchWeaponRecords(token: string, serverId: string) {
const allRecords = [];
const poolListUrl = `https://ef-webview.hypergryph.com/api/record/weapon/pool?lang=zh-cn&token=${encodeURIComponent(token)}&server_id=${serverId}`;
const poolListResponse = await fetch(poolListUrl);
const { data: weaponPools } = await poolListResponse.json();
if (!weaponPools?.length) return allRecords;
for (const pool of weaponPools) {
let cursor = null;
let hasMore = true;
while (hasMore) {
const seqIdParam = cursor !== null ? `&seq_id=${cursor}` : "";
const url = `https://ef-webview.hypergryph.com/api/record/weapon?lang=zh-cn${seqIdParam}&pool_id=${pool.poolId}&token=${token}&server_id=${serverId}`;
const response = await fetch(url);
const { data } = await response.json();
if (data?.list?.length > 0) {
allRecords.push(...data.list);
hasMore = data.hasMore;
if (hasMore) {
const seqIds = data.list.map(item => Number(item.seqId));
cursor = Math.min(...seqIds);
await new Promise(resolve => setTimeout(resolve, 300));
}
} else {
hasMore = false;
}
}
}
return allRecords;
}
これで、『アークナイツ:エンドフィールド』のすべてのガチャの全履歴を取得できるようになりました。
- 1: 『アークナイツ:エンドフィールド』の1.1バージョン以降、HGWebview.log ログファイルにガチャ履歴リンクが記録されなくなり、現在コミュニティの関連スクリプトはすべて機能しなくなっています。ただし、鷹角ネットワークのパスポートなどのページで、ログイン後の loginToken -> oauthToken -> uid -> u8Token を利用して、jsで有効なガチャ履歴リンクをワンクリックで組み立てることは可能です。具体的な方法についてはここでは詳しく説明しません。戻る1