Compare commits

...

22 Commits

Author SHA1 Message Date
alex47exe
56e8e6adfe
Merge branch 'dev' into dev 2024-10-26 02:31:02 +01:00
Detanup01
63552d7584
fixing is_beta_branch in ini 2024-10-25 18:47:18 +02:00
Detanup01
2560c6eb8e
Merge pull request #66 from Detanup01/steamutils001
steamutils001 imp
2024-10-25 14:07:50 +02:00
Detanup01
8556336169
remove the comment in SteamUtils001 2024-10-25 14:07:34 +02:00
Detanup01
6be3ba1963
fix interface getter and steamutils class 2024-10-23 17:00:28 +02:00
alex47exe
20f50d8cb0
Merge branch 'Detanup01:dev' into dev 2024-10-23 00:15:02 +01:00
Detanup01
47c6f8ef3d
steamutils001 imp 2024-10-22 20:23:22 +02:00
Detanup01
3a4d7c4bc1
Merge pull request #64 from universal963/patch-oldsteamuser
Initial implementation of `ISteamUser004` to `ISteamUser008`
2024-10-22 20:17:42 +02:00
universal963
dee5201e61 Fix debug log 2024-10-22 19:55:12 +08:00
universal963
f8bf0ab381 Fix debug build 2024-10-22 19:13:36 +08:00
universal963
2ef54d0fb8 Fix again 2024-10-22 19:00:49 +08:00
universal963
e3527834d7 Fix compilation 2024-10-22 18:53:44 +08:00
universal963
415fd1ca3e Initial implementation of ISteamUser004 to ISteamUser008 2024-10-22 18:41:46 +08:00
alex47exe
68e35c17ee generate_emu_config, fix -rel argument
for better customization, it is now split in two arguments:
- rel_out:  generate complete game config in _OUTPUT/appid folder, relative to the bat, sh or app calling generate_emu_config app
- rel_raw:  generate complete game config in the same folder that contains the bat, sh or app calling generate_emu_config app
2024-10-21 02:42:54 +01:00
alex47exe
493cf75376
Merge branch 'Detanup01:dev' into dev 2024-10-21 00:19:06 +01:00
Detanup01
2b0eefd929
use UGC19 as UGC20 2024-10-20 23:10:22 +02:00
alex47exe
5e6fcc146c
Merge branch 'Detanup01:dev' into dev 2024-10-19 23:17:16 +01:00
alex47exe
169d29e53d fix generate_emu_config
fix two controller config related error when generating for appid 427520 and 1477940
2024-10-19 22:47:56 +01:00
Detanup01
2f81f755b7
Merge pull request #59 from universal963/patch-3
Fix possible memory leaks in `network.cpp`
2024-10-18 16:06:21 +02:00
universal963
ff5ef4f721
One more fix 2024-10-15 23:45:32 +08:00
alex47exe
766b685b62 update top_owners_ids.txt for generate_emu_config
add top owners_ids.txt to Linux build too
2024-10-14 20:10:36 +01:00
universal963
4823a2be70
Fix possible memory leak 2024-10-14 13:40:21 +08:00
25 changed files with 1260 additions and 438 deletions

View File

@ -361,6 +361,7 @@ public:
CSteamID get_lobby(); CSteamID get_lobby();
bool is_offline(); bool is_offline();
void set_offline(bool offline);
uint16 get_port(); uint16 get_port();
void set_port(uint16 port); void set_port(uint16 port);

View File

@ -22,6 +22,11 @@
#include "auth.h" #include "auth.h"
class Steam_User : class Steam_User :
public ISteamUser004,
public ISteamUser005,
public ISteamUser006,
public ISteamUser007,
public ISteamUser008,
public ISteamUser009, public ISteamUser009,
public ISteamUser010, public ISteamUser010,
public ISteamUser011, public ISteamUser011,
@ -48,6 +53,8 @@ public ISteamUser
std::chrono::high_resolution_clock::time_point last_get_voice{}; std::chrono::high_resolution_clock::time_point last_get_voice{};
std::string encrypted_app_ticket{}; std::string encrypted_app_ticket{};
Auth_Manager *auth_manager{}; Auth_Manager *auth_manager{};
std::map<std::string, std::string> registry{};
std::string registry_nullptr{};
public: public:
Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks); Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks);
@ -57,15 +64,41 @@ public:
// this is only used internally by the API, and by a few select interfaces that support multi-user // this is only used internally by the API, and by a few select interfaces that support multi-user
HSteamUser GetHSteamUser(); HSteamUser GetHSteamUser();
void LogOn( CSteamID steamID );
void LogOff();
// returns true if the Steam client current has a live connection to the Steam servers. // returns true if the Steam client current has a live connection to the Steam servers.
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy. // If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
// The Steam client will automatically be trying to recreate the connection as often as possible. // The Steam client will automatically be trying to recreate the connection as often as possible.
bool BLoggedOn(); bool BLoggedOn();
ELogonState GetLogonState();
bool BConnected();
// returns the CSteamID of the account currently logged into the Steam client // returns the CSteamID of the account currently logged into the Steam client
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API // a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
CSteamID GetSteamID(); CSteamID GetSteamID();
bool IsVACBanned( int nGameID );
bool RequireShowVACBannedMessage( int nGameID );
void AcknowledgeVACBanning( int nGameID );
// These are dead.
int NClientGameIDAdd( int nGameID );
void RemoveClientGame( int nClientGameID );
void SetClientGameServer( int nClientGameID, uint32 unIPServer, uint16 usPortServer );
void SetSteam2Ticket( uint8 *pubTicket, int cubTicket );
void AddServerNetAddress( uint32 unIP, uint16 unPort );
bool SetEmail( const char *pchEmail );
// logon cookie - this is obsolete and never used
int GetSteamGameConnectToken( void *pBlob, int cbMaxBlob );
bool SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue );
bool GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue );
bool SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue );
bool GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue );
// Multiplayer Authentication functions // Multiplayer Authentication functions
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server // InitiateGameConnection() starts the state machine for authenticating the game client with the game server
@ -86,15 +119,40 @@ public:
int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure ); int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure );
int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure, void *pvSteam2GetEncryptionKey, int cbSteam2GetEncryptionKey );
int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, int nGameAppID, uint32 unIPServer, uint16 usPortServer, bool bSecure );
// notify of disconnect // notify of disconnect
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call // needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ); void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer );
// Legacy functions // Legacy functions
void SetSelfAsPrimaryChatDestination();
bool IsPrimaryChatDestination();
void RequestLegacyCDKey( uint32 nAppID );
bool SendGuestPassByEmail( const char *pchEmailAccount, GID_t gidGuestPassID, bool bResending );
bool SendGuestPassByAccountID( uint32 uAccountID, GID_t gidGuestPassID, bool bResending );
bool AckGuestPass(const char *pchGuestPassCode);
bool RedeemGuestPass(const char *pchGuestPassCode);
uint32 GetGuestPassToGiveCount();
uint32 GetGuestPassToRedeemCount();
RTime32 GetGuestPassLastUpdateTime();
bool GetGuestPassToGiveInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed, char *pchRecipientAddress, int cRecipientAddressSize );
bool GetGuestPassToRedeemInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed);
bool GetGuestPassToRedeemSenderAddress( uint32 nPassIndex, char* pchSenderAddress, int cSenderAddressSize );
bool GetGuestPassToRedeemSenderName( uint32 nPassIndex, char* pchSenderName, int cSenderNameSize );
void AcknowledgeMessageByGID( const char *pchMessageGID );
bool SetLanguage( const char *pchLanguage );
// used by only a few games to track usage events // used by only a few games to track usage events
void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo); void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo);
void SetAccountName( const char *pchAccountName );
void SetPassword( const char *pchPassword );
void SetAccountCreationTime( RTime32 rt );
void RefreshSteam2Login(); void RefreshSteam2Login();
// get the local storage folder for current Steam account to write application data, e.g. save games, configs etc. // get the local storage folder for current Steam account to write application data, e.g. save games, configs etc.

View File

@ -25,6 +25,7 @@
class Steam_Utils : class Steam_Utils :
public ISteamUtils001,
public ISteamUtils002, public ISteamUtils002,
public ISteamUtils003, public ISteamUtils003,
public ISteamUtils004, public ISteamUtils004,

View File

@ -110,7 +110,7 @@ static void get_broadcast_info(uint16 port)
number_broadcasts++; number_broadcasts++;
if (number_broadcasts >= MAX_BROADCASTS) { if (number_broadcasts >= MAX_BROADCASTS) {
return; break;
} }
} }
@ -542,6 +542,8 @@ std::set<IP_PORT> Networking::resolve_ip(std::string dns)
} }
} }
if (result)
freeaddrinfo(result);
return ips; return ips;
} }

View File

@ -161,6 +161,11 @@ bool Settings::is_offline()
return offline; return offline;
} }
void Settings::set_offline(bool offline)
{
this->offline = offline;
}
uint16 Settings::get_port() uint16 Settings::get_port()
{ {
return port; return port;

View File

@ -71,7 +71,17 @@ ISteamUser *Steam_Client::GetISteamUser( HSteamUser hSteamUser, HSteamPipe hStea
PRINT_DEBUG("%s", pchVersion); PRINT_DEBUG("%s", pchVersion);
if (!steam_pipes.count(hSteamPipe) || !hSteamUser) return NULL; if (!steam_pipes.count(hSteamPipe) || !hSteamUser) return NULL;
if (strcmp(pchVersion, "SteamUser009") == 0) { if (strcmp(pchVersion, "SteamUser004") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser004 *>(steam_user)); // sdk 0.99u
} else if (strcmp(pchVersion, "SteamUser005") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser005 *>(steam_user)); // sdk 0.99v
} else if (strcmp(pchVersion, "SteamUser006") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser006 *>(steam_user)); // sdk 0.99w
} else if (strcmp(pchVersion, "SteamUser007") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser007 *>(steam_user)); // sdk 0.99x
} else if (strcmp(pchVersion, "SteamUser008") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser008 *>(steam_user)); // sdk 0.99y
} else if (strcmp(pchVersion, "SteamUser009") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser009 *>(steam_user)); return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser009 *>(steam_user));
} else if (strcmp(pchVersion, "SteamUser010") == 0) { } else if (strcmp(pchVersion, "SteamUser010") == 0) {
return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser010 *>(steam_user)); return reinterpret_cast<ISteamUser *>(static_cast<ISteamUser010 *>(steam_user));
@ -199,7 +209,10 @@ ISteamUtils *Steam_Client::GetISteamUtils( HSteamPipe hSteamPipe, const char *pc
steam_utils_temp = steam_utils; steam_utils_temp = steam_utils;
} }
if (strcmp(pchVersion, "SteamUtils002") == 0) {
if (strcmp(pchVersion, "SteamUtils001") == 0) {
return reinterpret_cast<ISteamUtils *>(static_cast<ISteamUtils001 *>(steam_utils_temp));
} else if (strcmp(pchVersion, "SteamUtils002") == 0) {
return reinterpret_cast<ISteamUtils *>(static_cast<ISteamUtils002 *>(steam_utils_temp)); return reinterpret_cast<ISteamUtils *>(static_cast<ISteamUtils002 *>(steam_utils_temp));
} else if (strcmp(pchVersion, "SteamUtils003") == 0) { } else if (strcmp(pchVersion, "SteamUtils003") == 0) {
return reinterpret_cast<ISteamUtils *>(static_cast<ISteamUtils003 *>(steam_utils_temp)); // ISteamUtils003 Not found in public Archive, must be between 1.02-1.03 return reinterpret_cast<ISteamUtils *>(static_cast<ISteamUtils003 *>(steam_utils_temp)); // ISteamUtils003 Not found in public Archive, must be between 1.02-1.03
@ -740,6 +753,8 @@ ISteamUGC *Steam_Client::GetISteamUGC( HSteamUser hSteamUser, HSteamPipe hSteamP
return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC017 *>(steam_ugc_temp)); return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC017 *>(steam_ugc_temp));
} else if (strcmp(pchVersion, "STEAMUGC_INTERFACE_VERSION018") == 0) { } else if (strcmp(pchVersion, "STEAMUGC_INTERFACE_VERSION018") == 0) {
return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC018 *>(steam_ugc_temp)); return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC018 *>(steam_ugc_temp));
} else if (strcmp(pchVersion, "STEAMUGC_INTERFACE_VERSION019") == 0) {
return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC *>(steam_ugc_temp));
} else if (strcmp(pchVersion, STEAMUGC_INTERFACE_VERSION) == 0) { } else if (strcmp(pchVersion, STEAMUGC_INTERFACE_VERSION) == 0) {
return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC *>(steam_ugc_temp)); return reinterpret_cast<ISteamUGC *>(static_cast<ISteamUGC *>(steam_ugc_temp));
} }

View File

@ -44,6 +44,18 @@ HSteamUser Steam_User::GetHSteamUser()
return CLIENT_HSTEAMUSER; return CLIENT_HSTEAMUSER;
} }
void Steam_User::LogOn( CSteamID steamID )
{
PRINT_DEBUG_ENTRY();
settings->set_offline(false);
}
void Steam_User::LogOff()
{
PRINT_DEBUG_ENTRY();
settings->set_offline(true);
}
// returns true if the Steam client current has a live connection to the Steam servers. // returns true if the Steam client current has a live connection to the Steam servers.
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy. // If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
// The Steam client will automatically be trying to recreate the connection as often as possible. // The Steam client will automatically be trying to recreate the connection as often as possible.
@ -53,6 +65,21 @@ bool Steam_User::BLoggedOn()
return !settings->is_offline(); return !settings->is_offline();
} }
ELogonState Steam_User::GetLogonState()
{
PRINT_DEBUG_ENTRY();
if(settings->is_offline())
return (ELogonState)0;
else
return (ELogonState)4; // tested on real steam, undocumented return value
}
bool Steam_User::BConnected()
{
PRINT_DEBUG_ENTRY();
return !settings->is_offline();
}
// returns the CSteamID of the account currently logged into the Steam client // returns the CSteamID of the account currently logged into the Steam client
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API // a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
CSteamID Steam_User::GetSteamID() CSteamID Steam_User::GetSteamID()
@ -63,6 +90,160 @@ CSteamID Steam_User::GetSteamID()
return id; return id;
} }
bool Steam_User::IsVACBanned( int nGameID )
{
PRINT_DEBUG_ENTRY();
return false;
}
bool Steam_User::RequireShowVACBannedMessage( int nGameID )
{
PRINT_DEBUG_ENTRY();
return false;
}
void Steam_User::AcknowledgeVACBanning( int nGameID )
{
PRINT_DEBUG_ENTRY();
}
// according to comments in sdk, "these are dead."
int Steam_User::NClientGameIDAdd( int nGameID )
{
PRINT_DEBUG_ENTRY();
return 0;
}
// according to comments in sdk, "these are dead."
void Steam_User::RemoveClientGame( int nClientGameID )
{
PRINT_DEBUG_ENTRY();
}
// according to comments in sdk, "these are dead."
void Steam_User::SetClientGameServer( int nClientGameID, uint32 unIPServer, uint16 usPortServer )
{
PRINT_DEBUG_ENTRY();
}
void Steam_User::SetSteam2Ticket( uint8 *pubTicket, int cubTicket )
{
PRINT_DEBUG_ENTRY();
}
void Steam_User::AddServerNetAddress( uint32 unIP, uint16 unPort )
{
PRINT_DEBUG_ENTRY();
}
bool Steam_User::SetEmail( const char *pchEmail )
{
PRINT_DEBUG_ENTRY();
return false;
}
// according to comments in sdk, "logon cookie - this is obsolete and never used"
int Steam_User::GetSteamGameConnectToken( void *pBlob, int cbMaxBlob )
{
PRINT_DEBUG_ENTRY();
return 0;
}
bool Steam_User::SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue )
{
PRINT_DEBUG_TODO();
if (!pchValue)
return false; // real steam crashes, so return value is assumed
if (!pchKey) // tested on real steam
{
registry.clear();
registry_nullptr = std::string(pchValue);
}
else
{
registry[std::string(pchKey)] = std::string(pchValue);
// TODO: save it to disk, because real steam can get the string when app restarts
}
return true;
}
bool Steam_User::GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue )
{
PRINT_DEBUG_TODO();
// TODO: read data on disk, because real steam can get the string when app restarts
if (pchValue && cbValue > 0)
memset(pchValue, 0, cbValue);
std::string value{};
if(!pchKey)
{
value = registry_nullptr;
}
else
{
auto it = registry.find(std::string(pchKey));
if (it == registry.end())
return false;
value = it->second;
}
if (pchValue && cbValue > 0)
value.copy(pchValue, cbValue - 1);
return true;
}
bool Steam_User::SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue )
{
PRINT_DEBUG_TODO();
if (!pchKey) // tested on real steam
{
registry.clear();
registry_nullptr = std::to_string(iValue);
}
else
{
registry[std::string(pchKey)] = std::to_string(iValue);
// TODO: save it to disk, because real steam can get the string when app restarts
}
return true;
}
bool Steam_User::GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue )
{
PRINT_DEBUG_TODO();
// TODO: read data on disk, because real steam can get the string when app restarts
if (piValue)
*piValue = 0;
std::string value{};
if(!pchKey)
{
value = registry_nullptr;
}
else
{
auto it = registry.find(std::string(pchKey));
if (it == registry.end())
return false;
value = it->second;
}
try
{
if (piValue)
*piValue = std::stoi(value);
}
catch(...)
{
PRINT_DEBUG("not a number"); // TODO: real steam returns a value other than 0 under this condition
}
return true;
}
// Multiplayer Authentication functions // Multiplayer Authentication functions
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server // InitiateGameConnection() starts the state machine for authenticating the game client with the game server
@ -101,6 +282,18 @@ int Steam_User::InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSte
return InitiateGameConnection(pAuthBlob, cbMaxAuthBlob, steamIDGameServer, unIPServer, usPortServer, bSecure); return InitiateGameConnection(pAuthBlob, cbMaxAuthBlob, steamIDGameServer, unIPServer, usPortServer, bSecure);
} }
int Steam_User::InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure, void *pvSteam2GetEncryptionKey, int cbSteam2GetEncryptionKey )
{
PRINT_DEBUG("sdk 0.99x, 0.99y");
return InitiateGameConnection(pBlob, cbMaxBlob, steamID, unIPServer, usPortServer, bSecure);
}
int Steam_User::InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, int nGameAppID, uint32 unIPServer, uint16 usPortServer, bool bSecure )
{
PRINT_DEBUG("sdk 0.99u");
return InitiateGameConnection(pBlob, cbMaxBlob, steamID, unIPServer, usPortServer, bSecure);
}
// notify of disconnect // notify of disconnect
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call // needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
void Steam_User::TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) void Steam_User::TerminateGameConnection( uint32 unIPServer, uint16 usPortServer )
@ -110,12 +303,147 @@ void Steam_User::TerminateGameConnection( uint32 unIPServer, uint16 usPortServer
// Legacy functions // Legacy functions
void Steam_User::SetSelfAsPrimaryChatDestination()
{
PRINT_DEBUG_TODO();
}
bool Steam_User::IsPrimaryChatDestination()
{
PRINT_DEBUG_ENTRY();
return false;
}
void Steam_User::RequestLegacyCDKey( uint32 iAppID )
{
PRINT_DEBUG_TODO();
}
bool Steam_User::SendGuestPassByEmail( const char *pchEmailAccount, GID_t gidGuestPassID, bool bResending )
{
PRINT_DEBUG_TODO();
return false;
}
bool Steam_User::SendGuestPassByAccountID( uint32 uAccountID, GID_t gidGuestPassID, bool bResending )
{
PRINT_DEBUG_TODO();
return false;
}
bool Steam_User::AckGuestPass(const char *pchGuestPassCode)
{
PRINT_DEBUG_TODO();
return false;
}
bool Steam_User::RedeemGuestPass(const char *pchGuestPassCode)
{
PRINT_DEBUG_TODO();
return false;
}
uint32 Steam_User::GetGuestPassToGiveCount()
{
PRINT_DEBUG_TODO();
return 0;
}
uint32 Steam_User::GetGuestPassToRedeemCount()
{
PRINT_DEBUG_TODO();
return 0;
}
RTime32 Steam_User::GetGuestPassLastUpdateTime()
{
PRINT_DEBUG_TODO();
return 0;
}
bool Steam_User::GetGuestPassToGiveInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed, char *pchRecipientAddress, int cRecipientAddressSize )
{
PRINT_DEBUG_TODO();
// TODO: pgidGuestPassID
if (pnPackageID)
*pnPackageID = 0;
if (pRTime32Created)
*pRTime32Created = 0;
if (pRTime32Expiration)
*pRTime32Expiration = 0;
if (pRTime32Sent)
*pRTime32Sent = 0;
if (pRTime32Redeemed)
*pRTime32Redeemed = 0;
if (pchRecipientAddress && cRecipientAddressSize > 0)
memset(pchRecipientAddress, 0, cRecipientAddressSize);
return false;
}
bool Steam_User::GetGuestPassToRedeemInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed)
{
PRINT_DEBUG_TODO();
// TODO: pgidGuestPassID
if (pnPackageID)
*pnPackageID = 0;
if (pRTime32Created)
*pRTime32Created = 0;
if (pRTime32Expiration)
*pRTime32Expiration = 0;
if (pRTime32Sent)
*pRTime32Sent = 0;
if (pRTime32Redeemed)
*pRTime32Redeemed = 0;
return false;
}
bool Steam_User::GetGuestPassToRedeemSenderAddress( uint32 nPassIndex, char* pchSenderAddress, int cSenderAddressSize )
{
PRINT_DEBUG_TODO();
return false;
}
bool Steam_User::GetGuestPassToRedeemSenderName( uint32 nPassIndex, char* pchSenderName, int cSenderNameSize )
{
PRINT_DEBUG_TODO();
if (pchSenderName && cSenderNameSize > 0)
memset(pchSenderName, 0, cSenderNameSize);
return false;
}
void Steam_User::AcknowledgeMessageByGID( const char *pchMessageGID )
{
PRINT_DEBUG_TODO();
}
bool Steam_User::SetLanguage( const char *pchLanguage )
{
PRINT_DEBUG_TODO();
// TODO: don't know what this api actually does other than returning true
return true;
}
// used by only a few games to track usage events // used by only a few games to track usage events
void Steam_User::TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo) void Steam_User::TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo)
{ {
PRINT_DEBUG_TODO(); PRINT_DEBUG_TODO();
} }
void Steam_User::SetAccountName( const char *pchAccountName )
{
PRINT_DEBUG_TODO();
}
void Steam_User::SetPassword( const char *pchPassword )
{
PRINT_DEBUG_TODO();
}
void Steam_User::SetAccountCreationTime( RTime32 rt )
{
PRINT_DEBUG_TODO();
}
void Steam_User::RefreshSteam2Login() void Steam_User::RefreshSteam2Login()
{ {
PRINT_DEBUG_TODO(); PRINT_DEBUG_TODO();

53
sdk/steam/isteamuser004.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef ISTEAMUSER004_H
#define ISTEAMUSER004_H
#ifdef STEAM_WIN32
#pragma once
#endif
enum EConfigSubTree {
EConfigSubTree_stub
};
enum ELogonState {
ELogonState_stub
};
class ISteamUser004
{
public:
virtual HSteamUser GetHSteamUser() = 0;
virtual void LogOn( CSteamID steamID ) = 0;
virtual void LogOff() = 0;
virtual bool BLoggedOn() = 0;
virtual ELogonState GetLogonState() = 0;
virtual bool BConnected() = 0;
virtual CSteamID GetSteamID() = 0;
virtual bool IsVACBanned( int nGameID ) = 0;
virtual bool RequireShowVACBannedMessage( int nGameID ) = 0;
virtual void AcknowledgeVACBanning( int nGameID ) = 0;
// These are dead.
virtual int NClientGameIDAdd( int nGameID ) = 0;
virtual void RemoveClientGame( int nClientGameID ) = 0;
virtual void SetClientGameServer( int nClientGameID, uint32 unIPServer, uint16 usPortServer ) = 0;
virtual void SetSteam2Ticket( uint8 *pubTicket, int cubTicket ) = 0;
virtual void AddServerNetAddress( uint32 unIP, uint16 unPort ) = 0;
virtual bool SetEmail( const char *pchEmail ) = 0;
// logon cookie - this is obsolete and never used
virtual int GetSteamGameConnectToken( void *pBlob, int cbMaxBlob ) = 0;
virtual bool SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue ) = 0;
virtual bool GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue ) = 0;
virtual bool SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue ) = 0;
virtual bool GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue ) = 0;
virtual int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, int nGameAppID, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0;
virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0;
virtual void SetSelfAsPrimaryChatDestination() = 0;
virtual bool IsPrimaryChatDestination() = 0;
virtual void RequestLegacyCDKey( uint32 iAppID ) = 0;
};
#endif // ISTEAMUSER004_H

57
sdk/steam/isteamuser005.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef ISTEAMUSER005_H
#define ISTEAMUSER005_H
#ifdef STEAM_WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Functions for accessing and manipulating a steam account
// associated with one client instance
//-----------------------------------------------------------------------------
class ISteamUser005
{
public:
virtual HSteamUser GetHSteamUser() = 0;
virtual void LogOn( CSteamID steamID ) = 0;
virtual void LogOff() = 0;
virtual bool BLoggedOn() = 0;
virtual ELogonState GetLogonState() = 0;
virtual bool BConnected() = 0;
virtual CSteamID GetSteamID() = 0;
virtual bool IsVACBanned( int nGameID ) = 0;
virtual bool RequireShowVACBannedMessage( int nAppID ) = 0;
virtual void AcknowledgeVACBanning( int nAppID ) = 0;
virtual void SetSteam2Ticket( uint8 *pubTicket, int cubTicket ) = 0;
virtual void AddServerNetAddress( uint32 unIP, uint16 unPort ) = 0;
virtual bool SetEmail( const char *pchEmail ) = 0;
virtual bool SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue ) = 0;
virtual bool GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue ) = 0;
virtual bool SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue ) = 0;
virtual bool GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue ) = 0;
virtual int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0;
virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0;
virtual void SetSelfAsPrimaryChatDestination() = 0;
virtual bool IsPrimaryChatDestination() = 0;
virtual void RequestLegacyCDKey( uint32 nAppID ) = 0;
virtual bool SendGuestPassByEmail( const char *pchEmailAccount, GID_t gidGuestPassID, bool bResending ) = 0;
virtual bool SendGuestPassByAccountID( uint32 uAccountID, GID_t gidGuestPassID, bool bResending ) = 0;
virtual bool AckGuestPass(const char *pchGuestPassCode) = 0;
virtual bool RedeemGuestPass(const char *pchGuestPassCode) = 0;
virtual uint32 GetGuestPassToGiveCount() = 0;
virtual uint32 GetGuestPassToRedeemCount() = 0;
virtual RTime32 GetGuestPassLastUpdateTime() = 0;
virtual bool GetGuestPassToGiveInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed, char *pchRecipientAddress, int cRecipientAddressSize ) = 0;
virtual bool GetGuestPassToRedeemInfo( uint32 nPassIndex, GID_t *pgidGuestPassID, PackageId_t *pnPackageID, RTime32 *pRTime32Created, RTime32 *pRTime32Expiration, RTime32 *pRTime32Sent, RTime32 *pRTime32Redeemed) = 0;
virtual bool GetGuestPassToRedeemSenderAddress( uint32 nPassIndex, char* pchSenderAddress, int cSenderAddressSize ) = 0;
virtual bool GetGuestPassToRedeemSenderName( uint32 nPassIndex, char* pchSenderName, int cSenderNameSize ) = 0;
virtual void AcknowledgeMessageByGID( const char *pchMessageGID ) = 0;
virtual bool SetLanguage( const char *pchLanguage ) = 0;
virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0;
virtual void SetAccountName( const char *pchAccountName ) = 0;
virtual void SetPassword( const char *pchPassword ) = 0;
virtual void SetAccountCreationTime( RTime32 rt ) = 0;
};
#endif // ISTEAMUSER005_H

64
sdk/steam/isteamuser006.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef ISTEAMUSER006_H
#define ISTEAMUSER006_H
#ifdef STEAM_WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Functions for accessing and manipulating a steam account
// associated with one client instance
//-----------------------------------------------------------------------------
class ISteamUser006
{
public:
// returns the HSteamUser this interface represents
// this is only used internally by the API, and by a few select interfaces that support multi-user
virtual HSteamUser GetHSteamUser() = 0;
virtual void LogOn( CSteamID steamID ) = 0;
virtual void LogOff() = 0;
// returns true if the Steam client current has a live connection to the Steam servers.
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
// The Steam client will automatically be trying to recreate the connection as often as possible.
virtual bool BLoggedOn() = 0;
// returns the CSteamID of the account currently logged into the Steam client
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
virtual CSteamID GetSteamID() = 0;
virtual bool SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue ) = 0;
virtual bool GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue ) = 0;
virtual bool SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue ) = 0;
virtual bool GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue ) = 0;
// Multiplayer Authentication functions
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
//
// Parameters:
// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( <appID> )
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
//
// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
virtual int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure ) = 0;
// notify of disconnect
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0;
// Legacy functions
// used by only a few games to track usage events
virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0;
};
#endif // ISTEAMUSER006_H

68
sdk/steam/isteamuser007.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef ISTEAMUSER007_H
#define ISTEAMUSER007_H
#ifdef STEAM_WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Functions for accessing and manipulating a steam account
// associated with one client instance
//-----------------------------------------------------------------------------
class ISteamUser007
{
public:
// returns the HSteamUser this interface represents
// this is only used internally by the API, and by a few select interfaces that support multi-user
virtual HSteamUser GetHSteamUser() = 0;
virtual void LogOn( CSteamID steamID ) = 0;
virtual void LogOff() = 0;
// returns true if the Steam client current has a live connection to the Steam servers.
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
// The Steam client will automatically be trying to recreate the connection as often as possible.
virtual bool BLoggedOn() = 0;
// returns the CSteamID of the account currently logged into the Steam client
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
virtual CSteamID GetSteamID() = 0;
virtual bool SetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, const char *pchValue ) = 0;
virtual bool GetRegistryString( EConfigSubTree eRegistrySubTree, const char *pchKey, char *pchValue, int cbValue ) = 0;
virtual bool SetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int iValue ) = 0;
virtual bool GetRegistryInt( EConfigSubTree eRegistrySubTree, const char *pchKey, int *piValue ) = 0;
// Multiplayer Authentication functions
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
//
// Parameters:
// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( <appID> )
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
//
// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
virtual int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure, void *pvSteam2GetEncryptionKey, int cbSteam2GetEncryptionKey ) = 0;
// notify of disconnect
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0;
// Legacy functions
// used by only a few games to track usage events
virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0;
// legacy authentication support - need to be called if the game server rejects the user with a 'bad ticket' error
// this is only needed under very specific circumstances
virtual void RefreshSteam2Login() = 0;
};
#endif // ISTEAMUSER007_H

60
sdk/steam/isteamuser008.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef ISTEAMUSER008_H
#define ISTEAMUSER008_H
#ifdef STEAM_WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Functions for accessing and manipulating a steam account
// associated with one client instance
//-----------------------------------------------------------------------------
class ISteamUser008
{
public:
// returns the HSteamUser this interface represents
// this is only used internally by the API, and by a few select interfaces that support multi-user
virtual HSteamUser GetHSteamUser() = 0;
// returns true if the Steam client current has a live connection to the Steam servers.
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
// The Steam client will automatically be trying to recreate the connection as often as possible.
virtual bool BLoggedOn() = 0;
// returns the CSteamID of the account currently logged into the Steam client
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
virtual CSteamID GetSteamID() = 0;
// Multiplayer Authentication functions
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
//
// Parameters:
// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( <appID> )
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
//
// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
virtual int InitiateGameConnection( void *pBlob, int cbMaxBlob, CSteamID steamID, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure, void *pvSteam2GetEncryptionKey, int cbSteam2GetEncryptionKey ) = 0;
// notify of disconnect
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
virtual void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer ) = 0;
// Legacy functions
// used by only a few games to track usage events
virtual void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo = "" ) = 0;
// legacy authentication support - need to be called if the game server rejects the user with a 'bad ticket' error
// this is only needed under very specific circumstances
virtual void RefreshSteam2Login() = 0;
};
#endif // ISTEAMUSER008_H

View File

@ -0,0 +1,34 @@
#ifndef ISTEAMUTILS001_H
#define ISTEAMUTILS001_H
#ifdef STEAM_WIN32
#pragma once
#endif
class ISteamUtils001
{
public:
// return the number of seconds since the user
virtual uint32 GetSecondsSinceAppActive() = 0;
virtual uint32 GetSecondsSinceComputerActive() = 0;
// the universe this client is connecting to
virtual EUniverse GetConnectedUniverse() = 0;
// Steam server time - in PST, number of seconds since January 1, 1970 (i.e unix time)
virtual uint32 GetServerRealTime() = 0;
// returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database)
// e.g "US" or "UK".
virtual const char *GetIPCountry() = 0;
// returns true if the image exists, and valid sizes were filled out
virtual bool GetImageSize( int iImage, uint32 *pnWidth, uint32 *pnHeight ) = 0;
// returns true if the image exists, and the buffer was successfully filled out
// results are returned in RGBA format
// the destination buffer size should be 4 * height * width * sizeof(char)
virtual bool GetImageRGBA( int iImage, uint8 *pubDest, int nDestBufferSize ) = 0;
};
#endif // ISTEAMUTILS001_H

View File

@ -38,6 +38,11 @@
#include "isteamclient019.h" #include "isteamclient019.h"
#include "isteamclient020.h" #include "isteamclient020.h"
#include "isteamuser.h" #include "isteamuser.h"
#include "isteamuser004.h"
#include "isteamuser005.h"
#include "isteamuser006.h"
#include "isteamuser007.h"
#include "isteamuser008.h"
#include "isteamuser009.h" #include "isteamuser009.h"
#include "isteamuser010.h" #include "isteamuser010.h"
#include "isteamuser011.h" #include "isteamuser011.h"
@ -68,6 +73,7 @@
#include "isteamfriends015.h" #include "isteamfriends015.h"
#include "isteamfriends016.h" #include "isteamfriends016.h"
#include "isteamutils.h" #include "isteamutils.h"
#include "isteamutils001.h"
#include "isteamutils002.h" #include "isteamutils002.h"
#include "isteamutils003.h" #include "isteamutils003.h"
#include "isteamutils004.h" #include "isteamutils004.h"

View File

@ -107,10 +107,10 @@ FileClose($hFile)
$interfaces_ini = @ScriptDir & '\steam_settings\steam_interfaces.ini' $interfaces_ini = @ScriptDir & '\steam_settings\steam_interfaces.ini'
$codex_ini = @ScriptDir & '\steam_misc\extra_cdx\CODEX\steam_emu.ini' $codex_ini = @ScriptDir & '\steam_misc\extra_crk\CODEX\steam_emu.ini'
_AddInterfaces($codex_ini) _AddInterfaces($codex_ini)
$rune_ini = @ScriptDir & '\steam_misc\extra_cdx\RUNE\steam_emu.ini' $rune_ini = @ScriptDir & '\steam_misc\extra_crk\RUNE\steam_emu.ini'
_AddInterfaces($rune_ini) _AddInterfaces($rune_ini)
FileDelete($interfaces_ini) FileDelete($interfaces_ini)

View File

