Skip to content

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:

from swgoh_comlink.helpers import DataItems, Constants, sanitize_allycode

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 None if not found.

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 relic.currentTier, as an integer, a numeric string, or the enum name returned with enums=True (e.g. "RELIC_TIER_07").

required

Returns:

Type Description
str | None

"LOCKED", "UNLOCKED" (relic 0), the relic level as a string ("1" to "10"), or

str | None

None for an unrecognized value.

Raises:

Type Description
SwgohComlinkValueError

If the provided 'relic_tier' is not a string or integer.

Examples:

>>> convert_relic_tier(1)
'LOCKED'
>>> convert_relic_tier(2)
'UNLOCKED'
>>> convert_relic_tier(9)
'7'
>>> convert_relic_tier("RELIC_TIER_07")
'7'

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

("1.5" returns default).

Examples:

>>> as_int("1655938556")
1655938556
>>> as_int(None)
0
>>> as_int("", default=-1)
-1
>>> as_int(True)
0

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 str. [Default: ""]

''

Returns:

Type Description
str

value when it is a string, otherwise default.

Examples:

>>> as_str("Rebels")
'Rebels'
>>> as_str(42)
''

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 str nor an int. [Default: ""]

''

Returns:

Type Description
str

The id as a string.

Examples:

>>> as_id(2)
'2'
>>> as_id("O1700000000000:1")
'O1700000000000:1'
>>> as_id(None)
''

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 int or a str, otherwise None.

Examples:

>>> as_scalar(1)
1
>>> as_scalar("CHARACTER")
'CHARACTER'
>>> as_scalar(True) is None
True

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 None when value is missing, not

datetime | None

positive, unreadable, or past the year 9999.

Examples:

>>> as_epoch("1700000000000")
datetime.datetime(2023, 11, 14, 22, 13, 20, tzinfo=datetime.timezone.utc)
>>> as_epoch(1655938556)
datetime.datetime(2022, 6, 22, 22, 55, 56, tzinfo=datetime.timezone.utc)
>>> as_epoch("0") is None
True

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:

>>> as_list([{"id": "a"}, {"id": "b"}])
[{'id': 'a'}, {'id': 'b'}]
>>> as_list({"id": "a"})
[{'id': 'a'}]
>>> as_list(None)
[]

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 definitionId, unitIdentifier or game data unit id.

required

Returns:

Type Description
str

The part before the first colon, or "" when unit_identifier is not a string.

Examples:

>>> base_id("GENERALSKYWALKER:SEVEN_STAR")
'GENERALSKYWALKER'
>>> base_id("BOUSHH")
'BOUSHH'

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 get_enums() (e.g. comlink.get_enums()["CurrencyType"]).

required
enum_name str | None

The enum's type name (e.g. "CampaignNodeDifficulty"), checked against the first half of a decoder-style name. [Default: inferred from members when possible]

None

Returns:

Type Description
str | None

The member name as spelled in members, or None when value names no member or a

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:

>>> currency = {"CurrencyType_DEFAULT": 0, "GRIND": 1, "SHARD_CURRENCY": 16}
>>> parse_enum(16, currency)
'SHARD_CURRENCY'
>>> parse_enum("16", currency)
'SHARD_CURRENCY'
>>> parse_enum("CURRENCYTYPE_SHARDCURRENCY", currency)
'SHARD_CURRENCY'
>>> parse_enum("NEW_GRIND", currency) is None
True

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 localTimeZoneOffsetMinutes from get_player().

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 now, as a timezone-aware UTC datetime.

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)

get_current_gac_event(
    comlink: SwgohComlink,
) -> dict[str, Any]
get_current_gac_event(
    comlink: SwgohComlinkAsync,
) -> Coroutine[Any, Any, dict[str, Any]]

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:async_get_current_gac_event is returned for the caller to await.

required

Returns:

Type Description
dict[str, Any] | Coroutine[Any, Any, dict[str, Any]]

Current GAC event object, or an awaitable of it when comlink is a SwgohComlinkAsync

