Appendix

Cacher

class circleguard.cacher.Cacher(cache, path)[source]

Handles compressing and caching replay data to a database.

Parameters:
  • cache (bool) – Whether or not replays should be cached.
  • path (str or os.PathLike) – The absolute path to the database. If the path does not exist, a fresh database will be created there.

Notes

Each Cacher instance maintains its own database connection.

cache(lzma_bytes, replay_info)[source]

Caches a replay in the form of a (compressed) lzma stream to the database, linking it to the replay info.

Parameters:
  • map_id (str) – The map id to insert into the db.
  • lzma_bytes (str) – The lzma stream to compress and insert into the db.
  • replay_info (ReplayInfo) – The ReplayInfo object representing this replay.

Notes

If an entry with the given replay info already exists, it is overwritten by the passed lzma.

The lzma string is compressed with wtc compression. See _compress() and wtc.compress() for more.

A call to this method has no effect if the Cacher’s should_cache is False.

revalidate(loader, replay_info)[source]

Checks entries in replay_info against their entries in the database (if any) to look for score id mismatches, indicating an outdated replay. If there are mismatches, the replay is redownloaded and cached from the replay info.

Parameters:
  • loader (Loader) – The Loader from the circleguard instance to redownload replays with if they are outdated.
  • replay_info (list[ReplayInfo]) – A list of ReplayInfo objects containing the up-to-date information of user’s replays.
Raises:

CircleguardException – Raised when the redownloaded replay id is lower than the cached replay id. This should never happen and is indicative of either a fault on our end or the api’s end.

Also raised if the replay data is not available from the api when redownloaded.

Notes

If the replay is found to be outdated, it will be overwritten by the newer replay in the database.

check_cache(map_id, user_id, mods)[source]

Checks the cache for a replay described by the parameters, and returns its data if the cache contains the replay.

Parameters:
  • map_id (int) – The id of the map the replay was played on.
  • user_id (int) – The id of the user that played the replay.
  • mods (ModCombination) – The mods this replay was played with.
Returns:

The replay data in decompressed lzma form if the cache contains the replay, or None if not.

Return type:

str or None

Circleguard

class circleguard.circleguard.Circleguard(key, db_path=None, slider_dir=None, loader=None, cache=True)[source]

Circleguard investigates replays for cheats.

Parameters:
  • key (str) – A valid api key. Can be retrieved from https://osu.ppy.sh/p/api/.
  • db_path (str or os.PathLike) – The path to the database file to read and write cached replays. If the path does not exist, a fresh database will be created there. If None, no replays will be cached or loaded from cache.
  • slider_dir (str or os.PathLike) – The path to the directory used by slider.library.Library to store beatmaps. If None, a temporary directory will be created for slider.library.Library and subsequently destroyed when this Circleguard object is garbage collected.
  • loader (Loader) – This loader will be used instead of the base loader if passed. This must be the class itself, not an instantiation of it. It will be with two args - a key and a cacher.
run(loadables, detect, loadables2=None, max_angle=10, min_distance=8) → Iterable[circleguard.result.Result][source]

Investigates loadables for cheats.

Parameters:
  • loadables (list[Loadable]) – The loadables to investigate.
  • detect (Detect) – What cheats to investigate for.
  • loadables2 (list[Loadable]) – For STEAL, compare each loadable in loadables against each loadable in loadables2 for replay stealing, instead of to other loadables in loadables.
  • max_angle (float) – For Detect.CORRECTION, consider only points (a,b,c) where ∠abc < max_angle.
  • min_distance (float) – For Detect.CORRECTION, consider only points (a,b,c) where |ab| > min_distance and |bc| > min_distance.
Yields:

Result – A result representing an investigation of one or more of the replays in loadables, depending on the detect passed.

Notes

Results are yielded one at a time, as circleguard finishes investigating them. This means that you can process results from run() without waiting for all of the investigations to finish.

steal_check(loadables, loadables2=None, method=<Detect.STEAL_SIM: 1>) → Iterable[circleguard.result.StealResult][source]

Investigates loadables for replay stealing.

Parameters:
  • loadables (list[Loadable]) – The loadables to investigate.
  • loadables2 (list[Loadable]) – If passed, compare each loadable in loadables against each loadable in loadables2 for replay stealing, instead of to other loadables in loadables.
  • method (:class`~.Detect`) – What method to use to investigate the loadables for replay stealing. This should be one of Detect.STEAL_SIM or Detect.STEAL_CORR, or both (or’d together).
Yields:

StealResult – A result representing a replay stealing investigtion into a pair of loadables from loadables and/or loadables2.

relax_check(loadables) → Iterable[circleguard.result.RelaxResult][source]

Investigates loadables for relax.

Parameters:loadables (list[Loadable]) – The loadables to investigate.
Yields:RelaxResult – A result representing a relax investigation into a loadable from loadables.
correction_check(loadables, max_angle=10, min_distance=8) → Iterable[circleguard.result.CorrectionResult][source]

Investigates loadables for aim correction.

Parameters:loadables (list[Loadable]) – The loadables to investigate.
Yields:CorrectionResult – A result representing an aim correction investigation into a loadable from loadables.
load(loadable)[source]

Loads a loadable.

Parameters:loadable (Loadable) – The loadable to load.

Notes

This is identical to calling loadable.load(cg.loader).

load_info(loadable_container)[source]

Loads a loadable container.

Parameters:loadable (LoadableContainer) – The loadable container to load.

Notes

This is identical to calling loadable_container.load_info(cg.loader).

set_options(cache=None)[source]

Sets options for this instance of circlecore.

Parameters:cache (bool) – Whether to cache loaded loadables.
circleguard.circleguard.set_options(loglevel=None)[source]

Set global options for circlecore.

Parameters:logevel (int) – What level to log at. Circlecore follows standard python logging levels, with an added level of TRACE with a value of 5 (lower than debug, which is 10). The value passed to loglevel is passed directly to the setLevel function of the circleguard root logger. WARNING by default. For more information on log levels, see the standard python logging lib.

Comparer

class circleguard.comparer.Comparer(replays1, replays2, detect)[source]

Manages comparing Replays for replay stealing.

Parameters:
  • replays1 (list[Replay]) – The replays to compare against either replays2 if replays2 is not None, or against other replays in replays1.
  • replays2 (list[Replay]) – The replays to compare against replays1.

Notes

If replays2 is passed, each replay in replays1 is compared against each replay in replays2. Otherwise, each replay in replays1 is compared against each other replay in replays1 (len(replays1) choose 2 comparisons).

The order of replays1 and replays2 has no effect; comparing 1 to 2 is the same as comparing 2 to 1.

See also

Investigator, for investigating single replays.

compare()[source]

If replays2 is not None, compares all replays in replays1 against all replays in replays2. Otherwise, compares all replays in replays1 against all other replays in replays1 (len(replays1) choose 2 comparisons).

Yields:ComparisonResult – Results representing the comparison of two replays.
compare_two_replays(replay1, replay2)[source]

Compares two Replays.

Parameters:
  • replay1 (Replay) – The first replay to compare.
  • replay2 (Replay) – The second replay to compare.
Returns:

The result of comparing replay1 to replay2.

Return type:

ComparisonResult

static compute_similarity(xy1, xy2)[source]

Calculates the average distance between two sets of cursor position data.

Parameters:
  • replay1 (ndarray) – The first xy data to compare.
  • replay2 (ndarray) – The second xy data to compare.
Returns:

The mean distance between the two datasets.

Return type:

float

static interpolate(t1, t2, xy1, xy2)[source]

Interpolates the xy data of the shorter replay to the longer replay.

Returns:The interpolated replay data of the first and second replay respectively.
Return type:(ndarray, ndarray)

Notes

The length of the two returned arrays will be equal. This is a (desired) side effect of interpolating.

static clean(xy1, xy2)[source]

Cleans the given xy data to only include indices where both coordinates are inside the osu gameplay window (a 512 by 384 osu!pixel window).

Warning

The length of the two passed arrays must be equal.

Enums

class circleguard.enums.Error[source]

An enumeration.

