@@ -27,35 +27,90 @@ namespace gameanalytics
2727
2828 namespace state
2929 {
30- bool GAState::LevelContext::StartLevel (int32_t id, std::string const & name)
30+ bool GAState::LevelContext::startLevel (int32_t id, std::string const & name)
3131 {
32- if (!IsInLevel () && id > 0 )
32+ if (!isInLevel () && id > INVALID_LVL )
3333 {
34+ logging::GALogger::d (" Starting level %d with name %s" , id, name.c_str ());
35+
3436 levelId = id;
3537 levelName = name;
3638
3739 timer.reset ();
3840 timer.start ();
3941
42+ cachedTime = 0 ;
43+ wasContextResumed = false ;
44+
4045 return true ;
4146 }
4247
4348 return false ;
4449 }
4550
46- bool GAState::LevelContext::EndLevel ()
51+ bool GAState::LevelContext::endLevel ()
4752 {
48- if (IsInLevel ())
53+ if (isInLevel ())
4954 {
55+ logging::GALogger::d (" Ending level %d with name %s, total duration of %I64d seconds" , levelId, levelName.c_str (), getLevelTime ());
56+
5057 levelId = INVALID_LVL;
5158 levelName = " " ;
59+ cachedTime = 0 ;
60+ wasContextResumed = false ;
61+
62+ return true ;
63+ }
64+
65+ return false ;
66+ }
67+
68+ bool GAState::LevelContext::resumeLevel (int32_t id, std::string const & name, int64_t timeElapsed)
69+ {
70+ if (startLevel (id, name))
71+ {
72+ logging::GALogger::d (" Resumed cached level %d with name %s, total duration of %I64d seconds" , levelId, levelName.c_str (), timeElapsed);
73+
74+ cachedTime = timeElapsed;
75+ wasContextResumed = true ;
76+
77+ return true ;
78+ }
79+
80+ return false ;
81+ }
5282
83+ bool GAState::LevelContext::resumeLevel ()
84+ {
85+ if (isInLevel ())
86+ {
87+ logging::GALogger::d (" Resuming level %d with name %s, total duration of %I64d seconds" , levelId, levelName.c_str (), getLevelTime ());
88+
89+ timer.start ();
5390 return true ;
5491 }
5592
5693 return false ;
5794 }
5895
96+ bool GAState::LevelContext::pauseLevel ()
97+ {
98+ if (isInLevel ())
99+ {
100+ logging::GALogger::d (" Paused level %d with name %s, total duration of %I64d seconds" , levelId, levelName.c_str (), getLevelTime ());
101+
102+ timer.stop ();
103+ return true ;
104+ }
105+
106+ return false ;
107+ }
108+
109+ int64_t GAState::LevelContext::getLevelTime () const
110+ {
111+ return timer.getSeconds () + cachedTime;
112+ }
113+
59114 GAState& GAState::getInstance ()
60115 {
61116 static GAState instance;
@@ -416,6 +471,11 @@ namespace gameanalytics
416471 events::GAEvents::addHealthEvent ();
417472 events::GAEvents::addSessionEndEvent ();
418473 getInstance ()._sessionStart = 0 ;
474+
475+ if (getInstance ()._levelContext .isInLevel ())
476+ {
477+ getInstance ().cacheLevelContext ();
478+ }
419479 }
420480 events::GAEvents::stopEventQueue ();
421481 }
@@ -458,10 +518,11 @@ namespace gameanalytics
458518 // ---- OPTIONAL ---- //
459519
460520 // level
461- if (getInstance ()._levelContext .IsInLevel ())
521+ if (getInstance ()._levelContext .isInLevel ())
462522 {
463523 out[" level_name" ] = getInstance ()._levelContext .levelName ;
464524 out[" level_id" ] = getInstance ()._levelContext .levelId ;
525+ out[" level_time" ] = getInstance ()._levelContext .getLevelTime ();
465526 }
466527
467528 // A/B testing
@@ -668,6 +729,12 @@ namespace gameanalytics
668729 }
669730 }
670731 }
732+
733+ if (checkCachedLevelContext (state_dict))
734+ {
735+ logging::GALogger::d (" Found active level attempt." );
736+ restoreLevelContext (state_dict);
737+ }
671738 }
672739 catch (json::exception& e)
673740 {
@@ -835,7 +902,7 @@ namespace gameanalytics
835902 // Set session start
836903 _sessionStart = getClientTsAdjusted ();
837904
838- // to acurrately measure time
905+ // to accurately measure time
839906 _startTimepoint = std::chrono::high_resolution_clock::now ();
840907
841908 // Add session start event
@@ -898,6 +965,11 @@ namespace gameanalytics
898965 return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::high_resolution_clock::now () - _startTimepoint).count ();
899966 }
900967
968+ bool GAState::isLevelTracked () const
969+ {
970+ return _levelContext.isInLevel ();
971+ }
972+
901973 void GAState::addRemoteConfigsListener (const std::shared_ptr<IRemoteConfigsListener>& listener)
902974 {
903975 if (std::find (getInstance ()._remoteConfigsListeners .begin (), getInstance ()._remoteConfigsListeners .end (), listener) == getInstance ()._remoteConfigsListeners .end ())
@@ -1176,27 +1248,85 @@ namespace gameanalytics
11761248 {
11771249 case EGALevelStatus::Start:
11781250 {
1179- if (_levelContext.IsInLevel ())
1251+ if (_levelContext.isInLevel ())
11801252 {
1181-
1253+ logging::GALogger::w (" A level is already active. Please call a level abort/failure/complete first!" );
1254+ return false ;
11821255 }
11831256
1184- return _levelContext.StartLevel (id, levelName);
1257+ return _levelContext.startLevel (id, levelName);
11851258 }
11861259
11871260 case EGALevelStatus::Failure:
11881261 case EGALevelStatus::Complete:
11891262 case EGALevelStatus::Abort:
11901263 {
1191- if (!_levelContext.IsInLevel ())
1264+ if (!_levelContext.isInLevel ())
11921265 {
11931266 logging::GALogger::w (" No active level found. A level start event must be called before Failure/Complete/Abort events!" );
11941267 return false ;
11951268 }
11961269
1197- return _levelContext.EndLevel ();
1270+ if (_levelContext.endLevel ())
1271+ {
1272+ resetCachedLevelContext ();
1273+ return true ;
1274+ }
1275+ }
1276+ }
1277+ }
1278+
1279+ bool GAState::cacheLevelContext ()
1280+ {
1281+ if (_levelContext.isInLevel ())
1282+ {
1283+ logging::GALogger::d (" Level is active. Caching level context." );
1284+
1285+ _gaStore.setState (" level_id" , std::to_string (_levelContext.levelId ));
1286+ _gaStore.setState (" level_name" , _levelContext.levelName );
1287+ _gaStore.setState (" level_time" , std::to_string (_levelContext.getLevelTime ()));
1288+
1289+ return true ;
1290+ }
1291+
1292+ return false ;
1293+ }
1294+
1295+ void GAState::resetCachedLevelContext ()
1296+ {
1297+ // clear level context state
1298+ _gaStore.setState (" level_id" , " -1" );
1299+ _gaStore.setState (" level_name" , " " );
1300+ _gaStore.setState (" level_time" , " 0" );
1301+ }
1302+
1303+ bool GAState::restoreLevelContext (json& stateDict)
1304+ {
1305+ if (!_levelContext.isInLevel ())
1306+ {
1307+ int32_t levelId = utilities::getNumberFromCache (stateDict, " level_id" , LevelContext::INVALID_LVL);
1308+ int64_t levelTime = utilities::getNumberFromCache (stateDict, " level_time" , 0 );
1309+ std::string levelName = utilities::getOptionalValue<std::string>(stateDict, " level_name" , " " );
1310+
1311+ if (levelId > LevelContext::INVALID_LVL)
1312+ {
1313+ logging::GALogger::d (" Restoring level context from local cache." );
1314+
1315+ _levelContext.resumeLevel (levelId, levelName, levelTime);
1316+
1317+ resetCachedLevelContext ();
1318+
1319+ return true ;
11981320 }
11991321 }
1322+
1323+ return false ;
1324+ }
1325+
1326+ bool GAState::checkCachedLevelContext (json& stateDict)
1327+ {
1328+ int32_t levelId = utilities::getNumberFromCache (stateDict, " level_id" , LevelContext::INVALID_LVL);
1329+ return levelId > LevelContext::INVALID_LVL;
12001330 }
12011331 }
12021332}
0 commit comments