Raises:

Type Description
SwgohComlinkValueError

If no active GAC event is found

get_gac_brackets

get_gac_brackets(comlink, league, limit=0)

get_gac_brackets(
    comlink: SwgohComlink, league: str, limit: int = 0
) -> dict[int, Any]
get_gac_brackets(
    comlink: SwgohComlinkAsync, league: str, limit: int = 0
) -> Coroutine[Any, Any, dict[int, Any]]

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:async_get_gac_brackets is returned for the caller to await.

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 comlink is a SwgohComlinkAsync, an

dict[int, Any] | Coroutine[Any, Any, dict[int, Any]]

awaitable of that result.

Raises:

Type Description
SwgohComlinkValueError

If comlink or league is invalid, or no GAC event is running.

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 comlink or league is invalid, or no GAC event is running.

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 SwgohComlink.get_events(), or its gameEvent list.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, names are returned as their localization keys.

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:ScheduledEvent dictionaries: live events in gameEvent order, then upcoming

list[ScheduledEvent]

events soonest first.

Raises:

Type Description
SwgohComlinkValueError

If events is not a get_events() response or list, or localization is not a dictionary.

Examples:

>>> loc = get_localization_dictionary(comlink)
>>> for event in get_event_schedule(comlink.get_events(), loc):
...     print(event["status"], event["name"], event["end"])
live THE MANDALORIAN - Hero's Journey None

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)

get_guild_members(
    comlink: SwgohComlink,
    player_id: str | None = None,
    allycode: str | int | None = None,
) -> list[Any]
get_guild_members(
    comlink: SwgohComlinkAsync,
    player_id: str | None = None,
    allycode: str | int | None = None,
) -> Coroutine[Any, Any, list[Any]]

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:async_get_guild_members is returned for the caller to await.

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 comlink is a SwgohComlinkAsync

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 SwgohComlink.get_guild(..., include_recent_guild_activity_info=True). A response still wrapped as {"guild": {...}} is accepted.

required

Returns:

Name Type Description
A GuildActivity

class:GuildActivity dictionary. best_territory_battle is the recent battle with the most

GuildActivity

stars (the payload carries no all-time best); a Territory War is a win when score beats

GuildActivity

opponentScore, and a tie counts as neither; last_raid is the first recentRaidResult.

GuildActivity

Members are in payload order.

Raises:

Type Description
SwgohComlinkValueError

If guild is not a dictionary.

Examples:

>>> guild = comlink.get_guild(guild_id, include_recent_guild_activity_info=True)
>>> activity = get_guild_activity(guild)
>>> activity["territory_war_wins"], activity["territory_war_losses"]
(6, 2)

GuildActivity

Bases: TypedDict

A guild's recent activity as returned by :func:get_guild_activity.

best_territory_battle instance-attribute

The recent Territory Battle with the most stars, or None when there is none.

territory_wars instance-attribute

Recent Territory Wars, in payload order.

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

Bases: TypedDict

A completed Territory War, as returned in :attr:GuildActivity.territory_wars.

result instance-attribute

"win" when score is higher than opponent_score.

opponent_name instance-attribute

The opponent guild's name, when the payload carries its profile.

RaidResult

Bases: TypedDict

A guild's most recent raid, as returned in :attr:GuildActivity.last_raid.

raid_id instance-attribute

The raid's raidId, e.g. "order66" or "kraytdragon".

guild_score instance-attribute

The guild's guildRewardScore: the sum of every member's score.

member_scores instance-attribute

Player id to that member's memberProgress (score) in this 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 unitStamina entry from a player's Conquest status, with remainingStamina and, usually, lastRefreshTime.

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 now); compare it with now to get

datetime

the time remaining.

Raises:

Type Description
SwgohComlinkValueError

If unit is not a dictionary or has no valid remainingStamina.

Examples:

>>> from datetime import datetime, timezone
>>> unit = {"remainingStamina": 90, "lastRefreshTime": "1790164800"}
>>> calc_stamina_full_time(unit, now=datetime(2026, 9, 23, 13, tzinfo=timezone.utc))
datetime.datetime(2026, 9, 23, 17, 0, tzinfo=datetime.timezone.utc)

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 conquestDefinition collection.

required
challenges list[dict[str, Any]]

The game data challenge collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, names and descriptions are returned as their localization keys.

None
artifact_definitions list[dict[str, Any]] | None

Optional game data artifactDefinition collection, used to resolve reward artifact names.

None
conquest_id str | None

Conquest id (e.g. "CONQUEST_VOL25", case-insensitive). Game data has no event calendar, so this defaults to the newest conquest: the last conquestDefinition entry.

None
difficulty str | None

Restrict to "easy", "normal" or "hard" (case-insensitive). [Default: all]

None

Returns:

Type Description
list[ConquestFeat]

A list of :class:ConquestFeat dictionaries ordered by difficulty, then global feats before

list[ConquestFeat]

sector feats, then sector, feat kind and name.

Raises:

Type Description
SwgohComlinkValueError

If an argument is not a list, difficulty is not recognized, or conquest_id does not match any conquest definition.

Examples:

>>> 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",
... )

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 territoryBattleDefinition collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, zone names are returned as their localization keys.

None
tb_id str | None

Restrict to one Territory Battle by definition id (case-insensitive): "t01D" Hoth Rebel Assault, "t02D" Hoth Imperial Retaliation, "t03D" Geonosis Separatist Might, "t04D" Geonosis Republic Offensive or "t05D" Rise of the Empire. [Default: all]

None

Returns:

Type Description
list[TBZoneStars]

A list of :class:TBZoneStars dictionaries, in definition order.

Raises:

Type Description
SwgohComlinkValueError

If territory_battle_definitions is not a list of dictionaries, localization is not a dictionary, or tb_id does not match any definition.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.TERRITORY_BATTLE_DEFINITION)
>>> zones = get_tb_star_thresholds(game_data["territoryBattleDefinition"], tb_id="t05D")
>>> zones[0]["zone_id"], zones[0]["stars"]
('tb3_mixed_phase01_conflict01', [116406250, 186250000, 248333333])

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 territoryBattleDefinition collection.

required
campaigns list[dict[str, Any]]

The game data campaign collection.

required
categories list[dict[str, Any]]

The game data category collection, used to name the gate's categories.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, names and requirement text are returned as their localization keys.

None
tb_id str | None

Restrict to one Territory Battle by definition id (case-insensitive), as in :func:get_tb_star_thresholds. [Default: all]

None

Returns:

Type Description
list[TBMissionRequirement]

A list of :class:TBMissionRequirement dictionaries, in definition order with each definition's

list[TBMissionRequirement]

combat missions before its special missions.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list of dictionaries, localization is not a dictionary, or tb_id does not match any definition.

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 territoryBattleDefinition collection.

required
tables list[dict[str, Any]]

The game data table collection.

required
tb_id str | None

Restrict to one Territory Battle by definition id (case-insensitive), as in :func:get_tb_star_thresholds. [Default: all]

None

Returns:

Type Description
list[TBMissionScore]

A list of :class:TBMissionScore dictionaries, in definition order.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list of dictionaries, tb_id does not match any definition, or a mission names a table that is not in tables.

Examples:

>>> game_data = comlink.get_game_data(
...     items=DataItems.TERRITORY_BATTLE_DEFINITION | DataItems.TABLE
... )
>>> scores = get_tb_mission_scores(
...     game_data["territoryBattleDefinition"], game_data["table"], tb_id="t05D"
... )
>>> scores[0]["wave_points"]
[0, 100000, 200000]

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 territoryBattleDefinition collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, zone names are returned as their localization keys.

None
tb_id str | None

Restrict to one Territory Battle by definition id (case-insensitive), as in :func:get_tb_star_thresholds. [Default: all]

None

Returns:

Type Description
list[TBReconZone]