NO_REPLAY = ['Replay not available.', <class 'circleguard.exceptions.ReplayUnavailableException'>, 'Could not find any replay data. Skipping']
RATELIMITED = ["Requesting too fast! Slow your operation, cap'n!", <class 'circleguard.exceptions.RatelimitException'>, 'We were ratelimited. Waiting it out']
RETRIEVAL_FAILED = ['Replay retrieval failed.', <class 'circleguard.exceptions.ReplayUnavailableException'>, 'Replay retrieval failed. Skipping']
INVALID_KEY = ['Please provide a valid API key.', <class 'circleguard.exceptions.InvalidKeyException'>, 'Please provide a valid api key']
INVALID_JSON = ['The api broke.', <class 'circleguard.exceptions.InvalidJSONException'>, 'The api returned an invalid json response, retrying']
UNKNOWN = ['Unknown error.', <class 'circleguard.exceptions.UnknownAPIException'>, 'Unknown error when requesting a replay. Please report this to the developers at https://github.com/circleguard/circlecore']
class circleguard.enums.RatelimitWeight[source]

How much it ‘costs’ to load a replay from the api.

NONE if the load method of a replay makes no api calls.

LIGHT if the load method of a replay makes only light api calls (anything but get_replay).

HEAVY if the load method of a replay makes any heavy api calls (get_replay).

Notes

This value currently has no effect on the program and is reserved for future functionality.

NONE = 'None'
LIGHT = 'Light'
HEAVY = 'Heavy'
class circleguard.enums.Detect[source]

A cheat, or set of cheats, to investigate for.

Notes

Also defines thresholds we feel are reasonable to determine a replay as cheated. These values are more conservative - that is, we try to not give false positives. You should decide where you fall on the scale of “few false positives, many false negatives” to “many false positives, few false negatives” for yourself, if necessary.

STEAL_SIM = 1
STEAL_CORR = 8
RELAX = 2
CORRECTION = 4
ALL = 15
STEAL = 1
SIM_LIMIT = 17
CORR_LIMIT = 0
UR_LIMIT = 50
class circleguard.enums.ResultType[source]

What type of cheat test to represent the results for.

STEAL = 'Replay Stealing'
REMOD = 'Remodding'
RELAX = 'Relax'
CORRECTION = 'Aim Correction'
TIMEWARP = 'Timewarp'
class circleguard.enums.Key[source]

An enumeration.

M1 = 1
M2 = 2
K1 = 4
K2 = 8
SMOKE = 16

Exceptions

exception circleguard.exceptions.CircleguardException[source]

Base class for exceptions in the circleguard program.

exception circleguard.exceptions.InvalidArgumentsException[source]

Indicates an invalid argument was passed to one of the flags.

exception circleguard.exceptions.APIException[source]

Indicates an error involving the API, which may or may not be fatal.

UnknownAPIExceptions are considered fatal, InternalAPIExceptions are not.

exception circleguard.exceptions.NoInfoAvailableException[source]

Indicates that the API returned no information for the given arguments

exception circleguard.exceptions.UnknownAPIException[source]

Indicates some error on the API’s end that we were not prepared to handle.

exception circleguard.exceptions.InternalAPIException[source]

Indicates a response from the API that we know how to handle.

exception circleguard.exceptions.InvalidKeyException[source]

Indicates that an api key was rejected by the api.

exception circleguard.exceptions.RatelimitException[source]

Indicates that our key has been ratelimited and we should retry the request at a later date.

exception circleguard.exceptions.InvalidJSONException[source]

Indicates that the api returned an invalid json response, and we should retry the request.

exception circleguard.exceptions.ReplayUnavailableException[source]

Indicates that we expected a replay from the api but it was not able to deliver it.

Investigator

class circleguard.investigator.Investigator(replay, detect, max_angle, min_distance, beatmap=None)[source]

Manages the investigation of individual Replays for cheats.

Parameters:
  • replay (Replay) – The replay to investigate.
  • detect (Detect) – What cheats to investigate the replay for.
  • beatmap (slider.beatmap.Beatmap) – The beatmap to calculate ur from, with the replay. Should be None if Detect.RELAX in detect is False.

See also

Comparer, for comparing multiple replays.

static ur(replay, beatmap)[source]

Calculates the ur of replay when played against beatmap.

static aim_correction(replay, max_angle, min_distance)[source]

Calculates the angle between each set of three points (a,b,c) and finds points where this angle is extremely acute and neither |ab| or |bc| are small.

Parameters:
  • replay (Replay) – The replay to investigate for aim correction.
  • max_angle (float) – Consider only (a,b,c) where ∠abc < max_angle
  • min_distance (float) – Consider only (a,b,c) where |ab| > min_distance and |ab| > min_distance.
