Skip to content

Rewards

The free rewards behind client.rewards.

rewards.service

The free rewards: read whether each is available, and collect it.

Nothing here spends rubies: no request of these rewards carries a cost, so none needs a spend_rubies guard. Each collect sends what the client's button sends; the client only enables that button when the matching read says the reward is there, and the server refuses the rest.

Classes:

Name Description
RewardsService

The daily login bonus, the startup bonus, lost and found, the activity chest, the weekly honour

RewardsService

RewardsService(client: EmpireClient)

Bases: BaseService

The daily login bonus, the startup bonus, lost and found, the activity chest, the weekly honour reward, the patch note rewards, and the pending rewards count.

Reached as client.rewards.

Methods:

Name Description
get_login_bonus

Get the daily login bonus: today's rewards to pick one from, and what was collected.

collect_login_bonus

Pick one of today's login bonus rewards.

collect_login_bonus_special

Collect today's alliance or VIP login bonus.

get_startup_bonus

Get the startup (beginner) login bonus; collectable says whether its next reward waits.

collect_startup_bonus

Collect the next startup login bonus reward.

get_lost_and_found

Get the items in lost and found: those that found no room in their inventory.

collect_lost_and_found

Collect an item from lost and found into its inventory.

on_activity_chest

Call callback with each uac push, after activity_chest is updated.

open_activity_chest

Open the activity chest, and wait for the next chest the server pushes.

get_weekly_honor

Get your weekly honour rank; is_ready says whether last week's reward waits.

redeem_weekly_honor

Redeem last week's honour reward.

get_patch_note_rewards

Get a patch note's rewards; the header's collected says whether they were collected.

collect_patch_note_rewards

Collect a patch note's rewards.

on_pending_rewards

Call callback with each pre push, after pending_rewards is updated.

Attributes:

Name Type Description
activity_chest ActivityChestInfo | None

The activity chest from the last uac push; None until one arrived.

pending_rewards int | None

How many rewards wait in the reward hub, from the last pre push; None until one arrived.

activity_chest property

activity_chest: ActivityChestInfo | None

The activity chest from the last uac push; None until one arrived.

The server pushes it and nothing asks for it, so it is only as fresh as the last push; is_ready() says whether the chest can be opened now.

Client: CastleActivityBonusData.parse_UAC (bundle line 110921)

pending_rewards property

pending_rewards: int | None

How many rewards wait in the reward hub, from the last pre push; None until one arrived.

The reward hub lists and hands out the rewards over its web service, which the library does not reach.

Client: RewardHubData.getAmountOfPendingRewards (bundle line 29787)

get_login_bonus

get_login_bonus(timeout: float = 5.0) -> GetLoginBonusResponse

Get the daily login bonus: today's rewards to pick one from, and what was collected.

today is the day to collect; has_anything_to_collect says whether a pick, or an alliance or VIP bonus you may have, is left.

The client asks for it only from LOGIN_BONUS_REQUIRED_XP XP on, and below that the server sends no alb at all (seen live), so nothing is sent then.

Raises:

Type Description
LoginBonusUnavailableError

Your XP is below LOGIN_BONUS_REQUIRED_XP, or not known yet

CommandError / EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: C2SGetLoginBonusVO (bundle line 39171), sent by GBDCommand (bundle line 129389) only with userXP >= CastleLoginBonusData.REQUIRED_XP (bundle line 39163); ALBCommand (bundle line 124772)

collect_login_bonus

collect_login_bonus(reward: Collectable, timeout: float = 5.0) -> LoginBonus

Pick one of today's login bonus rewards.

Parameters:

Name Type Description Default
reward Collectable

One of get_login_bonus().today.rewards; sent as its send_key, and its unit id for units

required
timeout float

Timeout in seconds

5.0

Returns:

Type Description
LoginBonus

The login bonus after the pick

Raises:

Type Description
ValueError

A reward with no key to send: one the client has no type for, or a currency whose key is unknown (see Collectable.send_key); nothing is sent

LoginBonusUnavailableError

Your XP is below LOGIN_BONUS_REQUIRED_XP, or not known yet

CommandError

The server refused the pick (already picked, another day, ...)

PacketError

The reply carries no login bonus

EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: CastleDailyLoginBonusDialog.performDailyRewardButtonSelection (bundle line 39228) sends C2SCatchLoginBonusVO(getServerKeyByCollectable(item), unitId or -1); CLBCommand (bundle line 124790)

collect_login_bonus_special

collect_login_bonus_special(special: LoginBonusSpecial, timeout: float = 5.0) -> LoginBonus

Collect today's alliance or VIP login bonus.

The client offers the alliance bonus only to an alliance member, so outside one nothing is sent. It offers the VIP bonus only while VIP is active, which the state does not know: the server decides that one.

Parameters:

Name Type Description Default
special LoginBonusSpecial

LoginBonusSpecial.ALLIANCE or LoginBonusSpecial.VIP

required
timeout float

Timeout in seconds

5.0

Returns:

Type Description
LoginBonus

The login bonus after the pick

Raises:

Type Description
ValueError

special is not a LoginBonusSpecial

LoginBonusUnavailableError

Your XP is below LOGIN_BONUS_REQUIRED_XP, or not known yet

NotInAllianceError

The alliance bonus while you are in no alliance; nothing is sent

CommandError

The server refused it

PacketError

The reply carries no login bonus

EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: CastleDailyLoginBonusDialog.performDailySpecialBonusButtonSelection (bundle lines 39229-39237) sends C2SCatchLoginBonusVO(null, -1, "ALLI" or "VIP"), the alliance one enabled only with isInAlliance (bundle line 39230; allianceID >= 0, bundle line 9986)

get_startup_bonus

get_startup_bonus(timeout: float = 5.0) -> GetStartupBonusResponse

Get the startup (beginner) login bonus; collectable says whether its next reward waits.

Raises:

Type Description
CommandError / EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: C2SGetSLI (bundle line 54338), SLICommand (bundle line 129798)

collect_startup_bonus

collect_startup_bonus(timeout: float = 5.0) -> bool

Collect the next startup login bonus reward.

Returns:

Type Description
bool

True when the server accepted it, False when it refused it

Client: C2SStartupLoginBonusCollectVO (bundle line 104974), sent by CastleStartupLoginBonusDialog.onClick (bundle line 57261) from a button enabled only for the next reward while it can be collected (bundle line 57258)

get_lost_and_found

get_lost_and_found(timeout: float = 5.0) -> list[LostAndFoundItem]

Get the items in lost and found: those that found no room in their inventory.

Raises:

Type Description
CommandError / EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: C2SGetLostAndFoundListVO (bundle line 107124), LFECommand (bundle line 125350)

collect_lost_and_found

collect_lost_and_found(item_id: int, timeout: float = 5.0) -> bool

Collect an item from lost and found into its inventory.

Parameters:

Name Type Description Default
item_id int

A LostAndFoundItem.item_id from get_lost_and_found

required
timeout float

Timeout in seconds

5.0

Returns:

Type Description
bool

