mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-23 11:15:34 +08:00
Merge pull request #3 from otavepto/patch-1
Fixes for some crashes + behavior enhancements
This commit is contained in:
commit
39d14cd4e4
@ -154,6 +154,8 @@ public:
|
||||
Steam_Networking_Messages *steam_gameserver_networking_messages{};
|
||||
Steam_Game_Coordinator *steam_gameserver_game_coordinator{};
|
||||
Steam_Masterserver_Updater *steam_masterserver_updater{};
|
||||
Steam_GameStats *steam_gameserver_gamestats{};
|
||||
|
||||
Steam_AppTicket *steam_app_ticket{};
|
||||
|
||||
Steam_Overlay* steam_overlay{};
|
||||
|
@ -26,91 +26,98 @@
|
||||
class Steam_GameStats :
|
||||
public ISteamGameStats
|
||||
{
|
||||
enum class AttributeType_t
|
||||
{
|
||||
Int, Str, Float, Int64,
|
||||
};
|
||||
private:
|
||||
// how much time to wait before removing ended sessions
|
||||
constexpr const static int MAX_DEAD_SESSION_SECONDS = 15; // TODO not sure what would be sensible in this case
|
||||
|
||||
struct Attribute_t
|
||||
{
|
||||
AttributeType_t type{};
|
||||
union {
|
||||
int32 n_data;
|
||||
std::string s_data;
|
||||
float f_data;
|
||||
int64 ll_data{};
|
||||
};
|
||||
enum class AttributeType_t
|
||||
{
|
||||
Int, Str, Float, Int64,
|
||||
};
|
||||
|
||||
Attribute_t();
|
||||
Attribute_t(const Attribute_t &other);
|
||||
Attribute_t(Attribute_t &&other);
|
||||
~Attribute_t();
|
||||
};
|
||||
struct Attribute_t
|
||||
{
|
||||
const AttributeType_t type;
|
||||
union {
|
||||
int32 n_data;
|
||||
std::string s_data;
|
||||
float f_data;
|
||||
int64 ll_data;
|
||||
};
|
||||
|
||||
struct Row_t
|
||||
{
|
||||
bool committed = false;
|
||||
std::map<std::string, Attribute_t> attributes{};
|
||||
};
|
||||
Attribute_t(AttributeType_t type);
|
||||
Attribute_t(const Attribute_t &other);
|
||||
Attribute_t(Attribute_t &&other);
|
||||
~Attribute_t();
|
||||
};
|
||||
|
||||
struct Table_t
|
||||
{
|
||||
std::vector<Row_t> rows{};
|
||||
};
|
||||
struct Row_t
|
||||
{
|
||||
bool committed = false;
|
||||
std::map<std::string, Attribute_t> attributes{};
|
||||
};
|
||||
|
||||
struct Session_t
|
||||
{
|
||||
EGameStatsAccountType nAccountType{};
|
||||
RTime32 rtTimeStarted{};
|
||||
RTime32 rtTimeEnded{};
|
||||
int nReasonCode{};
|
||||
bool ended = false;
|
||||
std::map<std::string, Attribute_t> attributes{};
|
||||
struct Table_t
|
||||
{
|
||||
std::vector<Row_t> rows{};
|
||||
};
|
||||
|
||||
std::vector<std::pair<std::string, Table_t>> tables{};
|
||||
};
|
||||
struct Session_t
|
||||
{
|
||||
EGameStatsAccountType nAccountType{};
|
||||
RTime32 rtTimeStarted{};
|
||||
RTime32 rtTimeEnded{};
|
||||
int nReasonCode{};
|
||||
bool ended = false;
|
||||
std::map<std::string, Attribute_t> attributes{};
|
||||
|
||||
class Settings *settings{};
|
||||
class Networking *network{};
|
||||
class SteamCallResults *callback_results{};
|
||||
class SteamCallBacks *callbacks{};
|
||||
class RunEveryRunCB *run_every_runcb{};
|
||||
|
||||
std::vector<Session_t> sessions{};
|
||||
std::vector<std::pair<std::string, Table_t>> tables{};
|
||||
};
|
||||
|
||||
class Settings *settings{};
|
||||
class Networking *network{};
|
||||
class SteamCallResults *callback_results{};
|
||||
class SteamCallBacks *callbacks{};
|
||||
class RunEveryRunCB *run_every_runcb{};
|
||||
|
||||
std::map<uint64, Session_t> sessions{};
|
||||
|
||||
|
||||
bool valid_stats_account_type(int8 nAccountType);
|
||||
Table_t *get_or_create_session_table(Session_t &session, const char *table_name);
|
||||
Attribute_t *get_or_create_session_att(const char *att_name, Session_t &session, AttributeType_t type_if_create);
|
||||
Attribute_t *get_or_create_row_att(uint64 ulRowID, const char *att_name, Table_t &table, AttributeType_t type_if_create);
|
||||
uint64 create_session_id() const;
|
||||
bool valid_stats_account_type(int8 nAccountType);
|
||||
Table_t *get_or_create_session_table(Session_t &session, const char *table_name);
|
||||
Attribute_t *get_or_create_session_att(const char *att_name, Session_t &session, AttributeType_t type_if_create);
|
||||
Attribute_t *get_or_create_row_att(uint64 ulRowID, const char *att_name, Table_t &table, AttributeType_t type_if_create);
|
||||
Session_t* get_last_active_session();
|
||||
|
||||
void steam_run_callback();
|
||||
void steam_run_callback();
|
||||
|
||||
// user connect/disconnect
|
||||
void network_callback_low_level(Common_Message *msg);
|
||||
// user connect/disconnect
|
||||
void network_callback_low_level(Common_Message *msg);
|
||||
|
||||
static void steam_gamestats_network_low_level(void *object, Common_Message *msg);
|
||||
static void steam_gamestats_run_every_runcb(void *object);
|
||||
|
||||
static void steam_gamestats_network_low_level(void *object, Common_Message *msg);
|
||||
static void steam_gamestats_run_every_runcb(void *object);
|
||||
|
||||
public:
|
||||
Steam_GameStats(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||
~Steam_GameStats();
|
||||
|
||||
SteamAPICall_t GetNewSession( int8 nAccountType, uint64 ulAccountID, int32 nAppID, RTime32 rtTimeStarted );
|
||||
SteamAPICall_t EndSession( uint64 ulSessionID, RTime32 rtTimeEnded, int nReasonCode );
|
||||
EResult AddSessionAttributeInt( uint64 ulSessionID, const char* pstrName, int32 nData );
|
||||
EResult AddSessionAttributeString( uint64 ulSessionID, const char* pstrName, const char *pstrData );
|
||||
EResult AddSessionAttributeFloat( uint64 ulSessionID, const char* pstrName, float fData );
|
||||
Steam_GameStats(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||
~Steam_GameStats();
|
||||
|
||||
SteamAPICall_t GetNewSession( int8 nAccountType, uint64 ulAccountID, int32 nAppID, RTime32 rtTimeStarted );
|
||||
SteamAPICall_t EndSession( uint64 ulSessionID, RTime32 rtTimeEnded, int nReasonCode );
|
||||
EResult AddSessionAttributeInt( uint64 ulSessionID, const char* pstrName, int32 nData );
|
||||
EResult AddSessionAttributeString( uint64 ulSessionID, const char* pstrName, const char *pstrData );
|
||||
EResult AddSessionAttributeFloat( uint64 ulSessionID, const char* pstrName, float fData );
|
||||
|
||||
EResult AddNewRow( uint64 *pulRowID, uint64 ulSessionID, const char *pstrTableName );
|
||||
EResult CommitRow( uint64 ulRowID );
|
||||
EResult CommitOutstandingRows( uint64 ulSessionID );
|
||||
EResult AddRowAttributeInt( uint64 ulRowID, const char *pstrName, int32 nData );
|
||||
EResult AddRowAtributeString( uint64 ulRowID, const char *pstrName, const char *pstrData );
|
||||
EResult AddRowAttributeFloat( uint64 ulRowID, const char *pstrName, float fData );
|
||||
EResult AddNewRow( uint64 *pulRowID, uint64 ulSessionID, const char *pstrTableName );
|
||||
EResult CommitRow( uint64 ulRowID );
|
||||
EResult CommitOutstandingRows( uint64 ulSessionID );
|
||||
EResult AddRowAttributeInt( uint64 ulRowID, const char *pstrName, int32 nData );
|
||||
EResult AddRowAtributeString( uint64 ulRowID, const char *pstrName, const char *pstrData );
|
||||
EResult AddRowAttributeFloat( uint64 ulRowID, const char *pstrName, float fData );
|
||||
|
||||
EResult AddSessionAttributeInt64( uint64 ulSessionID, const char *pstrName, int64 llData );
|
||||
EResult AddRowAttributeInt64( uint64 ulRowID, const char *pstrName, int64 llData );
|
||||
EResult AddSessionAttributeInt64( uint64 ulSessionID, const char *pstrName, int64 llData );
|
||||
EResult AddRowAttributeInt64( uint64 ulRowID, const char *pstrName, int64 llData );
|
||||
|
||||
};
|
||||
|
||||
|
@ -36,30 +36,29 @@ struct Stream_Write {
|
||||
};
|
||||
|
||||
struct Downloaded_File {
|
||||
// --- these are needed due to the usage of union
|
||||
Downloaded_File();
|
||||
~Downloaded_File();
|
||||
// ---
|
||||
|
||||
enum DownloadSource {
|
||||
enum class DownloadSource {
|
||||
AfterFileShare, // attempted download after a call to Steam_Remote_Storage::FileShare()
|
||||
AfterSendQueryUGCRequest, // attempted download after a call to Steam_UGC::SendQueryUGCRequest()
|
||||
FromUGCDownloadToLocation, // attempted download via Steam_Remote_Storage::UGCDownloadToLocation()
|
||||
} source{};
|
||||
};
|
||||
|
||||
private:
|
||||
DownloadSource source;
|
||||
|
||||
public:
|
||||
Downloaded_File(DownloadSource src);
|
||||
|
||||
DownloadSource get_source() const;
|
||||
|
||||
// *** used in any case
|
||||
std::string file{};
|
||||
uint64 total_size{};
|
||||
|
||||
// put any additional data needed by other sources here
|
||||
|
||||
union {
|
||||
// *** used when source = SendQueryUGCRequest only
|
||||
Ugc_Remote_Storage_Bridge::QueryInfo mod_query_info;
|
||||
// *** used when source = AfterSendQueryUGCRequest and FromUGCDownloadToLocation
|
||||
Ugc_Remote_Storage_Bridge::QueryInfo mod_query_info{};
|
||||
|
||||
// *** used when source = FromUGCDownloadToLocation only
|
||||
std::string download_to_location_fullpath;
|
||||
};
|
||||
// *** used when source = FromUGCDownloadToLocation only
|
||||
std::string download_to_location_fullpath{};
|
||||
|
||||
};
|
||||
|
||||
@ -85,6 +84,7 @@ private:
|
||||
class Ugc_Remote_Storage_Bridge *ugc_bridge{};
|
||||
class Local_Storage *local_storage{};
|
||||
class SteamCallResults *callback_results{};
|
||||
class SteamCallBacks *callbacks{};
|
||||
|
||||
std::vector<struct Async_Read> async_reads{};
|
||||
std::vector<struct Stream_Write> stream_writes{};
|
||||
@ -95,7 +95,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results);
|
||||
Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks);
|
||||
|
||||
// NOTE
|
||||
//
|
||||
|
@ -24,6 +24,8 @@ class Steam_Timeline :
|
||||
public ISteamTimeline
|
||||
{
|
||||
private:
|
||||
constexpr const static float PRIORITY_CLIP_MIN_SEC = 8.0f;
|
||||
|
||||
struct TimelineEvent_t
|
||||
{
|
||||
// emu specific: time when this event was added to the list via 'Steam_Timeline::AddTimelineEvent()'
|
||||
@ -68,7 +70,7 @@ private:
|
||||
class RunEveryRunCB *run_every_runcb{};
|
||||
|
||||
std::vector<TimelineEvent_t> timeline_events{};
|
||||
std::vector<TimelineState_t> timeline_states{TimelineState_t{}}; // it seems to always start with a default event
|
||||
std::vector<TimelineState_t> timeline_states{};
|
||||
|
||||
// unconditional periodic callback
|
||||
void RunCallbacks();
|
||||
|
@ -1114,7 +1114,7 @@ static void try_detect_mods_folder(class Settings *settings_client, Settings *se
|
||||
PRINT_DEBUG(" preview_filename: '%s'", newMod.previewFileName.c_str());
|
||||
PRINT_DEBUG(" preview_filesize: %i bytes", newMod.previewFileSize);
|
||||
PRINT_DEBUG(" preview file handle: %llu", settings_client->getMod(newMod.id).handlePreviewFile);
|
||||
PRINT_DEBUG(" total_files_sizes: '%s'", newMod.total_files_sizes);
|
||||
PRINT_DEBUG(" total_files_sizes: '%llu'", newMod.total_files_sizes);
|
||||
PRINT_DEBUG(" min_game_branch: '%s'", newMod.min_game_branch.c_str());
|
||||
PRINT_DEBUG(" max_game_branch: '%s'", newMod.max_game_branch.c_str());
|
||||
PRINT_DEBUG(" workshop_item_url: '%s'", newMod.workshopItemURL.c_str());
|
||||
@ -1379,8 +1379,8 @@ static void parse_simple_features(class Settings *settings_client, class Setting
|
||||
settings_client->matchmaking_server_details_via_source_query = ini.GetBoolValue("main::general", "matchmaking_server_details_via_source_query", settings_client->matchmaking_server_details_via_source_query);
|
||||
settings_server->matchmaking_server_details_via_source_query = ini.GetBoolValue("main::general", "matchmaking_server_details_via_source_query", settings_server->matchmaking_server_details_via_source_query);
|
||||
|
||||
settings_client->matchmaking_server_list_always_lan_type = ini.GetBoolValue("main::general", "matchmaking_server_list_actual_type", settings_client->matchmaking_server_list_always_lan_type);
|
||||
settings_server->matchmaking_server_list_always_lan_type = ini.GetBoolValue("main::general", "matchmaking_server_list_actual_type", settings_server->matchmaking_server_list_always_lan_type);
|
||||
settings_client->matchmaking_server_list_always_lan_type = !ini.GetBoolValue("main::general", "matchmaking_server_list_actual_type", !settings_client->matchmaking_server_list_always_lan_type);
|
||||
settings_server->matchmaking_server_list_always_lan_type = !ini.GetBoolValue("main::general", "matchmaking_server_list_actual_type", !settings_server->matchmaking_server_list_always_lan_type);
|
||||
|
||||
|
||||
// [main::connectivity]
|
||||
|
@ -100,7 +100,7 @@ Steam_Client::Steam_Client()
|
||||
steam_user_stats = new Steam_User_Stats(settings_client, network, local_storage, callback_results_client, callbacks_client, run_every_runcb, steam_overlay);
|
||||
steam_apps = new Steam_Apps(settings_client, callback_results_client, callbacks_client);
|
||||
steam_networking = new Steam_Networking(settings_client, network, callbacks_client, run_every_runcb);
|
||||
steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client);
|
||||
steam_remote_storage = new Steam_Remote_Storage(settings_client, ugc_bridge, local_storage, callback_results_client, callbacks_client);
|
||||
steam_screenshots = new Steam_Screenshots(local_storage, callbacks_client);
|
||||
steam_http = new Steam_HTTP(settings_client, network, callback_results_client, callbacks_client);
|
||||
steam_controller = new Steam_Controller(settings_client, callback_results_client, callbacks_client, run_every_runcb);
|
||||
@ -143,6 +143,7 @@ Steam_Client::Steam_Client()
|
||||
steam_gameserver_networking_messages = new Steam_Networking_Messages(settings_server, network, callback_results_server, callbacks_server, run_every_runcb);
|
||||
steam_gameserver_game_coordinator = new Steam_Game_Coordinator(settings_server, network, callback_results_server, callbacks_server, run_every_runcb);
|
||||
steam_masterserver_updater = new Steam_Masterserver_Updater(settings_server, network, callback_results_server, callbacks_server, run_every_runcb);
|
||||
steam_gameserver_gamestats = new Steam_GameStats(settings_server, network, callback_results_server, callbacks_server, run_every_runcb);
|
||||
|
||||
PRINT_DEBUG("init AppTicket");
|
||||
steam_app_ticket = new Steam_AppTicket(settings_client);
|
||||
|
@ -37,8 +37,16 @@ ISteamGameStats *Steam_Client::GetISteamGameStats( HSteamUser hSteamUser, HSteam
|
||||
PRINT_DEBUG("%s", pchVersion);
|
||||
if (!steam_pipes.count(hSteamPipe) || !hSteamUser) return nullptr;
|
||||
|
||||
Steam_GameStats *steam_gamestats_tmp{};
|
||||
|
||||
if (steam_pipes[hSteamPipe] == Steam_Pipe::SERVER) {
|
||||
steam_gamestats_tmp = steam_gameserver_gamestats;
|
||||
} else {
|
||||
steam_gamestats_tmp = steam_gamestats;
|
||||
}
|
||||
|
||||
if (strcmp(pchVersion, STEAMGAMESTATS_INTERFACE_VERSION) == 0) {
|
||||
return reinterpret_cast<ISteamGameStats *>(static_cast<ISteamGameStats *>(steam_gamestats));
|
||||
return reinterpret_cast<ISteamGameStats *>(static_cast<ISteamGameStats *>(steam_gamestats_tmp));
|
||||
}
|
||||
|
||||
report_missing_impl_and_exit(pchVersion, EMU_FUNC_NAME);
|
||||
@ -249,13 +257,15 @@ ISteamMatchmakingServers *Steam_Client::GetISteamMatchmakingServers( HSteamUser
|
||||
// returns the a generic interface
|
||||
void *Steam_Client::GetISteamGenericInterface( HSteamUser hSteamUser, HSteamPipe hSteamPipe, const char *pchVersion )
|
||||
{
|
||||
PRINT_DEBUG("%s", pchVersion);
|
||||
PRINT_DEBUG("'%s' %i %i", pchVersion, hSteamUser, hSteamPipe);
|
||||
if (!steam_pipes.count(hSteamPipe)) return NULL;
|
||||
|
||||
bool server = false;
|
||||
if (steam_pipes[hSteamPipe] == Steam_Pipe::SERVER) {
|
||||
// PRINT_DEBUG("requesting interface with server pipe");
|
||||
server = true;
|
||||
} else {
|
||||
// PRINT_DEBUG("requesting interface with client pipe");
|
||||
// if this is a user pipe, and version != "SteamNetworkingUtils", and version != "SteamUtils"
|
||||
if ((strstr(pchVersion, "SteamNetworkingUtils") != pchVersion) && (strstr(pchVersion, "SteamUtils") != pchVersion)) {
|
||||
if (!hSteamUser) return NULL;
|
||||
|
@ -209,21 +209,16 @@ SteamAPICall_t Steam_Friends::SetPersonaName( const char *pchPersonaName )
|
||||
PRINT_DEBUG_ENTRY();
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
// send PersonaStateChange_t callbacks
|
||||
persona_change(settings->get_local_steam_id(), EPersonaChange::k_EPersonaChangeName);
|
||||
|
||||
SetPersonaNameResponse_t data{};
|
||||
data.m_bSuccess = true;
|
||||
data.m_bLocalSuccess = false;
|
||||
data.m_result = k_EResultOK;
|
||||
persona_change(settings->get_local_steam_id(), k_EPersonaChangeName);
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
{
|
||||
PersonaStateChange_t data2{};
|
||||
data2.m_nChangeFlags = EPersonaChange::k_EPersonaChangeName;
|
||||
data2.m_ulSteamID = settings->get_local_steam_id().ConvertToUint64();
|
||||
callbacks->addCBResult(data2.k_iCallback, &data2, sizeof(data2));
|
||||
}
|
||||
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1032,7 +1027,10 @@ SteamAPICall_t Steam_Friends::JoinClanChatRoom( CSteamID steamIDClan )
|
||||
JoinClanChatRoomCompletionResult_t data;
|
||||
data.m_steamIDClanChat = steamIDClan;
|
||||
data.m_eChatRoomEnterResponse = k_EChatRoomEnterResponseSuccess;
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Steam_Friends::LeaveClanChatRoom( CSteamID steamIDClan )
|
||||
|
@ -24,39 +24,54 @@
|
||||
#include "dll/steam_gamestats.h"
|
||||
|
||||
|
||||
Steam_GameStats::Attribute_t::Attribute_t()
|
||||
{ }
|
||||
Steam_GameStats::Attribute_t::Attribute_t(AttributeType_t type)
|
||||
:type(type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case AttributeType_t::Float: f_data = 0; break;
|
||||
case AttributeType_t::Int64: ll_data = 0; break;
|
||||
case AttributeType_t::Int: n_data = 0; break;
|
||||
case AttributeType_t::Str: new (&s_data) std::string{}; break;
|
||||
|
||||
default: PRINT_DEBUG("[X] invalid type %i", (int)type); break;
|
||||
}
|
||||
}
|
||||
|
||||
Steam_GameStats::Attribute_t::Attribute_t(const Attribute_t &other)
|
||||
:type(type)
|
||||
{
|
||||
type = other.type;
|
||||
switch (other.type)
|
||||
{
|
||||
case AttributeType_t::Int: n_data = other.n_data; break;
|
||||
case AttributeType_t::Str: s_data = other.s_data; break;
|
||||
case AttributeType_t::Str: new (&s_data) std::string(other.s_data); break;
|
||||
case AttributeType_t::Float: f_data = other.f_data; break;
|
||||
case AttributeType_t::Int64: ll_data = other.ll_data; break;
|
||||
|
||||
default: break;
|
||||
default: PRINT_DEBUG("[X] invalid type %i", (int)other.type); break;
|
||||
}
|
||||
}
|
||||
|
||||
Steam_GameStats::Attribute_t::Attribute_t(Attribute_t &&other)
|
||||
:type(type)
|
||||
{
|
||||
type = other.type;
|
||||
switch (other.type)
|
||||
{
|
||||
case AttributeType_t::Int: n_data = other.n_data; break;
|
||||
case AttributeType_t::Str: s_data = std::move(other.s_data); break;
|
||||
case AttributeType_t::Str: new (&s_data) std::string(std::move(other.s_data)); break;
|
||||
case AttributeType_t::Float: f_data = other.f_data; break;
|
||||
case AttributeType_t::Int64: ll_data = other.ll_data; break;
|
||||
|
||||
default: break;
|
||||
default: PRINT_DEBUG("[X] invalid type %i", (int)other.type); break;
|
||||
}
|
||||
}
|
||||
|
||||
Steam_GameStats::Attribute_t::~Attribute_t()
|
||||
{ }
|
||||
{
|
||||
if (type == AttributeType_t::Str) {
|
||||
s_data.~basic_string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Steam_GameStats::steam_gamestats_network_low_level(void *object, Common_Message *msg)
|
||||
@ -83,18 +98,26 @@ Steam_GameStats::Steam_GameStats(class Settings *settings, class Networking *net
|
||||
this->callbacks = callbacks;
|
||||
this->run_every_runcb = run_every_runcb;
|
||||
|
||||
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_GameStats::steam_gamestats_network_low_level, this);
|
||||
// this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_GameStats::steam_gamestats_network_low_level, this);
|
||||
this->run_every_runcb->add(&Steam_GameStats::steam_gamestats_run_every_runcb, this);
|
||||
|
||||
}
|
||||
|
||||
Steam_GameStats::~Steam_GameStats()
|
||||
{
|
||||
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_GameStats::steam_gamestats_network_low_level, this);
|
||||
// this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_GameStats::steam_gamestats_network_low_level, this);
|
||||
this->run_every_runcb->remove(&Steam_GameStats::steam_gamestats_run_every_runcb, this);
|
||||
}
|
||||
|
||||
|
||||
uint64 Steam_GameStats::create_session_id() const
|
||||
{
|
||||
static uint64 session_id = 0;
|
||||
session_id++;
|
||||
if (!session_id) session_id = 1; // not sure if 0 is a good idea
|
||||
return session_id;
|
||||
}
|
||||
|
||||
bool Steam_GameStats::valid_stats_account_type(int8 nAccountType)
|
||||
{
|
||||
switch ((EGameStatsAccountType)nAccountType) {
|
||||
@ -113,8 +136,8 @@ Steam_GameStats::Table_t *Steam_GameStats::get_or_create_session_table(Session_t
|
||||
{
|
||||
auto table_it = std::find_if(session.tables.rbegin(), session.tables.rend(), [=](const std::pair<std::string, Table_t> &item){ return item.first == table_name; });
|
||||
if (session.tables.rend() == table_it) {
|
||||
session.tables.emplace_back(std::pair<std::string, Table_t>{});
|
||||
table = &session.tables.back().second;
|
||||
auto& [key, val] = session.tables.emplace_back(std::pair<std::string, Table_t>{});
|
||||
table = &val;
|
||||
} else {
|
||||
table = &table_it->second;
|
||||
}
|
||||
@ -125,40 +148,29 @@ Steam_GameStats::Table_t *Steam_GameStats::get_or_create_session_table(Session_t
|
||||
|
||||
Steam_GameStats::Attribute_t *Steam_GameStats::get_or_create_session_att(const char *att_name, Session_t &session, AttributeType_t type_if_create)
|
||||
{
|
||||
Attribute_t *att{};
|
||||
{
|
||||
auto att_itr = session.attributes.find(att_name);
|
||||
if (att_itr != session.attributes.end()) {
|
||||
att = &att_itr->second;
|
||||
} else {
|
||||
att = &session.attributes[att_name];
|
||||
att->type = type_if_create;
|
||||
}
|
||||
}
|
||||
|
||||
return att;
|
||||
auto [ele_it, _] = session.attributes.emplace(att_name, type_if_create);
|
||||
return &ele_it->second;
|
||||
}
|
||||
|
||||
Steam_GameStats::Attribute_t *Steam_GameStats::get_or_create_row_att(uint64 ulRowID, const char *att_name, Table_t &table, AttributeType_t type_if_create)
|
||||
{
|
||||
Attribute_t *att{};
|
||||
{
|
||||
auto &row = table.rows[static_cast<unsigned>(ulRowID)];
|
||||
auto att_itr = row.attributes.find(att_name);
|
||||
if (att_itr != row.attributes.end()) {
|
||||
att = &att_itr->second;
|
||||
} else {
|
||||
att = &row.attributes[att_name];
|
||||
att->type = type_if_create;
|
||||
}
|
||||
}
|
||||
auto &row = table.rows[static_cast<unsigned>(ulRowID)];
|
||||
auto [ele_it, _] = row.attributes.emplace(att_name, type_if_create);
|
||||
return &ele_it->second;
|
||||
}
|
||||
|
||||
return att;
|
||||
Steam_GameStats::Session_t* Steam_GameStats::get_last_active_session()
|
||||
{
|
||||
auto active_session_it = std::find_if(sessions.rbegin(), sessions.rend(), [](std::pair<const uint64, Steam_GameStats::Session_t> item){ return !item.second.ended; });
|
||||
if (sessions.rend() == active_session_it) return nullptr; // TODO is this correct?
|
||||
|
||||
return &active_session_it->second;
|
||||
}
|
||||
|
||||
|
||||
SteamAPICall_t Steam_GameStats::GetNewSession( int8 nAccountType, uint64 ulAccountID, int32 nAppID, RTime32 rtTimeStarted )
|
||||
{
|
||||
// appid 550 calls this function once with client account id, and another time with server account id
|
||||
PRINT_DEBUG("%i, %llu, %i, %u", (int)nAccountType, ulAccountID, nAppID, rtTimeStarted);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
@ -166,11 +178,13 @@ SteamAPICall_t Steam_GameStats::GetNewSession( int8 nAccountType, uint64 ulAccou
|
||||
(nAppID < 0) ||
|
||||
(settings->get_local_game_id().AppID() != (uint32)nAppID) ||
|
||||
!valid_stats_account_type(nAccountType)) {
|
||||
|
||||
GameStatsSessionIssued_t data_invalid{};
|
||||
data_invalid.m_bCollectingAny = false;
|
||||
data_invalid.m_bCollectingDetails = false;
|
||||
data_invalid.m_eResult = EResult::k_EResultInvalidParam;
|
||||
data_invalid.m_ulSessionID = 0;
|
||||
PRINT_DEBUG("[X] invalid param");
|
||||
|
||||
auto ret = callback_results->addCallResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
||||
// the function returns SteamAPICall_t (call result), but in isteamstats.h you can see that a callback is also expected
|
||||
@ -178,16 +192,18 @@ SteamAPICall_t Steam_GameStats::GetNewSession( int8 nAccountType, uint64 ulAccou
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto session_id = create_session_id();
|
||||
Session_t new_session{};
|
||||
new_session.nAccountType = (EGameStatsAccountType)nAccountType;
|
||||
new_session.rtTimeStarted = rtTimeStarted;
|
||||
sessions.emplace_back(new_session);
|
||||
sessions.insert_or_assign(session_id, new_session);
|
||||
|
||||
GameStatsSessionIssued_t data{};
|
||||
data.m_bCollectingAny = true; // TODO is this correct?
|
||||
data.m_bCollectingDetails = true; // TODO is this correct?
|
||||
data.m_eResult = EResult::k_EResultOK;
|
||||
data.m_ulSessionID = (uint64)sessions.size(); // I don't know if 0 is a bad value, so always send count (index + 1)
|
||||
data.m_ulSessionID = session_id;
|
||||
PRINT_DEBUG("new session id = %llu", session_id);
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
// the function returns SteamAPICall_t (call result), but in isteamstats.h you can see that a callback is also expected
|
||||
@ -200,10 +216,12 @@ SteamAPICall_t Steam_GameStats::EndSession( uint64 ulSessionID, RTime32 rtTimeEn
|
||||
PRINT_DEBUG("%llu, %u, %i", ulSessionID, rtTimeEnded, nReasonCode);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size()) {
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) {
|
||||
GameStatsSessionClosed_t data_invalid{};
|
||||
data_invalid.m_eResult = EResult::k_EResultInvalidParam;
|
||||
data_invalid.m_ulSessionID = ulSessionID;
|
||||
PRINT_DEBUG("[X] session doesn't exist");
|
||||
|
||||
auto ret = callback_results->addCallResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
||||
// the function returns SteamAPICall_t (call result), but in isteamstats.h you can see that a callback is also expected
|
||||
@ -211,7 +229,7 @@ SteamAPICall_t Steam_GameStats::EndSession( uint64 ulSessionID, RTime32 rtTimeEn
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) {
|
||||
GameStatsSessionClosed_t data_invalid{};
|
||||
data_invalid.m_eResult = EResult::k_EResultExpired; // TODO is this correct?
|
||||
@ -230,6 +248,7 @@ SteamAPICall_t Steam_GameStats::EndSession( uint64 ulSessionID, RTime32 rtTimeEn
|
||||
GameStatsSessionClosed_t data{};
|
||||
data.m_eResult = EResult::k_EResultOK;
|
||||
data.m_ulSessionID = ulSessionID;
|
||||
PRINT_DEBUG("ended session");
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
// the function returns SteamAPICall_t (call result), but in isteamstats.h you can see that a callback is also expected
|
||||
@ -239,69 +258,77 @@ SteamAPICall_t Steam_GameStats::EndSession( uint64 ulSessionID, RTime32 rtTimeEn
|
||||
|
||||
EResult Steam_GameStats::AddSessionAttributeInt( uint64 ulSessionID, const char* pstrName, int32 nData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', %i", ulSessionID, pstrName, nData);
|
||||
PRINT_DEBUG("%llu, '%s'=%i", ulSessionID, pstrName, nData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size() || !pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
||||
|
||||
auto att = get_or_create_session_att(pstrName, session, AttributeType_t::Int);
|
||||
if (att->type != AttributeType_t::Int) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->n_data = nData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
EResult Steam_GameStats::AddSessionAttributeString( uint64 ulSessionID, const char* pstrName, const char *pstrData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', '%s'", ulSessionID, pstrName, pstrData);
|
||||
PRINT_DEBUG("%llu, '%s'='%s'", ulSessionID, pstrName, pstrData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size() || !pstrName || !pstrData) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
||||
|
||||
auto att = get_or_create_session_att(pstrName, session, AttributeType_t::Str);
|
||||
if (att->type != AttributeType_t::Str) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->s_data = pstrData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
EResult Steam_GameStats::AddSessionAttributeFloat( uint64 ulSessionID, const char* pstrName, float fData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', %f", ulSessionID, pstrName, fData);
|
||||
PRINT_DEBUG("%llu, '%s'=%f", ulSessionID, pstrName, fData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size() || !pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
||||
|
||||
auto att = get_or_create_session_att(pstrName, session, AttributeType_t::Float);
|
||||
if (att->type != AttributeType_t::Float) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->f_data = fData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
|
||||
EResult Steam_GameStats::AddNewRow( uint64 *pulRowID, uint64 ulSessionID, const char *pstrTableName )
|
||||
{
|
||||
PRINT_DEBUG("%p, %llu, '%s'", pulRowID, ulSessionID, pstrTableName);
|
||||
PRINT_DEBUG("%p, %llu, ['%s']", pulRowID, ulSessionID, pstrTableName);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size() || !pstrTableName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
||||
|
||||
auto table = get_or_create_session_table(session, pstrTableName);
|
||||
table->rows.emplace_back(Row_t{});
|
||||
if (pulRowID) *pulRowID = (uint64)(table->rows.size() - 1);
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
@ -310,8 +337,8 @@ EResult Steam_GameStats::CommitRow( uint64 ulRowID )
|
||||
PRINT_DEBUG("%llu", ulRowID);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
auto active_session = std::find_if(sessions.rbegin(), sessions.rend(), [](const Session_t &item){ return !item.ended; });
|
||||
if (sessions.rend() == active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
auto active_session = get_last_active_session();
|
||||
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
if (active_session->tables.empty()) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
auto &table = active_session->tables.back().second;
|
||||
@ -321,6 +348,7 @@ EResult Steam_GameStats::CommitRow( uint64 ulRowID )
|
||||
auto& row = table.rows[static_cast<unsigned>(ulRowID)];
|
||||
row.committed = true;
|
||||
|
||||
PRINT_DEBUG("committed successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
@ -329,9 +357,10 @@ EResult Steam_GameStats::CommitOutstandingRows( uint64 ulSessionID )
|
||||
PRINT_DEBUG("%llu", ulSessionID);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
||||
|
||||
if (session.tables.size()) {
|
||||
@ -339,18 +368,19 @@ EResult Steam_GameStats::CommitOutstandingRows( uint64 ulSessionID )
|
||||
row.committed = true;
|
||||
}
|
||||
}
|
||||
PRINT_DEBUG("committed all successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
EResult Steam_GameStats::AddRowAttributeInt( uint64 ulRowID, const char *pstrName, int32 nData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', %i", ulRowID, pstrName, nData);
|
||||
PRINT_DEBUG("%llu, '%s'=%i", ulRowID, pstrName, nData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (!pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto active_session = std::find_if(sessions.rbegin(), sessions.rend(), [](const Session_t &item){ return !item.ended; });
|
||||
if (sessions.rend() == active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
auto active_session = get_last_active_session();
|
||||
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
if (active_session->tables.empty()) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
auto &table = active_session->tables.back().second;
|
||||
@ -360,18 +390,20 @@ EResult Steam_GameStats::AddRowAttributeInt( uint64 ulRowID, const char *pstrNam
|
||||
if (att->type != AttributeType_t::Int) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->n_data = nData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
EResult Steam_GameStats::AddRowAtributeString( uint64 ulRowID, const char *pstrName, const char *pstrData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', '%s'", ulRowID, pstrName, pstrData);
|
||||
PRINT_DEBUG("%llu, '%s'='%s'", ulRowID, pstrName, pstrData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (!pstrName || !pstrData) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto active_session = std::find_if(sessions.rbegin(), sessions.rend(), [](const Session_t &item){ return !item.ended; });
|
||||
if (sessions.rend() == active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
auto active_session = get_last_active_session();
|
||||
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
if (active_session->tables.empty()) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
auto &table = active_session->tables.back().second;
|
||||
if (ulRowID >= table.rows.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
@ -380,18 +412,20 @@ EResult Steam_GameStats::AddRowAtributeString( uint64 ulRowID, const char *pstrN
|
||||
if (att->type != AttributeType_t::Str) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->s_data = pstrData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
EResult Steam_GameStats::AddRowAttributeFloat( uint64 ulRowID, const char *pstrName, float fData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', %f", ulRowID, pstrName, fData);
|
||||
PRINT_DEBUG("%llu, '%s'=%f", ulRowID, pstrName, fData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (!pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto active_session = std::find_if(sessions.rbegin(), sessions.rend(), [](const Session_t &item){ return !item.ended; });
|
||||
if (sessions.rend() == active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
auto active_session = get_last_active_session();
|
||||
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
if (active_session->tables.empty()) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
auto &table = active_session->tables.back().second;
|
||||
if (ulRowID >= table.rows.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
@ -400,36 +434,40 @@ EResult Steam_GameStats::AddRowAttributeFloat( uint64 ulRowID, const char *pstrN
|
||||
if (att->type != AttributeType_t::Float) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->f_data = fData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
|
||||
EResult Steam_GameStats::AddSessionAttributeInt64( uint64 ulSessionID, const char *pstrName, int64 llData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', %lli", ulSessionID, pstrName, llData);
|
||||
PRINT_DEBUG("%llu, '%s'=%lli", ulSessionID, pstrName, llData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (ulSessionID == 0 || ulSessionID > sessions.size() || !pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
auto session_it = sessions.find(ulSessionID);
|
||||
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto& session = sessions[static_cast<unsigned>(ulSessionID - 1)];
|
||||
auto& session = session_it->second;
|
||||
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
||||
|
||||
auto att = get_or_create_session_att(pstrName, session, AttributeType_t::Int64);
|
||||
if (att->type != AttributeType_t::Int64) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->ll_data = llData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
EResult Steam_GameStats::AddRowAttributeInt64( uint64 ulRowID, const char *pstrName, int64 llData )
|
||||
{
|
||||
PRINT_DEBUG("%llu, '%s', %lli", ulRowID, pstrName, llData);
|
||||
PRINT_DEBUG("%llu, '%s'=%lli", ulRowID, pstrName, llData);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (!pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
|
||||
auto active_session = std::find_if(sessions.rbegin(), sessions.rend(), [](const Session_t &item){ return !item.ended; });
|
||||
if (sessions.rend() == active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
auto active_session = get_last_active_session();
|
||||
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
||||
if (active_session->tables.empty()) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
auto &table = active_session->tables.back().second;
|
||||
if (ulRowID >= table.rows.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
||||
@ -438,6 +476,7 @@ EResult Steam_GameStats::AddRowAttributeInt64( uint64 ulRowID, const char *pstrN
|
||||
if (att->type != AttributeType_t::Int64) return EResult::k_EResultFail; // TODO is this correct?
|
||||
|
||||
att->ll_data = llData;
|
||||
PRINT_DEBUG("added successfully");
|
||||
return EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
@ -447,7 +486,28 @@ EResult Steam_GameStats::AddRowAttributeInt64( uint64 ulRowID, const char *pstrN
|
||||
|
||||
void Steam_GameStats::steam_run_callback()
|
||||
{
|
||||
// nothing
|
||||
// remove ended sessions that are inactive
|
||||
auto session_it = sessions.begin();
|
||||
auto now_epoch_sec = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()
|
||||
);
|
||||
while (sessions.end() != session_it) {
|
||||
bool should_remove = false;
|
||||
|
||||
auto &session = session_it->second;
|
||||
if (session.ended) {
|
||||
if ( (now_epoch_sec.count() - (long long)session.rtTimeEnded) >= MAX_DEAD_SESSION_SECONDS ) {
|
||||
should_remove = true;
|
||||
PRINT_DEBUG("removing outdated session id=%llu", session_it->first);
|
||||
}
|
||||
}
|
||||
|
||||
if (should_remove) {
|
||||
session_it = sessions.erase(session_it);
|
||||
} else {
|
||||
++session_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,7 +180,9 @@ void Steam_HTTP::online_http_request(Steam_Http_Request *request, SteamAPICall_t
|
||||
data.m_eStatusCode = k_EHTTPStatusCode200OK;
|
||||
}
|
||||
|
||||
if (pCallHandle) *pCallHandle = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||
auto callres = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||
if (pCallHandle) *pCallHandle = callres;
|
||||
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||
};
|
||||
|
||||
@ -356,7 +358,9 @@ bool Steam_HTTP::SendHTTPRequest( HTTPRequestHandle hRequest, SteamAPICall_t *pC
|
||||
data.m_eStatusCode = k_EHTTPStatusCode200OK;
|
||||
}
|
||||
|
||||
if (pCallHandle) *pCallHandle = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||
auto callres = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||
if (pCallHandle) *pCallHandle = callres;
|
||||
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,9 @@ SteamAPICall_t Steam_Networking_Sockets_Serialized::GetCertAsync()
|
||||
struct SteamNetworkingSocketsCert_t data = {};
|
||||
data.m_eResult = k_EResultOK;
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Steam_Networking_Sockets_Serialized::GetNetworkConfigJSON( void *buf, uint32 cbBuf, const char *pszLauncherPartner )
|
||||
|
@ -18,14 +18,13 @@
|
||||
#include "dll/steam_remote_storage.h"
|
||||
|
||||
|
||||
Downloaded_File::Downloaded_File()
|
||||
{
|
||||
Downloaded_File::Downloaded_File(DownloadSource src)
|
||||
:source(src)
|
||||
{ }
|
||||
|
||||
}
|
||||
|
||||
Downloaded_File::~Downloaded_File()
|
||||
Downloaded_File::DownloadSource Downloaded_File::get_source() const
|
||||
{
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
static void copy_file(const std::string &src_filepath, const std::string &dst_filepath)
|
||||
@ -43,12 +42,13 @@ static void copy_file(const std::string &src_filepath, const std::string &dst_fi
|
||||
} catch(...) {}
|
||||
}
|
||||
|
||||
Steam_Remote_Storage::Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results)
|
||||
Steam_Remote_Storage::Steam_Remote_Storage(class Settings *settings, class Ugc_Remote_Storage_Bridge *ugc_bridge, class Local_Storage *local_storage, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
|
||||
{
|
||||
this->settings = settings;
|
||||
this->ugc_bridge = ugc_bridge;
|
||||
this->local_storage = local_storage;
|
||||
this->callback_results = callback_results;
|
||||
this->callbacks = callbacks;
|
||||
|
||||
steam_cloud_enabled = true;
|
||||
}
|
||||
@ -101,7 +101,9 @@ SteamAPICall_t Steam_Remote_Storage::FileWriteAsync( const char *pchFile, const
|
||||
RemoteStorageFileWriteAsyncComplete_t data;
|
||||
data.m_eResult = success ? k_EResultOK : k_EResultFail;
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.01);
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.01);
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.01);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -130,7 +132,9 @@ SteamAPICall_t Steam_Remote_Storage::FileReadAsync( const char *pchFile, uint32
|
||||
a_read.size = size;
|
||||
|
||||
async_reads.push_back(a_read);
|
||||
|
||||
callback_results->addCallResult(data.m_hFileReadAsync, data.k_iCallback, &data, sizeof(data), 0.0);
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.0);
|
||||
return data.m_hFileReadAsync;
|
||||
}
|
||||
|
||||
@ -161,7 +165,7 @@ bool Steam_Remote_Storage::FileReadAsyncComplete( SteamAPICall_t hReadCall, void
|
||||
|
||||
bool Steam_Remote_Storage::FileForget( const char *pchFile )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG("'%s'", pchFile);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!pchFile || !pchFile[0]) return false;
|
||||
|
||||
@ -170,7 +174,7 @@ bool Steam_Remote_Storage::FileForget( const char *pchFile )
|
||||
|
||||
bool Steam_Remote_Storage::FileDelete( const char *pchFile )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG("'%s'", pchFile);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!pchFile || !pchFile[0]) return false;
|
||||
|
||||
@ -180,7 +184,7 @@ bool Steam_Remote_Storage::FileDelete( const char *pchFile )
|
||||
STEAM_CALL_RESULT( RemoteStorageFileShareResult_t )
|
||||
SteamAPICall_t Steam_Remote_Storage::FileShare( const char *pchFile )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG("'%s'", pchFile);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!pchFile || !pchFile[0]) return k_uAPICallInvalid;
|
||||
|
||||
@ -194,12 +198,14 @@ SteamAPICall_t Steam_Remote_Storage::FileShare( const char *pchFile )
|
||||
data.m_eResult = k_EResultFileNotFound;
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Steam_Remote_Storage::SetSyncPlatforms( const char *pchFile, ERemoteStoragePlatform eRemoteStoragePlatform )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG("'%s' %i", pchFile, (int)eRemoteStoragePlatform);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!pchFile || !pchFile[0]) return false;
|
||||
|
||||
@ -210,13 +216,15 @@ bool Steam_Remote_Storage::SetSyncPlatforms( const char *pchFile, ERemoteStorage
|
||||
// file operations that cause network IO
|
||||
UGCFileWriteStreamHandle_t Steam_Remote_Storage::FileWriteStreamOpen( const char *pchFile )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG("'%s'", pchFile);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!pchFile || !pchFile[0]) return k_UGCFileStreamHandleInvalid;
|
||||
|
||||
static UGCFileWriteStreamHandle_t handle;
|
||||
static UGCFileWriteStreamHandle_t handle = 0;
|
||||
++handle;
|
||||
struct Stream_Write stream_write;
|
||||
if (!handle) handle = 1;
|
||||
|
||||
struct Stream_Write stream_write{};
|
||||
stream_write.file_name = std::string(pchFile);
|
||||
stream_write.write_stream_handle = handle;
|
||||
stream_writes.push_back(stream_write);
|
||||
@ -412,18 +420,20 @@ SteamAPICall_t Steam_Remote_Storage::UGCDownload( UGCHandle_t hContent, uint32 u
|
||||
|
||||
RemoteStorageDownloadUGCResult_t data{};
|
||||
data.m_hFile = hContent;
|
||||
data.m_nAppID = settings->get_local_game_id().AppID();
|
||||
|
||||
if (shared_files.count(hContent)) {
|
||||
data.m_eResult = k_EResultOK;
|
||||
data.m_nAppID = settings->get_local_game_id().AppID();
|
||||
data.m_ulSteamIDOwner = settings->get_local_steam_id().ConvertToUint64();
|
||||
data.m_nSizeInBytes = local_storage->file_size(Local_Storage::remote_storage_folder, shared_files[hContent]);
|
||||
|
||||
shared_files[hContent].copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1);
|
||||
PRINT_DEBUG(" FileShare data.m_pchFileName = '%s'", data.m_pchFileName);
|
||||
|
||||
downloaded_files[hContent].source = Downloaded_File::DownloadSource::AfterFileShare;
|
||||
downloaded_files[hContent].file = shared_files[hContent];
|
||||
downloaded_files[hContent].total_size = data.m_nSizeInBytes;
|
||||
auto [ele_itr, _] = downloaded_files.insert_or_assign(hContent, Downloaded_File::DownloadSource::AfterFileShare);
|
||||
auto &ele = ele_itr->second;
|
||||
ele.file = shared_files[hContent];
|
||||
ele.total_size = data.m_nSizeInBytes;
|
||||
} else if (auto query_res = ugc_bridge->get_ugc_query_result(hContent)) {
|
||||
auto mod = settings->getMod(query_res.value().mod_id);
|
||||
auto &mod_name = query_res.value().is_primary_file
|
||||
@ -434,24 +444,25 @@ SteamAPICall_t Steam_Remote_Storage::UGCDownload( UGCHandle_t hContent, uint32 u
|
||||
: mod.previewFileSize;
|
||||
|
||||
data.m_eResult = k_EResultOK;
|
||||
data.m_nAppID = settings->get_local_game_id().AppID();
|
||||
data.m_ulSteamIDOwner = mod.steamIDOwner;
|
||||
data.m_nSizeInBytes = mod_size;
|
||||
data.m_ulSteamIDOwner = mod.steamIDOwner;
|
||||
|
||||
mod_name.copy(data.m_pchFileName, sizeof(data.m_pchFileName) - 1);
|
||||
PRINT_DEBUG(" QueryUGCRequest data.m_pchFileName = '%s'", data.m_pchFileName);
|
||||
|
||||
downloaded_files[hContent].source = Downloaded_File::DownloadSource::AfterSendQueryUGCRequest;
|
||||
downloaded_files[hContent].file = mod_name;
|
||||
downloaded_files[hContent].total_size = mod_size;
|
||||
|
||||
downloaded_files[hContent].mod_query_info = query_res.value();
|
||||
|
||||
auto [ele_itr, _] = downloaded_files.insert_or_assign(hContent, Downloaded_File::DownloadSource::AfterSendQueryUGCRequest);
|
||||
auto &ele = ele_itr->second;
|
||||
ele.file = mod_name;
|
||||
ele.total_size = mod_size;
|
||||
ele.mod_query_info = query_res.value();
|
||||
} else {
|
||||
data.m_eResult = k_EResultFileNotFound; //TODO: not sure if this is the right result
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageDownloadUGCResult_t )
|
||||
@ -512,7 +523,7 @@ int32 Steam_Remote_Storage::UGCRead( UGCHandle_t hContent, void *pvData, int32 c
|
||||
Downloaded_File &dwf = f_itr->second;
|
||||
|
||||
// depending on the download source, we have to decide where to grab the content/data
|
||||
switch (dwf.source)
|
||||
switch (dwf.get_source())
|
||||
{
|
||||
case Downloaded_File::DownloadSource::AfterFileShare: {
|
||||
PRINT_DEBUG(" source = AfterFileShare '%s'", dwf.file.c_str());
|
||||
@ -523,14 +534,14 @@ int32 Steam_Remote_Storage::UGCRead( UGCHandle_t hContent, void *pvData, int32 c
|
||||
|
||||
case Downloaded_File::DownloadSource::AfterSendQueryUGCRequest:
|
||||
case Downloaded_File::DownloadSource::FromUGCDownloadToLocation: {
|
||||
PRINT_DEBUG(" source = AfterSendQueryUGCRequest || FromUGCDownloadToLocation [%i]", (int)dwf.source);
|
||||
PRINT_DEBUG(" source = AfterSendQueryUGCRequest || FromUGCDownloadToLocation [%i]", (int)dwf.get_source());
|
||||
auto mod = settings->getMod(dwf.mod_query_info.mod_id);
|
||||
auto &mod_name = dwf.mod_query_info.is_primary_file
|
||||
? mod.primaryFileName
|
||||
: mod.previewFileName;
|
||||
|
||||
std::string mod_fullpath{};
|
||||
if (dwf.source == Downloaded_File::DownloadSource::AfterSendQueryUGCRequest) {
|
||||
if (dwf.get_source() == Downloaded_File::DownloadSource::AfterSendQueryUGCRequest) {
|
||||
std::string mod_base_path = dwf.mod_query_info.is_primary_file
|
||||
? mod.path
|
||||
: Local_Storage::get_game_settings_path() + "mod_images" + PATH_SEPARATOR + std::to_string(mod.id);
|
||||
@ -547,7 +558,7 @@ int32 Steam_Remote_Storage::UGCRead( UGCHandle_t hContent, void *pvData, int32 c
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT_DEBUG(" unhandled download source %i", (int)dwf.source);
|
||||
PRINT_DEBUG(" unhandled download source %i", (int)dwf.get_source());
|
||||
return -1; //TODO: is this the right return value?
|
||||
break;
|
||||
}
|
||||
@ -790,12 +801,13 @@ SteamAPICall_t Steam_Remote_Storage::GetPublishedFileDetails( PublishedFileId_t
|
||||
mod.tags.copy(data.m_rgchTags, sizeof(data.m_rgchTags) - 1);
|
||||
mod.title.copy(data.m_rgchTitle, sizeof(data.m_rgchTitle) - 1);
|
||||
mod.workshopItemURL.copy(data.m_rgchURL, sizeof(data.m_rgchURL) - 1);
|
||||
|
||||
} else {
|
||||
data.m_eResult = EResult::k_EResultFail; // TODO is this correct?
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
|
||||
// return 0;
|
||||
/*
|
||||
@ -830,6 +842,7 @@ SteamAPICall_t Steam_Remote_Storage::EnumerateUserPublishedFiles( uint32 unStart
|
||||
PRINT_DEBUG("TODO %u", unStartIndex);
|
||||
// TODO is this implementation correct?
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
RemoteStorageEnumerateUserPublishedFilesResult_t data{};
|
||||
|
||||
// collect all published mods by this user
|
||||
@ -861,7 +874,9 @@ SteamAPICall_t Steam_Remote_Storage::EnumerateUserPublishedFiles( uint32 unStart
|
||||
data.m_nResultsReturned = iterated;
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageSubscribePublishedFileResult_t )
|
||||
@ -882,7 +897,9 @@ SteamAPICall_t Steam_Remote_Storage::SubscribePublishedFile( PublishedFileId_t u
|
||||
data.m_eResult = EResult::k_EResultFail; // TODO is this correct?
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageEnumerateUserSubscribedFilesResult_t )
|
||||
@ -914,7 +931,9 @@ SteamAPICall_t Steam_Remote_Storage::EnumerateUserSubscribedFiles( uint32 unStar
|
||||
data.m_nResultsReturned = iterated;
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageUnsubscribePublishedFileResult_t )
|
||||
@ -935,7 +954,9 @@ SteamAPICall_t Steam_Remote_Storage::UnsubscribePublishedFile( PublishedFileId_t
|
||||
data.m_eResult = k_EResultFail;
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Steam_Remote_Storage::UpdatePublishedFileSetChangeDescription( PublishedFileUpdateHandle_t updateHandle, const char *pchChangeDescription )
|
||||
@ -967,7 +988,9 @@ SteamAPICall_t Steam_Remote_Storage::GetPublishedItemVoteDetails( PublishedFileI
|
||||
data.m_eResult = EResult::k_EResultFail; // TODO is this correct?
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageUpdateUserPublishedItemVoteResult_t )
|
||||
@ -993,7 +1016,9 @@ SteamAPICall_t Steam_Remote_Storage::UpdateUserPublishedItemVote( PublishedFileI
|
||||
data.m_eResult = EResult::k_EResultFail; // TODO is this correct?
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageGetPublishedItemVoteDetailsResult_t )
|
||||
@ -1022,22 +1047,26 @@ SteamAPICall_t Steam_Remote_Storage::GetUserPublishedItemVoteDetails( PublishedF
|
||||
data.m_eResult = EResult::k_EResultFail; // TODO is this correct?
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
return 0;
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t )
|
||||
SteamAPICall_t Steam_Remote_Storage::EnumerateUserSharedWorkshopFiles( CSteamID steamId, uint32 unStartIndex, SteamParamStringArray_t *pRequiredTags, SteamParamStringArray_t *pExcludedTags )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG_TODO();
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
RemoteStorageEnumerateUserPublishedFilesResult_t data{};
|
||||
data.m_eResult = k_EResultOK;
|
||||
data.m_nResultsReturned = 0;
|
||||
data.m_nTotalResultCount = 0;
|
||||
//data.m_rgPublishedFileId;
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( RemoteStorageEnumerateUserPublishedFilesResult_t )
|
||||
@ -1086,12 +1115,15 @@ SteamAPICall_t Steam_Remote_Storage::EnumeratePublishedWorkshopFiles( EWorkshopE
|
||||
PRINT_DEBUG_TODO();
|
||||
// TODO is this implementation correct?
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
RemoteStorageEnumerateWorkshopFilesResult_t data{};
|
||||
data.m_eResult = EResult::k_EResultOK;
|
||||
data.m_nResultsReturned = 0;
|
||||
data.m_nTotalResultCount = 0;
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1134,18 +1166,20 @@ SteamAPICall_t Steam_Remote_Storage::UGCDownloadToLocation( UGCHandle_t hContent
|
||||
copy_file(mod_fullpath, pchLocation);
|
||||
|
||||
// TODO not sure about this though
|
||||
downloaded_files[hContent].source = Downloaded_File::DownloadSource::FromUGCDownloadToLocation;
|
||||
downloaded_files[hContent].file = mod_name;
|
||||
downloaded_files[hContent].total_size = mod_size;
|
||||
|
||||
downloaded_files[hContent].mod_query_info = query_res.value();
|
||||
downloaded_files[hContent].download_to_location_fullpath = pchLocation;
|
||||
auto [ele_itr, _] = downloaded_files.insert_or_assign(hContent, Downloaded_File::DownloadSource::FromUGCDownloadToLocation);
|
||||
auto &ele = ele_itr->second;
|
||||
ele.file = mod_name;
|
||||
ele.total_size = mod_size;
|
||||
ele.mod_query_info = query_res.value();
|
||||
ele.download_to_location_fullpath = pchLocation;
|
||||
|
||||
} else {
|
||||
data.m_eResult = k_EResultFileNotFound; //TODO: not sure if this is the right result
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Cloud dynamic state change notification
|
||||
|
@ -47,6 +47,9 @@ Steam_Timeline::Steam_Timeline(class Settings *settings, class Networking *netwo
|
||||
|
||||
// this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Timeline::steam_callback, this);
|
||||
this->run_every_runcb->add(&Steam_Timeline::steam_run_every_runcb, this);
|
||||
|
||||
// timeline starts with a default event as seen here: https://www.youtube.com/watch?v=YwBD0E4-EsI
|
||||
SetTimelineGameMode(ETimelineGameMode::k_ETimelineGameMode_Invalid);
|
||||
}
|
||||
|
||||
Steam_Timeline::~Steam_Timeline()
|
||||
@ -55,6 +58,20 @@ Steam_Timeline::~Steam_Timeline()
|
||||
this->run_every_runcb->remove(&Steam_Timeline::steam_run_every_runcb, this);
|
||||
}
|
||||
|
||||
|
||||
// Sets a description for the current game state in the timeline. These help the user to find specific
|
||||
// moments in the timeline when saving clips. Setting a new state description replaces any previous
|
||||
// description.
|
||||
//
|
||||
// Examples could include:
|
||||
// * Where the user is in the world in a single player game
|
||||
// * Which round is happening in a multiplayer game
|
||||
// * The current score for a sports game
|
||||
//
|
||||
// Parameters:
|
||||
// - pchDescription: provide a localized string in the language returned by SteamUtils()->GetSteamUILanguage()
|
||||
// - flTimeDelta: The time offset in seconds to apply to this event. Negative times indicate an
|
||||
// event that happened in the past.
|
||||
void Steam_Timeline::SetTimelineStateDescription( const char *pchDescription, float flTimeDelta )
|
||||
{
|
||||
PRINT_DEBUG("'%s' %f", pchDescription, flTimeDelta);
|
||||
@ -78,7 +95,6 @@ void Steam_Timeline::SetTimelineStateDescription( const char *pchDescription, fl
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Steam_Timeline::ClearTimelineStateDescription( float flTimeDelta )
|
||||
{
|
||||
PRINT_DEBUG("%f", flTimeDelta);
|
||||
@ -98,10 +114,35 @@ void Steam_Timeline::ClearTimelineStateDescription( float flTimeDelta )
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Use this to mark an event on the Timeline. The event can be instantaneous or take some amount of time
|
||||
// to complete, depending on the value passed in flDurationSeconds
|
||||
//
|
||||
// Examples could include:
|
||||
// * a boss battle
|
||||
// * a cut scene
|
||||
// * a large team fight
|
||||
// * picking up a new weapon or ammunition
|
||||
// * scoring a goal
|
||||
//
|
||||
// Parameters:
|
||||
//
|
||||
// - pchIcon: specify the name of the icon uploaded through the Steamworks Partner Site for your title
|
||||
// or one of the provided icons that start with steam_
|
||||
// - pchTitle & pchDescription: provide a localized string in the language returned by
|
||||
// SteamUtils()->GetSteamUILanguage()
|
||||
// - unPriority: specify how important this range is compared to other markers provided by the game.
|
||||
// Ranges with larger priority values will be displayed more prominently in the UI. This value
|
||||
// may be between 0 and k_unMaxTimelinePriority.
|
||||
// - flStartOffsetSeconds: The time that this range started relative to now. Negative times
|
||||
// indicate an event that happened in the past.
|
||||
// - flDurationSeconds: How long the time range should be in seconds. For instantaneous events, this
|
||||
// should be 0
|
||||
// - ePossibleClip: By setting this parameter to Featured or Standard, the game indicates to Steam that it
|
||||
// would be appropriate to offer this range as a clip to the user. For instantaneous events, the
|
||||
// suggested clip will be for a short time before and after the event itself.
|
||||
void Steam_Timeline::AddTimelineEvent( const char *pchIcon, const char *pchTitle, const char *pchDescription, uint32 unPriority, float flStartOffsetSeconds, float flDurationSeconds, ETimelineEventClipPriority ePossibleClip )
|
||||
{
|
||||
PRINT_DEBUG("'%s' | '%s' - '%s', %u, [%f, %f) %i", pchIcon, pchTitle, pchDescription, unPriority, flStartOffsetSeconds, flDurationSeconds, (int)ePossibleClip);
|
||||
PRINT_DEBUG("icon='%s' | '%s' - '%s', %u, [%f, %f) %i", pchIcon, pchTitle, pchDescription, unPriority, flStartOffsetSeconds, flDurationSeconds, (int)ePossibleClip);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
auto &new_event = timeline_events.emplace_back(TimelineEvent_t{});
|
||||
@ -112,24 +153,28 @@ void Steam_Timeline::AddTimelineEvent( const char *pchIcon, const char *pchTitle
|
||||
|
||||
new_event.flStartOffsetSeconds = flStartOffsetSeconds;
|
||||
|
||||
// for instantanious event with flDurationSeconds=0 steam creates 8 sec clip
|
||||
if (static_cast<long>(flDurationSeconds * 1000) <= 100) { // <= 100ms
|
||||
flDurationSeconds = 8;
|
||||
// make events last at least 1 sec
|
||||
if (static_cast<long>(flDurationSeconds * 1000) < 1000) { // < 1000ms
|
||||
flDurationSeconds = 1;
|
||||
}
|
||||
// for events with priority=ETimelineEventClipPriority::k_ETimelineEventClipPriority_Featured steam creates ~8 sec clip
|
||||
// seen here: https://www.youtube.com/watch?v=YwBD0E4-EsI
|
||||
if (flDurationSeconds < PRIORITY_CLIP_MIN_SEC && ePossibleClip == ETimelineEventClipPriority::k_ETimelineEventClipPriority_Featured) {
|
||||
flDurationSeconds = PRIORITY_CLIP_MIN_SEC;
|
||||
}
|
||||
new_event.flDurationSeconds = flDurationSeconds;
|
||||
|
||||
new_event.ePossibleClip = ePossibleClip;
|
||||
}
|
||||
|
||||
|
||||
// Changes the color of the timeline bar. See ETimelineGameMode comments for how to use each value
|
||||
void Steam_Timeline::SetTimelineGameMode( ETimelineGameMode eMode )
|
||||
{
|
||||
PRINT_DEBUG("%i", (int)eMode);
|
||||
std::lock_guard lock(global_mutex);
|
||||
|
||||
if (timeline_states.empty()) return;
|
||||
|
||||
timeline_states.back().bar_color = eMode;
|
||||
auto &new_timeline_state = timeline_states.emplace_back(TimelineState_t{});
|
||||
new_timeline_state.bar_color = eMode;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1123,7 +1123,10 @@ SteamAPICall_t Steam_UGC::SetUserItemVote( PublishedFileId_t nPublishedFileID, b
|
||||
++mod.votesDown;
|
||||
}
|
||||
settings->addModDetails(nPublishedFileID, mod);
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1141,7 +1144,10 @@ SteamAPICall_t Steam_UGC::GetUserItemVote( PublishedFileId_t nPublishedFileID )
|
||||
data.m_bVotedDown = mod.votesDown;
|
||||
data.m_bVotedUp = mod.votesUp;
|
||||
data.m_bVoteSkipped = true;
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1166,7 +1172,9 @@ SteamAPICall_t Steam_UGC::AddItemToFavorites( AppId_t nAppId, PublishedFileId_t
|
||||
data.m_eResult = EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1191,7 +1199,9 @@ SteamAPICall_t Steam_UGC::RemoveItemFromFavorites( AppId_t nAppId, PublishedFile
|
||||
data.m_eResult = EResult::k_EResultOK;
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1209,7 +1219,9 @@ SteamAPICall_t Steam_UGC::SubscribeItem( PublishedFileId_t nPublishedFileID )
|
||||
} else {
|
||||
data.m_eResult = k_EResultFail;
|
||||
}
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
// subscribe to this item, will be installed ASAP
|
||||
|
||||
@ -1228,7 +1240,9 @@ SteamAPICall_t Steam_UGC::UnsubscribeItem( PublishedFileId_t nPublishedFileID )
|
||||
ugc_bridge->remove_subbed_mod(nPublishedFileID);
|
||||
}
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
// unsubscribe from this item, will be uninstalled after game quits
|
||||
|
||||
@ -1383,7 +1397,10 @@ SteamAPICall_t Steam_UGC::StartPlaytimeTracking( PublishedFileId_t *pvecPublishe
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
StopPlaytimeTrackingResult_t data;
|
||||
data.m_eResult = k_EResultOK;
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( StopPlaytimeTrackingResult_t )
|
||||
@ -1393,7 +1410,10 @@ SteamAPICall_t Steam_UGC::StopPlaytimeTracking( PublishedFileId_t *pvecPublished
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
StopPlaytimeTrackingResult_t data;
|
||||
data.m_eResult = k_EResultOK;
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
STEAM_CALL_RESULT( StopPlaytimeTrackingResult_t )
|
||||
@ -1403,7 +1423,10 @@ SteamAPICall_t Steam_UGC::StopPlaytimeTrackingForAllItems()
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
StopPlaytimeTrackingResult_t data;
|
||||
data.m_eResult = k_EResultOK;
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -126,9 +126,11 @@ void Steam_User::RefreshSteam2Login()
|
||||
bool Steam_User::GetUserDataFolder( char *pchBuffer, int cubBuffer )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
if (!cubBuffer) return false;
|
||||
if (!cubBuffer || cubBuffer <= 0) return false;
|
||||
|
||||
std::string user_data = local_storage->get_path(Local_Storage::user_data_storage);
|
||||
if (static_cast<size_t>(cubBuffer) <= user_data.size()) return false;
|
||||
|
||||
strncpy(pchBuffer, user_data.c_str(), cubBuffer - 1);
|
||||
pchBuffer[cubBuffer - 1] = 0;
|
||||
return true;
|
||||
@ -201,6 +203,7 @@ EVoiceResult Steam_User::GetVoice( bool bWantCompressed, void *pDestBuffer, uint
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
if (!recording) return k_EVoiceResultNotRecording;
|
||||
|
||||
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
|
||||
if (bWantCompressed) {
|
||||
uint32 towrite = static_cast<uint32>(seconds * 1024.0 * 64.0 / 8.0);
|
||||
@ -239,6 +242,7 @@ EVoiceResult Steam_User::DecompressVoice( const void *pCompressed, uint32 cbComp
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
if (!recording) return k_EVoiceResultNotRecording;
|
||||
|
||||
uint32 uncompressed = static_cast<uint32>((double)cbCompressed * ((double)nDesiredSampleRate / 8192.0));
|
||||
if(nBytesWritten) *nBytesWritten = uncompressed;
|
||||
if (uncompressed > cbDestBufferSize) uncompressed = cbDestBufferSize;
|
||||
@ -296,7 +300,7 @@ HAuthTicket Steam_User::GetAuthSessionTicket( void *pTicket, int cbMaxTicket, ui
|
||||
// the ticket will be returned in callback GetTicketForWebApiResponse_t
|
||||
HAuthTicket Steam_User::GetAuthTicketForWebApi( const char *pchIdentity )
|
||||
{
|
||||
PRINT_DEBUG("%s", pchIdentity);
|
||||
PRINT_DEBUG("'%s'", pchIdentity);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
return auth_manager->getWebApiTicket(pchIdentity);
|
||||
@ -377,7 +381,7 @@ void Steam_User::AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, u
|
||||
STEAM_CALL_RESULT( EncryptedAppTicketResponse_t )
|
||||
SteamAPICall_t Steam_User::RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude )
|
||||
{
|
||||
PRINT_DEBUG("%i", cbDataToInclude);
|
||||
PRINT_DEBUG("%i %p", cbDataToInclude, pDataToInclude);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
EncryptedAppTicketResponse_t data;
|
||||
data.m_eResult = k_EResultOK;
|
||||
@ -420,7 +424,9 @@ SteamAPICall_t Steam_User::RequestEncryptedAppTicket( void *pDataToInclude, int
|
||||
|
||||
encrypted_app_ticket = pb.SerializeAsString();
|
||||
|
||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// retrieve a finished ticket
|
||||
@ -439,6 +445,7 @@ bool Steam_User::GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *
|
||||
if (ticket_size > static_cast<uint32>(cbMaxTicket)) return false;
|
||||
encrypted_app_ticket.copy((char *)pTicket, cbMaxTicket);
|
||||
|
||||
PRINT_DEBUG("copied successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -471,7 +478,7 @@ int Steam_User::GetPlayerSteamLevel()
|
||||
STEAM_CALL_RESULT( StoreAuthURLResponse_t )
|
||||
SteamAPICall_t Steam_User::RequestStoreAuthURL( const char *pchRedirectURL )
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG_TODO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -506,7 +513,7 @@ bool Steam_User::BIsPhoneRequiringVerification()
|
||||
STEAM_CALL_RESULT( MarketEligibilityResponse_t )
|
||||
SteamAPICall_t Steam_User::GetMarketEligibility()
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG_TODO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -514,7 +521,7 @@ SteamAPICall_t Steam_User::GetMarketEligibility()
|
||||
STEAM_CALL_RESULT( DurationControl_t )
|
||||
SteamAPICall_t Steam_User::GetDurationControl()
|
||||
{
|
||||
PRINT_DEBUG_ENTRY();
|
||||
PRINT_DEBUG_TODO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -255,11 +255,10 @@ SteamAPICall_t Steam_Utils::CheckFileSignature( const char *szFileName )
|
||||
{
|
||||
PRINT_DEBUG("'%s'", szFileName);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
CheckFileSignature_t data;
|
||||
CheckFileSignature_t data{};
|
||||
data.m_eCheckFileSignature = k_ECheckFileSignatureValidSignature;
|
||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||
// TODO callback too?
|
||||
// callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,7 @@ std::wstring common_helpers::to_lower(std::wstring_view wstr)
|
||||
{
|
||||
if (wstr.empty()) return {};
|
||||
|
||||
std::wstring _wstr(wstr.size(), '\0');
|
||||
std::wstring _wstr(wstr.size(), L'\0');
|
||||
std::transform(wstr.begin(), wstr.end(), _wstr.begin(), [](wchar_t c) { return std::tolower(c); });
|
||||
return _wstr;
|
||||
}
|
||||
@ -308,7 +308,7 @@ std::wstring common_helpers::to_upper(std::wstring_view wstr)
|
||||
{
|
||||
if (wstr.empty()) return {};
|
||||
|
||||
std::wstring _wstr(wstr.size(), '\0');
|
||||
std::wstring _wstr(wstr.size(), L'\0');
|
||||
std::transform(wstr.begin(), wstr.end(), _wstr.begin(), [](wchar_t c) { return std::toupper(c); });
|
||||
return _wstr;
|
||||
}
|
||||
|
@ -4,14 +4,17 @@
|
||||
|
||||
[app::general]
|
||||
# by default the emu will report a `non-beta` branch when the game calls `Steam_Apps::GetCurrentBetaName()`
|
||||
# make the game/app think we're playing on a beta branch
|
||||
# 1=make the game/app think we're playing on a beta branch
|
||||
# default=0
|
||||
is_beta_branch=0
|
||||
# the name of the current branch, this must also exist in branches.json
|
||||
# otherwise will be ignored by the emu and the default 'public' branch will be used
|
||||
# default=public
|
||||
branch_name=public
|
||||
|
||||
[app::dlcs]
|
||||
# should the emu report all DLCs as unlocked
|
||||
# 1=report all DLCs as unlocked
|
||||
# 0=report only the DLCs mentioned
|
||||
# some games check for "hidden" DLCs, hence this should be set to 1 in that case
|
||||
# but other games detect emus by querying for a fake/bad DLC, hence this should be set to 0 in that case
|
||||
# default=1
|
||||
|
@ -3,80 +3,105 @@
|
||||
# ############################################################################## #
|
||||
|
||||
[main::general]
|
||||
# generate new app auth ticket
|
||||
# 1=generate newer version of auth ticket, used by some modern apps
|
||||
# default=0
|
||||
new_app_ticket=1
|
||||
# generate/embed GC token inside new App Ticket
|
||||
# 1=generate/embed Game Coordinator token inside the new auth ticket
|
||||
# default=0
|
||||
gc_token=1
|
||||
# pretend the app is running on a steam deck
|
||||
# 1=pretend the app is running on a steam deck
|
||||
# default=0
|
||||
steam_deck=0
|
||||
# enable avatar functionality
|
||||
# 1=enable avatar functionality
|
||||
# default=0
|
||||
enable_account_avatar=0
|
||||
# prevent Steam_User_Stats::FindLeaderboard() from always succeeding and creating the unknown leaderboard
|
||||
# not recommended to disable this
|
||||
# 1=prevent `Steam_User_Stats::FindLeaderboard()` from always succeeding and creating the unknown leaderboard
|
||||
# not recommended to enable this
|
||||
# default=0
|
||||
disable_leaderboards_create_unknown=0
|
||||
# the emu will only save/update stats defined by the user, unknown stats requested or updated by the game will be rejected
|
||||
# set this to 1 to allow unknown stats
|
||||
# 1=allow unknown stats to be saved/updated
|
||||
# default=0
|
||||
allow_unknown_stats=0
|
||||
# whenever a game updates a stat which is tied to an achievement progress, the emu will save that progress immediately
|
||||
# but some games will update the stat very frequently (with lower & higher values) resulting in a spam of disk writes or overlay notifications
|
||||
# set this to 0 to save any stat achievement progress value (higher or lower)
|
||||
# this has no impact on the stat itself, only the achievement progress of a stat which is tied to an achievement
|
||||
# 0=save any stat achievement progress value (higher or lower)
|
||||
# 1=save stat achievement progress value only if it is higher than the current one
|
||||
# this has no impact on the stat itself, only the achievement progress
|
||||
# also has no impact on the functions which directly change stats, achievements, or achievements progress
|
||||
# default=1
|
||||
save_only_higher_stat_achievement_progress=1
|
||||
# synchronize user stats/achievements with game servers as soon as possible instead of caching them until the next call to `Steam_RunCallbacks()`
|
||||
# not recommended
|
||||
# 1=synchronize user stats/achievements with game servers as soon as possible instead of caching them until the next call to `Steam_RunCallbacks()`
|
||||
# not recommended to enable this
|
||||
# default=0
|
||||
immediate_gameserver_stats=0
|
||||
# use the proper type of the server list (internet, friends, etc...) when requested by the game
|
||||
# otherwise, the emu will always return the type "LAN server"
|
||||
# not recommended
|
||||
# 1=use the proper type of the server list (internet, friends, etc...) when requested by the game
|
||||
# 0=always return the type of the server list as "LAN server"
|
||||
# not recommended to enable this
|
||||
# default=0
|
||||
matchmaking_server_list_actual_type=0
|
||||
# grab the server details for match making using an actual server query
|
||||
# not recommended
|
||||
# 1=grab the server details for match making using an actual server query
|
||||
# 0=use the info from the local network messages shared between client/server
|
||||
# not recommended to enable this, currently breaks some games
|
||||
# default=0
|
||||
matchmaking_server_details_via_source_query=0
|
||||
# very basic crash logger/printer
|
||||
# this is intended to debug some annoying scenarios, and best used with the debug build of the emu
|
||||
# default=
|
||||
crash_printer_location=./path/relative/to/dll/crashes.txt
|
||||
|
||||
[main::connectivity]
|
||||
# prevent hooking OS networking APIs and allow any external requests
|
||||
# only used by the experimental builds on Windows
|
||||
# 1=prevent hooking OS networking APIs and allow any external requests
|
||||
# only used by the experimental builds on **Windows**
|
||||
# default=0
|
||||
disable_lan_only=0
|
||||
# disable all steam networking interface functionality
|
||||
# 1=disable all steam networking interface functionality
|
||||
# this won't prevent games/apps from making external requests
|
||||
# networking related functionality like lobbies or those that launch a server in the background will not work
|
||||
# default=0
|
||||
disable_networking=0
|
||||
# change the UDP/TCP port the emulator listens on, you should probably not change this because everyone needs to use the same port or you won't find yourselves on the network
|
||||
# default=47584
|
||||
listen_port=47584
|
||||
# pretend steam is running in offline mode
|
||||
# 1=pretend steam is running in offline mode, mainly affects the function `ISteamUser::BLoggedOn()`
|
||||
# Some games that connect to online servers might only work if the steam emu behaves like steam is in offline mode
|
||||
# default=0
|
||||
offline=0
|
||||
# prevent sharing stats and achievements with any game server,
|
||||
# this also disables the interface ISteamGameServerStats
|
||||
# 1=prevent sharing stats and achievements with any game server, this also disables the interface ISteamGameServerStats
|
||||
# default=0
|
||||
disable_sharing_stats_with_gameserver=0
|
||||
# do not send server details to the server browser, only works for game servers
|
||||
# 1=do not send server details to the server browser, only works for game servers
|
||||
# default=0
|
||||
disable_source_query=0
|
||||
# enable sharing leaderboards scores with people playing the same game on the same network
|
||||
# 1=enable sharing leaderboards scores with people playing the same game on the same network
|
||||
# not ideal and synchronization isn't perfect
|
||||
# default=0
|
||||
share_leaderboards_over_network=0
|
||||
# prevent lobby creation in steam matchmaking interface
|
||||
# 1=prevent lobby creation in the steam matchmaking interface
|
||||
# default=0
|
||||
disable_lobby_creation=0
|
||||
# attempt to download external HTTP(S) requests made via Steam_HTTP::SendHTTPRequest() inside "steam_settings/http/"
|
||||
# 1=attempt to download external HTTP(S) requests made via Steam_HTTP::SendHTTPRequest() inside "steam_settings/http/"
|
||||
# make sure to:
|
||||
# * set disable_lan_only=1
|
||||
# * set disable_networking=0
|
||||
# this will **not** work if the app is using native/OS web APIs
|
||||
# default=0
|
||||
download_steamhttp_requests=0
|
||||
|
||||
# mostly workarounds for specific problems
|
||||
[main::misc]
|
||||
# force SetAchievement() to always return true
|
||||
# 1=force `ISteamUserStats::SetAchievement()` to always return true
|
||||
# this is a workaround for some games that otherwise won't work
|
||||
# default=0
|
||||
achievements_bypass=0
|
||||
# force the function Steam_HTTP::SendHTTPRequest() to always succeed
|
||||
# force the function `Steam_HTTP::SendHTTPRequest()` to always succeed
|
||||
# default=0
|
||||
force_steamhttp_success=0
|
||||
# env var SteamOverlayGameId breaks Steam Input when the game is added to Steam as a non-steam game
|
||||
# env var `SteamOverlayGameId` breaks Steam Input when the game is added to Steam as a non-steam game
|
||||
# 1=don't write this env var, allowing Steam Input to work
|
||||
# default=0
|
||||
disable_steamoverlaygameid_env_var=0
|
||||
# add many Steam apps to the list of owned DLCs and the emu's list of installed app IDs
|
||||
# 1=add many Steam apps to the list of owned DLCs and the emu's list of installed app IDs
|
||||
# useful for many Source-based games
|
||||
# https://developer.valvesoftware.com/wiki/Steam_Application_IDs
|
||||
# https://developer.valvesoftware.com/wiki/Dedicated_Servers_List
|
||||
|
@ -11,7 +11,8 @@
|
||||
# ############################################################################## #
|
||||
|
||||
[overlay::general]
|
||||
# enable the experimental overlay, might cause crashes
|
||||
# 1=enable the experimental overlay, might cause crashes
|
||||
# default=0
|
||||
enable_experimental_overlay=0
|
||||
# amount of time to wait before attempting to detect and hook the renderer (DirectX, OpenGL, etc...)
|
||||
# default=0
|
||||
@ -19,26 +20,34 @@ hook_delay_sec=0
|
||||
# timeout for the renderer detector
|
||||
# default=15
|
||||
renderer_detector_timeout_sec=15
|
||||
# disable the achievements notifications
|
||||
# 1=disable the achievements notifications
|
||||
# default=0
|
||||
disable_achievement_notification=0
|
||||
# disable friends invitations and messages notifications
|
||||
# 1=disable friends invitations and messages notifications
|
||||
# default=0
|
||||
disable_friend_notification=0
|
||||
# disable showing notifications for achievements progress
|
||||
# 1=disable showing notifications for achievements progress
|
||||
# default=0
|
||||
disable_achievement_progress=0
|
||||
# disable any warning in the overlay
|
||||
# 1=disable any warning in the overlay
|
||||
# default=0
|
||||
disable_warning_any=0
|
||||
# disable the bad app ID warning in the overlay
|
||||
# 1=disable the bad app ID warning in the overlay
|
||||
# default=0
|
||||
disable_warning_bad_appid=0
|
||||
# disable the local_save warning in the overlay
|
||||
# 1=disable the local_save warning in the overlay
|
||||
# default=0
|
||||
disable_warning_local_save=0
|
||||
|
||||
[overlay::appearance]
|
||||
# load custom TrueType font from a path, it could be absolute, or relative
|
||||
# relative paths will be looked up inside the local folder "steam_settings/fonts" first,
|
||||
# if that wasn't found, it will be looked up inside the global folder "GSE Settings/settings/fonts"
|
||||
# default=
|
||||
Font_Override=Roboto-Medium.ttf
|
||||
# global font size
|
||||
# for built-in font, multiple of 16 is recommended. e.g. 16 32...
|
||||
# default=16.0
|
||||
Font_Size=20.0
|
||||
|
||||
# achievement icon size
|
||||
@ -75,6 +84,7 @@ Notification_Duration_Chat=4.0
|
||||
# format for the achievement unlock date/time, limited to 79 characters
|
||||
# if the output formatted string exceeded this limit, the builtin format will be used
|
||||
# look for the format here: https://en.cppreference.com/w/cpp/chrono/c/strftime
|
||||
# default=%Y/%m/%d - %H:%M:%S
|
||||
Achievement_Unlock_Datetime_Format=%Y/%m/%d - %H:%M:%S
|
||||
|
||||
# main background when you press shift+tab
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
[user::general]
|
||||
# user account name
|
||||
# default=gse orca
|
||||
account_name=gse orca
|
||||
# Steam64 format
|
||||
# your account ID in Steam64 format
|
||||
# if the specified ID is invalid, the emu will ignore it and generate a proper one
|
||||
# default=randomly generated by the emu only once and saved in the global settings
|
||||
account_steamid=76561197960287930
|
||||
# the language reported to the app/game
|
||||
# this must exist in 'supported_languages.txt', otherwise it will be ignored by the emu
|
||||
# look for the column 'API language code' here: https://partner.steamgames.com/doc/store/localization/languages
|
||||
# this must also exist in 'supported_languages.txt', otherwise it will be ignored by the emu
|
||||
# default=english
|
||||
language=english
|
||||
# report a country IP if the game queries it
|
||||
@ -22,6 +25,7 @@ ip_country=US
|
||||
# path could be absolute, or relative to the location of the .dll/.so
|
||||
# leading and trailing whitespaces are trimmed
|
||||
# when this option is used, the global settings folder is completely ignored, allowing a full portable behavior
|
||||
# default=
|
||||
local_save_path=./path/relative/to/dll
|
||||
# name of the base folder used to store save data, leading and trailing whitespaces are trimmed
|
||||
# only useful if 'local_save_path' isn't used
|
||||
|
@ -34,16 +34,16 @@ static dbg_log logger{pe_helpers::get_current_exe_path() + pe_helpers::get_curre
|
||||
constexpr static const wchar_t STEAM_UNIVERSE[] = L"Public";
|
||||
constexpr static const wchar_t STEAM_URL_PROTOCOL[] = L"URL:steam protocol";
|
||||
|
||||
const bool loader_is_32 = pe_helpers::is_module_32(GetModuleHandleW(NULL));
|
||||
const static bool loader_is_32 = pe_helpers::is_module_32(GetModuleHandleW(NULL));
|
||||
|
||||
const std::wstring hklm_path(loader_is_32
|
||||
const static std::wstring hklm_path(loader_is_32
|
||||
? L"SOFTWARE\\Valve\\Steam"
|
||||
: L"SOFTWARE\\WOW6432Node\\Valve\\Steam"
|
||||
);
|
||||
|
||||
// Declare some variables to be used for Steam registry.
|
||||
const DWORD UserId = 0x03100004771F810D & 0xffffffff;
|
||||
const DWORD ProcessID = GetCurrentProcessId();
|
||||
const static DWORD UserId = 0x03100004771F810D & 0xffffffff;
|
||||
const static DWORD ProcessID = GetCurrentProcessId();
|
||||
|
||||
static std::string IniFile{};
|
||||
static std::string ClientPath{};
|
||||
@ -154,20 +154,26 @@ static std::vector<std::string> collect_dlls_to_inject(const bool is_exe_32, std
|
||||
}
|
||||
}
|
||||
|
||||
bool orig_steam_hkcu = false;
|
||||
WCHAR OrgSteamCDir_hkcu[8192] = { 0 };
|
||||
DWORD Size1_hkcu = _countof(OrgSteamCDir_hkcu);
|
||||
WCHAR OrgSteamCDir64_hkcu[8192] = { 0 };
|
||||
DWORD Size2_hkcu = _countof(OrgSteamCDir64_hkcu);
|
||||
bool patch_registry_hkcu()
|
||||
static bool orig_steam_hkcu = false;
|
||||
static WCHAR OrgSteamCDir_hkcu[8192] = { 0 };
|
||||
static DWORD Size1_hkcu = sizeof(OrgSteamCDir_hkcu);
|
||||
static WCHAR OrgSteamCDir64_hkcu[8192] = { 0 };
|
||||
static DWORD Size2_hkcu = sizeof(OrgSteamCDir64_hkcu);
|
||||
static DWORD OrgSteamActiveUser_hkcu = 0;
|
||||
static WCHAR OrgSteamUniverse_hkcu[8192] = { 0 };
|
||||
static DWORD Size4_hkcu = sizeof(OrgSteamUniverse_hkcu);
|
||||
static bool patch_registry_hkcu()
|
||||
{
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
orig_steam_hkcu = true;
|
||||
// Get original values to restore later.
|
||||
DWORD keyType = REG_SZ;
|
||||
RegQueryValueExW(Registrykey, L"SteamClientDll", 0, &keyType, (LPBYTE)&OrgSteamCDir_hkcu, &Size1_hkcu);
|
||||
RegQueryValueExW(Registrykey, L"SteamClientDll64", 0, &keyType, (LPBYTE)&OrgSteamCDir64_hkcu, &Size2_hkcu);
|
||||
RegQueryValueExW(Registrykey, L"SteamClientDll", 0, &keyType, (LPBYTE)OrgSteamCDir_hkcu, &Size1_hkcu);
|
||||
RegQueryValueExW(Registrykey, L"SteamClientDll64", 0, &keyType, (LPBYTE)OrgSteamCDir64_hkcu, &Size2_hkcu);
|
||||
DWORD SizeActiveUser_hkcu = sizeof(DWORD);
|
||||
RegQueryValueExW(Registrykey, L"ActiveUser", 0, &keyType, (LPBYTE)&OrgSteamActiveUser_hkcu, &SizeActiveUser_hkcu);
|
||||
RegQueryValueExW(Registrykey, L"Universe", 0, &keyType, (LPBYTE)OrgSteamUniverse_hkcu, &Size4_hkcu);
|
||||
logger.write("Found previous registry entry (HKCU) for Steam");
|
||||
} else if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, 0, REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS, NULL, &Registrykey, NULL) == ERROR_SUCCESS) {
|
||||
@ -177,18 +183,18 @@ bool patch_registry_hkcu()
|
||||
return false;
|
||||
}
|
||||
|
||||
RegSetValueExW(Registrykey, L"ActiveUser", NULL, REG_DWORD, (const BYTE *)&UserId, sizeof(DWORD));
|
||||
RegSetValueExW(Registrykey, L"pid", NULL, REG_DWORD, (const BYTE *)&ProcessID, sizeof(DWORD));
|
||||
auto client_path = common_helpers::to_wstr(ClientPath);
|
||||
auto client64_path = common_helpers::to_wstr(Client64Path);
|
||||
RegSetValueExW(Registrykey, L"pid", NULL, REG_DWORD, (const BYTE *)&ProcessID, sizeof(DWORD));
|
||||
RegSetValueExW(Registrykey, L"SteamClientDll", NULL, REG_SZ, (const BYTE*)(client_path).c_str(), static_cast<DWORD>((client_path.size() + 1) * sizeof(client_path[0])));
|
||||
RegSetValueExW(Registrykey, L"SteamClientDll64", NULL, REG_SZ, (const BYTE*)client64_path.c_str(), static_cast<DWORD>((client64_path.size() + 1) * sizeof(client64_path[0])));
|
||||
RegSetValueExW(Registrykey, L"ActiveUser", NULL, REG_DWORD, (const BYTE *)&UserId, sizeof(DWORD));
|
||||
RegSetValueExW(Registrykey, L"Universe", NULL, REG_SZ, (const BYTE *)STEAM_UNIVERSE, (DWORD)sizeof(STEAM_UNIVERSE));
|
||||
RegCloseKey(Registrykey);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanup_registry_hkcu()
|
||||
static void cleanup_registry_hkcu()
|
||||
{
|
||||
if (!orig_steam_hkcu) return;
|
||||
|
||||
@ -196,8 +202,10 @@ void cleanup_registry_hkcu()
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam\\ActiveProcess", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
// Restore the values.
|
||||
RegSetValueExW(Registrykey, L"SteamClientDll", NULL, REG_SZ, (LPBYTE)OrgSteamCDir_hkcu, Size1_hkcu);
|
||||
RegSetValueExW(Registrykey, L"SteamClientDll64", NULL, REG_SZ, (LPBYTE)OrgSteamCDir64_hkcu, Size2_hkcu);
|
||||
RegSetValueExW(Registrykey, L"SteamClientDll", NULL, REG_SZ, (const BYTE *)OrgSteamCDir_hkcu, Size1_hkcu);
|
||||
RegSetValueExW(Registrykey, L"SteamClientDll64", NULL, REG_SZ, (const BYTE *)OrgSteamCDir64_hkcu, Size2_hkcu);
|
||||
RegSetValueExW(Registrykey, L"ActiveUser", NULL, REG_DWORD, (const BYTE *)&OrgSteamActiveUser_hkcu, sizeof(DWORD));
|
||||
RegSetValueExW(Registrykey, L"Universe", NULL, REG_SZ, (const BYTE *)OrgSteamUniverse_hkcu, Size4_hkcu);
|
||||
|
||||
// Close the HKEY Handle.
|
||||
RegCloseKey(Registrykey);
|
||||
@ -207,17 +215,80 @@ void cleanup_registry_hkcu()
|
||||
}
|
||||
|
||||
|
||||
bool orig_steam_hklm = false;
|
||||
WCHAR OrgInstallPath_hklm[8192] = { 0 };
|
||||
DWORD Size1_hklm = _countof(OrgInstallPath_hklm);
|
||||
bool patch_registry_hklm()
|
||||
static bool orig_steam_hkcu_2 = false;
|
||||
static WCHAR OrgSteamModDir_hkcu_2[8192] = { 0 };
|
||||
static DWORD Size1_hkcu_2 = sizeof(OrgSteamModDir_hkcu_2);
|
||||
static WCHAR OrgSteamPath_hkcu_2[8192] = { 0 };
|
||||
static DWORD Size2_hkcu_2 = sizeof(OrgSteamPath_hkcu_2);
|
||||
static WCHAR OrgSteamExe_2[8192] = { 0 };
|
||||
static DWORD Size3_hkcu_2 = sizeof(OrgSteamExe_2);
|
||||
static bool patch_registry_hkcu_2()
|
||||
{
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
orig_steam_hkcu_2 = true;
|
||||
// Get original values to restore later.
|
||||
DWORD keyType = REG_SZ;
|
||||
RegQueryValueExW(Registrykey, L"SourceModInstallPath", 0, &keyType, (LPBYTE)OrgSteamModDir_hkcu_2, &Size1_hkcu_2);
|
||||
RegQueryValueExW(Registrykey, L"SteamPath", 0, &keyType, (LPBYTE)OrgSteamPath_hkcu_2, &Size2_hkcu_2);
|
||||
RegQueryValueExW(Registrykey, L"SteamExe", 0, &keyType, (LPBYTE)OrgSteamExe_2, &Size3_hkcu_2);
|
||||
logger.write("Found previous registry entry (HKCU #2) for Steam");
|
||||
} else if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, 0, REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS, NULL, &Registrykey, NULL) == ERROR_SUCCESS) {
|
||||
logger.write("Created new registry entry (HKCU #2) for Steam");
|
||||
} else {
|
||||
logger.write("Unable to patch Registry (HKCU #2), error = " + std::to_string(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto my_path = common_helpers::to_wstr(pe_helpers::get_current_exe_path());
|
||||
my_path.pop_back(); // remove last '\\'
|
||||
const auto my_exe = common_helpers::to_wstr(pe_helpers::get_current_exe_path() + pe_helpers::get_current_exe_name());
|
||||
if (AppId.size()) { // empty in persistent mode = 2
|
||||
const auto appid_dword = std::stoul(AppId);
|
||||
RegSetValueExW(Registrykey, L"RunningAppID", NULL, REG_DWORD, (const BYTE*)&appid_dword, sizeof(DWORD));
|
||||
}
|
||||
RegSetValueExW(Registrykey, L"SourceModInstallPath", NULL, REG_SZ, (const BYTE*)my_path.c_str(), static_cast<DWORD>((my_path.size() + 1) * sizeof(my_path[0])));
|
||||
RegSetValueExW(Registrykey, L"SteamPath", NULL, REG_SZ, (const BYTE*)my_path.c_str(), static_cast<DWORD>((my_path.size() + 1) * sizeof(my_path[0])));
|
||||
RegSetValueExW(Registrykey, L"SteamExe", NULL, REG_SZ, (const BYTE*)my_exe.c_str(), static_cast<DWORD>((my_exe.size() + 1) * sizeof(my_exe[0])));
|
||||
RegCloseKey(Registrykey);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cleanup_registry_hkcu_2()
|
||||
{
|
||||
if (!orig_steam_hkcu_2) return;
|
||||
|
||||
logger.write("restoring registry entries (HKCU #2)");
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
// Restore the values.
|
||||
RegSetValueExW(Registrykey, L"SourceModInstallPath", NULL, REG_SZ, (LPBYTE)OrgSteamModDir_hkcu_2, Size1_hkcu_2);
|
||||
RegSetValueExW(Registrykey, L"SteamPath", NULL, REG_SZ, (LPBYTE)OrgSteamPath_hkcu_2, Size2_hkcu_2);
|
||||
RegSetValueExW(Registrykey, L"SteamExe", NULL, REG_SZ, (LPBYTE)OrgSteamExe_2, Size3_hkcu_2);
|
||||
|
||||
// Close the HKEY Handle.
|
||||
RegCloseKey(Registrykey);
|
||||
} else {
|
||||
logger.write("Unable to restore the original registry entry (HKCU #2), error = " + std::to_string(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool orig_steam_hklm = false;
|
||||
static WCHAR OrgInstallPath_hklm[8192] = { 0 };
|
||||
static DWORD Size1_hklm = sizeof(OrgInstallPath_hklm);
|
||||
static WCHAR OrgUniverse_hklm[8192] = { 0 };
|
||||
static DWORD Size2_hklm = sizeof(OrgUniverse_hklm);
|
||||
static bool patch_registry_hklm()
|
||||
{
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, hklm_path.c_str(), 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
orig_steam_hklm = true;
|
||||
// Get original values to restore later.
|
||||
DWORD keyType = REG_SZ;
|
||||
RegQueryValueExW(Registrykey, L"InstallPath", 0, &keyType, (LPBYTE)&OrgInstallPath_hklm, &Size1_hklm);
|
||||
RegQueryValueExW(Registrykey, L"InstallPath", 0, &keyType, (LPBYTE)OrgInstallPath_hklm, &Size1_hklm);
|
||||
RegQueryValueExW(Registrykey, L"Universe", 0, &keyType, (LPBYTE)OrgUniverse_hklm, &Size2_hklm);
|
||||
logger.write("Found previous registry entry (HKLM) for Steam");
|
||||
} else if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, hklm_path.c_str(), 0, 0, REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS, NULL, &Registrykey, NULL) == ERROR_SUCCESS) {
|
||||
@ -227,15 +298,16 @@ bool patch_registry_hklm()
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto my_path = common_helpers::to_wstr(pe_helpers::get_current_exe_path());
|
||||
RegSetValueExW(Registrykey, L"InstallPath", NULL, REG_SZ, (const BYTE*)my_path.c_str(), static_cast<DWORD>((my_path.size() + 1) * sizeof(my_path[0])));
|
||||
auto my_path = common_helpers::to_wstr(pe_helpers::get_current_exe_path());
|
||||
my_path.pop_back(); // remove last '\\'
|
||||
RegSetValueExW(Registrykey, L"SteamPID", NULL, REG_DWORD, (const BYTE *)&ProcessID, sizeof(DWORD));
|
||||
RegSetValueExW(Registrykey, L"InstallPath", NULL, REG_SZ, (const BYTE*)my_path.c_str(), static_cast<DWORD>((my_path.size() + 1) * sizeof(my_path[0])));
|
||||
RegSetValueExW(Registrykey, L"Universe", NULL, REG_SZ, (const BYTE *)STEAM_UNIVERSE, (DWORD)sizeof(STEAM_UNIVERSE));
|
||||
RegCloseKey(Registrykey);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanup_registry_hklm()
|
||||
static void cleanup_registry_hklm()
|
||||
{
|
||||
if (!orig_steam_hklm) return;
|
||||
|
||||
@ -243,6 +315,7 @@ void cleanup_registry_hklm()
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, hklm_path.c_str(), 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
RegSetValueExW(Registrykey, L"InstallPath", NULL, REG_SZ, (const BYTE *)OrgInstallPath_hklm, Size1_hklm);
|
||||
RegSetValueExW(Registrykey, L"Universe", NULL, REG_SZ, (const BYTE *)OrgUniverse_hklm, Size2_hklm);
|
||||
RegCloseKey(Registrykey);
|
||||
} else {
|
||||
logger.write("Unable to restore the original registry entry (HKLM), error = " + std::to_string(GetLastError()));
|
||||
@ -250,15 +323,20 @@ void cleanup_registry_hklm()
|
||||
}
|
||||
|
||||
|
||||
bool orig_steam_hkcs_1 = false;
|
||||
bool orig_steam_hkcs_2 = false;
|
||||
WCHAR OrgCommand_hkcs[8192] = { 0 };
|
||||
DWORD Size1_hkcs = _countof(OrgCommand_hkcs);
|
||||
bool patch_registry_hkcs()
|
||||
static bool orig_steam_hkcs_1 = false;
|
||||
static bool orig_steam_hkcs_2 = false;
|
||||
static WCHAR OrgCommand_hkcs[8192] = { 0 };
|
||||
static DWORD Size1_hkcs = sizeof(OrgCommand_hkcs);
|
||||
static WCHAR OrgUrlProtocol_hkcs[8192] = { 0 };
|
||||
static DWORD Size2_hkcs = sizeof(OrgUrlProtocol_hkcs);
|
||||
static bool patch_registry_hkcs()
|
||||
{
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"steam", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
orig_steam_hkcs_1 = true;
|
||||
// Get original values to restore later.
|
||||
DWORD keyType = REG_SZ;
|
||||
RegQueryValueExW(Registrykey, L"URL Protocol", 0, &keyType, (LPBYTE)&OrgUrlProtocol_hkcs, &Size2_hkcs);
|
||||
logger.write("Found previous registry entry (HKCS) #1 for Steam");
|
||||
} else if (RegCreateKeyExW(HKEY_CLASSES_ROOT, L"steam", 0, 0, REG_OPTION_NON_VOLATILE,
|
||||
KEY_ALL_ACCESS, NULL, &Registrykey, NULL) == ERROR_SUCCESS) {
|
||||
@ -288,16 +366,16 @@ bool patch_registry_hkcs()
|
||||
RegSetValueExW(Registrykey, L"URL Protocol", NULL, REG_SZ, (const BYTE *)L"", (DWORD)sizeof(L""));
|
||||
RegCloseKey(Registrykey);
|
||||
|
||||
const auto cmd = common_helpers::to_wstr(pe_helpers::get_current_exe_path() + "steam.exe -- \"%1\"");
|
||||
const auto cmd = common_helpers::to_wstr("\"" + pe_helpers::get_current_exe_path() + pe_helpers::get_current_exe_name() + "\" -- \"%1\"");
|
||||
RegSetValueExW(Registrykey_2, L"", NULL, REG_SZ, (const BYTE*)cmd.c_str(), static_cast<DWORD>((cmd.size() + 1) * sizeof(cmd[0])));
|
||||
RegCloseKey(Registrykey_2);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cleanup_registry_hkcs()
|
||||
static void cleanup_registry_hkcs()
|
||||
{
|
||||
if (orig_steam_hkcs_2) {
|
||||
logger.write("restoring registry entries (HKCS) #1");
|
||||
logger.write("restoring registry entries (HKCS) #2");
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"steam\\Shell\\Open\\Command", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
RegSetValueExW(Registrykey, L"", NULL, REG_SZ, (const BYTE *)OrgCommand_hkcs, Size1_hkcs);
|
||||
@ -307,7 +385,16 @@ void cleanup_registry_hkcs()
|
||||
}
|
||||
}
|
||||
|
||||
if (!orig_steam_hkcs_1) {
|
||||
if (orig_steam_hkcs_1) {
|
||||
logger.write("restoring registry entries (HKCS) #1");
|
||||
HKEY Registrykey = { 0 };
|
||||
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"steam", 0, KEY_ALL_ACCESS, &Registrykey) == ERROR_SUCCESS) {
|
||||
RegSetValueExW(Registrykey, L"URL Protocol", NULL, REG_SZ, (const BYTE *)OrgUrlProtocol_hkcs, Size2_hkcs);
|
||||
RegCloseKey(Registrykey);
|
||||
} else {
|
||||
logger.write("Unable to restore the original registry entry (HKCS) #1, error = " + std::to_string(GetLastError()));
|
||||
}
|
||||
} else {
|
||||
logger.write("removing registry entries (HKCS) #2 (added by loader)");
|
||||
HKEY Registrykey = { 0 };
|
||||
RegDeleteKeyW(HKEY_CLASSES_ROOT, L"steam");
|
||||
@ -316,7 +403,7 @@ void cleanup_registry_hkcs()
|
||||
|
||||
|
||||
|
||||
void set_steam_env_vars(const std::string &AppId)
|
||||
static void set_steam_env_vars(const std::string &AppId)
|
||||
{
|
||||
SetEnvironmentVariableA("SteamAppId", AppId.c_str());
|
||||
SetEnvironmentVariableA("SteamGameId", AppId.c_str());
|
||||
@ -552,12 +639,13 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
return 1;
|
||||
}
|
||||
} else { // steam://run/
|
||||
constexpr const static wchar_t STEAM_LAUNCH_CMD_1[] = L"steam://run/";
|
||||
constexpr const static wchar_t STEAM_LAUNCH_CMD_1[] = L"-- \"steam://run/";
|
||||
constexpr const static wchar_t STEAM_LAUNCH_CMD_2[] = L"-- \"steam://rungameid/";
|
||||
AppId.clear(); // we don't care about the app id in the ini
|
||||
auto my_cmd = lpCmdLine && lpCmdLine[0]
|
||||
? std::wstring(lpCmdLine)
|
||||
: std::wstring();
|
||||
//MessageBoxW(NULL, (my_cmd + L" ||| " + std::to_wstring(my_cmd.size())).c_str(), L"DEBUG ME", MB_OK);
|
||||
logger.write(L"persistent mode 2 detecting steam launch cmd from: '" + my_cmd + L"'");
|
||||
if (my_cmd.find(STEAM_LAUNCH_CMD_1) == 0) {
|
||||
AppId = common_helpers::to_str( my_cmd.substr(sizeof(STEAM_LAUNCH_CMD_1) / sizeof(STEAM_LAUNCH_CMD_1[0]), my_cmd.find_first_of(L" \t")) );
|
||||
@ -578,16 +666,37 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
}
|
||||
|
||||
if (!patch_registry_hkcu()) {
|
||||
cleanup_registry_hkcu();
|
||||
cleanup_registry_hkcu_2();
|
||||
cleanup_registry_hklm();
|
||||
cleanup_registry_hkcs();
|
||||
|
||||
logger.write("Unable to patch Registry (HKCU).");
|
||||
MessageBoxA(NULL, "Unable to patch Registry (HKCU).", "ColdClientLoader", MB_ICONERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!patch_registry_hkcu_2()) {
|
||||
cleanup_registry_hkcu();
|
||||
cleanup_registry_hkcu_2();
|
||||
cleanup_registry_hklm();
|
||||
cleanup_registry_hkcs();
|
||||
|
||||
logger.write("Unable to patch Registry (HKCU #2).");
|
||||
MessageBoxA(NULL, "Unable to patch Registry (HKCU #2).", "ColdClientLoader", MB_ICONERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// this fails due to admin rights when Steam isn't installed, not a big deal
|
||||
// ----------------------------------------------
|
||||
patch_registry_hklm();
|
||||
// if (!patch_registry_hklm()) {
|
||||
// cleanup_registry_hkcu();
|
||||
// cleanup_registry_hkcu_2();
|
||||
// cleanup_registry_hklm();
|
||||
// cleanup_registry_hkcs();
|
||||
//
|
||||
// logger.write("Unable to patch Registry (HKLM).");
|
||||
// MessageBoxA(NULL, "Unable to patch Registry (HKLM).", "ColdClientLoader", MB_ICONERROR);
|
||||
// return 1;
|
||||
// }
|
||||
@ -597,7 +706,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
patch_registry_hkcs();
|
||||
// if (!patch_registry_hkcs()) {
|
||||
// cleanup_registry_hkcu();
|
||||
// cleanup_registry_hkcu_2();
|
||||
// cleanup_registry_hklm();
|
||||
// cleanup_registry_hkcs();
|
||||
|
||||
// logger.write("Unable to patch Registry (HKCS).");
|
||||
// MessageBoxA(NULL, "Unable to patch Registry (HKCS).", "ColdClientLoader", MB_ICONERROR);
|
||||
@ -621,6 +732,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
if (!CreateProcessW(exe_file.c_str(), (LPWSTR)CommandLine.c_str(), NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, common_helpers::to_wstr(ExeRunDir).c_str(), &info, &processInfo)) {
|
||||
logger.write("Unable to load the requested EXE file, error = " + std::to_string(GetLastError()));
|
||||
cleanup_registry_hkcu();
|
||||
cleanup_registry_hkcu_2();
|
||||
cleanup_registry_hklm();
|
||||
cleanup_registry_hkcs();
|
||||
MessageBoxA(NULL, "Unable to load the requested EXE file.", "ColdClientLoader", MB_ICONERROR);
|
||||
@ -645,6 +757,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
CloseHandle(processInfo.hThread);
|
||||
|
||||
cleanup_registry_hkcu();
|
||||
cleanup_registry_hkcu_2();
|
||||
cleanup_registry_hklm();
|
||||
cleanup_registry_hkcs();
|
||||
|
||||
@ -684,8 +797,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
|
||||
MessageBoxA(NULL, "Start the game, then press OK when you have finished playing to close the loader", "Cold Client Loader (waiting)", MB_OK);
|
||||
}
|
||||
|
||||
if (PersistentMode != 2 || AppId.empty()) { // persistent mode 0 or 1, or mode 2 without app id
|
||||
if (PersistentMode != 2 || AppId.empty()) { // persistent mode 0 or 1, or mode 2 without app id
|
||||
cleanup_registry_hkcu();
|
||||
cleanup_registry_hkcu_2();
|
||||
cleanup_registry_hklm();
|
||||
cleanup_registry_hkcs();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user