- enable using steam statistics to save players network based game end game stats to steam

This commit is contained in:
SoftCoder 2017-10-07 02:40:34 -07:00
parent edfb1508f5
commit b34003b4a5
9 changed files with 368 additions and 77 deletions

View File

@ -27,6 +27,8 @@
#include "video_player.h"
#include "compression_utils.h"
#include "cache_manager.h"
#include "conversion.h"
#include "steam.h"
#include "leak_dumper.h"
@ -5170,6 +5172,68 @@ void Game::DumpCRCWorldLogIfRequired(string fileSuffix) {
}
}
void saveStatsToSteam(Game* game, Stats& endStats) {
if (NetworkManager::getInstance().isNetworkGame()) {
Steam* steamInstance = CacheManager::getCachedItem<Steam*>(GameConstants::steamCacheInstanceKey);
if (steamInstance != NULL) {
printf("\nSTEAM detected, writing out end game stats for player!\n");
//printf("\nSTEAM Refresh Stats!\n");
steamInstance->requestRefreshStats();
for (int factionIndex = 0;
factionIndex < game->getWorld()->getFactionCount();
++factionIndex) {
if (factionIndex == game->getWorld()->getThisFactionIndex()) {
//printf("\nWriting out game stats for Faction Index: %d!\n",factionIndex);
if (endStats.getVictory(factionIndex)) {
steamInstance->setStatAsInt("stat_online_wins",
steamInstance->getStatAsInt("stat_online_wins")
+ 1);
} else {
steamInstance->setStatAsInt("stat_online_loses",
steamInstance->getStatAsInt("stat_online_loses")
+ 1);
}
steamInstance->setStatAsInt("stat_online_kills",
steamInstance->getStatAsInt("stat_online_kills")
+ endStats.getKills(factionIndex));
steamInstance->setStatAsInt("stat_online_kills_enemy",
steamInstance->getStatAsInt(
"stat_online_kills_enemy")
+ endStats.getEnemyKills(factionIndex));
steamInstance->setStatAsInt("stat_online_deaths",
steamInstance->getStatAsInt("stat_online_deaths")
+ endStats.getDeaths(factionIndex));
steamInstance->setStatAsInt("stat_online_units",
steamInstance->getStatAsInt("stat_online_units")
+ endStats.getUnitsProduced(factionIndex));
steamInstance->setStatAsInt(
"stat_online_resources_harvested",
steamInstance->getStatAsInt(
"stat_online_resources_harvested")
+ endStats.getResourcesHarvested(
factionIndex));
if (endStats.getPlayerLeftBeforeEnd(factionIndex)) {
steamInstance->setStatAsInt(
"stat_online_quit_before_end",
steamInstance->getStatAsInt(
"stat_online_quit_before_end") + 1);
}
steamInstance->setStatAsDouble("stat_online_minutes_played",
steamInstance->getStatAsDouble(
"stat_online_minutes_played")
+ getTimeDuationMinutes(
endStats.getFramesToCalculatePlaytime(),
GameConstants::updateFps));
}
}
//printf("\nSTEAM Store Stats!\n");
steamInstance->storeStats();
//printf("\nSTEAM Refresh Stats!\n");
steamInstance->requestRefreshStats();
}
}
}
void Game::exitGameState(Program *program, Stats &endStats) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
@ -5193,6 +5257,8 @@ void Game::exitGameState(Program *program, Stats &endStats) {
printf("-----------------------\n");
}
saveStatsToSteam(game, endStats);
ProgramState *newState = new BattleEnd(program, &endStats, game);
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);

View File

@ -47,7 +47,7 @@ public:
}
static string getString(const T &value) {
static EnumParser<T> parser;
for(enumMapTypeIter iValue = parser.enumMap.first();
for(enumMapTypeIter iValue = parser.enumMap.begin();
iValue != parser.enumMap.end(); ++iValue) {
if(iValue->second == value) {
return iValue->first;
@ -55,6 +55,10 @@ public:
}
throw std::runtime_error("unknown enum lookup [" + intToStr(value) + "]");
}
static int getCount() {
static EnumParser<T> parser;
return parser.enumMap.size();
}
};
// =====================================================
@ -151,6 +155,7 @@ public:
static const char *OBSERVER_SLOTNAME;
static const char *RANDOMFACTION_SLOTNAME;
static const char *steamCacheInstanceKey;
static const char *preCacheThreadCacheLookupKey;
static const char *playerTextureCacheLookupKey;
static const char *ircClientCacheLookupKey;

View File

@ -51,6 +51,7 @@ const char *GameConstants::folder_path_screenshots = "screens/";
const char *GameConstants::OBSERVER_SLOTNAME = "*Observer*";
const char *GameConstants::RANDOMFACTION_SLOTNAME = "*Random*";
const char *GameConstants::steamCacheInstanceKey = "steamInstanceCache";
const char *GameConstants::preCacheThreadCacheLookupKey = "preCacheThreadCache";
const char *GameConstants::ircClientCacheLookupKey = "ircClientCache";
const char *GameConstants::playerTextureCacheLookupKey = "playerTextureCache";

View File

@ -138,6 +138,8 @@ static string runtimeErrorMsg = "";
auto_ptr<google_breakpad::ExceptionHandler> errorHandlerPtr;
#endif
//auto_ptr<Steam> steamInstance;
class NavtiveLanguageNameListCacheGenerator : public SimpleTaskCallbackInterface {
virtual void simpleTask(BaseThread *callingThread,void *userdata) {
Lang &lang = Lang::getInstance();
@ -145,34 +147,6 @@ class NavtiveLanguageNameListCacheGenerator : public SimpleTaskCallbackInterface
}
};
/*
static void printEvent(const STEAMSHIM_Event *e)
{
if (!e) return;
printf("CHILD EVENT: ");
switch (e->type)
{
#define PRINTGOTEVENT(x) case SHIMEVENT_##x: printf("%s(", #x); break
PRINTGOTEVENT(BYE);
PRINTGOTEVENT(STATSRECEIVED);
PRINTGOTEVENT(STATSSTORED);
PRINTGOTEVENT(SETACHIEVEMENT);
PRINTGOTEVENT(GETACHIEVEMENT);
PRINTGOTEVENT(RESETSTATS);
PRINTGOTEVENT(SETSTATI);
PRINTGOTEVENT(GETSTATI);
PRINTGOTEVENT(SETSTATF);
PRINTGOTEVENT(GETSTATF);
#undef PRINTGOTEVENT
default: printf("UNKNOWN("); break;
}
printf("%sokay, ival=%d, fval=%f, time=%llu, name='%s').\n",
e->okay ? "" : "!", e->ivalue, e->fvalue, e->epochsecs, e->name);
}
*/
// =====================================================
// class ExceptionHandler
// =====================================================
@ -3326,15 +3300,31 @@ void ShowINISettings(int argc, char **argv,Config &config,Config &configKeys) {
}
}
Steam & initSteamInstance() {
Steam *&steamInstance = CacheManager::getCachedItem< Steam *>(GameConstants::steamCacheInstanceKey);
if(steamInstance == NULL) {
// Steam &cacheInstance = CacheManager::getCachedItem< Steam * >(GameConstants::steamCacheInstanceKey);
// steamInstance.reset(&cacheInstance);
// //CacheManager::setCachedItem< Steam * >(GameConstants::steamCacheInstanceKey, steamInstance.get());
//
// cacheInstance = steamInstance.get();
steamInstance = new Steam();
}
// return *steamInstance.get();
return *steamInstance;
}
void setupSteamSettings(bool steamEnabled) {
bool needToSaveConfig=false;
Config &config = Config::getInstance();
config.setBool("SteamEnabled",steamEnabled,true);
if(steamEnabled) {
printf("*NOTE: Steam Integration Enabled.\n");
//string steamPlayerName = safeCharPtrCopy(getenv("SteamAppUser"),100);
//if( steamPlayerName=="") return;// not a steam launch
Steam steam;
Steam &steam = initSteamInstance();
// For Debugging purposes:
//steam.resetStats(false);
string steamPlayerName = steam.userName();
string steamLang = steam.lang();
printf("Steam Integration Enabled!\nSteam User Name is [%s] Language is [%s]\n", steamPlayerName.c_str(), steamLang.c_str());
@ -4240,18 +4230,6 @@ int glestMain(int argc, char** argv) {
return 2;
}
// if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_STEAM]) == true) {
// STEAMSHIM_requestStats();
// while (STEAMSHIM_alive()) {
// const STEAMSHIM_Event *e = STEAMSHIM_pump();
// printEvent(e);
// if (e && e->type == SHIMEVENT_STATSRECEIVED) {
// break;
// }
// usleep(100 * 1000);
// } // while
// }
if( hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE])) == true) {
//isMasterServerModeEnabled = true;
//Window::setMasterserverMode(isMasterServerModeEnabled);
@ -5037,7 +5015,7 @@ int glestMain(int argc, char** argv) {
else {
if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_STEAM]) == true) {
Steam steam;
Steam &steam = initSteamInstance();
string steamUser = steam.userName();
string steamLang = steam.lang();
printf("Steam Integration Enabled!\nSteam User Name is [%s] Language is [%s]\n", steamUser.c_str(), steamLang.c_str());
@ -6141,6 +6119,7 @@ int glestMainWrapper(int argc, char** argv) {
int result = glestMainSEHWrapper(argc, argv);
if (isSteamMode == true) {
//steamInstance.reset(NULL);
STEAMSHIM_deinit();
}

View File

@ -25,6 +25,7 @@
#include "network_message.h"
#include "socket.h"
#include "auto_test.h"
#include "cache_manager.h"
#include "steam.h"
#include <stdio.h>
@ -80,10 +81,10 @@ MenuStateRoot::MenuStateRoot(Program *program, MainMenu *mainMenu) :
labelGreeting.init(labelVersion.getX(), labelVersion.getY()-16);
labelGreeting.setText("");
Config &config = Config::getInstance();
if(config.getBool("SteamEnabled")) {
Steam steam;
string steamPlayerName = steam.userName();
Steam *steamInstance = CacheManager::getCachedItem< Steam *>(GameConstants::steamCacheInstanceKey);
if(steamInstance != NULL) {
string steamPlayerName = steamInstance->userName();
labelGreeting.setText("Welcome Steam Player: " + steamPlayerName);
}

View File

@ -3,14 +3,19 @@
#include <map>
#include <SDL.h>
#include "steamshim_child.h"
#include "platform_common.h"
/* Achievements */
namespace Glest{ namespace Game{
std::map<std::string,SteamStatType> Steam::SteamStatNameTypes = Steam::create_map();
// Achievements
//static const char *const achievementNames[] = {
// "X",
//};
//#define NUM_ACHIEVEMENTS (sizeof(achievementNames) / sizeof(achievementNames[0]))
/* Language map */
// Language map
static inline std::map<std::string, std::string> gen_langToCode()
{
std::map<std::string, std::string> map;
@ -45,31 +50,51 @@ static inline std::map<std::string, std::string> gen_langToCode()
}
static const std::map<std::string, std::string> langToCode = gen_langToCode();
static std::string steamToIsoLang(const char *steamLang)
{
static std::string steamToIsoLang(const char *steamLang) {
//printf("Steam language [%s]\n",steamLang);
std::map<std::string, std::string>::const_iterator it = langToCode.find(steamLang);
if (it != langToCode.end())
if (it != langToCode.end()) {
return it->second;
}
return "en";
}
/* SteamPrivate */
struct SteamPrivate
{
// SteamPrivate
struct SteamPrivate {
//std::map<std::string, bool> achievements;
std::map<std::string, double> stats;
std::string userName;
std::string lang;
SteamPrivate()
{
SteamPrivate() {
//printf("\ncreating private steam state container\n");
STEAMSHIM_getPersonaName();
STEAMSHIM_getCurrentGameLanguage();
STEAMSHIM_requestStats();
// for (size_t i = 0; i < NUM_ACHIEVEMENTS; ++i)
// STEAMSHIM_getAchievement(achievementNames[i]);
while (!initialized())
{
for(int index = 0; index < EnumParser<SteamStatName>::getCount(); ++index) {
SteamStatName statName = static_cast<SteamStatName>(index);
string statNameStr = EnumParser<SteamStatName>::getString(statName);
SteamStatType statType = Steam::getSteamStatNameType(statNameStr);
switch(statType) {
case stat_int:
STEAMSHIM_getStatI(statNameStr.c_str());
break;
case stat_float:
STEAMSHIM_getStatF(statNameStr.c_str());
break;
default:
break;
}
}
Shared::PlatformCommon::Chrono timer;
timer.start();
while(!initialized() && timer.getMillis() < 2500) {
SDL_Delay(100);
update();
}
@ -92,11 +117,40 @@ struct SteamPrivate
// return achievements[name];
// }
void update()
{
void updateStat(const char *name, double value) {
stats[name] = value;
}
int getStatAsInt(const char *name) const {
std::map<std::string, double>::const_iterator iterFind = stats.find(name);
if(iterFind != stats.end()) {
return iterFind->second;
}
return 0;
}
double getStatAsDouble(const char *name) const {
std::map<std::string, double>::const_iterator iterFind = stats.find(name);
if(iterFind != stats.end()) {
return iterFind->second;
}
return 0;
}
void setStatAsInt(const char *name, int value) {
STEAMSHIM_setStatI(name, value);
update();
}
void setStatAsFloat(const char *name, float value) {
STEAMSHIM_setStatF(name, value);
update();
}
void clearLocalStats() {
stats.clear();
}
const STEAMSHIM_Event * update(STEAMSHIM_EventType *waitForEvent=NULL) {
const STEAMSHIM_Event *e;
while ((e = STEAMSHIM_pump()) != 0)
{
while ((e = STEAMSHIM_pump()) != 0) {
/* Handle events */
switch (e->type)
{
@ -104,45 +158,146 @@ struct SteamPrivate
// updateAchievement(e->name, e->ivalue);
// break;
case SHIMEVENT_GETPERSONANAME:
//printf("\nGot Shim event SHIMEVENT_GETPERSONANAME isOk = %d\n",e->okay);
userName = e->name;
break;
case SHIMEVENT_GETCURRENTGAMELANGUAGE:
//printf("\nGot Shim event SHIMEVENT_GETCURRENTGAMELANGUAGE isOk = %d\n",e->okay);
lang = steamToIsoLang(e->name);
break;
case SHIMEVENT_STATSRECEIVED:
//printf("\nGot Shim event SHIMEVENT_STATSRECEIVED isOk = %d\n",e->okay);
break;
case SHIMEVENT_STATSSTORED:
//printf("\nGot Shim event SHIMEVENT_STATSSTORED isOk = %d\n",e->okay);
break;
//case SHIMEVENT_SETSTATI:
case SHIMEVENT_GETSTATI:
//printf("\nGot Shim event SHIMEVENT_GETSTATI for stat [%s] value [%d] isOk = %d\n",e->name,e->ivalue,e->okay);
if(e->okay) {
updateStat(e->name, e->ivalue);
}
break;
case SHIMEVENT_GETSTATF:
//printf("\nGot Shim event SHIMEVENT_GETSTATF for stat [%s] value [%f] isOk = %d\n",e->name,e->fvalue,e->okay);
if(e->okay) {
updateStat(e->name, e->fvalue);
}
break;
case SHIMEVENT_SETSTATI:
//printf("\nGot Shim event SHIMEVENT_SETSTATI for stat [%s] value [%d] isOk = %d\n",e->name,e->ivalue,e->okay);
break;
case SHIMEVENT_SETSTATF:
//printf("\nGot Shim event SHIMEVENT_SETSTATF for stat [%s] value [%f] isOk = %d\n",e->name,e->fvalue,e->okay);
break;
default:
//printf("\nGot Shim event [%d] isOk = %d\n",e->type,e->okay);
break;
}
if(waitForEvent != NULL && *waitForEvent == e->type) {
return e;
}
}
return NULL;
}
bool initialized()
{
bool initialized() {
return !userName.empty()
&& !lang.empty();
&& !lang.empty()
&& (int)stats.size() >= EnumParser<SteamStatName>::getCount();
//&& achievements.size() == NUM_ACHIEVEMENTS;
}
};
/* Steam */
Steam::Steam()
: p(new SteamPrivate())
{
Steam::Steam() : p(new SteamPrivate()) {
}
Steam::~Steam()
{
Steam::~Steam() {
delete p;
}
const std::string &Steam::userName() const
{
const std::string &Steam::userName() const {
return p->userName;
}
const std::string &Steam::lang() const
{
const std::string &Steam::lang() const {
return p->lang;
}
void Steam::resetStats(const int bAlsoAchievements) const {
STEAMSHIM_resetStats(false);
p->update();
}
void Steam::storeStats() const {
STEAMSHIM_storeStats();
STEAMSHIM_EventType statsStored = SHIMEVENT_STATSSTORED;
Shared::PlatformCommon::Chrono timer;
timer.start();
while(timer.getMillis() < 2500) {
SDL_Delay(100);
const STEAMSHIM_Event *evt = p->update(&statsStored);
if(evt != NULL && evt->type == statsStored) {
break;
}
}
}
int Steam::getStatAsInt(const char *name) const {
return p->getStatAsInt(name);
}
double Steam::getStatAsDouble(const char *name) const {
return p->getStatAsDouble(name);
}
void Steam::setStatAsInt(const char *name, int value) {
p->setStatAsInt(name, value);
}
void Steam::setStatAsDouble(const char *name, double value) {
p->setStatAsFloat(name, value);
}
void Steam::requestRefreshStats() {
p->clearLocalStats();
STEAMSHIM_requestStats();
STEAMSHIM_EventType statsReceived = SHIMEVENT_STATSRECEIVED;
p->update(&statsReceived);
for(int index = 0; index < EnumParser<SteamStatName>::getCount(); ++index) {
SteamStatName statName = static_cast<SteamStatName>(index);
string statNameStr = EnumParser<SteamStatName>::getString(statName);
SteamStatType statType = Steam::getSteamStatNameType(statNameStr);
switch(statType) {
case stat_int:
STEAMSHIM_getStatI(statNameStr.c_str());
break;
case stat_float:
STEAMSHIM_getStatF(statNameStr.c_str());
break;
default:
break;
}
}
Shared::PlatformCommon::Chrono timer;
timer.start();
while(!p->initialized() && timer.getMillis() < 2500) {
SDL_Delay(100);
p->update();
}
}
SteamStatType Steam::getSteamStatNameType(string value) {
return SteamStatNameTypes[value];
}
//void Steam::unlock(const char *name)
//{
// p->setAchievement(name, true);
@ -157,3 +312,6 @@ const std::string &Steam::lang() const
//{
// return p->isAchievementSet(name);
//}
}}//end namespace

View File

@ -2,9 +2,46 @@
#define STEAM_H
#include <string>
#include <map>
#include "game_constants.h"
namespace Glest{ namespace Game{
struct SteamPrivate;
enum SteamStatName {
stat_online_wins,
stat_online_loses,
stat_online_kills,
stat_online_kills_enemy,
stat_online_deaths,
stat_online_units,
stat_online_resources_harvested,
stat_online_quit_before_end,
stat_online_minutes_played
};
enum SteamStatType {
stat_int,
stat_float,
stat_avg
};
template <>
inline EnumParser<SteamStatName>::EnumParser() {
enumMap["stat_online_wins"] = stat_online_wins;
enumMap["stat_online_loses"] = stat_online_loses;
enumMap["stat_online_kills"] = stat_online_kills;
enumMap["stat_online_kills_enemy"] = stat_online_kills_enemy;
enumMap["stat_online_deaths"] = stat_online_deaths;
enumMap["stat_online_units"] = stat_online_units;
enumMap["stat_online_resources_harvested"] = stat_online_resources_harvested;
enumMap["stat_online_quit_before_end"] = stat_online_quit_before_end;
enumMap["stat_online_minutes_played"] = stat_online_minutes_played;
}
class Steam
{
public:
@ -12,9 +49,20 @@ public:
// void lock(const char *name);
// bool isUnlocked(const char *name);
static SteamStatType getSteamStatNameType(string value);
const std::string &userName() const;
const std::string &lang() const;
void resetStats(const int bAlsoAchievements) const;
void storeStats() const;
int getStatAsInt(const char *name) const;
double getStatAsDouble(const char *name) const;
void setStatAsInt(const char *name, int value);
void setStatAsDouble(const char *name, double value);
void requestRefreshStats();
Steam();
~Steam();
@ -22,6 +70,23 @@ private:
//friend struct SharedStatePrivate;
SteamPrivate *p;
static std::map<std::string,SteamStatType> SteamStatNameTypes;
static std::map<std::string,SteamStatType> create_map() {
std::map<std::string,SteamStatType> steamStatNameTypes;
steamStatNameTypes["stat_online_wins"] = stat_int;
steamStatNameTypes["stat_online_loses"] = stat_int;
steamStatNameTypes["stat_online_kills"] = stat_int;
steamStatNameTypes["stat_online_kills_enemy"] = stat_int;
steamStatNameTypes["stat_online_deaths"] = stat_int;
steamStatNameTypes["stat_online_units"] = stat_int;
steamStatNameTypes["stat_online_resources_harvested"] = stat_int;
steamStatNameTypes["stat_online_quit_before_end"] = stat_int;
steamStatNameTypes["stat_online_minutes_played"] = stat_float;
return steamStatNameTypes;
}
};
}}//end namespace
#endif // STEAM_H

View File

@ -43,6 +43,7 @@ bool IsNumeric(const char *p, bool allowNegative=true);
string formatNumber(uint64 f);
double getTimeDuationMinutes(int frames, int updateFps);
string getTimeDuationString(int frames, int updateFps);
}}//end namespace

View File

@ -215,6 +215,21 @@ string formatNumber(uint64 f) {
return out.str();
}
double getTimeDuationMinutes(int frames, int updateFps) {
int framesleft = frames;
double hours = (int)((int) frames / (float)updateFps / 3600.0f);
framesleft = framesleft - hours * 3600 * updateFps;
double minutes = (int)((int) framesleft / (float)updateFps / 60.0f);
framesleft = framesleft - minutes * 60 * updateFps;
double seconds = (int)((int) framesleft / (float)updateFps);
double result = (hours * 60.0) + minutes;
if(seconds > 0) {
result += seconds / 60.0;
}
return result;
}
string getTimeDuationString(int frames, int updateFps) {
int framesleft = frames;
int hours = (int)((int) frames / (float)updateFps / 3600.0f);