├── .gitignore ├── img └── blueprint.png ├── .gitattributes ├── GameAnalytics ├── .DS_Store ├── Source │ ├── .DS_Store │ ├── ThirdParty │ │ ├── .DS_Store │ │ ├── GA-SDK-CPP │ │ │ ├── .DS_Store │ │ │ └── lib │ │ │ │ ├── .DS_Store │ │ │ │ ├── Mac │ │ │ │ └── libGameAnalytics.a │ │ │ │ ├── Win64 │ │ │ │ └── GameAnalytics.lib │ │ │ │ └── Linux-clang │ │ │ │ └── libGameAnalytics.a │ │ └── lib │ │ │ ├── ios │ │ │ └── libGameAnalytics.a │ │ │ └── html5 │ │ │ └── GameAnalyticsUnreal.js │ ├── GameAnalytics │ │ ├── .DS_Store │ │ ├── Private │ │ │ ├── .DS_Store │ │ │ ├── GameAnalyticsPerformance.h │ │ │ ├── GameAnalyticsPerformance.cpp │ │ │ ├── GameAnalyticsProvider.h │ │ │ ├── Desktop │ │ │ │ ├── GAWrapperCpp.h │ │ │ │ └── GAWrapperCpp.cpp │ │ │ ├── IOS │ │ │ │ ├── GAWrapperIOS.h │ │ │ │ └── GAWrapperIOS.mm │ │ │ ├── Android │ │ │ │ └── GAWrapperAndroid.h │ │ │ ├── GameAnalyticsModule.cpp │ │ │ ├── GameAnalyticsProvider.cpp │ │ │ └── GameAnalytics.cpp │ │ ├── GA-SDK-IOS │ │ │ └── PrivacyInfo.xcprivacy │ │ ├── GA-SDK-ANDROID │ │ │ └── lib │ │ │ │ ├── gameanalytics.aar │ │ │ │ └── gameanalytics.jar │ │ ├── GameAnalytics_iOS_UPL.xml │ │ ├── Public │ │ │ ├── GAEnums.h │ │ │ ├── GameAnalyticsModule.h │ │ │ ├── GAWrapper.h │ │ │ └── GameAnalytics.h │ │ ├── GameAnalytics_APL.xml │ │ ├── GA-SDK-CPP │ │ │ └── GameAnalytics │ │ │ │ ├── GATypes.h │ │ │ │ └── GameAnalytics.h │ │ ├── GA-SDK-HTML5 │ │ │ └── GameAnalytics.h │ │ └── GameAnalytics.Build.cs │ └── GameAnalyticsEditor │ │ ├── Private │ │ ├── GameAnalyticsProjectSettings.cpp │ │ ├── GameAnalyticsEditor.cpp │ │ └── GameAnalyticsTargetSettingsCustomization.h │ │ ├── Public │ │ ├── GameAnalyticsEditor.h │ │ └── GameAnalyticsProjectSettings.h │ │ └── GameAnalyticsEditor.Build.cs ├── Resources │ └── Icon128.png ├── Config │ └── FilterPlugin.ini ├── GameAnalytics.uplugin └── README.md ├── LICENSE ├── README.md └── CHANGELOG.md /.gitignore: -------------------------------------------------------------------------------- 1 | GameAnalytics/Binaries/* 2 | GameAnalytics/Intermediate/* 3 | -------------------------------------------------------------------------------- /img/blueprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/img/blueprint.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.a filter=lfs diff=lfs merge=lfs -text 2 | *.lib filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /GameAnalytics/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Source/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Resources/Icon128.png -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/ThirdParty/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/GameAnalytics/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/GameAnalytics/Private/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/GA-SDK-CPP/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/ThirdParty/GA-SDK-CPP/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/GA-SDK-CPP/lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/ThirdParty/GA-SDK-CPP/lib/.DS_Store -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GA-SDK-IOS/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/GameAnalytics/GA-SDK-IOS/PrivacyInfo.xcprivacy -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/lib/ios/libGameAnalytics.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:09907239f51c5e728919d50d2f75fa1d644ec47fc727552a746da1b77ee3a0f4 3 | size 4040752 4 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GA-SDK-ANDROID/lib/gameanalytics.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/GameAnalytics/GA-SDK-ANDROID/lib/gameanalytics.aar -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GA-SDK-ANDROID/lib/gameanalytics.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GameAnalytics/GA-SDK-UNREAL/HEAD/GameAnalytics/Source/GameAnalytics/GA-SDK-ANDROID/lib/gameanalytics.jar -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/GA-SDK-CPP/lib/Mac/libGameAnalytics.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:15b3522bc253e1da0f531932983d9f28ca73ce272019b6faf9b6cc5129a4036c 3 | size 6423952 4 | -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/GA-SDK-CPP/lib/Win64/GameAnalytics.lib: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:160f42d1c2dc6c1eb7f74e90711426f990b4985f2dcd7bead68b8529121ae1af 3 | size 11347588 4 | -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/GA-SDK-CPP/lib/Linux-clang/libGameAnalytics.a: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2f8a5519771c4e41f50c57899dc66e949d367cedc67acf37920749cf1edb8716 3 | size 4397192 4 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GameAnalytics_iOS_UPL.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalyticsEditor/Private/GameAnalyticsProjectSettings.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "GameAnalyticsProjectSettings.h" 4 | #include "GameAnalyticsEditor.h" 5 | 6 | 7 | UGameAnalyticsProjectSettings::UGameAnalyticsProjectSettings( const FObjectInitializer& ObjectInitializer ) 8 | : Super( ObjectInitializer ) 9 | { 10 | } -------------------------------------------------------------------------------- /GameAnalytics/Config/FilterPlugin.ini: -------------------------------------------------------------------------------- 1 | [FilterPlugin] 2 | ; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and 3 | ; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. 4 | ; 5 | ; Examples: 6 | ; /README.txt 7 | ; /Extras/... 8 | ; /Binaries/ThirdParty/*.dll 9 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalyticsEditor/Public/GameAnalyticsEditor.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "Modules/ModuleManager.h" 6 | 7 | /** 8 | * The public interface to this module 9 | */ 10 | class FGameAnalyticsEditor : public IModuleInterface 11 | { 12 | /*public: 13 | 14 | static inline FGameAnalyticsEditor& Get() 15 | { 16 | return FModuleManager::LoadModuleChecked< FGameAnalyticsEditor >("GameAnalyticsEditor"); 17 | }*/ 18 | 19 | public: 20 | /** IModuleInterface implementation */ 21 | void StartupModule(); 22 | void ShutdownModule(); 23 | }; 24 | -------------------------------------------------------------------------------- /GameAnalytics/GameAnalytics.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion" : 3, 3 | 4 | "FriendlyName" : "GameAnalytics", 5 | "Version" : 1, 6 | "VersionName" : "6.1.0", 7 | "CreatedBy" : "GameAnalytics", 8 | "CreatedByURL" : "http://gameanalytics.com", 9 | "MarketplaceURL" : "com.epicgames.launcher://ue/marketplace/content/d070c3fab7b74c08bab3a89c9cbf4490", 10 | "Description" : "GameAnalytics is a free analytics platform that helps game developers understand their players' behaviour by delivering relevant insights.", 11 | "Category" : "Analytics", 12 | 13 | "Modules" : 14 | [ 15 | { 16 | "Name" : "GameAnalytics", 17 | "Type" : "Runtime", 18 | "LoadingPhase" : "PreDefault", 19 | "WhitelistPlatforms" : [ "Android", "IOS", "Mac", "Win64", "Linux" ] 20 | }, 21 | { 22 | "Name" : "GameAnalyticsEditor", 23 | "Type" : "UncookedOnly", 24 | "LoadingPhase" : "PreDefault" 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 GameAnalytics 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/GameAnalyticsPerformance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GAEnums.h" 4 | #include "Tickable.h" 5 | #include "GenericPlatform/GenericPlatformMisc.h" 6 | #include "GameAnalyticsPerformance.generated.h" 7 | 8 | UCLASS() 9 | class UGameAnalyticsPerformance: 10 | public UObject, 11 | public FTickableGameObject 12 | { 13 | GENERATED_UCLASS_BODY() 14 | 15 | int32 _frameCount = 0; 16 | float _accm = 0.0; 17 | float _avgFps = 0.0; 18 | float _timePassed = 0.0; 19 | 20 | static constexpr float kMaxFpsValue = 120.f; 21 | 22 | public: 23 | 24 | bool EnableFPSTracking = true; 25 | 26 | virtual ~UGameAnalyticsPerformance(); 27 | 28 | // returns last fps reading 29 | float GetAvgFps() const; 30 | 31 | // do fps average and reset counter 32 | int32 DoFpsSample(); 33 | 34 | virtual void Tick(float DeltaTime) override; 35 | 36 | virtual bool IsTickable() const override; 37 | 38 | virtual bool IsTickableInEditor () const override; 39 | 40 | virtual TStatId GetStatId() const override; 41 | 42 | FString GetGPUModel() const; 43 | }; 44 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Public/GAEnums.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "UObject/Object.h" 4 | 5 | UENUM() 6 | enum class EGAResourceFlowType : uint8 7 | { 8 | undefined = 0, 9 | source = 1, 10 | sink = 2 11 | }; 12 | 13 | UENUM() 14 | enum class EGAProgressionStatus : uint8 15 | { 16 | undefined = 0, 17 | start = 1, 18 | complete = 2, 19 | fail = 3 20 | }; 21 | 22 | UENUM() 23 | enum class EGAErrorSeverity : uint8 24 | { 25 | undefined = 0, 26 | debug = 1, 27 | info = 2, 28 | warning = 3, 29 | error = 4, 30 | critical = 5 31 | }; 32 | 33 | UENUM() 34 | enum class EGAAdAction : uint8 35 | { 36 | undefined = 0, 37 | clicked = 1, 38 | show = 2, 39 | failedshow = 3, 40 | rewardreceived = 4, 41 | request = 5, 42 | loaded = 6 43 | }; 44 | 45 | UENUM() 46 | enum class EGAAdType : uint8 47 | { 48 | undefined = 0, 49 | video = 1, 50 | rewardedvideo = 2, 51 | playable = 3, 52 | interstitial = 4, 53 | offerwall = 5, 54 | banner = 6 55 | }; 56 | 57 | UENUM() 58 | enum class EGAAdError : uint8 59 | { 60 | undefined = 0, 61 | unknown = 1, 62 | offline = 2, 63 | nofill = 3, 64 | internalerror = 4, 65 | invalidrequest = 5, 66 | unabletoprecache = 6 67 | }; 68 | 69 | UENUM() 70 | enum class EGAValueType : uint8 71 | { 72 | value_number = 0, 73 | value_string, 74 | value_bool 75 | }; 76 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalyticsEditor/GameAnalyticsEditor.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2014 Epic Games, Inc. All Rights Reserved. 2 | 3 | namespace UnrealBuildTool.Rules 4 | { 5 | public class GameAnalyticsEditor : ModuleRules 6 | { 7 | #if WITH_FORWARDED_MODULE_RULES_CTOR 8 | public GameAnalyticsEditor(ReadOnlyTargetRules Target) : base(Target) 9 | #else 10 | public GameAnalyticsEditor(TargetInfo Target) 11 | #endif 12 | { 13 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 14 | 15 | PrivateDependencyModuleNames.AddRange( 16 | new string[] 17 | { 18 | "Core", 19 | "CoreUObject", 20 | "Engine", 21 | "RenderCore", 22 | "RHI", 23 | "Slate", 24 | "SlateCore", 25 | "EditorStyle", 26 | "EditorWidgets", 27 | "DesktopWidgets", 28 | "PropertyEditor", 29 | "SharedSettingsWidgets", 30 | "SourceControl", 31 | "UnrealEd", 32 | "HTTP", 33 | "Json", 34 | "JsonUtilities", 35 | "InputCore" 36 | } 37 | ); 38 | 39 | DynamicallyLoadedModuleNames.AddRange( 40 | new string[] 41 | { 42 | "Settings" 43 | } 44 | ); 45 | 46 | PublicIncludePathModuleNames.AddRange( 47 | new string[] 48 | { 49 | "Settings" 50 | } 51 | ); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GameAnalytics_APL.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | -keep class com.gameanalytics.sdk.** { *; } 21 | -keep class android.net.** { *; } 22 | -dontwarn android.net.** 23 | 24 | 25 | 26 | 27 | 28 | repositories { 29 | maven { url 'https://maven.gameanalytics.com/release' } 30 | maven { url 'https://maven.google.com' } 31 | flatDir { dirs("libs") } 32 | } 33 | dependencies { 34 | implementation('com.gameanalytics.sdk:gameanalytics-android:7.0.0') 35 | implementation('com.google.android.gms:play-services-appset:16.0.1') 36 | } 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/GameAnalyticsPerformance.cpp: -------------------------------------------------------------------------------- 1 | #include "GameAnalyticsPerformance.h" 2 | 3 | DEFINE_LOG_CATEGORY_STATIC(LogGameAnalyticsDebug, Display, All); 4 | 5 | void UGameAnalyticsPerformance::Tick(float DeltaTime) 6 | { 7 | _timePassed += DeltaTime; 8 | 9 | float fps = 1.0 / DeltaTime; 10 | _accm += fps; 11 | _frameCount++; 12 | 13 | if(_timePassed >= 1.f) 14 | { 15 | _timePassed = 0.f; 16 | DoFpsSample(); 17 | } 18 | 19 | //UE_LOG(LogGameAnalyticsDebug, Display, TEXT("GameAnalytics FPS: %.2f Avg Fps: %.2f"), fps, _avgFps); 20 | } 21 | 22 | float UGameAnalyticsPerformance::GetAvgFps() const 23 | { 24 | if (_avgFps > kMaxFpsValue) 25 | { 26 | return kMaxFpsValue; 27 | } 28 | 29 | return _avgFps; 30 | } 31 | 32 | UGameAnalyticsPerformance::UGameAnalyticsPerformance(const FObjectInitializer& ObjectInitializer) : 33 | UObject(ObjectInitializer), FTickableGameObject() 34 | { 35 | } 36 | 37 | UGameAnalyticsPerformance::~UGameAnalyticsPerformance() 38 | { 39 | } 40 | 41 | FString UGameAnalyticsPerformance::GetGPUModel() const 42 | { 43 | return FPlatformMisc::GetPrimaryGPUBrand(); 44 | } 45 | 46 | int32 UGameAnalyticsPerformance::DoFpsSample() 47 | { 48 | if(_accm && _frameCount) 49 | { 50 | _avgFps = _accm / _frameCount; 51 | } 52 | 53 | _accm = 0; 54 | _frameCount = 0; 55 | 56 | return static_cast(_avgFps); 57 | } 58 | 59 | bool UGameAnalyticsPerformance::IsTickable() const 60 | { 61 | return true; 62 | 63 | /* 64 | #if WITH_EDITOR 65 | return false; 66 | #else 67 | return true; 68 | #endif 69 | */ 70 | } 71 | 72 | bool UGameAnalyticsPerformance::IsTickableInEditor() const 73 | { 74 | return false; 75 | } 76 | 77 | TStatId UGameAnalyticsPerformance::GetStatId() const 78 | { 79 | return Super::GetStatID(); 80 | } 81 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalyticsEditor/Private/GameAnalyticsEditor.cpp: -------------------------------------------------------------------------------- 1 | #include "GameAnalyticsEditor.h" 2 | 3 | #include "GameAnalyticsTargetSettingsCustomization.h" 4 | 5 | #include "Modules/ModuleInterface.h" 6 | #include "ISettingsModule.h" 7 | #include "Modules/ModuleManager.h" 8 | 9 | #include "GameAnalyticsProjectSettings.h" 10 | 11 | #define LOCTEXT_NAMESPACE "GameAnalyticsPlugin" 12 | 13 | void FGameAnalyticsEditor::StartupModule() 14 | { 15 | // register settings detail panel customization 16 | FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked("PropertyEditor"); 17 | PropertyModule.RegisterCustomClassLayout( 18 | UGameAnalyticsProjectSettings::StaticClass()->GetFName(), 19 | FOnGetDetailCustomizationInstance::CreateStatic(&FGameAnalyticsTargetSettingsCustomization::MakeInstance) 20 | ); 21 | 22 | PropertyModule.NotifyCustomizationModuleChanged(); 23 | 24 | ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); 25 | if( SettingsModule != nullptr ) 26 | { 27 | SettingsModule->RegisterSettings( 28 | "Project", "Plugins", "GameAnalytics", 29 | LOCTEXT( "GameAnalyticsSettingsName", "GameAnalytics" ), 30 | LOCTEXT( "GameAnalyticsSettingsDescription", "GameAnalytics settings" ), 31 | GetMutableDefault< UGameAnalyticsProjectSettings >() ); 32 | } 33 | } 34 | 35 | void FGameAnalyticsEditor::ShutdownModule() 36 | { 37 | ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); 38 | if( SettingsModule != nullptr ) 39 | { 40 | SettingsModule->UnregisterSettings( "Project", "Plugins", "GameAnalytics" ); 41 | } 42 | } 43 | 44 | IMPLEMENT_MODULE(FGameAnalyticsEditor, GameAnalyticsEditor) 45 | 46 | #undef LOCTEXT_NAMESPACE 47 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GA-SDK-CPP/GameAnalytics/GATypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace gameanalytics 14 | { 15 | /*! 16 | @enum 17 | @discussion 18 | This enum is used to specify flow in resource events 19 | @constant GAResourceFlowTypeSource 20 | Used when adding to a resource currency 21 | @constant GAResourceFlowTypeSink 22 | Used when subtracting from a resource currency 23 | */ 24 | enum EGAResourceFlowType 25 | { 26 | Source = 1, 27 | Sink = 2 28 | }; 29 | 30 | /*! 31 | @enum 32 | @discussion 33 | this enum is used to specify status for progression event 34 | @constant GAProgressionStatusStart 35 | User started progression 36 | @constant GAProgressionStatusComplete 37 | User succesfully ended a progression 38 | @constant GAProgressionStatusFail 39 | User failed a progression 40 | */ 41 | enum EGAProgressionStatus 42 | { 43 | Start = 1, 44 | Complete = 2, 45 | Fail = 3 46 | }; 47 | 48 | /*! 49 | @enum 50 | @discussion 51 | this enum is used to specify severity of an error event 52 | @constant GAErrorSeverityDebug 53 | @constant GAErrorSeverityInfo 54 | @constant GAErrorSeverityWarning 55 | @constant GAErrorSeverityError 56 | @constant GAErrorSeverityCritical 57 | */ 58 | enum EGAErrorSeverity 59 | { 60 | Debug = 1, 61 | Info = 2, 62 | Warning = 3, 63 | Error = 4, 64 | Critical = 5 65 | }; 66 | 67 | enum EGALoggerMessageType 68 | { 69 | LogError = 0, 70 | LogWarning = 1, 71 | LogInfo = 2, 72 | LogDebug = 3, 73 | LogVerbose = 4 74 | }; 75 | 76 | using StringVector = std::vector; 77 | 78 | using LogHandler = std::function; 79 | using FPSTracker = std::function; 80 | 81 | struct IRemoteConfigsListener 82 | { 83 | virtual void onRemoteConfigsUpdated(std::string const& remoteConfigs) = 0; 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GA-SDK-HTML5/GameAnalytics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" 4 | { 5 | void js_configureAvailableCustomDimensions01(const char *list); 6 | void js_configureAvailableCustomDimensions02(const char *list); 7 | void js_configureAvailableCustomDimensions03(const char *list); 8 | void js_configureAvailableResourceCurrencies(const char *list); 9 | void js_configureAvailableResourceItemTypes(const char *list); 10 | void js_configureSdkGameEngineVersion(const char *version); 11 | void js_configureGameEngineVersion(const char *version); 12 | void js_configureBuild(const char *build); 13 | void js_configureUserId(const char *userId); 14 | void js_initialize(const char *gamekey, const char *gamesecret); 15 | void js_setCustomDimension01(const char *customDimension); 16 | void js_setCustomDimension02(const char *customDimension); 17 | void js_setCustomDimension03(const char *customDimension); 18 | void js_addBusinessEvent(const char *currency, int amount, const char *itemType, const char *itemId, const char *cartType, const char *fields); 19 | void js_addResourceEvent(int flowType, const char *currency, float amount, const char *itemType, const char *itemId, const char *fields); 20 | void js_addProgressionEvent(int progressionStatus, const char *progression01, const char *progression02, const char *progression03, const char *fields); 21 | void js_addProgressionEventWithScore(int progressionStatus, const char *progression01, const char *progression02, const char *progression03, int score, const char *fields); 22 | void js_addDesignEvent(const char *eventId, const char *fields); 23 | void js_addDesignEventWithValue(const char *eventId, float value, const char *fields); 24 | void js_addErrorEvent(int severity, const char *message, const char *fields); 25 | void js_setEnabledInfoLog(bool enabled); 26 | void js_setEnabledVerboseLog(bool enabled); 27 | void js_setManualSessionHandling(bool enabled); 28 | void js_setEventSubmission(bool enabled); 29 | void js_startSession(); 30 | void js_endSession(); 31 | void js_onStop(); 32 | const char* js_getRemoteConfigsValueAsString(const char *key); 33 | const char* js_getRemoteConfigsValueAsStringWithDefaultValue(const char *key, const char *defaultValue); 34 | bool js_isRemoteConfigsReady(); 35 | const char* js_getRemoteConfigsContentAsString(); 36 | const char* js_getABTestingId(); 37 | const char* js_getABTestingVariantId(); 38 | } 39 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Public/GameAnalyticsModule.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "Interfaces/IAnalyticsProviderModule.h" 6 | #include "Interfaces/IAnalyticsProvider.h" 7 | #include "CoreMinimal.h" 8 | #include "Misc/Paths.h" 9 | #include "Runtime/Launch/Resources/Version.h" 10 | 11 | #include "GameAnalytics.h" 12 | 13 | #if (ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 15) || (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 0) 14 | #include "Modules/ModuleManager.h" 15 | #endif 16 | 17 | /** 18 | * The public interface to this module 19 | */ 20 | class FGameAnalyticsModule : 21 | public IAnalyticsProviderModule 22 | { 23 | /** Singleton for analytics */ 24 | TSharedPtr GameAnalyticsProvider; 25 | 26 | //-------------------------------------------------------------------------- 27 | // Module functionality 28 | //-------------------------------------------------------------------------- 29 | public: 30 | /** 31 | * Singleton-like access to this module's interface. This is just for convenience! 32 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 33 | * 34 | * @return Returns singleton instance, loading the module on demand if needed 35 | */ 36 | static inline FGameAnalyticsModule& Get() 37 | { 38 | return FModuleManager::LoadModuleChecked< FGameAnalyticsModule >( "GameAnalytics" ); 39 | } 40 | 41 | inline UGameAnalytics* GetInstance() 42 | { 43 | return GameAnalytics; 44 | } 45 | 46 | //-------------------------------------------------------------------------- 47 | // provider factory functions 48 | //-------------------------------------------------------------------------- 49 | public: 50 | /** 51 | * IAnalyticsProviderModule interface. 52 | * Creates the analytics provider given a configuration delegate. 53 | * The keys required exactly match the field names in the Config object. 54 | */ 55 | #if (ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 13) || (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 0) 56 | using Delegate = FAnalyticsProviderConfigurationDelegate; 57 | #else 58 | using Delegate = FAnalytics::FProviderConfigurationDelegate; 59 | #endif 60 | 61 | virtual TSharedPtr CreateAnalyticsProvider(const Delegate& GetConfigValue) const override; 62 | 63 | struct FGameAnalyticsProjectSettings 64 | { 65 | struct PlatformInfo 66 | { 67 | FString GameKey; 68 | FString SecretKey; 69 | FString Build; 70 | }; 71 | 72 | PlatformInfo iOS; 73 | PlatformInfo Android; 74 | PlatformInfo Mac; 75 | PlatformInfo Windows; 76 | PlatformInfo Linux; 77 | 78 | TArray CustomDimensions01; 79 | TArray CustomDimensions02; 80 | TArray CustomDimensions03; 81 | TArray ResourceCurrencies; 82 | TArray ResourceItemTypes; 83 | 84 | bool UseManualSessionHandling; 85 | bool AutoDetectAppVersion; 86 | bool DisableDeviceInfo; 87 | bool UseErrorReporting; 88 | bool SubmitErrors; 89 | bool SubmitAverageFPS; 90 | bool SubmitCriticalFPS; 91 | bool InfoLogEditor; 92 | bool InfoLogBuild; 93 | bool VerboseLogBuild; 94 | 95 | PlatformInfo GetActivePlatform() const; 96 | }; 97 | 98 | static FGameAnalyticsProjectSettings LoadProjectSettings(); 99 | 100 | private: 101 | 102 | UGameAnalytics* GameAnalytics{nullptr}; 103 | 104 | virtual void StartupModule() override; 105 | virtual void ShutdownModule() override; 106 | 107 | static FORCEINLINE FString GetIniName() { return FString::Printf(TEXT("%sDefaultEngine.ini"), *FPaths::SourceConfigDir()); } 108 | }; 109 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/GameAnalyticsProvider.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "UObject/Package.h" 7 | #include "UObject/UObjectGlobals.h" 8 | 9 | #include "GameAnalytics.h" 10 | #include "GameAnalyticsModule.h" 11 | 12 | class FGameAnalyticsProvider : 13 | public IAnalyticsProvider 14 | { 15 | /** Path where analytics files are saved out */ 16 | FString AnalyticsFilePath; 17 | /** Tracks whether we need to start the session or restart it */ 18 | bool bHasSessionStarted; 19 | /** Whether an event was written before or not */ 20 | bool bHasWrittenFirstEvent; 21 | /** Id representing the user the analytics are recording for */ 22 | FString UserId; 23 | /** Unique Id representing the session the analytics are recording for */ 24 | FString SessionId; 25 | /** Holds the Age if set */ 26 | int32 Age; 27 | 28 | /** handles GA */ 29 | UGameAnalytics* GameAnalytics; 30 | 31 | /** Settings for GameAnalytics, loaded from project configuration files */ 32 | FGameAnalyticsModule::FGameAnalyticsProjectSettings ProjectSettings; 33 | 34 | FString GetAnalyticsPath() const; 35 | FString GenerateUserId() const; 36 | 37 | public: 38 | 39 | FGameAnalyticsProvider(UGameAnalytics* GameAnalytics); 40 | virtual ~FGameAnalyticsProvider(); 41 | 42 | virtual bool StartSession(const TArray& Attributes) override; 43 | virtual void EndSession() override; 44 | virtual void FlushEvents() override; 45 | 46 | void OnQuit(); 47 | 48 | virtual void SetDefaultEventAttributes(TArray&& Attributes) override; 49 | virtual TArray GetDefaultEventAttributesSafe() const override; 50 | virtual int32 GetDefaultEventAttributeCount() const override; 51 | virtual FAnalyticsEventAttribute GetDefaultEventAttribute(int AttributeIndex) const override; 52 | 53 | virtual void SetUserID(const FString& InUserID) override; 54 | virtual FString GetUserID() const override; 55 | 56 | virtual FString GetSessionID() const override; 57 | virtual bool SetSessionID(const FString& InSessionID) override; 58 | 59 | virtual void RecordEvent(const FString& EventName, const TArray& Attributes) override; 60 | 61 | virtual void SetGender(const FString& InGender) ; 62 | virtual void SetAge(const int32 InAge) ; 63 | 64 | virtual void RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) override; 65 | virtual void RecordItemPurchase(const FString& ItemId, int ItemQuantity, const TArray& Attributes) override; 66 | virtual void RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) override; 67 | virtual void RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount) override; 68 | virtual void RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const TArray& Attributes) override; 69 | virtual void RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount) override; 70 | virtual void RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount, const TArray& Attributes) override; 71 | virtual void RecordError(const FString& Error) override; 72 | virtual void RecordError(const FString& Error, const TArray& Attributes) override; 73 | virtual void RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy) override; 74 | virtual void RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy, const TArray& Attributes) override; 75 | virtual void RecordProgress(const FString& ProgressType, const TArray& ProgressHierarchy, const TArray& Attributes) override; 76 | }; 77 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GameAnalytics.Build.cs: -------------------------------------------------------------------------------- 1 | using UnrealBuildTool; 2 | using System.IO; 3 | using System; 4 | 5 | 6 | namespace UnrealBuildTool.Rules 7 | { 8 | public class GameAnalytics : ModuleRules 9 | { 10 | #if WITH_FORWARDED_MODULE_RULES_CTOR 11 | public GameAnalytics(ReadOnlyTargetRules Target) : base(Target) 12 | #else 13 | public GameAnalytics(TargetInfo Target) 14 | #endif 15 | { 16 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 17 | 18 | var ThirdPartyPath = Path.GetFullPath(Path.Combine(ModuleDirectory, "../ThirdParty/")); 19 | var GA_SDK_CppPath = Path.GetFullPath(Path.Combine(ThirdPartyPath, "GA-SDK-CPP", "lib")); 20 | var libPath = Path.Combine(ThirdPartyPath, "lib"); 21 | 22 | if(Target.Platform == UnrealTargetPlatform.Win64) 23 | { 24 | PublicAdditionalLibraries.Add(Path.Combine(GA_SDK_CppPath, "Win64", "GameAnalytics.lib")); 25 | PrivateDependencyModuleNames.AddRange(new string[] { "OpenSSL", "libcurl", "nghttp2", "zlib" }); 26 | PrivateIncludePaths.Add(Path.GetFullPath(Path.Combine(ModuleDirectory, "GA-SDK-CPP"))); 27 | } 28 | else if(Target.Platform == UnrealTargetPlatform.Android) 29 | { 30 | PrivateDependencyModuleNames.Add("Launch"); 31 | PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private/Android")); 32 | } 33 | else if(Target.Platform == UnrealTargetPlatform.Mac) 34 | { 35 | PublicAdditionalLibraries.Add(Path.Combine(GA_SDK_CppPath, "Mac", "libGameAnalytics.a")); 36 | 37 | PublicFrameworks.AddRange( 38 | new string[] { 39 | "CoreFoundation", 40 | "Foundation", 41 | "CoreServices", 42 | "SystemConfiguration", 43 | "Metal", 44 | "MetalKit" 45 | } 46 | ); 47 | PrivateDependencyModuleNames.AddRange(new string[] { "OpenSSL", "libcurl", "nghttp2" }); 48 | 49 | PrivateIncludePaths.Add(Path.GetFullPath(Path.Combine(ModuleDirectory, "GA-SDK-CPP"))); 50 | } 51 | else if(Target.Platform == UnrealTargetPlatform.Linux) 52 | { 53 | PublicAdditionalLibraries.Add(Path.Combine(GA_SDK_CppPath, "Linux-clang", "libGameAnalytics.a")); 54 | PrivateDependencyModuleNames.AddRange(new string[] { "OpenSSL", "libcurl", "nghttp2" }); 55 | PrivateIncludePaths.Add(Path.GetFullPath(Path.Combine(ModuleDirectory, "GA-SDK-CPP"))); 56 | } 57 | else if(Target.Platform == UnrealTargetPlatform.IOS) 58 | { 59 | PublicAdditionalLibraries.Add(Path.Combine(libPath, "ios", "libGameAnalytics.a")); 60 | PrivateIncludePaths.Add(Path.Combine(ModuleDirectory, "Private/IOS")); 61 | PublicFrameworks.AddRange( 62 | new string[] { 63 | "AdSupport", 64 | "SystemConfiguration", 65 | "AppTrackingTransparency" 66 | } 67 | ); 68 | 69 | PublicAdditionalLibraries.AddRange( 70 | new string[] { 71 | "sqlite3", 72 | "z", 73 | "c++" 74 | }); 75 | 76 | string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath); 77 | AdditionalPropertiesForReceipt.Add("IOSPlugin", Path.Combine(PluginPath, "GameAnalytics_iOS_UPL.xml")); 78 | } 79 | /*else if(Target.Platform == UnrealTargetPlatform.HTML5) 80 | { 81 | if (Target.Architecture != "-win32") 82 | { 83 | PublicAdditionalLibraries.Add(Path.Combine(libPath, "html5", "GameAnalytics.jspre")); 84 | PublicAdditionalLibraries.Add(Path.Combine(libPath, "html5", "GameAnalyticsUnreal.js")); 85 | } 86 | }*/ 87 | else 88 | { 89 | throw new NotImplementedException("This target platform is not configured for GameAnalytics SDK: " + Target.Platform.ToString()); 90 | } 91 | 92 | PublicDependencyModuleNames.AddRange( 93 | new string[] 94 | { 95 | "Core", 96 | "CoreUObject", 97 | "Engine", 98 | "Json" 99 | // ... add other public dependencies that you statically link with here ... 100 | } 101 | ); 102 | 103 | PrivateIncludePaths.Add(Path.GetFullPath(Path.Combine(ModuleDirectory, "Private"))); 104 | PrivateIncludePaths.Add(Path.GetFullPath(Path.Combine(ModuleDirectory, "Public"))); 105 | PublicIncludePaths.Add(Path.GetFullPath(Path.Combine(ModuleDirectory, "Public"))); 106 | 107 | 108 | PrivateDependencyModuleNames.AddRange( 109 | new string[] 110 | { 111 | "Analytics", 112 | "Engine", 113 | "Json" 114 | } 115 | ); 116 | 117 | PublicIncludePathModuleNames.AddRange( 118 | new string[] 119 | { 120 | "Analytics", 121 | "Engine", 122 | "Json" 123 | } 124 | ); 125 | 126 | if (Target.Platform == UnrealTargetPlatform.Android) 127 | { 128 | string PluginPath = Utils.MakePathRelativeTo(ModuleDirectory, Target.RelativeEnginePath); 129 | AdditionalPropertiesForReceipt.Add("AndroidPlugin", Path.Combine(PluginPath, "GameAnalytics_APL.xml")); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GA-SDK-UNREAL 2 | GameAnalytics SDK for the Unreal Engine. 3 | 4 | Documentation can be found [here](https://docs.gameanalytics.com/integrations/sdk/unreal). 5 | 6 | If you have any issues or feedback regarding the SDK, please contact our friendly support team [here](https://gameanalytics.com/contact). 7 | 8 | > :information_source: 9 | > 10 | > The Unreal SDK include support for **iOS**, **Android**, **HTML5**, **Windows**, **Linux** and **Mac** platforms 11 | > 12 | > Requirements: 13 | > * **Unreal Engine:** 5.3+   14 | > * **iOS:** iOS 10+   15 | > * **Android:** Android API Level 21   16 | > * **Windows:** Minimum specs for UE5   17 | > * **Mac:** Minimum specs for UE5   18 | 19 | ## Usage 20 | 21 | ## C++ Code 22 | 23 | There are two ways of using the GameAnalytics plugin inside your C++ code: 24 | 25 | - directly using an instance of an `UGameAnalytics` object 26 | - using the `IAnalyticsProvider` interface 27 | 28 | The former will provide all the plugin features, including remote configurations and performance tracking. The `IAnalyticsProvider` will provide an easier integration inside Unreal, but will only expose limited features. 29 | 30 | Due to the inner workings of the module the `IAnalyticsProvider` will retrieve its settings from `Project Settings -> Plugins -> GameAnalytics`. While using `UGameAnalytics` directly will require you to manually call the setup functions (either from C++ or Blueprints). 31 | 32 | If you are using the `IAnalyticsInterface`, but desire to enable advanced features of the SDK, you can safely mix calls from both `IAnalyticsInterface` and `UGameAnalytics` as both are using the same instance inside the module (provided you initialize the SDK only once). 33 | 34 | ### Initialization 35 | 36 | The `UGameAnalytics` class provides all plugin functionality. The GameAnalytics module will hold an instance of `UGameAnalytics*`. 37 | 38 | Add the headers to your project: 39 | 40 | ```c++ 41 | #include "GameAnalytics.h" 42 | #include "GameAnalyticsModule.h" 43 | ``` 44 | 45 | Setup and initialize the SDK: 46 | 47 | ```c++ 48 | UGameAnalytics* GameAnalytics = FGameAnalyticsModule::Get().GetInstance(); 49 | 50 | // enable extra info logging 51 | GameAnalytics->SetEnabledInfoLog(true); 52 | 53 | // enable verbose logging -> don't forget to turn off in shipping builds 54 | GameAnalytics->SetEnabledVerboseLog(true); 55 | 56 | // configure available resources 57 | GameAnalytics->ConfigureAvailableResourceItemTypes({ TEXT("copper"), TEXT("silver"), TEXT("gold") }); 58 | 59 | // initialize the SDK with your keys 60 | GameAnalytics->Initialize(GAME_KEY, SECRET_KEY); 61 | ``` 62 | 63 | ### Sending Events 64 | 65 | After the SDK initialization you can start sending events 66 | 67 | ```c++ 68 | // send a design event 69 | GameAnalytics->AddDesignEventWithValue(TEXT("kill:dragon"), 100); 70 | 71 | // send a progression event 72 | GameAnalytics->AddProgressionEvent(EGAProgressionStatus::complete, TEXT("swamplands"), TEXT("temple"), TEXT("level_0")); 73 | 74 | // send a resource event 75 | GameAnalytics->AddResourceEvent(EGAResourceFlowType::source, TEXT("gold"), 200, TEXT("gold_pack"), TEXT("gold_pack_large")); 76 | 77 | // add a business event, amount needs to be in the smallest currency denominiation! (this means for USD you need to send the amount in cents) 78 | GameAnalytics->AddBusinessEvent(TEXT("USD"), 1000, TEXT("premium_gold_bundle"), TEXT("gold_pack_5000"), TEXT("end_level_shop")); 79 | 80 | // send an error event 81 | GameAnalytics->AddErrorEvent(EGAErrorSeverity::warning, TEXT("error message")); 82 | 83 | ``` 84 | 85 | ### Using Custom Fields 86 | 87 | You can attach up to 50 custom fields to any event. 88 | 89 | The following types are supported: 90 | 91 | - boolean 92 | - number (64-bit floating point) 93 | - string 94 | 95 | ```c++ 96 | FGACustomFields Fields; 97 | 98 | Fields.Set(TEXT("my_bool"), true); 99 | Fields.Set(TEXT("my_number"), 1000.f); 100 | fields.Set(TEXT("my_string"), FString(TEXT("halloween_event"))); 101 | 102 | GameAnalytics->AddDesignEventWithValue(TEXT("MyEvent"), 200, fields); 103 | ``` 104 | 105 | ### Performance Tracker 106 | 107 | Before initialization (e.g: calling `UGameAnlalytics::Initialize`), you can setup optional performance reporting. 108 | 109 | ```c++ 110 | // track boot-time 111 | GameAnalytics->EnableSDKInitEvent(true); 112 | 113 | // track hardware information (e.g: cpu name, gpu name, number of cores, memory etc) 114 | GameAnalytics->EnableHealthHardwareInfo(true); 115 | 116 | // track FPS 117 | GameAnalytics->EnableFpsHistogram(true); 118 | 119 | // track memory usage 120 | GameAnalytics->EnableMemoryHistogram(true); 121 | ``` 122 | 123 | ### Using IAnalyticsProvider 124 | 125 | GameAnalytics also proivdes a `IAnalyticsProvider` implementation for seamless integration inside the Unreal ecosystem. 126 | 127 | The `IAnalyticsProvider` interface will retrieve its configuration from `Project Settings -> Plugins -> GameAnalytics` (e.g: game keys, resources, info/verbose log). 128 | 129 | ```c++ 130 | 131 | TSharedPtr AnalyticsProvider = FGameAnalyticsModule::Get().CreateAnalyticsProvider(FGameAnalyticsModule::Delegate()); 132 | 133 | // start session will invoke UGameAnalytics::Initialize on first call 134 | AnalyticsProvider->StartSession(); 135 | 136 | // equivalent to GameAnalytics->AddDesginEvent(TEXT("my:level:id")) 137 | AnalyticsProvider->RecordEvent(TEXT("my:level:id"), MakeAnalyticsEventAttributeArray(TEXT("value"), 100.0)); 138 | 139 | // equivalent to GameAnalytics->AddErrorEvent(EGAErrorSeverity::warning, TEXT("error message")); 140 | AnalyticsProvider->RecordError(TEXT("error message"), MakeAnalyticsEventAttributeArray(TEXT("severity"), TEXT("warning"))); 141 | 142 | // equivalent to GameAnalytics->AddProgressionEventWithScore(EGAProgressionStatus::complete, 100, TEXT("progression1"), TEXT("progression2"), TEXT("progression3")) 143 | AnalyticsProvider->RecordProgress(TEXT("complete"), {TEXT("progression1"), TEXT("progression2"), TEXT("progression3")}, MakeAnalyticsEventAttributeArray(TEXT("value"), 100)); 144 | ``` 145 | 146 | ## Blueprints 147 | 148 | All public functions from `UGameAnalytics` are also exposed to blueprints, as well as the `IAnalyticsProvider` implementation. Anything that can be done via code is also possible using only blueprints. 149 | 150 | Example initialization from blueprint: 151 | ![GameAnalytics Blueprint](img/blueprint.png) -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/Desktop/GAWrapperCpp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GAWrapper.h" 4 | 5 | namespace gameanalytics 6 | { 7 | class GAWrapperCpp: 8 | public GAWrapper 9 | { 10 | virtual void SetAvailableCustomDimensions01(std::vector const& list) override; 11 | virtual void SetAvailableCustomDimensions02(std::vector const& list) override; 12 | virtual void SetAvailableCustomDimensions03(std::vector const& list) override; 13 | 14 | virtual void SetAvailableResourceCurrencies(std::vector const& list) override; 15 | virtual void SetAvailableResourceItemTypes(std::vector const& list) override; 16 | 17 | virtual void SetSDKVersion(std::string const& version) override; 18 | 19 | virtual void SetGameEngineVersion(std::string const& version) override; 20 | 21 | virtual void SetBuild(std::string const& build) override; 22 | virtual void SetCustomUserId(std::string const& userId) override; 23 | virtual void SetExternalUserId(std::string const& extUserId) override; 24 | 25 | virtual std::string GetUserId() override; 26 | virtual std::string GetExternalUserId() override; 27 | 28 | virtual void SetAutoDetectAppVersion(bool flag) override; 29 | 30 | virtual void Initialize(std::string const& gamekey, std::string const& gamesecret) override; 31 | 32 | virtual void SetCustomDimension01(std::string const& customDimension) override; 33 | virtual void SetCustomDimension02(std::string const& customDimension) override; 34 | virtual void SetCustomDimension03(std::string const& customDimension) override; 35 | 36 | virtual void SetGlobalCustomEventFields(std::string const& customFields) override; 37 | virtual void SetEnabledManualSessionHandling (bool enabled) override; 38 | virtual void SetEnabledEventSubmission(bool enabled, bool doCacheLocally = false) override; 39 | 40 | virtual void SetEnabledErrorReporting(bool flag) override; 41 | 42 | virtual void StartSession() override; 43 | virtual void EndSession() override; 44 | 45 | virtual void AddBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const&cartType, std::string const& receipt, std::string const& fields, bool mergeFields) override; 46 | virtual void AddBusinessEventAndAutoFetchReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& fields, bool mergeFields) override; 47 | virtual void AddBusinessEventWithReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& store, std::string const& signature, std::string const& fields, bool mergeFields) override; 48 | 49 | virtual void AddResourceEvent(EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& fields, bool mergeFields) override; 50 | 51 | virtual void AddProgressionEvent(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, std::string const& fields, bool mergeFields) override; 52 | virtual void AddProgressionEventWithScore(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, int score, std::string const& fields, bool mergeFields) override; 53 | 54 | virtual void AddDesignEvent(std::string const& eventID, std::string const& fields, bool mergeFields) override; 55 | virtual void AddDesignEventWithValue(std::string const& eventId, float value, std::string const& fields, bool mergeFields) override; 56 | 57 | virtual void AddErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& fields, bool mergeFields) override; 58 | 59 | virtual void AddAdEventWithDuration(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, int64_t duration, std::string const& fields, bool mergeFields) override; 60 | virtual void AddAdEventWithReason(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, EGAAdError noAdReason, std::string const& fields, bool mergeFields) override; 61 | virtual void AddAdEvent(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, std::string const& fields, bool mergeFields) override; 62 | 63 | virtual void SetInfoLog (bool enabled) override; 64 | virtual void SetVerboseLog (bool enabled) override; 65 | 66 | // ----------------------- REMOTE CONFIGS ---------------------- // 67 | virtual std::string GetRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue) override; 68 | 69 | virtual double GetRemoteConfigsValueAsNumber(std::string const& key, double defaultValue) override; 70 | 71 | virtual std::string GetRemoteConfigsValueAsJson(std::string const& key) override; 72 | 73 | virtual bool IsRemoteConfigsReady() override; 74 | 75 | virtual std::string GetRemoteConfigsContentAsString() override; 76 | 77 | virtual std::string GetABTestingId() override; 78 | 79 | virtual std::string GetABTestingVariantId() override; 80 | 81 | /////////////////// HEALTH ///////////////////////// 82 | 83 | virtual void EnableSDKInitEvent(bool flag) override; 84 | 85 | virtual void EnableFpsHistogram(FPSTracker tracker, bool flag) override; 86 | 87 | virtual void EnableMemoryHistogram(bool flag) override; 88 | 89 | virtual void EnableHealthHardwareInfo(bool flag) override; 90 | 91 | ////////////////////////////////////////////////// 92 | 93 | virtual int64_t GetElapsedSessionTime() override; 94 | 95 | virtual int64_t GetElapsedTimeForPreviousSession() override; 96 | 97 | virtual int64_t GetElapsedTimeFromAllSessions() override; 98 | 99 | ////////////////////////////////////////////////// 100 | 101 | virtual void EnableAdvertisingId(bool enabled) override; 102 | 103 | ///// 104 | 105 | virtual void OnQuit() override; 106 | 107 | virtual void SetWritablePath(std::string const& path) override; 108 | 109 | }; 110 | } 111 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Public/GAWrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "GAEnums.h" 9 | 10 | namespace gameanalytics 11 | { 12 | using FPSTracker = std::function; 13 | 14 | class GAWrapper 15 | { 16 | public: 17 | 18 | virtual ~GAWrapper() {}; 19 | 20 | virtual void SetAvailableCustomDimensions01(std::vector const& list) = 0; 21 | virtual void SetAvailableCustomDimensions02(std::vector const& list) = 0; 22 | virtual void SetAvailableCustomDimensions03(std::vector const& list) = 0; 23 | 24 | virtual void SetAvailableResourceCurrencies(std::vector const& list) = 0; 25 | virtual void SetAvailableResourceItemTypes(std::vector const& list) = 0; 26 | 27 | virtual void SetSDKVersion(std::string const& version) = 0; 28 | 29 | virtual void SetGameEngineVersion(std::string const& version) = 0; 30 | 31 | virtual void SetBuild(std::string const& build) = 0; 32 | virtual void SetCustomUserId(std::string const& userId) = 0; 33 | virtual void SetExternalUserId(std::string const& extUserId) = 0; 34 | 35 | virtual std::string GetUserId() = 0; 36 | virtual std::string GetExternalUserId() = 0; 37 | 38 | virtual void SetAutoDetectAppVersion(bool flag) = 0; 39 | 40 | virtual void Initialize(std::string const& gamekey, std::string const& gamesecret) = 0; 41 | 42 | virtual void SetCustomDimension01(std::string const& customDimension) = 0; 43 | virtual void SetCustomDimension02(std::string const& customDimension) = 0; 44 | virtual void SetCustomDimension03(std::string const& customDimension) = 0; 45 | 46 | virtual void SetGlobalCustomEventFields(std::string const& customFields) = 0; 47 | virtual void SetEnabledManualSessionHandling (bool enabled) = 0; 48 | 49 | virtual void SetEnabledEventSubmission(bool enabled, bool doCache) = 0; 50 | virtual void SetEnabledErrorReporting(bool flag) = 0; 51 | 52 | virtual void StartSession() = 0; 53 | virtual void EndSession() = 0; 54 | 55 | virtual void AddBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const&cartType, std::string const& receipt, std::string const& fields, bool mergeFields) = 0; 56 | virtual void AddBusinessEventAndAutoFetchReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& fields, bool mergeFields) = 0; 57 | virtual void AddBusinessEventWithReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& store, std::string const& signature, std::string const& fields, bool mergeFields) = 0; 58 | 59 | virtual void AddResourceEvent(EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& fields, bool mergeFields) = 0; 60 | 61 | virtual void AddProgressionEvent(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, std::string const& fields, bool mergeFields) = 0; 62 | virtual void AddProgressionEventWithScore(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, int score, std::string const& fields, bool mergeFields) = 0; 63 | 64 | virtual void AddDesignEvent(std::string const& eventID, std::string const& fields, bool mergeFields) = 0; 65 | virtual void AddDesignEventWithValue(std::string const& eventId, float value, std::string const& fields, bool mergeFields) = 0; 66 | 67 | virtual void AddErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& fields, bool mergeFields) = 0; 68 | 69 | virtual void AddAdEventWithDuration(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, int64_t duration, std::string const& fields, bool mergeFields) = 0; 70 | virtual void AddAdEventWithReason(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, EGAAdError noAdReason, std::string const& fields, bool mergeFields) = 0; 71 | virtual void AddAdEvent(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, std::string const& fields, bool mergeFields) = 0; 72 | 73 | virtual void SetInfoLog (bool enabled) = 0; 74 | virtual void SetVerboseLog (bool enabled) = 0; 75 | 76 | // ----------------------- REMOTE CONFIGS ---------------------- // 77 | virtual std::string GetRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue) = 0; 78 | 79 | virtual double GetRemoteConfigsValueAsNumber(std::string const& key, double defaultValue) = 0; 80 | 81 | virtual std::string GetRemoteConfigsValueAsJson(std::string const& key) = 0; 82 | 83 | virtual bool IsRemoteConfigsReady() = 0; 84 | 85 | virtual std::string GetRemoteConfigsContentAsString() = 0; 86 | 87 | virtual std::string GetABTestingId() = 0; 88 | 89 | virtual std::string GetABTestingVariantId() = 0; 90 | 91 | /////////////////// HEALTH ///////////////////////// 92 | 93 | virtual void EnableSDKInitEvent(bool flag) = 0; 94 | 95 | virtual void EnableFpsHistogram(FPSTracker tracker, bool flag) = 0; 96 | 97 | virtual void EnableMemoryHistogram(bool flag) = 0; 98 | 99 | virtual void EnableHealthHardwareInfo(bool flag) = 0; 100 | 101 | ////////////////////////////////////////////////// 102 | 103 | virtual int64_t GetElapsedSessionTime() = 0; 104 | 105 | virtual int64_t GetElapsedTimeForPreviousSession() = 0; 106 | 107 | virtual int64_t GetElapsedTimeFromAllSessions() = 0; 108 | 109 | ////////////////////////////////////////////////// 110 | 111 | virtual void EnableAdvertisingId(bool enabled) = 0; 112 | 113 | ///// 114 | 115 | virtual void OnQuit() = 0; 116 | 117 | virtual void SetWritablePath(std::string const& path) = 0; 118 | }; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/IOS/GAWrapperIOS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GAWrapper.h" 4 | 5 | namespace gameanalytics 6 | { 7 | class GAWrapperIOS: 8 | public GAWrapper 9 | { 10 | public: 11 | 12 | virtual void SetAvailableCustomDimensions01(std::vector const& list) override; 13 | virtual void SetAvailableCustomDimensions02(std::vector const& list) override; 14 | virtual void SetAvailableCustomDimensions03(std::vector const& list) override; 15 | 16 | virtual void SetAvailableResourceCurrencies(std::vector const& list) override; 17 | virtual void SetAvailableResourceItemTypes(std::vector const& list) override; 18 | 19 | virtual void SetSDKVersion(std::string const& version) override; 20 | 21 | virtual void SetGameEngineVersion(std::string const& version) override; 22 | 23 | virtual void SetBuild(std::string const& build) override; 24 | virtual void SetCustomUserId(std::string const& userId) override; 25 | virtual void SetExternalUserId(std::string const& extUserId) override; 26 | 27 | virtual std::string GetUserId() override; 28 | virtual std::string GetExternalUserId() override; 29 | 30 | virtual void SetAutoDetectAppVersion(bool flag) override; 31 | 32 | virtual void Initialize(std::string const& gamekey, std::string const& gamesecret) override; 33 | 34 | virtual void SetCustomDimension01(std::string const& customDimension) override; 35 | virtual void SetCustomDimension02(std::string const& customDimension) override; 36 | virtual void SetCustomDimension03(std::string const& customDimension) override; 37 | 38 | virtual void SetGlobalCustomEventFields(std::string const& customFields) override; 39 | virtual void SetEnabledManualSessionHandling(bool enabled) override; 40 | virtual void SetEnabledEventSubmission(bool enable, bool offlineCaching = true) override; 41 | virtual void SetEnabledErrorReporting(bool flag) override; 42 | 43 | virtual void StartSession() override; 44 | virtual void EndSession() override; 45 | 46 | virtual void AddBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const&cartType, std::string const& receipt, std::string const& fields, bool mergeFields) override; 47 | virtual void AddBusinessEventAndAutoFetchReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& fields, bool mergeFields) override; 48 | virtual void AddBusinessEventWithReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& store, std::string const& signature, std::string const& fields, bool mergeFields) override; 49 | 50 | virtual void AddResourceEvent(EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& fields, bool mergeFields) override; 51 | 52 | virtual void AddProgressionEvent(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, std::string const& fields, bool mergeFields) override; 53 | virtual void AddProgressionEventWithScore(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, int score, std::string const& fields, bool mergeFields) override; 54 | 55 | virtual void AddDesignEvent(std::string const& eventID, std::string const& fields, bool mergeFields) override; 56 | virtual void AddDesignEventWithValue(std::string const& eventId, float value, std::string const& fields, bool mergeFields) override; 57 | 58 | virtual void AddErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& fields, bool mergeFields) override; 59 | 60 | virtual void AddAdEventWithDuration(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, int64_t duration, std::string const& fields, bool mergeFields) override; 61 | virtual void AddAdEventWithReason(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, EGAAdError noAdReason, std::string const& fields, bool mergeFields) override; 62 | virtual void AddAdEvent(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, std::string const& fields, bool mergeFields) override; 63 | 64 | virtual void SetInfoLog(bool enabled) override; 65 | virtual void SetVerboseLog(bool enabled) override; 66 | 67 | 68 | // ----------------------- REMOTE CONFIGS ---------------------- // 69 | 70 | virtual std::string GetRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue) override; 71 | 72 | virtual std::string GetRemoteConfigsValueAsJson(std::string const& key) override; 73 | 74 | virtual double GetRemoteConfigsValueAsNumber(std::string const& key, double defaultValue) override; 75 | 76 | virtual bool IsRemoteConfigsReady() override; 77 | 78 | virtual std::string GetRemoteConfigsContentAsString() override; 79 | 80 | virtual std::string GetABTestingId() override; 81 | 82 | virtual std::string GetABTestingVariantId() override; 83 | 84 | ///// HEALTH 85 | 86 | virtual void EnableSDKInitEvent(bool flag) override; 87 | 88 | virtual void EnableFpsHistogram(FPSTracker tracker, bool flag) override; 89 | 90 | virtual void EnableMemoryHistogram(bool flag) override; 91 | 92 | virtual void EnableHealthHardwareInfo(bool flag) override; 93 | 94 | ///////////////////////////////////////////////////////////// 95 | 96 | virtual int64_t GetElapsedSessionTime() override; 97 | 98 | virtual int64_t GetElapsedTimeForPreviousSession() override; 99 | 100 | virtual int64_t GetElapsedTimeFromAllSessions() override; 101 | 102 | //////////////////////////////////////////////////////// 103 | 104 | virtual void EnableAdvertisingId(bool value) override; 105 | 106 | virtual void OnQuit() override; 107 | 108 | virtual void SetWritablePath(std::string const& path) override; 109 | 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalyticsEditor/Private/GameAnalyticsTargetSettingsCustomization.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Widgets/Input/SComboBox.h" 7 | #include "PropertyEditorModule.h" 8 | #include "GameAnalyticsProjectSettings.h" 9 | #include "IDetailCustomization.h" 10 | 11 | #include "Http.h" 12 | 13 | ////////////////////////////////////////////////////////////////////////// 14 | // FAndroidTargetSettingsCustomization 15 | 16 | class FGameAnalyticsTargetSettingsCustomization : public IDetailCustomization 17 | { 18 | public: 19 | 20 | struct GAME { 21 | FString Name; 22 | int Id; 23 | FString GameKey; 24 | FString SecretKey; 25 | }; 26 | 27 | struct STUDIO { 28 | FString Name; 29 | int Id; 30 | int OrganizationId; 31 | TArray Games; 32 | 33 | /*STUDIO (FString aName, int aId, TArray aGames) : 34 | Name(aName), Id(aId), Games(aGames) 35 | { 36 | }*/ 37 | }; 38 | 39 | struct ORGANIZATION { 40 | FString Name; 41 | int Id; 42 | TArray Studios; 43 | }; 44 | 45 | // Makes a new instance of this detail layout class for a specific detail view requesting it 46 | static TSharedRef MakeInstance(); 47 | 48 | // IDetailCustomization interface 49 | virtual void CustomizeDetails(IDetailLayoutBuilder& DetailLayout) override; 50 | // End of IDetailCustomization interface 51 | 52 | void UsernameEntered(const FText& NewText, ETextCommit::Type CommitInfo); 53 | void UsernameChanged(const FText& NewText); 54 | 55 | void PasswordEntered(const FText& NewText, ETextCommit::Type CommitInfo); 56 | void PasswordChanged(const FText& NewText); 57 | 58 | void FillOrganizationsString(TArray OrganizationList); 59 | TSharedRef HandleStudiosComboBoxGenerateWidget(TSharedPtr StringItem); 60 | void HandleStudiosComboBoxSelectionChanged(TSharedPtr StringItem, ESelectInfo::Type SelectInfo); 61 | FText HandleStudiosComboBoxContentText() const; 62 | 63 | void OpenStudioAndGameSelector(); 64 | 65 | void OnOrganizationMenuItemClickedIos(FGameAnalyticsTargetSettingsCustomization::ORGANIZATION OrganizationItem) const; 66 | void OnStudioMenuItemClickedIos(FGameAnalyticsTargetSettingsCustomization::STUDIO StudioItem) const; 67 | void OnGameMenuItemClickedIos(FGameAnalyticsTargetSettingsCustomization::GAME GameItem) const; 68 | void OnOrganizationMenuItemClickedAndroid(FGameAnalyticsTargetSettingsCustomization::ORGANIZATION OrganizationItem) const; 69 | void OnStudioMenuItemClickedAndroid(FGameAnalyticsTargetSettingsCustomization::STUDIO StudioItem) const; 70 | void OnGameMenuItemClickedAndroid(FGameAnalyticsTargetSettingsCustomization::GAME GameItem) const; 71 | void OnOrganizationMenuItemClickedMac(FGameAnalyticsTargetSettingsCustomization::ORGANIZATION OrganizationItem) const; 72 | void OnStudioMenuItemClickedMac(FGameAnalyticsTargetSettingsCustomization::STUDIO StudioItem) const; 73 | void OnGameMenuItemClickedMac(FGameAnalyticsTargetSettingsCustomization::GAME GameItem) const; 74 | void OnOrganizationMenuItemClickedWindows(FGameAnalyticsTargetSettingsCustomization::ORGANIZATION OrganizationItem) const; 75 | void OnStudioMenuItemClickedWindows(FGameAnalyticsTargetSettingsCustomization::STUDIO StudioItem) const; 76 | void OnGameMenuItemClickedWindows(FGameAnalyticsTargetSettingsCustomization::GAME GameItem) const; 77 | void OnOrganizationMenuItemClickedLinux(FGameAnalyticsTargetSettingsCustomization::ORGANIZATION OrganizationItem) const; 78 | void OnStudioMenuItemClickedLinux(FGameAnalyticsTargetSettingsCustomization::STUDIO StudioItem) const; 79 | void OnGameMenuItemClickedLinux(FGameAnalyticsTargetSettingsCustomization::GAME GameItem) const; 80 | void OnOrganizationMenuItemClickedHtml5(FGameAnalyticsTargetSettingsCustomization::ORGANIZATION OrganizationItem) const; 81 | void OnStudioMenuItemClickedHtml5(FGameAnalyticsTargetSettingsCustomization::STUDIO StudioItem) const; 82 | void OnGameMenuItemClickedHtml5(FGameAnalyticsTargetSettingsCustomization::GAME GameItem) const; 83 | 84 | public: 85 | static FGameAnalyticsTargetSettingsCustomization& getInstance() 86 | { 87 | static FGameAnalyticsTargetSettingsCustomization instance; // Guaranteed to be destroyed. 88 | // Instantiated on first use. 89 | return instance; 90 | } 91 | 92 | TArray Organizations; 93 | ORGANIZATION SelectedOrganizationIos; 94 | STUDIO SelectedStudioIos; 95 | GAME SelectedGameIos; 96 | ORGANIZATION SelectedOrganizationAndroid; 97 | STUDIO SelectedStudioAndroid; 98 | GAME SelectedGameAndroid; 99 | ORGANIZATION SelectedOrganizationMac; 100 | STUDIO SelectedStudioMac; 101 | GAME SelectedGameMac; 102 | ORGANIZATION SelectedOrganizationWindows; 103 | STUDIO SelectedStudioWindows; 104 | GAME SelectedGameWindows; 105 | ORGANIZATION SelectedOrganizationLinux; 106 | STUDIO SelectedStudioLinux; 107 | GAME SelectedGameLinux; 108 | ORGANIZATION SelectedOrganizationHtml5; 109 | STUDIO SelectedStudioHtml5; 110 | GAME SelectedGameHtml5; 111 | 112 | private: 113 | FGameAnalyticsTargetSettingsCustomization() {}; 114 | 115 | FGameAnalyticsTargetSettingsCustomization(FGameAnalyticsTargetSettingsCustomization const&) = delete; 116 | void operator=(FGameAnalyticsTargetSettingsCustomization const&) = delete; 117 | 118 | FReply OpenSetupWizard(); 119 | FReply Login(); 120 | TSharedRef UpdateOrganizationsIos() const; 121 | TSharedRef UpdateStudiosIos() const; 122 | TSharedRef UpdateGamesIos() const; 123 | TSharedRef UpdateOrganizationsAndroid() const; 124 | TSharedRef UpdateStudiosAndroid() const; 125 | TSharedRef UpdateGamesAndroid() const; 126 | TSharedRef UpdateOrganizationsMac() const; 127 | TSharedRef UpdateStudiosMac() const; 128 | TSharedRef UpdateGamesMac() const; 129 | TSharedRef UpdateOrganizationsWindows() const; 130 | TSharedRef UpdateStudiosWindows() const; 131 | TSharedRef UpdateGamesWindows() const; 132 | TSharedRef UpdateOrganizationsLinux() const; 133 | TSharedRef UpdateStudiosLinux() const; 134 | TSharedRef UpdateGamesLinux() const; 135 | TSharedRef UpdateOrganizationsHtml5() const; 136 | TSharedRef UpdateStudiosHtml5() const; 137 | TSharedRef UpdateGamesHtml5() const; 138 | 139 | FORCEINLINE FString GetIniName() const { return FString::Printf(TEXT("%sDefaultEngine.ini"), *FPaths::SourceConfigDir()); } 140 | 141 | private: 142 | IDetailLayoutBuilder* SavedLayoutBuilder; 143 | 144 | FHttpModule* Http; 145 | bool bIsBusy; 146 | 147 | FName Username; 148 | FName Password; 149 | 150 | TSharedPtr >> StudiosComboBox; 151 | TArray< TSharedPtr > StudiosComboBoxString; 152 | }; 153 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/Android/GAWrapperAndroid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "GAWrapper.h" 6 | 7 | namespace gameanalytics 8 | { 9 | class GAWrapperAndroid: 10 | public GAWrapper 11 | { 12 | std::string CallStringMethod(std::string const& name); 13 | std::string ConvertJString(jstring str); 14 | 15 | virtual JNIEnv* GetJavaEnv(); 16 | virtual jclass GetGameAnalyticsClass(); 17 | 18 | public: 19 | 20 | GAWrapperAndroid(); 21 | virtual ~GAWrapperAndroid(); 22 | 23 | virtual void SetAvailableCustomDimensions01(std::vector const& list) override; 24 | virtual void SetAvailableCustomDimensions02(std::vector const& list) override; 25 | virtual void SetAvailableCustomDimensions03(std::vector const& list) override; 26 | 27 | virtual void SetAvailableResourceCurrencies(std::vector const& list) override; 28 | virtual void SetAvailableResourceItemTypes(std::vector const& list) override; 29 | 30 | virtual void SetSDKVersion(std::string const& version) override; 31 | virtual void SetGameEngineVersion(std::string const& version) override; 32 | 33 | virtual void SetBuild(std::string const& build) override; 34 | virtual void SetCustomUserId(std::string const& userId) override; 35 | virtual void SetExternalUserId(std::string const& extUserId) override; 36 | 37 | virtual std::string GetUserId() override; 38 | virtual std::string GetExternalUserId() override; 39 | 40 | virtual void SetAutoDetectAppVersion(bool flag) override; 41 | 42 | virtual void Initialize(std::string const& gamekey, std::string const& gamesecret) override; 43 | 44 | virtual void SetCustomDimension01(std::string const& customDimension) override; 45 | virtual void SetCustomDimension02(std::string const& customDimension) override; 46 | virtual void SetCustomDimension03(std::string const& customDimension) override; 47 | 48 | virtual void SetGlobalCustomEventFields(std::string const& customFields) override; 49 | virtual void SetEnabledManualSessionHandling (bool enabled) override; 50 | virtual void SetEnabledEventSubmission(bool enabled, bool doCacheLocally = false) override; 51 | 52 | virtual void StartSession() override; 53 | virtual void EndSession() override; 54 | 55 | virtual void AddBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const&cartType, std::string const& receipt, std::string const& fields, bool mergeFields) override; 56 | virtual void AddBusinessEventAndAutoFetchReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& fields, bool mergeFields) override; 57 | virtual void AddBusinessEventWithReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& store, std::string const& signature, std::string const& fields, bool mergeFields) override; 58 | 59 | virtual void AddResourceEvent(EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& fields, bool mergeFields) override; 60 | 61 | virtual void AddProgressionEvent(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, std::string const& fields, bool mergeFields) override; 62 | virtual void AddProgressionEventWithScore(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, int score, std::string const& fields, bool mergeFields) override; 63 | 64 | virtual void AddDesignEvent(std::string const& eventID, std::string const& fields, bool mergeFields) override; 65 | virtual void AddDesignEventWithValue(std::string const& eventId, float value, std::string const& fields, bool mergeFields) override; 66 | 67 | virtual void AddErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& fields, bool mergeFields) override; 68 | 69 | virtual void AddAdEventWithDuration(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, int64_t duration, std::string const& fields, bool mergeFields) override; 70 | virtual void AddAdEventWithReason(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, EGAAdError noAdReason, std::string const& fields, bool mergeFields) override; 71 | virtual void AddAdEvent(EGAAdAction adAction, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, std::string const& fields, bool mergeFields) override; 72 | 73 | virtual void SetInfoLog(bool enabled) override; 74 | 75 | virtual void SetVerboseLog(bool enabled) override; 76 | 77 | virtual void SetEnabledErrorReporting(bool flag) override; 78 | 79 | // ----------------------- REMOTE CONFIGS ---------------------- // 80 | virtual std::string GetRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue) override; 81 | 82 | virtual double GetRemoteConfigsValueAsNumber(std::string const& key, double defaultValue) override; 83 | 84 | virtual std::string GetRemoteConfigsValueAsJson(std::string const& key) override; 85 | 86 | virtual bool IsRemoteConfigsReady() override; 87 | 88 | virtual std::string GetRemoteConfigsContentAsString() override; 89 | 90 | virtual std::string GetABTestingId() override; 91 | 92 | virtual std::string GetABTestingVariantId() override; 93 | 94 | ///// HEALTH 95 | 96 | virtual void EnableSDKInitEvent(bool flag) override; 97 | 98 | virtual void EnableFpsHistogram(FPSTracker tracker, bool flag) override; 99 | 100 | virtual void EnableMemoryHistogram(bool flag) override; 101 | 102 | virtual void EnableHealthHardwareInfo(bool flag) override; 103 | 104 | //////////////////////////////////////////////////////// 105 | 106 | virtual int64_t GetElapsedSessionTime() override; 107 | 108 | virtual int64_t GetElapsedTimeForPreviousSession() override; 109 | 110 | virtual int64_t GetElapsedTimeFromAllSessions() override; 111 | 112 | //////////////////////////////////////////////////////// 113 | 114 | virtual void EnableAdvertisingId(bool value) override; 115 | 116 | virtual void OnQuit() override; 117 | 118 | virtual void SetWritablePath(std::string const& path) override; 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/GameAnalyticsModule.cpp: -------------------------------------------------------------------------------- 1 | #include "GameAnalyticsModule.h" 2 | #include "GameAnalytics.h" 3 | #include "GameAnalyticsProvider.h" 4 | #include "Misc/ConfigCacheIni.h" 5 | 6 | #define GA_PROJECT_SETTINGS TEXT("/Script/GameAnalyticsEditor.GameAnalyticsProjectSettings") 7 | 8 | IMPLEMENT_MODULE( FGameAnalyticsModule, GameAnalytics ) 9 | 10 | FGameAnalyticsModule::FGameAnalyticsProjectSettings::PlatformInfo FGameAnalyticsModule::FGameAnalyticsProjectSettings::GetActivePlatform() const 11 | { 12 | #if PLATFORM_IOS 13 | return iOS; 14 | #elif PLATFORM_ANDROID 15 | return Android; 16 | #elif PLATFORM_MAC 17 | return Mac; 18 | #elif PLATFORM_WINDOWS 19 | return Windows; 20 | #elif PLATFORM_LINUX 21 | return Linux; 22 | #else 23 | return {}; 24 | #endif 25 | } 26 | 27 | void FGameAnalyticsModule::StartupModule() 28 | { 29 | UE_LOG(LogGameAnalytics, Display, TEXT("FGameAnalyticsModule Constructor")); 30 | 31 | GameAnalytics = NewObject(GetTransientPackage(), UGameAnalytics::StaticClass(), "GameAnalytics", EObjectFlags::RF_Standalone); 32 | GameAnalytics->AddToRoot(); 33 | 34 | GameAnalyticsProvider = MakeShareable(new FGameAnalyticsProvider(GameAnalytics)); 35 | } 36 | 37 | void FGameAnalyticsModule::ShutdownModule() 38 | { 39 | if (!GExitPurge && IsValid(GameAnalytics)) 40 | { 41 | GameAnalytics->RemoveFromRoot(); 42 | } 43 | 44 | GameAnalytics = nullptr; 45 | } 46 | 47 | #if (ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 13) || (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 0) 48 | TSharedPtr FGameAnalyticsModule::CreateAnalyticsProvider(const FAnalyticsProviderConfigurationDelegate& GetConfigValue) const 49 | { 50 | return GameAnalyticsProvider; 51 | } 52 | #else 53 | TSharedPtr FGameAnalyticsModule::CreateAnalyticsProvider(const FAnalytics::FProviderConfigurationDelegate& GetConfigValue) const 54 | { 55 | return GameAnalyticsProvider; 56 | } 57 | #endif 58 | 59 | FGameAnalyticsModule::FGameAnalyticsProjectSettings FGameAnalyticsModule::LoadProjectSettings() 60 | { 61 | FGameAnalyticsProjectSettings Settings; 62 | 63 | if (!GConfig) return Settings; 64 | 65 | // Android 66 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("AndroidGameKey"), Settings.Android.GameKey, GetIniName())) 67 | { 68 | Settings.Android.GameKey = TEXT(""); 69 | } 70 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("AndroidSecretKey"), Settings.Android.SecretKey, GetIniName())) 71 | { 72 | Settings.Android.SecretKey = TEXT(""); 73 | } 74 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("AndroidBuild"), Settings.Android.Build, GetIniName())) 75 | { 76 | Settings.Android.Build = TEXT("0.1"); 77 | } 78 | 79 | // iOS 80 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("IosGameKey"), Settings.iOS.GameKey, GetIniName())) 81 | { 82 | Settings.iOS.GameKey = TEXT(""); 83 | } 84 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("IosSecretKey"), Settings.iOS.SecretKey, GetIniName())) 85 | { 86 | Settings.iOS.SecretKey = TEXT(""); 87 | } 88 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("IosBuild"), Settings.iOS.Build, GetIniName())) 89 | { 90 | Settings.iOS.Build = TEXT("0.1"); 91 | } 92 | 93 | // MacOS 94 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("MacGameKey"), Settings.Mac.GameKey, GetIniName())) 95 | { 96 | Settings.Mac.GameKey = TEXT(""); 97 | } 98 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("MacSecretKey"), Settings.Mac.SecretKey, GetIniName())) 99 | { 100 | Settings.Mac.SecretKey = TEXT(""); 101 | } 102 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("MacBuild"), Settings.Mac.Build, GetIniName())) 103 | { 104 | Settings.Mac.Build = TEXT("0.1"); 105 | } 106 | 107 | // Windows 108 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("WindowsGameKey"), Settings.Windows.GameKey, GetIniName())) 109 | { 110 | Settings.Windows.GameKey = TEXT(""); 111 | } 112 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("WindowsSecretKey"), Settings.Windows.SecretKey, GetIniName())) 113 | { 114 | Settings.Windows.SecretKey = TEXT(""); 115 | } 116 | if(!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("WindowsBuild"), Settings.Windows.Build, GetIniName())) 117 | { 118 | Settings.Windows.Build = TEXT("0.1"); 119 | } 120 | 121 | // Linux 122 | if (!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("LinuxGameKey"), Settings.Linux.GameKey, GetIniName())) 123 | { 124 | Settings.Linux.GameKey = TEXT(""); 125 | } 126 | if (!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("LinuxSecretKey"), Settings.Linux.SecretKey, GetIniName())) 127 | { 128 | Settings.Linux.SecretKey = TEXT(""); 129 | } 130 | if (!GConfig->GetString(GA_PROJECT_SETTINGS, TEXT("LinuxBuild"), Settings.Linux.Build, GetIniName())) 131 | { 132 | Settings.Linux.Build = TEXT("0.1"); 133 | } 134 | 135 | // Global options 136 | if(!GConfig->GetBool(GA_PROJECT_SETTINGS, TEXT("UseManualSessionHandling"), Settings.UseManualSessionHandling, GetIniName())) 137 | { 138 | Settings.UseManualSessionHandling = false; 139 | } 140 | if(!GConfig->GetBool(GA_PROJECT_SETTINGS, TEXT("AutoDetectAppVersion"), Settings.AutoDetectAppVersion, GetIniName())) 141 | { 142 | Settings.AutoDetectAppVersion = false; 143 | } 144 | if (!GConfig->GetBool(GA_PROJECT_SETTINGS, TEXT("DisableDeviceInfo"), Settings.DisableDeviceInfo, GetIniName())) 145 | { 146 | Settings.DisableDeviceInfo = false; 147 | } 148 | if (!GConfig->GetBool(GA_PROJECT_SETTINGS, TEXT("UseErrorReporting"), Settings.UseErrorReporting, GetIniName())) 149 | { 150 | Settings.UseErrorReporting = true; 151 | } 152 | if(!GConfig->GetBool(GA_PROJECT_SETTINGS, TEXT("InfoLogBuild"), Settings.InfoLogBuild, GetIniName())) 153 | { 154 | Settings.InfoLogBuild = true; 155 | } 156 | if(!GConfig->GetBool(GA_PROJECT_SETTINGS, TEXT("VerboseLogBuild"), Settings.VerboseLogBuild, GetIniName())) 157 | { 158 | Settings.VerboseLogBuild = false; 159 | } 160 | 161 | GConfig->GetArray(GA_PROJECT_SETTINGS, TEXT("+CustomDimensions01"), Settings.CustomDimensions01, GetIniName()); 162 | GConfig->GetArray(GA_PROJECT_SETTINGS, TEXT("+CustomDimensions02"), Settings.CustomDimensions02, GetIniName()); 163 | GConfig->GetArray(GA_PROJECT_SETTINGS, TEXT("+CustomDimensions03"), Settings.CustomDimensions03, GetIniName()); 164 | GConfig->GetArray(GA_PROJECT_SETTINGS, TEXT("+ResourceCurrencies"), Settings.ResourceCurrencies, GetIniName()); 165 | GConfig->GetArray(GA_PROJECT_SETTINGS, TEXT("+ResourceItemTypes"), Settings.ResourceItemTypes, GetIniName()); 166 | 167 | return Settings; 168 | } 169 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/GA-SDK-CPP/GameAnalytics/GameAnalytics.h: -------------------------------------------------------------------------------- 1 | // 2 | // GA-SDK-CPP 3 | // Copyright 2018 GameAnalytics C++ SDK. All rights reserved. 4 | // 5 | 6 | #pragma once 7 | 8 | #include "GameAnalytics/GATypes.h" 9 | 10 | namespace gameanalytics 11 | { 12 | class GameAnalytics 13 | { 14 | public: 15 | 16 | /** 17 | * @brief: sets the available custom dimensions for index 1, needs to be called before initialization 18 | * 19 | * @param customDimensions: valid values to be used as customDimension0 20 | */ 21 | static void configureAvailableCustomDimensions01(const StringVector &customDimensions); 22 | 23 | /** 24 | * @brief: sets the available custom dimensions for index 2, needs to be called before initialization 25 | * 26 | * @param customDimensions: valid values 27 | */ 28 | static void configureAvailableCustomDimensions02(const StringVector &customDimensions); 29 | 30 | /** 31 | * @brief: sets the available custom dimensions for index 3, needs to be called before initialization 32 | * 33 | * @param customDimensions: valid values to be used as customDimension3 34 | */ 35 | static void configureAvailableCustomDimensions03(const StringVector &customDimensions); 36 | 37 | /** 38 | * @brief 39 | * 40 | * @param resourceCurrencies 41 | */ 42 | static void configureAvailableResourceCurrencies(const StringVector &resourceCurrencies); 43 | static void configureAvailableResourceItemTypes(const StringVector &resourceItemTypes); 44 | 45 | static void configureBuild(std::string const& build); 46 | static void configureWritablePath(std::string const& writablePath); 47 | static void configureBuildPlatform(std::string const& platform); 48 | static void configureCustomLogHandler(const LogHandler &logHandler); 49 | static void disableDeviceInfo(); 50 | static void configureDeviceModel(std::string const& deviceModel); 51 | static void configureDeviceManufacturer(std::string const& deviceManufacturer); 52 | 53 | // the version of SDK code used in an engine. Used for sdk_version field. 54 | // !! if set then it will override the SdkWrapperVersion. 55 | // example "unity 4.6.9" 56 | static void configureSdkGameEngineVersion(std::string const& sdkGameEngineVersion); 57 | // the version of the game engine (if used and version is available) 58 | static void configureGameEngineVersion(std::string const& engineVersion); 59 | 60 | static void configureUserId(std::string const& uId); 61 | 62 | static void configureExternalUserId(std::string const& extId); 63 | 64 | // initialize - starting SDK (need configuration before starting) 65 | static void initialize(std::string const& gameKey, std::string const& gameSecret); 66 | 67 | // add events 68 | static void addBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& customFields = "", bool mergeFields = false); 69 | 70 | static void addResourceEvent(EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& customFields = "", bool mergeFields = false); 71 | 72 | static void addProgressionEvent(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02 = "", std::string const& progression03 = "", std::string const& customFields = "", bool mergeFields = false); 73 | static void addProgressionEvent(EGAProgressionStatus progressionStatus, int score, std::string const& progression01, std::string const& progression02 = "", std::string const& progression03 = "", std::string const& customFields = "", bool mergeFields = false); 74 | 75 | static void addDesignEvent(std::string const& eventId, std::string const& customFields = "", bool mergeFields = false); 76 | static void addDesignEvent(std::string const& eventId, double value, std::string const& customFields = "", bool mergeFields = false); 77 | 78 | static void addErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& customFields = "", bool mergeFields = false); 79 | 80 | // set calls can be changed at any time (pre- and post-initialize) 81 | // some calls only work after a configure is called (setCustomDimension) 82 | static void setEnabledInfoLog(bool flag); 83 | static void setEnabledVerboseLog(bool flag); 84 | static void setEnabledManualSessionHandling(bool flag); 85 | static void setEnabledErrorReporting(bool flag); 86 | static void setEnabledEventSubmission(bool flag); 87 | static void setCustomDimension01(std::string const& dimension01); 88 | static void setCustomDimension02(std::string const& dimension02); 89 | static void setCustomDimension03(std::string const& dimension03); 90 | 91 | /////////// HEALTH EVENT 92 | 93 | static void enableSDKInitEvent(bool value = true); 94 | static void enableMemoryHistogram(bool value = true); 95 | static void enableFPSHistogram(FPSTracker fpsTracker, bool value = true); 96 | static void enableHardwareTracking(bool value = true); 97 | 98 | /////////// 99 | 100 | static void setGlobalCustomEventFields(std::string const& customFields); 101 | 102 | static void startSession(); 103 | static void endSession(); 104 | 105 | static std::string getRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue = ""); 106 | static std::string getRemoteConfigsValueAsJson(std::string const& key); 107 | 108 | 109 | static bool isRemoteConfigsReady(); 110 | static void addRemoteConfigsListener(const std::shared_ptr &listener); 111 | static void removeRemoteConfigsListener(const std::shared_ptr &listener); 112 | 113 | static std::string getRemoteConfigsContentAsString(); 114 | 115 | static std::string getUserId(); 116 | static std::string getExternalUserId(); 117 | 118 | static std::string getABTestingId(); 119 | static std::string getABTestingVariantId(); 120 | 121 | static int64_t getElapsedSessionTime(); 122 | static int64_t getElapsedTimeFromAllSessions(); 123 | static int64_t getElapsedTimeForPreviousSession(); 124 | 125 | // game state changes 126 | // will affect how session is started / ended 127 | static void onResume(); 128 | static void onSuspend(); 129 | static void onQuit(); 130 | 131 | static bool isThreadEnding(); 132 | 133 | private: 134 | 135 | static bool _endThread; 136 | static bool isSdkReady(bool needsInitialized, bool warn = true, std::string const& message = ""); 137 | }; 138 | 139 | } // namespace gameanalytics 140 | -------------------------------------------------------------------------------- /GameAnalytics/Source/ThirdParty/lib/html5/GameAnalyticsUnreal.js: -------------------------------------------------------------------------------- 1 | var GameAnalyticsUnreal = { 2 | js_configureAvailableCustomDimensions01: function(list) 3 | { 4 | gameanalytics.GameAnalytics.configureAvailableCustomDimensions01(JSON.parse(Pointer_stringify(list))); 5 | }, 6 | js_configureAvailableCustomDimensions02: function(list) 7 | { 8 | gameanalytics.GameAnalytics.configureAvailableCustomDimensions02(JSON.parse(Pointer_stringify(list))); 9 | }, 10 | js_configureAvailableCustomDimensions03: function(list) 11 | { 12 | gameanalytics.GameAnalytics.configureAvailableCustomDimensions03(JSON.parse(Pointer_stringify(list))); 13 | }, 14 | js_configureAvailableResourceCurrencies: function(list) 15 | { 16 | gameanalytics.GameAnalytics.configureAvailableResourceCurrencies(JSON.parse(Pointer_stringify(list))); 17 | }, 18 | js_configureAvailableResourceItemTypes: function(list) 19 | { 20 | gameanalytics.GameAnalytics.configureAvailableResourceItemTypes(JSON.parse(Pointer_stringify(list))); 21 | }, 22 | js_configureSdkGameEngineVersion: function(unitySdkVersion) 23 | { 24 | gameanalytics.GameAnalytics.configureSdkGameEngineVersion(Pointer_stringify(unitySdkVersion)); 25 | }, 26 | js_configureGameEngineVersion: function(unityEngineVersion) 27 | { 28 | gameanalytics.GameAnalytics.configureGameEngineVersion(Pointer_stringify(unityEngineVersion)); 29 | }, 30 | js_configureBuild: function(build) 31 | { 32 | gameanalytics.GameAnalytics.configureBuild(Pointer_stringify(build)); 33 | }, 34 | js_configureUserId: function(userId) 35 | { 36 | gameanalytics.GameAnalytics.configureUserId(Pointer_stringify(userId)); 37 | }, 38 | js_initialize: function(gamekey, gamesecret) 39 | { 40 | gameanalytics.GameAnalytics.initialize(Pointer_stringify(gamekey), Pointer_stringify(gamesecret)); 41 | }, 42 | js_setCustomDimension01: function(customDimension) 43 | { 44 | gameanalytics.GameAnalytics.setCustomDimension01(Pointer_stringify(customDimension)); 45 | }, 46 | js_setCustomDimension02: function(customDimension) 47 | { 48 | gameanalytics.GameAnalytics.setCustomDimension02(Pointer_stringify(customDimension)); 49 | }, 50 | js_setCustomDimension03: function(customDimension) 51 | { 52 | gameanalytics.GameAnalytics.setCustomDimension03(Pointer_stringify(customDimension)); 53 | }, 54 | js_addBusinessEvent: function(currency, amount, itemType, itemId, cartType, fields) 55 | { 56 | gameanalytics.GameAnalytics.addBusinessEvent(Pointer_stringify(currency), amount, Pointer_stringify(itemType), Pointer_stringify(itemId), Pointer_stringify(cartType)/*, JSON.parse(Pointer_stringify(fields))*/); 57 | }, 58 | js_addResourceEvent: function(flowType, currency, amount, itemType, itemId, fields) 59 | { 60 | gameanalytics.GameAnalytics.addResourceEvent(flowType, Pointer_stringify(currency), amount, Pointer_stringify(itemType), Pointer_stringify(itemId)/*, JSON.parse(Pointer_stringify(fields))*/); 61 | }, 62 | js_addProgressionEvent: function(progressionStatus, progression01, progression02, progression03, fields) 63 | { 64 | gameanalytics.GameAnalytics.addProgressionEvent(progressionStatus, Pointer_stringify(progression01), Pointer_stringify(progression02), Pointer_stringify(progression03)/*, JSON.parse(Pointer_stringify(fields))*/); 65 | }, 66 | js_addProgressionEventWithScore: function(progressionStatus, progression01, progression02, progression03, score, fields) 67 | { 68 | gameanalytics.GameAnalytics.addProgressionEvent(progressionStatus, Pointer_stringify(progression01), Pointer_stringify(progression02), Pointer_stringify(progression03), score/*, JSON.parse(Pointer_stringify(fields))*/); 69 | }, 70 | js_addDesignEvent: function(eventId, fields) 71 | { 72 | gameanalytics.GameAnalytics.addDesignEvent(Pointer_stringify(eventId)/*, JSON.parse(Pointer_stringify(fields))*/); 73 | }, 74 | js_addDesignEventWithValue: function(eventId, value, fields) 75 | { 76 | gameanalytics.GameAnalytics.addDesignEvent(Pointer_stringify(eventId), value/*, JSON.parse(Pointer_stringify(fields))*/); 77 | }, 78 | js_addErrorEvent: function(severity, message, fields) 79 | { 80 | gameanalytics.GameAnalytics.addErrorEvent(severity, Pointer_stringify(message)/*, JSON.parse(Pointer_stringify(fields))*/); 81 | }, 82 | js_setEnabledInfoLog: function(enabled) 83 | { 84 | gameanalytics.GameAnalytics.setEnabledInfoLog(enabled); 85 | }, 86 | js_setEnabledVerboseLog: function(enabled) 87 | { 88 | gameanalytics.GameAnalytics.setEnabledVerboseLog(enabled); 89 | }, 90 | js_setManualSessionHandling: function(enabled) 91 | { 92 | gameanalytics.GameAnalytics.setEnabledManualSessionHandling(enabled); 93 | }, 94 | js_startSession: function() 95 | { 96 | gameanalytics.GameAnalytics.startSession(); 97 | }, 98 | js_endSession: function() 99 | { 100 | gameanalytics.GameAnalytics.endSession(); 101 | }, 102 | js_onStop: function() 103 | { 104 | gameanalytics.GameAnalytics.onStop(); 105 | }, 106 | js_getRemoteConfigsValueAsString: function(key) 107 | { 108 | var returnStr = gameanalytics.GameAnalytics.getRemoteConfigsValueAsString(Pointer_stringify(key)); 109 | var bufferSize = lengthBytesUTF8(returnStr) + 1; 110 | var buffer = _malloc(bufferSize); 111 | stringToUTF8(returnStr, buffer, bufferSize); 112 | return buffer; 113 | }, 114 | js_getRemoteConfigsValueAsStringWithDefaultValue: function(key, defaultValue) 115 | { 116 | var returnStr = gameanalytics.GameAnalytics.getRemoteConfigsValueAsString(Pointer_stringify(key), Pointer_stringify(defaultValue)); 117 | var bufferSize = lengthBytesUTF8(returnStr) + 1; 118 | var buffer = _malloc(bufferSize); 119 | stringToUTF8(returnStr, buffer, bufferSize); 120 | return buffer; 121 | }, 122 | js_isRemoteConfigsReady: function() 123 | { 124 | return gameanalytics.GameAnalytics.isRemoteConfigsReady(); 125 | }, 126 | js_getRemoteConfigsContentAsString: function() 127 | { 128 | var returnStr = gameanalytics.GameAnalytics.getRemoteConfigsContentAsString(); 129 | var bufferSize = lengthBytesUTF8(returnStr) + 1; 130 | var buffer = _malloc(bufferSize); 131 | stringToUTF8(returnStr, buffer, bufferSize); 132 | return buffer; 133 | }, 134 | js_getABTestingId: function() 135 | { 136 | var returnStr = gameanalytics.GameAnalytics.getABTestingId(); 137 | var bufferSize = lengthBytesUTF8(returnStr) + 1; 138 | var buffer = _malloc(bufferSize); 139 | stringToUTF8(returnStr, buffer, bufferSize); 140 | return buffer; 141 | }, 142 | js_getABTestingVariantId: function() 143 | { 144 | var returnStr = gameanalytics.GameAnalytics.getABTestingVariantId(); 145 | var bufferSize = lengthBytesUTF8(returnStr) + 1; 146 | var buffer = _malloc(bufferSize); 147 | stringToUTF8(returnStr, buffer, bufferSize); 148 | return buffer; 149 | } 150 | }; 151 | 152 | mergeInto(LibraryManager.library, GameAnalyticsUnreal); 153 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalyticsEditor/Public/GameAnalyticsProjectSettings.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. 2 | #pragma once 3 | 4 | #include "GameAnalyticsProjectSettings.generated.h" 5 | 6 | UCLASS(config=Engine, defaultconfig) 7 | class UGameAnalyticsProjectSettings : public UObject 8 | { 9 | GENERATED_UCLASS_BODY() 10 | 11 | public: 12 | 13 | // Game Key 14 | UPROPERTY(Config, EditAnywhere, Category=IosSetup, Meta=(ToolTip="Your GameAnalytics iOS Game Key - copy/paste from the GA website or log in to autofill it.")) 15 | FString IosGameKey; 16 | 17 | // Secret Key 18 | UPROPERTY(Config, EditAnywhere, Category=IosSetup, Meta=(ToolTip="Your GameAnalytics iOS Secret Key - copy/paste from the GA website or log in to autofill it.")) 19 | FString IosSecretKey; 20 | 21 | // Build 22 | UPROPERTY(Config, EditAnywhere, Category = IosSetup, Meta=(ToolTip="The current version of the iOS game. Updating the build name for each test version of the game will allow you to filter by build when viewing your data on the GA website.")) 23 | FString IosBuild = "0.1"; 24 | 25 | // Game Key 26 | UPROPERTY(Config, EditAnywhere, Category=AndroidSetup, Meta=(ToolTip="Your GameAnalytics Android Game Key - copy/paste from the GA website or log in to autofill it.")) 27 | FString AndroidGameKey; 28 | 29 | // Secret Key 30 | UPROPERTY(Config, EditAnywhere, Category=AndroidSetup, Meta=(ToolTip="Your GameAnalytics Android Secret Key - copy/paste from the GA website or log in to autofill it.")) 31 | FString AndroidSecretKey; 32 | 33 | // Build 34 | UPROPERTY(Config, EditAnywhere, Category = AndroidSetup, Meta=(ToolTip="The current version of the game. Updating the build name for each test version of the game will allow you to filter by build when viewing your data on the GA website.")) 35 | FString AndroidBuild = "0.1"; 36 | 37 | // Game Key 38 | UPROPERTY(Config, EditAnywhere, Category=MacSetup, Meta=(ToolTip="Your GameAnalytics Mac Game Key - copy/paste from the GA website or log in to autofill it.")) 39 | FString MacGameKey; 40 | 41 | // Secret Key 42 | UPROPERTY(Config, EditAnywhere, Category=MacSetup, Meta=(ToolTip="Your GameAnalytics Mac Secret Key - copy/paste from the GA website or log in to autofill it.")) 43 | FString MacSecretKey; 44 | 45 | // Build 46 | UPROPERTY(Config, EditAnywhere, Category = MacSetup, Meta=(ToolTip="The current version of the Mac game. Updating the build name for each test version of the game will allow you to filter by build when viewing your data on the GA website.")) 47 | FString MacBuild = "0.1"; 48 | 49 | // Game Key 50 | UPROPERTY(Config, EditAnywhere, Category=WindowsSetup, Meta=(ToolTip="Your GameAnalytics Windows Game Key - copy/paste from the GA website or log in to autofill it.")) 51 | FString WindowsGameKey; 52 | 53 | // Secret Key 54 | UPROPERTY(Config, EditAnywhere, Category=WindowsSetup, Meta=(ToolTip="Your GameAnalytics Windows Secret Key - copy/paste from the GA website or log in to autofill it.")) 55 | FString WindowsSecretKey; 56 | 57 | // Build 58 | UPROPERTY(Config, EditAnywhere, Category = WindowsSetup, Meta=(ToolTip="The current version of the Windows game. Updating the build name for each test version of the game will allow you to filter by build when viewing your data on the GA website.")) 59 | FString WindowsBuild = "0.1"; 60 | 61 | // Game Key 62 | UPROPERTY(Config, EditAnywhere, Category = LinuxSetup, Meta = (ToolTip = "Your GameAnalytics Linux Game Key - copy/paste from the GA website or log in to autofill it.")) 63 | FString LinuxGameKey; 64 | 65 | // Secret Key 66 | UPROPERTY(Config, EditAnywhere, Category = LinuxSetup, Meta = (ToolTip = "Your GameAnalytics Linux Secret Key - copy/paste from the GA website or log in to autofill it.")) 67 | FString LinuxSecretKey; 68 | 69 | // Build 70 | UPROPERTY(Config, EditAnywhere, Category = LinuxSetup, Meta = (ToolTip = "The current version of the Linux game. Updating the build name for each test version of the game will allow you to filter by build when viewing your data on the GA website.")) 71 | FString LinuxBuild = "0.1"; 72 | 73 | // Game Key 74 | UPROPERTY(Config, EditAnywhere, Category = Html5Setup, Meta = (ToolTip = "Your GameAnalytics HTML5 Game Key - copy/paste from the GA website or log in to autofill it.")) 75 | FString Html5GameKey; 76 | 77 | // Secret Key 78 | UPROPERTY(Config, EditAnywhere, Category = Html5Setup, Meta = (ToolTip = "Your GameAnalytics HTML5 Secret Key - copy/paste from the GA website or log in to autofill it.")) 79 | FString Html5SecretKey; 80 | 81 | // Build 82 | UPROPERTY(Config, EditAnywhere, Category = Html5Setup, Meta = (ToolTip = "The current version of the HTML5 game. Updating the build name for each test version of the game will allow you to filter by build when viewing your data on the GA website.")) 83 | FString Html5Build = "0.1"; 84 | 85 | // Custom Dimensions 01 86 | UPROPERTY(Config, EditAnywhere, Category=CustomDimensions, Meta=(ToolTip="List of custom dimensions 01.")) 87 | TArray CustomDimensions01; 88 | 89 | // Custom Dimensions 02 90 | UPROPERTY(Config, EditAnywhere, Category=CustomDimensions, Meta=(ToolTip="List of custom dimensions 02.")) 91 | TArray CustomDimensions02; 92 | 93 | // Custom Dimensions 03 94 | UPROPERTY(Config, EditAnywhere, Category=CustomDimensions, Meta=(ToolTip="List of custom dimensions 03.")) 95 | TArray CustomDimensions03; 96 | 97 | // Resource Currencies 98 | UPROPERTY(Config, EditAnywhere, Category=ResourceTypes, Meta=(ToolTip="List of Resource Currencies.")) 99 | TArray ResourceCurrencies; 100 | 101 | // Resource Item Types 102 | UPROPERTY(Config, EditAnywhere, Category=ResourceTypes, Meta=(ToolTip="List of Resource Item Types.")) 103 | TArray ResourceItemTypes; 104 | 105 | // Use custom id 106 | UPROPERTY(Config, EditAnywhere, Category=Advanced, Meta=(ToolTip="Use manual session handling. Manually choose when to end and start a new session. Note initializing of the SDK will automatically start the first session.")) 107 | bool UseManualSessionHandling = false; 108 | 109 | // Auto detect app version for build field (only Android and iOS) 110 | UPROPERTY(Config, EditAnywhere, Category=Advanced, Meta=(ToolTip="Auto detect app version to use for build field (only for Android and iOS).")) 111 | bool AutoDetectAppVersion = false; 112 | 113 | // Disable device info (only Mac, Windows and Linux) 114 | UPROPERTY(Config, EditAnywhere, Category = Advanced, Meta = (ToolTip = "Disable device info (only Mac, Windows and Linux).")) 115 | bool DisableDeviceInfo = false; 116 | 117 | // Use Error Reports 118 | UPROPERTY(Config, EditAnywhere, Category = Advanced, Meta = (ToolTip = "Use automatic error reporting.")) 119 | bool UseErrorReporting = true; 120 | 121 | // Submit Errors 122 | //UPROPERTY(Config, EditAnywhere, Category=Advanced) 123 | //bool SubmitErrors = true; 124 | 125 | // Submit Average Frames Per Second 126 | //UPROPERTY(Config, EditAnywhere, Category=Advanced) 127 | //bool SubmitAverageFPS = true; 128 | 129 | // Submit Critical Frames Per Second 130 | //UPROPERTY(Config, EditAnywhere, Category=Advanced) 131 | //bool SubmitCriticalFPS = true; 132 | 133 | // Info Log Editor 134 | //UPROPERTY(Config, EditAnywhere, Category=Debug) 135 | //bool InfoLogEditor = true; 136 | 137 | // Info Log Build 138 | UPROPERTY(Config, EditAnywhere, Category=Debug, Meta=(ToolTip="Show info messages from GA in builds (f.x. Xcode for iOS).")) 139 | bool InfoLogBuild = true; 140 | 141 | // Verbose Log Build 142 | UPROPERTY(Config, EditAnywhere, Category=Debug, Meta=(ToolTip="Show full info messages from GA in builds (f.x. Xcode for iOS). Noet that this option includes long JSON messages sent to the server.")) 143 | bool VerboseLogBuild = false; 144 | }; 145 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/Desktop/GAWrapperCpp.cpp: -------------------------------------------------------------------------------- 1 | #include "GAWrapperCpp.h" 2 | #include "GameAnalytics/GameAnalytics.h" 3 | 4 | namespace gameanalytics 5 | { 6 | void GAWrapperCpp::SetAvailableCustomDimensions01(const std::vector& list) { 7 | GameAnalytics::configureAvailableCustomDimensions01(list); 8 | } 9 | 10 | void GAWrapperCpp::SetAvailableCustomDimensions02(const std::vector& list) { 11 | GameAnalytics::configureAvailableCustomDimensions02(list); 12 | } 13 | 14 | void GAWrapperCpp::SetAvailableCustomDimensions03(const std::vector& list) { 15 | GameAnalytics::configureAvailableCustomDimensions03(list); 16 | } 17 | 18 | void GAWrapperCpp::SetAvailableResourceCurrencies(const std::vector& list) { 19 | GameAnalytics::configureAvailableResourceCurrencies(list); 20 | } 21 | 22 | void GAWrapperCpp::SetAvailableResourceItemTypes(const std::vector& list) { 23 | GameAnalytics::configureAvailableResourceItemTypes(list); 24 | } 25 | 26 | void GAWrapperCpp::SetBuild(std::string const& build) { 27 | GameAnalytics::configureBuild(build); 28 | } 29 | 30 | void GAWrapperCpp::SetAutoDetectAppVersion(bool flag) { 31 | (void)flag; 32 | return; 33 | } 34 | 35 | void GAWrapperCpp::SetCustomUserId(std::string const& userId) { 36 | GameAnalytics::configureUserId(userId); 37 | } 38 | 39 | void GAWrapperCpp::SetSDKVersion(std::string const& gameEngineSdkVersion) { 40 | GameAnalytics::configureSdkGameEngineVersion(gameEngineSdkVersion); 41 | } 42 | 43 | void GAWrapperCpp::SetGameEngineVersion(std::string const& gameEngineVersion) { 44 | GameAnalytics::configureGameEngineVersion(gameEngineVersion); 45 | } 46 | 47 | void GAWrapperCpp::Initialize(std::string const& gameKey, std::string const& gameSecret) { 48 | GameAnalytics::initialize(gameKey, gameSecret); 49 | } 50 | 51 | void GAWrapperCpp::AddBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& fields, bool mergeFields) { 52 | (void)receipt; 53 | GameAnalytics::addBusinessEvent(currency, amount, itemType, itemId, cartType, fields, mergeFields); 54 | } 55 | 56 | void GAWrapperCpp::AddBusinessEventWithReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& store, std::string const& signature, std::string const& fields, bool mergeFields) { 57 | (void)receipt; 58 | (void)store; 59 | (void)signature; 60 | GameAnalytics::addBusinessEvent(currency, amount, itemType, itemId, cartType, fields, mergeFields); 61 | } 62 | 63 | void GAWrapperCpp::AddBusinessEventAndAutoFetchReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& fields, bool mergeFields) { 64 | GameAnalytics::addBusinessEvent(currency, amount, itemType, itemId, cartType, fields, mergeFields); 65 | } 66 | 67 | void GAWrapperCpp::AddResourceEvent(::EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& fields, bool mergeFields) { 68 | GameAnalytics::addResourceEvent((gameanalytics::EGAResourceFlowType)flowType, currency, amount, itemType, itemId, fields, mergeFields); 69 | } 70 | 71 | void GAWrapperCpp::AddProgressionEvent(::EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, std::string const& fields, bool mergeFields) { 72 | GameAnalytics::addProgressionEvent((gameanalytics::EGAProgressionStatus)progressionStatus, progression01, progression02, progression03, fields, mergeFields); 73 | } 74 | 75 | void GAWrapperCpp::AddProgressionEventWithScore(::EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, int score, std::string const& fields, bool mergeFields) { 76 | GameAnalytics::addProgressionEvent((gameanalytics::EGAProgressionStatus)progressionStatus, score, progression01, progression02, progression03, fields, mergeFields); 77 | } 78 | 79 | void GAWrapperCpp::AddDesignEvent(std::string const& eventId, std::string const& fields, bool mergeFields) { 80 | GameAnalytics::addDesignEvent(eventId, fields, mergeFields); 81 | } 82 | 83 | void GAWrapperCpp::AddDesignEventWithValue(std::string const& eventId, float value, std::string const& fields, bool mergeFields) { 84 | GameAnalytics::addDesignEvent(eventId, value, fields, mergeFields); 85 | } 86 | 87 | void GAWrapperCpp::AddErrorEvent(::EGAErrorSeverity severity, std::string const& message, std::string const& fields, bool mergeFields){ 88 | GameAnalytics::addErrorEvent(static_cast(severity), message, fields, mergeFields); 89 | } 90 | 91 | void GAWrapperCpp::AddAdEvent(::EGAAdAction action, ::EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, std::string const& fields, bool mergeFields) { 92 | return; // ad events are not supported on desktop 93 | } 94 | 95 | void GAWrapperCpp::AddAdEventWithDuration(::EGAAdAction action, ::EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, int64_t duration, std::string const& fields, bool mergeFields) { 96 | return; // ad events are not supported on desktop 97 | } 98 | 99 | void GAWrapperCpp::AddAdEventWithReason(::EGAAdAction adAction, ::EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, ::EGAAdError noAdReason, std::string const& fields, bool mergeFields) { 100 | return; // ad events are not supported on desktop 101 | } 102 | 103 | void GAWrapperCpp::SetInfoLog(bool flag) { 104 | GameAnalytics::setEnabledInfoLog(flag); 105 | } 106 | 107 | void GAWrapperCpp::SetVerboseLog(bool flag) { 108 | GameAnalytics::setEnabledVerboseLog(flag); 109 | } 110 | 111 | void GAWrapperCpp::SetEnabledManualSessionHandling(bool flag) { 112 | GameAnalytics::setEnabledManualSessionHandling(flag); 113 | } 114 | 115 | void GAWrapperCpp::SetEnabledErrorReporting(bool flag) { 116 | GameAnalytics::setEnabledErrorReporting(flag); 117 | } 118 | 119 | void GAWrapperCpp::SetEnabledEventSubmission(bool flag, bool doCache) { 120 | (void)doCache; 121 | GameAnalytics::setEnabledErrorReporting(flag); 122 | } 123 | 124 | void GAWrapperCpp::SetCustomDimension01(std::string const& customDimension) { 125 | GameAnalytics::setCustomDimension01(customDimension); 126 | } 127 | 128 | void GAWrapperCpp::SetCustomDimension02(std::string const& customDimension) { 129 | GameAnalytics::setCustomDimension02(customDimension); 130 | } 131 | 132 | void GAWrapperCpp::SetCustomDimension03(std::string const& customDimension) { 133 | GameAnalytics::setCustomDimension03(customDimension); 134 | } 135 | 136 | void GAWrapperCpp::StartSession() { 137 | GameAnalytics::startSession(); 138 | } 139 | 140 | void GAWrapperCpp::EndSession() { 141 | GameAnalytics::endSession(); 142 | } 143 | 144 | std::string GAWrapperCpp::GetRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue) { 145 | return GameAnalytics::getRemoteConfigsValueAsString(key, defaultValue); 146 | } 147 | 148 | double GAWrapperCpp::GetRemoteConfigsValueAsNumber(std::string const& key, double defaultValue) { 149 | return defaultValue; //return GameAnalytics::getRemoteConfigsValueAsNumber(key, defaultValue); 150 | } 151 | 152 | std::string GAWrapperCpp::GetRemoteConfigsValueAsJson(std::string const& key) { 153 | return ""; //return GameAnalytics::getRemoteConfigsValueAsJson(key); 154 | } 155 | 156 | bool GAWrapperCpp::IsRemoteConfigsReady() { 157 | return GameAnalytics::isRemoteConfigsReady(); 158 | } 159 | 160 | std::string GAWrapperCpp::GetRemoteConfigsContentAsString() { 161 | return GameAnalytics::getRemoteConfigsContentAsString(); 162 | } 163 | 164 | std::string GAWrapperCpp::GetABTestingId() { 165 | return GameAnalytics::getABTestingId(); 166 | } 167 | 168 | std::string GAWrapperCpp::GetABTestingVariantId() { 169 | return GameAnalytics::getABTestingVariantId(); 170 | } 171 | 172 | void GAWrapperCpp::EnableAdvertisingId(bool value) { 173 | (void)value; // for desktop advertising ids are not collected 174 | } 175 | 176 | void GAWrapperCpp::EnableSDKInitEvent(bool value) { 177 | GameAnalytics::enableSDKInitEvent(value); 178 | } 179 | 180 | void GAWrapperCpp::EnableFpsHistogram(FPSTracker tracker, bool value) { 181 | GameAnalytics::enableFPSHistogram(tracker, value); 182 | } 183 | 184 | void GAWrapperCpp::EnableMemoryHistogram(bool value) { 185 | GameAnalytics::enableMemoryHistogram(value); 186 | } 187 | 188 | void GAWrapperCpp::EnableHealthHardwareInfo(bool value) { 189 | GameAnalytics::enableHardwareTracking(value); 190 | } 191 | 192 | void GAWrapperCpp::OnQuit() { 193 | GameAnalytics::onQuit(); 194 | } 195 | 196 | void GAWrapperCpp::SetWritablePath(std::string const& path) { 197 | GameAnalytics::configureWritablePath(path); 198 | } 199 | 200 | std::string GAWrapperCpp::GetExternalUserId() { 201 | return GameAnalytics::getExternalUserId(); 202 | } 203 | 204 | void GAWrapperCpp::SetExternalUserId(const std::string &extUserId) { 205 | return GameAnalytics::configureExternalUserId(extUserId); 206 | } 207 | 208 | std::string GAWrapperCpp::GetUserId() { 209 | return GameAnalytics::getUserId(); 210 | } 211 | 212 | void GAWrapperCpp::SetGlobalCustomEventFields(const std::string &customFields) { 213 | GameAnalytics::setGlobalCustomEventFields(customFields); 214 | } 215 | 216 | int64_t GAWrapperCpp::GetElapsedSessionTime() { 217 | return GameAnalytics::getElapsedSessionTime(); 218 | } 219 | 220 | int64_t GAWrapperCpp::GetElapsedTimeForPreviousSession() { 221 | 222 | // TODO: implement when supported in cpp SDK 223 | return 0; 224 | } 225 | 226 | int64_t GAWrapperCpp::GetElapsedTimeFromAllSessions() { 227 | return GameAnalytics::getElapsedTimeFromAllSessions(); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Public/GameAnalytics.h: -------------------------------------------------------------------------------- 1 | // 2 | // GameAnalytics.h 3 | // GA-SDK-IOS 4 | // 5 | // Copyright (c) 2015 GameAnalytics. All rights reserved. 6 | // 7 | 8 | #pragma once 9 | 10 | #include "UObject/Object.h" 11 | #include "Dom/JsonObject.h" 12 | 13 | #include "GAEnums.h" 14 | #include "GAWrapper.h" 15 | #include "GameAnalytics.generated.h" 16 | 17 | DEFINE_LOG_CATEGORY_STATIC(LogGameAnalytics, Display, All); 18 | 19 | USTRUCT(BlueprintType) 20 | struct FGACustomValue 21 | { 22 | GENERATED_BODY(); 23 | 24 | UPROPERTY(BlueprintReadWrite, Category = "GameAnalytics") 25 | FString Key; 26 | 27 | UPROPERTY(BlueprintReadWrite, Category = "GameAnalytics") 28 | FString ValueString; 29 | 30 | UPROPERTY(BlueprintReadWrite, Category = "GameAnalytics") 31 | double ValueNumber = 0.0; 32 | 33 | UPROPERTY(BlueprintReadWrite, Category = "GameAnalytics") 34 | bool ValueBool = false; 35 | 36 | UPROPERTY(BlueprintReadWrite, Category = "GameAnalytics") 37 | EGAValueType ValueType = EGAValueType::value_number; 38 | }; 39 | 40 | USTRUCT(BlueprintType) 41 | struct GAMEANALYTICS_API FGACustomFields 42 | { 43 | GENERATED_BODY(); 44 | 45 | UPROPERTY(BlueprintReadWrite, Category = "GameAnalytics") 46 | TArray Values; 47 | 48 | bool IsEmpty() const; 49 | 50 | void Set(FString const& Key, double Value); 51 | void Set(FString const& Key, FString const& Value); 52 | void Set(FString const& Key, bool Value); 53 | 54 | FString ToString() const; 55 | 56 | TSharedRef ToJson() const; 57 | }; 58 | 59 | class UGameAnalyticsPerformance; 60 | 61 | UCLASS(BlueprintType) 62 | class GAMEANALYTICS_API UGameAnalytics : public UObject 63 | { 64 | GENERATED_UCLASS_BODY() 65 | 66 | // pointer to implementation 67 | TUniquePtr _impl; 68 | 69 | // optional performance tracker 70 | UGameAnalyticsPerformance* _performanceTracker = nullptr; 71 | 72 | public: 73 | 74 | virtual void BeginDestroy() override; 75 | 76 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 77 | static UGameAnalytics* GetInstance(); 78 | 79 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 80 | void ConfigureAvailableCustomDimensions01(const TArray& List); 81 | 82 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 83 | void ConfigureAvailableCustomDimensions02(const TArray& List); 84 | 85 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 86 | void ConfigureAvailableCustomDimensions03(const TArray& List); 87 | 88 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 89 | void ConfigureAvailableResourceCurrencies(const TArray& List); 90 | 91 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 92 | void ConfigureAvailableResourceItemTypes(const TArray& List); 93 | 94 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 95 | void ConfigureBuild(FString const& Build); 96 | 97 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 98 | void ConfigureAutoDetectAppVersion(bool Flag); 99 | 100 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 101 | void DisableDeviceInfo(); 102 | 103 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 104 | void ConfigureUserId(FString const& UserId); 105 | 106 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 107 | void ConfigureExternalUserId(FString const& UserId); 108 | 109 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 110 | void ConfigureSdkGameEngineVersion(const FString& GameEngineSdkVersion); 111 | 112 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 113 | void ConfigureGameEngineVersion(const FString& GameEngineVersion); 114 | 115 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 116 | void Initialize(FString const& GameKey, FString const& GameSecret); 117 | 118 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 119 | void SetEnabledInfoLog(bool Flag); 120 | 121 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 122 | void SetEnabledVerboseLog(bool Flag); 123 | 124 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 125 | void SetEnabledManualSessionHandling(bool Flag); 126 | 127 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 128 | void SetEnabledErrorReporting(bool Flag); 129 | 130 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 131 | void SetEnabledEventSubmission(bool Flag); 132 | 133 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 134 | void StartSession(); 135 | 136 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 137 | void EndSession(); 138 | 139 | ////////////////////////////////////////////////////// 140 | 141 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 142 | void AddBusinessEvent(FString const& Currency, int Amount, FString const& ItemType, FString const& ItemId, FString const& CartType, FString const& Receipt = "", const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 143 | 144 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 145 | void AddBusinessEventAndAutoFetchReceipt(FString const& Currency, int Amount, FString const& ItemType, FString const& ItemId, FString const& CartType, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 146 | 147 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 148 | void AddBusinessEventWithReceipt(FString const& Currency, int Amount, FString const& ItemType, FString const& ItemId, FString const& CartType, FString const& Receipt, FString const& Store, FString const& Signature, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 149 | 150 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 151 | void AddResourceEvent(EGAResourceFlowType FlowType, const FString &Currency, float Amount, const FString &ItemType, const FString &ItemId, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 152 | 153 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 154 | void AddProgressionEvent(EGAProgressionStatus ProgressionStatus, const FString &Progression01, const FString &Progression02 = "", const FString &Progression03 = "", const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 155 | 156 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 157 | void AddProgressionEventWithScore(EGAProgressionStatus ProgressionStatus, int Score, const FString &Progression01 = "", const FString &Progression02 = "", const FString &Progression03 = "", const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 158 | 159 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 160 | void AddDesignEvent(const FString& EventId, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 161 | 162 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 163 | void AddDesignEventWithValue(const FString& EventId, float Value, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 164 | 165 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 166 | void AddErrorEvent(EGAErrorSeverity Severity, const FString& Message, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 167 | 168 | ////////////////////////////////////////////////////// 169 | // AD EVENTS ARE ONLY AVAILABLE FOR IOS AND ANDROID // 170 | ////////////////////////////////////////////////////// 171 | 172 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 173 | void AddAdEvent(EGAAdAction Action, EGAAdType AdType, const FString& AdSdkName, const FString& AdPlacement, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 174 | 175 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 176 | void AddAdEventWithDuration(EGAAdAction Action, EGAAdType AdType, const FString& AdSdkName, const FString& AdPlacement, int64 Duration, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 177 | 178 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 179 | void AddAdEventWithReason(EGAAdAction Action, EGAAdType AdType, const FString& AdSdkName, const FString& AdPlacement, EGAAdError Reason, const FGACustomFields CustomFields = FGACustomFields(), bool MergeFields = false); 180 | 181 | //////////////////////////////////////////////////////////// 182 | 183 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 184 | void SetCustomDimension01(const FString& CustomDimension); 185 | 186 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 187 | void SetCustomDimension02(const FString& CustomDimension); 188 | 189 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 190 | void SetCustomDimension03(const FString& CustomDimension); 191 | 192 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 193 | FString GetUserId(); 194 | 195 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 196 | FString GetExternalUserId(); 197 | 198 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 199 | FString GetRemoteConfigsValueAsString(const FString& Key, const FString& DefaultValue = ""); 200 | 201 | // FJsonObject cannot be exposed to blueprints 202 | TSharedPtr GetRemoteConfigsValueAsJSON(const FString& key); 203 | 204 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 205 | bool IsRemoteConfigsReady(); 206 | 207 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 208 | FString GetRemoteConfigsContentAsString(); 209 | 210 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 211 | FString GetABTestingId(); 212 | 213 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 214 | FString GetABTestingVariantId(); 215 | 216 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 217 | void OnQuit(); 218 | 219 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 220 | void EnableAdvertisingId(bool Value); 221 | 222 | //////////////////////////////////////////////////////////// 223 | // HEALTH EVENT 224 | //////////////////////////////////////////////////////////// 225 | 226 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 227 | void EnableSDKInitEvent(bool Value); 228 | 229 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 230 | void EnableFpsHistogram(bool Value); 231 | 232 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 233 | void EnableMemoryHistogram(bool Value); 234 | 235 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 236 | void EnableHealthHardwareInfo(bool Value); 237 | 238 | //////////////////////////////////////////////////////////// 239 | 240 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 241 | int64 GetElapsedSessionTime(); 242 | 243 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 244 | int64 GetElapsedTimeFromAllSessions(); 245 | 246 | //////////////////////////////////////////////////////////// 247 | 248 | UFUNCTION(BlueprintCallable, Category = "GameAnalytics") 249 | void SetWritablePath(FString const& Path); 250 | }; 251 | 252 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | --------- 3 | 4 | **6.0.0** 5 | * removed static functions, UGameAnalytics is now an object 6 | * added instance of UGameAnalytics inside UGameAnalyticsModule 7 | * refactored the codebase, added GAWrapper to handle different platforms 8 | * removed all duplicate functions inside UGameAnalytics 9 | * exposed all functions to blueprints 10 | * introduced a new performance tracker, improved FPS reporting 11 | * added FPS reporting for desktop platforms 12 | * updated GameAnalytics dependencies to GA SDK C++ v5.0.0, GA iOS v5.0.0 and GA Android v7.0.0 13 | * added playtime metrics tracking and public functions: GetElapsedSessionTime/GetElapsedTimeFromAllSessions 14 | * added support for Remote Configs v2 with json support: GetRemoteConfigsValueAsJSON 15 | * various improvements and bug-fixes 16 | 17 | **5.6.1** 18 | * fixed iOS compilation issues 19 | * fixed linux broken paths for static cpp ga sdk lib 20 | 21 | **5.6.0** 22 | - fixed UE 5.4 or later compilation issues 23 | - **Boot Time in Milliseconds**: Boot time now reported in milliseconds for precise performance metrics. 24 | - **Design Event Values**: Improved the consistency of design event value handling, ensuring more accurate data delivery. 25 | - **Local Cache Path**: Refined the local cache path configuration to automatically use the default writable path, streamlining setup by making `configureWritablePath` optional. 26 | - **Verbose Logging**: more logs are not visible when verbose logging is enabled. 27 | 28 | **5.5.0** 29 | * updated the C++ SDK dependency 30 | * updated user api routes for login 31 | * added partial health feature support for windows/macos/linux 32 | 33 | **5.4.5** 34 | * fixed documentation links 35 | * added experimental health feature 36 | 37 | **5.4.5** 38 | * fixed documentation links 39 | * added experimental health feature 40 | 41 | **5.4.4** 42 | * support for Unreal 5.4 43 | * added iOS privacy manifest 44 | 45 | **5.4.3** 46 | * updated plugin for UE 5.3 47 | 48 | **5.4.2** 49 | * fixed compilation warnings for android (fix for builds using -werror flag) 50 | 51 | **5.4.1** 52 | * fixed a bug where the android library would fail to load in some cases 53 | * implemented new method to retrieve the device name for win64 54 | 55 | **5.4.0** 56 | * support for UE 5.2.0 preview 57 | 58 | **5.3.1** 59 | * fixed a compilation issue on android for ndk25 60 | 61 | **5.3.0** 62 | * updated plugin for unreal 5.1 63 | 64 | **5.2.0** 65 | * added support for unreal 5 66 | 67 | **5.1.14** 68 | * fixed crash on android 69 | 70 | **5.1.13** 71 | * fixed bug in internal error reporting 72 | 73 | **5.1.12** 74 | * small corrections 75 | 76 | **5.1.11** 77 | * restructured location of files 78 | 79 | **5.1.10** 80 | * added event uuid for events sent 81 | 82 | **5.1.9** 83 | * fixed progression tries bug for desktop platforms 84 | 85 | **5.1.8** 86 | * removed imei identifiers and other alternative identifiers from user identifier logic (android) 87 | 88 | **5.1.7** 89 | * added error events to be sent for invalid custom event fields used 90 | * added optional mergeFields argument to event methods to merge with global custom fields instead of overwrite them 91 | 92 | **5.1.6** 93 | * more build error fixes 94 | 95 | **5.1.5** 96 | * fix build errors 97 | 98 | **5.1.4** 99 | * fixed missing custom event fields for when trying to fix missing session end events 100 | 101 | **5.1.3** 102 | * added error reporting option to settings 103 | 104 | **5.1.2** 105 | * added functionality to force a new user in a/b testing without having to uninstall app first, simply use custom user id function to set a new user id which hasn't been used yet 106 | 107 | **5.1.1** 108 | * small compile fix 109 | 110 | **5.1.0** 111 | * added custom event fields feature 112 | 113 | **5.0.1** 114 | * small correct to support unreal engine 4.27 115 | 116 | **5.0.0** 117 | * Changed user identifier logic in preparation for Google changes to GAID. User id for a new install is now a randomised GUID. Existing installs that update SDK will continue using previous identifier logic. It is recommended to update as soon as possible to reduce impact on calculated metrics. 118 | * added support for unreal engine 4.27 119 | 120 | **4.3.15** 121 | * it should now be possible to not show idfa consent dialog if you don't have any third party code that needs to use idfa (ios) 122 | * prepared for google advertising identifier changes (will not use google advertising identifier when user has opted out) (android) 123 | 124 | **4.3.14** 125 | * added idfa consent status field to events (ios) 126 | 127 | **4.3.13** 128 | * added disable device info to settings 129 | 130 | **4.3.12** 131 | * updated client ts validator 132 | 133 | **4.3.11** 134 | * fixed dependencies for iOS (min. XCode 12 required) 135 | 136 | **4.3.10** 137 | * fixed return values for remote configs and ab testing functions 138 | 139 | **4.3.9** 140 | * added support for unreal engine 4.26 141 | 142 | **4.3.8** 143 | * corrected ad event annotation 144 | 145 | **4.3.7** 146 | * added ARM64 architecture to mac libs 147 | 148 | **4.3.6** 149 | * fixed build errors for linux 150 | 151 | **4.3.5** 152 | * fixed log messages output to console in editor 153 | 154 | **4.3.4** 155 | * added editor logs when calling functions in editor play mode 156 | 157 | **4.3.3** 158 | * improved user identifer flow for ios (ios) 159 | 160 | **4.3.2** 161 | * fix to the seperation of sqlite code for some platforms 162 | 163 | **4.3.1** 164 | * seperated sqlite code into its own library (osx, windows, linux) 165 | 166 | **4.3.0** 167 | * updated user identifier flow to prepare for iOS 14 IDFA changes (ios) 168 | 169 | **4.2.1** 170 | * fixed progression event with scores (android) 171 | 172 | **4.2.0** 173 | * exposed functions to get AB testing id and variant id 174 | 175 | **4.1.5** 176 | * fixed link errors for ios 177 | 178 | **4.1.4** 179 | * added support for unreal engine 4.25 180 | 181 | **4.1.3** 182 | * fixed compile errors 183 | 184 | **4.1.2** 185 | * compile error fix for int64 186 | 187 | **4.1.1** 188 | * compile error fixes 189 | 190 | **4.1.0** 191 | * added ad event (ios, android) 192 | * organizations added to games key list 193 | 194 | **4.0.13** 195 | * logo updated 196 | 197 | **4.0.12** 198 | * uplugin fix 199 | 200 | **4.0.11** 201 | * compile fixes 202 | 203 | **4.0.10** 204 | * removed facebook, gender and birthyear methods 205 | * added auto detect app version for build field option (only android, ios) 206 | 207 | **4.0.9** 208 | * changed editor module type from 'Developer' to 'DeveloperTool' 209 | 210 | **4.0.8** 211 | * removed html5 related code 212 | 213 | **4.0.7** 214 | * A/B testing fixes 215 | 216 | **4.0.6** 217 | * removed compile warnings 218 | 219 | **4.0.5** 220 | * added support for Unreal Engine 4.24 221 | 222 | **4.0.4** 223 | * fixed getRemoteConfigsValueAsString (ios) 224 | 225 | **4.0.3** 226 | * remote configs fixes 227 | 228 | **4.0.2** 229 | * corrected naming of function 230 | 231 | **4.0.1** 232 | * small fixes 233 | 234 | **4.0.0** 235 | * Remote Config calls have been updated and the old calls have deprecated. Please see GA documentation for the new SDK calls and migration guide 236 | * A/B testing support added 237 | 238 | **3.1.13** 239 | * compile error fixes for html5 240 | 241 | **3.1.12** 242 | * compile error fixes for html5 243 | 244 | **3.1.11** 245 | * fixes android builds 246 | 247 | **3.1.10** 248 | * fixed build errors 249 | 250 | **3.1.9** 251 | * fixed command center bugs 252 | 253 | **3.1.8** 254 | * added support for unreal engine 4.23 255 | 256 | **3.1.7** 257 | * added check if log files and database can't be created (desktop platforms) 258 | 259 | **3.1.6** 260 | * fixed progression event for desktop platforms 261 | * fixed hanging background thread when closing application down for desktop platforms 262 | 263 | **3.1.5** 264 | * fixes to warnings and errors 265 | 266 | **3.1.4** 267 | * fixed build errors for html5 268 | 269 | **3.1.3** 270 | * fixed initialize method to be able to be called from code 271 | 272 | **3.1.2** 273 | * added support for unreal engine v4.22 274 | 275 | **3.1.1** 276 | * html5 build fix 277 | * various other bug fixes 278 | 279 | **3.1.0** 280 | * added enable/disable event submission function 281 | 282 | **3.0.6** 283 | * fixed business event validation 284 | 285 | **3.0.5** 286 | * updated to support unreal engine 4.21 287 | 288 | **3.0.4** 289 | * android bug fixes 290 | 291 | **3.0.3** 292 | * fixed shutdown bugs for desktop platforms 293 | 294 | **3.0.2** 295 | * fixed thread hanging on shutdown for desktop platforms 296 | 297 | **3.0.1** 298 | * fixed compile errors 299 | 300 | **3.0.0** 301 | * added command center functionality 302 | * added gameanalytics blueprint functions 303 | 304 | **2.6.28** 305 | * fixed more compile errors for mac 306 | 307 | **2.6.27** 308 | * fixed android crash 309 | 310 | **2.6.26** 311 | * fixed compile errors 312 | 313 | **2.6.19** 314 | * compile fixes for android (android) 315 | * updated to be compatible with unreal engine v4.20 316 | 317 | **2.6.18** 318 | * various bug fixes 319 | 320 | **2.6.17** 321 | * fixes building for linux (linux) 322 | 323 | **2.6.16** 324 | * added custom dimensions to design error events 325 | * added option to startsession with gamekey and secretkey instead of getting keys from settings object 326 | 327 | **2.6.15** 328 | * fixed session length bug 329 | * fixed not allowing to add events when session is not started 330 | 331 | **2.6.14** 332 | * fixed crash bug for closing down sdk for desktop platforms (windows, mac, linux) 333 | 334 | **2.6.13** 335 | * iOS support temporarily removed until Epic fixes some issues the iOS toolchain causes in Unreal Engine 4.19 336 | 337 | **2.6.12** 338 | * added compatability for Unreal Engine v4.19 339 | 340 | **2.6.11** 341 | * log library has been replaced which caused some problems on machine with certain locales set (mac, windows, linux) 342 | 343 | **2.6.10** 344 | * bug fix to progression event crashes 345 | 346 | **2.6.9** 347 | * additional fixes to Unreal Engine 4.18 compatability 348 | 349 | **2.6.8** 350 | * fixes to Unreal Engine 4.18 compatability 351 | 352 | **2.6.7** 353 | * fixed javascript library (html5) 354 | 355 | **2.6.6** 356 | * updated to be compatible with Unreal Engine 4.18 357 | 358 | **2.6.5** 359 | * bug fix to android JNI memory leak (android) 360 | 361 | **2.6.4** 362 | * made compatible with Unreal Engine 4.17 363 | 364 | **2.6.3** 365 | * jni bug fix for progression events with scores (android) 366 | 367 | **2.6.2** 368 | * switched to use third party OpenSSL and libCurl libraries bundled with Unreal Engine 369 | 370 | **2.6.1** 371 | * editor UI bug fix when running game in editor viewport with GameAnalytics plugin enabled 372 | 373 | **2.6.0** 374 | * changed the behaviour of using IMEI with the 'READ_PHONE_STATE' permission to guarantee precise analytics for certain regions (android) 375 | 376 | **2.5.5** 377 | * fixed compile warnings 378 | 379 | **2.5.4** 380 | * fixed html5 wrapper to use correct namespace (html5) 381 | 382 | **2.5.3** 383 | * bug fix for end session when using manual session handling 384 | 385 | **2.5.2** 386 | * session length precision improvement 387 | 388 | **2.5.1** 389 | * custom user id bug fix 390 | 391 | **2.5.0** 392 | * added support for linux 393 | 394 | **2.4.0** 395 | * added support for html5 396 | 397 | **2.2.13** 398 | * corrected win32 library (win32) 399 | 400 | **2.2.12** 401 | * bug fix for progression event with score in Android builds (android) 402 | 403 | **2.2.11** 404 | * proguard fix when making distribution build (android) 405 | 406 | **2.2.10** 407 | * possible to set custom dimensions and demographics before initialise 408 | 409 | **2.2.9** 410 | * fixed missing namespace for JNI function calls (android) 411 | 412 | **2.2.8** 413 | * fix for using plugin directly from C++ code in your project 414 | 415 | **2.2.7** 416 | * fix for empty user_id bug (windows, mac) 417 | 418 | **2.2.6** 419 | * added support for both Unreal Engine 4.12 and 4.13 420 | 421 | **2.2.5** 422 | * bug fix to error when cooking and packaging build 423 | 424 | **2.2.4** 425 | * fixed user_id tracking for iOS 10 (ios) 426 | * small fix related to manual session handling (android) 427 | 428 | **2.2.3** 429 | * fix for empty user id in events (mac, windows) 430 | 431 | **2.2.2** 432 | * Updated to be compatible with Unreal 4.13 433 | * Updated Google Play Services libraries to use latest version (android) 434 | 435 | **2.2.1** 436 | * wrong platform in events bug fix (windows, mac) 437 | * crash bug fix (windows, mac) 438 | 439 | **2.2.0** 440 | * added manual session handling 441 | 442 | **2.1.2** 443 | * fixed default GameAnalytics settings values 444 | 445 | **2.1.1** 446 | * bug fix for missing configureUsedId in native iOS lib (ios) 447 | 448 | **2.1.0** 449 | * Windows and Mac support added (windows and mac) 450 | 451 | **2.0.0** 452 | * various Blueprint event bug fixes 453 | * Android support added (android) 454 | 455 | **0.1.3** 456 | * fixed third party include path 457 | 458 | **0.1.2** 459 | * fixed compile warnings for Unreal Engine 4.11 460 | 461 | **0.1.1** 462 | * minor fixes 463 | 464 | **0.1.0** 465 | * initial version (iOS) 466 | -------------------------------------------------------------------------------- /GameAnalytics/README.md: -------------------------------------------------------------------------------- 1 | # GA-SDK-UNREAL 2 | GameAnalytics SDK for the Unreal Engine. 3 | 4 | Documentation can be found [here](https://docs.gameanalytics.com/integrations/sdk/unreal). 5 | 6 | If you have any issues or feedback regarding the SDK, please contact our friendly support team [here](https://gameanalytics.com/contact). 7 | 8 | > :information_source: 9 | > 10 | > The Unreal SDK include support for **iOS**, **Android**, **HTML5**, **Windows**, **Linux** and **Mac** platforms 11 | > 12 | > Requirements: 13 | > * **Unreal Engine:** 5.3+   14 | > * **iOS:** iOS 10+   15 | > * **Android:** Android API Level 21   16 | > * **Windows:** Minimum specs for UE5   17 | > * **Mac:** Minimum specs for UE5   18 | > 19 | 20 | Changelog 21 | --------- 22 | 23 | **6.1.0** 24 | * support for unreal 5.7:updated ga-cpp-sdk to v5.1.0:exposed internal GameAnalytics instance to blueprints via `GameAnalytics 25 | * GetInstance()`:fixed `FGACustomFields` blueprints 26 | 27 | **6.0.0** 28 | * removed static functions, UGameAnalytics is now an object 29 | * added instance of UGameAnalytics inside UGameAnalyticsModule 30 | * refactored the codebase, added GAWrapper to handle different platforms 31 | * removed all duplicate functions inside UGameAnalytics 32 | * exposed all functions to blueprints 33 | * introduced a new performance tracker, improved FPS reporting 34 | * added FPS reporting for desktop platforms 35 | * updated GameAnalytics dependencies to GA SDK C++ v5.0.0, GA iOS v5.0.0 and GA Android v7.0.0 36 | * added playtime metrics tracking and public functions: GetElapsedSessionTime/GetElapsedTimeFromAllSessions 37 | * added support for Remote Configs v2 with json support: GetRemoteConfigsValueAsJSON 38 | * various improvements and bug-fixes 39 | 40 | **5.6.1** 41 | * fixed iOS compilation issues 42 | * fixed linux broken paths for static cpp ga sdk lib 43 | 44 | **5.6.0** 45 | - fixed UE 5.4 or later compilation issues 46 | - **Boot Time in Milliseconds**: Boot time now reported in milliseconds for precise performance metrics. 47 | - **Design Event Values**: Improved the consistency of design event value handling, ensuring more accurate data delivery. 48 | - **Local Cache Path**: Refined the local cache path configuration to automatically use the default writable path, streamlining setup by making `configureWritablePath` optional. 49 | - **Verbose Logging**: more logs are not visible when verbose logging is enabled. 50 | 51 | **5.5.0** 52 | * updated the C++ SDK dependency 53 | * updated user api routes for login 54 | * added partial health feature support for windows/macos/linux 55 | 56 | **5.4.5** 57 | * fixed documentation links 58 | * added experimental health feature 59 | 60 | **5.4.5** 61 | * fixed documentation links 62 | * added experimental health feature 63 | 64 | **5.4.4** 65 | * support for Unreal 5.4 66 | * added iOS privacy manifest 67 | 68 | **5.4.3** 69 | * updated plugin for UE 5.3 70 | 71 | **5.4.2** 72 | * fixed compilation warnings for android (fix for builds using -werror flag) 73 | 74 | **5.4.1** 75 | * fixed a bug where the android library would fail to load in some cases 76 | * implemented new method to retrieve the device name for win64 77 | 78 | **5.4.0** 79 | * support for UE 5.2.0 preview 80 | 81 | **5.3.1** 82 | * fixed a compilation issue on android for ndk25 83 | 84 | **5.3.0** 85 | * updated plugin for unreal 5.1 86 | 87 | **5.2.0** 88 | * added support for unreal 5 89 | 90 | **5.1.14** 91 | * fixed crash on android 92 | 93 | **5.1.13** 94 | * fixed bug in internal error reporting 95 | 96 | **5.1.12** 97 | * small corrections 98 | 99 | **5.1.11** 100 | * restructured location of files 101 | 102 | **5.1.10** 103 | * added event uuid for events sent 104 | 105 | **5.1.9** 106 | * fixed progression tries bug for desktop platforms 107 | 108 | **5.1.8** 109 | * removed imei identifiers and other alternative identifiers from user identifier logic (android) 110 | 111 | **5.1.7** 112 | * added error events to be sent for invalid custom event fields used 113 | * added optional mergeFields argument to event methods to merge with global custom fields instead of overwrite them 114 | 115 | **5.1.6** 116 | * more build error fixes 117 | 118 | **5.1.5** 119 | * fix build errors 120 | 121 | **5.1.4** 122 | * fixed missing custom event fields for when trying to fix missing session end events 123 | 124 | **5.1.3** 125 | * added error reporting option to settings 126 | 127 | **5.1.2** 128 | * added functionality to force a new user in a/b testing without having to uninstall app first, simply use custom user id function to set a new user id which hasn't been used yet 129 | 130 | **5.1.1** 131 | * small compile fix 132 | 133 | **5.1.0** 134 | * added custom event fields feature 135 | 136 | **5.0.1** 137 | * small correct to support unreal engine 4.27 138 | 139 | **5.0.0** 140 | * Changed user identifier logic in preparation for Google changes to GAID. User id for a new install is now a randomised GUID. Existing installs that update SDK will continue using previous identifier logic. It is recommended to update as soon as possible to reduce impact on calculated metrics. 141 | * added support for unreal engine 4.27 142 | 143 | **4.3.15** 144 | * it should now be possible to not show idfa consent dialog if you don't have any third party code that needs to use idfa (ios) 145 | * prepared for google advertising identifier changes (will not use google advertising identifier when user has opted out) (android) 146 | 147 | **4.3.14** 148 | * added idfa consent status field to events (ios) 149 | 150 | **4.3.13** 151 | * added disable device info to settings 152 | 153 | **4.3.12** 154 | * updated client ts validator 155 | 156 | **4.3.11** 157 | * fixed dependencies for iOS (min. XCode 12 required) 158 | 159 | **4.3.10** 160 | * fixed return values for remote configs and ab testing functions 161 | 162 | **4.3.9** 163 | * added support for unreal engine 4.26 164 | 165 | **4.3.8** 166 | * corrected ad event annotation 167 | 168 | **4.3.7** 169 | * added ARM64 architecture to mac libs 170 | 171 | **4.3.6** 172 | * fixed build errors for linux 173 | 174 | **4.3.5** 175 | * fixed log messages output to console in editor 176 | 177 | **4.3.4** 178 | * added editor logs when calling functions in editor play mode 179 | 180 | **4.3.3** 181 | * improved user identifer flow for ios (ios) 182 | 183 | **4.3.2** 184 | * fix to the seperation of sqlite code for some platforms 185 | 186 | **4.3.1** 187 | * seperated sqlite code into its own library (osx, windows, linux) 188 | 189 | **4.3.0** 190 | * updated user identifier flow to prepare for iOS 14 IDFA changes (ios) 191 | 192 | **4.2.1** 193 | * fixed progression event with scores (android) 194 | 195 | **4.2.0** 196 | * exposed functions to get AB testing id and variant id 197 | 198 | **4.1.5** 199 | * fixed link errors for ios 200 | 201 | **4.1.4** 202 | * added support for unreal engine 4.25 203 | 204 | **4.1.3** 205 | * fixed compile errors 206 | 207 | **4.1.2** 208 | * compile error fix for int64 209 | 210 | **4.1.1** 211 | * compile error fixes 212 | 213 | **4.1.0** 214 | * added ad event (ios, android) 215 | * organizations added to games key list 216 | 217 | **4.0.13** 218 | * logo updated 219 | 220 | **4.0.12** 221 | * uplugin fix 222 | 223 | **4.0.11** 224 | * compile fixes 225 | 226 | **4.0.10** 227 | * removed facebook, gender and birthyear methods 228 | * added auto detect app version for build field option (only android, ios) 229 | 230 | **4.0.9** 231 | * changed editor module type from 'Developer' to 'DeveloperTool' 232 | 233 | **4.0.8** 234 | * removed html5 related code 235 | 236 | **4.0.7** 237 | * A/B testing fixes 238 | 239 | **4.0.6** 240 | * removed compile warnings 241 | 242 | **4.0.5** 243 | * added support for Unreal Engine 4.24 244 | 245 | **4.0.4** 246 | * fixed getRemoteConfigsValueAsString (ios) 247 | 248 | **4.0.3** 249 | * remote configs fixes 250 | 251 | **4.0.2** 252 | * corrected naming of function 253 | 254 | **4.0.1** 255 | * small fixes 256 | 257 | **4.0.0** 258 | * Remote Config calls have been updated and the old calls have deprecated. Please see GA documentation for the new SDK calls and migration guide 259 | * A/B testing support added 260 | 261 | **3.1.13** 262 | * compile error fixes for html5 263 | 264 | **3.1.12** 265 | * compile error fixes for html5 266 | 267 | **3.1.11** 268 | * fixes android builds 269 | 270 | **3.1.10** 271 | * fixed build errors 272 | 273 | **3.1.9** 274 | * fixed command center bugs 275 | 276 | **3.1.8** 277 | * added support for unreal engine 4.23 278 | 279 | **3.1.7** 280 | * added check if log files and database can't be created (desktop platforms) 281 | 282 | **3.1.6** 283 | * fixed progression event for desktop platforms 284 | * fixed hanging background thread when closing application down for desktop platforms 285 | 286 | **3.1.5** 287 | * fixes to warnings and errors 288 | 289 | **3.1.4** 290 | * fixed build errors for html5 291 | 292 | **3.1.3** 293 | * fixed initialize method to be able to be called from code 294 | 295 | **3.1.2** 296 | * added support for unreal engine v4.22 297 | 298 | **3.1.1** 299 | * html5 build fix 300 | * various other bug fixes 301 | 302 | **3.1.0** 303 | * added enable/disable event submission function 304 | 305 | **3.0.6** 306 | * fixed business event validation 307 | 308 | **3.0.5** 309 | * updated to support unreal engine 4.21 310 | 311 | **3.0.4** 312 | * android bug fixes 313 | 314 | **3.0.3** 315 | * fixed shutdown bugs for desktop platforms 316 | 317 | **3.0.2** 318 | * fixed thread hanging on shutdown for desktop platforms 319 | 320 | **3.0.1** 321 | * fixed compile errors 322 | 323 | **3.0.0** 324 | * added command center functionality 325 | * added gameanalytics blueprint functions 326 | 327 | **2.6.28** 328 | * fixed more compile errors for mac 329 | 330 | **2.6.27** 331 | * fixed android crash 332 | 333 | **2.6.26** 334 | * fixed compile errors 335 | 336 | **2.6.19** 337 | * compile fixes for android (android) 338 | * updated to be compatible with unreal engine v4.20 339 | 340 | **2.6.18** 341 | * various bug fixes 342 | 343 | **2.6.17** 344 | * fixes building for linux (linux) 345 | 346 | **2.6.16** 347 | * added custom dimensions to design error events 348 | * added option to startsession with gamekey and secretkey instead of getting keys from settings object 349 | 350 | **2.6.15** 351 | * fixed session length bug 352 | * fixed not allowing to add events when session is not started 353 | 354 | **2.6.14** 355 | * fixed crash bug for closing down sdk for desktop platforms (windows, mac, linux) 356 | 357 | **2.6.13** 358 | * iOS support temporarily removed until Epic fixes some issues the iOS toolchain causes in Unreal Engine 4.19 359 | 360 | **2.6.12** 361 | * added compatability for Unreal Engine v4.19 362 | 363 | **2.6.11** 364 | * log library has been replaced which caused some problems on machine with certain locales set (mac, windows, linux) 365 | 366 | **2.6.10** 367 | * bug fix to progression event crashes 368 | 369 | **2.6.9** 370 | * additional fixes to Unreal Engine 4.18 compatability 371 | 372 | **2.6.8** 373 | * fixes to Unreal Engine 4.18 compatability 374 | 375 | **2.6.7** 376 | * fixed javascript library (html5) 377 | 378 | **2.6.6** 379 | * updated to be compatible with Unreal Engine 4.18 380 | 381 | **2.6.5** 382 | * bug fix to android JNI memory leak (android) 383 | 384 | **2.6.4** 385 | * made compatible with Unreal Engine 4.17 386 | 387 | **2.6.3** 388 | * jni bug fix for progression events with scores (android) 389 | 390 | **2.6.2** 391 | * switched to use third party OpenSSL and libCurl libraries bundled with Unreal Engine 392 | 393 | **2.6.1** 394 | * editor UI bug fix when running game in editor viewport with GameAnalytics plugin enabled 395 | 396 | **2.6.0** 397 | * changed the behaviour of using IMEI with the 'READ_PHONE_STATE' permission to guarantee precise analytics for certain regions (android) 398 | 399 | **2.5.5** 400 | * fixed compile warnings 401 | 402 | **2.5.4** 403 | * fixed html5 wrapper to use correct namespace (html5) 404 | 405 | **2.5.3** 406 | * bug fix for end session when using manual session handling 407 | 408 | **2.5.2** 409 | * session length precision improvement 410 | 411 | **2.5.1** 412 | * custom user id bug fix 413 | 414 | **2.5.0** 415 | * added support for linux 416 | 417 | **2.4.0** 418 | * added support for html5 419 | 420 | **2.2.13** 421 | * corrected win32 library (win32) 422 | 423 | **2.2.12** 424 | * bug fix for progression event with score in Android builds (android) 425 | 426 | **2.2.11** 427 | * proguard fix when making distribution build (android) 428 | 429 | **2.2.10** 430 | * possible to set custom dimensions and demographics before initialise 431 | 432 | **2.2.9** 433 | * fixed missing namespace for JNI function calls (android) 434 | 435 | **2.2.8** 436 | * fix for using plugin directly from C++ code in your project 437 | 438 | **2.2.7** 439 | * fix for empty user_id bug (windows, mac) 440 | 441 | **2.2.6** 442 | * added support for both Unreal Engine 4.12 and 4.13 443 | 444 | **2.2.5** 445 | * bug fix to error when cooking and packaging build 446 | 447 | **2.2.4** 448 | * fixed user_id tracking for iOS 10 (ios) 449 | * small fix related to manual session handling (android) 450 | 451 | **2.2.3** 452 | * fix for empty user id in events (mac, windows) 453 | 454 | **2.2.2** 455 | * Updated to be compatible with Unreal 4.13 456 | * Updated Google Play Services libraries to use latest version (android) 457 | 458 | **2.2.1** 459 | * wrong platform in events bug fix (windows, mac) 460 | * crash bug fix (windows, mac) 461 | 462 | **2.2.0** 463 | * added manual session handling 464 | 465 | **2.1.2** 466 | * fixed default GameAnalytics settings values 467 | 468 | **2.1.1** 469 | * bug fix for missing configureUsedId in native iOS lib (ios) 470 | 471 | **2.1.0** 472 | * Windows and Mac support added (windows and mac) 473 | 474 | **2.0.0** 475 | * various Blueprint event bug fixes 476 | * Android support added (android) 477 | 478 | **0.1.3** 479 | * fixed third party include path 480 | 481 | **0.1.2** 482 | * fixed compile warnings for Unreal Engine 4.11 483 | 484 | **0.1.1** 485 | * minor fixes 486 | 487 | **0.1.0** 488 | * initial version (iOS) 489 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/GameAnalyticsProvider.cpp: -------------------------------------------------------------------------------- 1 | #include "GameAnalyticsProvider.h" 2 | #include "GameAnalyticsModule.h" 3 | #include "Misc/ConfigCacheIni.h" 4 | #include "Interfaces/IAnalyticsProvider.h" 5 | #include "GameAnalytics.h" 6 | 7 | #if PLATFORM_WINDOWS 8 | #include "Windows/AllowWindowsPlatformTypes.h" 9 | #endif 10 | 11 | static const TMap kProgressionStrings = 12 | { 13 | {TEXT("start"), EGAProgressionStatus::start}, 14 | {TEXT("complete"), EGAProgressionStatus::complete}, 15 | {TEXT("fail"), EGAProgressionStatus::fail} 16 | }; 17 | 18 | static const TMap kSeverityStrings = 19 | { 20 | {TEXT("debug"), EGAErrorSeverity::debug}, 21 | {TEXT("info"), EGAErrorSeverity::info}, 22 | {TEXT("warning"), EGAErrorSeverity::warning}, 23 | {TEXT("error"), EGAErrorSeverity::error}, 24 | {TEXT("critical"), EGAErrorSeverity::critical} 25 | }; 26 | 27 | static const TMap kFlowTypes = 28 | { 29 | {TEXT("sink"), EGAResourceFlowType::sink}, 30 | {TEXT("source"), EGAResourceFlowType::source}, 31 | }; 32 | 33 | void GAPrintUsageWarning(const char* func) 34 | { 35 | auto constexpr DOCS_LINK = TEXT("https://docs.gameanalytics.com/integrations/sdk/unreal"); 36 | UE_LOG(LogGameAnalytics, Warning, TEXT("%hs(): wrong usage, for correct usage see: %s/event-tracking"), func, DOCS_LINK); 37 | } 38 | 39 | #define GA_USAGE_WARNING() GAPrintUsageWarning(__FUNCTION__) 40 | 41 | #if PLATFORM_IOS 42 | #define GA_GAME_KEY_NAME TEXT("ios_gameKey") 43 | #define GA_SECRET_KEY_NAME TEXT("ios_secretKey") 44 | #elif PLATFORM_ANDROID 45 | #define GA_GAME_KEY_NAME TEXT("android_gameKey") 46 | #define GA_SECRET_KEY_NAME TEXT("android_secretKey") 47 | #elif PLATFORM_MAC 48 | #define GA_GAME_KEY_NAME TEXT("mac_gameKey") 49 | #define GA_SECRET_KEY_NAME TEXT("mac_secretKey") 50 | #elif PLATFORM_WINDOWS 51 | #define GA_GAME_KEY_NAME TEXT("windows_gameKey") 52 | #define GA_SECRET_KEY_NAME TEXT("windows_secretKey") 53 | #elif PLATFORM_LINUX 54 | #define GA_GAME_KEY_NAME TEXT("linux_gameKey") 55 | #define GA_SECRET_KEY_NAME TEXT("linux_secretKey") 56 | #else 57 | #define GA_GAME_KEY_NAME TEXT("") 58 | #define GA_SECRET_KEY_NAME TEXT("") 59 | #endif 60 | 61 | FString FGameAnalyticsProvider::GenerateUserId() const 62 | { 63 | #if (ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 15) || (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 0) 64 | return FPlatformMisc::GetDeviceId(); 65 | #else 66 | return FPlatformMisc::GetUniqueDeviceId(); 67 | #endif 68 | } 69 | 70 | FString FGameAnalyticsProvider::GetAnalyticsPath() const 71 | { 72 | #if (ENGINE_MAJOR_VERSION >= 4 && ENGINE_MINOR_VERSION >= 18) || (ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 0) 73 | return FPaths::ProjectSavedDir(); 74 | #else 75 | return FPaths::GameSavedDir(); 76 | #endif 77 | } 78 | 79 | #if !UE_BUILD_SHIPPING 80 | /** 81 | * Verifies that the event name matches GameAnalytics's 32 char limit and warns if it doesn't 82 | */ 83 | inline void CheckEventNameLen(const FString& EventName) 84 | { 85 | constexpr int32 kMaxLength = 32; 86 | 87 | const int32 Length = EventName.Len(); 88 | if (Length > kMaxLength) 89 | { 90 | UE_LOG(LogGameAnalytics, Warning, TEXT("GameAnalytics event name is too long: %s and will be truncated by GameAnalytics. %i characters max limit."), *EventName, kMaxLength); 91 | } 92 | else if (Length == 0) 93 | { 94 | UE_LOG(LogGameAnalytics, Warning, TEXT("GameAnalytics event name is empty!")); 95 | } 96 | } 97 | 98 | #define WarnIfEventNameIsWrongLength(x) CheckEventNameLen(x) 99 | 100 | #else 101 | // Have these compile out 102 | #define WarnIfEventNameIsWrongLength(x) 103 | #endif 104 | 105 | // Provider 106 | FGameAnalyticsProvider::FGameAnalyticsProvider(UGameAnalytics* GameAnalytics) : 107 | bHasSessionStarted(false), 108 | bHasWrittenFirstEvent(false), 109 | Age(0), 110 | GameAnalytics(GameAnalytics) 111 | { 112 | AnalyticsFilePath = GetAnalyticsPath() + TEXT("Analytics/"); 113 | } 114 | 115 | FGameAnalyticsProvider::~FGameAnalyticsProvider() 116 | { 117 | UE_LOG(LogGameAnalytics, Display, TEXT("FGameAnalyticsModule ~FGameAnalyticsProvider")); 118 | } 119 | 120 | void FGameAnalyticsProvider::SetDefaultEventAttributes(TArray&& Attributes) 121 | { 122 | (void)Attributes; 123 | } 124 | 125 | TArray FGameAnalyticsProvider::GetDefaultEventAttributesSafe() const 126 | { 127 | return {}; 128 | } 129 | 130 | int32 FGameAnalyticsProvider::GetDefaultEventAttributeCount() const 131 | { 132 | return 0; 133 | } 134 | 135 | FAnalyticsEventAttribute FGameAnalyticsProvider::GetDefaultEventAttribute(int AttributeIndex) const 136 | { 137 | (void)AttributeIndex; 138 | return FAnalyticsEventAttribute(); 139 | } 140 | 141 | void FGameAnalyticsProvider::OnQuit() 142 | { 143 | GameAnalytics->OnQuit(); 144 | } 145 | 146 | bool FGameAnalyticsProvider::StartSession(const TArray& Attributes) 147 | { 148 | if(!bHasSessionStarted) 149 | { 150 | ProjectSettings = FGameAnalyticsModule::LoadProjectSettings(); 151 | 152 | auto PlatformInfo = ProjectSettings.GetActivePlatform(); 153 | 154 | GameAnalytics->SetWritablePath(GetAnalyticsPath()); 155 | 156 | ////// Enable log 157 | GameAnalytics->SetEnabledInfoLog(ProjectSettings.InfoLogBuild); 158 | GameAnalytics->SetEnabledVerboseLog(ProjectSettings.VerboseLogBuild); 159 | 160 | if(ProjectSettings.AutoDetectAppVersion) 161 | { 162 | GameAnalytics->ConfigureAutoDetectAppVersion(ProjectSettings.AutoDetectAppVersion); 163 | } 164 | 165 | if (ProjectSettings.DisableDeviceInfo) 166 | { 167 | GameAnalytics->DisableDeviceInfo(); 168 | } 169 | 170 | //// Configure build version 171 | if(!ProjectSettings.AutoDetectAppVersion) 172 | { 173 | GameAnalytics->ConfigureBuild(PlatformInfo.Build); 174 | } 175 | 176 | ////// Configure available virtual currencies and item types 177 | if (ProjectSettings.ResourceCurrencies.Num() > 0) 178 | { 179 | GameAnalytics->ConfigureAvailableResourceCurrencies(ProjectSettings.ResourceCurrencies); 180 | } 181 | 182 | if (ProjectSettings.ResourceItemTypes.Num() > 0) 183 | { 184 | GameAnalytics->ConfigureAvailableResourceItemTypes(ProjectSettings.ResourceItemTypes); 185 | } 186 | 187 | // Configure available custom dimensions 188 | if (ProjectSettings.CustomDimensions01.Num() > 0) 189 | { 190 | GameAnalytics->ConfigureAvailableCustomDimensions01(ProjectSettings.CustomDimensions01); 191 | } 192 | 193 | if (ProjectSettings.CustomDimensions02.Num() > 0) 194 | { 195 | GameAnalytics->ConfigureAvailableCustomDimensions02(ProjectSettings.CustomDimensions02); 196 | } 197 | 198 | if (ProjectSettings.CustomDimensions03.Num() > 0) 199 | { 200 | GameAnalytics->ConfigureAvailableCustomDimensions03(ProjectSettings.CustomDimensions03); 201 | } 202 | 203 | if(ProjectSettings.UseManualSessionHandling) 204 | { 205 | GameAnalytics->SetEnabledManualSessionHandling(ProjectSettings.UseManualSessionHandling); 206 | } 207 | 208 | GameAnalytics->SetEnabledErrorReporting(ProjectSettings.UseErrorReporting); 209 | 210 | const int32 AttrCount = Attributes.Num(); 211 | FString GameKey; 212 | FString SecretKey; 213 | if (AttrCount > 0) 214 | { 215 | for (auto Attr : Attributes) 216 | { 217 | if (Attr.GetName() == GA_GAME_KEY_NAME) 218 | { 219 | GameKey = Attr.GetValue(); 220 | } 221 | else if (Attr.GetName() == GA_SECRET_KEY_NAME) 222 | { 223 | SecretKey = Attr.GetValue(); 224 | } 225 | } 226 | } 227 | else 228 | { 229 | GameKey = PlatformInfo.GameKey; 230 | SecretKey = PlatformInfo.SecretKey; 231 | } 232 | 233 | GameAnalytics->Initialize(GameKey, SecretKey); 234 | bHasSessionStarted = true; 235 | } 236 | else if(ProjectSettings.UseManualSessionHandling) 237 | { 238 | GameAnalytics->StartSession(); 239 | } 240 | 241 | return bHasSessionStarted; 242 | } 243 | 244 | void FGameAnalyticsProvider::EndSession() 245 | { 246 | if (bHasSessionStarted) 247 | { 248 | if(ProjectSettings.UseManualSessionHandling) 249 | { 250 | GameAnalytics->EndSession(); 251 | } 252 | else 253 | { 254 | UE_LOG(LogGameAnalytics, Warning, TEXT("FGameAnalyticsProvider::EndSession ignored.")); 255 | } 256 | } 257 | } 258 | 259 | void FGameAnalyticsProvider::FlushEvents() 260 | { 261 | UE_LOG(LogGameAnalytics, Warning, TEXT("FGameAnalyticsProvider::FlushEvents ignored.")); 262 | } 263 | 264 | void FGameAnalyticsProvider::SetUserID(const FString& InUserID) 265 | { 266 | if(!bHasSessionStarted) 267 | { 268 | UE_LOG(LogGameAnalytics, Display, TEXT("GameAnalytics::SetCustomId('%s')"), *InUserID); 269 | GameAnalytics->ConfigureUserId(InUserID); 270 | UserId = InUserID; 271 | } 272 | else 273 | { 274 | UE_LOG(LogGameAnalytics, Warning, TEXT("FGameAnalyticsProvider::SetCustomId Custom id can only be set when SDK is not initialized.")); 275 | } 276 | } 277 | 278 | FString FGameAnalyticsProvider::GetUserID() const 279 | { 280 | return UserId; 281 | } 282 | 283 | FString FGameAnalyticsProvider::GetSessionID() const 284 | { 285 | UE_LOG(LogGameAnalytics, Warning, TEXT("FGameAnalyticsProvider::GetSessionID ignored.")); 286 | return SessionId; 287 | } 288 | 289 | bool FGameAnalyticsProvider::SetSessionID(const FString& InSessionID) 290 | { 291 | UE_LOG(LogGameAnalytics, Warning, TEXT("FGameAnalyticsProvider::SetSessionID ignored.")); 292 | return !bHasSessionStarted; 293 | } 294 | 295 | void FGameAnalyticsProvider::RecordEvent(const FString& EventName, const TArray& Attributes) 296 | { 297 | const int32 AttrCount = Attributes.Num(); 298 | if (AttrCount > 0) 299 | { 300 | // Send an event for each attribute 301 | for (auto& Attr : Attributes) 302 | { 303 | if (Attr.GetName() == TEXT("custom1")) 304 | { 305 | GameAnalytics->SetCustomDimension01(Attr.GetValue()); 306 | } 307 | else if (Attr.GetName() == TEXT("custom2")) 308 | { 309 | GameAnalytics->SetCustomDimension02(Attr.GetValue()); 310 | } 311 | else if (Attr.GetName() == TEXT("custom3")) 312 | { 313 | GameAnalytics->SetCustomDimension03(Attr.GetValue()); 314 | } 315 | else 316 | { 317 | float AttrValue = FCString::Atof(*Attr.GetValue()); 318 | GameAnalytics->AddDesignEventWithValue(Attr.GetName(), AttrValue); 319 | } 320 | } 321 | } 322 | else if (EventName.Len() > 0) 323 | { 324 | // Send an event without value 325 | GameAnalytics->AddDesignEvent(EventName); 326 | } 327 | } 328 | 329 | void FGameAnalyticsProvider::SetAge(int InAge) 330 | { 331 | } 332 | 333 | void FGameAnalyticsProvider::SetGender(const FString& InGender) 334 | { 335 | } 336 | 337 | void FGameAnalyticsProvider::RecordError(const FString& Error) 338 | { 339 | GameAnalytics->AddErrorEvent(EGAErrorSeverity::error, Error); 340 | } 341 | 342 | void FGameAnalyticsProvider::RecordError(const FString& Error, const TArray& Attributes) 343 | { 344 | const int32 AttrCount = Attributes.Num(); 345 | if (AttrCount > 0) 346 | { 347 | for (auto Attr : Attributes) 348 | { 349 | if (Attr.GetName() == TEXT("severity")) 350 | { 351 | FString const Key = Attr.GetValue().ToLower(); 352 | if (!kSeverityStrings.Contains(Key)) 353 | { 354 | UE_LOG(LogGameAnalytics, Warning, TEXT("RecordError: Severity value must be either debug, info, warning, error, critical. Error=%s"), *Error); 355 | return; 356 | } 357 | 358 | EGAErrorSeverity ErrorSeverity = kSeverityStrings[Key]; 359 | GameAnalytics->AddErrorEvent(ErrorSeverity, Error); 360 | } 361 | } 362 | } 363 | else 364 | { 365 | GA_USAGE_WARNING(); 366 | } 367 | } 368 | 369 | void FGameAnalyticsProvider::RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy) 370 | { 371 | FString const Key = ProgressType.ToLower(); 372 | if (!kProgressionStrings.Contains(Key)) 373 | { 374 | UE_LOG(LogGameAnalytics, Warning, TEXT("RecordProgress: ProgressType value must be either start, complete or fail. ProgressType=%s"), *ProgressType); 375 | return; 376 | } 377 | 378 | EGAProgressionStatus ProgressionStatus = kProgressionStrings[Key]; 379 | GameAnalytics->AddProgressionEvent(ProgressionStatus, ProgressHierarchy); 380 | } 381 | 382 | void FGameAnalyticsProvider::RecordProgress(const FString& ProgressType, const FString& ProgressHierarchy, const TArray& Attributes) 383 | { 384 | FString const Key = ProgressType.ToLower(); 385 | 386 | if (!kProgressionStrings.Contains(Key)) 387 | { 388 | UE_LOG(LogGameAnalytics, Warning, TEXT("RecordProgress: ProgressType value must be either start, complete or fail. ProgressType=%s"), *ProgressType); 389 | return; 390 | } 391 | 392 | EGAProgressionStatus ProgressionStatus = kProgressionStrings[Key]; 393 | 394 | for (auto& Attr : Attributes) 395 | { 396 | if (Attr.GetName() == TEXT("value")) 397 | { 398 | FString const& Val = Attr.GetValue(); 399 | if(Val.IsNumeric()) 400 | { 401 | int32 value = FCString::Atoi(*Val); 402 | GameAnalytics->AddProgressionEventWithScore(ProgressionStatus, value, ProgressHierarchy); 403 | return; 404 | } 405 | } 406 | } 407 | 408 | GameAnalytics->AddProgressionEvent(ProgressionStatus, ProgressHierarchy); 409 | } 410 | 411 | void FGameAnalyticsProvider::RecordProgress(const FString& ProgressType, const TArray& ProgressHierarchy, const TArray& Attributes) 412 | { 413 | FString const Key = ProgressType.ToLower(); 414 | 415 | if (!kProgressionStrings.Contains(Key)) 416 | { 417 | UE_LOG(LogGameAnalytics, Warning, TEXT("RecordProgress: ProgressType value must be either start, complete or fail. ProgressType=%s"), *ProgressType); 418 | return; 419 | } 420 | 421 | EGAProgressionStatus ProgressionStatus = kProgressionStrings[Key]; 422 | 423 | const int32 ProgressHierarchyCount = ProgressHierarchy.Num(); 424 | if(ProgressHierarchyCount > 0) 425 | { 426 | bool useValue = false; 427 | int32 value = 0; 428 | 429 | for (auto& Attr : Attributes) 430 | { 431 | UE_LOG(LogGameAnalytics, Warning, TEXT("RecordProgress: Attributes. AttrName=%s"), *Attr.GetName()); 432 | if (Attr.GetName() == TEXT("value")) 433 | { 434 | useValue = true; 435 | value = FCString::Atoi(*Attr.GetValue()); 436 | break; 437 | } 438 | } 439 | 440 | switch(ProgressHierarchyCount) 441 | { 442 | case 1: 443 | return useValue ? 444 | GameAnalytics->AddProgressionEventWithScore(ProgressionStatus, value, ProgressHierarchy[0]): 445 | GameAnalytics->AddProgressionEvent(ProgressionStatus, ProgressHierarchy[0]); 446 | 447 | case 2: 448 | return useValue ? 449 | GameAnalytics->AddProgressionEventWithScore(ProgressionStatus, value, ProgressHierarchy[0], ProgressHierarchy[1]): 450 | GameAnalytics->AddProgressionEvent(ProgressionStatus, ProgressHierarchy[0], ProgressHierarchy[1]); 451 | 452 | default: 453 | return useValue ? 454 | GameAnalytics->AddProgressionEventWithScore(ProgressionStatus, value, ProgressHierarchy[0], ProgressHierarchy[1], ProgressHierarchy[2]): 455 | GameAnalytics->AddProgressionEvent(ProgressionStatus, ProgressHierarchy[0], ProgressHierarchy[1], ProgressHierarchy[2]); 456 | } 457 | } 458 | else 459 | { 460 | GA_USAGE_WARNING(); 461 | } 462 | } 463 | 464 | void FGameAnalyticsProvider::RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) 465 | { 466 | UE_LOG(LogGameAnalytics, Warning, TEXT("FGameAnalyticsProvider::RecordItemPurchase(const FString& ItemId, const FString& Currency, int PerItemCost, int ItemQuantity) ignored. Please use instead: FGameAnalyticsProvider::RecordItemPurchase(const FString& ItemId, int ItemQuantity, const TArray& Attributes)")); 467 | } 468 | 469 | void FGameAnalyticsProvider::RecordItemPurchase(const FString& ItemId, int ItemQuantity, const TArray& Attributes) 470 | { 471 | EGAResourceFlowType FlowType = EGAResourceFlowType::source; 472 | FString Currency; 473 | FString ItemType; 474 | 475 | const int32 AttrCount = Attributes.Num(); 476 | if (AttrCount > 0) 477 | { 478 | for (auto& Attr : Attributes) 479 | { 480 | if (Attr.GetName() == TEXT("flowType")) 481 | { 482 | FString const Key = Attr.GetValue().ToLower(); 483 | if (!kFlowTypes.Contains(Key)) 484 | { 485 | UE_LOG(LogGameAnalytics, Warning, TEXT("RecordItemPurchaseError: FlowType value must be either sink or source. flowType=%s"), *Attr.GetValue()); 486 | return; 487 | } 488 | 489 | FlowType = kFlowTypes[Key]; 490 | } 491 | else if (Attr.GetName() == TEXT("currency")) 492 | { 493 | Currency = Attr.GetValue(); 494 | } 495 | else if (Attr.GetName() == TEXT("itemType")) 496 | { 497 | ItemType = Attr.GetValue(); 498 | } 499 | } 500 | 501 | if (!Currency.IsEmpty() && !ItemType.IsEmpty()) 502 | { 503 | GameAnalytics->AddResourceEvent(FlowType, Currency, ItemQuantity, ItemType, ItemId); 504 | } 505 | else 506 | { 507 | GA_USAGE_WARNING(); 508 | } 509 | } 510 | else 511 | { 512 | GA_USAGE_WARNING(); 513 | } 514 | } 515 | 516 | void FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) 517 | { 518 | UE_LOG(LogGameAnalytics, Display, TEXT("FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const FString& RealCurrencyType, float RealMoneyCost, const FString& PaymentProvider) - ignoring call. Instead use: FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const TArray& Attributes)")); 519 | } 520 | 521 | void FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount) 522 | { 523 | UE_LOG(LogGameAnalytics, Display, TEXT("FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount) - ignoring call. Instead use: FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const TArray& Attributes)")); 524 | } 525 | 526 | void FGameAnalyticsProvider::RecordCurrencyPurchase(const FString& GameCurrencyType, int GameCurrencyAmount, const TArray& Attributes) 527 | { 528 | FString ItemType; 529 | FString ItemId; 530 | FString CartType; 531 | FString Receipt; 532 | FString Signature; 533 | FString Store; 534 | bool AutoFetchReceipt = false; 535 | 536 | const int32 AttrCount = Attributes.Num(); 537 | if (AttrCount > 0) 538 | { 539 | for (auto& Attr : Attributes) 540 | { 541 | FString AttrString = Attr.GetName(); 542 | 543 | if (Attr.GetName() == TEXT("itemType")) 544 | { 545 | ItemType = Attr.GetValue(); 546 | } 547 | else if (Attr.GetName() == TEXT("itemId")) 548 | { 549 | ItemId = Attr.GetValue(); 550 | } 551 | else if (Attr.GetName() == TEXT("cartType")) 552 | { 553 | CartType = Attr.GetValue(); 554 | } 555 | else if (Attr.GetName() == TEXT("receipt")) 556 | { 557 | Receipt = Attr.GetValue(); 558 | } 559 | else if (Attr.GetName() == TEXT("autoFetchReceipt")) 560 | { 561 | if (Attr.GetValue().ToBool()) 562 | { 563 | AutoFetchReceipt = true; 564 | } 565 | } 566 | else if (Attr.GetName() == TEXT("signature")) 567 | { 568 | Signature = Attr.GetValue(); 569 | } 570 | else if (Attr.GetName() == TEXT("store")) 571 | { 572 | Store = Attr.GetValue(); 573 | } 574 | } 575 | 576 | if (!ItemType.IsEmpty() && !ItemId.IsEmpty() && !CartType.IsEmpty()) 577 | { 578 | if (!Receipt.IsEmpty()) 579 | { 580 | GameAnalytics->AddBusinessEventWithReceipt(GameCurrencyType, GameCurrencyAmount, ItemType, ItemId, CartType, Receipt, Store, Signature); 581 | } 582 | else if(AutoFetchReceipt) 583 | { 584 | GameAnalytics->AddBusinessEventAndAutoFetchReceipt(GameCurrencyType, GameCurrencyAmount, ItemType, ItemId, CartType); 585 | } 586 | else 587 | { 588 | GameAnalytics->AddBusinessEvent(GameCurrencyType, GameCurrencyAmount, ItemType, ItemId, CartType); 589 | } 590 | } 591 | else 592 | { 593 | GA_USAGE_WARNING(); 594 | } 595 | } 596 | else 597 | { 598 | GA_USAGE_WARNING(); 599 | } 600 | } 601 | 602 | void FGameAnalyticsProvider::RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount) 603 | { 604 | UE_LOG(LogGameAnalytics, Display, TEXT("GameAnalytics::RecordCurrencyGiven - ignoring call")); 605 | } 606 | 607 | void FGameAnalyticsProvider::RecordCurrencyGiven(const FString& GameCurrencyType, int GameCurrencyAmount, const TArray& Attributes) 608 | { 609 | UE_LOG(LogGameAnalytics, Display, TEXT("GameAnalytics::RecordCurrencyGiven - ignoring call")); 610 | } 611 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/GameAnalytics.cpp: -------------------------------------------------------------------------------- 1 | #include "GameAnalytics.h" 2 | 3 | #include "Misc/EngineVersion.h" 4 | #include "AnalyticsEventAttribute.h" 5 | #include "Serialization/JsonWriter.h" 6 | #include "Serialization/JsonSerializer.h" 7 | 8 | #include "GameAnalyticsPerformance.h" 9 | #include "GameAnalyticsModule.h" 10 | 11 | #define GA_VERSION TEXT("6.1.0") 12 | 13 | #if PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX 14 | #define GA_USE_CPP_SDK 1 15 | #include "Desktop/GAWrapperCpp.h" 16 | #else 17 | #define GA_USE_CPP_SDK 0 18 | #if PLATFORM_IOS 19 | #include "IOS/GAWrapperIOS.h" 20 | #elif PLATFORM_ANDROID 21 | #include "Android/GAWrapperAndroid.h" 22 | #endif 23 | #endif 24 | 25 | std::string ToStdString(const FString& str) 26 | { 27 | std::string s = TCHAR_TO_UTF8(*str); 28 | return s; 29 | } 30 | 31 | FString ToFString(std::string const& str) 32 | { 33 | FString s = UTF8_TO_TCHAR(str.c_str()); 34 | return s; 35 | } 36 | 37 | std::vector ToStringVector(const TArray& arr) 38 | { 39 | std::vector v; 40 | v.reserve(arr.Num()); 41 | 42 | for (const FString& item : arr) 43 | { 44 | v.push_back(ToStdString(item)); 45 | } 46 | 47 | return v; 48 | } 49 | 50 | inline constexpr auto BoolToStr(bool flag) 51 | { 52 | return flag ? TEXT("TRUE") : TEXT("FALSE"); 53 | } 54 | 55 | void PrintImplWarning(const char* funcName) 56 | { 57 | UE_LOG(LogGameAnalytics, Display, TEXT("UGameAnalytics::%hs(): This platform is not supported (please note GameAnalytics will not work inside the editor!)"), funcName); 58 | } 59 | 60 | #define GA_NOT_SUPPORTED_WARNING() PrintImplWarning(__FUNCTION__) 61 | 62 | void FGACustomFields::Set(FString const& key, double value) 63 | { 64 | FGACustomValue v = {}; 65 | 66 | v.Key = key; 67 | v.ValueNumber = value; 68 | v.ValueType = EGAValueType::value_number; 69 | 70 | Values.Push(std::move(v)); 71 | } 72 | 73 | void FGACustomFields::Set(FString const& key, FString const& value) 74 | { 75 | FGACustomValue v = {}; 76 | 77 | v.Key = key; 78 | v.ValueString = value; 79 | v.ValueType = EGAValueType::value_string; 80 | 81 | Values.Push(std::move(v)); 82 | } 83 | 84 | void FGACustomFields::Set(FString const& key, bool value) 85 | { 86 | FGACustomValue v = {}; 87 | 88 | v.Key = key; 89 | v.ValueBool = value; 90 | v.ValueType = EGAValueType::value_bool; 91 | 92 | Values.Push(std::move(v)); 93 | } 94 | 95 | bool FGACustomFields::IsEmpty() const 96 | { 97 | return Values.Num() == 0; 98 | } 99 | 100 | TSharedRef FGACustomFields::ToJson() const 101 | { 102 | TSharedRef Json = MakeShared(); 103 | for(auto& V : Values) 104 | { 105 | if(V.Key.IsEmpty()) 106 | { 107 | UE_LOG(LogGameAnalytics, Display, TEXT("Custom field key cannot be empty!")); 108 | continue; 109 | } 110 | 111 | switch(V.ValueType) 112 | { 113 | case EGAValueType::value_string: 114 | { 115 | Json->SetStringField(V.Key, V.ValueString); 116 | break; 117 | } 118 | 119 | case EGAValueType::value_bool: 120 | { 121 | Json->SetBoolField(V.Key, V.ValueBool); 122 | break; 123 | } 124 | 125 | case EGAValueType::value_number: 126 | default: 127 | { 128 | Json->SetNumberField(V.Key, V.ValueNumber); 129 | } 130 | } 131 | } 132 | 133 | return Json; 134 | } 135 | 136 | FString FGACustomFields::ToString() const 137 | { 138 | if(IsEmpty()) 139 | { 140 | return TEXT(""); 141 | } 142 | 143 | TSharedRef Json = ToJson(); 144 | 145 | FString FieldsString; 146 | TSharedRef> Writer = TJsonWriterFactory<>::Create(&FieldsString); 147 | FJsonSerializer::Serialize(Json, Writer); 148 | 149 | return FieldsString; 150 | } 151 | 152 | UGameAnalytics* UGameAnalytics::GetInstance() 153 | { 154 | return FGameAnalyticsModule::Get().GetInstance(); 155 | } 156 | 157 | UGameAnalytics::UGameAnalytics(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) 158 | { 159 | #if WITH_EDITOR 160 | _impl.Reset(nullptr); 161 | #elif PLATFORM_IOS 162 | _impl.Reset(new gameanalytics::GAWrapperIOS); 163 | #elif PLATFORM_ANDROID 164 | _impl.Reset(new gameanalytics::GAWrapperAndroid); 165 | #elif GA_USE_CPP_SDK 166 | _impl.Reset(new gameanalytics::GAWrapperCpp); 167 | #endif 168 | } 169 | 170 | void UGameAnalytics::BeginDestroy() 171 | { 172 | OnQuit(); 173 | 174 | if(IsValid(_performanceTracker)) 175 | { 176 | _performanceTracker->RemoveFromRoot(); 177 | } 178 | 179 | Super::BeginDestroy(); 180 | } 181 | 182 | void UGameAnalytics::ConfigureAvailableCustomDimensions01(const TArray& list) 183 | { 184 | if(_impl) 185 | { 186 | std::vector v = ToStringVector(list); 187 | _impl->SetAvailableCustomDimensions01(v); 188 | } 189 | else 190 | { 191 | GA_NOT_SUPPORTED_WARNING(); 192 | } 193 | } 194 | 195 | void UGameAnalytics::ConfigureAvailableCustomDimensions02(const TArray& list) 196 | { 197 | if(_impl) 198 | { 199 | std::vector v = ToStringVector(list); 200 | _impl->SetAvailableCustomDimensions02(v); 201 | } 202 | else 203 | { 204 | GA_NOT_SUPPORTED_WARNING(); 205 | } 206 | } 207 | 208 | void UGameAnalytics::ConfigureAvailableCustomDimensions03(const TArray& list) 209 | { 210 | if(_impl) 211 | { 212 | std::vector v = ToStringVector(list); 213 | _impl->SetAvailableCustomDimensions03(v); 214 | } 215 | else 216 | { 217 | GA_NOT_SUPPORTED_WARNING(); 218 | } 219 | } 220 | 221 | void UGameAnalytics::ConfigureAvailableResourceCurrencies(const TArray& list) 222 | { 223 | if(_impl) 224 | { 225 | std::vector v = ToStringVector(list); 226 | _impl->SetAvailableResourceCurrencies(v); 227 | } 228 | else 229 | { 230 | GA_NOT_SUPPORTED_WARNING(); 231 | } 232 | } 233 | 234 | void UGameAnalytics::ConfigureAvailableResourceItemTypes(const TArray& list) 235 | { 236 | if(_impl) 237 | { 238 | std::vector v = ToStringVector(list); 239 | _impl->SetAvailableResourceItemTypes(v); 240 | } 241 | else 242 | { 243 | GA_NOT_SUPPORTED_WARNING(); 244 | } 245 | } 246 | 247 | void UGameAnalytics::ConfigureBuild(FString const& build) 248 | { 249 | if(_impl) 250 | { 251 | _impl->SetBuild(ToStdString(build)); 252 | } 253 | else 254 | { 255 | GA_NOT_SUPPORTED_WARNING(); 256 | } 257 | } 258 | 259 | void UGameAnalytics::ConfigureAutoDetectAppVersion(bool flag) 260 | { 261 | if(_impl) 262 | { 263 | _impl->SetAutoDetectAppVersion(flag); 264 | } 265 | else 266 | { 267 | GA_NOT_SUPPORTED_WARNING(); 268 | } 269 | } 270 | 271 | void UGameAnalytics::DisableDeviceInfo() 272 | { 273 | if(_impl) 274 | { 275 | //_impl->DisableDeviceInfo(flag); 276 | } 277 | else 278 | { 279 | GA_NOT_SUPPORTED_WARNING(); 280 | } 281 | } 282 | 283 | void UGameAnalytics::ConfigureUserId(FString const& UserId) 284 | { 285 | if(_impl) 286 | { 287 | _impl->SetCustomUserId(ToStdString(UserId)); 288 | } 289 | else 290 | { 291 | GA_NOT_SUPPORTED_WARNING(); 292 | } 293 | } 294 | 295 | void UGameAnalytics::ConfigureExternalUserId(FString const& UserId) 296 | { 297 | if (_impl) 298 | { 299 | _impl->SetExternalUserId(ToStdString(UserId)); 300 | } 301 | else 302 | { 303 | GA_NOT_SUPPORTED_WARNING(); 304 | } 305 | } 306 | 307 | void UGameAnalytics::ConfigureSdkGameEngineVersion(FString const& gameEngineSdkVersion) 308 | { 309 | if(_impl) 310 | { 311 | _impl->SetSDKVersion(ToStdString(gameEngineSdkVersion)); 312 | } 313 | else 314 | { 315 | GA_NOT_SUPPORTED_WARNING(); 316 | } 317 | } 318 | 319 | void UGameAnalytics::ConfigureGameEngineVersion(FString const& gameEngineVersion) 320 | { 321 | if(_impl) 322 | { 323 | _impl->SetSDKVersion(ToStdString(gameEngineVersion)); 324 | } 325 | else 326 | { 327 | GA_NOT_SUPPORTED_WARNING(); 328 | } 329 | } 330 | 331 | void UGameAnalytics::Initialize(FString const& gameKey, FString const& gameSecret) 332 | { 333 | if(_impl) 334 | { 335 | // Configure engine version 336 | FString EngineVersionString = FString::Printf(TEXT("unreal %d.%d.%d"), FEngineVersion::Current().GetMajor(), FEngineVersion::Current().GetMinor(), FEngineVersion::Current().GetPatch()); 337 | ConfigureGameEngineVersion(EngineVersionString); 338 | 339 | // Configure sdk version 340 | FString SdkVersionString = FString::Printf(TEXT("unreal %s"), GA_VERSION); 341 | ConfigureSdkGameEngineVersion(SdkVersionString); 342 | 343 | _impl->Initialize(ToStdString(gameKey), ToStdString(gameSecret)); 344 | } 345 | else 346 | { 347 | GA_NOT_SUPPORTED_WARNING(); 348 | } 349 | } 350 | 351 | void UGameAnalytics::AddBusinessEvent(FString const& Currency, int Amount, FString const& ItemType, FString const& ItemId, FString const& CartType, FString const& Receipt, const FGACustomFields CustomFields, bool MergeFields) 352 | { 353 | if(_impl) 354 | { 355 | _impl->AddBusinessEvent(ToStdString(Currency), Amount, ToStdString(ItemType), ToStdString(ItemId), ToStdString(CartType), ToStdString(Receipt), ToStdString(CustomFields.ToString()), MergeFields); 356 | } 357 | else 358 | { 359 | GA_NOT_SUPPORTED_WARNING(); 360 | } 361 | } 362 | 363 | void UGameAnalytics::AddBusinessEventAndAutoFetchReceipt(FString const& currency, int amount, FString const& itemType, FString const& itemId, FString const& cartType, const FGACustomFields CustomFields, bool mergeFields) 364 | { 365 | if(_impl) 366 | { 367 | _impl->AddBusinessEventAndAutoFetchReceipt(ToStdString(currency), amount, ToStdString(itemType), ToStdString(itemId), ToStdString(cartType), ToStdString(CustomFields.ToString()), mergeFields); 368 | } 369 | else 370 | { 371 | GA_NOT_SUPPORTED_WARNING(); 372 | } 373 | } 374 | 375 | void UGameAnalytics::AddBusinessEventWithReceipt(FString const& Currency, int Amount, FString const& ItemType, FString const& ItemId, FString const& CartType, FString const& Receipt, FString const& Store, FString const& Signature, const FGACustomFields CustomFields, bool MergeFields) 376 | { 377 | if(_impl) 378 | { 379 | _impl->AddBusinessEventWithReceipt(ToStdString(Currency), Amount, ToStdString(ItemType), ToStdString(ItemId), ToStdString(CartType), ToStdString(Receipt), ToStdString(Store), ToStdString(Signature), ToStdString(CustomFields.ToString()), MergeFields); 380 | } 381 | else 382 | { 383 | GA_NOT_SUPPORTED_WARNING(); 384 | } 385 | } 386 | 387 | void UGameAnalytics::AddProgressionEvent(EGAProgressionStatus ProgressionStatus, const FString &Progression01, const FString &Progression02, const FString &Progression03, const FGACustomFields CustomFields, bool MergeFields) 388 | { 389 | if(_impl) 390 | { 391 | _impl->AddProgressionEvent(ProgressionStatus, ToStdString(Progression01), ToStdString(Progression02), ToStdString(Progression03), ToStdString(CustomFields.ToString()), MergeFields); 392 | } 393 | else 394 | { 395 | GA_NOT_SUPPORTED_WARNING(); 396 | } 397 | } 398 | 399 | void UGameAnalytics::AddProgressionEventWithScore(EGAProgressionStatus ProgressionStatus, int Score, const FString &Progression01, const FString &Progression02, const FString &Progression03, const FGACustomFields CustomFields, bool MergeFields) 400 | { 401 | if(_impl) 402 | { 403 | _impl->AddProgressionEventWithScore(ProgressionStatus, ToStdString(Progression01), ToStdString(Progression02), ToStdString(Progression03), Score, ToStdString(CustomFields.ToString()), MergeFields); 404 | } 405 | else 406 | { 407 | GA_NOT_SUPPORTED_WARNING(); 408 | } 409 | } 410 | 411 | void UGameAnalytics::AddDesignEvent(FString const& eventId, const FGACustomFields CustomFields, bool mergeFields) 412 | { 413 | if(_impl) 414 | { 415 | _impl->AddDesignEvent(ToStdString(eventId), ToStdString(CustomFields.ToString()), mergeFields); 416 | } 417 | else 418 | { 419 | GA_NOT_SUPPORTED_WARNING(); 420 | } 421 | } 422 | 423 | void UGameAnalytics::AddDesignEventWithValue(FString const& eventId, float value, const FGACustomFields CustomFields, bool mergeFields) 424 | { 425 | if(_impl) 426 | { 427 | _impl->AddDesignEventWithValue(ToStdString(eventId), value, ToStdString(CustomFields.ToString()), mergeFields); 428 | } 429 | else 430 | { 431 | GA_NOT_SUPPORTED_WARNING(); 432 | } 433 | } 434 | 435 | void UGameAnalytics::AddErrorEvent(EGAErrorSeverity severity, FString const& message, const FGACustomFields CustomFields, bool mergeFields) 436 | { 437 | if(_impl) 438 | { 439 | _impl->AddErrorEvent(severity, ToStdString(message), ToStdString(CustomFields.ToString()), mergeFields); 440 | } 441 | else 442 | { 443 | GA_NOT_SUPPORTED_WARNING(); 444 | } 445 | } 446 | 447 | void UGameAnalytics::AddResourceEvent(EGAResourceFlowType FlowType, const FString& Currency, float Amount, const FString& ItemType, const FString& ItemId, const FGACustomFields CustomFields, bool MergeFields) 448 | { 449 | if(_impl) 450 | { 451 | _impl->AddResourceEvent(FlowType, ToStdString(Currency), Amount, ToStdString(ItemType), ToStdString(ItemId), ToStdString(CustomFields.ToString()), MergeFields); 452 | } 453 | else 454 | { 455 | GA_NOT_SUPPORTED_WARNING(); 456 | } 457 | } 458 | 459 | void UGameAnalytics::AddAdEvent(EGAAdAction action, EGAAdType adType, const FString& adSdkName, const FString& adPlacement, const FGACustomFields CustomFields, bool mergeFields) 460 | { 461 | if(_impl) 462 | { 463 | _impl->AddAdEvent(action, adType, ToStdString(adSdkName), ToStdString(adPlacement), ToStdString(CustomFields.ToString()), mergeFields); 464 | } 465 | else 466 | { 467 | GA_NOT_SUPPORTED_WARNING(); 468 | } 469 | } 470 | 471 | void UGameAnalytics::AddAdEventWithDuration(EGAAdAction Action, EGAAdType AdType, const FString& AdSdkName, const FString& AdPlacement, int64 Duration, const FGACustomFields CustomFields, bool MergeFields) 472 | { 473 | if(_impl) 474 | { 475 | _impl->AddAdEventWithDuration(Action, AdType, ToStdString(AdSdkName), ToStdString(AdPlacement), Duration, ToStdString(CustomFields.ToString()), MergeFields); 476 | } 477 | else 478 | { 479 | GA_NOT_SUPPORTED_WARNING(); 480 | } 481 | } 482 | 483 | void UGameAnalytics::AddAdEventWithReason(EGAAdAction Action, EGAAdType AdType, const FString& AdSdkName, const FString& AdPlacement, EGAAdError Reason, const FGACustomFields CustomFields, bool MergeFields) 484 | { 485 | if(_impl) 486 | { 487 | _impl->AddAdEventWithReason(Action, AdType, ToStdString(AdSdkName), ToStdString(AdPlacement), Reason, ToStdString(CustomFields.ToString()), MergeFields); 488 | } 489 | else 490 | { 491 | GA_NOT_SUPPORTED_WARNING(); 492 | } 493 | } 494 | 495 | void UGameAnalytics::SetEnabledInfoLog(bool flag) 496 | { 497 | if(_impl) 498 | { 499 | _impl->SetInfoLog(flag); 500 | } 501 | else 502 | { 503 | GA_NOT_SUPPORTED_WARNING(); 504 | } 505 | } 506 | 507 | void UGameAnalytics::SetEnabledVerboseLog(bool flag) 508 | { 509 | if(_impl) 510 | { 511 | _impl->SetVerboseLog(flag); 512 | } 513 | else 514 | { 515 | GA_NOT_SUPPORTED_WARNING(); 516 | } 517 | } 518 | 519 | void UGameAnalytics::SetEnabledManualSessionHandling(bool flag) 520 | { 521 | if(_impl) 522 | { 523 | _impl->SetEnabledManualSessionHandling(flag); 524 | } 525 | else 526 | { 527 | GA_NOT_SUPPORTED_WARNING(); 528 | } 529 | } 530 | 531 | void UGameAnalytics::SetEnabledErrorReporting(bool flag) 532 | { 533 | if(_impl) 534 | { 535 | _impl->SetEnabledErrorReporting(flag); 536 | } 537 | else 538 | { 539 | GA_NOT_SUPPORTED_WARNING(); 540 | } 541 | } 542 | 543 | void UGameAnalytics::SetEnabledEventSubmission(bool flag) 544 | { 545 | if(_impl) 546 | { 547 | _impl->SetEnabledEventSubmission(flag, false); 548 | } 549 | else 550 | { 551 | GA_NOT_SUPPORTED_WARNING(); 552 | } 553 | } 554 | 555 | void UGameAnalytics::SetCustomDimension01(FString const& customDimension) 556 | { 557 | if(_impl) 558 | { 559 | _impl->SetCustomDimension01(ToStdString(customDimension)); 560 | } 561 | else 562 | { 563 | GA_NOT_SUPPORTED_WARNING(); 564 | } 565 | } 566 | 567 | void UGameAnalytics::SetCustomDimension02(FString const& customDimension) 568 | { 569 | if(_impl) 570 | { 571 | _impl->SetCustomDimension02(ToStdString(customDimension)); 572 | } 573 | else 574 | { 575 | GA_NOT_SUPPORTED_WARNING(); 576 | } 577 | } 578 | 579 | void UGameAnalytics::SetCustomDimension03(FString const& customDimension) 580 | { 581 | if(_impl) 582 | { 583 | _impl->SetCustomDimension03(ToStdString(customDimension)); 584 | } 585 | else 586 | { 587 | GA_NOT_SUPPORTED_WARNING(); 588 | } 589 | } 590 | 591 | FString UGameAnalytics::GetUserId() 592 | { 593 | if (_impl) 594 | { 595 | FString uid = ToFString(_impl->GetUserId()); 596 | return uid; 597 | } 598 | else 599 | { 600 | GA_NOT_SUPPORTED_WARNING(); 601 | return TEXT(""); 602 | } 603 | } 604 | 605 | FString UGameAnalytics::GetExternalUserId() 606 | { 607 | if (_impl) 608 | { 609 | FString uid = ToFString(_impl->GetExternalUserId()); 610 | return uid; 611 | } 612 | else 613 | { 614 | GA_NOT_SUPPORTED_WARNING(); 615 | return TEXT(""); 616 | } 617 | } 618 | 619 | void UGameAnalytics::StartSession() 620 | { 621 | if(_impl) 622 | { 623 | _impl->StartSession(); 624 | } 625 | else 626 | { 627 | GA_NOT_SUPPORTED_WARNING(); 628 | } 629 | } 630 | 631 | void UGameAnalytics::EndSession() 632 | { 633 | if(_impl) 634 | { 635 | _impl->EndSession(); 636 | } 637 | else 638 | { 639 | GA_NOT_SUPPORTED_WARNING(); 640 | } 641 | } 642 | 643 | void UGameAnalytics::OnQuit() 644 | { 645 | if(_impl) 646 | { 647 | _impl->OnQuit(); 648 | } 649 | else 650 | { 651 | GA_NOT_SUPPORTED_WARNING(); 652 | } 653 | } 654 | 655 | FString UGameAnalytics::GetRemoteConfigsValueAsString(FString const& key, FString const& defaultValue) 656 | { 657 | if(_impl) 658 | { 659 | std::string val = _impl->GetRemoteConfigsValueAsString(ToStdString(key), ToStdString(defaultValue)); 660 | return ToFString(val); 661 | } 662 | else 663 | { 664 | GA_NOT_SUPPORTED_WARNING(); 665 | return defaultValue; 666 | } 667 | } 668 | 669 | TSharedPtr UGameAnalytics::GetRemoteConfigsValueAsJSON(FString const& key) 670 | { 671 | TSharedPtr Json(new FJsonObject); 672 | 673 | if(_impl) 674 | { 675 | FString JsonString = GetRemoteConfigsValueAsString(key); 676 | TSharedRef> Reader = FJsonStringReader::Create(JsonString); 677 | FJsonSerializer::Deserialize(Reader, Json); 678 | } 679 | else 680 | { 681 | GA_NOT_SUPPORTED_WARNING(); 682 | } 683 | 684 | return Json; 685 | } 686 | 687 | 688 | bool UGameAnalytics::IsRemoteConfigsReady() 689 | { 690 | if(_impl) 691 | { 692 | return _impl->IsRemoteConfigsReady(); 693 | } 694 | else 695 | { 696 | GA_NOT_SUPPORTED_WARNING(); 697 | return false; 698 | } 699 | } 700 | 701 | FString UGameAnalytics::GetRemoteConfigsContentAsString() 702 | { 703 | if(_impl) 704 | { 705 | std::string remoteConfigs = _impl->GetRemoteConfigsContentAsString(); 706 | return ToFString(remoteConfigs); 707 | } 708 | else 709 | { 710 | GA_NOT_SUPPORTED_WARNING(); 711 | return TEXT(""); 712 | } 713 | } 714 | 715 | FString UGameAnalytics::GetABTestingId() 716 | { 717 | if(_impl) 718 | { 719 | std::string abTestingId = _impl->GetABTestingId(); 720 | return ToFString(abTestingId); 721 | } 722 | else 723 | { 724 | GA_NOT_SUPPORTED_WARNING(); 725 | return TEXT(""); 726 | } 727 | } 728 | 729 | FString UGameAnalytics::GetABTestingVariantId() 730 | { 731 | if(_impl) 732 | { 733 | std::string abTestingVarId = _impl->GetABTestingVariantId(); 734 | return ToFString(abTestingVarId); 735 | } 736 | else 737 | { 738 | GA_NOT_SUPPORTED_WARNING(); 739 | return TEXT(""); 740 | } 741 | } 742 | 743 | void UGameAnalytics::EnableSDKInitEvent(bool value) 744 | { 745 | if(_impl) 746 | { 747 | _impl->EnableSDKInitEvent(value); 748 | } 749 | else 750 | { 751 | GA_NOT_SUPPORTED_WARNING(); 752 | } 753 | } 754 | 755 | void UGameAnalytics::EnableFpsHistogram(bool value) 756 | { 757 | if(_impl) 758 | { 759 | if(value && !_performanceTracker) 760 | { 761 | _performanceTracker = NewObject(); 762 | _performanceTracker->AddToRoot(); 763 | } 764 | 765 | if(_performanceTracker) 766 | { 767 | _performanceTracker->EnableFPSTracking = value; 768 | } 769 | 770 | gameanalytics::FPSTracker tracker = [this]() -> float 771 | { 772 | return _performanceTracker->GetAvgFps(); 773 | }; 774 | 775 | _impl->EnableFpsHistogram(tracker, value); 776 | } 777 | else 778 | { 779 | GA_NOT_SUPPORTED_WARNING(); 780 | } 781 | } 782 | 783 | void UGameAnalytics::EnableMemoryHistogram(bool value) 784 | { 785 | if(_impl) 786 | { 787 | _impl->EnableMemoryHistogram(value); 788 | } 789 | else 790 | { 791 | GA_NOT_SUPPORTED_WARNING(); 792 | } 793 | } 794 | 795 | void UGameAnalytics::EnableHealthHardwareInfo(bool value) 796 | { 797 | if(_impl) 798 | { 799 | _impl->EnableHealthHardwareInfo(value); 800 | } 801 | else 802 | { 803 | GA_NOT_SUPPORTED_WARNING(); 804 | } 805 | } 806 | 807 | void UGameAnalytics::EnableAdvertisingId(bool value) 808 | { 809 | if(_impl) 810 | { 811 | _impl->EnableAdvertisingId(value); 812 | } 813 | else 814 | { 815 | GA_NOT_SUPPORTED_WARNING(); 816 | } 817 | } 818 | 819 | int64 UGameAnalytics::GetElapsedSessionTime() 820 | { 821 | if (_impl) 822 | { 823 | return _impl->GetElapsedSessionTime(); 824 | } 825 | else 826 | { 827 | GA_NOT_SUPPORTED_WARNING(); 828 | return 0; 829 | } 830 | } 831 | 832 | int64 UGameAnalytics::GetElapsedTimeFromAllSessions() 833 | { 834 | if (_impl) 835 | { 836 | return _impl->GetElapsedTimeFromAllSessions(); 837 | } 838 | else 839 | { 840 | GA_NOT_SUPPORTED_WARNING(); 841 | return 0; 842 | } 843 | } 844 | 845 | void UGameAnalytics::SetWritablePath(FString const& path) 846 | { 847 | if(_impl) 848 | { 849 | _impl->SetWritablePath(ToStdString(path)); 850 | } 851 | else 852 | { 853 | GA_NOT_SUPPORTED_WARNING(); 854 | } 855 | } 856 | 857 | -------------------------------------------------------------------------------- /GameAnalytics/Source/GameAnalytics/Private/IOS/GAWrapperIOS.mm: -------------------------------------------------------------------------------- 1 | #import "GameAnalytics/GA-SDK-IOS/GameAnalytics.h" 2 | #import "GAWrapperIOS.h" 3 | 4 | 5 | // Objective-C++ wrapper for FPSTracker 6 | @interface GAHealthMetricsProvider : NSObject 7 | { 8 | std::function fpsTracker; 9 | } 10 | - (instancetype)initWithFPSTracker:(const std::function&)tracker; 11 | @end 12 | 13 | @implementation GAHealthMetricsProvider 14 | - (instancetype)initWithFPSTracker:(const std::function&)tracker { 15 | self = [super init]; 16 | if (self) { 17 | fpsTracker = tracker; 18 | } 19 | return self; 20 | } 21 | - (double)provideCurrentFPS { 22 | if (fpsTracker) { 23 | return (double)fpsTracker(); 24 | } 25 | return -1.0; 26 | } 27 | @end 28 | 29 | namespace gameanalytics 30 | { 31 | NSString* ToNSString(std::string const& str) 32 | { 33 | NSString *s = (!str.empty()) ? [NSString stringWithUTF8String:str.c_str()] : nil; 34 | return s; 35 | } 36 | 37 | std::string FromNSString(NSString* str) 38 | { 39 | std::string s = (str != nil) ? [str UTF8String] : ""; 40 | return s; 41 | } 42 | 43 | void GAWrapperIOS::SetAvailableCustomDimensions01(const std::vector& list) 44 | { 45 | NSMutableArray * tmpary = [[NSMutableArray alloc] initWithCapacity: list.size()]; 46 | for (const std::string& s : list) 47 | { 48 | [tmpary addObject: [NSString stringWithUTF8String: s.c_str()]]; 49 | } 50 | NSArray *list_array = tmpary; 51 | [GameAnalytics configureAvailableCustomDimensions01:list_array]; 52 | } 53 | 54 | void GAWrapperIOS::SetAvailableCustomDimensions02(const std::vector& list) { 55 | NSMutableArray * tmpary = [[NSMutableArray alloc] initWithCapacity: list.size()]; 56 | for (const std::string& s : list) 57 | { 58 | [tmpary addObject: [NSString stringWithUTF8String: s.c_str()]]; 59 | } 60 | NSArray *list_array = tmpary; 61 | [GameAnalytics configureAvailableCustomDimensions02:list_array]; 62 | } 63 | 64 | void GAWrapperIOS::SetAvailableCustomDimensions03(const std::vector& list) { 65 | NSMutableArray * tmpary = [[NSMutableArray alloc] initWithCapacity: list.size()]; 66 | for (const std::string& s : list) 67 | { 68 | [tmpary addObject: [NSString stringWithUTF8String: s.c_str()]]; 69 | } 70 | NSArray *list_array = tmpary; 71 | [GameAnalytics configureAvailableCustomDimensions03:list_array]; 72 | } 73 | 74 | void GAWrapperIOS::SetAvailableResourceCurrencies(const std::vector& list) { 75 | NSMutableArray * tmpary = [[NSMutableArray alloc] initWithCapacity: list.size()]; 76 | for (const std::string& s : list) 77 | { 78 | [tmpary addObject: [NSString stringWithUTF8String: s.c_str()]]; 79 | } 80 | NSArray *list_array = tmpary; 81 | [GameAnalytics configureAvailableResourceCurrencies:list_array]; 82 | } 83 | 84 | void GAWrapperIOS::SetAvailableResourceItemTypes(const std::vector& list) { 85 | NSMutableArray * tmpary = [[NSMutableArray alloc] initWithCapacity: list.size()]; 86 | for (const std::string& s : list) 87 | { 88 | [tmpary addObject: [NSString stringWithUTF8String: s.c_str()]]; 89 | } 90 | NSArray *list_array = tmpary; 91 | [GameAnalytics configureAvailableResourceItemTypes:list_array]; 92 | } 93 | 94 | void GAWrapperIOS::SetBuild(std::string const& build) { 95 | NSString *buildString = ToNSString(build); 96 | [GameAnalytics configureBuild:buildString]; 97 | } 98 | 99 | void GAWrapperIOS::SetAutoDetectAppVersion(bool flag) { 100 | [GameAnalytics configureAutoDetectAppVersion:flag]; 101 | } 102 | 103 | void GAWrapperIOS::SetCustomUserId(std::string const& userId) { 104 | NSString *userIdString = ToNSString(userId); 105 | [GameAnalytics configureUserId:userIdString]; 106 | } 107 | 108 | void GAWrapperIOS::SetGameEngineVersion(std::string const& gameEngineSdkVersion) { 109 | NSString *gameEngineSdkVersionString = ToNSString(gameEngineSdkVersion); 110 | [GameAnalytics configureSdkVersion:gameEngineSdkVersionString]; 111 | } 112 | 113 | void GAWrapperIOS::SetSDKVersion(std::string const& sdkVersion) { 114 | NSString *sdkVersionString = ToNSString(sdkVersion); 115 | [GameAnalytics configureSdkVersion:sdkVersionString]; 116 | } 117 | 118 | void GAWrapperIOS::SetGlobalCustomEventFields(std::string const& fields) { 119 | 120 | NSString *jsonString = ToNSString(fields); 121 | NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; 122 | 123 | NSError *error = nil; 124 | NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; 125 | 126 | if (!error) 127 | { 128 | [GameAnalytics setGlobalCustomEventFields:jsonDict]; 129 | } 130 | } 131 | 132 | void GAWrapperIOS::Initialize(std::string const& gameKey, std::string const& gameSecret) { 133 | NSString *gameKeyString = ToNSString(gameKey); 134 | NSString *gameSecretString = ToNSString(gameSecret); 135 | 136 | [GameAnalytics initializeWithGameKey:gameKeyString gameSecret:gameSecretString]; 137 | } 138 | 139 | void GAWrapperIOS::AddBusinessEvent(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& fields, bool mergeFields) { 140 | NSString *currencyString = ToNSString(currency); 141 | NSInteger amountInteger = (NSInteger)amount; 142 | NSString *itemTypeString = ToNSString(itemType); 143 | NSString *itemIdString = ToNSString(itemId); 144 | NSString *cartTypeString = ToNSString(cartType); 145 | NSString *receiptString = ToNSString(receipt); 146 | NSString *fieldsString = ToNSString(fields); 147 | NSDictionary *fields_dict = nil; 148 | if (fieldsString) { 149 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 150 | } 151 | 152 | [GameAnalytics addBusinessEventWithCurrency:currencyString 153 | amount:amountInteger 154 | itemType:itemTypeString 155 | itemId:itemIdString 156 | cartType:cartTypeString 157 | receipt:receiptString 158 | customFields:fields_dict 159 | mergeFields:mergeFields]; 160 | } 161 | 162 | void GAWrapperIOS::AddBusinessEventWithReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& receipt, std::string const& store, std::string const& signature, std::string const& fields, bool mergeFields) 163 | { 164 | return AddBusinessEvent(currency, amount, itemType, itemId, cartType, receipt, fields, mergeFields); 165 | } 166 | 167 | void GAWrapperIOS::AddBusinessEventAndAutoFetchReceipt(std::string const& currency, int amount, std::string const& itemType, std::string const& itemId, std::string const& cartType, std::string const& fields, bool mergeFields) { 168 | NSString *currencyString = ToNSString(currency); 169 | NSInteger amountInteger = (NSInteger)amount; 170 | NSString *itemTypeString = ToNSString(itemType); 171 | NSString *itemIdString = ToNSString(itemId); 172 | NSString *cartTypeString = ToNSString(cartType); 173 | NSString *fieldsString = ToNSString(fields); 174 | NSDictionary *fields_dict = nil; 175 | if (fieldsString) { 176 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 177 | } 178 | 179 | [GameAnalytics addBusinessEventWithCurrency:currencyString 180 | amount:amountInteger 181 | itemType:itemTypeString 182 | itemId:itemIdString 183 | cartType:cartTypeString 184 | autoFetchReceipt:true 185 | customFields:fields_dict 186 | mergeFields:mergeFields]; 187 | } 188 | 189 | void GAWrapperIOS::AddResourceEvent(EGAResourceFlowType flowType, std::string const& currency, float amount, std::string const& itemType, std::string const& itemId, std::string const& fields, bool mergeFields) { 190 | NSString *currencyString = ToNSString(currency); 191 | NSNumber* amountNumber = [NSNumber numberWithFloat:amount];; 192 | NSString *itemTypeString = ToNSString(itemType); 193 | NSString *itemIdString = ToNSString(itemId); 194 | NSString *fieldsString = ToNSString(fields); 195 | NSDictionary *fields_dict = nil; 196 | if (fieldsString) { 197 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 198 | } 199 | 200 | [GameAnalytics addResourceEventWithFlowType:(GAResourceFlowType)flowType 201 | currency:currencyString 202 | amount:amountNumber 203 | itemType:itemTypeString 204 | itemId:itemIdString 205 | customFields:fields_dict 206 | mergeFields:mergeFields]; 207 | } 208 | 209 | void GAWrapperIOS::AddProgressionEvent(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, std::string const& fields, bool mergeFields) { 210 | NSString *progression01String = ToNSString(progression01); 211 | NSString *progression02String = ToNSString(progression02); 212 | NSString *progression03String = ToNSString(progression03); 213 | NSString *fieldsString = ToNSString(fields); 214 | NSDictionary *fields_dict = nil; 215 | if (fieldsString) { 216 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 217 | } 218 | 219 | [GameAnalytics addProgressionEventWithProgressionStatus:(GAProgressionStatus)progressionStatus 220 | progression01:progression01String 221 | progression02:progression02String 222 | progression03:progression03String 223 | customFields:fields_dict 224 | mergeFields:mergeFields]; 225 | } 226 | 227 | void GAWrapperIOS::AddProgressionEventWithScore(EGAProgressionStatus progressionStatus, std::string const& progression01, std::string const& progression02, std::string const& progression03, int score, std::string const& fields, bool mergeFields) { 228 | NSString *progression01String = ToNSString(progression01); 229 | NSString *progression02String = ToNSString(progression02); 230 | NSString *progression03String = ToNSString(progression03); 231 | NSString *fieldsString = ToNSString(fields); 232 | NSDictionary *fields_dict = nil; 233 | if (fieldsString) { 234 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 235 | } 236 | 237 | [GameAnalytics addProgressionEventWithProgressionStatus:(GAProgressionStatus)progressionStatus 238 | progression01:progression01String 239 | progression02:progression02String 240 | progression03:progression03String 241 | score:score 242 | customFields:fields_dict 243 | mergeFields:mergeFields]; 244 | } 245 | 246 | void GAWrapperIOS::AddDesignEvent(std::string const& eventId, std::string const& fields, bool mergeFields) { 247 | NSString *eventIdString = ToNSString(eventId); 248 | NSString *fieldsString = ToNSString(fields); 249 | NSDictionary *fields_dict = nil; 250 | if (fieldsString) { 251 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 252 | } 253 | 254 | [GameAnalytics addDesignEventWithEventId:eventIdString value:nil customFields:fields_dict mergeFields:mergeFields]; 255 | } 256 | 257 | void GAWrapperIOS::AddDesignEventWithValue(std::string const& eventId, float value, std::string const& fields, bool mergeFields) { 258 | NSString *eventIdString = ToNSString(eventId); 259 | NSNumber *valueNumber = [NSNumber numberWithFloat:value]; 260 | NSString *fieldsString = ToNSString(fields); 261 | NSDictionary *fields_dict = nil; 262 | if (fieldsString) { 263 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 264 | } 265 | 266 | [GameAnalytics addDesignEventWithEventId:eventIdString value:valueNumber customFields:fields_dict mergeFields:mergeFields]; 267 | } 268 | 269 | void GAWrapperIOS::AddErrorEvent(EGAErrorSeverity severity, std::string const& message, std::string const& fields, bool mergeFields) { 270 | NSString *messageString = ToNSString(message); 271 | NSString *fieldsString = ToNSString(fields); 272 | NSDictionary *fields_dict = nil; 273 | if (fieldsString) { 274 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 275 | } 276 | 277 | [GameAnalytics addErrorEventWithSeverity:(GAErrorSeverity)severity message:messageString customFields:fields_dict mergeFields:mergeFields]; 278 | } 279 | 280 | void GAWrapperIOS::AddAdEvent(EGAAdAction action, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, std::string const& fields, bool mergeFields) { 281 | NSString *adSdkNameString = ToNSString(adSdkName); 282 | NSString *adPlacementString = ToNSString(adPlacement); 283 | NSString *fieldsString = ToNSString(fields); 284 | NSDictionary *fields_dict = nil; 285 | if (fieldsString) { 286 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 287 | } 288 | [GameAnalytics addAdEventWithAction:(GAAdAction)action 289 | adType:(GAAdType)adType 290 | adSdkName:adSdkNameString 291 | adPlacement:adPlacementString 292 | customFields:fields_dict 293 | mergeFields:mergeFields]; 294 | } 295 | void GAWrapperIOS::AddAdEventWithDuration(EGAAdAction action, EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, int64_t duration, std::string const& fields, bool mergeFields) { 296 | NSString *adSdkNameString = ToNSString(adSdkName); 297 | NSString *adPlacementString = ToNSString(adPlacement); 298 | NSString *fieldsString = ToNSString(fields); 299 | NSDictionary *fields_dict = nil; 300 | if (fieldsString) { 301 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 302 | } 303 | [GameAnalytics addAdEventWithAction:(GAAdAction)action 304 | adType:(GAAdType)adType 305 | adSdkName:adSdkNameString 306 | adPlacement:adPlacementString 307 | duration:(NSInteger)duration 308 | customFields:fields_dict 309 | mergeFields:mergeFields]; 310 | } 311 | 312 | void GAWrapperIOS::AddAdEventWithReason(::EGAAdAction action, ::EGAAdType adType, std::string const& adSdkName, std::string const& adPlacement, ::EGAAdError noAdReason, std::string const& fields, bool mergeFields) { 313 | NSString *adSdkNameString = ToNSString(adSdkName); 314 | NSString *adPlacementString = ToNSString(adPlacement); 315 | NSString *fieldsString = ToNSString(fields); 316 | NSDictionary *fields_dict = nil; 317 | if (fieldsString) { 318 | fields_dict = [NSJSONSerialization JSONObjectWithData:[fieldsString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 319 | } 320 | [GameAnalytics addAdEventWithAction:(GAAdAction)action 321 | adType:(GAAdType)adType 322 | adSdkName:adSdkNameString 323 | adPlacement:adPlacementString 324 | noAdReason:(GAAdError)noAdReason 325 | customFields:fields_dict 326 | mergeFields:mergeFields]; 327 | } 328 | 329 | void GAWrapperIOS::SetInfoLog(bool flag) { 330 | [GameAnalytics setEnabledInfoLog:flag]; 331 | } 332 | 333 | void GAWrapperIOS::SetVerboseLog(bool flag) { 334 | [GameAnalytics setEnabledVerboseLog:flag]; 335 | } 336 | 337 | void GAWrapperIOS::SetEnabledManualSessionHandling(bool flag) { 338 | [GameAnalytics setEnabledManualSessionHandling:flag]; 339 | } 340 | 341 | void GAWrapperIOS::SetEnabledErrorReporting(bool flag) { 342 | [GameAnalytics setEnabledErrorReporting:flag]; 343 | } 344 | 345 | void GAWrapperIOS::SetEnabledEventSubmission(bool flag, bool doOfflineCache) { 346 | [GameAnalytics setEnabledEventSubmission:flag]; 347 | } 348 | 349 | void GAWrapperIOS::SetCustomDimension01(std::string const& customDimension) { 350 | NSString *customDimensionString = ToNSString(customDimension); 351 | [GameAnalytics setCustomDimension01:customDimensionString]; 352 | } 353 | 354 | void GAWrapperIOS::SetCustomDimension02(std::string const& customDimension) { 355 | NSString *customDimensionString = ToNSString(customDimension); 356 | [GameAnalytics setCustomDimension02:customDimensionString]; 357 | } 358 | 359 | void GAWrapperIOS::SetCustomDimension03(std::string const& customDimension) { 360 | NSString *customDimensionString = ToNSString(customDimension); 361 | [GameAnalytics setCustomDimension03:customDimensionString]; 362 | } 363 | 364 | void GAWrapperIOS::StartSession() { 365 | [GameAnalytics startSession]; 366 | } 367 | 368 | void GAWrapperIOS::EndSession() { 369 | [GameAnalytics endSession]; 370 | } 371 | 372 | std::string GAWrapperIOS::GetRemoteConfigsValueAsString(std::string const& key, std::string const& defaultValue) { 373 | NSString *keyString = ToNSString(key); 374 | NSString *result = [GameAnalytics getRemoteConfigsValueAsString:keyString]; 375 | 376 | std::string s = result != nil ? [result UTF8String] : defaultValue; 377 | return s; 378 | } 379 | 380 | double GAWrapperIOS::GetRemoteConfigsValueAsNumber(std::string const& key, double defaultValue) { 381 | return defaultValue; 382 | } 383 | 384 | std::string GAWrapperIOS::GetRemoteConfigsValueAsJson(std::string const& key) { 385 | return ""; 386 | } 387 | 388 | bool GAWrapperIOS::IsRemoteConfigsReady() { 389 | return [GameAnalytics isRemoteConfigsReady] ? true : false; 390 | } 391 | 392 | std::string GAWrapperIOS::GetRemoteConfigsContentAsString() { 393 | NSString *result = [GameAnalytics getRemoteConfigsContentAsString]; 394 | 395 | std::string s = FromNSString(result); 396 | return s; 397 | } 398 | 399 | std::string GAWrapperIOS::GetUserId() { 400 | NSString* uid = [GameAnalytics getUserId]; 401 | return FromNSString(uid); 402 | } 403 | 404 | std::string GAWrapperIOS::GetExternalUserId() { 405 | NSString* uid = [GameAnalytics getExternalUserId]; 406 | return FromNSString(uid); 407 | } 408 | 409 | void GAWrapperIOS::SetExternalUserId(std::string const& id) { 410 | NSString* uid = ToNSString(id); 411 | [GameAnalytics configureExternalUserId:uid]; 412 | } 413 | 414 | std::string GAWrapperIOS::GetABTestingId() { 415 | NSString *result = [GameAnalytics getABTestingId]; 416 | 417 | std::string s = FromNSString(result); 418 | return s; 419 | } 420 | 421 | std::string GAWrapperIOS::GetABTestingVariantId() { 422 | NSString *result = [GameAnalytics getABTestingVariantId]; 423 | 424 | std::string s = FromNSString(result); 425 | return s; 426 | } 427 | 428 | void GAWrapperIOS::EnableAdvertisingId(bool value) 429 | { 430 | // Note: This method is deprecated and has no effect. 431 | } 432 | 433 | void GAWrapperIOS::EnableSDKInitEvent(bool value) 434 | { 435 | [GameAnalytics enableSDKInitEvent:value]; 436 | } 437 | 438 | 439 | 440 | void GAWrapperIOS::EnableFpsHistogram(FPSTracker tracker, bool value) 441 | { 442 | if (value) 443 | { 444 | // Always create a new delegate with the latest tracker 445 | GAHealthMetricsProvider *provider = [[GAHealthMetricsProvider alloc] initWithFPSTracker:tracker]; 446 | [GameAnalytics setHealthMetricsDelegate:provider]; 447 | } 448 | else 449 | { 450 | [GameAnalytics setHealthMetricsDelegate:nil]; 451 | } 452 | 453 | [GameAnalytics enableFpsHistogram:value]; 454 | } 455 | 456 | int64_t GAWrapperIOS::GetElapsedSessionTime() 457 | { 458 | // Returns the elapsed time for the current session in seconds 459 | return (int64_t)[GameAnalytics getElapsedSessionTime]; 460 | } 461 | 462 | int64_t GAWrapperIOS::GetElapsedTimeForPreviousSession() 463 | { 464 | // Returns the elapsed time for the previous session in seconds 465 | return (int64_t)[GameAnalytics getElapsedTimeForPreviousSession]; 466 | } 467 | 468 | int64_t GAWrapperIOS::GetElapsedTimeFromAllSessions() 469 | { 470 | // Returns the total elapsed time from all sessions in seconds 471 | return (int64_t)[GameAnalytics getElapsedTimeFromAllSessions]; 472 | } 473 | 474 | void GAWrapperIOS::EnableMemoryHistogram(bool value) 475 | { 476 | [GameAnalytics enableMemoryHistogram:value]; 477 | } 478 | 479 | void GAWrapperIOS::EnableHealthHardwareInfo(bool value) 480 | { 481 | [GameAnalytics enableHealthHardwareInfo:value]; 482 | } 483 | 484 | void GAWrapperIOS::OnQuit() 485 | { 486 | 487 | } 488 | 489 | void GAWrapperIOS::SetWritablePath(std::string const& path) 490 | { 491 | (void)path; 492 | } 493 | 494 | } 495 | --------------------------------------------------------------------------------