A list of :class:TBReconZone dictionaries, in definition order.

Raises:

Type Description
SwgohComlinkValueError

If territory_battle_definitions is not a list of dictionaries, localization is not a dictionary, or tb_id does not match any definition.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.TERRITORY_BATTLE_DEFINITION)
>>> zones = get_tb_platoon_definitions(game_data["territoryBattleDefinition"], tb_id="t05D")
>>> zones[0]["min_relic"], zones[0]["total_points"]
(5, 60000000)

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 campaign_data is not structured as expected, such as if it is not a list or contains improperly formatted elements.

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. "UNIT_REX_NAME") to the unit's name.

Examples:

>>> names = create_localized_unit_name_dictionary(locale)
>>> names[unit["nameKey"]]
'CT-7567 "Rex"'

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 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 total quantity and type, e.g. {"mat_id": {"quantity": 150, "type": 3}}.


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)

get_game_config(
    metadata: dict[str, Any] | list[dict[str, Any]],
    key: None = None,
) -> dict[str, str]
get_game_config(
    metadata: dict[str, Any] | list[dict[str, Any]],
    key: str,
) -> str | 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 SwgohComlink.get_game_metadata(), or its config list.

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 key, a dictionary of every configuration key to its string value. With a key, its

dict[str, str] | str | None

value, or None when the game metadata does not carry it. A key listed more than once keeps

dict[str, str] | str | None

its first value.

Raises:

Type Description
SwgohComlinkValueError

If metadata is not a get_game_metadata() response or its config list.

Examples:

>>> metadata = comlink.get_game_metadata()
>>> get_game_config(metadata, "max-conquest-currency")
'3500'
>>> get_game_config(metadata)["stat-mod-max-level"]
'15'

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 SwgohComlink.get_game_metadata(), or its config list.

required
key str

The configuration key, e.g. "stat-mod-max-storage".

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 default.

Raises:

Type Description
SwgohComlinkValueError

If metadata is not a get_game_metadata() response or its config list.

Examples:

>>> get_game_config_int(comlink.get_game_metadata(), "stat-mod-max-storage")
500

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 units collection. Each baseId is listed once, from its first row, so the raw per-rarity collection works; pass :func:get_playable_units output to leave out NPC and event units.

required
skills list[dict[str, Any]]

The game data skill collection.

required
abilities list[dict[str, Any]]

The game data ability collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, names and descriptions are returned as their localization keys.

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. 8 for Territory War (see OMICRON_MODE). Compared with the raw omicronMode value, so pass enum names when the game data was fetched with enums=True. [Default: all abilities]

None

Returns:

Type Description
list[UnitAbility]

A list of :class:UnitAbility dictionaries, in units order and then each unit's

list[UnitAbility]

skillReference order, followed by its crew abilities.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list, localization is not a dictionary, or a filter has the wrong type.

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.

level instance-attribute

The skill level this tier upgrades to. Level 1 is the base ability, so tiers start at 2.

description instance-attribute

The ability's full description at this level.

upgrade instance-attribute

What this tier adds, e.g. "+5% Damage" or the omicron's effect text.

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:get_localization_dictionary.

required

Returns:

Type Description
dict[str, NamedEffect]

A dictionary of effect name to :class:NamedEffect, sorted by name.

Raises:

Type Description
SwgohComlinkValueError

If localization is not a dictionary.

Examples:

>>> effects = get_named_effects(get_localization_dictionary(comlink))
>>> effects["Potency Up"]["description"]
'Increased chance to apply detrimental effects'

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 in ANAKINKNIGHT:ONE_STAR.
  • CURRENCY: no collection. The id is the CurrencyType name (or number), named from CURRENCY_NAMES, which is English whatever the localization. A CurrencyType member missing from that table, such as a currency the game added since that enums lists, is spelled out from its member name.
  • MATERIAL: material. A unit shard (unitshard_<baseId>) is named by the unit: through the material's own nameKey, which also covers event shard ids no unit has (such as unitshard_VADER_JKL_EVENT), then through units.
  • EQUIPMENT: equipment.
  • MYSTERY_BOX: mysteryBox, by its titleKey.
  • MYSTERY_STAT_MOD: mysteryStatMod and statModSet. 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", and any-slot for 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) and LIGHTSPEED_TOKEN: playerTitle, playerPortrait, artifactDefinition and lightspeedToken, always through the record's own nameKey, 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 get_game_data returns.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, names are returned as their localization keys.

