爲誰鍊金戰鬥自動化的 MMA 實現

あららぎ
Aug 26, 2017 · 1 min read

起因

玩過的大概都直到爲誰鍊金是一個肝爆炸的遊戲,筆者因爲帳號繼承出現失誤,把號弄沒了只能重新再來,又無法忍受從0開始重耍,便有了這個東西。主要用的 MMA 的 HTTPRequest 功能和 ExportStringImportString 實現 JSON 和 Association 之間的轉換。

封包分析

共有

也就是每個封包 Headers 里都有的信息,包括一下幾個:

  • x-app-ver: app版本
  • X-GUMI-TRANSACTION: 隨便拿個東西生成 UUID/GUID 就成
  • X-Unity-Version: Unity 版本,一般不會變
  • x-asset-ver: 資源版本
  • Content-Type: 用 “application/json; charset=utf-8” 就成
  • Content-Length: 請求 body 的長度
    這些數據都可以自己生成/抓包取得,遊戲更新時重抓一次就行。
    然後便能寫好兩個通用 HTTP 請求函數,需要 session id 的和不需要的:
tagatameRequestWithoutSSID[path_,body_]:=Block[{req},
req=HTTPRequest[
<|"Scheme"->"https",
"Domain"->"alchemist.gu3.jp",
"Path"->path,
Method -> "POST",
"Headers"->{
"x-app-ver" -> "5f3debcd:a",
"X-GUMI-TRANSACTION"-> CreateUUID[],
"X-Unity-Version"-> "5.3.6p1",
"x-asset-ver"->"99d08f149a67de3c1d4b312638ea51a6ca83519b_gumi",
"Content-Type"->"application/json; charset=utf-8",
"Content-Length"->Length@ImportString[body,{"Binary","Byte"}]},
"Body"-> body,
VerifySecurityCertificates -> False
|>];
ImportString[URLRead[req,"Body"],"RawJSON"]
];
tagatameRequest[path_,body_]:=Block[{req},
req=HTTPRequest[
<|"Scheme"->"https",
"Domain"->"alchemist.gu3.jp",
"Path"->path,
Method -> "POST",
"Headers"->{
"x-app-ver" -> "5f3debcd:a",
"X-GUMI-TRANSACTION"-> CreateUUID[],
"Authorization"->"gumi "<>sessionId,
"X-Unity-Version"-> "5.3.6p1",
"x-asset-ver"->"99d08f149a67de3c1d4b312638ea51a6ca83519b_gumi",
"Content-Type"->"application/json; charset=utf-8",
"Content-Length"->Length@ImportString[body,{"Binary","Byte"}]},
"Body"-> body,
VerifySecurityCertificates -> False
|>];
ImportString[URLRead[req,"Body"],"RawJSON"]
];

登錄

登錄也就是生成 session id,除了登錄之外的所有通信都需要 session id.
登錄 需要 device_idsecret_key,也可以通過抓包獲得。

generateSSID[deviceid_:"a7b429b5-88a0-4a5b-9082-495f526dc8a0",secretkey_:"ef9ac5ff-0818-46e0-9837-e1b20fd47b5a"]:=
Block[{json,body},
ticket=ticket+1;
json=<|"ticket"->ticket,"access_token"->"", "param"-><|"device_id"->deviceid,"secret_key"->secretkey|>|>;
body=ExportString[json,"RawJSON","Compact"->True] ;
json=tagatameRequestWithoutSSID["/gauth/accesstoken",body];
sessionId=json["body"]["access_token"];
tagatameRequest["/product","{\"ticket\":"<>ToString[ticket]<>"}"];
Return[sessionId];
];

戰鬥

戰鬥請求數據里有一個時間數據,抓包兩次相減就能獲得算法,結果如下:

getTime[]:=QuantityMagnitude[DateObject[Now,"Second"]-DateObject[{2017,8,11,12,12,03},"Second"]]+1502424733;

然後戰鬥請求的數據根據抓包把格式弄好即可。不過如果要同步成就,就要先獲取所有成就,然後戰鬥後將所有成就推進一次(實測一次直接推進N次也是可以的。)

getTrophyToReward[]:=Block[
{result},
ticket++;
result=tagatameRequest["/login/param","{\"ticket\":"<>ToString[ticket]<>"}"];
result=result["body"]["trophyprogs"];
Select[result,!IntegerQ[#["rewarded_at"]]&]
];
battleStart[questid_]:=Block[{json,body,result},
ticket++;
json=<|"ticket"->ticket,"param"-><|"iname"->questid,"partyid"->0,"req_at"->getTime[],"btlparam"-><|"help"-><|"fuid"->""|>|>,"location"-><|"lat"->0,"lng"->0|>|>|>;
body=ExportString[json,"RawJSON","Compact"->True] ;
result=tagatameRequest["/btl/com/req",body];
battleId=result["body"]["btlid"];
battleResult=result["body"]
];
battleEnd[mission_,trophytime_]:=Block[
{json,number,trophyprogs,body,today},
ticket++;
number=Length[battleResult["btlinfo"]["drops"]];
today=StringJoin[IntegerString[#,10,2]&/@DateValue[{"Year","Month","Day"}]];
trophyprogs=getTrophyToReward[];
(*trophyprogs=Select[trophyprogs,StringContainsQ[#["iname"],StringTake[battleResult["btlinfo"]["qid"],{7,-1}]]&];*)
trophyprogs=<|"iname"->#["iname"],"pts"->#["pts"]+trophytime,"ymd"->#["ymd"]|>&/@trophyprogs;
json=<|"ticket"->ticket,"param"-><|"btlid"->battleId,"btlendparam"-><|"time"->0,"result"->"win","beats"->Table[1,number],"steals"-><|"items"->Table[0,number],"golds"->Table[0,number]|>,"missions"->{mission,mission,mission},"inputs"->{}|>,"trophyprogs"->trophyprogs|>|>;
body=ExportString[json,"RawJSON","Compact"->True];
tagatameRequest["/btl/com/end",body]
];
)
あららぎ

Written by

Please persuade me to study

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade