Skip to content

Commit

Permalink
PZAccountKit // Add Echo-of-War support for HSR daily notes.
Browse files Browse the repository at this point in the history
  • Loading branch information
ShikiSuen committed Nov 26, 2024
1 parent 62c7648 commit 85738e5
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -237,3 +237,12 @@ extension DailyNoteProtocol {
(self as? GeneralNote4GI)?.weeklyBossesInfo
}
}

// MARK: - Per-game properties (HSR Echo-of-War Weekly Attempts)

extension DailyNoteProtocol {
/// DailyNoteProtocol: HSR Echo-of-War Weekly Attempts, Star Rail Only
public var echoOfWarIntel: EchoOfWarInfo4HSR? {
(self as? RealtimeNote4HSR)?.echoOfWarCostStatus
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// (c) 2024 and onwards Pizza Studio (AGPL v3.0 License or later).
// ====================
// This code is released under the SPDX-License-Identifier: `AGPL-3.0-or-later`.

import Foundation
import PZBaseKit

/// Echo of War weekly attempts(HSR). Unavailable if daily note is fetched from Widget API.
public struct EchoOfWarInfo4HSR: AbleToCodeSendHash {
// MARK: Lifecycle

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.weeklyEOWAttemptsCount = try container.decode(Int.self, forKey: .weeklyEOWAttemptsCount)
self.weeklyEOWAttemptsLimit = try container.decode(Int.self, forKey: .weeklyEOWAttemptsLimit)
}

// MARK: Public

public let weeklyEOWAttemptsCount: Int
public let weeklyEOWAttemptsLimit: Int

public var isFinished: Bool { weeklyEOWAttemptsCount == weeklyEOWAttemptsLimit }

public var textDescription: String {
guard !isFinished else { return "✔︎" }
return "\(weeklyEOWAttemptsCount) / \(weeklyEOWAttemptsLimit)"
}

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(weeklyEOWAttemptsCount, forKey: .weeklyEOWAttemptsCount)
try container.encode(weeklyEOWAttemptsLimit, forKey: .weeklyEOWAttemptsLimit)
}

// MARK: Private

private enum CodingKeys: String, CodingKey {
case weeklyEOWAttemptsCount = "weekly_cocoon_cnt"
case weeklyEOWAttemptsLimit = "weekly_cocoon_limit"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public protocol Note4HSR: BenchmarkTimeEditable, DailyNoteProtocol {
var simulatedUniverseInfo: SimuUnivInfo4HSR { get }
/// Daily Training Info
var dailyTrainingInfo: DailyTrainingInfo4HSR { get }
/// Echo of War (unable from Widget APIs)
var echoOfWarCostStatus: EchoOfWarInfo4HSR? { get }
/// Optional Metadata (unable from Widget APIs)
var optionalMetaData: NoteMetaData4HSR? { get }
}

extension Note4HSR {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// (c) 2024 and onwards Pizza Studio (AGPL v3.0 License or later).
// ====================
// This code is released under the SPDX-License-Identifier: `AGPL-3.0-or-later`.

import Foundation
import PZBaseKit

/// Daily Note Metadata. Unavailable if daily note is fetched from Widget API.
public struct NoteMetaData4HSR: AbleToCodeSendHash {
// MARK: Lifecycle

public init(from decoder: any Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

self.currentTs = try container.decode(Int.self, forKey: .currentTs)
self.signURL = try container.decode(URL.self, forKey: .signURL)
self.homeURL = try container.decode(URL.self, forKey: .homeURL)
self.noteURL = try container.decode(URL.self, forKey: .noteURL)
}

// MARK: Public

public let currentTs: Int
public let signURL: URL
public let homeURL: URL
public let noteURL: URL

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)

try container.encode(currentTs, forKey: .currentTs)
try container.encode(signURL, forKey: .signURL)
try container.encode(homeURL, forKey: .homeURL)
try container.encode(noteURL, forKey: .noteURL)
}

// MARK: Private

private enum CodingKeys: String, CodingKey {
case currentTs = "current_ts"
case signURL = "sign_url"
case homeURL = "home_url"
case noteURL = "note_url"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public struct RealtimeNote4HSR: DecodableFromMiHoYoAPIJSONResult, Note4HSR {
self.assignmentInfo = try decoder.decode(AssignmentInfo4HSR.self)
self.simulatedUniverseInfo = try decoder.decode(SimuUnivInfo4HSR.self)
self.dailyTrainingInfo = try decoder.decode(DailyTrainingInfo4HSR.self)
self.optionalMetaData = try? decoder.decode(NoteMetaData4HSR.self)
self.echoOfWarCostStatus = try? decoder.decode(EchoOfWarInfo4HSR.self)
}

// MARK: Public
Expand All @@ -30,6 +32,10 @@ public struct RealtimeNote4HSR: DecodableFromMiHoYoAPIJSONResult, Note4HSR {
public let simulatedUniverseInfo: SimuUnivInfo4HSR
/// Daily Training Info
public let dailyTrainingInfo: DailyTrainingInfo4HSR
/// Echo of War (unable from Widget APIs)
public let echoOfWarCostStatus: EchoOfWarInfo4HSR?
/// Optional Metadata (unable from Widget APIs)
public let optionalMetaData: NoteMetaData4HSR?
}

// MARK: BenchmarkTimeEditable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ public struct StaminaInfo4HSR: Sendable {

/// The time when stamina is full
public var fullTime: Date {
Date(timeInterval: _staminaRecoverTime, since: fetchTime)
if let staminaFullTimestamp {
return .init(timeIntervalSince1970: staminaFullTimestamp)
}
return Date(timeInterval: _staminaRecoverTime, since: fetchTime)
}

/// The time when next stamina recover. If the stamina is full, return `nil`
Expand All @@ -55,6 +58,9 @@ public struct StaminaInfo4HSR: Sendable {

public let isReserveStaminaFull: Bool

// Unix Timestamp.
public let staminaFullTimestamp: Double?

/// Reserved Stamina when data is fetched.
public let currentReserveStamina: Int

Expand Down Expand Up @@ -87,6 +93,7 @@ extension StaminaInfo4HSR: Decodable {
self._staminaRecoverTime = try TimeInterval(container.decode(Int.self, forKey: .staminaRecoverTime))
self.currentReserveStamina = try container.decode(Int.self, forKey: .currentReserveStamina)
self.isReserveStaminaFull = (try? container.decode(Bool.self, forKey: .isReserveStaminaFull)) ?? false
self.staminaFullTimestamp = try container.decodeIfPresent(Double.self, forKey: .staminaFullTimestamp)
}

enum CodingKeys: String, CodingKey {
Expand All @@ -95,6 +102,7 @@ extension StaminaInfo4HSR: Decodable {
case staminaRecoverTime = "stamina_recover_time"
case isReserveStaminaFull = "is_reserve_stamina_full"
case currentReserveStamina = "current_reserve_stamina"
case staminaFullTimestamp = "stamina_full_ts"
}
}

Expand Down

0 comments on commit 85738e5

Please sign in to comment.