public async Task <int> GetGachiSchedule() { var splatNet2TimeNow = (decimal)Math.Floor((DateTime.UtcNow - DateTime2020).TotalSeconds) + SplatNet2Time2020; int GetRuleFromSchedule() { for (int i = 0; i < schedules.Count; i++) { if (schedules[i].start_time <= splatNet2TimeNow && schedules[i].end_time < splatNet2TimeNow) { schedules.RemoveAt(i); i--; } else if (schedules[i].start_time <= splatNet2TimeNow && splatNet2TimeNow < schedules[i].end_time) { foreach (var ruleName in Rules.Keys) { if (ruleName == schedules[i].rule.key) { return(Rules[ruleName]); } } } } return(-1); } var ans = GetRuleFromSchedule(); if (ans != -1) { return(ans); } var res = await HttpManager.GetDeserializedJsonAsyncWithCookieContainer <SplatNet2DataStructure.Schedules>(ApiUriPrefix + "schedules", Cookie); schedules = res.gachi; schedules.Sort((a, b) => a.start_time - b.start_time > 0 ? 1 : -1); return(GetRuleFromSchedule()); }
public static async Task <bool> UpdateApplication() { const string url = "https://github.com/boomxch/StreamingWidget/raw/master/Splatoon2StreamingWidget.exe"; if (!Directory.Exists("data")) { Directory.CreateDirectory("data"); } try { // config削除 if (File.Exists("data/config.xml")) { File.Delete("data/config.xml"); } // ファイル置き換え await HttpManager.DownloadAsync(url, "data"); if (File.Exists("Splatoon2StreamingWidget.old")) { File.Delete("Splatoon2StreamingWidget.old"); } File.Move("Splatoon2StreamingWidget.exe", "Splatoon2StreamingWidget.old"); File.Move("data/Splatoon2StreamingWidget.exe", "Splatoon2StreamingWidget.exe"); Process.Start("Splatoon2StreamingWidget.exe", "/up " + Process.GetCurrentProcess().Id); } catch (HttpRequestException) { return(false); } finally { DeleteTempUpdateFiles(); } return(true); }
public static async Task <string> GetHashFromS2SAPI(string idToken, long timeStamp) { const string url = ""; using var request = new HttpRequestMessage(HttpMethod.Post, url); request.Headers.Add("User-Agent", "" + UpdateManager.VersionNumber); var body = new Dictionary <string, string> { { "naIdToken", idToken }, { "timestamp", timeStamp.ToString() } }; if (IsBodyEmpty(body)) { await LogManager.WriteLogAsync("Body is null"); return(""); } request.Content = new StringContent(await new FormUrlEncodedContent(body).ReadAsStringAsync(), Encoding.UTF8, "application/x-www-form-urlencoded"); try { var res = await HttpManager.GetAutoDeserializedJsonAsync <SplatNet2DataStructure.S2SResult>(request); return(res.hash); } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"hash\""); return(""); } }
// LPの処理について、機能をオンにするなら別のリグマが始まったときとの区別をつける必要がある public async Task UpdatePlayerData() { var res = await HttpManager.GetDeserializedJsonAsyncWithCookieContainer <SplatNet2DataStructure.Results>(ApiUriPrefix + "results", Cookie); var battleData = res.results; battleData = battleData.Where(v => v.battle_number > lastBattleNumber).OrderBy(a => a.battle_number).ToList(); #if DEBUG battleData = battleData.Where(v => v.battle_number == lastBattleNumber + 1).OrderBy(a => a.battle_number).ToList(); #endif if (battleData.Count == 0) { return; } if (battleData.Last().battle_number - lastBattleNumber > 50) { await TryInitializePlayerData(); return; } lastBattleNumber = battleData.Last().battle_number; var ruleNow = Rules[battleData.Last().rule.key]; PlayerData.KillCountN = battleData.Last().player_result.kill_count; PlayerData.AssistCountN = battleData.Last().player_result.assist_count; PlayerData.DeathCountN = battleData.Last().player_result.death_count; PlayerData.PaintPoint = battleData.Last().player_result.game_paint_point; foreach (var item in battleData) { // common PlayerData.KillCount += item.player_result.kill_count; PlayerData.AssistCount += item.player_result.assist_count; PlayerData.DeathCount += item.player_result.death_count; if (item.my_team_result.key == "victory") { PlayerData.WinCount++; } else { PlayerData.LoseCount++; } RuleData.RuleIndex = Rules[item.rule.key]; switch (item.game_mode.key) { // XPについての処理 case "gachi": if (item.player_result.player.udemae.is_x) { PlayerData.XPowerDiff = 0; var xPower = item.x_power ?? 0; // 計測が終わった直後はDiffの表示は行わない if (ruleNow == Rules[item.rule.key] && PlayerData.XPower[ruleNow] != 0) { PlayerData.XPowerDiff = xPower - PlayerData.XPower[ruleNow]; } PlayerData.XPower[Rules[item.rule.key]] = xPower; } else { // ウデマエ更新 PlayerData.Udemae[Rules[item.rule.key]] = item.player_result.player.udemae.name + item.player_result.player.udemae.s_plus_number; } RuleData.Mode = RuleData.GameMode.Gachi; RuleData.Name = ruleNamesJP[RuleData.RuleIndex]; break; // LPについての処理 case "league_pair": PlayerData.LeaguePowerDiff = 0; var lp2 = WillDisplayEstimateLp ? item.league_point ?? (item.my_estimate_league_point ?? 0) : (item.league_point ?? 0); if (PlayerData.LeaguePower != 0) { PlayerData.LeaguePowerDiff = lp2 - PlayerData.LeaguePower; } PlayerData.LeaguePower = lp2; RuleData.Mode = RuleData.GameMode.League2; RuleData.Name = "リーグマッチ"; break; // LPについての処理 case "league_team": PlayerData.LeaguePowerDiff = 0; var lp4 = WillDisplayEstimateLp ? item.league_point ?? (item.my_estimate_league_point ?? 0) : (item.league_point ?? 0); if (PlayerData.LeaguePower != 0) { PlayerData.LeaguePowerDiff = lp4 - PlayerData.LeaguePower; } PlayerData.LeaguePower = lp4; RuleData.Mode = RuleData.GameMode.League4; RuleData.Name = "リーグマッチ"; break; // いくつかの項目についてMVPの回数を算出 case "private": var detailResult = await HttpManager.GetDeserializedJsonAsyncWithCookieContainer <SplatNet2DataStructure.DetailResult>(ApiUriPrefix + "results/" + item.battle_number, Cookie); // 味方チーム内でのMVP 1on1の時は常にプラスになる 敵チームとの複合にした方が良い? if (!detailResult.my_team_members.Any(v => v.kill_count > item.player_result.kill_count)) { PlayerData.KillMVP++; } if (!detailResult.my_team_members.Any(v => v.death_count < item.player_result.death_count)) { PlayerData.DeathMVP++; } if (!detailResult.my_team_members.Any(v => (float)v.kill_count / v.death_count > (float)item.player_result.kill_count / item.player_result.death_count)) { PlayerData.KDMVP++; } if (!detailResult.my_team_members.Any(v => v.game_paint_point > item.player_result.game_paint_point)) { PlayerData.PointMVP++; } RuleData.Mode = RuleData.GameMode.Private; RuleData.Name = "プライベートマッチ"; break; // 調子メータについての処理 case "regular": var winMeter = item.win_meter ?? 0; PlayerData.WinMeter = winMeter; PlayerData.ImageUri = new Uri(ApiUriPrefix.Substring(0, ApiUriPrefix.Length - 5) + item.player_result.player.weapon.image); RuleData.Mode = RuleData.GameMode.Regular; RuleData.Name = "ナワバリバトル"; break; // フェス case "fes_solo": PlayerData.FesPowerDiff = 0; var fesPower = item.fes_power ?? 0; // 計測が終わった直後はDiffの表示は行わない if (PlayerData.FesPower != 0) { PlayerData.FesPowerDiff = fesPower - PlayerData.FesPower; } PlayerData.FesPower = fesPower; RuleData.Mode = RuleData.GameMode.FestivalSolo; RuleData.Name = "フェス(チャレンジ)"; break; case "fes_team": PlayerData.ContributionPointTotal = item.contribution_point_total ?? 0; RuleData.Mode = RuleData.GameMode.FestivalTeam; RuleData.Name = "フェス(レギュラー)"; break; } } }
public async Task <bool> TryInitializePlayerData() { SplatNet2DataStructure.Records.PersonalRecords.PlayerRecords udemaeData; try { var result = await HttpManager.GetDeserializedJsonAsyncWithCookieContainer <SplatNet2DataStructure.Records>(ApiUriPrefix + "records", Cookie); udemaeData = result.records.player; } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"records\""); return(false); } catch (JsonException) { await LogManager.WriteLogAsync("Failed to convert \"records\""); return(false); } PlayerData = new PlayerData(udemaeData.nickname, udemaeData.principal_id); string GetUdemaeName(SplatNet2DataStructure.Records.PersonalRecords.PlayerRecords.RuleData r) => r.name == null ? "-" : (r.name + r.s_plus_number); PlayerData.Udemae = new[] { GetUdemaeName(udemaeData.udemae_zones), GetUdemaeName(udemaeData.udemae_tower), GetUdemaeName(udemaeData.udemae_rainmaker), GetUdemaeName(udemaeData.udemae_clam), }; SplatNet2DataStructure.XPowerRanking powerData; try { powerData = await HttpManager.GetDeserializedJsonAsyncWithCookieContainer <SplatNet2DataStructure.XPowerRanking>(ApiUriPrefix + "x_power_ranking/" + GetSeason() + "/summary", Cookie); } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"XPowerRanking\""); return(false); } catch (JsonException) { await LogManager.WriteLogAsync("Failed to convert \"XPowerRanking\""); return(false); } // parse時にCultureInfo.InvariantCultureを付けないとフランスの方を筆頭にバグる float GetXPower(SplatNet2DataStructure.Records.PersonalRecords.PlayerRecords.RuleData r, SplatNet2DataStructure.XPowerRanking.RuleStats m) => r.is_x && m.my_ranking != null?float.Parse(m.my_ranking.x_power, CultureInfo.InvariantCulture) : 0; PlayerData.XPower = new[] { GetXPower(udemaeData.udemae_zones, powerData.splat_zones), GetXPower(udemaeData.udemae_tower, powerData.tower_control), GetXPower(udemaeData.udemae_rainmaker, powerData.rainmaker), GetXPower(udemaeData.udemae_clam, powerData.clam_blitz) }; List <SplatNet2DataStructure.Results.BattleResult> battleData; try { var result2 = await HttpManager.GetDeserializedJsonAsyncWithCookieContainer <SplatNet2DataStructure.Results>(ApiUriPrefix + "results", Cookie); battleData = result2.results; } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"results\""); return(false); } catch (JsonException) { await LogManager.WriteLogAsync("Failed to convert \"results\""); return(false); } lastBattleNumber = battleData.Max(a => a.battle_number); #if DEBUG lastBattleNumber = battleData.Max(a => a.battle_number) - 50; #endif var ruleIndex = await GetGachiSchedule(); RuleData = new RuleData(RuleData.GameMode.Gachi, ruleIndex, ruleNamesJP[ruleIndex]); return(true); }
/// <summary> /// Login process for SplatNet2 /// </summary> /// <returns>iksm session</returns> public static async Task <string> GetCookie(string sessionToken) { var timeStamp = GetUnixTime(); var guid = Guid.NewGuid().ToString(); // access token 取得 const string url = ""; var request = new HttpRequestMessage(HttpMethod.Post, url); request.Headers.Add("Accept-Language", "ja-JP"); request.Headers.Add("Accept", "application/json"); request.Headers.Add("Connection", "Keep-Alive"); request.Headers.Add("Accept-Encoding", "gzip"); var body = new Dictionary <string, string> { { "session_token", sessionToken }, { "grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer-session-token" } }; if (IsBodyEmpty(body)) { await LogManager.WriteLogAsync("Body is null"); return(""); } var json = JsonConvert.SerializeObject(body); request.Content = new StringContent(json, Encoding.UTF8, "application/json"); string accessToken; try { var res = await HttpManager.GetAutoDeserializedJsonAsync <SplatNet2DataStructure.AccessToken>(request); accessToken = res.access_token; } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"access token\""); return(""); } catch (InvalidDataException) { await LogManager.WriteLogAsync("Failed to decompress \"access token\""); return(""); } finally { request.Dispose(); } // user data 取得 const string url2 = ""; request = new HttpRequestMessage(HttpMethod.Get, url2); request.Headers.Add("Accept-Language", "ja-JP"); request.Headers.Add("Accept", "application/json"); request.Headers.Add("Authorization", "Bearer " + accessToken); request.Headers.Add("Connection", "Keep-Alive"); request.Headers.Add("Accept-Encoding", "gzip"); if (IsBodyEmpty(accessToken)) { await LogManager.WriteLogAsync("Body is null"); return(""); } SplatNet2DataStructure.UserInfo userInfo; try { userInfo = await HttpManager.GetAutoDeserializedJsonAsync <SplatNet2DataStructure.UserInfo>(request); } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"user data\""); return(""); } catch (InvalidDataException) { await LogManager.WriteLogAsync("Failed to decompress \"user data\""); return(""); } finally { request.Dispose(); } // 新 access token 取得 const string url3 = ""; request = new HttpRequestMessage(HttpMethod.Post, url3); request.Headers.Add("Accept-Language", "ja-JP"); request.Headers.Add("Accept", "application/json"); request.Headers.Add("Connection", "Keep-Alive"); request.Headers.Add("Accept-Encoding", "gzip"); request.Headers.Add("Authorization", "Bearer"); request.Headers.Add("X-Platform", "Android"); var flapgNSO = await CallFlapgAPI(accessToken, guid, timeStamp, "nso"); var body3 = new Dictionary <string, Dictionary <string, string> > { { "parameter", new Dictionary <string, string> { { "f", flapgNSO.f }, { "naIdToken", flapgNSO.p1 }, { "timestamp", flapgNSO.p2 }, { "requestId", flapgNSO.p3 }, { "naCountry", userInfo.country }, { "naBirthday", userInfo.birthday }, { "language", userInfo.language } } }, }; if (IsBodyEmpty(body3)) { await LogManager.WriteLogAsync("Body is null"); return(""); } var json3 = JsonConvert.SerializeObject(body3); request.Content = new StringContent(json3, Encoding.UTF8, "application/json"); string idToken; try { var res = await HttpManager.GetAutoDeserializedJsonAsync <SplatNet2DataStructure.SplatoonToken>(request); idToken = res.result.webApiServerCredential.accessToken; } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"id token\""); return(""); } catch (InvalidDataException) { await LogManager.WriteLogAsync("Failed to decompress \"id token\""); return(""); } finally { request.Dispose(); } var flapgApp = await CallFlapgAPI(idToken, guid, timeStamp, "app"); // splatoon access token 取得 const string url4 = ""; request = new HttpRequestMessage(HttpMethod.Post, url4); request.Headers.Add("Accept", "application/json"); request.Headers.Add("Connection", "Keep-Alive"); request.Headers.Add("Accept-Encoding", "gzip"); request.Headers.Add("Authorization", "Bearer " + idToken); request.Headers.Add("X-Platform", "Android"); if (IsBodyEmpty(idToken)) { await LogManager.WriteLogAsync("Body is null"); return(""); } var body4 = new Dictionary <string, Dictionary <string, string> > { { "parameter", new Dictionary <string, string> { { "f", flapgApp.f }, { "registrationToken", flapgApp.p1 }, { "timestamp", flapgApp.p2 }, { "requestId", flapgApp.p3 } } }, }; if (IsBodyEmpty(body4)) { await LogManager.WriteLogAsync("Body is null"); return(""); } var json4 = JsonConvert.SerializeObject(body4); request.Content = new StringContent(json4, Encoding.UTF8, "application/json"); string splatoonAccessToken; try { var res = await HttpManager.GetAutoDeserializedJsonAsync <SplatNet2DataStructure.WebServiceToken>(request); splatoonAccessToken = res.result.accessToken; } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"splatoon access token\""); return(""); } catch (InvalidDataException) { await LogManager.WriteLogAsync("Failed to decompress \"session token\""); return(""); } finally { request.Dispose(); } // iksm_session 取得 const string url5 = ""; request = new HttpRequestMessage(HttpMethod.Get, url5); request.Headers.Add("X-IsAppAnalyticsOptedIn", "false"); request.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); request.Headers.Add("Accept-Encoding", "gzip,deflate"); request.Headers.Add("X-GameWebToken", splatoonAccessToken); request.Headers.Add("Accept-Language", "ja-JP"); request.Headers.Add("X-IsAnalyticsOptedIn", "false"); request.Headers.Add("Connection", "keep-alive"); request.Headers.Add("DNT", "0"); if (IsBodyEmpty(splatoonAccessToken)) { await LogManager.WriteLogAsync("Body is null"); return(""); } try { var cookies = await HttpManager.GetCookieContainer(request); var responseCookies = cookies.GetCookies(new Uri("")).Cast <Cookie>(); return(responseCookies.First().Value); } catch (HttpRequestException) { await LogManager.WriteLogAsync("Failed to get \"iksm session\""); return(""); } catch (IndexOutOfRangeException) { await LogManager.WriteLogAsync("Failed to get \"cookie\""); return(""); } finally { request.Dispose(); } }