None
enums Mapping[str, Any] | None

Optional get_enums() response. Its ItemType and CurrencyType tables are used in place of the ITEM_TYPES and CURRENCY_TYPES snapshots, so item types and currencies the game has added since are recognised. [Default: the bundled snapshots]

None

Raises:

Type Description
SwgohComlinkValueError

If game_data is not a dictionary, one of the collections it reads is not a list, localization is not a dictionary, or enums (or one of the two groups it reads) is not a dictionary.

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 ItemType, as a number (7) or an enum name ("MATERIAL").

required
item_id str | int

The item's id. A currency may be given by its CurrencyType number.

required
default str | None

Returned when the item cannot be named. [Default: None]

None

Returns:

Type Description
str | None

The item's display name, or default.

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:ItemNames built from the game data the rewards come from.

required

Returns:

Type Description
list[NamedReward]

A list of :class:NamedReward dictionaries in preview order.

Raises:

Type Description
SwgohComlinkValueError

If rewards is not a list or item_names is not an :class:ItemNames.

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 statMod collection.

required
stat_mod_sets list[dict[str, Any]]

The game data statModSet collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, or when it has no name for a set, set names are the English names from MOD_SET_IDS.

None

Returns:

Name Type Description
A ModCatalog

class:ModCatalog dictionary. Slot names come from MOD_SLOTS.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list or localization is not a dictionary.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.STAT_MOD)
>>> catalog = get_mod_catalog(game_data["statMod"], game_data["statModSet"])
>>> mod = catalog["definitions"]["451"]
>>> mod["set_name"], mod["slot_name"], mod["rarity"]
('Speed', 'Square', 5)

ModCatalog

Bases: TypedDict

The mod catalog returned by :func:get_mod_catalog.

sets instance-attribute

Set id to :class:ModSet.

definitions instance-attribute

Mod definitionId to :class:ModDefinition.

ModSet

Bases: TypedDict

A mod set as returned in :attr:ModCatalog.sets.

name instance-attribute

Localized set name. Without a localization string it is the English name from MOD_SET_IDS.

set_count instance-attribute

How many mods of the set complete its bonus: 4 for Speed, Offense and Critical Damage, 2 otherwise.

ModDefinition

Bases: TypedDict

A mod definition as returned in :attr:ModCatalog.definitions.

slot instance-attribute

StatModSlot number, 2 (Square) to 7 (Cross); see MOD_SLOTS.

rarity instance-attribute

The mod's dots (pips), 1 to 6.

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 artifactDefinition collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, the nameKey is returned in place of the name, which makes this the id to localization key join.

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 nameKey.

Raises:

Type Description
SwgohComlinkValueError

If artifact_definitions is not a list or localization is not a dictionary.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.CONQUEST)
>>> discs = get_data_disc_names(game_data["artifactDefinition"], get_localization_dictionary(comlink))

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 playerTitle collection.

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, the nameKey is returned in place of the name, which makes this the id to localization key join.

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]

nameKey.

Raises:

Type Description
SwgohComlinkValueError

If player_titles is not a list or localization is not a dictionary.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.PLAYER_TITLE)
>>> titles = get_player_title_names(game_data["playerTitle"], get_localization_dictionary(comlink))
>>> titles["PLAYERTITLE_GRANDARENA_INTRO"]
'Fight Me'

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 units collection. The first row for base_id is used, so the raw per-rarity collection works.

required
base_id str

The character's base id (case-insensitive), e.g. "COMMANDERLUKESKYWALKER".

required

Returns:

Type Description
list[GearTier]