Returns:

Hits where the angle was less than max_angle and the distance was more than min_distance.

Return type:

list[Snap]

Notes

This does not detect correction where multiple datapoints are placed at the correction site (which creates a small min_distance).

Another possible method is to look at the ratio between the angle and distance.

See also

aim_correction_sam() for an alternative, unused approach involving velocity and jerk.

static aim_correction_sam(replay_data, num_jerks, min_jerk)[source]

Calculates the jerk at each moment in the Replay, counts the number of times it exceeds min_jerk and reports a positive if that number is over num_jerks. Also reports all suspicious jerks and their timestamps.

Warning

Unused function. Kept for historical purposes and ease of viewing in case we want to switch to this track of aim correction in the future, or provide it as an alternative.

class circleguard.investigator.Snap(time, angle, distance)[source]

A suspicious hit in a replay, specifically so because it snaps away from the otherwise normal path. Snaps currently represent the middle datapoint in a set of three replay datapoints.

Parameters:
  • time (int) – The time value of the middle datapoint, in ms. 0 represents the beginning of the replay.
  • angle (float) – The angle between the three datapoints.
  • distance (float) – min(dist_a_b, dist_b_c) if a, b, and c are three datapoints with b being the middle one.

See also

aim_correction()

Loadable

class circleguard.loadable.Loadable(cache)[source]

Represents one or multiple replays, which have replay data to be loaded from some additional source - the osu! api, local cache, or some other location.

Parameters:cache (bool) – Whether to cache the replay data once loaded.
load(loader, cache)[source]

Loads the information this loadable needs to become fully loaded. Details left to the subclass implementation.

Parameters:
  • loader (Loader) – The loader to load this loadable with. Although subclasses may not end up using a Loader to load themselves (if they don’t load anything from the osu api, for instance), a loader is still passed regardless.
  • cache (bool) – Whether to cache the replay data once loaded. This argument comes from a parent—either a LoadableContainer or Circleguard itself. Should the loadable already have a set cache value, that should take precedence over the option passed in this method, but if the loadable has no preference then it should respect the value passed here.
class circleguard.loadable.LoadableContainer(cache)[source]

A loadable which contains other loadables. This means that it has three stages - unloaded, info loaded, and loaded.

When info loaded, the LoadableContainer has Loadables but they are unloaded.

When loaded, the LoadableContainer has loaded Loadables.

load(loader, cache=None)[source]

Loads all Loadables contained by this loadable container.

Parameters:loader (Loader) – The loader to load the Loadables with.
all_replays()[source]

Returns all the Replays in this loadable container.

Warning

If you want an accurate list of Replays in this instance, you must call load() on this instance before all_replays(). Otherwise, this instance is not info loaded, and does not have a complete list of replays it represents.

class circleguard.loadable.ReplayContainer(cache)[source]

A LoadableContainer that only holds Replays and subclasses thereof.

ReplayContainer’s start unloaded and become info loaded when load_info() is called. They become fully loaded when load() is called (and if this is called when the ReplayContainer is in the unloaded state, load() will load info first, then load the replays.)

In the unloaded state, the container has no actual Replay objects. It may have limited knowledge about their number or type.

In the info loaded state, the container has references to Replay objects, but those Replay objects are unloaded.

In the loaded state, the Replay objects are loaded.

class circleguard.loadable.Check(loadables, cache, loadables2=None)[source]

Organizes Loadables and what to investigate them for.

Parameters:
  • loadables (list[Loadable]) – The loadables to hold for investigation.
  • cache (bool) – Whether to cache the loadables once they are loaded. This will be overriden by a cache option set by a Loadable in loadables. It only affects children loadables when they do not have a cache option set.
  • loadables2 (list[Loadable]) – A second set of loadables to hold. Useful for partitioning loadables for a replay stealing investigations.
all_loadables()[source]

Returns all the Loadables contained by this check.

Returns:All the loadables in this check.
Return type:list[Loadable]

See also

all_replays().

Notes

Loadables are very different from Replays - len(check.all_loadables()) will not return the number of replays in the check, for instance.

all_replays()[source]

Returns all the Replays in this check. Contrast with all_loadables(), which returns all the Loadables in this check.