@ -12,7 +12,7 @@ def __ClosestDictKey(targetKey : str, srcDict : dict[str, object] | set[str]) ->
return None return None
def __generate_ach_watcher_schema(lang: str, app_id: int, achs: list[dict]) -> list[dict]: def __generate_ach_watcher_schema(lang: str, app_id: int, achs: list[dict]) -> list[dict]:
print(f"[ ] __ writing {lang} {app_id}.db to '.\\schema\\{lang}' folder") print(f"[ ] __ writing {lang} {app_id}.db to <SCH_DIR>\\{lang} folder")
out_achs_list = [] out_achs_list = []
for idx in range(len(achs)): for idx in range(len(achs)):
ach = copy.deepcopy(achs[idx]) ach = copy.deepcopy(achs[idx])
@ -114,7 +114,7 @@ def generate_all_ach_watcher_schemas(
#print("[X] Couldn't generate Achievement Watcher schemas, no achievements found") # move notification to main script #print("[X] Couldn't generate Achievement Watcher schemas, no achievements found") # move notification to main script
return return
else: else:
print(f"[ ] Generating Achievement Watcher schemas...") print(f"[ ] Generating & packing Achievement Watcher schemas...")
#if app_exe: #if app_exe:
# print(f"[ ] __ Detected app exe: '{app_exe}'") # move notification to main script # print(f"[ ] __ Detected app exe: '{app_exe}'") # move notification to main script
#else: #else:
@ -163,7 +163,7 @@ def generate_all_ach_watcher_schemas(
print(f"[ ] __ Assuming english is the only supported language") print(f"[ ] __ Assuming english is the only supported language")
langs = ["english"] langs = ["english"]
print(f"[ ] __ schema = OUTPUT\\{appid}\\steam_misc\\achievement_watcher\\steam_cache\\schema") print(f"[ ] __ <SCH_DIR> = <OUT_DIR>\\steam_misc\\extra_acw\\steam_cache\\schema")
for lang in langs: for lang in langs:
out_schema_folder = os.path.join(ach_watcher_out_dir, lang) out_schema_folder = os.path.join(ach_watcher_out_dir, lang)

View File

@ -340,14 +340,14 @@ def download_app_details(
time.sleep(0.1) time.sleep(0.1)
if not app_details: if not app_details:
print(f"[?] No app details found - skip creating 'app_details.json'") print(f"[?] No app details found - skip creating <OUT_DIR>\\steam_misc\\app_info\\app_details.json")
#if last_exception: # skip showing last_exception #if last_exception: # skip showing last_exception
# print(f"[X] __ last error: {last_exception}") # print(f"[X] __ last error: {last_exception}")
return return
with open(details_out_file, "wt", encoding='utf-8') as f: with open(details_out_file, "wt", encoding='utf-8') as f:
json.dump(app_details, f, ensure_ascii=False, indent=2) json.dump(app_details, f, ensure_ascii=False, indent=2)
print(f"[ ] Found app details --- writing to 'app_details.json'") # move it here to avoid showing both 'downloading' and 'cannot download' print(f"[ ] Found app details --- writing to <OUT_DIR>\\steam_misc\\app_info\\app_details.json") # move it here to avoid showing both 'downloading' and 'cannot download'
if download_screenshots: if download_screenshots:
__download_screenshots(base_out_dir, appid, app_details) __download_screenshots(base_out_dir, appid, app_details)

View File

@ -17,7 +17,7 @@ __codex_ini = r'''###
### ßßßÛÛ²ÜÜÜÜÜÛ²ÛÛÛ²ßß ### ßßßÛÛ²ÜÜÜÜÜÛ²ÛÛÛ²ßß
### ###
### ###
### Game data is stored at %SystemDrive%\\Users\\Public\\Documents\\Steam\\CODEX\\{cdx_id} ### Game data is stored at %SystemDrive%\Users\Public\Documents\Steam\CODEX\{cdx_id}
### ###
[Settings] [Settings]
@ -141,7 +141,7 @@ def generate_cdx_ini(
os.makedirs(os.path.join(base_out_dir, "steam_misc\\extra_crk\\CODEX")) os.makedirs(os.path.join(base_out_dir, "steam_misc\\extra_crk\\CODEX"))
codex_ini_path = os.path.join(base_out_dir, "steam_misc\\extra_crk\\CODEX\\steam_emu.ini") codex_ini_path = os.path.join(base_out_dir, "steam_misc\\extra_crk\\CODEX\\steam_emu.ini")
print(f"[ ] Generating CODEX config --- writing 'steam_emu.ini'") print(f"[ ] Generating CODEX config --- writing <OUT_DIR>\\steam_misc\\extra_crk\\CODEX\\steam_emu.ini")
print(f"[ ] __ if to be used, make sure it has the correct interface versions") print(f"[ ] __ if to be used, make sure it has the correct interface versions")
dlc_list = [f"{d[0]}={d[1]}" for d in dlc] dlc_list = [f"{d[0]}={d[1]}" for d in dlc]

View File

@ -132,7 +132,7 @@ def generate_rne_ini(
os.makedirs(os.path.join(base_out_dir, "steam_misc\\extra_crk\\RUNE")) os.makedirs(os.path.join(base_out_dir, "steam_misc\\extra_crk\\RUNE"))
rune_ini_path = os.path.join(base_out_dir, "steam_misc\\extra_crk\\RUNE\\steam_emu.ini") rune_ini_path = os.path.join(base_out_dir, "steam_misc\\extra_crk\\RUNE\\steam_emu.ini")
print(f"[ ] Generating RUNE config --- writing 'steam_emu.ini'") print(f"[ ] Generating RUNE config --- writing <OUT_DIR>\\steam_misc\\extra_crk\\RUNE\\steam_emu.ini")
print(f"[ ] __ if to be used, make sure it has the correct interface versions") print(f"[ ] __ if to be used, make sure it has the correct interface versions")
dlc_list = [f"{d[0]}={d[1]}" for d in dlc] dlc_list = [f"{d[0]}={d[1]}" for d in dlc]

View File

@ -95,10 +95,13 @@ def download_scx(base_out_dir : str, appid : int):
_game_found=True _game_found=True
print(f"[ ] Searching SCX content...")
for line in app_scx_line: for line in app_scx_line:
if 'Game not found' in line: if 'Game not found' in line:
shutil.rmtree(os.path.join(base_out_dir, 'steam_misc\\app_scx')) shutil.rmtree(os.path.join(base_out_dir, 'steam_misc\\app_scx'))
_game_found=False _game_found=False
print(f"[?] __ no SCX content found --- nothing downloaded to <OUT_DIR>\\steam_misc\\app_scx folder")
break break
if ('class="tracking-wider font-league-gothic"' in line) and ('<a href="' in line): if ('class="tracking-wider font-league-gothic"' in line) and ('<a href="' in line):
@ -242,7 +245,7 @@ def download_scx(base_out_dir : str, appid : int):
if _trading_cards != line_series_name_safe: if _trading_cards != line_series_name_safe:
if _trading_cards_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _trading_cards_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading trading cards...") print(f"[ ] __ found '{line_series_name_safe}' trading cards...")
_trading_cards = line_series_name_safe _trading_cards = line_series_name_safe
if 'data-gallery-type="cards"' in line: if 'data-gallery-type="cards"' in line:
@ -296,7 +299,7 @@ def download_scx(base_out_dir : str, appid : int):
#if _foil_trading_cards != line_series_name_safe: #if _foil_trading_cards != line_series_name_safe:
#if _foil_trading_cards_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' #if _foil_trading_cards_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
#print(f"[ ] __ {line_series_name_safe} --- downloading foil trading cards...") #print(f"[ ] __ found '{line_series_name_safe}' foil trading cards...")
#_foil_trading_cards = line_series_name_safe #_foil_trading_cards = line_series_name_safe
if 'data-gallery-type="foil-cards"' in line: if 'data-gallery-type="foil-cards"' in line:
@ -340,7 +343,7 @@ def download_scx(base_out_dir : str, appid : int):
if _backgrounds != line_series_name_safe: if _backgrounds != line_series_name_safe:
if _backgrounds_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _backgrounds_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading backgrounds...") print(f"[ ] __ found '{line_series_name_safe}' backgrounds...")
_backgrounds = line_series_name_safe _backgrounds = line_series_name_safe
if 'data-gallery-type="backgrounds"' in line: if 'data-gallery-type="backgrounds"' in line:
@ -386,7 +389,7 @@ def download_scx(base_out_dir : str, appid : int):
if _badges != line_series_name_safe: if _badges != line_series_name_safe:
if _badges_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _badges_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading badges...") print(f"[ ] __ found '{line_series_name_safe}' badges...")
_badges = line_series_name_safe _badges = line_series_name_safe
if 'class="sm:h-[80px]"' in line: if 'class="sm:h-[80px]"' in line:
@ -418,7 +421,7 @@ def download_scx(base_out_dir : str, appid : int):
#if _foil_badges != line_series_name_safe: #if _foil_badges != line_series_name_safe:
#if _foil_badges_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' #if _foil_badges_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
#print(f"[ ] __ {line_series_name_safe} --- downloading foil badges...") #print(f"[ ] __ found '{line_series_name_safe}' foil badges...")
#_foil_badges = line_series_name_safe #_foil_badges = line_series_name_safe
if 'class="sm:h-[80px]"' in line: if 'class="sm:h-[80px]"' in line:
@ -450,7 +453,7 @@ def download_scx(base_out_dir : str, appid : int):
if _emoticons != line_series_name_safe: if _emoticons != line_series_name_safe:
if _emoticons_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _emoticons_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading emoticons...") print(f"[ ] __ found '{line_series_name_safe}' emoticons...")
_emoticons = line_series_name_safe _emoticons = line_series_name_safe
if 'class="sm:h-[54px]"' in line: if 'class="sm:h-[54px]"' in line:
@ -504,7 +507,7 @@ def download_scx(base_out_dir : str, appid : int):
if _animated_stickers != line_series_name_safe: if _animated_stickers != line_series_name_safe:
if _animated_stickers_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _animated_stickers_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading animated stickers...") print(f"[ ] __ found '{line_series_name_safe}' animated stickers...")
_animated_stickers = line_series_name_safe _animated_stickers = line_series_name_safe
if 'Animated" class=' in line: if 'Animated" class=' in line:
@ -559,7 +562,7 @@ def download_scx(base_out_dir : str, appid : int):
if _animated_backgrounds != line_series_name_safe: if _animated_backgrounds != line_series_name_safe:
if _animated_backgrounds_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _animated_backgrounds_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading animated backgrounds...") print(f"[ ] __ found '{line_series_name_safe}' animated backgrounds...")
_animated_backgrounds = line_series_name_safe _animated_backgrounds = line_series_name_safe
if 'class="sm:h-[99px] md:h-[87px] lg:h-[75px] xl:h-[83px] 2xl:h-[88px]"' in line: if 'class="sm:h-[99px] md:h-[87px] lg:h-[75px] xl:h-[83px] 2xl:h-[88px]"' in line:
@ -628,7 +631,7 @@ def download_scx(base_out_dir : str, appid : int):
if _animated_mini_backgrounds != line_series_name_safe: if _animated_mini_backgrounds != line_series_name_safe:
if _animated_mini_backgrounds_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _animated_mini_backgrounds_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading animated mini backgrounds...") print(f"[ ] __ found '{line_series_name_safe}' animated mini backgrounds...")
_animated_mini_backgrounds = line_series_name_safe _animated_mini_backgrounds = line_series_name_safe
if 'class="sm:h-[148px] md:h-[130px] lg:h-[112px] xl:h-[123px] 2xl:h-[132px]"' in line: if 'class="sm:h-[148px] md:h-[130px] lg:h-[112px] xl:h-[123px] 2xl:h-[132px]"' in line:
@ -697,7 +700,7 @@ def download_scx(base_out_dir : str, appid : int):
if _avatar_frames != line_series_name_safe: if _avatar_frames != line_series_name_safe:
if _avatar_frames_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _avatar_frames_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading avatar frames...") print(f"[ ] __ found '{line_series_name_safe}' avatar frames...")
_avatar_frames = line_series_name_safe _avatar_frames = line_series_name_safe
if '>Animation<' in line: if '>Animation<' in line:
@ -753,7 +756,7 @@ def download_scx(base_out_dir : str, appid : int):
if _animated_avatars != line_series_name_safe: if _animated_avatars != line_series_name_safe:
if _animated_avatars_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _animated_avatars_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading animated avatars...") print(f"[ ] __ found '{line_series_name_safe}' animated avatars...")
_animated_avatars = line_series_name_safe _animated_avatars = line_series_name_safe
if '>Animation<' in line: if '>Animation<' in line:
@ -809,7 +812,7 @@ def download_scx(base_out_dir : str, appid : int):
if _profiles != line_series_name_safe: if _profiles != line_series_name_safe:
if _profiles_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series' if _profiles_series == line_series_count: # this fixes duplicating message for last found 'section' in html source, after finding a new 'series'
print(f"[ ] __ {line_series_name_safe} --- downloading profiles...") print(f"[ ] __ found '{line_series_name_safe}' profiles...")
_profiles = line_series_name_safe _profiles = line_series_name_safe
if 'class="sm:h-[166px] md:h-[146px] lg:h-[126px] xl:h-[138px] 2xl:h-[148px]"' in line: if 'class="sm:h-[166px] md:h-[146px] lg:h-[126px] xl:h-[138px] 2xl:h-[148px]"' in line:

View File

@ -30,254 +30,254 @@ from configobj import ConfigObj
TOP_OWNER_IDS = list(dict.fromkeys([ TOP_OWNER_IDS = list(dict.fromkeys([
76561198028121353, 76561198028121353,
76561197979911851, 76561197979911851,
76561198017975643,
76561197993544755, 76561197993544755,
76561198355953202, 76561198355953202,
76561198001237877, 76561198001237877,
76561198237402290, 76561198237402290,
76561198355625888,
76561198152618007, 76561198152618007,
76561198355625888,
76561198213148949, 76561198213148949,
76561197969050296, 76561197969050296,
76561198217186687, 76561198217186687,
76561198037867621, 76561198037867621,
76561198017975643,
76561198094227663, 76561198094227663,
76561198019712127, 76561198019712127,
76561197963550511, 76561197963550511,
76561198134044398, 76561198134044398,
76561198001678750, 76561198001678750,
76561197973009892, 76561197973009892,
76561197976597747,
76561198044596404, 76561198044596404,
76561197976597747,
76561197969810632, 76561197969810632,
76561198095049646,
76561198085065107, 76561198085065107,
76561198864213876, 76561198864213876,
76561198095049646,
76561197962473290, 76561197962473290,
76561198388522904, 76561198388522904,
76561198063574735,
76561198033715344, 76561198033715344,
76561198313790296,
76561197995070100, 76561197995070100,
76561198313790296,
76561198063574735,
76561197996432822, 76561197996432822,
76561197976968076, 76561197976968076,
76561198281128349, 76561198281128349,
76561198027233260,
76561198154462478, 76561198154462478,
76561198027233260,
76561198842864763, 76561198842864763,
76561198235911884, 76561198010615256,
76561198035900006,
76561198122859224, 76561198122859224,
76561198235911884,
76561198027214426, 76561198027214426,
76561197970825215, 76561197970825215,
76561198035900006,
76561197968410781, 76561197968410781,
76561198407953371,
76561198001221571,
76561198104323854, 76561198104323854,
76561197979667190, 76561198001221571,
76561198256917957, 76561198256917957,
76561198008181611, 76561198008181611,
76561198407953371,
76561198062901118, 76561198062901118,
#76561198121398682, #76561197979667190,
#76561198077213101,
#76561197974742349, #76561197974742349,
#76561198096081579, #76561198077213101,
#76561198121398682,
#76561198019009765, #76561198019009765,
#76561199130977924,
#76561198139084236,
#76561197990233857,
#76561198118726910,
#76561197971011821,
#76561198124872187,
#76561198063728345,
#76561198119667710, #76561198119667710,
#76561198808371265, #76561197990233857,
#76561197992133229, #76561199130977924,
#76561198077248235, #76561198096081579,
#76561198005337430, #76561198139084236,
#76561197971011821,
#76561198063728345,
#76561198082995144, #76561198082995144,
#76561198045455280, #76561197963534359,
#76561198048373585, #76561198118726910,
#76561198109083829, #76561198097945516,
#76561198124872187,
#76561198077248235,
#76561198326510209, #76561198326510209,
#76561198152760885, #76561198109083829,
#76561198808371265,
#76561198048373585,
#76561198005337430,
#76561198045455280,
#76561197981111953, #76561197981111953,
#76561197992133229,
#76561198152760885,
#76561198037809069, #76561198037809069,
#76561198382166453,
#76561198093753361, #76561198093753361,
#76561199168919006,
#76561198396723427, #76561198396723427,
#76561198040421250, #76561199168919006,
#76561198017902347,
#76561198006391846, #76561198006391846,
#76561198121336040, #76561198040421250,
#76561198044387084,
#76561197994616562, #76561197994616562,
#76561199353305847, #76561198017902347,
#76561198044387084,
#76561198172367910, #76561198172367910,
#76561199353305847,
#76561198121336040,
#76561197972951657,
#76561198251835488, #76561198251835488,
#76561198021180815,
#76561198102767019, #76561198102767019,
#76561198021180815,
#76561197976796589, #76561197976796589,
#76561197992548975, #76561197992548975,
#76561198890581618, #76561198367471798,
#76561197972951657,
#76561198128158703,
#76561197965978376, #76561197965978376,
#76561198047438206,
#76561197993312863, #76561197993312863,
#76561198128158703,
#76561198015685843, #76561198015685843,
#76561198047438206,
#76561197971026489, #76561197971026489,
#76561198252374474, #76561198252374474,
#76561197995008105,
#76561199173688191,
#76561197984235967,
#76561198031837797,
#76561198417144062,
#76561198008797636,
#76561198020125851,
#76561198039492467,
#76561198061393233, #76561198061393233,
#76561198028011423, #76561199173688191,
#76561198008797636,
#76561197995008105,
#76561197984235967,
#76561198417144062,
#76561197978640923,
#76561198219343843,
#76561197982718230,
#76561198031837797,
#76561198039492467,
#76561198020125851,
#76561198192399786, #76561198192399786,
#76561198996604130, #76561198028011423,
#76561198367471798, #76561198318111105,
#76561197969148931,
#76561198029503957,
#76561198155124847, #76561198155124847,
#76561198168877244, #76561198168877244,
#76561198105279930,
#76561197988664525,
#76561198996604130,
#76561197969148931,
#76561198035552258, #76561198035552258,
#76561198015992850, #76561198015992850,
#76561198050474710,
#76561198029503957,
#76561198026221141, #76561198026221141,
#76561198025653291, #76561198025653291,
#76561197982718230,
#76561198219343843,
#76561198034213886, #76561198034213886,
#76561197972378106,
#76561198318111105,
#76561198004332929,
#76561198018254158,
#76561197970246998,
#76561197997477460,
#76561198158932704,
#76561198269242105,
#76561198045540632,
#76561198294806446,
#76561197986240493,
#76561198105279930,
#76561198043532513,
#76561197973230221,
#76561198003041763,
#76561198020746864,
#76561198054210948,
#76561198096632451, #76561198096632451,
#76561197962630138, #76561197972378106,
#76561198029532782, #76561197997477460,
#76561198086250077, #76561198054210948,
#76561198120120943,
#76561198111433283, #76561198111433283,
#76561198046642155, #76561198004332929,
#76561198048151962, #76561198045540632,
#76561198072936438, #76561198043532513,
#76561198124865933, #76561199080934614,
#76561197970246998,
#76561197986240493,
#76561198029532782,
#76561198018254158,
#76561197973230221,
#76561198020746864,
#76561198158932704,
#76561198086250077,
#76561198269242105,
#76561198294806446,
#76561198031164839,
#76561198019555404, #76561198019555404,
#76561198075477583, #76561198048151962,
#76561198042781427, #76561198003041763,
#76561198443388781, #76561198025391492,
#76561197962630138,
#76561198072936438,
#76561198120120943,
#76561197984010356, #76561197984010356,
#76561198042965266, #76561198042965266,
#76561198031164839, #76561198046642155,
#76561198025391492,
#76561198122276418,
#76561197981228012,
#76561198019841907,
#76561198106206019,
#76561197981027062,
#76561197992105918,
#76561198104561325,
#76561198015856631, #76561198015856631,
#76561197991699268, #76561198124865933,
#76561198315929726, #76561198042781427,
#76561198443388781,
#76561198426000196,
#76561198051725954, #76561198051725954,
#76561198050474710, #76561197992105918,
#76561198172925593,
#76561198071709714,
#76561197981228012,
#76561197981027062,
#76561198122276418,
#76561198019841907,
#76561197985091630, #76561197985091630,
#76561199492215670,
#76561198106206019,
#76561198090111762,
#76561198104561325,
#76561197991699268,
#76561198072361453,
#76561198027066612,
#76561198032614383,
#76561198844130640, #76561198844130640,
#76561198106145311,
#76561198079227501,
#76561198093579202,
#76561198315929726,
#76561198171791210,
#76561198264362271, #76561198264362271,
#76561198846208086, #76561198846208086,
#76561198032614383,
#76561198079227501,
#76561198026306582,
#76561198009596142,
#76561198056971296,
#76561197991613008, #76561197991613008,
#76561198026306582,
#76561197973701057,
#76561198028428529, #76561198028428529,
#76561198427572372, #76561198427572372,
#76561198071709714, #76561197983517848,
#76561198085238363,
#76561198070220549,
#76561198101049562, #76561198101049562,
#76561197969365800, #76561197969365800,
#76561198093579202,
#76561198171791210,
#76561198413266831, #76561198413266831,
#76561198165450871, #76561198015514779,
#76561198085238363,
#76561198106145311,
#76561197973701057,
#76561198811114019, #76561198811114019,
#76561198165450871,
#76561197994575642,
#76561198034906703, #76561198034906703,
#76561198119915053, #76561198119915053,
#76561198079896896, #76561198079896896,
#76561197988052802,
#76561198172925593,
#76561197970545939,
#76561198004532679,
#76561198008549198, #76561198008549198,
#76561198831075066, #76561197988052802,
#76561198004532679,
#76561198002535276, #76561198002535276,
#76561197970545939,
#76561197977920776, #76561197977920776,
#76561198015514779,
#76561198072361453,
#76561198070220549,
#76561197970307937,
#76561197982273259,
#76561197978640923,
#76561198090111762,
#76561198007200913, #76561198007200913,
#76561197984605215,
#76561198831075066,
#76561197970970678, #76561197970970678,
#76561197982273259,
#76561197970307937,
#76561198413088851,
#76561197970360549, #76561197970360549,
#76561198051740093, #76561198051740093,
#76561197966617426,
#76561198356842617,
#76561198025111129,
#76561197996825541, #76561197996825541,
#76561197967716198, #76561197967716198,
#76561198027066612, #76561197975329196,
#76561197962850521,
#76561197998058239, #76561197998058239,
#76561197966617426, #76561198027668357,
#76561197962850521,
#76561198258304011,
#76561198098314980, #76561198098314980,
#76561197984605215, #76561198127957838,
#76561198060520130,
#76561198035612474, #76561198035612474,
#76561198025111129,
#76561198318547224, #76561198318547224,
#76561198034503074, #76561198020810038,
#76561198426000196,
#76561198356842617,
#76561198150467988,
#76561198080773680, #76561198080773680,
#76561198083977059,
#76561198286209051,
#76561198033967307, #76561198033967307,
#76561197988445370, #76561198034503074,
#76561198217979953, #76561198150467988,
#76561198026278913,
#76561198321551799,
#76561199080934614,
#76561197963735863,
#76561197970127197,
#76561197994153029, #76561197994153029,
#76561197992357639, #76561198026278913,
#76561198070585472, #76561198217979953,
#76561198026921217, #76561197988445370,
#76561197983517848, #76561198083977059
#76561198027904347,
#76561198002536379,
#76561198027917594
])) ]))
def get_exe_dir(relative = False): def get_exe_dir(relative = False):
@ -301,7 +301,7 @@ def get_stats_schema(client, game_id, owner_id):
return client.wait_msg(EMsg.ClientGetUserStatsResponse, timeout=5) return client.wait_msg(EMsg.ClientGetUserStatsResponse, timeout=5)
def download_achievement_images(game_id : int, image_names : set[str], output_folder : str): def download_achievement_images(game_id : int, image_names : set[str], output_folder : str):
print(f"[ ] Found {len(image_names)} achievements images --- downloading to '.\\steam_settings\\img' folder") print(f"[ ] Found {len(image_names)} achievements images --- downloading to <OUT_DIR>\\steam_settings\\img folder")
q : queue.Queue[str] = queue.Queue() q : queue.Queue[str] = queue.Queue()
@ -356,7 +356,7 @@ def generate_achievement_stats(client, game_id : int, output_directory, backup_d
break break
if stats_schema_found is None: # no achievement found if stats_schema_found is None: # no achievement found
print(f"[?] No achievements found - skip creating 'achievements.json'") print(f"[?] No achievements found - skip creating <OUT_DIR>\\steam_settings\\achievements.json")
return [] return []
achievement_images_dir = os.path.join(output_directory, "img") achievement_images_dir = os.path.join(output_directory, "img")
@ -371,9 +371,9 @@ def generate_achievement_stats(client, game_id : int, output_directory, backup_d
) = achievements_gen.generate_stats_achievements(stats_schema_found.body.schema, output_directory) ) = achievements_gen.generate_stats_achievements(stats_schema_found.body.schema, output_directory)
if len(achievements) != 1: if len(achievements) != 1:
print(f"[ ] Found {len(achievements)} achievements --- writing to 'achievements.json'") print(f"[ ] Found {len(achievements)} achievements --- writing to <OUT_DIR>\\steam_settings\\achievements.json")
else: else:
print(f"[ ] Found {len(achievements)} achievement --- writing to 'achievements.json'") print(f"[ ] Found {len(achievements)} achievement --- writing to <OUT_DIR>\\steam_settings\\achievements.json")
#print(f"[ ] Writing 'UserGameStatsSchema_{game_id}.bin'") #print(f"[ ] Writing 'UserGameStatsSchema_{game_id}.bin'")
@ -592,16 +592,19 @@ def help():
print(" -rne: generate .ini file for RUNE Steam emu for each app") print(" -rne: generate .ini file for RUNE Steam emu for each app")
print(" -acw: generate schemas of all possible languages for Achievement Watcher") print(" -acw: generate schemas of all possible languages for Achievement Watcher")
print(" -skip_ach: skip downloading & generating achievements and their images") print(" -skip_ach: skip downloading & generating achievements and their images")
print(" -skip_con: skip downloading & generating controller configuration files") print(" -skip_con: skip downloading & generating controller configuration files (action sets txt files)")
print(" -skip_inv: skip downloading & generating inventory data (items.json & default_items.json)") print(" -skip_inv: skip downloading & generating inventory data ('items.json' & 'default_items.json')")
print(" -clr: delete any folder/file with the same name as the output before generating any data")
print(" -rel: generate temp files/folders, and expect input files, relative to the current working directory")
print(" -anon: login as an anonymous account, these have very limited access and cannot get all app details") print(" -anon: login as an anonymous account, these have very limited access and cannot get all app details")
print(" -name: save the output of each app in a folder with the same name as the app, unsafe characters are discarded") print(" -name: save the complete game config in a folder with the same name as the app (unsafe characters are discarded)")
print("\nAll switches are optional except app id, at least 1 app id must be provided") print(" -rel_out: generate complete game config in _OUTPUT/appid folder, relative to the bat, sh or app calling generate_emu_config app")
print(" -rel_raw: generate complete game config in the same folder that contains the bat, sh or app calling generate_emu_config app")
print(" -clr: clear output folder before generating the complete game config")
print(" do note that it will not work when '-rel_raw' argument is used too")
print("\nAll switches are optional except appid, at least 1 appid must be provided")
print("\nAutomate the login prompt:") print("\nAutomate the login prompt:")
print(" * You can create a file called 'my_login.txt' beside the script, then add your username on the first line") print(" * You can create a file called 'my_login.txt' beside the script, then add your:")
print(" and your password on the second line.") print(" USERNAME on the first line")
print(" PASSWORD on the second line")
print(" * You can set these 2 environment variables (will override 'my_login.txt'):") print(" * You can set these 2 environment variables (will override 'my_login.txt'):")
print(" GSE_CFG_USERNAME") print(" GSE_CFG_USERNAME")
print(" GSE_CFG_PASSWORD") print(" GSE_CFG_PASSWORD")
@ -664,8 +667,12 @@ def main():
CLEANUP_BEFORE_GENERATING = True CLEANUP_BEFORE_GENERATING = True
elif f'{appid}'.lower() == '-anon': elif f'{appid}'.lower() == '-anon':
ANON_LOGIN = True ANON_LOGIN = True
elif f'{appid}'.lower() == '-rel': elif f'{appid}'.lower() == '-rel_out':
RELATIVE_DIR = True RELATIVE_DIR = True
RELATIVE_set = 'out'
elif f'{appid}'.lower() == '-rel_raw':
RELATIVE_DIR = True
RELATIVE_set = 'raw'
elif f'{appid}'.lower() == '-skip_ach': elif f'{appid}'.lower() == '-skip_ach':
SKIP_ACH = True SKIP_ACH = True
elif f'{appid}'.lower() == '-skip_con': elif f'{appid}'.lower() == '-skip_con':
@ -698,13 +705,13 @@ def main():
sys.exit(1) sys.exit(1)
client = SteamClient() client = SteamClient()
# login_tmp_folder = os.path.join(get_exe_dir(RELATIVE_DIR), "login_temp") # login_tmp_folder = os.path.join(get_exe_dir(False), "login_temp") # replaced 'RELATIVE_DIR with 'False' to always look for or create login_temp in generate_emu_config folder
# if not os.path.exists(login_tmp_folder): # if not os.path.exists(login_tmp_folder):
# os.makedirs(login_tmp_folder) # os.makedirs(login_tmp_folder)
# client.set_credential_location(login_tmp_folder) # client.set_credential_location(login_tmp_folder)
# first read the 'my_login.txt' file # first read the 'my_login.txt' file
my_login_file = os.path.join(get_exe_dir(RELATIVE_DIR), "my_login.txt") my_login_file = os.path.join(get_exe_dir(False), "my_login.txt") # replaced 'RELATIVE_DIR with 'False' to always look for or create my_login.txt in generate_emu_config folder
if not ANON_LOGIN and os.path.isfile(my_login_file): if not ANON_LOGIN and os.path.isfile(my_login_file):
filedata = [''] filedata = ['']
with open(my_login_file, "r", encoding="utf-8") as f: with open(my_login_file, "r", encoding="utf-8") as f:
@ -743,7 +750,7 @@ def main():
top_own.top_owners() top_own.top_owners()
# read and prepend top_owners_ids.txt # read and prepend top_owners_ids.txt
top_owners_file = os.path.join(get_exe_dir(RELATIVE_DIR), "top_owners_ids.txt") top_owners_file = os.path.join(get_exe_dir(False), "top_owners_ids.txt") # replaced 'RELATIVE_DIR with 'False' to always look for or create top_owners_ids.txt in generate_emu_config folder
if os.path.isfile(top_owners_file): if os.path.isfile(top_owners_file):
filedata = [''] filedata = ['']
with open(top_owners_file, "r", encoding="utf-8") as f: with open(top_owners_file, "r", encoding="utf-8") as f:
@ -757,6 +764,17 @@ def main():
if not ANON_LOGIN: if not ANON_LOGIN:
TOP_OWNER_IDS.insert(0, client.steam_id.as_64) TOP_OWNER_IDS.insert(0, client.steam_id.as_64)
user_name = ''
user_repl = ''
if platform.system() == "Windows": # Windows
user_name = os.getenv("USERNAME")
user_repl = r'%username%'
elif platform.system() == "Linux": # Linux
user_name = os.getenv("USER")
user_repl = r'$user'
username = os.getenv("USERNAME") or os.getenv("USER")
for appid in appids: for appid in appids:
print(" ") print(" ")
@ -772,10 +790,8 @@ def main():
print(f"*** ABORTED config for app id {appid} ***") print(f"*** ABORTED config for app id {appid} ***")
print(" ") print(" ")
break break
game_info : dict = raw["apps"][appid]
print(f"[ ] Found product info --- writing to 'app_product_info.json'") game_info : dict = raw["apps"][appid]
game_info_common : dict = game_info.get("common", {}) game_info_common : dict = game_info.get("common", {})
app_name = game_info_common.get("name", "") app_name = game_info_common.get("name", "")
app_name_on_disk = f"{appid}" app_name_on_disk = f"{appid}"
@ -791,33 +807,64 @@ def main():
app_name = f"Unknown_Steam_app_{appid}" # we need this for later use in the Achievement Watcher app_name = f"Unknown_Steam_app_{appid}" # we need this for later use in the Achievement Watcher
print(f"[X] Cannot find app name on Steam store") print(f"[X] Cannot find app name on Steam store")
#root_backup_dir = os.path.join(get_exe_dir(RELATIVE_DIR), "BACKUP") #root_backup_dir = os.path.join(get_exe_dir(False), "_BACKUP") # replaced 'RELATIVE_DIR with 'False' to always look for or create _BACKUP in generate_emu_config folder
#backup_dir = os.path.join(root_backup_dir, f"{appid}") #backup_dir = os.path.join(root_backup_dir, f"{appid}")
#if not os.path.exists(backup_dir): #if not os.path.exists(backup_dir):
# os.makedirs(backup_dir) # os.makedirs(backup_dir)
root_def_dir = "_DEFAULT" root_def_dir_RELATIVE = os.path.join(get_exe_dir(True), "_DEFAULT") # _DEFAULT folder relative to external bat, sh or app calling generate_emu_config exe; with get_exe_dir(False) is only relative to generate_emu_config exe
root_out_dir = "_OUTPUT" root_out_dir_RELATIVE = os.path.join(get_exe_dir(True), "_OUTPUT") # _OUTPUT folder relative to external bat, sh or app calling generate_emu_config exe; with get_exe_dir(False) is only relative to generate_emu_config exe
base_out_dir = os.path.join(root_out_dir, app_name_on_disk)
if RELATIVE_DIR:
if RELATIVE_set == 'out':
root_out_dir = os.path.join(get_exe_dir(True), "_OUTPUT")
base_out_dir = os.path.join(root_out_dir, app_name_on_disk)
CLEANUP_override = 0
elif RELATIVE_set == 'raw':
root_out_dir = os.path.join(get_exe_dir(True))
base_out_dir = os.path.join(get_exe_dir(True))
CLEANUP_override = 1
if os.path.exists(root_def_dir_RELATIVE) and os.path.isdir(root_def_dir_RELATIVE):
if os.listdir(root_def_dir_RELATIVE):
root_def_dir = os.path.join(get_exe_dir(True), "_DEFAULT")
else:
root_def_dir = os.path.join(get_exe_dir(False), "_DEFAULT")
else:
root_def_dir = os.path.join(get_exe_dir(False), "_DEFAULT")
else:
root_out_dir = os.path.join(get_exe_dir(False), "_OUTPUT")
base_out_dir = os.path.join(root_out_dir, app_name_on_disk)
CLEANUP_override = 0
root_def_dir = os.path.join(get_exe_dir(False), "_DEFAULT")
emu_settings_dir = os.path.join(base_out_dir, "steam_settings") emu_settings_dir = os.path.join(base_out_dir, "steam_settings")
info_out_dir = os.path.join(base_out_dir, "steam_misc\\app_info") info_out_dir = os.path.join(base_out_dir, "steam_misc\\app_info")
print(f"[ ] DEF_DIR = {root_def_dir.replace(user_name, user_repl, 1)}")
if RELATIVE_DIR and (RELATIVE_set == 'raw'):
print(f"[ ] OUT_DIR = {os.getcwd().replace(user_name, user_repl, 1)}")
else:
print(f"[ ] OUT_DIR = {base_out_dir.replace(user_name, user_repl, 1)}")
if CLEANUP_BEFORE_GENERATING: if CLEANUP_BEFORE_GENERATING:
print(f"[ ] Cleaning '{base_out_dir}' folder...") if CLEANUP_override == 0:
base_dir_path = pathlib.Path(base_out_dir) print(f"[ ] Cleaning <OUT_DIR> folder...")
if base_dir_path.is_file(): base_dir_path = pathlib.Path(base_out_dir)
base_dir_path.unlink() if base_dir_path.is_file():
time.sleep(0.05) base_dir_path.unlink()
elif base_dir_path.is_dir(): time.sleep(0.05)
shutil.rmtree(base_dir_path) elif base_dir_path.is_dir():
time.sleep(0.05) shutil.rmtree(base_dir_path)
time.sleep(0.05)
while base_dir_path.exists(): while base_dir_path.exists():
time.sleep(0.05) time.sleep(0.05)
root_backup_dir = os.path.join(base_out_dir, "steam_misc\\app_backup") root_backup_dir = os.path.join(base_out_dir, "steam_misc\\app_backup")
#backup_dir = os.path.join(root_backup_dir, f"{appid}") #backup_dir = os.path.join(root_backup_dir, f"{appid}")
backup_dir = root_backup_dir #use different structure for 'backup' dir backup_dir = root_backup_dir #use different structure for 'backup' dir
if not os.path.exists(backup_dir): if not os.path.exists(backup_dir):
os.makedirs(backup_dir) os.makedirs(backup_dir)
@ -830,27 +877,28 @@ def main():
#with open(os.path.join(info_out_dir, "app_widget.url"), mode='w', newline='\r\n') as f: #with open(os.path.join(info_out_dir, "app_widget.url"), mode='w', newline='\r\n') as f:
#f.write(f"[InternetShortcut]\nURL=https://store.steampowered.com/widget/{appid}/") #f.write(f"[InternetShortcut]\nURL=https://store.steampowered.com/widget/{appid}/")
if DEFAULT_PRESET == True: print(f"[ ] Copying preset emu configs...")
print(f"[ ] Copying preset emu configs to '{base_out_dir}' folder") shutil.copytree(os.path.join(root_def_dir, str(0)), base_out_dir, dirs_exist_ok=True) # copy from default emu dir
shutil.copytree(os.path.join(root_def_dir, str(0)), base_out_dir, dirs_exist_ok=True) # copy from default emu dir print(f"[ ] __ default emu config from <DEF_DIR>\\{str(0)} folder")
print(f"[ ] __ default emu config from '{os.path.join(root_def_dir, str(0))}' folder") shutil.copytree(os.path.join(root_def_dir, str(DEFAULT_PRESET_NO)), base_out_dir, dirs_exist_ok=True) # copy from preset emu dir
shutil.copytree(os.path.join(root_def_dir, str(DEFAULT_PRESET_NO)), base_out_dir, dirs_exist_ok=True) # copy from preset emu dir print(f"[ ] __ preset emu config from <DEF_DIR>\\{str(DEFAULT_PRESET_NO)} folder")
print(f"[ ] __ preset emu config from '{os.path.join(root_def_dir, str(DEFAULT_PRESET_NO))}' folder") if os.path.exists(os.path.join(root_def_dir, str(appid))):
if os.path.exists(os.path.join(root_def_dir, str(appid))): shutil.copytree(os.path.join(root_def_dir, str(appid)), base_out_dir, dirs_exist_ok=True) # copy from preset app dir
shutil.copytree(os.path.join(root_def_dir, str(appid)), base_out_dir, dirs_exist_ok=True) # copy from preset app dir print(f"[ ] __ app emu config from <DEF_DIR>\\{str(appid)} folder")
print(f"[ ] __ app emu config from '{os.path.join(root_def_dir, str(appid))}' folder")
with open(os.path.join(emu_settings_dir, "steam_appid.txt"), 'w') as f: with open(os.path.join(emu_settings_dir, "steam_appid.txt"), 'w') as f:
f.write(str(appid)) f.write(str(appid))
#print(f"[ ] Writing 'steam_appid.txt'") #print(f"[ ] Writing 'steam_appid.txt'")
print(f"[ ] Found product info --- writing to <OUT_DIR>\\steam_misc\\app_info\\app_product_info.json")
with open(os.path.join(info_out_dir, "app_product_info.json"), "wt", encoding='utf-8') as f: with open(os.path.join(info_out_dir, "app_product_info.json"), "wt", encoding='utf-8') as f:
json.dump(game_info, f, ensure_ascii=False, indent=2) json.dump(game_info, f, ensure_ascii=False, indent=2)
#print(f"[ ] Writing 'app_product_info.json'") #print(f"[ ] Writing 'app_product_info.json'")
with open(os.path.join(backup_dir, "product_info.json"), "wt", encoding='utf-8') as f: with open(os.path.join(backup_dir, "product_info.json"), "wt", encoding='utf-8') as f:
json.dump(game_info, f, ensure_ascii=False, indent=2) json.dump(game_info, f, ensure_ascii=False, indent=2)
#print(f"[ ] Writing 'app_product_info.json'") #print(f"[ ] Writing 'product_info.json'")
app_details.download_app_details( app_details.download_app_details(
base_out_dir, info_out_dir, base_out_dir, info_out_dir,
@ -897,11 +945,11 @@ def main():
f.write(f'{lang}\n') f.write(f'{lang}\n')
#print(f"[ ] Writing 'supported_languages.txt'") #print(f"[ ] Writing 'supported_languages.txt'")
if len(languages) == 1: if len(languages) == 1:
print(f"[ ] Found {len(languages)} supported language --- writing to 'supported_languages.txt'") print(f"[ ] Found {len(languages)} supported language --- writing to <OUT_DIR>\\steam_settings\\supported_languages.txt")
else: else:
print(f"[ ] Found {len(languages)} supported languages --- writing to 'supported_languages.txt'") print(f"[ ] Found {len(languages)} supported languages --- writing to <OUT_DIR>\\steam_settings\\supported_languages.txt")
else: else:
print(f"[?] No supported languages found - skip creating 'supported_languages.txt'") print(f"[?] No supported languages found - skip creating <OUT_DIR>\\steam_settings\\supported_languages.txt")
ReplaceStringInFile(os.path.join(emu_settings_dir, "configs.app.ini"), 'This is another example DLC name', '# 56789=', '56789=') # make sure we write DLCs after '# 56789=This is another example DLC name' ReplaceStringInFile(os.path.join(emu_settings_dir, "configs.app.ini"), 'This is another example DLC name', '# 56789=', '56789=') # make sure we write DLCs after '# 56789=This is another example DLC name'
@ -935,11 +983,11 @@ def main():
dlc_config_list.append((dlc, dlc_name)) dlc_config_list.append((dlc, dlc_name))
if len(dlc_list) == 1: if len(dlc_list) == 1:
print(f"[ ] Found {len(dlc_config_list)} DLC --- writing to 'configs.app.ini'") print(f"[ ] Found {len(dlc_config_list)} DLC --- writing to <OUT_DIR>\\steam_settings\\configs.app.ini")
else: else:
print(f"[ ] Found {len(dlc_config_list)} DLCs --- writing to 'configs.app.ini'") print(f"[ ] Found {len(dlc_config_list)} DLCs --- writing to <OUT_DIR>\\steam_settings\\configs.app.ini")
else: else:
print(f"[?] No DLCs found - skip writing to 'configs.app.ini'") print(f"[?] No DLCs found - skip writing to <OUT_DIR>\\steam_settings\\configs.app.ini")
if not dlc_raw == {}: if not dlc_raw == {}:
with open(os.path.join(info_out_dir, "dlc_product_info.json"), "wt", encoding='utf-8') as f: with open(os.path.join(info_out_dir, "dlc_product_info.json"), "wt", encoding='utf-8') as f:
@ -1021,25 +1069,25 @@ def main():
f.write(f"{game_depot}\n") f.write(f"{game_depot}\n")
#print(f"[ ] Writing 'depots.txt'") #print(f"[ ] Writing 'depots.txt'")
if len(all_depots) == 1: if len(all_depots) == 1:
print(f"[ ] Found {len(all_depots)} depot --- writing to 'depots.txt'") print(f"[ ] Found {len(all_depots)} depot --- writing to <OUT_DIR>\\steam_settings\\depots.txt")
else: else:
print(f"[ ] Found {len(all_depots)} depots --- writing to 'depots.txt'") print(f"[ ] Found {len(all_depots)} depots --- writing to <OUT_DIR>\\steam_settings\\depots.txt")
else: else:
print(f"[?] No depots found - skip creating 'depots.txt'") print(f"[?] No depots found - skip creating <OUT_DIR>\\steam_settings\\depots.txt")
if len(all_branches) >= 1: if len(all_branches) >= 1:
with open(os.path.join(emu_settings_dir, "branches.json"), "wt", encoding='utf-8') as f: with open(os.path.join(emu_settings_dir, "branches.json"), "wt", encoding='utf-8') as f:
json.dump(all_branches, f, ensure_ascii=False, indent=2) json.dump(all_branches, f, ensure_ascii=False, indent=2)
if len(all_branches) == 1: if len(all_branches) == 1:
print(f"[ ] Found {len(all_branches)} branch --- writing to 'branches.json'") print(f"[ ] Found {len(all_branches)} branch --- writing to <OUT_DIR>\\steam_settings\\branches.json")
else: else:
print(f"[ ] Found {len(all_branches)} branches --- writing to 'branches.json'") print(f"[ ] Found {len(all_branches)} branches --- writing to <OUT_DIR>\\steam_settings\\branches.json")
if "public" in game_info["depots"]["branches"]: if "public" in game_info["depots"]["branches"]:
if "buildid" in game_info["depots"]["branches"]["public"]: if "buildid" in game_info["depots"]["branches"]["public"]:
buildid = game_info["depots"]["branches"]["public"]["buildid"] buildid = game_info["depots"]["branches"]["public"]["buildid"]
print(f"[ ] __ default branch name: public, latest build id: {buildid}") print(f"[ ] __ default branch name: public, latest build id: {buildid}")
else: else:
print(f"[?] No branches found - skip creating 'branches.json'") print(f"[?] No branches found - skip creating <OUT_DIR>\\steam_settings\\branches.json")
# read some keys from 'configs.user.ini' # read some keys from 'configs.user.ini'
cfg_user = ConfigObj(os.path.join(emu_settings_dir, "configs.user.ini"), encoding='utf-8') cfg_user = ConfigObj(os.path.join(emu_settings_dir, "configs.user.ini"), encoding='utf-8')
@ -1047,86 +1095,100 @@ def main():
cfg_user_account_steamid = cfg_user["user::general"]["account_steamid"] cfg_user_account_steamid = cfg_user["user::general"]["account_steamid"]
cfg_user_language = cfg_user["user::general"]["language"] cfg_user_language = cfg_user["user::general"]["language"]
config_found = 0 config_found = 0 # needed to show 'No controller configs found...' if value remains 0
config_generated = 0 # used to avoid overwriting supported config by unsupported one config_generated = 0 # used to avoid overwriting supported config by unsupported one
config_generated_not_sup = 0 # used to avoid overwriting prefered unsupported config if no supported config present
downloading_ctrl_vdf = 0 # needed to remove possible duplicate 'Found controller configs...' downloading_ctrl_vdf = 0 # needed to remove possible duplicate 'Found controller configs...'
valid_id = 0 # needed to skip showing "Found controller configs..." if no valid is found in either "steamcontrollerconfigdetails" or "steamcontrollertouchconfigdetails"
if "config" in game_info: if "config" in game_info:
if not SKIP_CONTROLLER and "steamcontrollerconfigdetails" in game_info["config"]: if not SKIP_CONTROLLER and "steamcontrollerconfigdetails" in game_info["config"]:
controller_details = game_info["config"]["steamcontrollerconfigdetails"] controller_details = game_info["config"]["steamcontrollerconfigdetails"]
print(f"[ ] Found controller configs --- generating action sets...")
downloading_ctrl_vdf=1
for id in controller_details: for id in controller_details:
details = controller_details[id] # make sure the controller config id exists and is a numeric string
controller_type = "" # fixes "TypeError: string indices must be integers, not 'str'" when generating for "Unknown 9: Awakening" (appid 1477940)
enabled_branches = "" if id.isdigit():
if "controller_type" in details: if (downloading_ctrl_vdf == 0) and (valid_id == 0):
controller_type = details["controller_type"] print(f"[ ] Found controller configs --- generating action sets...")
if "enabled_branches" in details: downloading_ctrl_vdf = 1
enabled_branches = details["enabled_branches"] valid_id = 1
details = controller_details[id]
if (("default" in enabled_branches) or ("public" in enabled_branches)): # download only 'default' and 'public' branches to avoid multiple configs for same controller type controller_type = ""
print(f'[ ] __ downloading config, file id = {id}, controller type = {controller_type}') # first noticed for Elden Ring, two 'controller_ps4' vdf configs are downloaded, but only one of them is converted to action sets enabled_branches = ""
out_vdf = download_published_file(client, int(id), os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}')) if "controller_type" in details:
controller_type = details["controller_type"]
if "enabled_branches" in details:
enabled_branches = details["enabled_branches"]
if out_vdf is not None: out_vdf = None # initialize out_vdf, fixes "UnboundLocalError: cannot access local variable 'out_vdf' where it is not associated with a value" when generating for "Factorio" (appid 427520)
if (controller_type in ["controller_xbox360", "controller_xboxone"] and (("default" in enabled_branches) or ("public" in enabled_branches))):
config_found = 1 if (("default" in enabled_branches) or ("public" in enabled_branches)): # download only 'default' and 'public' branches to avoid multiple configs for same controller type
#print(f"[ ] __ controller type '{controller_type}' is supported ... converting .vdf to action sets") print(f'[ ] __ downloading config, file id = {id}, controller type = {controller_type}') # first noticed for Elden Ring, two 'controller_ps4' vdf configs are downloaded, but only one of them is converted to action sets
if config_generated == 0: out_vdf = download_published_file(client, int(id), os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'))
print(f"[ ] __ parsing '{controller_type}' vdf - supported, can be used with emu")
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
# delete txt files in .\steam_settings\controller folder if out_vdf is not None:
for txt_file in os.listdir(os.path.join(emu_settings_dir, "controller")): if (controller_type in ["controller_xbox360", "controller_xboxone"] and (("default" in enabled_branches) or ("public" in enabled_branches))):
if not txt_file.endswith(".txt"): config_found = 1
continue #print(f"[ ] __ controller type '{controller_type}' is supported ... converting .vdf to action sets")
os.remove(os.path.join(os.path.join(emu_settings_dir, "controller"), txt_file)) if config_generated == 0:
shutil.copytree(os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"), os.path.join(emu_settings_dir, "controller"), dirs_exist_ok=True) print(f"[ ] __ parsing '{controller_type}' vdf - supported, can be used with emu")
config_generated = 1 parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
else:
print(f"[ ] __ parsing '{controller_type}' vdf - supported, can be used with emu")
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
if controller_type in ["controller_xboxone"]: # always use xboxone config if present
# delete txt files in .\steam_settings\controller folder # delete txt files in .\steam_settings\controller folder
for txt_file in os.listdir(os.path.join(emu_settings_dir, "controller")): for txt_file in os.listdir(os.path.join(emu_settings_dir, "controller")):
if not txt_file.endswith(".txt"): if not txt_file.endswith(".txt"):
continue continue
os.remove(os.path.join(os.path.join(emu_settings_dir, "controller"), txt_file)) os.remove(os.path.join(os.path.join(emu_settings_dir, "controller"), txt_file))
shutil.copytree(os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"), os.path.join(emu_settings_dir, "controller"), dirs_exist_ok=True) shutil.copytree(os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"), os.path.join(emu_settings_dir, "controller"), dirs_exist_ok=True)
#config_generated = 1 config_generated = 1
else:
print(f"[ ] __ parsing '{controller_type}' vdf - supported, can be used with emu")
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
elif (controller_type in ["controller_ps4", "controller_ps5", "controller_steamcontroller_gordon", "controller_neptune", "controller_switch_pro"] and (("default" in enabled_branches) or ("public" in enabled_branches))): if controller_type in ["controller_xboxone"]: # always use xboxone config if present
config_found=1 # delete txt files in .\steam_settings\controller folder
#print(f"[X] __ controller type '{controller_type}' is not supported ... converting .vdf to action sets") for txt_file in os.listdir(os.path.join(emu_settings_dir, "controller")):
print(f"[X] __ parsing '{controller_type}' vdf - not supported, backup purposes only") if not txt_file.endswith(".txt"):
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set")) continue
os.remove(os.path.join(os.path.join(emu_settings_dir, "controller"), txt_file))
shutil.copytree(os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"), os.path.join(emu_settings_dir, "controller"), dirs_exist_ok=True)
#config_generated = 1
elif (controller_type in ["controller_ps4", "controller_ps5", "controller_steamcontroller_gordon", "controller_neptune", "controller_switch_pro"] and (("default" in enabled_branches) or ("public" in enabled_branches))):
config_found=1
#print(f"[ ] __ controller type '{controller_type}' is not supported ... converting .vdf to action sets")
print(f"[ ] __ parsing '{controller_type}' vdf - not supported, backup purposes only")
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
if not SKIP_CONTROLLER and "steamcontrollertouchconfigdetails" in game_info["config"]: if not SKIP_CONTROLLER and "steamcontrollertouchconfigdetails" in game_info["config"]:
controller_details = game_info["config"]["steamcontrollertouchconfigdetails"] controller_details = game_info["config"]["steamcontrollertouchconfigdetails"]
if downloading_ctrl_vdf == 0:
print(f"[ ] Found controller configs --- generating action sets...")
for id in controller_details: for id in controller_details:
details = controller_details[id] # make sure the controller config id exists and is a numeric string
controller_type = "" # fixes "TypeError: string indices must be integers, not 'str'" when generating for "Unknown 9: Awakening" (appid 1477940)
enabled_branches = "" if id.isdigit():
if "controller_type" in details: if (downloading_ctrl_vdf == 0) and (valid_id == 0):
controller_type = details["controller_type"] print(f"[ ] Found controller configs --- generating action sets...")
if "enabled_branches" in details: downloading_ctrl_vdf = 1
enabled_branches = details["enabled_branches"] valid_id = 1
details = controller_details[id]
controller_type = ""
enabled_branches = ""
if "controller_type" in details:
controller_type = details["controller_type"]
if "enabled_branches" in details:
enabled_branches = details["enabled_branches"]
out_vdf = None # initialize out_vdf, fixes "UnboundLocalError: cannot access local variable 'out_vdf' where it is not associated with a value" when generating for "Factorio" (appid 427520)
if (("default" in enabled_branches) or ("public" in enabled_branches)): # download only 'default' and 'public' branches to avoid multiple configs for same controller type
print(f'[ ] __ downloading config, file id = {id}, controller type = {controller_type}') # first noticed for Elden Ring, two 'controller_ps4' vdf configs are downloaded, but only one of them is converted to action sets
out_vdf = download_published_file(client, int(id), os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'))
if out_vdf is not None:
if (controller_type in ["controller_mobile_touch"] and (("default" in enabled_branches) or ("public" in enabled_branches))):
config_found = 1
#print(f"[ ] __ controller type '{controller_type}' is not supported ... converting .vdf to action sets")
print(f"[ ] __ parsing '{controller_type}' vdf - not supported, backup purposes only")
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
if (("default" in enabled_branches) or ("public" in enabled_branches)): # download only 'default' and 'public' branches to avoid multiple configs for same controller type
print(f'[ ] __ downloading config, file id = {id}, controller type = {controller_type}') # first noticed for Elden Ring, two 'controller_ps4' vdf configs are downloaded, but only one of them is converted to action sets
out_vdf = download_published_file(client, int(id), os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'))
if out_vdf is not None:
if (controller_type in ["controller_mobile_touch"] and (("default" in enabled_branches) or ("public" in enabled_branches))):
config_found = 1
#print(f"[X] __ controller type '{controller_type}' is not supported ... converting .vdf to action sets")
print(f"[X] __ parsing '{controller_type}' vdf - not supported, backup purposes only")
parse_controller_vdf.generate_controller_config(out_vdf.decode('utf-8'), os.path.join(os.path.join(backup_dir, 'controller\\' + f'{controller_type}' + '_' + f'{id}'), "action_set"))
''' # NOTE zip the parent 'app_backup' folder instead of only the child 'controller' folder ''' # NOTE zip the parent 'app_backup' folder instead of only the child 'controller' folder
if config_found: if config_found:
shutil.make_archive(os.path.join(backup_dir, 'controller'), 'zip', os.path.join(backup_dir, 'controller')) # first argument is the name of the zip file shutil.make_archive(os.path.join(backup_dir, 'controller'), 'zip', os.path.join(backup_dir, 'controller')) # first argument is the name of the zip file
@ -1230,9 +1292,9 @@ def main():
raw_inventory = json.dumps(inventory, indent=4) raw_inventory = json.dumps(inventory, indent=4)
if len(inventory) != 1: if len(inventory) != 1:
print(f"[ ] Found {len(inventory)} inventory items --- writing to 'items.json' and 'default_items.json'") print(f"[ ] Found {len(inventory)} inventory items --- writing to <OUT_DIR>\\steam_settings\\items.json & default_items.json")
else: else:
print(f"[ ] Found {len(inventory)} inventory item --- writing to 'items.json' and 'default_items.json'") print(f"[ ] Found {len(inventory)} inventory item --- writing to <OUT_DIR>\\steam_settings\\items.json & default_items.json")
with open(os.path.join(backup_dir, f"InventoryItems_{appid}.json"), "w") as f: with open(os.path.join(backup_dir, f"InventoryItems_{appid}.json"), "w") as f:
f.write(raw_inventory) f.write(raw_inventory)
@ -1260,7 +1322,7 @@ def main():
#print(f"[ ] __ writing 'default_items.json'") #print(f"[ ] __ writing 'default_items.json'")
else: else:
print(f"[?] No inventory items found - skip creating 'items.json' and 'default_items.json'") print(f"[?] No inventory items found - skip creating <OUT_DIR>\\steam_settings\\items.json & default_items.json")
if app_exe: if app_exe:
if app_mode_new != "": if app_mode_new != "":

View File

@ -30,9 +30,14 @@ cp -a "_DEFAULT" "$out_dir/generate_emu_config/_DEFAULT"
cp -f "steam_default_icon_locked.jpg" "$out_dir/generate_emu_config" cp -f "steam_default_icon_locked.jpg" "$out_dir/generate_emu_config"
cp -f "steam_default_icon_unlocked.jpg" "$out_dir/generate_emu_config" cp -f "steam_default_icon_unlocked.jpg" "$out_dir/generate_emu_config"
cp -f "README.md" "$out_dir/generate_emu_config" cp -f "README.md" "$out_dir/generate_emu_config"
echo "Check the README" > "$out_dir/generate_emu_config/my_login.EXAMPLE.txt" if [ -e top_owners_ids.txt ]
echo "Check the README" > "$out_dir/generate_emu_config/top_owners_ids.EXAMPLE.txt" then
echo "You can use a website like: https://steamladder.com/games/" >> "$out_dir/generate_emu_config/top_owners_ids.EXAMPLE.txt" cp -f "top_owners_ids.txt" "$out_dir/generate_emu_config"
else
echo "Check the README" > "$out_dir/generate_emu_config/my_login.EXAMPLE.txt"
echo "Check the README" > "$out_dir/generate_emu_config/top_owners_ids.EXAMPLE.txt"
echo "You can use a website like: https://steamladder.com/games/" >> "$out_dir/generate_emu_config/top_owners_ids.EXAMPLE.txt"
fi
echo; echo;
echo ============= echo =============

View File

@ -122,9 +122,9 @@ def generate_stats_achievements(
if output_stats: if output_stats:
with open(os.path.join(config_directory, "stats.txt"), 'wt', encoding='utf-8') as f: with open(os.path.join(config_directory, "stats.txt"), 'wt', encoding='utf-8') as f:
f.writelines(output_stats) f.writelines(output_stats)
print(f"[ ] Found {len(output_stats)} stats --- writing to 'stats.txt'") print(f"[ ] Found {len(output_stats)} stats --- writing to <OUT_DIR>\\steam_settings\\stats.txt'")
else: else:
print(f"[?] No stats found - skip creating 'stats.txt'") print(f"[?] No stats found - skip creating <OUT_DIR>\\steam_settings\\stats.txt")
return (achievements_out, stats_out, return (achievements_out, stats_out,
copy_default_unlocked_img, copy_default_locked_img) copy_default_unlocked_img, copy_default_locked_img)

View File

@ -1,250 +1,250 @@
76561198028121353 76561198028121353
76561197979911851 76561197979911851
76561198017975643
76561197993544755 76561197993544755
76561198355953202 76561198355953202
76561198001237877 76561198001237877
76561198237402290 76561198237402290
76561198355625888
76561198152618007 76561198152618007
76561198355625888
76561198213148949 76561198213148949
76561197969050296 76561197969050296
76561198217186687 76561198217186687
76561198037867621 76561198037867621
76561198017975643
76561198094227663 76561198094227663
76561198019712127 76561198019712127
76561197963550511 76561197963550511
76561198134044398 76561198134044398
76561198001678750 76561198001678750
76561197973009892 76561197973009892
76561197976597747
76561198044596404 76561198044596404
76561197976597747
76561197969810632 76561197969810632
76561198095049646
76561198085065107 76561198085065107
76561198864213876 76561198864213876
76561198095049646
76561197962473290 76561197962473290
76561198388522904 76561198388522904
76561198063574735
76561198033715344 76561198033715344
76561198313790296
76561197995070100 76561197995070100
76561198313790296
76561198063574735
76561197996432822 76561197996432822
76561197976968076 76561197976968076
76561198281128349 76561198281128349
76561198027233260
76561198154462478 76561198154462478
76561198027233260
76561198842864763 76561198842864763
76561198235911884 76561198010615256
76561198035900006
76561198122859224 76561198122859224
76561198235911884
76561198027214426 76561198027214426
76561197970825215 76561197970825215
76561198035900006
76561197968410781 76561197968410781
76561198407953371
76561198001221571
76561198104323854 76561198104323854
76561197979667190 76561198001221571
76561198256917957 76561198256917957
76561198008181611 76561198008181611
76561198407953371
76561198062901118 76561198062901118
76561198121398682 76561197979667190
76561198077213101
76561197974742349 76561197974742349
76561198096081579 76561198077213101
76561198121398682
76561198019009765 76561198019009765
76561199130977924
76561198139084236
76561197990233857
76561198118726910
76561197971011821
76561198124872187
76561198063728345
76561198119667710 76561198119667710
76561198808371265 76561197990233857
76561197992133229 76561199130977924
76561198077248235 76561198096081579
76561198005337430 76561198139084236
76561197971011821
76561198063728345
76561198082995144 76561198082995144
76561198045455280 76561197963534359
76561198048373585 76561198118726910
76561198109083829 76561198097945516
76561198124872187
76561198077248235
76561198326510209 76561198326510209
76561198152760885 76561198109083829
76561198808371265
76561198048373585
76561198005337430
76561198045455280
76561197981111953 76561197981111953
76561197992133229
76561198152760885
76561198037809069 76561198037809069
76561198382166453
76561198093753361 76561198093753361
76561199168919006
76561198396723427 76561198396723427
76561198040421250 76561199168919006
76561198017902347
76561198006391846 76561198006391846
76561198121336040 76561198040421250
76561198044387084
76561197994616562 76561197994616562
76561199353305847 76561198017902347
76561198044387084
76561198172367910 76561198172367910
76561199353305847
76561198121336040
76561197972951657
76561198251835488 76561198251835488
76561198021180815
76561198102767019 76561198102767019
76561198021180815
76561197976796589 76561197976796589
76561197992548975 76561197992548975
76561198890581618 76561198367471798
76561197972951657
76561198128158703
76561197965978376 76561197965978376
76561198047438206
76561197993312863 76561197993312863
76561198128158703
76561198015685843 76561198015685843
76561198047438206
76561197971026489 76561197971026489
76561198252374474 76561198252374474
76561197995008105
76561199173688191
76561197984235967
76561198031837797
76561198417144062
76561198008797636
76561198020125851
76561198039492467
76561198061393233 76561198061393233
76561198028011423 76561199173688191
76561198008797636
76561197995008105
76561197984235967
76561198417144062
76561197978640923
76561198219343843
76561197982718230
76561198031837797
76561198039492467
76561198020125851
76561198192399786 76561198192399786
76561198996604130 76561198028011423
76561198367471798 76561198318111105
76561197969148931
76561198029503957
76561198155124847 76561198155124847
76561198168877244 76561198168877244
76561198105279930
76561197988664525
76561198996604130
76561197969148931
76561198035552258 76561198035552258
76561198015992850 76561198015992850
76561198050474710
76561198029503957
76561198026221141 76561198026221141
76561198025653291 76561198025653291
76561197982718230
76561198219343843
76561198034213886 76561198034213886
76561197972378106
76561198318111105
76561198004332929
76561198018254158
76561197970246998
76561197997477460
76561198158932704
76561198269242105
76561198045540632
76561198294806446
76561197986240493
76561198105279930
76561198043532513
76561197973230221
76561198003041763
76561198020746864
76561198054210948
76561198096632451 76561198096632451
76561197962630138 76561197972378106
76561198029532782 76561197997477460
76561198086250077 76561198054210948
76561198120120943
76561198111433283 76561198111433283
76561198046642155 76561198004332929
76561198048151962 76561198045540632
76561198072936438 76561198043532513
76561198124865933 76561199080934614
76561197970246998
76561197986240493
76561198029532782
76561198018254158
76561197973230221
76561198020746864
76561198158932704
76561198086250077
76561198269242105
76561198294806446
76561198031164839
76561198019555404 76561198019555404
76561198075477583 76561198048151962
76561198042781427 76561198003041763
76561198443388781 76561198025391492
76561197962630138
76561198072936438
76561198120120943
76561197984010356 76561197984010356
76561198042965266 76561198042965266
76561198031164839 76561198046642155
76561198025391492
76561198122276418
76561197981228012
76561198019841907
76561198106206019
76561197981027062
76561197992105918
76561198104561325
76561198015856631 76561198015856631
76561197991699268 76561198124865933
76561198315929726 76561198042781427
76561198443388781
76561198426000196
76561198051725954 76561198051725954
76561198050474710 76561197992105918
76561198172925593
76561198071709714
76561197981228012
76561197981027062
76561198122276418
76561198019841907
76561197985091630 76561197985091630
76561199492215670
76561198106206019
76561198090111762
76561198104561325
76561197991699268
76561198072361453
76561198027066612
76561198032614383
76561198844130640 76561198844130640
76561198106145311
76561198079227501
76561198093579202
76561198315929726
76561198171791210
76561198264362271 76561198264362271
76561198846208086 76561198846208086
76561198032614383
76561198079227501
76561198026306582
76561198009596142
76561198056971296
76561197991613008 76561197991613008
76561198026306582
76561197973701057
76561198028428529 76561198028428529
76561198427572372 76561198427572372
76561198071709714 76561197983517848
76561198085238363
76561198070220549
76561198101049562 76561198101049562
76561197969365800 76561197969365800
76561198093579202
76561198171791210
76561198413266831 76561198413266831
76561198165450871 76561198015514779
76561198085238363
76561198106145311
76561197973701057
76561198811114019 76561198811114019
76561198165450871
76561197994575642
76561198034906703 76561198034906703
76561198119915053 76561198119915053
76561198079896896 76561198079896896
76561197988052802
76561198172925593
76561197970545939
76561198004532679
76561198008549198 76561198008549198
76561198831075066 76561197988052802
76561198004532679
76561198002535276 76561198002535276
76561197970545939
76561197977920776 76561197977920776
76561198015514779
76561198072361453
76561198070220549
76561197970307937
76561197982273259
76561197978640923
76561198090111762
76561198007200913 76561198007200913
76561197984605215
76561198831075066
76561197970970678 76561197970970678
76561197982273259
76561197970307937
76561198413088851
76561197970360549 76561197970360549
76561198051740093 76561198051740093
76561197966617426
76561198356842617
76561198025111129
76561197996825541 76561197996825541
76561197967716198 76561197967716198
76561198027066612 76561197975329196
76561197962850521
76561197998058239 76561197998058239
76561197966617426 76561198027668357
76561197962850521
76561198258304011
76561198098314980 76561198098314980
76561197984605215 76561198127957838
76561198060520130
76561198035612474 76561198035612474
76561198025111129
76561198318547224 76561198318547224
76561198034503074 76561198020810038
76561198426000196
76561198356842617
76561198150467988
76561198080773680 76561198080773680
76561198083977059
76561198286209051
76561198033967307 76561198033967307
76561197988445370 76561198034503074
76561198217979953 76561198150467988
76561198026278913
76561198321551799
76561199080934614
76561197963735863
76561197970127197
76561197994153029 76561197994153029
76561197992357639 76561198026278913
76561198070585472 76561198217979953
76561198026921217 76561197988445370
76561197983517848 76561198083977059
76561198027904347
76561198002536379
76561198027917594