True when the server accepted it, False when it refused it (the client keeps the

bool

button disabled while the item's inventory is full)

Client: C2SCollectLostAndFoundItemVO (bundle line 107195), LostAndFoundListItem.onCollect (bundle line 107151)

on_activity_chest

on_activity_chest(callback: Callable[[ActivityChestInfo], object]) -> None

Call callback with each uac push, after activity_chest is updated.

Detach it again with on_activity_chest.remove(callback), a no-op if it is not registered.

Unregister a callback with on_activity_chest.remove(callback).

open_activity_chest

open_activity_chest(timeout: float = 10.0) -> ActivityChestInfo | None

Open the activity chest, and wait for the next chest the server pushes.

The client sends this only once activity_chest has no time left, and waits for no reply: the server sends none (seen live). What follows is a uac with the next chest, which updates activity_chest as any push does; a uac still naming the opened chest, ready, is not taken for it.

Returning None on a timeout is this method's own rule: with no reply to the open, only the next chest tells that it opened. A uac that comes later still updates activity_chest.

Parameters:

Name Type Description Default
timeout float

Seconds to wait for the next uac

10.0

Returns:

Type Description
ActivityChestInfo | None

The next chest, or None when none came within timeout: the request went out,

ActivityChestInfo | None

but nothing tells whether the chest opened

Raises:

Type Description
ValueError

No chest is known yet, or it is not ready (see ActivityChestInfo.is_ready); nothing is sent

CommandError

The server answered with an error uac

PacketError

The uac is not an object

ReceiveThreadError

Called on the receive thread; nothing is sent

ConnectionClosedError / NetworkError

The connection dropped, or the send failed

Client: C2SOpenActivityChest (bundle line 104948), sent by CastleActivityBonusDialog.onClick (bundle line 104934) only with remainingTimeTillNextActivityBonus <= 0 and with no reply handled (no uoa command in the table at bundle line 120368); UACCommand (bundle line 129828) reads the next chest

get_weekly_honor

get_weekly_honor(timeout: float = 5.0) -> GetWeeklyHonorResponse

Get your weekly honour rank; is_ready says whether last week's reward waits.

Raises:

Type Description
CommandError / EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: C2SGetWeeklyHonorRankVO (bundle line 69926), GWHCommand (bundle line 124364)

redeem_weekly_honor

redeem_weekly_honor(timeout: float = 5.0) -> RedeemWeeklyHonorResponse

Redeem last week's honour reward.

The client enables its button only with honour and a waiting reward. The reply's coins and rubies reach client.state as any gcu does.

Returns:

Type Description
RedeemWeeklyHonorResponse

Your coins, rubies and units after the reward

Raises:

Type Description
CommandError

The server refused it (no reward waits)

EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: C2SRedeemWeeklyHonorBonus (bundle line 69934), sent by CastleWeeklyHighscoreRewardDialog.collect (bundle line 45392); RWBCommand (bundle line 124426)

get_patch_note_rewards

get_patch_note_rewards(message_id: int, timeout: float = 5.0) -> tuple[Collectable, ...]

Get a patch note's rewards; the header's collected says whether they were collected.

Parameters:

Name Type Description Default
message_id int

A patch note's MessageInfo.message_id in client.messages.mailbox

required
timeout float

Timeout in seconds

5.0

Raises:

Type Description
ValueError

message_id is no patch note in the mailbox, or its header names no patch note id; nothing is sent

CommandError / EmpireTimeoutError / ConnectionClosedError

see EmpireClient.send

Client: CastleChangelistDialog.requestRewards (bundle line 136088) sends C2SGetPatchNoteRewardsVO (bundle line 136140) when the dialog opens; GPNCommand (bundle line 125302)

collect_patch_note_rewards

collect_patch_note_rewards(message_id: int, timeout: float = 5.0) -> bool

Collect a patch note's rewards.

As the dialog does, the rewards are read first (a gpn), and only a patch note not collected yet that has rewards is collected. The mailbox copy of the message keeps its header: the client marks only its own copy collected.

Parameters:

Name Type Description Default
message_id int

A patch note's MessageInfo.message_id in client.messages.mailbox

required
timeout float

Timeout in seconds for each request

5.0

Returns:

Type Description
bool

True when the server accepted it, False when it refused it

Raises:

Type Description
ValueError

message_id is no patch note in the mailbox, its header names no patch note id or says it was collected, or it has no rewards; the collect is not sent

CommandError / EmpireTimeoutError / ConnectionClosedError

the reward read failed; see EmpireClient.send

Client: CastleChangelistDialog.collectRewards (bundle line 136119) sends C2SCollectPatchNoteRewardsVO (bundle line 136131) from a button enabled only while the header's collected is false and shown only with rewards (updateCollectButton, bundle line 136114); CPNCommand (bundle line 125269)

on_pending_rewards

on_pending_rewards(callback: Callable[[PendingRewardsInfo], object]) -> None

Call callback with each pre push, after pending_rewards is updated.

Detach it again with on_pending_rewards.remove(callback), a no-op if it is not registered.

Client: PRECommand.executeCommand (bundle line 120837) dispatches PRE_ARRIVED

Unregister a callback with on_pending_rewards.remove(callback).

rewards.models

The free rewards: the login bonus, the startup bonus, lost and found, the activity chest, the weekly honour reward, the patch note rewards, and the pending rewards count.

Commands:

  • alb / clb: The daily login bonus and picking one of its rewards
  • sli / slc: The startup (beginner) login bonus and collecting it
  • lfe / clf: Lost and found and collecting an item from it
  • uac / uoa: The activity chest (pushed) and opening it
  • gwh / rwb: Your weekly honour rank and redeeming its reward
  • gpn / cpn: A patch note's rewards and collecting them
  • pre: How many rewards wait in the reward hub (pushed)

None of these requests carries a cost: each VO holds only the ids below, and the one reply with coins and rubies (rwb) brings the totals after the reward.

Classes:

Name Description
GetLoginBonusRequest

Ask for the daily login bonus.

LoginBonusDay

One day of the login bonus week: the rewards to pick one from, and what was collected.

LoginBonus

The daily login bonus: the day it is, and the week's rewards.

GetLoginBonusResponse

The daily login bonus.

CollectLoginBonusRequest

Collect today's login bonus: one of its rewards, or its alliance or VIP bonus.

CollectLoginBonusResponse

The login bonus after a pick.

GetStartupBonusRequest

Ask for the startup (beginner) login bonus.

GetStartupBonusResponse

The startup login bonus: the next reward and whether it can be collected now.

CollectStartupBonusRequest

Collect the next startup login bonus reward.

CollectStartupBonusResponse

Acknowledgement of a collected startup bonus; the client reads nothing from it.

LostAndFoundItem

An item in lost and found: one that found no room in its inventory, kept until it expires.

GetLostAndFoundRequest

Ask for lost and found.

GetLostAndFoundResponse

Lost and found.

CollectLostAndFoundRequest

Collect an item from lost and found.

CollectLostAndFoundResponse

Acknowledgement of a collected item; the client reads nothing from it.

ActivityChestInfo

The activity chest: the next one and how long until it opens. The server pushes it; nothing asks for it.

OpenActivityChestRequest

Open the activity chest.

OpenActivityChestResponse

A reply to opening the chest, should one come: none did live, and the client registers no command for it.

GetWeeklyHonorRequest

Ask for your weekly honour rank.

GetWeeklyHonorResponse

Your weekly honour rank, and when the next reward comes.

RedeemWeeklyHonorRequest

Redeem last week's honour reward.

RedeemWeeklyHonorResponse

Your coins, rubies and units after the reward.

GetPatchNoteRewardsRequest

Ask for a patch note's rewards.

GetPatchNoteRewardsResponse

A patch note's rewards.

CollectPatchNoteRewardsRequest

Collect a patch note's rewards.

CollectPatchNoteRewardsResponse

Acknowledgement of collected patch note rewards; the client reads nothing from it.

PendingRewardsInfo

How many rewards wait in the reward hub. The server pushes it; nothing asks for it.

Attributes:

Name Type Description
LOGIN_BONUS_REQUIRED_XP

The XP from which the client asks for the login bonus.

logger module-attribute

logger = logging.getLogger(__name__)

LOGIN_BONUS_REQUIRED_XP module-attribute

LOGIN_BONUS_REQUIRED_XP = 1200

The XP from which the client asks for the login bonus.

Client: CastleLoginBonusData.REQUIRED_XP (bundle line 39163), GBDCommand (bundle line 129389)

GetLoginBonusRequest pydantic-model

Bases: BaseRequest

Ask for the daily login bonus.

Command: alb Payload: {}

Client: C2SGetLoginBonusVO (bundle line 39171), sent by GBDCommand.checkLoginBonus (bundle line 129391) after a login with at least LOGIN_BONUS_REQUIRED_XP XP

LoginBonusDay pydantic-model

Bases: BasePayload

One day of the login bonus week: the rewards to pick one from, and what was collected.

Client: CastleLoginBonusData.parseALB (bundle line 39138) reads R[d]["D"+(d+1)] as [{REW}, {PICK}, {ALLI}, {VIP}]

Fields:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

day pydantic-field

day: int

The day of the week, 0 to 6

rewards pydantic-field

rewards: tuple[Collectable, ...] = ()

The rewards to pick one from (REW)

picked pydantic-field

picked: Collectable | None = None

The reward picked (PICK); None while none was

alliance_reward pydantic-field

alliance_reward: Collectable | None = None

The alliance bonus collected (ALLI); None while it was not

vip_reward pydantic-field

vip_reward: Collectable | None = None

The VIP bonus collected (VIP); None while it was not

LoginBonus pydantic-model

Bases: BasePayload

The daily login bonus: the day it is, and the week's rewards.

Client: CastleLoginBonusData.parseALB (bundle lines 39133-39139)

Fields:

Validators:

day_index pydantic-field

day_index: ClientInt = 0

Wire key D

Days of the bonus so far; today is day_index % 7

days pydantic-field

days: tuple[LoginBonusDay, ...] = ()

Wire key R

The week's days, in order

today property

today: LoginBonusDay | None

Today's day of the week, None when the reply has no such day.

has_anything_to_collect

has_anything_to_collect(*, in_alliance: bool = False, vip_active: bool = False) -> bool

Whether today has a reward left: no pick yet, or the alliance or VIP bonus where you may have one.

Client: CastleLoginBonusData.parseALB (bundle line 39138) sets hasAnythingToCollect

GetLoginBonusResponse pydantic-model

Bases: BaseResponse, LoginBonus

The daily login bonus.

Command: alb

Client: ALBCommand.executeCommand (bundle line 124772)

Fields:

Validators:

CollectLoginBonusRequest pydantic-model

Bases: BaseRequest

Collect today's login bonus: one of its rewards, or its alliance or VIP bonus.

Command: clb Payload: {"ID": unit id or -1, "I": reward key or null, "SP": "ALLI", "VIP" or null}

The client's object sends its nulls, so they go out here too.

Client: C2SCatchLoginBonusVO (bundle line 104761), from CastleDailyLoginBonusDialog.performDailyRewardButtonSelection (bundle line 39228) for a reward and performDailySpecialBonusButtonSelection (bundle line 39237) for a bonus

Fields:

unit_id pydantic-field

unit_id: int = -1

Wire key ID

The unit's id for a units reward, else -1

reward_key pydantic-field

reward_key: str | None = None

Wire key I

The picked reward's Collectable.send_key

special pydantic-field

special: LoginBonusSpecial | None = None

Wire key SP

The alliance or VIP bonus instead of a reward

to_payload

to_payload() -> dict[str, Any]

CollectLoginBonusResponse pydantic-model

Bases: BaseResponse

The login bonus after a pick.

Command: clb

Client: CLBCommand.executeCommand (bundle line 124790) passes alb to parseALB

Fields:

Validators:

login_bonus pydantic-field

login_bonus: LoginBonus | None = None

Wire key alb

The login bonus after the pick

GetStartupBonusRequest pydantic-model

Bases: BaseRequest

Ask for the startup (beginner) login bonus.

Command: sli Payload: {}

Client: C2SGetSLI (bundle line 54338), sent by GBDCommand after every login (bundle line 129389) and on reaching level 6 (bundle line 13066)

GetStartupBonusResponse pydantic-model

Bases: BaseResponse

The startup login bonus: the next reward and whether it can be collected now.

Command: sli

Client: SLICommand.executeCommand (bundle line 129798), CastleStartUpBonusData.parse_SLI (bundle line 113943); the dialog's collect button (bundle line 57258)

Fields:

Validators:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

next_reward_id pydantic-field

next_reward_id: ClientInt = 0

Wire key NRR

The next reward's beginnerLoginRewardID; -1 once all are collected

can_collect pydantic-field

can_collect: bool = False

Wire key CC

Whether the next reward can be collected now

collectable property

collectable: bool

Whether there is a next reward and it can be collected now, as the dialog enables its button.

CollectStartupBonusRequest pydantic-model

Bases: BaseRequest

Collect the next startup login bonus reward.

Command: slc Payload: {}

Client: C2SStartupLoginBonusCollectVO (bundle line 104974), sent by CastleStartupLoginBonusDialog.onClick (bundle line 57261)

CollectStartupBonusResponse pydantic-model

Bases: BaseResponse

Acknowledgement of a collected startup bonus; the client reads nothing from it.

Command: slc Client: SLCCommand.executeCommand (bundle line 129785)

Fields:

LostAndFoundItem pydantic-model

Bases: BasePayload

An item in lost and found: one that found no room in its inventory, kept until it expires.

Client: LostAndFoundListItemVO.parseData and remainingTimeInSeconds (bundle lines 144545-144549)

Fields:

Validators:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

item_id pydantic-field

item_id: ClientInt = 0

Wire key LFID

The entry's id, to collect it

reward pydantic-field

reward: Collectable

The item, from its server key (ROT) and entry (ROV)

seconds pydantic-field

seconds: int | float = 0

Wire key ET

Seconds until it expires, when read

received_time pydantic-field

received_time: int | float | None = None

Wire key CT

When it arrived, unix seconds; None when not sent

equipment_elapsed pydantic-field

equipment_elapsed: ClientInt = 0

Wire key LFES

Seconds a timed equipment has run while here

received_at pydantic-field

received_at: float

When the values were read, in time.monotonic() seconds

remaining_seconds

remaining_seconds(now: float | None = None) -> float

Seconds until it expires, 0 once it has.

GetLostAndFoundRequest pydantic-model

Bases: BaseRequest

Ask for lost and found.

Command: lfe Payload: {}

Client: C2SGetLostAndFoundListVO (bundle line 107124), sent when the inventory dialog opens (bundle line 107082)

GetLostAndFoundResponse pydantic-model

Bases: BaseResponse

Lost and found.

Command: lfe

Client: LFECommand.executeCommand (bundle line 125350), CastleLostAndFoundData.parse_LFE (bundle line 144517), which sorts the items by arrival and then expiry for display

Fields:

Validators:

items pydantic-field

Wire key lfe

The items, in the order sent

CollectLostAndFoundRequest pydantic-model

Bases: BaseRequest

Collect an item from lost and found.

Command: clf Payload: {"LFID": item id}

Client: C2SCollectLostAndFoundItemVO (bundle line 107195), sent by LostAndFoundListItem.onCollect (bundle line 107151); the button is disabled while the item's inventory is full (bundle line 107139)

Fields:

item_id pydantic-field

item_id: int

Wire key LFID

The item's LostAndFoundItem.item_id

CollectLostAndFoundResponse pydantic-model

Bases: BaseResponse

Acknowledgement of a collected item; the client reads nothing from it.

Command: clf Client: CLFCommand.executeCommand (bundle line 125256)

Fields:

ActivityChestInfo pydantic-model

Bases: BaseResponse

The activity chest: the next one and how long until it opens. The server pushes it; nothing asks for it.

Command: uac

Client: UACCommand.executeCommand (bundle line 129828), CastleActivityBonusData.parse_UAC, isActive and remainingTimeTillNextActivityBonus (bundle lines 110921-110932)

Fields:

Validators:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

next_reward_id pydantic-field

next_reward_id: ClientInt = 0

Wire key CID

The next chest's activityRewardID; -1 without one

seconds pydantic-field

seconds: int | float = 0

Wire key TTU

Seconds until it can be opened, when read

received_at pydantic-field

received_at: float

When the values were read, in time.monotonic() seconds

is_active property

is_active: bool

Whether there is a next chest.

remaining_seconds

remaining_seconds(now: float | None = None) -> float

Seconds until the chest can be opened, 0 once it can.

is_ready

is_ready(now: float | None = None) -> bool

Whether there is a chest and it can be opened now, as the dialog enables its button.

OpenActivityChestRequest pydantic-model

Bases: BaseRequest

Open the activity chest.

Command: uoa Payload: {}

Client: C2SOpenActivityChest (bundle line 104948), sent by CastleActivityBonusDialog.onClick (bundle line 104934) once no time is left

OpenActivityChestResponse pydantic-model

Bases: BaseResponse

A reply to opening the chest, should one come: none did live, and the client registers no command for it.

Command: uoa Client: ClientConstSF.S2C_OPEN_ACTIVITY_CHEST (bundle line 71), absent from the command table (bundle line 120368)

Fields:

GetWeeklyHonorRequest pydantic-model

Bases: BaseRequest

Ask for your weekly honour rank.

Command: gwh Payload: {}

Client: C2SGetWeeklyHonorRankVO (bundle line 69926), sent when CastleWeeklyHighscoreRewardDialog opens (bundle line 45344)

GetWeeklyHonorResponse pydantic-model

Bases: BaseResponse

Your weekly honour rank, and when the next reward comes.

Command: gwh

Client: GWHCommand.executeCommand (bundle line 124364), CastleHighscoreData.parseGWH, isReadyToCollect and nextRewardRemainingTime (bundle lines 111899-111912)

Fields:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

last_week_rank pydantic-field

last_week_rank: ParseInt = 0

Wire key LWR

Last week's rank, whose reward waits; 0 when none waits

current_rank pydantic-field

current_rank: ParseInt = 0

Wire key CWR

This week's rank so far

seconds pydantic-field

seconds: ParseInt = 0

Wire key RT

Seconds until the next reward, when read

league_id pydantic-field

league_id: ParseInt = 0

Wire key LID

Your league

received_at pydantic-field

received_at: float

When the values were read, in time.monotonic() seconds

is_ready property

is_ready: bool

Whether last week's reward waits to be redeemed.

remaining_seconds

remaining_seconds(now: float | None = None) -> float

Seconds until the next reward, 0 once it is due.

RedeemWeeklyHonorRequest pydantic-model

Bases: BaseRequest

Redeem last week's honour reward.

Command: rwb Payload: {}

Client: C2SRedeemWeeklyHonorBonus (bundle line 69934), sent by CastleWeeklyHighscoreRewardDialog.collect (bundle line 45392); the button is enabled only with honour and a waiting reward (bundle line 45347)

RedeemWeeklyHonorResponse pydantic-model

Bases: BaseResponse

Your coins, rubies and units after the reward.

Command: rwb

Client: RWBCommand.executeCommand (bundle line 124426), CastleHighscoreData.parseRWB (bundle line 111900) reads gcu and gui

Fields:

currencies pydantic-field

currencies: CurrencyBlock = None

Wire key gcu

Coins and rubies after the reward

unit_inventory pydantic-field

unit_inventory: UnitInventoryBlock = None

Wire key gui

Units after the reward

GetPatchNoteRewardsRequest pydantic-model

Bases: BaseRequest

Ask for a patch note's rewards.

Command: gpn Payload: {"PNID": patch note id}

Client: C2SGetPatchNoteRewardsVO (bundle line 136140), sent by CastleChangelistDialog.requestRewards (bundle line 136088) when the patch note's dialog opens

Fields:

patch_note_id pydantic-field

patch_note_id: int

Wire key PNID

The patch note's PatchNoteHeader.patch_note_id

GetPatchNoteRewardsResponse pydantic-model

Bases: BaseResponse

A patch note's rewards.

Command: gpn

Client: GPNCommand.executeCommand (bundle line 125302) reads R with CollectableParserS2CParamObject.createList

Fields:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

rewards pydantic-field

rewards: CollectableObject = ()

Wire key R

The rewards, in the order sent

CollectPatchNoteRewardsRequest pydantic-model

Bases: BaseRequest

Collect a patch note's rewards.

Command: cpn Payload: {"PNID": patch note id, "MID": message id}

Client: C2SCollectPatchNoteRewardsVO (bundle line 136131), sent by CastleChangelistDialog.collectRewards (bundle line 136119)

Fields:

patch_note_id pydantic-field

patch_note_id: int

Wire key PNID

The patch note's PatchNoteHeader.patch_note_id

message_id pydantic-field

message_id: int

Wire key MID

The patch note message's MessageInfo.message_id

CollectPatchNoteRewardsResponse pydantic-model

Bases: BaseResponse

Acknowledgement of collected patch note rewards; the client reads nothing from it.

Command: cpn Client: CPNCommand.executeCommand (bundle line 125269)

Fields:

PendingRewardsInfo pydantic-model

Bases: BaseResponse

How many rewards wait in the reward hub. The server pushes it; nothing asks for it.

The rewards themselves are listed and collected over the reward hub's web service, not over this connection.

Command: pre

Client: PRECommand.executeCommand (bundle line 120837) passes AMT (CommKeys.AMOUNT, dll line 18945; read at bundle line 120838) to RewardHubData.setAmountOfPendingRewards (bundle line 29786); CastleRewardHubMicroservice (bundle line 12885) fetches the rewards themselves

Fields:

model_config class-attribute

model_config: ConfigDict = ConfigDict(frozen=True)

amount pydantic-field

amount: ClientInt = 0

Wire key AMT

How many rewards wait