Helpers API¶
The swgoh_comlink.helpers subpackage provides utility functions, constants,
and data structures for working with game data returned by the Comlink API.
All public names are importable directly from swgoh_comlink.helpers:
Sync and async clients¶
Helpers that make requests take a client as their first argument. Each one has an async_ twin,
and the sync-named helper also accepts a SwgohComlinkAsync: it hands the call to the twin and
returns an awaitable. Subclasses of either client are accepted too.
members = get_guild_members(comlink, allycode=123456789) # SwgohComlink
members = await get_guild_members(async_comlink, allycode=123456789) # SwgohComlinkAsync
members = await async_get_guild_members(async_comlink, allycode=123456789)
Given an async client, argument errors are raised when the result is awaited rather than when the
helper is called. The async_ twins accept only async clients.
DataItems¶
DataItems is an IntFlag enum mapping game data collection names to bit
positions for use with get_game_data(items=...).
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import DataItems
comlink = SwgohComlink()
# A single collection
units = comlink.get_game_data(items=DataItems.UNITS)
# Only the collections you need, combined with `|`
data = comlink.get_game_data(items=DataItems.SKILL | DataItems.EQUIPMENT)
# Whole segments (the collections returned by the legacy request_segment= calls)
segments = comlink.get_game_data(items=DataItems.SEGMENT1 | DataItems.SEGMENT2)
# All collections
everything = comlink.get_game_data(items=DataItems.ALL)
Request only the collections you need where you can. Comlink assembles the whole
response before sending it, so smaller masks are faster and use less memory on both
sides. For example, DataItems.CHALLENGE | DataItems.CONQUEST returns about 32 MB
in about 2.4 seconds, versus about 147 MB in about 12.5 seconds for
SEGMENT2 | SEGMENT4.
Combine members with |, not +
Some members are aliases that share a bit with another member. For example,
CONQUEST_DEFINITION, ARTIFACT_DEFINITION and CONQUEST_MISSION are all the
CONQUEST bit. Adding aliases together sets a different bit:
DataItems.CONQUEST_DEFINITION + DataItems.ARTIFACT_DEFINITION requests
ABILITY_DECISION_TREE. Bitwise OR (|) is always safe.
Note
Comlink accepts any items bitmask from 1 to 252 − 1, or -1
(DataItems.ALL) for everything, and rejects values outside that range with an
HTTP 400. Older Comlink releases had a bug in how CDN URLs were built that could
make some single-collection requests fail; upgrade Comlink if you see that.
Use DataItems.members() to list all available member names.
DataItems
¶
Bases: IntFlag
Integer flag enum class mapping game data collection names to the integer values of their bit positions for use
in the items parameter of the get_game_data() method.
Members can be combined with the bitwise OR operator (|) to request more than one collection in a single call.
Requesting only the collections you need is significantly faster and uses less memory than requesting whole
segments.
Examples:
units = comlink.get_game_data(items=DataItems.UNITS) skill_equipment = comlink.get_game_data(items=DataItems.SKILL | DataItems.EQUIPMENT) units_no_pve = comlink.get_game_data(items=DataItems.UNITS, include_pve_units=False) segments_1_and_2 = comlink.get_game_data(items=DataItems.SEGMENT1 | DataItems.SEGMENT2)
Note
Combine members with |, not +. Aliased members share a bit, so adding them sets a different bit:
DataItems.CONQUEST_DEFINITION + DataItems.ARTIFACT_DEFINITION requests ABILITY_DECISION_TREE, while
DataItems.CONQUEST_DEFINITION | DataItems.ARTIFACT_DEFINITION correctly requests CONQUEST.
Comlink accepts any bitmask from 1 to 2**52 - 1, or -1 (DataItems.ALL) for everything. Values outside
that range are rejected with an HTTP 400.
Some of the DataItems members are actually aliases for other members. For example, the TABLE member is an
alias for the XP_TABLE member. This is done because both members name the same bit, which Comlink calls
AllTables: requesting it returns two collections, xpTable and table (the latter holds lookup tables such as
relic_promotion_table).
Other members are provided as a convenience. For example, the SEGMENT1 member is assigned the integer value of
all the collections that are included when using the original (request_segment=) style of calling the
get_game_data() method.
To retrieve all of the available game data, use the DataItems.ALL member.
A list of the member names of the DataItems class can be retrieved using the DataItems.members() class method.
members()
classmethod
¶
Return a list of the member names of the DataItems class.
Constants¶
Constants holds game-related lookup tables (leagues, divisions, relic tiers,
max values) and provides a get() classmethod that resolves both legacy
Constants names and DataItems member names.
from swgoh_comlink.helpers import Constants
Constants.LEAGUES # {"kyber": 100, "aurodium": 80, ...}
Constants.DIVISIONS # {"1": 25, "2": 20, ...}
Constants.RELIC_TIERS # {"1": "LOCKED", "2": "UNLOCKED", "3": "1", ...} (wire relic tier -> relic)
Constants.MAX_VALUES # {"GEAR_TIER": 13, "UNIT_LEVEL": 85, ...}
# Resolve a collection name to its integer value
Constants.get("UNITS") # "137438953472"
Constants.get("UnitDefinitions") # "137438953472" (legacy name)
Constants
¶
Collection of constants used throughout the SwgohComlink project.
Game data collection bit values have been moved to :class:DataItems.
The get() classmethod still resolves both old Constants names and
DataItems member names for backward compatibility.
get(item)
classmethod
¶
Resolve a string name to a game data collection integer value.
Accepts Constants attribute names (e.g. "UnitDefinitions"),
DataItems member names (e.g. "UNITS"), or special names like
"ALL".
Returns:
| Type | Description |
|---|---|
str | None
|
The integer value as a string, or |
get_names()
classmethod
¶
Return a list of resolvable names (Constants attrs + DataItems members).
Utility Functions¶
General-purpose validation and conversion helpers.
sanitize_allycode¶
sanitize_allycode(allycode=None)
¶
Sanitize a player allycode
Ensure that allycode does not
- contain dashes
- is the proper length
- contains only digits
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allycode
|
str | int | None
|
Player allycode to sanitize |
None
|
Returns:
| Type | Description |
|---|---|
str
|
Player allycode in the proper format |
human_time¶
human_time(unix_time)
¶
Convert unix time to human-readable string
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unix_time
|
int | float
|
standard unix time in seconds or milliseconds |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
human-readable time string |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If the provided unix time is not of the expected type |
Notes
If the provided unix time is invalid or an error occurs, the default time string returned is 1970-01-01 00:00:00
convert_relic_tier¶
convert_relic_tier(relic_tier)
¶
Convert a unit's wire relic tier to the relic level shown in game.
The game's RelicTier enum starts two below the relic level: RELIC_LOCKED is 1, RELIC_UNLOCKED
(relic 0) is 2 and RELIC_TIER_01 is 3, so a roster unit's relic.currentTier of 9 is relic 7.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
relic_tier
|
str | int
|
A roster unit's |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
|
str | None
|
|
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If the provided 'relic_tier' is not a string or integer. |
Examples:
validate_file_path¶
validate_file_path(path)
¶
Test whether provided path exists or not
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path | PathLike[str]
|
path of file to validate |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if exists, False otherwise. |
get_enum_key_by_value¶
get_enum_key_by_value(enum_dict, category, enum_value, default_return=None)
¶
Return the key from enum_dict for the given enum_value.
Wire Value Helpers¶
Comlink payloads are loosely typed. These functions read one raw field each and fail soft to a fixed default, so one unusable field never costs the whole record. They do not need a comlink instance.
| Payload quirk | Helper |
|---|---|
int64 values arrive as strings ("1655938556") |
as_int |
Ids such as matchId sometimes arrive as integers |
as_id |
Enums arrive as an int, a numeric string, the member name, or a decoder-style name such as CURRENCYTYPE_SHARDCURRENCY |
parse_enum, as_scalar |
Timestamps are seconds (guildJoinTime, Conquest lastRefreshTime) or milliseconds (lastActivityTime), and 0 means "no time" |
as_epoch |
| A repeated field with one element can decode as a single object | as_list |
Unit identifiers are "BASEID:SEVEN_STAR" or a bare "BASEID" |
base_id |
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import as_epoch, as_int, base_id, parse_enum
comlink = SwgohComlink()
player = comlink.get_player(allycode=123456789)
last_active = as_epoch(player["lastActivityTime"]) # aware UTC datetime, or None
season_score = as_int(player.get("lifetimeSeasonScore"))
roster = {base_id(unit["definitionId"]) for unit in player["rosterUnit"]}
currency = comlink.get_enums()["CurrencyType"]
parse_enum(16, currency) # 'SHARD_CURRENCY'
parse_enum("CURRENCYTYPE_SHARDCURRENCY", currency) # 'SHARD_CURRENCY'
Note
bool is never read as a number: as_int(True) is 0, not 1, and
parse_enum(True, ...) is None. Values below 1011 are read as
seconds by as_epoch (1011 seconds is the year 5138).
as_int¶
as_int(value, default=0)
¶
Read a payload number, which arrives as a string as often as an int.
int64 fields are quoted under proto3's JSON mapping ("1655938556") and bare elsewhere,
so both parse. bool is never read as a number even though it subclasses int:
int(True) is 1, which would look like real data (a score, a timestamp).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value. |
required |
default
|
int
|
Returned when value is missing or is not a whole number. [Default: 0] |
0
|
Returns:
| Type | Description |
|---|---|
int
|
The value as an int. A float is truncated; a string must hold a whole number |
int
|
( |
Examples:
as_str¶
as_str(value, default='')
¶
Read a payload string, or default when the value is not one.
Nothing is converted: a number, None or a nested object returns default. Use
:func:as_id for an id that may arrive as a number.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value. |
required |
default
|
str
|
Returned when value is not a |
''
|
Returns:
| Type | Description |
|---|---|
str
|
value when it is a string, otherwise default. |
Examples:
as_id¶
as_id(value, default='')
¶
Read an id that may arrive as a string or as a bare integer.
Ids such as matchId and currentMatchId are usually strings but have also been sent as
integers (currentMatchId: 2), so an int is converted with str(). bool and anything
other than a string or an int return default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value. |
required |
default
|
str
|
Returned when value is neither a |
''
|
Returns:
| Type | Description |
|---|---|
str
|
The id as a string. |
Examples:
as_scalar¶
as_scalar(value)
¶
Read an enum-rendered field exactly as sent: an int or a string, otherwise None.
An enum field (CombatType, ForceAlignment and the like) is a bare integer
when fetched with enums=False and a name with enums=True, so both are kept unchanged.
bool is excluded despite subclassing int. Use :func:parse_enum to resolve either
form to the member name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value. |
required |
Returns:
| Type | Description |
|---|---|
int | str | None
|
value when it is an |
Examples:
as_epoch¶
as_epoch(value)
¶
Read a payload timestamp as an aware UTC datetime, in seconds or milliseconds.
The game sends both units: guildJoinTime and Conquest lastRefreshTime are seconds,
lastActivityTime and most event and match times are milliseconds. A value below
1e11 is read as seconds (1e11 seconds is the year 5138) and anything larger as
milliseconds. 0, "0", None and anything unreadable mean "no time" and return
None rather than 1970: an unstarted phase carries the field set to zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value, as an int or a numeric string. |
required |
Returns:
| Type | Description |
|---|---|
datetime | None
|
The moment as a timezone-aware UTC datetime, or |
datetime | None
|
positive, unreadable, or past the year 9999. |
Examples:
as_list¶
as_list(value)
¶
Read a repeated field, whether it arrived as a list or as a single element.
A repeated field with one element can decode the same as a scalar field, so a lone object
is wrapped in a list. A missing field (None) is an empty list: proto3 omits empty
repeated fields. A tuple is converted to a list; any other value becomes its only element.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value. |
required |
Returns:
| Type | Description |
|---|---|
list[Any]
|
value itself when it is already a list (not a copy), otherwise a new list. |
Examples:
base_id¶
base_id(unit_identifier)
¶
Return the base id from a unit identifier such as "GENERALSKYWALKER:SEVEN_STAR".
Unit identifiers usually carry the unit's rarity after a colon, but some payloads name a unit
by its bare base id ("BOUSHH"), so the identifier is split rather than sliced.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit_identifier
|
Any
|
A unit |
required |
Returns:
| Type | Description |
|---|---|
str
|
The part before the first colon, or |
Examples:
parse_enum¶
parse_enum(value, members, *, enum_name=None)
¶
Resolve any wire spelling of an enum value to the member's canonical name.
An enum field arrives as an int (16), a numeric string ("16"), the member name
("SHARD_CURRENCY"), or a decoder-style name made of the enum type and the member name,
upper-cased and without underscores ("CURRENCYTYPE_SHARDCURRENCY"). All four resolve to
"SHARD_CURRENCY". Names are also matched ignoring case and underscores.
A decoder-style name must be upper-case and hold exactly one underscore, and its first half
must be the enum's type name when that is known: from enum_name, or else from a
<TypeName>_DEFAULT member (most of the game's enums have one, such as
CurrencyType_DEFAULT). This keeps an unknown
member from a newer game version, such as "NEW_GRIND", from being read as "GRIND".
When the type name is not known, any first half is accepted. bool and floats are never read
as a member value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Any
|
The raw payload value. |
required |
members
|
Mapping[str, int]
|
One enum's member names mapped to their values, as returned for that enum by
|
required |
enum_name
|
str | None
|
The enum's type name (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
str | None
|
The member name as spelled in members, or |
str | None
|
name could mean more than one. When several names share a value, the first one in |
str | None
|
members is returned for that value. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If members is not a mapping. |
Examples:
Arena Helpers¶
get_arena_payout¶
get_arena_payout(offset, fleet=False, *, now=None)
¶
Calculate the next arena payout time.
A player's payout is a fixed time each day: 18:00 UTC (squad) or 19:00 UTC (fleet), moved back by
the player's localTimeZoneOffsetMinutes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
offset
|
int
|
The player's |
required |
fleet
|
bool
|
Indicates if the payout is for fleet arena (True) or squad arena (False). Defaults to False. |
False
|
now
|
datetime | None
|
The time to count from. A naive value is read as local time. Defaults to the current time. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
datetime |
datetime
|
The next payout after |
get_max_rank_jump¶
get_max_rank_jump(current_rank)
¶
Calculates the maximum rank jump a player can achieve based on their current rank. The calculation is determined by applying different logic according to ranges of the current rank.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_rank
|
int
|
The player's current rank. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The maximum rank jump the player can achieve. |
GAC Helpers¶
Functions for working with Grand Arena Championships data. Functions prefixed
with async_ accept a SwgohComlinkAsync instance and must be awaited.
Sync¶
get_current_gac_event¶
get_current_gac_event(comlink)
¶
Return the event object for the current gac season
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comlink
|
Any
|
Instance of SwgohComlink. An instance of SwgohComlinkAsync is also accepted, in which case
the result of :func: |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any] | Coroutine[Any, Any, dict[str, Any]]
|
Current GAC event object, or an awaitable of it when |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If no active GAC event is found |
get_gac_brackets¶
get_gac_brackets(comlink, league, limit=0)
¶
Scan currently running GAC brackets for the requested league.
Uses exponential probing with binary search to find the last non-empty bracket before fetching all bracket data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comlink
|
Any
|
Instance of SwgohComlink. An instance of SwgohComlinkAsync is also accepted, in which case
the result of :func: |
required |
league
|
str
|
League to scan |
required |
limit
|
int
|
Maximum number of brackets to return. 0 means no limit. |
0
|
Returns:
| Type | Description |
|---|---|
dict[int, Any] | Coroutine[Any, Any, dict[int, Any]]
|
Dictionary mapping bracket index to player list. When |
dict[int, Any] | Coroutine[Any, Any, dict[int, Any]]
|
awaitable of that result. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Async¶
async_get_current_gac_event¶
async_get_current_gac_event(comlink)
async
¶
Return the event object for the current gac season (async version).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comlink
|
Any
|
Instance of SwgohComlinkAsync |
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Current GAC event object |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If no active GAC event is found |
async_get_gac_brackets¶
async_get_gac_brackets(comlink, league, limit=0)
async
¶
Scan currently running GAC brackets for the requested league (async version).
Uses exponential probing with binary search to find the last non-empty
bracket, then fetches all bracket data in parallel batches using
asyncio.gather.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comlink
|
Any
|
Instance of SwgohComlinkAsync |
required |
league
|
str
|
League to scan |
required |
limit
|
int
|
Maximum number of brackets to return. 0 means no limit. |
0
|
Returns:
| Type | Description |
|---|---|
dict[int, Any]
|
Dictionary mapping bracket index to player list. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Utilities¶
convert_league_to_int¶
convert_league_to_int(league)
¶
Convert GAC leagues to integer
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
league
|
str
|
GAC league name |
required |
Returns:
| Type | Description |
|---|---|
int | None
|
GAC league identifier as used in game data |
convert_divisions_to_int¶
convert_divisions_to_int(division)
¶
Convert GAC divisions to integer
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
division
|
int | str
|
GAC division ID as seen in game |
required |
Returns:
| Type | Description |
|---|---|
int | None
|
GAC division identifier as used within game data |
search_gac_brackets¶
search_gac_brackets(gac_brackets, player_name)
¶
Search the provided gac brackets data for a specific player
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gac_brackets
|
dict
|
GAC bracket data to search |
required |
player_name
|
str
|
Player name to search for |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict[str, Any]
|
GAC bracket and player information or empty if no match is found |
Event Helpers¶
Functions for reading the game's event schedule from get_events(). These do not
call comlink themselves.
get_event_schedule¶
Lists the events that are live now and those scheduled to start later, with start and end times as timezone-aware datetimes and readable names.
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import get_event_schedule, get_localization_dictionary
comlink = SwgohComlink()
loc = get_localization_dictionary(comlink)
for event in get_event_schedule(comlink.get_events(), loc):
ends = event["end"].strftime("%Y-%m-%d %H:%M UTC") if event["end"] else "never"
print(event["status"], event["name"], ends)
# live THE MANDALORIAN - Hero's Journey never
# live ACTION JAXXON - Special Marquee Event 2026-09-24 12:00 UTC
# upcoming THE WANDERER'S BLADE - Special Marquee Event 2026-10-13 12:00 UTC
Names keep the game's own capitalisation. Most events have a two-line banner: title
is its first line ("THE MANDALORIAN"), subtitle the second ("Hero's Journey"),
and name joins them with " - ", so either the joined string or the two parts can be
displayed.
Note
Permanent events such as journeys have a single run that the game ends in the
year 2126; their end is None. When two runs of an event overlap at a
changeover, the one ending first is used.
get_event_schedule(events, localization=None, *, now=None, include_upcoming=True)
¶
List the game events that are live now and, optionally, those scheduled to start later.
Each gameEvent has one or more instance entries, the runs it is scheduled for, each with a
startTime and endTime in epoch milliseconds (sent as strings). An event is live when one of
its runs holds now, and upcoming when its next run has yet to open; the schedule carries runs
days ahead. Each event is listed once: for the run that is live, or the one ending first when two
overlap at a changeover, otherwise for its next run. Events whose every run has ended are left out.
Permanent events (journeys, legendary events) have a single run ending in the year 2126; their
end is None.
The game writes most event names as a two-line banner, THE MANDALORIAN\n[c][FFC891]Hero's
Journey[-][/c]. Markup is removed and the case is kept as written: title is the first line
("THE MANDALORIAN"), subtitle the second ("Hero's Journey"), and name joins them as
"THE MANDALORIAN - Hero's Journey".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events
|
dict[str, Any] | list[dict[str, Any]]
|
The response from |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
now
|
datetime | None
|
The time to compare against. A naive value is read as local time. Defaults to the current time. |
None
|
include_upcoming
|
bool
|
Also list events whose next run has not started yet. [Default: True] |
True
|
Returns:
| Type | Description |
|---|---|
list[ScheduledEvent]
|
A list of :class: |
list[ScheduledEvent]
|
events soonest first. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
ScheduledEvent
¶
Bases: TypedDict
One live or upcoming game event as returned by :func:get_event_schedule.
instance_id
instance-attribute
¶
The id of the run (instance) this entry describes, when the payload names one.
name
instance-attribute
¶
Localized name on one line: title and subtitle joined with " - ", or title alone.
Falls back to the event's nameKey and then its id.
title
instance-attribute
¶
The first line of the game's two-line banner, as the game writes it (often in capitals), e.g.
"THE MANDALORIAN". Falls back like name.
subtitle
instance-attribute
¶
The rest of the banner, e.g. "Hero's Journey", or None for a one-line name.
type
instance-attribute
¶
The event's type (see the GameEventType enum), e.g. 10 for Grand Arena.
start
instance-attribute
¶
When this run opens, as a timezone-aware UTC datetime.
end
instance-attribute
¶
When this run closes, as a timezone-aware UTC datetime, or None for a permanent event.
campaign_element
instance-attribute
¶
The run's campaignElementIdentifier (the campaign node it plays), or None.
Guild Helpers¶
Sync¶
get_guild_members¶
get_guild_members(comlink, player_id=None, allycode=None)
¶
Return list of guild member player allycodes based upon provided player ID or allycode
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comlink
|
Any
|
Instance of SwgohComlink. An instance of SwgohComlinkAsync is also accepted, in which case
the result of :func: |
required |
player_id
|
str | None
|
Player's ID |
None
|
allycode
|
str | int | None
|
Player's allycode |
None
|
Returns:
| Type | Description |
|---|---|
list[Any] | Coroutine[Any, Any, list[Any]]
|
list of guild members objects, or an awaitable of it when |
Note
A player_id or allycode argument is required. The guild is requested with
include_recent_guild_activity_info=True: without it, current game versions return every
member with an empty name, zero galactic power and no last activity time.
Async¶
async_get_guild_members¶
async_get_guild_members(comlink, player_id=None, allycode=None)
async
¶
Return list of guild member player allycodes based upon provided player ID or allycode (async version).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
comlink
|
Any
|
Instance of SwgohComlinkAsync |
required |
player_id
|
str | None
|
Player's ID |
None
|
allycode
|
str | int | None
|
Player's allycode |
None
|
Returns:
| Type | Description |
|---|---|
list[Any]
|
list of guild members objects |
Note
A player_id or allycode argument is required. The guild is requested with
include_recent_guild_activity_info=True: without it, current game versions return every
member with an empty name, zero galactic power and no last activity time.
get_guild_activity¶
Summarizes a guild's recent Territory Battles, Territory Wars and raid, and lists its
members with their role, join time, last activity and score in the last raid. Pass it
the result of get_guild() requested with include_recent_guild_activity_info=True;
without that flag the recent results are empty.
from datetime import datetime, timezone
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import get_guild_activity
comlink = SwgohComlink()
guild = comlink.get_guild(guild_id, include_recent_guild_activity_info=True)
activity = get_guild_activity(guild)
print(f"TW record: {activity['territory_war_wins']}-{activity['territory_war_losses']}")
if activity["best_territory_battle"]:
print("Best recent TB:", activity["best_territory_battle"]["total_stars"], "stars")
now = datetime.now(timezone.utc)
for member in activity["members"]:
days = (now - member["joined"]).days if member["joined"] else None
print(member["name"], member["role"], days, member["raid_score"])
Note
guildJoinTime is in epoch seconds while lastActivityTime is in epoch
milliseconds; both are returned as timezone-aware UTC datetimes.
get_guild_activity(guild)
¶
Summarize a guild's recent Territory Battles, Territory Wars and raid, and its members.
The recent results are only present when the guild was requested with
include_recent_guild_activity_info=True; without it they are empty, and current game versions
also return every member with an empty name, zero galactic power and no last activity time.
The payload's numbers are read whether they arrive as integers or as strings. Member join times
(guildJoinTime) are epoch seconds, while lastActivityTime is epoch milliseconds; both are
returned as datetimes, and a missing or zero value as None. memberLevel is read as a number
or as its GuildMemberLevel enum name (enums=True).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
guild
|
dict[str, Any]
|
The response from |
required |
Returns:
| Name | Type | Description |
|---|---|---|
A |
GuildActivity
|
class: |
GuildActivity
|
stars (the payload carries no all-time best); a Territory War is a win when |
|
GuildActivity
|
|
|
GuildActivity
|
Members are in payload order. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
GuildActivity
¶
GuildMemberActivity
¶
Bases: TypedDict
One guild member, as returned in :attr:GuildActivity.members.
member_level
instance-attribute
¶
memberLevel as a number: 1 pending, 2 member, 3 officer, 4 leader. None when unknown.
role
instance-attribute
¶
"Pending", "Member", "Officer" or "Leader", or None when unknown.
joined
instance-attribute
¶
When the member joined the guild (guildJoinTime), as a timezone-aware UTC datetime.
last_activity
instance-attribute
¶
The member's lastActivityTime, as a timezone-aware UTC datetime.
raid_score
instance-attribute
¶
The member's score in :attr:GuildActivity.last_raid, or None when they are not in it.
TerritoryBattleResult
¶
Bases: TypedDict
A completed Territory Battle, as returned in :attr:GuildActivity.best_territory_battle.
definition_id
instance-attribute
¶
The battle's definitionId, e.g. "t05D" for Rise of the Empire.
TerritoryWarResult
¶
RaidResult
¶
Bases: TypedDict
A guild's most recent raid, as returned in :attr:GuildActivity.last_raid.
Conquest Helpers¶
Functions for working with Conquest game mode data. These are pure calculation and data-transformation functions and do not require a comlink instance.
calc_current_stamina¶
calc_current_stamina(unit, pass_plus=False)
¶
Calculates the current stamina of a game unit based on the elapsed time since the last refresh. The calculation considers a unit's last recorded stamina value, the time that has passed since it was last refreshed, and the optional influence of Conquest Pass+ (which accelerates stamina recovery by 33%).
Parameters: unit (dict[str, Any]): A dictionary containing the unit's data, including "remainingStamina" and "lastRefreshTime". pass_plus (bool): A flag indicating whether the Conquest Pass+ is active. Defaults to False.
Returns: int: The calculated current stamina value, capped at a maximum of 100.
Raises: SwgohComlinkValueError: If 'unit' is not a dictionary. SwgohComlinkValueError: If the unit dictionary does not contain valid "remainingStamina" or "lastRefreshTime" fields.
calc_stamina_full_time¶
Returns when a unit's Conquest stamina reaches 100, using the same regeneration
model as calc_current_stamina.
from datetime import datetime, timedelta, timezone
from swgoh_comlink.helpers import calc_stamina_full_time
# One entry of a player's Conquest status 'unitStamina' list
unit = {"unitId": "...", "remainingStamina": 90, "lastRefreshTime": "1790164800"}
full_at = calc_stamina_full_time(unit)
time_left = max(full_at - datetime.now(timezone.utc), timedelta(0))
calc_stamina_full_time(unit, pass_plus=False, *, now=None)
¶
Calculate when a unit's Conquest stamina reaches 100.
Uses the same model as :func:calc_current_stamina: stamina regenerates 1 point every 30 minutes
(33% faster with Conquest Pass+) from remainingStamina at lastRefreshTime, an epoch time in
seconds. For a unit with a lastRefreshTime that is not in the future, :func:calc_current_stamina
returns 100 from the returned moment on.
A missing lastRefreshTime (an older payload) or one ahead of now (a clock running ahead) is
not treated as elapsed regeneration in either direction: the unit is counted as last refreshed at
now.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit
|
dict[str, Any]
|
A |
required |
pass_plus
|
bool
|
Whether Conquest Pass+ is active. [Default: False] |
False
|
now
|
datetime | None
|
The current time. A naive value is read as local time. Defaults to the current time. |
None
|
Returns:
| Type | Description |
|---|---|
datetime
|
The moment stamina reaches 100, as a timezone-aware UTC datetime with whole seconds. For a unit |
datetime
|
that was already full this is in the past (or equal to |
datetime
|
the time remaining. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
get_conquest_feats¶
Lists the feats for a Conquest event (the newest one by default), covering both global and per-sector feats, with keycard rewards and any bonus artifact.
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import DataItems, get_conquest_feats, get_localization_dictionary
comlink = SwgohComlink()
# The CONQUEST bit also covers 'conquestDefinition' and 'artifactDefinition'
game_data = comlink.get_game_data(items=DataItems.CHALLENGE | DataItems.CONQUEST)
loc = get_localization_dictionary(comlink)
feats = get_conquest_feats(
game_data["conquestDefinition"],
game_data["challenge"],
loc,
game_data["artifactDefinition"],
difficulty="hard",
)
for feat in feats:
print(feat["scope"], feat["name"], feat["keycards"])
Tip
Requesting only the CHALLENGE and CONQUEST collections returns about 32 MB of
game data instead of about 147 MB for SEGMENT2 | SEGMENT4, and is roughly 5x faster.
get_conquest_feats(conquest_definitions, challenges, localization=None, artifact_definitions=None, *, conquest_id=None, difficulty=None)
¶
List the feats for a Conquest event, covering both global and per-sector feats.
Feats are not referenced from conquestDefinition; they are linked to an event only by the
challenge id convention <CONQUEST_ID>_[<KIND>_]<NAME>_<I|II|III>_DIFF[_S<n>], where KIND is
EVENT (global feat, no sector suffix), SECTOR, MINIBOSS or BOSS, and the roman
numeral is the difficulty (I = Easy, II = Normal, III = Hard). Many feats, mostly in older
conquests, have no KIND token (CONQUEST_VOL23_SILVO_VANE_III_DIFF_S0); their kind is
"Sector" when the id has a sector suffix and "Global" otherwise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
conquest_definitions
|
list[dict[str, Any]]
|
The game data |
required |
challenges
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
artifact_definitions
|
list[dict[str, Any]] | None
|
Optional game data |
None
|
conquest_id
|
str | None
|
Conquest id (e.g. |
None
|
difficulty
|
str | None
|
Restrict to |
None
|
Returns:
| Type | Description |
|---|---|
list[ConquestFeat]
|
A list of :class: |
list[ConquestFeat]
|
sector feats, then sector, feat kind and name. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If an argument is not a list, |
Examples:
ConquestFeat
¶
Bases: TypedDict
A single Conquest feat as returned by :func:get_conquest_feats.
difficulty
instance-attribute
¶
"Easy", "Normal" or "Hard".
scope
instance-attribute
¶
"Global" for event-wide feats, otherwise the sector title (e.g. "Sector 1").
sector_id
instance-attribute
¶
Sector id ("S0" .. "S4"), or None for global feats.
kind
instance-attribute
¶
"Global", "Sector", "Mini-Boss" or "Boss".
reward_artifact
instance-attribute
¶
Localized artifact name, falling back to its id when no name can be resolved.
Territory Battle Helpers¶
Functions for reading what a Territory Battle asks for and pays from its definition in the game data: the points each planet's stars need, each mission's squad requirement and points, and each platoon's points. They read only game data collections and a localization dictionary, so they do not require a comlink instance and say nothing about a battle in progress.
Each function covers every Territory Battle in the collection unless tb_id names
one: "t01D" Hoth Rebel Assault, "t02D" Hoth Imperial Retaliation, "t03D"
Geonosis Separatist Might, "t04D" Geonosis Republic Offensive or "t05D" Rise of
the Empire.
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import (
DataItems,
get_localization_dictionary,
get_tb_mission_requirements,
get_tb_mission_scores,
get_tb_platoon_definitions,
get_tb_star_thresholds,
)
comlink = SwgohComlink()
# TERRITORY_BATTLE_DEFINITION is the GUILD bit, CAMPAIGN carries 'campaign',
# CATEGORY 'category', and TABLE (the XP_TABLE bit) carries 'table'.
game_data = comlink.get_game_data(
items=DataItems.TERRITORY_BATTLE_DEFINITION | DataItems.CAMPAIGN | DataItems.CATEGORY | DataItems.TABLE
)
loc = get_localization_dictionary(comlink)
definitions = game_data["territoryBattleDefinition"]
for zone in get_tb_star_thresholds(definitions, loc, tb_id="t05D"):
print(zone["name"], zone["stars"])
for mission in get_tb_mission_requirements(
definitions, game_data["campaign"], game_data["category"], loc, tb_id="t05D"
):
if mission["hidden_reason"] is None:
print(mission["zone_id"], mission["requirement_text"].replace("\n", " / "))
for score in get_tb_mission_scores(definitions, game_data["table"], tb_id="t05D"):
if score["hidden_reason"] is None:
print(score["zone_id"], score["wave_points"])
for zone in get_tb_platoon_definitions(definitions, loc, tb_id="t05D"):
print(zone["name"], f"R{zone['min_relic']}", zone["total_points"])
hidden_reason is a heuristic
A few strike zones are fully defined in game data but never shown in game: a second
zone on a planet that reuses an earlier zone's mission ("duplicate"), and special
missions left among the strike zones of a version 3 map ("special"). The game data
does not mark them; hidden_reason infers them from how the definition is wired. On
game data 0.40.6 it flags three Rise of the Empire zones and nothing on the other maps.
Treat it as a filter that may need revisiting when a new map is added.
Note
A mission's requirement is not in the battle definition. Each mission zone names
a campaign mission, and get_tb_mission_requirements reads that mission's
entry gate from the campaign collection. Relic floors are returned as the relic
level shown in game, not the wire RelicTier value.
get_tb_star_thresholds¶
get_tb_star_thresholds(territory_battle_definitions, localization=None, *, tb_id=None)
¶
List each Territory Battle conflict zone (planet) with the territory points that earn its stars.
A star is a conflictZoneDefinition[].victoryPointRewards bracket whose reward type is VICTORY_POINT
(2). Not every bracket is one: two Rise of the Empire bonus zones pay a MYSTERY_BOX_CONFLICT (3) for
their first two brackets, so they have a single star. Thresholds are sorted rather than taken in payload
order, and galacticScoreRequirement (an int64, so usually sent as a string) is read as an integer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
territory_battle_definitions
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
tb_id
|
str | None
|
Restrict to one Territory Battle by definition id (case-insensitive): |
None
|
Returns:
| Type | Description |
|---|---|
list[TBZoneStars]
|
A list of :class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
TBZoneStars
¶
Bases: TypedDict
A Territory Battle conflict zone (planet) and its stars, as returned by :func:get_tb_star_thresholds.
tb_id
instance-attribute
¶
The territoryBattleDefinition id, e.g. "t05D".
name
instance-attribute
¶
Localized zone name, falling back to its nameKey.
phase
instance-attribute
¶
The phase number read from the zone id, or None when the id carries none.
force_alignment
instance-attribute
¶
The zone's raw forceAlignment (1 neutral, 2 light side, 3 dark side).
stars
instance-attribute
¶
The territory points at which each star is earned, ascending. Usually three, but fewer on zones whose early brackets pay a mystery box instead of a star.
get_tb_mission_requirements¶
get_tb_mission_requirements(territory_battle_definitions, campaigns, categories, localization=None, *, tb_id=None)
¶
List the squad each Territory Battle combat and special mission accepts.
The gate is not in the battle definition. Each strike and covert zone names its mission with a five-part
campaignElementIdentifier (campaign, map, node difficulty, node, mission) that resolves through
campaign -> campaignMap -> campaignNodeDifficultyGroup -> campaignNode ->
campaignNodeMission, and that mission's entryCategoryAllowed is the gate. The node difficulty is
part of the key because node ids repeat across difficulties.
minimumRelicTier is on the wire RelicTier scale and is returned as the relic level shown in game
(wire value minus Constants.RELIC_OFFSET, floored at 0, so fleet missions' RELIC_LOCKED is 0).
Category names come from each category's descKey; categories keyed PLACEHOLDER have no name and
are returned with their id. The requirement text is the mission's descKey with its colour markup
removed and its literal \n separators turned into newlines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
territory_battle_definitions
|
list[dict[str, Any]]
|
The game data |
required |
campaigns
|
list[dict[str, Any]]
|
The game data |
required |
categories
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
tb_id
|
str | None
|
Restrict to one Territory Battle by definition id (case-insensitive), as in
:func: |
None
|
Returns:
| Type | Description |
|---|---|
list[TBMissionRequirement]
|
A list of :class: |
list[TBMissionRequirement]
|
combat missions before its special missions. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list of dictionaries, |
Examples:
>>> game_data = comlink.get_game_data(
... items=DataItems.TERRITORY_BATTLE_DEFINITION | DataItems.CAMPAIGN | DataItems.CATEGORY
... )
>>> missions = get_tb_mission_requirements(
... game_data["territoryBattleDefinition"], game_data["campaign"], game_data["category"],
... get_localization_dictionary(comlink), tb_id="t05D",
... )
>>> missions[0]["requirement_text"], missions[0]["min_relic"]
('5x Jedi (Relic 5+)', 5)
TBMissionRequirement
¶
Bases: TypedDict
A Territory Battle mission's squad gate, as returned by :func:get_tb_mission_requirements.
conflict_zone_id
instance-attribute
¶
The conflict zone (planet) the mission belongs to.
mission_type
instance-attribute
¶
"combat" for a strikeZoneDefinition zone, "special" for a covertZoneDefinition zone.
name
instance-attribute
¶
Localized zone name (e.g. "Combat Mission"), falling back to its nameKey.
resolved
instance-attribute
¶
False when the zone's campaign mission was not found in campaigns. The gate fields below are
then empty or zero.
requirement_text
instance-attribute
¶
The requirement as the game words it, without markup and with one line per clause, e.g.
"5x Jedi (Relic 5+)\nMace Windu\nKit Fisto". The localization key when no dictionary is given.
allowed_categories
instance-attribute
¶
Squad units must belong to these categories, combined as category_match_type says.
category_match_type
instance-attribute
¶
The gate's raw matchType (1 match all, 2 match any).
commander_categories
instance-attribute
¶
The leader must belong to one of these categories. Empty when any leader is allowed.
mandatory_units
instance-attribute
¶
Units the squad must include, in slot order.
min_relic
instance-attribute
¶
The minimum relic level as shown in game. 0 when the mission has no relic floor.
hidden_reason
instance-attribute
¶
Why the game is not expected to show this combat mission, or None. "duplicate": an earlier zone
on the same planet already uses its campaign mission. "special": a special-mission campaign mission
left in the strike array of a version 3 map, where special missions are covert zones.
This is a heuristic. The game data does not mark a zone as hidden; the reason is inferred from how the definition is wired. Checked against the five Territory Battle maps in game data 0.40.6, it flags three Rise of the Empire zones and nothing else. A map wired differently in future may need the rule revisited.
TBCategory
¶
Bases: TypedDict
A unit category named by a mission gate, as returned in :class:TBMissionRequirement.
name
instance-attribute
¶
Localized category name; the id when the category has no name of its own.
TBMandatoryUnit
¶
Bases: TypedDict
A unit a mission requires by name, as returned in :attr:TBMissionRequirement.mandatory_units.
slot
instance-attribute
¶
The squad position the game places the unit in, starting at 0; -1 (on older maps) for no fixed slot.
get_tb_mission_scores¶
get_tb_mission_scores(territory_battle_definitions, tables, *, tb_id=None)
¶
List the territory points each Territory Battle mission pays, by waves completed.
A mission zone names its points table in encounterRewardTableId. That table entry's rows are keyed
by waves completed, as strings and in no guaranteed order, and each holds a cumulative
GALACTIC_SCORE:<points> value, so a two-wave mission reads {0: 0, 1: 100000, 2: 200000}. Rows are
placed by their key; a wave missing from the table repeats the previous wave's total, and rows paying
anything other than GALACTIC_SCORE are ignored.
Covert zones (special missions) have no points table: they pay items, not territory points, and are not listed. Special missions the Geonosis maps place in the strike array do have tables and are listed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
territory_battle_definitions
|
list[dict[str, Any]]
|
The game data |
required |
tables
|
list[dict[str, Any]]
|
The game data |
required |
tb_id
|
str | None
|
Restrict to one Territory Battle by definition id (case-insensitive), as in
:func: |
None
|
Returns:
| Type | Description |
|---|---|
list[TBMissionScore]
|
A list of :class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list of dictionaries, |
Examples:
TBMissionScore
¶
Bases: TypedDict
The territory points a Territory Battle mission pays, as returned by :func:get_tb_mission_scores.
mission_type
instance-attribute
¶
"combat" or "special", as in :class:TBMissionRequirement.
wave_points
instance-attribute
¶
Cumulative points by waves completed: wave_points[n] is what clearing n waves pays, so
wave_points[0] is 0 and the last entry is a full clear.
hidden_reason
instance-attribute
¶
As in :class:TBMissionRequirement.
get_tb_platoon_definitions¶
get_tb_platoon_definitions(territory_battle_definitions, localization=None, *, tb_id=None)
¶
List each Territory Battle recon zone with its platoons, unit floor and the points each platoon pays.
Read from reconZoneDefinition. Platoon rewards are listed per platoon because they can differ within
a zone; only GALACTIC_SCORE rewards count as points. The zone's unitRelicTier is on the wire
RelicTier scale and is returned as the relic level shown in game. The game data does not list which
units each platoon asks for; those appear only on a live battle's map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
territory_battle_definitions
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
tb_id
|
str | None
|
Restrict to one Territory Battle by definition id (case-insensitive), as in
:func: |
None
|
Returns:
| Type | Description |
|---|---|
list[TBReconZone]
|
A list of :class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
TBReconZone
¶
Bases: TypedDict
A Territory Battle recon zone and its platoons, as returned by :func:get_tb_platoon_definitions.
min_rarity
instance-attribute
¶
The rarity a unit must have to fill a platoon slot.
min_relic
instance-attribute
¶
The relic level, as shown in game, a unit must have to fill a slot. 0 when there is no relic floor.
max_units_per_player
instance-attribute
¶
How many units one player may place in the zone, or None for no limit.
TBPlatoon
¶
Bases: TypedDict
One platoon of a recon zone, as returned in :attr:TBReconZone.platoons.
points
instance-attribute
¶
Territory points paid for filling the platoon.
Game Data Helpers¶
Pure data-transformation functions for working with game data collections. These do not require a comlink instance.
get_raid_leaderboard_ids¶
get_raid_leaderboard_ids(campaign_data)
¶
Extracts and returns the raid leaderboard IDs from the provided campaign data.
This function processes the campaign_data to find and extract the IDs of
raids associated with the guild campaigns. The IDs are formatted as a string
specifying the type and structure of the raid. The function specifically works
with the "GUILD" campaign type and retrieves IDs from the "NORMAL_DIFF"
difficulty group.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
campaign_data
|
list
|
A list of campaign data structures, where each structure represents campaign information. The input data is expected to have nested dictionaries and lists with specific keys such as 'id', 'campaignMap', 'campaignNodeDifficultyGroup', and 'campaignNode'. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
list |
list[str]
|
A list containing formatted raid leaderboard IDs extracted from the |
list[str]
|
guild campaign data. Each ID is constructed as a string containing the |
|
list[str]
|
relevant identifiers for the campaign and its raids. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If any of the required keys are missing in the input data. |
TypeError
|
If |
create_localized_unit_name_dictionary¶
create_localized_unit_name_dictionary(locale)
¶
Create localized translation mapping for unit names
Take a localization element from the SwgohComlink.get_localization() result dictionary and
extract the unit name entries (UNIT_* keys containing _NAME).
The keys are localization keys, not base ids: look a unit up with its nameKey from the game
data units collection. Many name keys cannot be derived from the base id (CT7567 is
UNIT_REX_NAME, VEERS is UNIT_VEERS_GENERAL_NAME, reworked units use _NAME_V2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locale
|
str | list[Any]
|
The string element or List[bytes] from the SwgohComlink.get_localization() result key value |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A dictionary of unit name localization key (e.g. |
Examples:
get_playable_units¶
get_playable_units(units_collection)
¶
Return the playable units from the game data 'units' collection, one seven-star row per unit.
A unit is playable when it is obtainable and its obtainableTime is "0". Event and Galactic
Legend template variants carry a far-future obtainableTime instead. A missing obtainableTime
(older game data) counts as "0", and rarity may be 7 or "SEVEN_STAR" (enums=True).
get_current_datacron_sets¶
get_current_datacron_sets(datacron_list)
¶
Get the currently active datacron sets
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
datacron_list
|
list
|
List of 'datacronSet' from game data |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
Filtered list of only active datacron sets |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If datacron list is not a list |
get_datacron_dismantle_value¶
get_datacron_dismantle_value(datacron, datacron_set_list, recipe_list)
¶
Retrieves datacron dismantle materials based on the input datacron, datacron sets, and recipes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
datacron
|
dict
|
The datacron object from a player object. |
required |
datacron_set_list
|
list
|
The game data 'datacronSet' collection. |
required |
recipe_list
|
list
|
The game data 'recipe' collection. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict[str, Any]
|
A dictionary mapping ingredient IDs to their required dismantle material details, which include the quantity and type. |
get_datacron_dismantle_total¶
get_datacron_dismantle_total(datacrons, datacron_set_list, recipe_list)
¶
Calculate aggregated dismantle materials across all datacrons.
Calls :func:get_datacron_dismantle_value for each datacron and sums
the quantities per ingredient ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
datacrons
|
list
|
List of datacron objects from a player object. |
required |
datacron_set_list
|
list
|
The game data |
required |
recipe_list
|
list
|
The game data |
required |
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict[str, Any]
|
A dictionary mapping ingredient IDs to total quantity and type,
e.g. |
Game Configuration Helpers¶
Functions for reading the game's own configuration values (limits and tuning) from
get_game_metadata(). These do not call comlink themselves.
get_game_config¶
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import get_game_config, get_game_config_int
comlink = SwgohComlink()
metadata = comlink.get_game_metadata()
config = get_game_config(metadata) # every key, as strings
config["stat-mod-highlight-stat"] # 'SPEED'
get_game_config_int(metadata, "max-conquest-currency") # 3500
get_game_config_int(metadata, "stat-mod-max-storage") # 500
get_game_config_int(metadata, "max-datacron-currency") # 100000000
Note
Every configuration value is a string, including the numeric ones, and some keys
hold text such as "true" or "SPEED". get_game_config_int returns its
default (None unless given) for a missing key or a value that is not an integer.
get_game_config(metadata, key=None)
¶
Read the game's own configuration values from the game metadata.
get_game_metadata() returns several hundred config rows of game tuning, each
{"key": ..., "value": ...}, with every value a string, including the numeric ones. Useful keys
include max-conquest-currency, max-datacron-currency, stat-mod-max-storage,
conquest-stamina-recovery-duration-in-seconds and the squad-preset-* limits. Use
:func:get_game_config_int to read one as an integer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
metadata
|
dict[str, Any] | list[dict[str, Any]]
|
The response from |
required |
key
|
str | None
|
A single configuration key to return. [Default: all of them] |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, str] | str | None
|
With no |
dict[str, str] | str | None
|
value, or |
dict[str, str] | str | None
|
its first value. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
get_game_config_int¶
get_game_config_int(metadata, key, default=None)
¶
Read one numeric configuration value from the game metadata as an integer.
Configuration values are strings, and some keys hold text ("true", "SPEED") rather than a
number. A missing key or a value that is not an integer returns default, so a caller can tell
"not known" apart from a real value of zero.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
metadata
|
dict[str, Any] | list[dict[str, Any]]
|
The response from |
required |
key
|
str
|
The configuration key, e.g. |
required |
default
|
int | None
|
The value to return when the key is missing or not an integer. [Default: None] |
None
|
Returns:
| Type | Description |
|---|---|
int | None
|
The configuration value as an integer, or |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
Ability and Effect Helpers¶
Functions for reading unit abilities and named battle effects from game data and a localization dictionary. These do not require a comlink instance.
get_unit_abilities¶
Lists units' abilities with their name, kind, description at every level, and which level is a zeta or an omicron. Ships include their crew members' abilities.
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import (
OMICRON_MODE,
DataItems,
get_localization_dictionary,
get_playable_units,
get_unit_abilities,
)
comlink = SwgohComlink()
game_data = comlink.get_game_data(items=DataItems.UNITS | DataItems.SKILL | DataItems.ABILITY)
loc = get_localization_dictionary(comlink)
# Every Territory War omicron, with what it adds
for ability in get_unit_abilities(
get_playable_units(game_data["units"]),
game_data["skill"],
game_data["ability"],
loc,
omicron_mode=8,
):
omicron_tier = next(tier for tier in ability["tiers"] if tier["is_omicron"])
print(ability["unit_name"], ability["name"], OMICRON_MODE[ability["omicron_mode"]])
print(" ", omicron_tier["upgrade"])
Note
Names and descriptions come from the keys each ability record names, so a
reworked ability shows its current text rather than the original wording the
game keeps under the old key. skill.nameKey is not used: it is usually a
placeholder such as DEFENSE_UP_NAME_KEY.
get_unit_abilities(units, skills, abilities, localization=None, *, base_id=None, omicron_mode=None)
¶
List units' abilities with their name, kind, per-level text and zeta/omicron tiers.
Joins units -> skillReference -> skill -> abilityReference -> ability. Text is
read through the keys each ability record names, never derived from the ability id: after a
rework the game moves the ability to new _V<n> keys and keeps the old lines, so a derived key
returns the pre-rework text. For the same reason the name comes from ability.nameKey;
skill.nameKey is usually a placeholder such as DEFENSE_UP_NAME_KEY.
skill.tier[i] and ability.tier[i] describe the same upgrade, so whether a level is a zeta or
an omicron is read from the same index as its text.
A ship's crew abilities (units.crew[].skillReference) are included, with crew_base_id set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
units
|
list[dict[str, Any]]
|
The game data |
required |
skills
|
list[dict[str, Any]]
|
The game data |
required |
abilities
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
base_id
|
str | list[str] | None
|
Restrict to one unit or a list of units (case-insensitive). [Default: all] |
None
|
omicron_mode
|
int | str | list[int | str] | None
|
Restrict to abilities with an omicron in this mode or modes, e.g. |
None
|
Returns:
| Type | Description |
|---|---|
list[UnitAbility]
|
A list of :class: |
list[UnitAbility]
|
|
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list, |
Examples:
>>> game_data = comlink.get_game_data(items=DataItems.UNITS | DataItems.SKILL | DataItems.ABILITY)
>>> loc = get_localization_dictionary(comlink)
>>> tw_omicrons = get_unit_abilities(
... get_playable_units(game_data["units"]), game_data["skill"], game_data["ability"], loc,
... omicron_mode=8,
... )
UnitAbility
¶
Bases: TypedDict
A single unit ability as returned by :func:get_unit_abilities.
base_id
instance-attribute
¶
The unit the ability belongs to.
unit_name
instance-attribute
¶
Localized unit name, falling back to its nameKey.
crew_base_id
instance-attribute
¶
For a ship's crew ability, the crew member it comes from; otherwise None.
kind
instance-attribute
¶
"basic", "special", "unique", "leader", "hardware" or "contract".
description
instance-attribute
¶
The ability's level 1 description.
omicron_mode
instance-attribute
¶
The skill's omicronMode (see OMICRON_MODE), or None when it has no omicron tier.
AbilityTier
¶
Bases: TypedDict
One upgrade tier of a unit ability, as returned in :attr:UnitAbility.tiers.
get_named_effects¶
Maps every named buff and debuff (Potency Up, Fear, Overcharge, ...) to its in-game description. Useful for tooltips, help commands, or resolving an effect name a user typed.
from swgoh_comlink.helpers import get_localization_dictionary, get_named_effects
effects = get_named_effects(get_localization_dictionary(comlink))
print(effects["Potency Up"]["description"])
# Increased chance to apply detrimental effects
get_named_effects(localization)
¶
Map every named buff and debuff (Potency Up, Fear, Overcharge, ...) to its description.
A named effect is a localization value that opens with the effect's name in the game's colour markup
followed by a colon, e.g. [c][ffff33]Potency Up:[-][/c] Increased chance to apply detrimental
effects. Stat lines such as +15% Accuracy are excluded. Most effects are keyed
BattleEffect_*, but several core ones are not: Fear and Armor Shred are keyed
<NAME>_(DE)BUFF[_DESC][_V<n>], Demoralized only under its stack tiers
(DEMORALIZED_DEBUFF_TIER0...), and VIP and Insight under unit-specific keys. All of these are read.
When a name is defined more than once, the BattleEffect_ key and then the highest _V<n> wins.
The key conventions are language-independent, so any language's dictionary works; names are then in that language.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
localization
|
dict[str, str]
|
A localization dictionary, e.g. from :func: |
required |
Returns:
| Type | Description |
|---|---|
dict[str, NamedEffect]
|
A dictionary of effect name to :class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
NamedEffect
¶
Bases: TypedDict
A named buff or debuff as returned by :func:get_named_effects.
key
instance-attribute
¶
The localization key the definition was read from.
Item and Reward Helpers¶
Functions for naming the items that rewards, previews and inventories carry, and catalogs for game data whose names cannot be derived from their ids. These do not require a comlink instance.
ItemNames¶
Resolves an (ItemType, id) pair to a display name. Item ids are only unique within
an ItemType, so both are needed. ItemType may be a number (7) or an enum name
("MATERIAL"), so game data fetched with or without enums=True works.
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import DataItems, ItemNames, get_localization_dictionary
comlink = SwgohComlink()
game_data = comlink.get_game_data(
items=DataItems.MATERIAL
| DataItems.EQUIPMENT
| DataItems.UNITS
| DataItems.MYSTERY_STAT_MOD # also covers 'mysteryBox'
| DataItems.STAT_MOD_SET
| DataItems.PLAYER_TITLE
| DataItems.PLAYER_PORTRAIT
)
# enums is optional; with it, item types and currencies added to the game since
# this release are recognised. get_enums() fetches them once per game data version
# and caches them on the client as comlink.enums.
comlink.get_enums()
names = ItemNames(game_data, get_localization_dictionary(comlink), enums=comlink.enums)
names.get("MATERIAL", "unitshard_GLLEIA") # 'Leia Organa'
names.get(3, "GRIND") # 'Credits'
names.get(16, "35155") # '5-dot Defense Square mod (A)'
names.get(6, "") # None: XP names no particular item
Note
No game data collection names a currency, so currencies are named from
CURRENCY_NAMES, which is English whatever the localization. A currency it does
not list but get_enums() does is spelled out from its member name
(GUILD_RAID_CURRENCY_13 reads "Guild Raid Currency 13"). A mystery mod has
no name of its own and is described by what it rolls, in English with a
localized set name.
ItemNames
¶
Resolve (ItemType, id) pairs from rewards, previews and inventories to display names.
Item ids are only unique within an ItemType, so a name is looked up by both. Build one per game
data version and localization, then call :meth:get for as many items as needed; each collection is
indexed once and each name is localized only the first time it is asked for.
Which collection names each ItemType (pass the ones you need; the rest resolve to nothing):
UNIT:units. The id may carry a rarity, as inANAKINKNIGHT:ONE_STAR.CURRENCY: no collection. The id is theCurrencyTypename (or number), named fromCURRENCY_NAMES, which is English whatever the localization. ACurrencyTypemember missing from that table, such as a currency the game added since thatenumslists, is spelled out from its member name.MATERIAL:material. A unit shard (unitshard_<baseId>) is named by the unit: through the material's ownnameKey, which also covers event shard ids no unit has (such asunitshard_VADER_JKL_EVENT), then throughunits.EQUIPMENT:equipment.MYSTERY_BOX:mysteryBox, by itstitleKey.MYSTERY_STAT_MOD:mysteryStatModandstatModSet. A mystery mod has no name of its own, so it is described by what it rolls:"5-dot Speed Arrow mod (A)", with ranges such as"1-2-dot"and"E-D", andany-slotfor a mod that may land in any slot. The wording is English; the set name is localized.PLAYER_TITLE,PLAYER_PORTRAIT,ARTIFACT(a Conquest data disc) andLIGHTSPEED_TOKEN:playerTitle,playerPortrait,artifactDefinitionandlightspeedToken, always through the record's ownnameKey, since these names cannot be derived from their ids.
XP and the other ItemType values name no particular item and resolve to nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
game_data
|
Mapping[str, Any]
|
Game data collections keyed by collection name, such as the dictionary
|
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
enums
|
Mapping[str, Any] | None
|
Optional |
None
|
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
>>> game_data = comlink.get_game_data(items=DataItems.MATERIAL | DataItems.EQUIPMENT | DataItems.UNITS)
>>> comlink.get_enums() # cached on the client as comlink.enums
>>> names = ItemNames(game_data, get_localization_dictionary(comlink), enums=comlink.enums)
>>> names.get("MATERIAL", "unitshard_GLLEIA")
'Leia Organa'
>>> names.get(3, "GRIND")
'Credits'
item_type_number(item_type)
¶
Return the ItemType number of a type given as a number, a numeric string or a member name.
Returns None for a member name this instance's table does not list.
item_type_name(number)
¶
Return the ItemType member name for a number, or None when the table does not list it.
get(item_type, item_id, default=None)
¶
Return the display name of an item, or default when it cannot be resolved.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
item_type
|
int | str
|
The item's |
required |
item_id
|
str | int
|
The item's id. A currency may be given by its |
required |
default
|
str | None
|
Returned when the item cannot be named. [Default: |
None
|
Returns:
| Type | Description |
|---|---|
str | None
|
The item's display name, or |
get_named_rewards¶
Reads a reward preview list (a campaign mission's rewardPreview,
firstCompleteRewardPreview, instanceFirstCompleteRewardPreview or
conditionalRewardsPreview, or an event instance's rewardPreview) into named
rewards. Items of a conditionalRewardsPreview are nested one level down, under
bucketItem, and are listed with the requirement they depend on. A mission's rank
reward previews (rankRewardPreview, immediateRegularRankRewardPreview) are
not read: each of their entries is a rank range, so pass an entry's
detailedReward (or primaryReward) list instead.
from swgoh_comlink.helpers import get_named_rewards
game_data = comlink.get_game_data(items=DataItems.CAMPAIGN | DataItems.MATERIAL | DataItems.UNITS)
names = ItemNames(game_data, get_localization_dictionary(comlink))
events = next(c for c in game_data["campaign"] if c["id"] == "EVENTS")
for campaign_map in events["campaignMap"]:
for group in campaign_map["campaignNodeDifficultyGroup"]:
for node in group["campaignNode"]:
for mission in node["campaignNodeMission"]:
for reward in get_named_rewards(mission["conditionalRewardsPreview"], names):
print(node["id"], mission["id"], reward["name"], reward["max_quantity"])
get_named_rewards(rewards, item_names)
¶
Read a reward preview list into named rewards.
Takes any of a campaign mission's reward previews (rewardPreview, firstCompleteRewardPreview,
instanceFirstCompleteRewardPreview, conditionalRewardsPreview) or an event instance's
rewardPreview. A conditionalRewardsPreview entry does not hold an item itself: its items are
nested under bucketItem, paid while its requirementId holds (a Galactic Legend event's shards
until the tier's allotment is exhausted, for example). Those items are listed in their place, with
requirement_id set. Entries that are neither an item nor a bucket are skipped, as are entries and
bucket items that are not dictionaries.
A campaign mission's rank reward previews (rankRewardPreview,
immediateRegularRankRewardPreview) are not reward lists of this shape: each entry is a rank range
holding its items under primaryReward and detailedReward. Passed as a whole they read as
[]; pass an entry's detailedReward (or primaryReward) list instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rewards
|
list[dict[str, Any]]
|
A reward preview list. |
required |
item_names
|
ItemNames
|
An :class: |
required |
Returns:
| Type | Description |
|---|---|
list[NamedReward]
|
A list of :class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
>>> game_data = comlink.get_game_data(items=DataItems.CAMPAIGN | DataItems.MATERIAL | DataItems.UNITS)
>>> names = ItemNames(game_data, get_localization_dictionary(comlink))
>>> mission = game_data["campaign"][4]["campaignMap"][0]["campaignNodeDifficultyGroup"][0][
... "campaignNode"][0]["campaignNodeMission"][0]
>>> for reward in get_named_rewards(mission["rewardPreview"], names):
... print(reward["name"], reward["max_quantity"])
NamedReward
¶
Bases: TypedDict
A single reward item as returned by :func:get_named_rewards.
item_type
instance-attribute
¶
The ItemType number (see ITEM_TYPES, or the enums given to :class:ItemNames). An enum
name the table does not list is kept as given;
an item with no type has None.
name
instance-attribute
¶
Display name; the item id (or the ItemType name for an item with no id, or "" when it has
neither) when it cannot be resolved.
base_id
instance-attribute
¶
For a unit, its baseId; for a unit shard, the id after unitshard_, which is the unit's
baseId except for event shard variants such as VADER_JKL_EVENT. Otherwise None.
requirement_id
instance-attribute
¶
For an item of a conditionalRewardsPreview bucket, the requirement that must hold for it to be
paid; otherwise None.
get_mod_catalog¶
Recovers an equipped mod's set, slot and rarity from its definitionId, and each
set's name and how many mods complete it.
from swgoh_comlink.helpers import get_mod_catalog
game_data = comlink.get_game_data(items=DataItems.STAT_MOD_SET) # also covers 'statMod'
catalog = get_mod_catalog(game_data["statMod"], game_data["statModSet"], get_localization_dictionary(comlink))
player = comlink.get_player(allycode=123456789)
for equipped in player["rosterUnit"][0]["equippedStatMod"]:
mod = catalog["definitions"][equipped["definitionId"]]
print(mod["set_name"], mod["slot_name"], mod["rarity"], catalog["sets"][mod["set_id"]]["set_count"])
get_mod_catalog(stat_mods, stat_mod_sets, localization=None)
¶
Map mod definition ids to their set, slot and rarity, and mod sets to their name and set count.
An equipped mod names only its definitionId; its set, slot and rarity are not on the mod itself
and are recovered by joining the id to statMod. How many mods complete a set comes from
statModSet. Numbers are read whether the game data was fetched with or without enums=True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stat_mods
|
list[dict[str, Any]]
|
The game data |
required |
stat_mod_sets
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
ModCatalog
|
class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list or |
Examples:
ModCatalog
¶
ModSet
¶
Bases: TypedDict
A mod set as returned in :attr:ModCatalog.sets.
ModDefinition
¶
get_data_disc_names¶
get_data_disc_names(artifact_definitions, localization=None)
¶
Map every Conquest data disc's definition id to its name.
A Conquest payload names a data disc only by its definitionId, and the localization key cannot be
derived from it: keys carry typos the ids do not (artifact_guard_and_pentrate_3_cost_rare is keyed
ARTIFACT_GURAD_AND_PENTRATE_3_COST_RARE_NAME, and certain_defeat keys spell COSE for
COST), some drop the cost tier (artifact_evasive_technique_2_cost_common is
ARTIFACT_EVASIVE_TECHNIQUE_COMMON_NAME), some are _NAME_V2 variants, and a rarity may reuse
another rarity's key. So each artifactDefinition record is joined through its own nameKey.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
artifact_definitions
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A dictionary of definition id (as the game data spells it; some ids are mixed case) to name. A |
dict[str, str]
|
name the localization does not hold is returned as its |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
get_player_title_names¶
get_player_title_names(player_titles, localization=None)
¶
Map every player title id to its name.
A player profile names its titles only by id, and a title's name is usually unrelated to it: the id
records what earned the title (PLAYERTITLE_GRANDARENA_INTRO is "Fight Me"), so spelling out the
id is wrong for most titles. Nor can the localization key be derived from the id:
PLAYERTITLE_GLLEIA_EVENT is keyed PLAYERTITLE_LEIA_EVENT_NAME, some titles use _NAME_V2
keys, and the guild rank titles are keyed GuildMemberLevel_*. So each playerTitle record is
joined through its own nameKey.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
player_titles
|
list[dict[str, Any]]
|
The game data |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
A dictionary of title id to name. A name the localization does not hold is returned as its |
dict[str, str]
|
|
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
Upgrade Cost Helpers¶
Functions for working out what the game charges to take a unit up: the gear for each gear tier and the salvage it is crafted from, relic promotions, and ability upgrades with their zeta and omicron levels. These do not require a comlink instance.
Every cost is an UpgradeCost: credits, Ship Building Materials (ship_credits,
which ship abilities charge instead of credits), materials by material id, and gear
pieces by equipment id. sum_upgrade_costs adds any mix of them and, given the
equipment and recipe collections, crafts gear down to the salvage it is made from.
from swgoh_comlink import SwgohComlink
from swgoh_comlink.helpers import (
DataItems,
get_ability_upgrade_costs,
get_relic_promotion_costs,
get_unit_gear_tiers,
sum_upgrade_costs,
)
comlink = SwgohComlink()
# DataItems.TABLE (an alias of XP_TABLE) returns the 'table' collection as well as 'xpTable'
game_data = comlink.get_game_data(
items=DataItems.UNITS | DataItems.EQUIPMENT | DataItems.RECIPE | DataItems.SKILL | DataItems.TABLE
)
units, equipment, recipes = game_data["units"], game_data["equipment"], game_data["recipe"]
# G1 to G13: the pieces of tiers 1 to 12, crafted down to salvage
gear = get_unit_gear_tiers(units, "COMMANDERLUKESKYWALKER")
g13 = sum_upgrade_costs((tier["cost"] for tier in gear), equipment, recipes)
# R0 to R9: the first nine promotions
relics = get_relic_promotion_costs(game_data["table"], recipes)
r9 = sum_upgrade_costs(relic["cost"] for relic in relics[:9])
# Every ability to its maximum level
abilities = get_ability_upgrade_costs(units, game_data["skill"], recipes, "COMMANDERLUKESKYWALKER")
maxed = sum_upgrade_costs(tier["cost"] for ability in abilities for tier in ability["tiers"])
total = sum_upgrade_costs([g13, r9, maxed])
print(f"{total['credits']:,} credits", total["materials"], total["equipment"])
Note
Costs are exact or not reported: a recipe ingredient with a quantity range
(minQuantity differing from maxQuantity), a currency other than credits or Ship
Building Materials, or a missing recipe, piece or skill raises
SwgohComlinkValueError rather than being guessed at or skipped. Game data fetched
with enums=True works too.
get_unit_gear_tiers¶
get_unit_gear_tiers(units, base_id)
¶
List the gear a character slots at each gear tier.
Read from units.unitTier[].equipmentSet. A unit at tier n slots that tier's six pieces to
promote to n + 1, so taking a unit from G1 to G13 needs the pieces of tiers 1 to 12. Tier 13's
equipmentSet holds six "9999" placeholders, not real gear: it is returned with no pieces.
The pieces are listed as they are slotted. Pass the tiers' cost to :func:sum_upgrade_costs with
the equipment and recipe collections to get the salvage and credits needed to craft them.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
units
|
list[dict[str, Any]]
|
The game data |
required |
base_id
|
str
|
The character's base id (case-insensitive), e.g. |
required |
Returns:
| Type | Description |
|---|---|
list[GearTier]
|
A list of :class: |
list[GearTier]
|
empty list. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If |
Examples:
GearTier
¶
Bases: TypedDict
One gear tier of a character, as returned by :func:get_unit_gear_tiers.
tier
instance-attribute
¶
The gear tier the pieces are slotted at. Slotting all six promotes the unit to tier + 1.
equipment
instance-attribute
¶
Piece ids in slot order. Empty at tier 13, which slots nothing.
cost
instance-attribute
¶
The pieces as equipment counts. Slotting and promoting are free, so no credits.
get_gear_craft_tree¶
get_gear_craft_tree(equipment, recipes, equipment_id, localization=None)
¶
Expand a gear piece into its full craft tree, down to the pieces that are farmed rather than crafted.
Joins equipment.recipeId -> recipe.ingredients. A gear recipe consumes other pieces
(ingredient type 11, EQUIPMENT) and credits; a piece with no recipeId is a leaf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
equipment
|
list[dict[str, Any]]
|
The game data |
required |
recipes
|
list[dict[str, Any]]
|
The game data |
required |
equipment_id
|
str
|
The piece to expand, e.g. |
required |
localization
|
dict[str, str] | None
|
Optional localization dictionary, e.g. from :func: |
None
|
Returns:
| Type | Description |
|---|---|
GearCraftNode
|
The root :class: |
GearCraftNode
|
needed to craft the piece. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list, |
Examples:
GearCraftNode
¶
Bases: TypedDict
One piece in a gear craft tree, as returned by :func:get_gear_craft_tree.
name
instance-attribute
¶
Localized piece name, falling back to its nameKey.
tier
instance-attribute
¶
The piece's gear tier (equipment.tier).
mark
instance-attribute
¶
The piece's mark, e.g. "Mk XII".
quantity
instance-attribute
¶
How many of this piece the tree needs here: 1 at the root, and for an ingredient the recipe quantity
times its parent's quantity.
recipe_credits
instance-attribute
¶
Credits this piece's own recipe charges to craft one of it; 0 for a piece that is not crafted.
cost
instance-attribute
¶
Everything needed to make quantity of this piece from uncraftable pieces: their counts under
equipment and the crafting credits of every step.
ingredients
instance-attribute
¶
The pieces the recipe consumes, in recipe order. Empty for a piece that is farmed, not crafted.
get_relic_promotion_costs¶
get_relic_promotion_costs(tables, recipes)
¶
List the cost of each relic promotion.
The promotion recipes are named by the table collection's relic_promotion_table rows,
TIER_01 (R0 -> R1) to TIER_10 (R9 -> R10), on the player relic scale rather than the wire
relicTier one (see :func:convert_relic_tier). Each recipe charges credits and relic materials.
The table collection has no DataItems member of its own: DataItems.TABLE (an alias of
DataItems.XP_TABLE) returns both table and xpTable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tables
|
list[dict[str, Any]]
|
The game data |
required |
recipes
|
list[dict[str, Any]]
|
The game data |
required |
Returns:
| Type | Description |
|---|---|
list[RelicPromotionCost]
|
A list of :class: |
list[RelicPromotionCost]
|
func: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list, |
Examples:
RelicPromotionCost
¶
Bases: TypedDict
One relic promotion, as returned by :func:get_relic_promotion_costs.
relic_tier
instance-attribute
¶
The relic tier the promotion reaches, on the player scale (1 is R0 -> R1).
get_ability_upgrade_costs¶
get_ability_upgrade_costs(units, skills, recipes, base_id)
¶
List the upgrade cost of every level of a unit's abilities, with zeta and omicron levels flagged.
Joins units.skillReference -> skill.tier[].recipeId -> recipe. A ship's crew abilities
(units.crew[].skillReference) are included, with crew_base_id set. Ship abilities charge
Ship Building Materials, reported as ship_credits, rather than credits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
units
|
list[dict[str, Any]]
|
The game data |
required |
skills
|
list[dict[str, Any]]
|
The game data |
required |
recipes
|
list[dict[str, Any]]
|
The game data |
required |
base_id
|
str
|
The unit's base id (case-insensitive). |
required |
Returns:
| Type | Description |
|---|---|
list[AbilityUpgradeCosts]
|
A list of :class: |
list[AbilityUpgradeCosts]
|
crew abilities. Each lists its upgrades from level 2 up. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If a collection is not a list, |
Examples:
>>> game_data = comlink.get_game_data(items=DataItems.UNITS | DataItems.SKILL | DataItems.RECIPE)
>>> abilities = get_ability_upgrade_costs(
... game_data["units"], game_data["skill"], game_data["recipe"], "COMMANDERLUKESKYWALKER"
... )
>>> total = sum_upgrade_costs(tier["cost"] for ability in abilities for tier in ability["tiers"])
AbilityUpgradeCosts
¶
AbilityUpgradeTier
¶
Bases: TypedDict
One upgrade of an ability, as listed in :attr:AbilityUpgradeCosts.tiers.
level
instance-attribute
¶
The skill level this upgrade reaches. Level 1 is the base ability, so upgrades start at 2.
sum_upgrade_costs¶
sum_upgrade_costs(costs, equipment=None, recipes=None)
¶
Add up upgrade costs, optionally breaking gear down into the salvage it is crafted from.
Takes the cost of any mix of :class:GearTier, :class:RelicPromotionCost and
:class:AbilityUpgradeTier entries. Fields missing from a cost count as zero.
With both equipment and recipes, every craftable piece in the total is replaced by the pieces
its recipe consumes, all the way down, and the crafting credits are added; equipment in the result
then holds only pieces that are farmed rather than crafted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
costs
|
Iterable[Mapping[str, Any]]
|
The costs to add, e.g. |
required |
equipment
|
list[dict[str, Any]] | None
|
Optional game data |
None
|
recipes
|
list[dict[str, Any]] | None
|
Optional game data |
None
|
Returns:
| Type | Description |
|---|---|
UpgradeCost
|
The total as an :class: |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If only one of |
Examples:
>>> tiers = get_unit_gear_tiers(game_data["units"], "COMMANDERLUKESKYWALKER")
>>> g1_to_g13 = sum_upgrade_costs(
... (tier["cost"] for tier in tiers), game_data["equipment"], game_data["recipe"]
... )
>>> relics = get_relic_promotion_costs(game_data["table"], game_data["recipe"])
>>> r0_to_r9 = sum_upgrade_costs(relic["cost"] for relic in relics[:9])
UpgradeCost
¶
Bases: TypedDict
What an upgrade charges. Every helper in this module reports its costs in this shape.
credits
instance-attribute
¶
Credits (currency GRIND).
ship_credits
instance-attribute
¶
Ship Building Materials (currency SHIP_GRIND), which ship abilities charge instead of credits.
materials
instance-attribute
¶
material id -> quantity, e.g. ability materials and relic salvage.
equipment
instance-attribute
¶
equipment piece id -> quantity.
Omicron Helpers¶
Functions for querying omicron skill data from game data collections.
get_tw_omicrons¶
get_tw_omicrons(skill_list)
¶
Return a list of territory war omicrons
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill_list
|
list
|
List of character abilities/skills |
required |
Returns:
| Type | Description |
|---|---|
list[dict[str, Any]]
|
List of territory war omicron abilities |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If skill_list is not a list |
get_omicron_skills¶
get_omicron_skills(skill_list, omicron_type)
¶
Filters and retrieves omicron skills from a given skill list based on the specified omicron type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill_list
|
list
|
A list of dictionaries representing skills. The 'skill' collection in game data. |
required |
omicron_type
|
int | list
|
The omicron mode type to filter the skills by. The 'OmicronMode' in the game data enums. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
list |
list[dict[str, Any]]
|
A list of dictionaries representing skills that match the specified omicron type. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If either of the arguments is not of the expected type. |
get_omicron_skill_tier¶
get_omicron_skill_tier(skill)
¶
Return the omicron tier index for the given skill.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skill
|
dict
|
A dictionary representing the skill, containing a 'tier' key which holds a list of tier dictionaries. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int | None
|
The index of the Omicron skill tier within the 'tier' list or None if not found. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If the input 'skill' is not a dictionary. |
SwgohComlinkValueError
|
If the required 'tier' key is not present in the 'skill' dictionary. |
is_omicron_skill¶
is_omicron_skill(omicron_skill_list, skill_id=None, skill_tier=None, *, roster_unit_skill=None)
¶
Check if a given skill is an Omicron skill based on its ID and tier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
omicron_skill_list
|
list[dict]
|
List of skills from game data that have omicron tiers. |
required |
skill_id
|
str
|
ID of the skill to check. |
None
|
skill_tier
|
int
|
Tier index of the skill to check. |
None
|
roster_unit_skill
|
Optional[dict]
|
Optional dictionary containing the skill data for the roster unit. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the skill is an Omicron skill, False otherwise. |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If either of the arguments is not of the expected type. |
get_unit_from_skill¶
get_unit_from_skill(unit_list, skill)
¶
Extracts the base ID and name key of a unit from a list of units based on a specific skill.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit_list
|
list[dict]
|
The list of units to search within. |
required |
skill
|
str
|
The skill to search for in the 'skillReference' field of each unit. |
required |
Returns:
| Type | Description |
|---|---|
Unit | None
|
Unit | None: A |
Raises:
| Type | Description |
|---|---|
SwgohComlinkValueError
|
If 'unit_list' is not of type list. |
SwgohComlinkValueError
|
If 'skill' is not of type string. |
Localization Helpers¶
Utilities for working with the SWGOH client's BBCode-style markup that appears throughout localization bundles (ability descriptions, mod descriptions, event banners, etc.).
parse_swgoh_string¶
Parse a raw localization string and convert it to plain text, ANSI-colored
terminal output, Discord markdown, or HTML. The parser follows
NGUIText.ParseSymbol() semantics, so it handles the same tag family the game
engine itself supports.
from swgoh_comlink.helpers import parse_swgoh_string
raw = "[c][FF0000][b]Boss[/b][-] deals [u]2x[/u] damage[/c]"
parse_swgoh_string(raw) # 'Boss deals 2x damage'
parse_swgoh_string(raw, output="discord") # '**Boss** deals __2x__ damage'
parse_swgoh_string(raw, output="web") # HTML with <b>, <u>, <span style=...>
parse_swgoh_string(raw, output="terminal") # ANSI truecolor escapes
Supported markup:
| Tag(s) | Purpose |
|---|---|
[c] [/c] [-c] |
Optional color block wrapper |
[-] |
Reset the active color |
[RGB] / [RGBA] / [RRGGBB] / [RRGGBBAA] |
Hex color literal (short forms duplicate each nibble) |
[A] |
1-digit hex alpha (reuses the previous RGB or white) |
[b] [/b] / [i] [/i] |
Bold / italic |
[u] [/u] / [s] [/s] |
Underline / strikethrough |
[t] [/t] |
Sprite color marker (stripped in text output) |
[sub] [sub=X] [/sub] / [sup] [sup=X] [/sup] |
Subscript / superscript with optional scale |
[y=X] [/y] |
Font scaling (web output uses inline font-size) |
\n |
Literal backslash-n escape -> newline |
The [c]...[/c] wrapper is optional — bare [FF0000] takes effect on its
own, and [-] clears the active color whether or not you're inside a [c]
block.
parse_swgoh_string(text, output='bare')
¶
Parse a SWGOH BBCode-style rich text string and convert it to the specified output format.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Raw SWGOH localization string containing BBCode markup. |
required |
output
|
OutputFormat
|
One of 'terminal', 'discord', 'web', or 'bare'. [Default: 'bare'] |
'bare'
|
Returns:
| Type | Description |
|---|---|
str
|
A formatted string in the target format. |
Supported tags (parity with NGUIText.ParseSymbol):
[c] [/c] [-c] - Optional color block wrapper
[-] - Reset the active color
[RGB] [RGBA] - Short-form hex color (each nibble duplicated)
[RRGGBB] [RRGGBBAA] - Hex color (alpha defaults to FF when omitted)
[A] - 1-digit hex alpha (reuses previous RGB or white)
[b] [/b] - Bold
[i] [/i] - Italic
[u] [/u] - Underline
[s] [/s] - Strikethrough
[t] [/t] - Sprite color forcing (stripped in text output)
[sub] [sub=X] [/sub] - Subscript (optional font-size scale)
[sup] [sup=X] [/sup] - Superscript (optional font-size scale)
[y=X] [/y] - Font scaling
\n - Newline (literal backslash-n in source)
Notes
The [c]...[/c] wrapper is optional; bare color codes such as [FF0000]
take effect on their own. A [-] anywhere clears the active color.
Output formats
terminal - ANSI truecolor escape codes + SGR styles
discord - Discord markdown (bold, italic, underline, ~~strike~~)
web - HTML (, , , , , , )
bare - Plain text, all markup stripped
Decorators¶
func_timer¶
func_timer(func)
¶
Decorator to record total execution time of a function to the configured logger using level DEBUG.
func_debug_logger¶
func_debug_logger(func)
¶
Decorator for applying DEBUG logging to a function.
Sensitive keyword arguments (secret_key, access_key) are
automatically masked before being written to the log.
Stat Data Constants¶
Reference data dictionaries available as module-level exports. These are also
accessible via Constants for backward compatibility.
| Name | Description |
|---|---|
STAT_ENUMS |
Mapping of stat enum names to integer values |
UNIT_STAT_ENUMS_MAP |
Mapping of stat IDs to enum name and display name |
STATS |
Stat display names and formatting info |
MOD_SET_IDS |
Mod set type ID to name mapping |
MOD_SLOTS |
Mod slot ID to name mapping |
UNIT_RARITY |
Rarity integer to star count mapping |
UNIT_RARITY_NAMES |
Rarity integer to display name mapping |
LANGUAGES |
Supported game language codes |
OMICRON_MODE |
Omicron mode IDs to game mode names |
ITEM_TYPES |
ItemType number to enum member name (a snapshot of get_enums()) |
CURRENCY_TYPES |
CurrencyType number to enum member name (a snapshot of get_enums()) |
CURRENCY_NAMES |
CurrencyType member name to English display name |