Returns:All the replays in this check.
Return type:list[Replay]
all_replays1()[source]

Returns all the Replays contained by loadables1 of this check.

Returns:All the replays contained by loadables1 of this check.
Return type:list[Replay]
all_replays2()[source]

Returns all the Replays contained by loadables2 of this check.

Returns:All the replays contained by loadables2 of this check.
Return type:list[Replay]
class circleguard.loadable.Map(map_id, span, mods=None, cache=None)[source]

A map’s top plays (leaderboard), as seen on the website.

Parameters:
  • map_id (int) – The map to represent the top plays for.
  • span (str or Span) – A comma separated list of ranges of top plays to retrieve. span="1-3,6,2-4" -> replays in the range [1,2,3,4,6].
  • mods (ModCombination) – If passed, only represent replays played with this exact mod combination. Due to limitations with the api, fuzzy matching is not implemented. <br> This is applied before span``. That is, if span="1-2" and mods=Mod.HD, the top two HD plays on the map are represented.
  • cache (bool) – Whether to cache the replays once they are loaded.
all_replays()[source]

Returns all the Replays in this loadable container.

Warning

If you want an accurate list of Replays in this instance, you must call load() on this instance before all_replays(). Otherwise, this instance is not info loaded, and does not have a complete list of replays it represents.

class circleguard.loadable.User(user_id, span, mods=None, cache=None, available_only=True)[source]

A user’s top plays (pp-wise, as seen on the website).

Parameters:
  • user_id (int) – The user to represent the top plays for.
  • span (str or Span) – A comma separated list of ranges of top plays to retrieve. span="1-3,6,2-4" -> replays in the range [1,2,3,4,6].
  • mods (ModCombination) – If passed, only represent replays played with this exact mod combination. Due to limitations with the api, fuzzy matching is not implemented. <br> This is applied before span. That is, if span="1-2" and mods=Mod.HD, the user’s top two HD plays are represented.
  • cache (bool) – Whether to cache the replays once they are loaded.
  • available_only (bool) – Whether to represent only replays that have replay data available. Replays are filtered on this basis after mods and span are applied. True by default.
all_replays()[source]

Returns all the Replays in this loadable container.

Warning

If you want an accurate list of Replays in this instance, you must call load() on this instance before all_replays(). Otherwise, this instance is not info loaded, and does not have a complete list of replays it represents.

class circleguard.loadable.MapUser(map_id, user_id, span={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100}, cache=None, available_only=True)[source]

All replays on a map by a user, not just the top replay.

Parameters:
  • map_id (int) – The map to represent scores by user_id on.
  • user_id (int) – The user to represent scores on map_id for.
  • span (str or Span) – A comma separated list of ranges of plays to retrieve. span="1-3,6,2-4" -> replays in the range [1,2,3,4,6].
  • cache (bool) – Whether to cache the replays once they are loaded.
  • available_only (bool) – Whether to represent only replays that have replay data available. Replays are filtered on this basis after span is applied. True by default.
all_replays()[source]

Returns all the Replays in this loadable container.

Warning

If you want an accurate list of Replays in this instance, you must call load() on this instance before all_replays(). Otherwise, this instance is not info loaded, and does not have a complete list of replays it represents.

class circleguard.loadable.Replay(weight, cache)[source]

A replay played by a player.

Parameters:
  • weight (RatelimitWeight) – How much it ‘costs’ to load this replay from the api.
  • cache (bool) – Whether to cache this replay once it is loaded.
timestamp

When this replay was played.

Type:datetime.datetime
map_id

The id of the map the replay was played on, or 0 if unknown or on an unsubmitted map.

Type:int
user_id

The id of the player who played the replay, or 0 if unknown (if the player is restricted, for instance). Note that if the user id is known, even if the user is restricted, it should still be given instead of 0.

Type:int
username

The username of the player who played the replay.

Type:str
mods

The mods the replay was played with.

Type:ModCombination
replay_id

The id of the replay, or 0 if the replay is unsubmitted.

Type:int
t

A 1d array containing the timestamp for each frame. <br> This is only nonnull after the replay has been loaded.

Type:ndarray[int]
xy

A 2d, two column array, containing the x and y coordinates of each frame in the first and second column respectively. <br> This is only nonnull after the replay has been loaded.

