Package: pybfbc2stats
pybfbc2statsPython 🐍 library for retrieving statistics of Battlefield: Bad Company 2 players. Possible thanks to previous work by Luigi Auriemma and nemo.Featureslookup players/personas by id or namesearch for players/personas by name (with wildcard support)retrieve all available player statisticsretrieve player dogtag recordsretrieve player leaderboardsretrieve server listretrieve individual game server's details for (including player list)support for all platforms (PC, Xbox 360, PS3)full support for async PythonInstallationSimply install the package via pip.$pipinstallpybfbc2statsUsageTLS 1.0The FESL backend only supports TSL 1.0. So, you can only use this library in an environment that allows Python to use TLS 1.0. The easiest and least intrusive way to enable TLS 1.0 support is to set anOPENSSL_CONFenvironment variable that contains the absolute path to the includedopenssl.cnf. On Linux, you can set it by running this in the project directory:exportOPENSSL_CONF=$(realpathopenssl.cnf)Basic exampleThe following examples show how to find a player/persona by name and retrieve their stats using the default as well as the async client.Retrieve stats using the default FESL clientfromurllib.parseimportquotefrompybfbc2statsimportFeslClient,Platform,Namespacedefmain():withFeslClient('ea_account_name','ea_account_password',Platform.pc)asclient:quoted_name=quote('Krut0r')persona=client.lookup_username(quoted_name,Namespace.pc)stats=client.get_stats(int(persona['userId']))print(stats)if__name__=='__main__':main()Retrieve stats using the async FESL clientimportasynciofromurllib.parseimportquotefrompybfbc2statsimportAsyncFeslClient,Platform,Namespaceasyncdefmain():asyncwithAsyncFeslClient('ea_account_name','ea_account_password',Platform.pc)asclient:quoted_name=quote('Krut0r')persona=awaitclient.lookup_username(quoted_name,Namespace.pc)stats=awaitclient.get_stats(int(persona['userId']))print(stats)if__name__=='__main__':asyncio.run(main())Retrieve the server list using the default theater clientfrompybfbc2statsimportFeslClient,TheaterClient,Platformdefmain():# First, get theater details and login key (lkey) from FESLwithFeslClient('ea_account_name','ea_account_password',Platform.ps3)asfeslClient:theater_hostname,theater_port=feslClient.get_theater_details()lkey=feslClient.get_lkey()# Now use the theater client to get the server listwithTheaterClient(theater_hostname,theater_port,lkey,Platform.ps3)astheaterClient:lobbies=theaterClient.get_lobbies()servers=[]forlobbyinlobbies:lobby_servers=theaterClient.get_servers(int(lobby['LID']))servers.extend(lobby_servers)print(servers)if__name__=='__main__':main()Retrieve the server list using the async theater clientimportasynciofrompybfbc2statsimportAsyncFeslClient,AsyncTheaterClient,Platformasyncdefmain():# First, get theater details and login key (lkey) from FESLasyncwithAsyncFeslClient('ea_account_name','ea_account_password',Platform.ps3)asfeslClient:theater_hostname,theater_port=awaitfeslClient.get_theater_details()lkey=awaitfeslClient.get_lkey()# Now use the theater client to get the server listasyncwithAsyncTheaterClient(theater_hostname,theater_port,lkey,Platform.ps3)astheaterClient:lobbies=awaittheaterClient.get_lobbies()servers=[]forlobbyinlobbies:lobby_servers=awaittheaterClient.get_servers(int(lobby['LID']))servers.extend(lobby_servers)print(servers)if__name__=='__main__':asyncio.run(main())Client methodsBoth the default and the async clients offer the same methods with the same signatures.[Async]FeslClient(username, password, platform, timeout)Create a new [Async]FeslClient instance.Note: The account has to be valid for Bad Company 2. If your account does not work, you can create a new one usingealist:.\ealist.exe -A -a [username] [password] bfbc2-pc(the created account will work for all platforms).ArgumentsArgumentTypeOpt/RequiredNoteusernamestrRequiredpasswordstrRequiredplatformPlatformRequiredOne of:Platform.pc,Platform.ps3(Xbox 360 is not yet supported)timeoutfloatOptionalHow long to wait for data before raising a timeout exception (timeout is appliedper socket operation, meaning the timeout is applied to each read from/write to the underlying connection to the FESL backend)[Async]FeslClient.hello()Send the initial "hello" packet to the FESL server.[Async]FeslClient.memcheck()Send the response to the FESL server's "memcheck" challenge.[Async]FeslClient.login()Send the login details to the FESL server.[Async]FeslClient.get_lkey()Get the login key (lkey) used to authenticate on theater backend.[Async]FeslClient.get_theater_details()Get the hostname and port of the theater backend for the client's platform.[Async]FeslClient.lookup_usernames(usernames, namespace)Lookup a list ofurl encoded/quotedusernames and return any matching personas (only exact name matches are returned).Note: Since this method accepts anamespaceargument, it can lookup usernames in any namespace (on any platform), regardless of whichPlatformwas used to create the client instance.ArgumentsArgumentTypeOpt/RequiredNoteusernamesList[str]RequiredList ofurl encoded/quotedusernamesnamespaceNamespaceRequiredOne of:Namespace.pc,Namespace.ps3,Namespace.xbox360Examplefromurllib.parseimportquotefrompybfbc2statsimportFeslClient,Platform,Namespaceclient=FeslClient('ea_account_name','ea_account_password',Platform.pc)names=['SickLittleMonkey','[SuX] DeLuXe']quoted=[quote(name)fornameinnames]persona=client.lookup_usernames(quoted,Namespace.pc)[Async]FeslClient.lookup_username(username, namespace)Lookup a singleurl encoded/quotedusername and return any matching persona (only exact name matches are returned).Note: Since this method accepts anamespaceargument, it can lookup usernames in any namespace (on any platform), regardless of whichPlatformwas used to create the client instance.ArgumentsArgumentTypeOpt/RequiredNoteusernamestrRequiredUrl encoded/quotedusernamenamespaceNamespaceRequiredOne of:Namespace.pc,Namespace.ps3,Namespace.xbox360Examplefromurllib.parseimportquotefrompybfbc2statsimportFeslClient,Platform,Namespaceclient=FeslClient('ea_account_name','ea_account_password',Platform.ps3)persona=client.lookup_username(quote('Major Brainhurt'),Namespace.pc)[Async]FeslClient.lookup_user_ids(user_ids, namespace)Lookup a list of user ids and return any matching personas.Note: Since this method accepts anamespaceargument, it can lookup user ids in any namespace (on any platform), regardless of whichPlatformwas used to create the client instance.ArgumentsArgumentTypeOpt/RequiredNoteuser_idsList[int]RequirednamespaceNamespaceRequiredOne of:Namespace.pc,Namespace.ps3,Namespace.xbox360Examplefrompybfbc2statsimportFeslClient,Platform,Namespaceclient=FeslClient('ea_account_name','ea_account_password',Platform.pc)persona=client.lookup_user_ids([232302860,233866102],Namespace.xbox360)[Async]FeslClient.lookup_user_id(user_id, namespace)Lookup a single user id and return any matching persona.Note: Since this method accepts anamespaceargument, it can lookup user ids in any namespace (on any platform), regardless of whichPlatformwas used to create the client instance.ArgumentsArgumentTypeOpt/RequiredNoteuser_idintRequirednamespaceNamespaceRequiredOne of:Namespace.pc,Namespace.ps3,Namespace.xbox360Examplefrompybfbc2statsimportFeslClient,Platform,Namespaceclient=FeslClient('ea_account_name','ea_account_password',Platform.pc)persona=client.lookup_user_id(232302860,Namespace.xbox360)[Async]FeslClient.search_name(screen_name, namespace)Find personas given aurl encoded/quoted(partial) name. You can use*as a trailing wildcard.Note: The FESL backend returns an error both if a) no matching results were found and b) too many matching results were found. So, be careful with wildcard characters in combination with short partial names.ArgumentsArgumentTypeOpt/RequiredNotescreen_namestrRequiredUrl encoded/quoted(partial) namenamespaceNamespaceRequiredOne of:Namespace.pc,Namespace.ps3,Namespace.xbox360Examplefromurllib.parseimportquotefrompybfbc2statsimportFeslClient,Platformclient=FeslClient('ea_account_name','ea_account_password',Platform.pc)results=client.search_name(quote('[=BL=] larryp11'))[Async]FeslClient.get_stats(userid, keys)Retrieve a given list of stats attributes for a given player id on the client instance's platform.ArgumentsArgumentTypeOpt/RequiredNoteuseridintRequiredkeysList[bytes]OptionalBy default, all available attributes are retrieved (seeSTATS_KEYSconstant for details)Examplefrompybfbc2statsimportFeslClient,Platformclient=FeslClient('ea_account_name','ea_account_password',Platform.ps3)stats=client.get_stats(223789857,[b'accuracy',b'kills',b'deaths',b'score',b'time'])[Async]FeslClient.get_leaderboard(min_rank, max_rank, sort_by, keys)Retrieve a given range of players on the leaderboard with the given list of stats, sorted by a given key, on the client instance's platform.Note: There does not seem to be a hard limit to either the rank rage size nor the number of stats keys that can be retrieved for each player. You will, however, need to increase your client-wide timeout if you are planning to retrieve large chunks of the leaderboard or lots of stats attributes.ArgumentsArgumentTypeOpt/RequiredNotemin_rankintOptionalMinimum placement/rank on the leaderboard (1-250000)max_rankintOptionalMaximum placement/rank on the leaderboard (1-250001)sort_bybytesOptionalKey to sort leaderboard by, must be one ofdeaths,elo,kills,rank,score,time,veterankeysList[bytes]OptionalBy default, onlydeaths,kills,scoreandtimeare retrieved (seeSTATS_KEYSconstant for additional available keys)Examplefrompybfbc2statsimportFeslClient,Platformclient=FeslClient('ea_account_name','ea_account_password',Platform.pc)leaderboard=client.get_leaderboard(1,50,b'time')[Async]FeslClient.get_dogtags(userid)Retrieve a list of players the given player id has taken dogtags from.Note: The FESL backend returns an error both if a) the given user id does not exist and b) the user has not yet taken any dogtags.ArgumentsArgumentTypeOpt/RequireduseridintRequiredExamplefrompybfbc2statsimportFeslClient,Platformclient=FeslClient('ea_account_name','ea_account_password',Platform.ps3)dogtags=client.get_dogtags(223789857)[Async]TheaterClient(host, port, lkey, platform, timeout)Create a new [Async]TheaterClient instance.ArgumentsArgumentTypeOpt/RequiredNotehoststrRequiredIP/hostname of the theater backend for the platform (can be retrieved via FESL)portintRequiredPort of the theater backend for the platform (can be retrieved via FESL)lkeystrRequiredLogin key (lkey) (retrieved via FESL)platformPlatformRequiredOne of:Platform.pc,Platform.ps3(Xbox 360 is not yet supported)timeoutfloatOptionalHow long to wait for data before raising a timeout exception (timeout is appliedper socket operation, meaning the timeout is applied to each read from/write to the underlying connection to the FESL backend)[Async]TheaterClient.connect()Initialize the connection to the Theater backend by sending the initial CONN/hello packet.[Async]TheaterClient.authenticate()Authenticate against/log into the Theater backend using the lkey retrieved via FESL.[Async]TheaterClient.get_lobbies()Retrieve all available game (server) lobbies.Examplefrompybfbc2statsimportTheaterClient,Platformclient=TheaterClient('bfbc2-ps3-server.theater.ea.com',18336,'your_lkey',Platform.ps3)lobbies=client.get_lobbies()[Async]TheaterClient.get_servers(lobby_id)Retrieve all available game servers from the given lobby.ArgumentsArgumentTypeOpt/RequiredNotelobby_idintRequiredId of the game server lobbyExamplefrompybfbc2statsimportTheaterClient,Platformclient=TheaterClient('bfbc2-ps3-server.theater.ea.com',18336,'your_lkey',Platform.ps3)servers=client.get_servers(257)[Async]TheaterClient.get_server_details(lobby_id, game_id)Retrieve full details and player list for a given server.ArgumentsArgumentTypeOpt/RequiredNotelobby_idintRequiredId of the game server lobby the server is hosted ingame_idintRequiredGame (server) idExamplefrompybfbc2statsimportTheaterClient,Platformclient=TheaterClient('bfbc2-ps3-server.theater.ea.com',18336,'your_lkey',Platform.ps3)general,detailed,players=client.get_server_details(257,120018)[Async]TheaterClient.get_current_server(user_id)Retrieve full details and player list for a given user's current server (server they are currently playing on,
raises a PlayerNotFound exception if the player is not currently playing online).ArgumentsArgumentTypeOpt/RequiredNoteuser_idintRequiredId of the user whose current server to getExamplefrompybfbc2statsimportTheaterClient,Platformclient=TheaterClient('bfbc2-ps3-server.theater.ea.com',18336,'your_lkey',Platform.ps3)general,detailed,players=client.get_current_server(227528903)