A list of :class:GearTier dictionaries, tier 1 first. Ships have no gear, so a ship returns an

list[GearTier]

empty list.

Raises:

Type Description
SwgohComlinkValueError

If units is not a list, base_id is not a string or is not in units, or a unitTier has a tier that is not a number or UnitTier name.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.UNITS)
>>> tiers = get_unit_gear_tiers(game_data["units"], "COMMANDERLUKESKYWALKER")
>>> tiers[0]["equipment"]
['001', '006', '005', '010', '003', '006']

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 equipment collection.

required
recipes list[dict[str, Any]]

The game data recipe collection.

required
equipment_id str

The piece to expand, e.g. "164".

required
localization dict[str, str] | None

Optional localization dictionary, e.g. from :func:get_localization_dictionary. When omitted, names are returned as their localization keys.

None

Returns:

Type Description
GearCraftNode

The root :class:GearCraftNode (quantity 1). Its cost is the total salvage and credits

GearCraftNode

needed to craft the piece.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list, localization is not a dictionary, a piece or recipe in the tree is missing or a piece's tier is not a number or UnitTier name, or a recipe has an ingredient that is not exact or is of a kind a gear recipe should not hold.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.EQUIPMENT | DataItems.RECIPE)
>>> loc = get_localization_dictionary(comlink)
>>> tree = get_gear_craft_tree(game_data["equipment"], game_data["recipe"], "164", loc)
>>> tree["cost"]["credits"]
44650

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 table collection.

required
recipes list[dict[str, Any]]

The game data recipe collection.

required

Returns:

Type Description
list[RelicPromotionCost]

A list of :class:RelicPromotionCost dictionaries, R1 first. Sum a slice of them with

list[RelicPromotionCost]

func:sum_upgrade_costs, e.g. costs[:9] for R0 to R9.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list, relic_promotion_table is missing or its rows are not TIER_01 to TIER_<n>, or a recipe is missing or not exact.

Examples:

>>> game_data = comlink.get_game_data(items=DataItems.TABLE | DataItems.RECIPE)
>>> relics = get_relic_promotion_costs(game_data["table"], game_data["recipe"])
>>> relics[0]["cost"]
{'credits': 10000, 'ship_credits': 0, 'materials': {'SCV_001': 40}, 'equipment': {}}

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 units collection. The first row for base_id is used, so the raw per-rarity collection works.

required
skills list[dict[str, Any]]

The game data skill collection.

required
recipes list[dict[str, Any]]

The game data recipe collection.

required
base_id str

The unit's base id (case-insensitive).

required

Returns:

Type Description
list[AbilityUpgradeCosts]

A list of :class:AbilityUpgradeCosts dictionaries in skillReference order, followed by any

list[AbilityUpgradeCosts]

crew abilities. Each lists its upgrades from level 2 up.

Raises:

Type Description
SwgohComlinkValueError

If a collection is not a list, base_id is not a string or is not in units, a skill or recipe the unit names is missing, or a recipe is not exact.

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

Bases: TypedDict

A unit ability's upgrade costs, as returned by :func:get_ability_upgrade_costs.

base_id instance-attribute

The unit the ability belongs to.

crew_base_id instance-attribute

For a ship's crew ability, the crew member it comes from; otherwise None.

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. tier["cost"] for tier in gear_tiers[:12].

required
equipment list[dict[str, Any]] | None

Optional game data equipment collection, to craft gear down to salvage.

None
recipes list[dict[str, Any]] | None

Optional game data recipe collection, to craft gear down to salvage.

None

Returns:

Type Description
UpgradeCost

The total as an :class:UpgradeCost, with materials and equipment sorted by id.

Raises:

Type Description
SwgohComlinkValueError

If only one of equipment and recipes is given, either is not a list, a cost is not a mapping, or crafting meets a missing piece or recipe or an ingredient that is not exact.

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 Unit named tuple with the 'baseId' and 'nameKey' of the first unit that matches the specified skill, or None if no such unit is found.

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