Skip to content

Commit 1a0c1c5

Browse files
committed
create and store context for the level event
1 parent 6c3d93a commit 1a0c1c5

File tree

9 files changed

+274
-51
lines changed

9 files changed

+274
-51
lines changed

include/GameAnalytics/GameAnalytics.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,18 @@ namespace gameanalytics
7777

7878
static void addErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& customFields = "", bool mergeFields = false);
7979

80-
static void addLevelEvent(EGALevelStatus status, int levelId, std::string const& levelName, int value = 0, std::string const& customFields);
80+
/// level event
81+
82+
static bool isLevelCurrentlyTracked();
83+
84+
static void addLevelStartEvent(int levelId, std::string const& levelName, int value = 0, std::string const& customFields = "");
85+
static void addLevelAbortEvent(int value = 0, std::string const& customFields = "");
86+
static void addLevelFailureEvent(int value = 0, std::string const& customFields = "");
87+
static void addLevelCompleteEvent(int value = 0, std::string const& customFields = "");
88+
89+
static void addLevelEvent(EGALevelStatus status, int levelId, std::string const& levelName, int value = 0, std::string const& customFields = "");
90+
91+
//////////////////////
8192

8293
// set calls can be changed at any time (pre- and post-initialize)
8394
// some calls only work after a configure is called (setCustomDimension)

source/gameanalytics/GAEvents.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -482,11 +482,7 @@ namespace gameanalytics
482482
return;
483483
}
484484

485-
if(!state::GAState::getInstance().updateLevelContext(status, id, name))
486-
{
487-
logging::GALogger::e("Invalid level");
488-
return;
489-
}
485+
state::GAState& state = state::GAState::getInstance();
490486

491487
// Validate
492488
validators::ValidationResult validationResult = validators::GAValidator::validateLevelEvent(status, id, name);
@@ -499,12 +495,18 @@ namespace gameanalytics
499495

500496
// Create empty eventData
501497
json eventData;
498+
502499
eventData["category"] = GAEvents::CategoryLevel;
503500
eventData["status"] = levelStatusString(status);
504-
eventData["level_id"] = id;
505-
eventData["level_name"] = name;
506501
eventData["value"] = value;
507502

503+
if (status == EGALevelStatus::Start)
504+
{
505+
eventData["level_id"] = id;
506+
eventData["level_name"] = name;
507+
eventData["level_time"] = 0;
508+
}
509+
508510
json cleanedFields = state::GAState::getValidatedCustomFields(fields);
509511
getInstance().addCustomFieldsToEvent(eventData, cleanedFields);
510512

@@ -516,6 +518,12 @@ namespace gameanalytics
516518

517519
// Send to store
518520
getInstance().addEventToStore(eventData);
521+
522+
if (!state.updateLevelContext(status, id, name))
523+
{
524+
logging::GALogger::e("Failed to update the level context with status:", levelStatusString(status));
525+
return;
526+
}
519527
}
520528
catch(std::exception& e)
521529
{
@@ -925,6 +933,23 @@ namespace gameanalytics
925933
}
926934
}
927935

936+
std::string GAEvents::levelStatusString(EGALevelStatus lvlStatus)
937+
{
938+
switch (lvlStatus)
939+
{
940+
case EGALevelStatus::Start:
941+
return "start";
942+
case EGALevelStatus::Abort:
943+
return "abort";
944+
case EGALevelStatus::Complete:
945+
return "complete";
946+
case EGALevelStatus::Failure:
947+
return "failure";
948+
default:
949+
return "";
950+
}
951+
}
952+
928953
void GAEvents::addSDKInitEvent()
929954
{
930955
try

source/gameanalytics/GALogger.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ namespace gameanalytics
2626
return;
2727
}
2828

29-
std::string tag = getInstance().tag;
29+
std::string tag = getInstance().TAG;
3030
tag += " :";
3131

3232
switch (logType)

source/gameanalytics/GAState.cpp

Lines changed: 141 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

source/gameanalytics/GAState.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ namespace gameanalytics
148148
static json getValidatedCustomFields(const json& withEventFields);
149149

150150
int64_t calculateSessionLength() const;
151+
bool isLevelTracked() const;
151152

152153
private:
153154

@@ -157,12 +158,23 @@ namespace gameanalytics
157158

158159
int32_t levelId{INVALID_LVL};
159160
std::string levelName;
160-
utilities::Stopwatch timer;
161161

162-
inline bool IsInLevel() const { return levelId != INVALID_LVL; }
162+
inline bool isInLevel() const { return levelId != INVALID_LVL; }
163+
164+
bool startLevel(int32_t id, std::string const& name);
165+
bool endLevel();
166+
167+
bool resumeLevel(int32_t id, std::string const& name, int64_t timeElapsed = 0);
168+
bool resumeLevel();
169+
bool pauseLevel();
170+
171+
int64_t getLevelTime() const;
163172

164-
bool StartLevel(int32_t id, std::string const& name);
165-
bool EndLevel();
173+
private:
174+
175+
utilities::Stopwatch timer;
176+
int64_t cachedTime = 0;
177+
bool wasContextResumed = false;
166178
};
167179

168180
GAState();
@@ -201,6 +213,11 @@ namespace gameanalytics
201213

202214
bool updateLevelContext(EGALevelStatus status, int levelId, std::string const& levelName);
203215

216+
bool cacheLevelContext();
217+
bool restoreLevelContext(json& stateDict);
218+
bool checkCachedLevelContext(json& stateDict);
219+
void resetCachedLevelContext();
220+
204221
threading::GAThreading _gaThread;
205222
events::GAEvents _gaEvents;
206223
device::GADevice _gaDevice;

0 commit comments

Comments
 (0)