Type:ndarray[float]
k

A 1d array containing the keys pressed for each frame. <br> This is only nonnull after the replay has been loaded.

Type:ndarray[int]
class circleguard.loadable.ReplayMap(map_id, user_id, mods=None, cache=None, info=None)[source]

A Replay that was submitted to online servers.

Parameters:
  • map_id (int) – The id of the map the replay was played on.
  • user_id (int) – The id of the player who played the replay.
  • mods (ModCombination) – The mods the replay was played with. If None, the highest scoring replay of user_id on map_id will be loaded, regardless of mod combination. Otherwise, the replay with mods will be loaded.
  • cache (bool) – Whether to cache this replay once it is loaded.
load(loader, cache)[source]

Loads the data for this replay from the api.

Parameters:
  • loader (Loader) – The Loader to load this replay with.
  • cache (bool) – Whether to cache this replay after loading it. This only has an effect if self.cache is unset (None).

Notes

If replay.loaded is True, this method has no effect. replay.loaded is set to True after this method is finished.

class circleguard.loadable.ReplayPath(path, cache=None)[source]

A Replay saved locally in a .osr file.

Parameters:
  • path (str or os.PathLike) – The path to the replay file.
  • cache (bool) – Whether to cache this replay once it is loaded. Note that currently we do not cache ReplayPath regardless of this parameter.
load(loader, cache)[source]

Loads the data for this replay from the osr file.

Parameters:
  • loader (Loader) – The Loader to load this replay with.
  • cache (bool) – Whether to cache this replay after loading it. This only has an effect if self.cache is unset (None). Note that currently we do not cache ReplayPath regardless of this parameter.

Notes

If replay.loaded is True, this method has no effect. replay.loaded is set to True after this method is finished.

Loader

circleguard.loader.request(function)[source]

A decorator that handles requests and api related exceptions, as well as resetting our ratelimits if appropriate.

Parameters:function (callable) – The function to wrap.

Notes

Should be wrapped around any function that makes a request; to the api or otherwise.

If it has been more than Loader.RATELIMIT_RESET since Loader.start_time, sets Loader.start_time to be datetime.now.

circleguard.loader.check_cache(function)[source]

A decorator that checks if the passed ReplayInfo has its replay cached. If so, returns a Replay instance from the cached data. Otherwise, calls and returns the function as normal.

Parameters:function (callable) – The function to wrap.

Notes

self and replay_info MUST be the first and second arguments to the function, respectively.

Returns:A Replay instance from the cached data if it was cached, or the return value of the function if not.
Return type:Replay or Unknown
class circleguard.loader.Loader(key, cacher=None)[source]

Manages interactions with the osu api, using the ossapi wrapper.

Parameters:
  • key (str) – A valid api key. Can be retrieved from https://osu.ppy.sh/p/api/.
  • cacher (Cacher) – A Cacher instance to manage replay loading/caching. If None, replays will not be loaded from the cache or cached to the database.

Notes

If the api ratelimits the key, we wait until our ratelimits are refreshed and retry the request. Because the api does not provide the time until the next refresh (and we do not use exponential backoff or another retry strategy), if the key is ratelimited because of an interaction not managed by this class, the class may wait more time than necessary for the key to refresh.

static check_response(response)[source]

Checks a response from the api for an error or empty response.

Parameters:

response (list or dict) – The response returned by the api.

Raises:
  • One of :class:`~.enums.Error` – If an error exists in the response.
  • NoInfoAvailable – If the response is empty.

ReplayInfo

class circleguard.replay_info.ReplayInfo(timestamp, map_id, user_id, username, replay_id, mods, replay_available)[source]

A container class representing all the information we get about a replay from the api.

Parameters:
  • timestamp (datetime.datetime) – When this replay was set.
  • map_id (int) – The id of the map the replay was played on.
  • user_id (int) – The id of the player who played the replay.
  • username (str) – The username of the player who played the replay.
  • replay_id (int) – The id of the replay.
  • mods (ModCombination) – The mods the replay was played with.
  • replay_available (bool) – Whether this replay is available from the api or not.

Result

class circleguard.result.Result(type_: circleguard.enums.ResultType)[source]

The result of a test for cheats, either on a single replay or a collection of replays.

