2024-06-14 17:57:04 +03:00
|
|
|
/* Copyright (C) 2019 Mr Goldberg
|
|
|
|
This file is part of the Goldberg Emulator
|
|
|
|
|
|
|
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with the Goldberg Emulator; if not, see
|
|
|
|
<http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
There are no public docs about this interface, this implementation
|
|
|
|
is an imagination of how it might have been implemented
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dll/steam_gamestats.h"
|
|
|
|
|
|
|
|
|
2024-08-02 03:28:30 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
Steam_GameStats::Attribute_t::Attribute_t(const Attribute_t &other)
|
2024-08-02 03:28:30 +03:00
|
|
|
:type(type)
|
2024-06-14 17:57:04 +03:00
|
|
|
{
|
|
|
|
switch (other.type)
|
|
|
|
{
|
|
|
|
case AttributeType_t::Int: n_data = other.n_data; break;
|
2024-08-02 03:28:30 +03:00
|
|
|
case AttributeType_t::Str: new (&s_data) std::string(other.s_data); break;
|
2024-06-14 17:57:04 +03:00
|
|
|
case AttributeType_t::Float: f_data = other.f_data; break;
|
|
|
|
case AttributeType_t::Int64: ll_data = other.ll_data; break;
|
|
|
|
|
2024-08-02 03:28:30 +03:00
|
|
|
default: PRINT_DEBUG("[X] invalid type %i", (int)other.type); break;
|
2024-06-14 17:57:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Steam_GameStats::Attribute_t::Attribute_t(Attribute_t &&other)
|
2024-08-02 03:28:30 +03:00
|
|
|
:type(type)
|
2024-06-14 17:57:04 +03:00
|
|
|
{
|
|
|
|
switch (other.type)
|
|
|
|
{
|
|
|
|
case AttributeType_t::Int: n_data = other.n_data; break;
|
2024-08-02 03:28:30 +03:00
|
|
|
case AttributeType_t::Str: new (&s_data) std::string(std::move(other.s_data)); break;
|
2024-06-14 17:57:04 +03:00
|
|
|
case AttributeType_t::Float: f_data = other.f_data; break;
|
|
|
|
case AttributeType_t::Int64: ll_data = other.ll_data; break;
|
|
|
|
|
2024-08-02 03:28:30 +03:00
|
|
|
default: PRINT_DEBUG("[X] invalid type %i", (int)other.type); break;
|
2024-06-14 17:57:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Steam_GameStats::Attribute_t::~Attribute_t()
|
2024-08-02 03:28:30 +03:00
|
|
|
{
|
|
|
|
if (type == AttributeType_t::Str) {
|
|
|
|
s_data.~basic_string();
|
|
|
|
}
|
|
|
|
}
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
|
|
|
|
void Steam_GameStats::steam_gamestats_network_low_level(void *object, Common_Message *msg)
|
|
|
|
{
|
|
|
|
//PRINT_DEBUG_ENTRY();
|
|
|
|
|
|
|
|
auto inst = (Steam_GameStats *)object;
|
|
|
|
inst->network_callback_low_level(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Steam_GameStats::steam_gamestats_run_every_runcb(void *object)
|
|
|
|
{
|
|
|
|
//PRINT_DEBUG_ENTRY();
|
|
|
|
|
|
|
|
auto inst = (Steam_GameStats *)object;
|
|
|
|
inst->steam_run_callback();
|
|
|
|
}
|
|
|
|
|
|
|
|
Steam_GameStats::Steam_GameStats(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
|
|
{
|
|
|
|
this->settings = settings;
|
|
|
|
this->network = network;
|
|
|
|
this->callback_results = callback_results;
|
|
|
|
this->callbacks = callbacks;
|
|
|
|
this->run_every_runcb = run_every_runcb;
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
// this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_GameStats::steam_gamestats_network_low_level, this);
|
2024-06-14 17:57:04 +03:00
|
|
|
this->run_every_runcb->add(&Steam_GameStats::steam_gamestats_run_every_runcb, this);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Steam_GameStats::~Steam_GameStats()
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
// this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_GameStats::steam_gamestats_network_low_level, this);
|
2024-06-14 17:57:04 +03:00
|
|
|
this->run_every_runcb->remove(&Steam_GameStats::steam_gamestats_run_every_runcb, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-14 17:57:04 +03:00
|
|
|
bool Steam_GameStats::valid_stats_account_type(int8 nAccountType)
|
|
|
|
{
|
|
|
|
switch ((EGameStatsAccountType)nAccountType) {
|
|
|
|
case EGameStatsAccountType::k_EGameStatsAccountType_Steam:
|
|
|
|
case EGameStatsAccountType::k_EGameStatsAccountType_Xbox:
|
|
|
|
case EGameStatsAccountType::k_EGameStatsAccountType_SteamGameServer:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Steam_GameStats::Table_t *Steam_GameStats::get_or_create_session_table(Session_t &session, const char *table_name)
|
|
|
|
{
|
|
|
|
Table_t *table{};
|
|
|
|
{
|
|
|
|
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) {
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& [key, val] = session.tables.emplace_back(std::pair<std::string, Table_t>{});
|
|
|
|
table = &val;
|
2024-06-14 17:57:04 +03:00
|
|
|
} else {
|
|
|
|
table = &table_it->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return table;
|
|
|
|
}
|
|
|
|
|
|
|
|
Steam_GameStats::Attribute_t *Steam_GameStats::get_or_create_session_att(const char *att_name, Session_t &session, AttributeType_t type_if_create)
|
|
|
|
{
|
2024-08-02 03:28:30 +03:00
|
|
|
auto [ele_it, _] = session.attributes.emplace(att_name, type_if_create);
|
|
|
|
return &ele_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2024-08-02 03:28:30 +03:00
|
|
|
auto &row = table.rows[static_cast<unsigned>(ulRowID)];
|
|
|
|
auto [ele_it, _] = row.attributes.emplace(att_name, type_if_create);
|
|
|
|
return &ele_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
}
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
SteamAPICall_t Steam_GameStats::GetNewSession( int8 nAccountType, uint64 ulAccountID, int32 nAppID, RTime32 rtTimeStarted )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
// appid 550 calls this function once with client account id, and another time with server account id
|
2024-06-14 17:57:04 +03:00
|
|
|
PRINT_DEBUG("%i, %llu, %i, %u", (int)nAccountType, ulAccountID, nAppID, rtTimeStarted);
|
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
|
|
|
if ((settings->get_local_steam_id().ConvertToUint64() != ulAccountID) ||
|
|
|
|
(nAppID < 0) ||
|
|
|
|
(settings->get_local_game_id().AppID() != (uint32)nAppID) ||
|
|
|
|
!valid_stats_account_type(nAccountType)) {
|
2024-08-02 23:41:53 +03:00
|
|
|
|
2024-06-14 17:57:04 +03:00
|
|
|
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;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("[X] invalid param");
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
callbacks->addCBResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_id = create_session_id();
|
2024-06-14 17:57:04 +03:00
|
|
|
Session_t new_session{};
|
|
|
|
new_session.nAccountType = (EGameStatsAccountType)nAccountType;
|
|
|
|
new_session.rtTimeStarted = rtTimeStarted;
|
2024-08-02 23:41:53 +03:00
|
|
|
sessions.insert_or_assign(session_id, new_session);
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
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;
|
2024-08-02 23:41:53 +03:00
|
|
|
data.m_ulSessionID = session_id;
|
|
|
|
PRINT_DEBUG("new session id = %llu", session_id);
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
SteamAPICall_t Steam_GameStats::EndSession( uint64 ulSessionID, RTime32 rtTimeEnded, int nReasonCode )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("%llu, %u, %i", ulSessionID, rtTimeEnded, nReasonCode);
|
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) {
|
2024-06-14 17:57:04 +03:00
|
|
|
GameStatsSessionClosed_t data_invalid{};
|
|
|
|
data_invalid.m_eResult = EResult::k_EResultInvalidParam;
|
|
|
|
data_invalid.m_ulSessionID = ulSessionID;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("[X] session doesn't exist");
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
callbacks->addCBResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
if (session.ended) {
|
|
|
|
GameStatsSessionClosed_t data_invalid{};
|
|
|
|
data_invalid.m_eResult = EResult::k_EResultExpired; // TODO is this correct?
|
|
|
|
data_invalid.m_ulSessionID = ulSessionID;
|
|
|
|
|
|
|
|
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
|
|
|
|
callbacks->addCBResult(data_invalid.k_iCallback, &data_invalid, sizeof(data_invalid));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
session.ended = true;
|
|
|
|
session.rtTimeEnded = rtTimeEnded;
|
|
|
|
session.nReasonCode = nReasonCode;
|
|
|
|
|
|
|
|
GameStatsSessionClosed_t data{};
|
|
|
|
data.m_eResult = EResult::k_EResultOK;
|
|
|
|
data.m_ulSessionID = ulSessionID;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("ended session");
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddSessionAttributeInt( uint64 ulSessionID, const char* pstrName, int32 nData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'=%i", ulSessionID, pstrName, nData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
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;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddSessionAttributeString( uint64 ulSessionID, const char* pstrName, const char *pstrData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'='%s'", ulSessionID, pstrName, pstrData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
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;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddSessionAttributeFloat( uint64 ulSessionID, const char* pstrName, float fData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'=%f", ulSessionID, pstrName, fData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
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;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddNewRow( uint64 *pulRowID, uint64 ulSessionID, const char *pstrTableName )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%p, %llu, ['%s']", pulRowID, ulSessionID, pstrTableName);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
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);
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::CommitRow( uint64 ulRowID )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("%llu", ulRowID);
|
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto active_session = get_last_active_session();
|
|
|
|
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
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?
|
|
|
|
|
|
|
|
// TODO what if it was already committed ?
|
2024-07-03 01:22:00 +03:00
|
|
|
auto& row = table.rows[static_cast<unsigned>(ulRowID)];
|
2024-06-14 17:57:04 +03:00
|
|
|
row.committed = true;
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("committed successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::CommitOutstandingRows( uint64 ulSessionID )
|
|
|
|
{
|
|
|
|
PRINT_DEBUG("%llu", ulSessionID);
|
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
if (session.ended) return EResult::k_EResultExpired; // TODO is this correct?
|
|
|
|
|
|
|
|
if (session.tables.size()) {
|
|
|
|
for (auto &row : session.tables.back().second.rows) {
|
|
|
|
row.committed = true;
|
|
|
|
}
|
|
|
|
}
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("committed all successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddRowAttributeInt( uint64 ulRowID, const char *pstrName, int32 nData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'=%i", ulRowID, pstrName, nData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
|
|
|
if (!pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto active_session = get_last_active_session();
|
|
|
|
if (!active_session) return EResult::k_EResultFail; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
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?
|
|
|
|
|
|
|
|
auto att = get_or_create_row_att(ulRowID, pstrName, table, AttributeType_t::Int);
|
|
|
|
if (att->type != AttributeType_t::Int) return EResult::k_EResultFail; // TODO is this correct?
|
|
|
|
|
|
|
|
att->n_data = nData;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddRowAtributeString( uint64 ulRowID, const char *pstrName, const char *pstrData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'='%s'", ulRowID, pstrName, pstrData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
|
|
|
if (!pstrName || !pstrData) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
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?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
auto &table = active_session->tables.back().second;
|
|
|
|
if (ulRowID >= table.rows.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
|
|
|
auto att = get_or_create_row_att(ulRowID, pstrName, table, AttributeType_t::Str);
|
|
|
|
if (att->type != AttributeType_t::Str) return EResult::k_EResultFail; // TODO is this correct?
|
|
|
|
|
|
|
|
att->s_data = pstrData;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddRowAttributeFloat( uint64 ulRowID, const char *pstrName, float fData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'=%f", ulRowID, pstrName, fData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
|
|
|
if (!pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
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?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
auto &table = active_session->tables.back().second;
|
|
|
|
if (ulRowID >= table.rows.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
|
|
|
auto att = get_or_create_row_att(ulRowID, pstrName, table, AttributeType_t::Float);
|
|
|
|
if (att->type != AttributeType_t::Float) return EResult::k_EResultFail; // TODO is this correct?
|
|
|
|
|
|
|
|
att->f_data = fData;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddSessionAttributeInt64( uint64 ulSessionID, const char *pstrName, int64 llData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'=%lli", ulSessionID, pstrName, llData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto session_it = sessions.find(ulSessionID);
|
|
|
|
if (sessions.end() == session_it) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
auto& session = session_it->second;
|
2024-06-14 17:57:04 +03:00
|
|
|
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;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
EResult Steam_GameStats::AddRowAttributeInt64( uint64 ulRowID, const char *pstrName, int64 llData )
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("%llu, '%s'=%lli", ulRowID, pstrName, llData);
|
2024-06-14 17:57:04 +03:00
|
|
|
std::lock_guard lock(global_mutex);
|
|
|
|
|
|
|
|
if (!pstrName) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
2024-08-02 23:41:53 +03:00
|
|
|
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?
|
2024-06-14 17:57:04 +03:00
|
|
|
|
|
|
|
auto &table = active_session->tables.back().second;
|
|
|
|
if (ulRowID >= table.rows.size()) return EResult::k_EResultInvalidParam; // TODO is this correct?
|
|
|
|
|
|
|
|
auto att = get_or_create_row_att(ulRowID, pstrName, table, AttributeType_t::Int64);
|
|
|
|
if (att->type != AttributeType_t::Int64) return EResult::k_EResultFail; // TODO is this correct?
|
|
|
|
|
|
|
|
att->ll_data = llData;
|
2024-08-02 23:41:53 +03:00
|
|
|
PRINT_DEBUG("added successfully");
|
2024-06-14 17:57:04 +03:00
|
|
|
return EResult::k_EResultOK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- steam callbacks
|
|
|
|
|
|
|
|
void Steam_GameStats::steam_run_callback()
|
|
|
|
{
|
2024-08-02 23:41:53 +03:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
2024-06-14 17:57:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- networking callbacks
|
|
|
|
|
|
|
|
// user connect/disconnect
|
|
|
|
void Steam_GameStats::network_callback_low_level(Common_Message *msg)
|
|
|
|
{
|
|
|
|
switch (msg->low_level().type())
|
|
|
|
{
|
|
|
|
case Low_Level::CONNECT:
|
|
|
|
// nothing
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Low_Level::DISCONNECT:
|
|
|
|
// nothing
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
PRINT_DEBUG("unknown type %i", (int)msg->low_level().type());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|