Parameters:
  • ischeat (bool) – Whether one or more of the replays involved is cheated or not.
  • type (ResultType) – What type of cheat test we are representing the results for.
class circleguard.result.InvestigationResult(replay: circleguard.loadable.Replay, type_: circleguard.enums.ResultType)[source]

The result of a test for cheats on a single replay.

Parameters:replay (Replay) – The replay investigated.
class circleguard.result.ComparisonResult(replay1: circleguard.loadable.Replay, replay2: circleguard.loadable.Replay, type_: circleguard.enums.ResultType)[source]

The result of a test for cheats by comparing two replays.

Parameters:
  • replay1 (Replay) – One of the replays involved.
  • replay2 (Replay) – The other replay involved.
class circleguard.result.StealResult(replay1: circleguard.loadable.Replay, replay2: circleguard.loadable.Replay)[source]

The result of a test for replay stealing between two replays.

Parameters:
  • replay1 (Replay) – One of the replays involved.
  • replay2 (Replay) – The other replay involved.
  • earlier_replay (Replay) – The earlier of the two replays (when the score was made). This is a reference to either replay1 or replay2.
  • later_replay (Replay) – The later of the two replays (when the score was made). This is a reference to either replay1 or replay2.
  • similarity (int) – The similarity of the two replays (the lower, the more similar). Similarity is, roughly speaking, a measure of the average pixel distance between the two replays.
  • correlation (float) – The median correlation of the two replays (the closer to 1, the more correlated). A value of 1.0 would be perfectly correlated, and a result of 0 would be uncorrelated.
class circleguard.result.StealResultSim(replay1: circleguard.loadable.Replay, replay2: circleguard.loadable.Replay, similarity: float)[source]

The result of a test for replay stealing between two replays, using the similarity algorithm.

Parameters:
  • replay1 (Replay) – One of the replays involved.
  • replay2 (Replay) – The other replay involved.
  • earlier_replay (Replay) – The earlier of the two replays (when the score was made). This is a reference to either replay1 or replay2.
  • later_replay (Replay) – The later of the two replays (when the score was made). This is a reference to either replay1 or replay2.
  • similarity (int) – The similarity of the two replays (the lower, the more similar). Similarity is, roughly speaking, a measure of the average pixel distance between the two replays.
class circleguard.result.StealResultCorr(replay1: circleguard.loadable.Replay, replay2: circleguard.loadable.Replay, correlation: float)[source]

The result of a test for replay stealing between two replays, using the similarity algorithm.

Parameters:
  • replay1 (Replay) – One of the replays involved.
  • replay2 (Replay) – The other replay involved.
  • earlier_replay (Replay) – The earlier of the two replays (when the score was made). This is a reference to either replay1 or replay2.
  • later_replay (Replay) – The later of the two replays (when the score was made). This is a reference to either replay1 or replay2.
  • similarity (int) – The similarity of the two replays (the lower, the more similar). Similarity is, roughly speaking, a measure of the average pixel distance between the two replays.
class circleguard.result.RelaxResult(replay: circleguard.loadable.Replay, ur: float)[source]

The result of a test for relax cheats.

Parameters:
class circleguard.result.CorrectionResult(replay: circleguard.loadable.Replay, snaps: list)[source]

The result of a test for aim correction cheats.

Parameters:
  • replay (Replay) – The replay investigated.
  • snaps (list[Snap]) – A list of suspicious hits in the replay.

Span

class circleguard.span.Span(data)[source]

A set of numbers represented by a string, which can include ranges or single numbers, separated by a comma.

Examples

>>> Span("1-3,6,2-4")
{1, 2, 3, 4, 6}

Utils

class circleguard.utils.ColoredFormatter(patern)[source]

A subclass of logging.Formatter that uses ANSI escape codes to color different parts of the logging.LogRecord when printed to the console.

Notes

Adapted from https://stackoverflow.com/a/46482050.

format(record)[source]

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

circleguard.utils.convert_ur(ur, mods, *, to)[source]

Converts an unstable rate to a converted unstable rate, depending on the mods the replay was played with.

Parameters:
  • ur (float) – The unconverted ur of the replay.
  • mods (Mod) – The mods the replay was played with. Only Mod.DT and Mod.HT will affect the unstable rate conversion.
  • to (string) – What to convert the ur to. One of cv (converted) or ucv (unconverted).