Files
UnrealEngineUWP/Engine/Source/Runtime/Analytics/AnalyticsET/Private/IAnalyticsProviderET.cpp
Andrew Grant a140e73bbf Copying //UE4/Orion-Staging to //UE4/Main (Source: //Orion/Dev-General @ 3064255)
#lockdown Nick.Penwarden

Change 3063869 on 2016/07/25 by Michael.Noland@mnoland_T2801_OrionStream

	Engine: Added a cvar (t.FPSChart.OpenFolderOnDump) to control whether or not FPS charts automatically open the profiling folder when stopfpschart is executed, which can be useful to avoid a bunch of open windows while doing automated testing
	#rb marcus.wassmer
	#tests Tested startfpschart + stopfpschart with t.FPSChart.OpenFolderOnDump set to 1 and 0
	#codereview david.nikdel

Change 3063829 on 2016/07/25 by Michael.Noland@mnoland_T2801_OrionStream

	Core: Added an optional size to MallocLeak Stop and made the default filter size 128 KB for both MallocLeak Dump and MallocLeak Stop if no size was specified
	#rb marcus.wassmer
	#tests Tested using MallocLeak Stop and MallocLeak Dump

Change 3063825 on 2016/07/25 by Michael.Noland@mnoland_T2801_OrionStream

	Engine: Exposed GPU revision ID as GRHIDeviceRevision and added it to the FPS chart analytics (gathered on D3D11 and D3D12 only)
	#rb marcus.wassmer
	#tests Tested on my desktop and compared to dxdiag output

Change 3063702 on 2016/07/25 by Ryan.Gerleve@Ryan.Gerleve_T3703_Orion

	Collect garbage when scrubbing in a replay. Scrubbing generates a lot of garbage, and can lead to running out of memory.
	Can be disabled with the cvar demo.LoadCheckpointGarbageCollect.

	#jira OR-25964
	#tests bug repro
	#rb john.pollard

Change 3063426 on 2016/07/25 by Michael.Trepka@Michael.Trepka_T3244_Orion-Dev

	Borderless window support improvements:

	- the cursor changes to resize when hovering over the window edge
	- added a way for widgets to register a delegate that's called when window actions occur (maximize, restore, etc.)
	- used he window action notification for WindowTitleBarArea to improve how toggling fullscreen on double click is handled

	#rb Jeff.Campeau
	#tests Tested in editor build on PC

Change 3063358 on 2016/07/25 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - Merge 29.2 @ CL 3063307

	#RB:none
	#tests:none

	#ROBOMERGE-SOURCE: CL 3063345 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3063353 on 2016/07/25 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ben.marsh
	Merging CL 3037547 and CL 3037552 from //UE4/Dev-Build to support BuildPatchTool analytics.

	#rb none
	#tests none

	#ROBOMERGE-SOURCE: CL 3063156 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3063198 on 2016/07/25 by Matt.Kuhlenschmidt@matt.kuhlenschmidt_orion_dev

	Temp fix for broken post process volumes

	#rb none
	#tests  none

Change 3063166 on 2016/07/25 by Daniel.Lamb@daniel.lamb_T3905_6612

	Added check to Redirect collector resolve string asset references.
	#rb none
	#test cook paragon

Change 3063057 on 2016/07/25 by Michael.Trepka@Michael.Trepka_T3244_Orion-Dev

	Use round corners for windows with no system title bar and border only in windowed mode.

	#rb Peter.Sauerbrei
	#tests Tested in editor build on PC

Change 3063015 on 2016/07/25 by Andrew.Rodham@Andrew.Rodham_Orion

	Sequencer: Fixed anim notifies not working when playing animation on blueprint-driven skeletal meshes

	We now inject a new animation position into the animation system, rather than trying to 'fake' events outside of the system. This allows for much more robust event triggering when playing back through sequencer. Previously, anim notifies for trail particles would be reset every frame due to TriggerAnimNotifies being called by the animation system, and sequencer. We now defer this responsibility to the animation system entirely during playback.

	#tests Tested sequencer driven animation with animation assets and (compatible) animation blueprints. Tested some non-sequencer animation.
	#rb Benn.Gallagher

Change 3062774 on 2016/07/24 by Ben.Marsh@Ben.Marsh_T3245_Orion

	BuildGraph: Fix <Cook> tasks failing when multiple platforms are specified, due to not scanning the output directories separately.

	#rb none
	#tests preflight

Change 3062761 on 2016/07/24 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Non-unity fix
	#rb none
	#tests compiled

Change 3062324 on 2016/07/22 by Marcus.Wassmer@Marcus.Wassmer_Orion_DevGeneral

	Skipped a file
	#rb none
	#test none

Change 3062315 on 2016/07/22 by Marcus.Wassmer@Marcus.Wassmer_Orion_DevGeneral

	Allow r.SSR.MaxRoughness in shipping builds.
	Art has been tweaking with this value, but it's not being honored in shipping.
	#rb none
	#tests adjusted settings in agora_p

Change 3062306 on 2016/07/22 by Marcus.Wassmer@Marcus.Wassmer_Orion_DevGeneral

	HLOD distance scalability option (r.HLOD.DistanceScale)
	Higher values make HLODS transition further away.
	#rb Michael.Noland
	#tests Tested in agora_p

Change 3061861 on 2016/07/22 by Lina.Halper@Lina.Halper_Orion

	Fix Compression - Reduce functions to be editoronly

	#rb: Martin.Wilson
	#tests: PIE/compile editor build/noneditor

Change 3061714 on 2016/07/22 by Andrew.Rodham@Andrew.Rodham_Orion

	Sequencer: Fixed anim trails not playing in full, sequencer-driven animation.

	There were 2 issues here. Firstly, we were force-handling events and anim notifies in non-preview animation which caused undefined behaviour when the animation was also updated on tick. Secondly, On the very first frame of a game, sequencer can sometimes use the PreviewSetMatineeAnimPositionInner method because the actor it is referencing has not begun play yet. Unfortunately this function left the animation in a state where the 'real' animation update function wouldn't trigger any anim notifies properly.

	#tests Tested animation with and without anim trails to verify they work in editor, PIE and standalone game with and without sequencer open. Rendered out the announce trailer before and after my changes to verify there was no change in behaviour.

	#jira OR-25967

	#review-3061494 @Max.Chen

	#rb Benn.Gallagher

Change 3061393 on 2016/07/22 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: sam.zamani
	compile errors
	#rb none
	#tests compile

	#ROBOMERGE-SOURCE: CL 3061392 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3061384 on 2016/07/22 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: andrew.grant
	Fixed build breakage
	#rb none
	#tests compiled PS4 client

	#ROBOMERGE-SOURCE: CL 3061383 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3060894 on 2016/07/21 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ian.fox
	#Orion, #OnlineSubsystem, #OnlineGameplayFramework - Game catalog supports Price Engine sales on real-money offers
	#rb Sam.Zamani
	#tests Real-money offers that are on sale show the correct sale price / discount display
	#jira OR-21659

	#ROBOMERGE-SOURCE: CL 3060891 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3060272 on 2016/07/21 by Lina.Halper@Lina.Halper_Orion

	Fix compile issue of non editor build

	#rb: none
	#tests: compile

Change 3060161 on 2016/07/21 by Marcus.Wassmer@Marcus.Wassmer_Orion_DevGeneral

	Duplicate 3046845
	CVAR threading crash fix.
	#rb none
	#tests compiled, ran ps4

Change 3060012 on 2016/07/21 by Lina.Halper@Lina.Halper_Orion

	- Back out changelist 3056611
	- Fix additive issue and built the new animation DDC
	#rb: Martin.Wilson
	#tests: Jump_Recovery_Additive, PIE

Change 3060009 on 2016/07/21 by Rob.Cannaday@rob.cannaday_orion-stream

	When receiving NotLeader party join rejection, include the new leader id and re-attempt the join to the new leader
	#jira OR-25648
	#rb bart.bressler
	#tests frontend parties with promotions, coop matchmaking

Change 3059989 on 2016/07/21 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Fixes for applocal redist
	#rb none
	#test built locally

Change 3059832 on 2016/07/21 by Martin.Wilson@MartinWilsonOrionStream

	Fix graph linked external object saving error on re-compressed animations (dup from dev-framework CL )

	#jira UE-33567
	#rb Thomas.Sarkanen
	#tests In editor testing that animations can be recompressed and saved

Change 3059803 on 2016/07/21 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Switching Orion, UnrealCEFSubProcess, and CrashReporterClient to build with VS2015
	Added AppLocalPrerequisitesDirectory editor setting that is passed in -applocaldir during staging
	WinPlatformAutomation now stages applocaldir to project and engine binaries
	Updated OrionBuild.xml to specify -applocaldir
	#codereview Jeff.Campeau, Ben.Marsh
	#rb none
	#tests build client locally and verified DLLs are local to executables

Change 3059707 on 2016/07/21 by David.Ratti@David.Ratti_G6218_Orion.Dev-General

	fix case where DefaultGameplayTags.ini fails to update if not checked out from source control
	#rb none
	#tests add tags without source control

Change 3059679 on 2016/07/21 by Rob.Cannaday@rob.cannaday_orion-stream

	Fix nonunity compile error due to OnlinePresenceInterface.h requiring enum defined in OnlineSubsystemTypes.h
	#rb paul.moore
	#tests compile with OrionFriendItem.cpp modified

Change 3059518 on 2016/07/21 by Andrew.Grant@andrew.grant.T6730.orion.floating

	AppLcoalDependencies required by VS2015

Change 3059477 on 2016/07/21 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - Merge 29.2 @ CL 3059419

	#RB:none
	#Tests:none

	#ROBOMERGE-SOURCE: CL 3059476 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3059455 on 2016/07/21 by Graeme.Thornton@GThornton_Orion_DevGeneral

	Linux build fix (bad case on #include filename)

	#rb robert.manuszewski
	#tests compiled Paragon on a linux machine

Change 3059258 on 2016/07/21 by Simon.Tovey@Simon.Tovey_OrionDev

	Implementing 3050352 in Dev-General.

	#rb none
	#tests Editor

	#codereview Marcus.Wassmer

Change 3058989 on 2016/07/21 by Michael.Noland@mnoland_T2801_OrionStream

	Audio: Disabling the audio thread to prevent a crash in async line trace code (it is already disabled in UE4 main)
	#rb none
	#codereview andrew.grant, ori.cohen

Change 3058773 on 2016/07/20 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ian.fox
	#Orion - Remove QoS* from junk manifest
	#review-3058772 @Rob.Cannaday
	#rb none
	#tests QoS module doesn't get nuked every build

	#ROBOMERGE-SOURCE: CL 3058771 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3058717 on 2016/07/20 by Daniel.Lamb@daniel.lamb_T3905_6612

	Added submitted CL to success email for rebuild lighting commandlet.
	Removed nosimplygon from resave lighting commandlet commandline.
	#rb Daniel.Wright
	#test rebuildlighting paragon devgeneral.

Change 3058565 on 2016/07/20 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ian.fox
	#Orion - Fix debug/non-development builds
	#rb Rob.Cannaday
	#tests it builds (and doesn't crash on login) on Debug Editor -debug -game!

	#ROBOMERGE-SOURCE: CL 3058563 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3058082 on 2016/07/20 by Daniel.Lamb@daniel.lamb_T3905_6612

	Added error to the lighting build whent it fails to build.
	#test Rebuild lighting commandlet
	#rb Daniel.Wright

Change 3057945 on 2016/07/20 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Fix for NAN issue introduced in 3032847
	#rb Jeff.Farris
	#tests none

Change 3057840 on 2016/07/20 by David.Ratti@David.Ratti_G6218_Orion.Dev-General

	fix developer tags not properly adding to perforce when creating a new file

	#rb none
	#tests developer tags

Change 3057553 on 2016/07/20 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - Merge 29.2 @ CL 3057330

	#RB:none
	#Tests:none

	#ROBOMERGE-SOURCE: CL 3057549 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3057313 on 2016/07/20 by bruce.nesbit@BNesbit_Orion_Stream_1

	Fixed shadowvariable in FAnalyticsEventEntry

	#rb none

	#tests compiled

	#codereview Wes.Hunt

Change 3056802 on 2016/07/19 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ryan.gerleve
	Fix issue where replicated map-placed actors with ability system components would cache an incorrect Role value.
	This could cause predicted gameplay effects in the fast TArray to have MarkItemDirty called on them, which in turn increments the item's ReplicationID, potentially causing a conflict with the server's ReplicationID.
	Since the Role may not be correct during OnRegister for these components, also cache it BeginPlay.

	#jira OR-25234
	#rb david.ratti
	#tests golden path, bug repro

	#ROBOMERGE-SOURCE: CL 3056801 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3056797 on 2016/07/19 by Wes.Hunt@WHUNT-ORION-STREAM

	OrionAnalytics updates.
	* Added IAnalyticsProviderET::SetDefaultEventAttributes to use to set the GameSessionID on all Orion Analytics events.
	* Removed OrionAnalyticsProvider as it was no longer necessary.
	* Updated all Orion code to use IAnalyticsProviderET directly in the code to be able to access all the new APIs.
	#rb sam.zamani, jason.bestimt
	#tests run dedicated server with 10 bot clients, observe analytics events sending correctly. Ran PIE.
	#jira UE-30980

Change 3056611 on 2016/07/19 by Lina.Halper@Lina.Halper_Orion

	Fix for additive broken with remove linear key
	- DDC key has been changed, so it will require to build DDC from this

	#rb: Martin.Wilson
	#tests: Jump_Recovery_Additive in editor, and PIE

Change 3056226 on 2016/07/19 by Lukasz.Furman@Lukasz.Furman_T7320_OrionStream

	extended gameplay debugger's ability category to show locally owned gameplay tags
	#orion
	#rb none
	#tests PIE

Change 3056204 on 2016/07/19 by Jeff.Campeau@jeff.campeau_3753_Orion

	Fix offset rendering of maximized borderless game window on Windows.
	#review-3055205 @michael.trepka
	#rb Michael.Trepka
	#tests Tested in editor build on PC (editor window normal and maximized, game window borderless normal and maximized, game window bordered normal and maximized).

Change 3056028 on 2016/07/19 by Rob.Cannaday@rob.cannaday_orion-stream

	Add moved modules to JunkManifest.txt

Change 3055650 on 2016/07/19 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - ACTUAL Merge 29.2 @ CL 3055553

	#RB:none
	#Tests:none

	#ROBOMERGE-SOURCE: CL 3055647 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3055620 on 2016/07/19 by Dmitry.Rekman@RCL_Win_Stream-ORMAIN

	Attempts to fix rare server crashes (OR-24947, OR-24952).

	- Rearranging to avoid AddDefaulted(), that might be triggering a compiler bug (conjecture).

	#rb Steve.Robb
	#codereview Steve.Robb
	#tests Compiled Windows client and Linux server, played a match.

Change 3054587 on 2016/07/18 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Merging from //UE4/Main @ 3043787 through //UE4/Orion-Staging
	#rb none
	#tests Smoked by engine and dev QA

Change 3054491 on 2016/07/18 by Frank.Gigliotti@Frank.Gig_T4217_Orion_Stream

	Removed warning when client miss-predicts ability activation.

	* It is valid for the client to miss-predict.  Warning was only added to track down a bug.

	#CodeReview David.Ratti
	#RB None
	#Tests None

Change 3053850 on 2016/07/18 by David.Ratti@David.Ratti_G6218_Orion.Dev-General

	Missed checkins on ability system engine work:
	-Register debug delegate on module startup for easier debugging
	-Fallback to actor location if no hit impact is specified in default engine GC notify class

	#rb none
	#tests ability system sample project

Change 3053825 on 2016/07/18 by David.Ratti@David.Ratti_G6218_Orion.Dev-General

	Fix issue where config file not actually flushed at right time when adding new tags

	Fix issue where orion projecetile tags that are auto generated was generating tags for non gameplay tag properties

	#rb DanY
	#codereview Dan.Youhon
	#tests pie

Change 3053438 on 2016/07/18 by David.Ratti@David.Ratti_G6218_Orion.Dev-General

	-Remove developer tags from master tag list before saving to ini file
	-inline some stuff (wip for gc tag translator system)

	#rb none
	#test adding tags

Change 3053414 on 2016/07/18 by Robert.Manuszewski@Robert_Manuszewski_NCL_Orion

	Fixing rare crash when async loading objects caused by linker being detached too early (before other package's import has been fully processed)

	#jira OR-24955
	#jira OR-25183
	#rb Graeme.Thornton
	#tests Win64 cooked client golden path (solo vs AI)

Change 3052009 on 2016/07/15 by Dmitry.Rekman@RCL_Win_Stream-ORMAIN

	Overhaul of behavior of headless applications (server, client) (OR-23529).

	- Removed FApp::ShouldUseNullRHI(). Rationale: FApp::CanEverRender() answers a higher level question and the code shouldn't predicate on the type of RHI used.
	- Multiple code paths updated to prevent code execution on headless clients (some of this is optimization, some was causing crashes).
	- Most of these changes originated from a shelved CL by BradA.

	#rb Michael.Noland
	#codereview Michael.Noland, Brad.Angelcyk, Andrew.Grant, Chris.Wood, Matt.Schembari
	#tests Cooked Windows client and server, Linux client and server. Ran Windows client and server, played a match, ran Linux bot (headless client, requires local changes not in this CL), ran the Windows editor (tried PIE).

Change 3051926 on 2016/07/15 by Marcus.Wassmer@Marcus.Wassmer_Orion_DevGeneral

	Reinstate color grading changes.
	Fix broken config file.
	#rb none
	#tests Agora_p color grading and warning check

Change 3051759 on 2016/07/15 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ryan.gerleve
	Don't record predicted elements of fast TArrays into client replays.
	Fixes issue where the client was incrementing the ReplicationID of predicted elements, potentially conflicting with the IDs of elements received by the server.

	#jira OR-25234, OR-25413, OR-25403
	#tests golden path, bug repo using 'net pktlag', replays
	#rb john.pollard, david.ratti

	#ROBOMERGE-SOURCE: CL 3051758 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3051702 on 2016/07/15 by Daniel.Lamb@daniel.lamb_T3905_6612

	Added jordan walker to rebuild lighting emails.
	Removed peter.sauerbrei.
	#rb Peter.Sauerbrei
	#test none

Change 3051661 on 2016/07/15 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ben.marsh
	Merging support for precompiled binaries in CIS from Release-29.

	#rb none
	#tests none

	#ROBOMERGE-SOURCE: CL 3051660 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3051466 on 2016/07/15 by Marcus.Wassmer@Marcus.Wassmer_Orion_DevGeneral

	Allow seamless upgrade from FVector -> FVector4 for UProperties.
	#rb Robert.Manuszewski
	#tests Color grading property changes.

Change 3050680 on 2016/07/14 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ian.fox
	#Mcp, #Orion - Fix initalization values of CatalogServiceMcp
	#rb none
	#tests Real money offers show in the store again

	#ROBOMERGE-SOURCE: CL 3050563 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3050520 on 2016/07/14 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - MERGING DUI @ CL 3047139

	#RB:none
	#Tests:none

	[CodeReviewed]: kerrington.smith, dan.hertzka, matt.schembari, benjamin.crocker, jaymee.stanford, alex.conner

	#ROBOMERGE-SOURCE: CL 3050519 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3050465 on 2016/07/14 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: ryan.gerleve
	Don't check IsClientOnly() to detemine whether a player controller is local or not.
	For client replay recording, the replay spectator controller should not return true from IsLocallyControlled(). This change fixes that case in client builds.
	Fixes issue where the SignificanceManager was using the replay spectator to influence significance values, causing them to be incorrect for the game player controller.

	#jira OR-25258
	#tests bug repro, golden path, replays
	#rb john.pollard
	[CodeReviewed] zak.middleton, josh.markiewicz

	#ROBOMERGE-SOURCE: CL 3050462 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3050326 on 2016/07/14 by Dan.Youhon@Dan.Youhon.Paragon

	Set CameraLensEffects position before activation so that initial significance values are correct, specifically to fix quick camera lens effects being culled out due to incorrect significance #OR-18321
	- Moves location determination code from AEmitterCameraLensEffectBase::UpdateLocation into a separate static GetAttachedEmitterTransform function, which is now called both from UpdateLocation and in APlayerCameraManager::AddCameraLensEffect to determine SpawnTransform for the LensEffect SpawnActor call
	- Unshelved from Jeff.Farris. Thanks Jeff!

	#rb Dan.Youhon
	#tests MultiPIE
	#codereview Jeff.Farris

Change 3049749 on 2016/07/14 by Daniel.Lamb@daniel.lamb_T3905_6612

	Added skipskin verify to rebuild lighting commandlet.
	#rb None
	#test Rebuild lighting commandlet

Change 3049728 on 2016/07/14 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: buildmachine
	Remove simplygon from rebuild lighting commandlet
	#rb none
	#test rebuild lighting

	#ROBOMERGE-SOURCE: CL 3049727 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3049721 on 2016/07/14 by buildmachine@buildmachine_Z4560_OrionDevGeneral

	Remove simplygon from rebuild lighting commandlet
	#rb none
	#test rebuild lighting

Change 3049325 on 2016/07/13 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Back out changelist 3049037 due to incompatibility with current assets
	#rb none
	#tests Cooked content and verified warnings & errors are gone.
	#codereview Marcus.Wasmer, Brian.Karis, HaarmPieter.Duiker

Change 3049319 on 2016/07/13 by Andrew.Grant@andrew.grant.T6730.orion.floating

	More work on content filtering (still disabled)
	#rb none
	#tests cooked content and verified filtered content is not found.

Change 3049298 on 2016/07/13 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - Merge 28.2/29 @ CL 3049113

	#RB:none
	#Tests:none

	#ROBOMERGE-SOURCE: CL 3049296 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

Change 3049269 on 2016/07/13 by Mieszko.Zielinski@mieszko.zielinski_T4675_Orion

	Constified FObjectFinder::Succeeded because why not #UE4

	#rb none
	#test golden path

Change 3049104 on 2016/07/13 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Created delegate for object name resolution and moved existing package localization code to use it.
	Orion code to filter out unreleased heroes and other data, but correnty disabled due to a cooking bug.
	#rb none
	#tests ran editor, ran cooker, verified object resolution is equivalent to before.

Change 3049037 on 2016/07/13 by HaarmPieter.Duiker@HPD-Dev-General

	Adding shadows, midtones and highlights color correction controls
	#rb brian.karis, marcus.wassmer
	#tests "postprocess color correction"

Change 3048457 on 2016/07/13 by Cody.Haskell@OrionStream

	#UE4

	- Adding a delegate that fires off when LastUserInteractionTime is updated

	#codereview Matt.Kuhlenschmidt
	#rb none
	#tests PIE

Change 3048420 on 2016/07/13 by Dmitry.Rekman@RCL_Lnx_CaseIns_Stream-ORMAIN

	Fix double #undef LOCTEXT_NAMESPACE in editor case.

	#rb none
	#codereview Nick.Darnell, Andrew.Grant
	#tests Compiled Linux editor (for running -server).

Change 3047891 on 2016/07/13 by Michael.Trepka@Michael.Trepka_T3244_Orion-Dev

	Rollback //Orion/Dev-General/Engine/Source/Runtime/Core/Private/Windows/WindowsWindow.cpp to revision 12

	#rb none
	#tests Tested in editor on PC

Change 3047216 on 2016/07/12 by Dmitry.Rekman@RCL_Lnx_CaseIns_Stream-ORMAIN

	Changes to Linux application specific to Linux client.

	#rb none
	#codereview Brad.Angelcyk
	#tests Ran Paragon Linux client (headless) locally.

Change 3047140 on 2016/07/12 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Fix for PS4
	#rb #tests na

Change 3047107 on 2016/07/12 by Andrew.Grant@andrew.grant.T6730.orion.floating

	Moved timeguards out of stats.h
	#rb none
	#tests compiled editor & shipping client

Change 3046996 on 2016/07/12 by Ryan.Gerleve@Ryan.Gerleve_T3703_Orion

	Don't check bTearOff when deciding whether to swap roles for client replay recording and improve the comment.
	Fixes an assert that could occur if a torn-off actor happened to get recorded into a checkpoint of a client replay.

	#tests golden path
	#rb john.pollard

Change 3046975 on 2016/07/12 by Michael.Trepka@Michael.Trepka_T3244_Orion-Dev

	Support for making the game window borderless (no system border or title bar). Disabled by default. Enabling requires adding bUseBorderlessWindow=True to [/Script/EngineSettings.GeneralProjectSettings] in DefaultGame.ini. The game using this is responsible for adding WindowTitleBarArea widget to its UI, as well as window minimize/maximize/close buttons.

	#codereview Dan.Hertzka
	#rb Jeff.Campeau
	#tests Tested in editor build on PC

Change 3046812 on 2016/07/12 by Michael.Trepka@Michael.Trepka_T3244_Orion-Dev

	New UI for selecting fullscreen mode in Paragon video settings

	#rb Dan.Hertzka
	#tests Tested in editor build on PC

Change 3046803 on 2016/07/12 by Michael.Trepka@Michael.Trepka_T3244_Orion-Dev

	Added an option to WindowTitleBarArea widget to make it toggle fullscreen mode instead of maximizing the window.

	#rb Dan.Hertzka
	#tests Tested in editor build on PC

Change 3045374 on 2016/07/11 by John.Pollard@John.Pollard_T2802_Orion_DevGeneral

	Fix assert in channel cleanup code that could occur if the connection was cleaned up, and there were KeepProcessingActorChannelBunchesMap in-flight still

	#rb RyanG
	#tests Replays

Change 3044696 on 2016/07/11 by Daniel.Lamb@daniel.lamb_T3905_6612

	Added additional checks to ResavePackagesCommandlet so people don't miss the required allowcommandletrendering flag when using buildlighting option.
	#test rebuild lighting using resave packages paragon
	#rb None

Change 3044690 on 2016/07/11 by Daniel.Lamb@daniel.lamb_T3905_6612

	Changed MBWritten cooker stats to report mb instead of bytes...
	#rb Wes.Hunt.
	#test cook paragon.

Change 3044439 on 2016/07/11 by Jason.Bestimt@Robomerge_Orion_DevGeneral

	#ROBOMERGE-AUTHOR: jason.bestimt
	#ORION_MAIN - Merge 28.2 @ CL 3043960

	#RB:none
	#Tests:none

	#ROBOMERGE-SOURCE: CL 3044428 in //Orion/Main/...
	#ROBOMERGE-BOT: ORION (Main -> Dev-General)

[CL 3070724 by Andrew Grant in Main branch]
2016-07-29 17:10:25 -04:00

703 lines
25 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "Runtime/Analytics/AnalyticsET/Private/AnalyticsETPrivatePCH.h"
#include "Core.h"
#include "Guid.h"
#include "Json.h"
#include "SecureHash.h"
#include "AnalyticsET.h"
#include "IAnalyticsProviderET.h"
#include "Http.h"
#include "EngineVersion.h"
/** When enabled (and -AnalyticsTrackPerf is specified on the command line, will log out analytics flush timings on a regular basis to Saved/AnalyticsTiming.csv. */
#define ANALYTICS_PERF_TRACKING_ENABLED !UE_BUILD_SHIPPING
#if ANALYTICS_PERF_TRACKING_ENABLED
/** Measures analytics bandwidth. Only active when -AnalyticsTrackPerf is specified on the command line. */
struct FAnalyticsPerfTracker : FTickerObjectBase
{
FAnalyticsPerfTracker()
{
bEnabled = FParse::Param(FCommandLine::Get(), TEXT("ANALYTICSTRACKPERF"));
if (bEnabled)
{
LogFile.SetSuppressEventTag(true);
LogFile.Serialize(TEXT("Date,CL,RunID,Time,WindowSeconds,ProfiledSeconds,Frames,Flushes,Events,Bytes"), ELogVerbosity::Log, FName());
LastSubmitTime = StartTime;
StartDate = FDateTime::UtcNow().ToIso8601();
CL = LexicalConversion::ToString(FEngineVersion::Current().GetChangelist());
}
}
/** Called once per flush */
void RecordFlush(uint64 Bytes, uint64 NumEvents, double TimeSec)
{
if (bEnabled)
{
++FlushesThisWindow;
BytesThisWindow += Bytes;
NumEventsThisWindow += NumEvents;
TimeThisWindow += TimeSec;
}
}
static FAnalyticsPerfTracker& Get()
{
static FAnalyticsPerfTracker GTracker;
return GTracker;
}
bool IsEnabled() const { return bEnabled; }
void SetRunID(const FString& InRunID)
{
if (bEnabled)
{
RunID = InRunID;
StartDate = FDateTime::UtcNow().ToIso8601();
}
}
private:
/** Check to see if we need to log another window of time. */
virtual bool Tick(float DeltaTime) override
{
if (bEnabled)
{
++FramesThisWindow;
double Now = FPlatformTime::Seconds();
if (WindowExpired(Now))
{
LogFile.Serialize(*FString::Printf(TEXT("%s,%s,%s,%f,%f,%f,%d,%d,%d,%d"),
*StartDate,
*CL,
*RunID,
Now - StartTime,
Now - LastSubmitTime,
TimeThisWindow,
FramesThisWindow,
FlushesThisWindow,
NumEventsThisWindow,
BytesThisWindow),
ELogVerbosity::Log, FName(), Now);
ResetWindow(Now);
}
return true;
}
else
{
return false;
}
}
/** Helper to reset our window in Tick. */
bool WindowExpired(double Now)
{
return Now > LastSubmitTime + 60.0;
}
/** Helper to reset our window in Tick. */
void ResetWindow(double Now)
{
LastSubmitTime = Now;
TimeThisWindow = 0.0;
BytesThisWindow = 0;
NumEventsThisWindow = 0;
FlushesThisWindow = 0;
FramesThisWindow = 0;
}
/** log file to use. */
FOutputDeviceFile LogFile{ *FPaths::Combine(*FPaths::GameSavedDir(), TEXT("AnalyticsTiming.csv")) };
FString StartDate;
FString CL;
FString RunID = FGuid().ToString().ToLower();
// Window tracking data
double LastSubmitTime = 0.0;
double TimeThisWindow = 0.0;
uint64 BytesThisWindow = 0;
uint64 NumEventsThisWindow = 0;
int FlushesThisWindow = 0;
int FramesThisWindow = 0;
// time when the first measurement was made.
double StartTime = FPlatformTime::Seconds();
/** Controls whether metrics gathering is enabled. */
bool bEnabled = false;
};
/** Used to set the RunID between matches in game code. Must be carefully called only in situations where ANALYTICS_PERF_TRACKING_ENABLED = 1 */
ANALYTICSET_API void SetAnayticsETPerfTrackingRunID(const FString& RunID)
{
FAnalyticsPerfTracker::Get().SetRunID(RunID);
}
#define ANALYTICS_FLUSH_TRACKING_BEGIN() double FlushStartTime = FPlatformTime::Seconds()
#define ANALYTICS_FLUSH_TRACKING_END(NumBytes, NumEvents) FAnalyticsPerfTracker::Get().RecordFlush(NumBytes, NumEvents, FPlatformTime::Seconds() - FlushStartTime)
#else
#define ANALYTICS_FLUSH_TRACKING_BEGIN(...)
#define ANALYTICS_FLUSH_TRACKING_END(...)
#endif
/**
* Implementation of analytics for Epic Telemetry.
* Supports caching events and flushing them periodically (currently hardcoded limits).
* Also supports a set of default attributes that will be added to every event.
* For efficiency, this set of attributes is added directly into the set of cached events
* with a special flag to indicate its purpose. This allows the set of cached events to be used like
* a set of commands to be executed on flush, and allows us to inject the default attributes
* efficiently into many events without copying the array at all.
*/
class FAnalyticsProviderET :
public IAnalyticsProviderET,
public FTickerObjectBase,
public TSharedFromThis<FAnalyticsProviderET>
{
public:
FAnalyticsProviderET(const FAnalyticsET::Config& ConfigValues);
// FTickerObjectBase
bool Tick(float DeltaSeconds) override;
// IAnalyticsProvider
virtual bool StartSession(const TArray<FAnalyticsEventAttribute>& Attributes) override;
virtual bool StartSession(TArray<FAnalyticsEventAttribute>&& Attributes) override;
virtual void EndSession() override;
virtual void FlushEvents() override;
virtual void SetUserID(const FString& InUserID) override;
virtual FString GetUserID() const override;
virtual FString GetSessionID() const override;
virtual bool SetSessionID(const FString& InSessionID) override;
virtual void RecordEvent(const FString& EventName, const TArray<FAnalyticsEventAttribute>& Attributes) override;
virtual void RecordEvent(FString EventName, TArray<FAnalyticsEventAttribute>&& Attributes) override;
virtual void RecordEventJson(FString EventName, TArray<FAnalyticsEventAttribute>&& AttributesJson) override;
virtual void SetDefaultEventAttributes(TArray<FAnalyticsEventAttribute>&& Attributes) override;
virtual ~FAnalyticsProviderET();
FString GetAPIKey() const { return APIKey; }
private:
/**
* Determines whether we need to flush. Generally, this is only if we have cached events.
* Since the first event is always a control event, and we overwrite multiple control events in a row,
* we can safely say that if the array is longer than 1 item, it must have a real event in it to flush.
*
* NOTE: This MUST be accessed inside a lock on CachedEventsCS!!
*/
bool ShouldFlush() const
{
return CachedEvents.Num() > 1;
}
bool bSessionInProgress;
/** ET Game API Key - Get from your account manager */
FString APIKey;
/** ET API Server */
FString APIServer;
/** the unique UserID as passed to ET. */
FString UserID;
/** The session ID */
FString SessionID;
/** The AppVersion passed to ET. */
FString AppVersion;
/** Max number of analytics events to cache before pushing to server */
const int32 MaxCachedNumEvents;
/** Max time that can elapse before pushing cached events to server */
const float MaxCachedElapsedTime;
/** Allows events to not be cached when -AnalyticsDisableCaching is used. This should only be used for debugging as caching significantly reduces bandwidth overhead per event. */
bool bShouldCacheEvents;
/** Current countdown timer to keep track of MaxCachedElapsedTime push */
float FlushEventsCountdown;
/** Track destructing for unbinding callbacks when firing events at shutdown */
bool bInDestructor;
/** True to use the legacy backend server protocol that uses URL params. */
bool UseLegacyProtocol;
/** AppEnvironment to use. */
FString AppEnvironment;
/** UploadType to use. */
FString UploadType;
/**
* Analytics event entry to be cached
*/
struct FAnalyticsEventEntry
{
/** name of event */
FString EventName;
/** optional list of attributes */
TArray<FAnalyticsEventAttribute> Attributes;
/** local time when event was triggered */
FDateTime TimeStamp;
/** Whether this event was added using the Json API. */
uint32 bIsJsonEvent : 1;
/** Whether this event is setting the default attributes to add to all events. Every cached event list will start with one of these, though it may be empty. */
uint32 bIsDefaultAttributes : 1;
/**
* Constructor. Requires rvalue-refs to ensure we move values efficiently into this struct.
*/
FAnalyticsEventEntry(FString&& InEventName, TArray<FAnalyticsEventAttribute>&& InAttributes, bool bInIsJsonEvent, bool bInIsDefaultAttributes)
: EventName(MoveTemp(InEventName))
, Attributes(MoveTemp(InAttributes))
, TimeStamp(FDateTime::UtcNow())
, bIsJsonEvent(bInIsJsonEvent)
, bIsDefaultAttributes(bInIsDefaultAttributes)
{}
};
/**
* List of analytic events pending a server update .
* NOTE: This MUST be accessed inside a lock on CachedEventsCS!!
*/
TArray<FAnalyticsEventEntry> CachedEvents;
/** Critical section for updating the CachedEvents */
FCriticalSection CachedEventsCS;
/**
* Delegate called when an event Http request completes
*/
void EventRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded);
};
TSharedPtr<IAnalyticsProviderET> FAnalyticsET::CreateAnalyticsProvider(const Config& ConfigValues) const
{
// If we didn't have a proper APIKey, return NULL
if (ConfigValues.APIKeyET.IsEmpty())
{
UE_LOG(LogAnalytics, Warning, TEXT("CreateAnalyticsProvider config not contain required parameter %s"), *Config::GetKeyNameForAPIKey());
return NULL;
}
return TSharedPtr<IAnalyticsProviderET>(new FAnalyticsProviderET(ConfigValues));
}
/**
* Perform any initialization.
*/
FAnalyticsProviderET::FAnalyticsProviderET(const FAnalyticsET::Config& ConfigValues)
:bSessionInProgress(false)
, APIKey(ConfigValues.APIKeyET)
, APIServer(ConfigValues.APIServerET)
, MaxCachedNumEvents(20)
, MaxCachedElapsedTime(60.0f)
, bShouldCacheEvents(true)
, FlushEventsCountdown(MaxCachedElapsedTime)
, bInDestructor(false)
, UseLegacyProtocol(ConfigValues.UseLegacyProtocol)
{
if (APIKey.IsEmpty() || APIServer.IsEmpty())
{
UE_LOG(LogAnalytics, Fatal, TEXT("AnalyticsET: APIKey (%s) and APIServer (%s) cannot be empty!"), *APIKey, *APIServer);
}
// force very verbose logging if we are force-disabling events.
bool bForceDisableCaching = FParse::Param(FCommandLine::Get(), TEXT("ANALYTICSDISABLECACHING"));
if (bForceDisableCaching)
{
UE_SET_LOG_VERBOSITY(LogAnalytics, VeryVerbose);
bShouldCacheEvents = false;
}
// if we are caching events, presize the array to max size. Otherwise, we will never have more than two entries in the array (one for the default attributes, one for the actual event)
CachedEvents.Reserve(bShouldCacheEvents ? MaxCachedNumEvents + 1 : 2);
// make sure that we always start with one control event in the CachedEvents array.
CachedEvents.Emplace(FString(), TArray<FAnalyticsEventAttribute>(), false, true);
UE_LOG(LogAnalytics, Verbose, TEXT("[%s] Initializing ET Analytics provider"), *APIKey);
// default to FEngineVersion::Current() if one is not provided, append FEngineVersion::Current() otherwise.
FString ConfigAppVersion = ConfigValues.AppVersionET;
// Allow the cmdline to force a specific AppVersion so it can be set dynamically.
FParse::Value(FCommandLine::Get(), TEXT("ANALYTICSAPPVERSION="), ConfigAppVersion, false);
AppVersion = ConfigAppVersion.IsEmpty()
? FString(FApp::GetBuildVersion())
: ConfigAppVersion.Replace(TEXT("%VERSION%"), FApp::GetBuildVersion(), ESearchCase::CaseSensitive);
UE_LOG(LogAnalytics, Log, TEXT("[%s] APIServer = %s. AppVersion = %s"), *APIKey, *APIServer, *AppVersion);
// only need these if we are using the data router protocol.
if (!UseLegacyProtocol)
{
AppEnvironment = ConfigValues.AppEnvironment.IsEmpty()
? FAnalyticsET::Config::GetDefaultAppEnvironment()
: ConfigValues.AppEnvironment;
UploadType = ConfigValues.UploadType.IsEmpty()
? FAnalyticsET::Config::GetDefaultUploadType()
: ConfigValues.UploadType;
}
// see if there is a cmdline supplied UserID.
#if !UE_BUILD_SHIPPING
FString ConfigUserID;
if (FParse::Value(FCommandLine::Get(), TEXT("ANALYTICSUSERID="), ConfigUserID, false))
{
SetUserID(ConfigUserID);
}
#endif // !UE_BUILD_SHIPPING
}
bool FAnalyticsProviderET::Tick(float DeltaSeconds)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FAnalyticsProviderET_Tick);
// There are much better ways to do this, but since most events are recorded and handled on the same (game) thread,
// this is probably mostly fine for now, and simply favoring not crashing at the moment
FScopeLock ScopedLock(&CachedEventsCS);
if (ShouldFlush())
{
// Countdown to flush
FlushEventsCountdown -= DeltaSeconds;
// If reached countdown or already at max cached events then flush
if (FlushEventsCountdown <= 0 ||
CachedEvents.Num() >= MaxCachedNumEvents)
{
FlushEvents();
}
}
return true;
}
FAnalyticsProviderET::~FAnalyticsProviderET()
{
UE_LOG(LogAnalytics, Verbose, TEXT("[%s] Destroying ET Analytics provider"), *APIKey);
bInDestructor = true;
EndSession();
}
/**
* Start capturing stats for upload
* Uses the unique ApiKey associated with your app
*/
bool FAnalyticsProviderET::StartSession(const TArray<FAnalyticsEventAttribute>& Attributes)
{
// Have to copy Attributes array because this doesn't come in as an rvalue ref.
return StartSession(TArray<FAnalyticsEventAttribute>(Attributes));
}
bool FAnalyticsProviderET::StartSession(TArray<FAnalyticsEventAttribute>&& Attributes)
{
UE_LOG(LogAnalytics, Log, TEXT("[%s] AnalyticsET::StartSession"), *APIKey);
// end/flush previous session before staring new one
if (bSessionInProgress)
{
EndSession();
}
FGuid SessionGUID;
FPlatformMisc::CreateGuid(SessionGUID);
SessionID = SessionGUID.ToString(EGuidFormats::DigitsWithHyphensInBraces);
// always ensure we send a few specific attributes on session start.
TArray<FAnalyticsEventAttribute> AppendedAttributes(MoveTemp(Attributes));
// this is for legacy reasons (we used to use this ID, so helps us create old->new mappings).
AppendedAttributes.Emplace(TEXT("UniqueDeviceId"), FPlatformMisc::GetUniqueDeviceId());
// we should always know what platform is hosting this session.
AppendedAttributes.Emplace(TEXT("Platform"), FString(FPlatformProperties::IniPlatformName()));
RecordEvent(TEXT("SessionStart"), MoveTemp(AppendedAttributes));
bSessionInProgress = true;
return bSessionInProgress;
}
/**
* End capturing stats and queue the upload
*/
void FAnalyticsProviderET::EndSession()
{
if (bSessionInProgress)
{
RecordEvent(TEXT("SessionEnd"), TArray<FAnalyticsEventAttribute>());
}
FlushEvents();
SessionID.Empty();
bSessionInProgress = false;
}
void FAnalyticsProviderET::FlushEvents()
{
// There are much better ways to do this, but since most events are recorded and handled on the same (game) thread,
// this is probably mostly fine for now, and simply favoring not crashing at the moment
FScopeLock ScopedLock(&CachedEventsCS);
// Make sure we don't try to flush too many times. When we are not caching events it's possible this can be called when there are no events in the array.
if (!ShouldFlush())
{
return;
}
ANALYTICS_FLUSH_TRACKING_BEGIN();
int EventCount = 0;
int PayloadSize = 0;
if(ensure(FModuleManager::Get().IsModuleLoaded("HTTP")))
{
FString Payload;
FDateTime CurrentTime = FDateTime::UtcNow();
// Track the current set of default attributes. We move into this array instead of just referencing it
// because at the end we will push the latest value back onto the list of cached events.
// We can do this without actually copying the array this way.
TArray<FAnalyticsEventAttribute> CurrentDefaultAttributes;
if (!UseLegacyProtocol)
{
TSharedRef< TJsonWriter<TCHAR, TCondensedJsonPrintPolicy<TCHAR> > > JsonWriter = TJsonWriterFactory<TCHAR, TCondensedJsonPrintPolicy<TCHAR> >::Create(&Payload);
JsonWriter->WriteObjectStart();
JsonWriter->WriteArrayStart(TEXT("Events"));
for (FAnalyticsEventEntry& Entry : CachedEvents)
{
if (Entry.bIsDefaultAttributes)
{
// This is the default attributes, so update the array.
CurrentDefaultAttributes = MoveTemp(Entry.Attributes);
}
else
{
++EventCount;
// event entry
JsonWriter->WriteObjectStart();
JsonWriter->WriteValue(TEXT("EventName"), Entry.EventName);
FString DateOffset = (CurrentTime - Entry.TimeStamp).ToString();
JsonWriter->WriteValue(TEXT("DateOffset"), DateOffset);
// default attributes for this event
for (const FAnalyticsEventAttribute& Attr : CurrentDefaultAttributes)
{
JsonWriter->WriteValue(Attr.AttrName, Attr.AttrValue);
}
// optional attributes for this event
if (!Entry.bIsJsonEvent)
{
for (const FAnalyticsEventAttribute& Attr : Entry.Attributes)
{
JsonWriter->WriteValue(Attr.AttrName, Attr.AttrValue);
}
}
else
{
for (const FAnalyticsEventAttribute& Attr : Entry.Attributes)
{
JsonWriter->WriteRawJSONValue(Attr.AttrName, Attr.AttrValue);
}
}
JsonWriter->WriteObjectEnd();
}
}
JsonWriter->WriteArrayEnd();
JsonWriter->WriteObjectEnd();
JsonWriter->Close();
FString URLPath = FString::Printf(TEXT("datarouter/api/v1/public/data?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&AppEnvironment=%s&UploadType=%s"),
*FPlatformHttp::UrlEncode(SessionID),
*FPlatformHttp::UrlEncode(APIKey),
*FPlatformHttp::UrlEncode(AppVersion),
*FPlatformHttp::UrlEncode(UserID),
*FPlatformHttp::UrlEncode(AppEnvironment),
*FPlatformHttp::UrlEncode(UploadType));
PayloadSize = URLPath.Len() + Payload.Len();
if (UE_LOG_ACTIVE(LogAnalytics, VeryVerbose))
{
// Recreate the URLPath for logging because we do not want to escape the parameters when logging.
// We cannot simply UrlEncode the entire Path after logging it because UrlEncode(Params) != UrlEncode(Param1) & UrlEncode(Param2) ...
FString LogString = FString::Printf(TEXT("[%s] AnalyticsET URL:datarouter/api/v1/public/data?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&AppEnvironment=%s&UploadType=%s. Payload:%s"),
*APIKey,
*SessionID,
*APIKey,
*AppVersion,
*UserID,
*AppEnvironment,
*UploadType,
*Payload);
UE_LOG(LogAnalytics, VeryVerbose, TEXT("%s"), *LogString);
}
// Create/send Http request for an event
TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("application/json; charset=utf-8"));
HttpRequest->SetURL(APIServer + URLPath);
HttpRequest->SetVerb(TEXT("POST"));
HttpRequest->SetContentAsString(Payload);
// Don't set a response callback if we are in our destructor, as the instance will no longer be there to call.
if (!bInDestructor)
{
HttpRequest->OnProcessRequestComplete().BindSP(this, &FAnalyticsProviderET::EventRequestComplete);
}
HttpRequest->ProcessRequest();
}
else
{
// this is a legacy pathway that doesn't accept batch payloads of cached data. We'll just send one request for each event, which will be slow for a large batch of requests at once.
for (auto& Event : CachedEvents)
{
if (Event.bIsDefaultAttributes)
{
// This is the default attributes, so update the array.
CurrentDefaultAttributes = MoveTemp(Event.Attributes);
}
else
{
++EventCount;
FString EventParams;
int PayloadNdx = 0;
// default attributes for this event
for (int DefaultAttributeNdx = 0; DefaultAttributeNdx < CurrentDefaultAttributes.Num() && PayloadNdx < 40; ++DefaultAttributeNdx, ++PayloadNdx)
{
EventParams += FString::Printf(TEXT("&AttributeName%d=%s&AttributeValue%d=%s"),
PayloadNdx,
*FPlatformHttp::UrlEncode(CurrentDefaultAttributes[DefaultAttributeNdx].AttrName),
PayloadNdx,
*FPlatformHttp::UrlEncode(CurrentDefaultAttributes[DefaultAttributeNdx].AttrValue));
}
// optional attributes for this event
for (int AttrNdx = 0; AttrNdx < Event.Attributes.Num() && PayloadNdx < 40; ++AttrNdx, ++PayloadNdx)
{
EventParams += FString::Printf(TEXT("&AttributeName%d=%s&AttributeValue%d=%s"),
PayloadNdx,
*FPlatformHttp::UrlEncode(Event.Attributes[AttrNdx].AttrName),
PayloadNdx,
*FPlatformHttp::UrlEncode(Event.Attributes[AttrNdx].AttrValue));
}
// log out the un-encoded values to make reading the log easier.
UE_LOG(LogAnalytics, VeryVerbose, TEXT("[%s] AnalyticsET URL:SendEvent.1?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&EventName=%s%s"),
*APIKey,
*SessionID,
*APIKey,
*AppVersion,
*UserID,
*Event.EventName,
*EventParams);
// Create/send Http request for an event
TSharedRef<IHttpRequest> HttpRequest = FHttpModule::Get().CreateRequest();
HttpRequest->SetHeader(TEXT("Content-Type"), TEXT("text/plain"));
// Don't need to URL encode the APIServer or the EventParams, which are already encoded, and contain parameter separaters that we DON'T want encoded.
HttpRequest->SetURL(FString::Printf(TEXT("%sSendEvent.1?SessionID=%s&AppID=%s&AppVersion=%s&UserID=%s&EventName=%s%s"),
*APIServer,
*FPlatformHttp::UrlEncode(SessionID),
*FPlatformHttp::UrlEncode(APIKey),
*FPlatformHttp::UrlEncode(AppVersion),
*FPlatformHttp::UrlEncode(UserID),
*FPlatformHttp::UrlEncode(Event.EventName),
*EventParams));
PayloadSize = HttpRequest->GetURL().Len();
HttpRequest->SetVerb(TEXT("GET"));
HttpRequest->OnProcessRequestComplete().BindRaw(this, &FAnalyticsProviderET::EventRequestComplete);
HttpRequest->ProcessRequest();
}
}
}
FlushEventsCountdown = MaxCachedElapsedTime;
// clear the array but don't reclaim the memory.
CachedEvents.Reset();
// Push the current set of default attributes back onto the events list for next time we flush.
// Can't call SetDefaultEventAttributes to do this because it already assumes we have one item in the array.
CachedEvents.Emplace(FString(), MoveTemp(CurrentDefaultAttributes), false, true);
}
ANALYTICS_FLUSH_TRACKING_END(PayloadSize, EventCount);
}
void FAnalyticsProviderET::SetUserID(const FString& InUserID)
{
// command-line specified user ID overrides all attempts to reset it.
if (!FParse::Value(FCommandLine::Get(), TEXT("ANALYTICSUSERID="), UserID, false))
{
UE_LOG(LogAnalytics, Log, TEXT("[%s] SetUserId %s"), *APIKey, *InUserID);
UserID = InUserID;
}
else if (UserID != InUserID)
{
UE_LOG(LogAnalytics, Log, TEXT("[%s] Overriding SetUserId %s with cmdline UserId of %s."), *APIKey, *InUserID, *UserID);
}
}
FString FAnalyticsProviderET::GetUserID() const
{
return UserID;
}
FString FAnalyticsProviderET::GetSessionID() const
{
return SessionID;
}
bool FAnalyticsProviderET::SetSessionID(const FString& InSessionID)
{
SessionID = InSessionID;
UE_LOG(LogAnalytics, Log, TEXT("[%s] Forcing SessionID to %s."), *APIKey, *SessionID);
return true;
}
void FAnalyticsProviderET::RecordEvent(const FString& EventName, const TArray<FAnalyticsEventAttribute>& Attributes)
{
// Have to copy Attributes array because this doesn't come in as an rvalue ref.
RecordEvent(EventName, TArray<FAnalyticsEventAttribute>(Attributes));
}
void FAnalyticsProviderET::RecordEvent(FString EventName, TArray<FAnalyticsEventAttribute>&& Attributes)
{
// There are much better ways to do this, but since most events are recorded and handled on the same (game) thread,
// this is probably mostly fine for now, and simply favoring not crashing at the moment
FScopeLock ScopedLock(&CachedEventsCS);
CachedEvents.Emplace(MoveTemp(EventName), MoveTemp(Attributes), false, false);
// if we aren't caching events, flush immediately. This is really only for debugging as it will significantly affect bandwidth.
if (!bShouldCacheEvents)
{
FlushEvents();
}
}
void FAnalyticsProviderET::RecordEventJson(FString EventName, TArray<FAnalyticsEventAttribute>&& AttributesJson)
{
checkf(!UseLegacyProtocol, TEXT("Cannot use Json events with legacy protocol"));
// There are much better ways to do this, but since most events are recorded and handled on the same (game) thread,
// this is probably mostly fine for now, and simply favoring not crashing at the moment
FScopeLock ScopedLock(&CachedEventsCS);
CachedEvents.Emplace(MoveTemp(EventName), MoveTemp(AttributesJson), true, false);
// if we aren't caching events, flush immediately. This is really only for debugging as it will significantly affect bandwidth.
if (!bShouldCacheEvents)
{
FlushEvents();
}
}
void FAnalyticsProviderET::SetDefaultEventAttributes(TArray<FAnalyticsEventAttribute>&& Attributes)
{
FScopeLock ScopedLock(&CachedEventsCS);
// we know we always have one entry in CachedEvents, so no need to check for Num() > 0.
// If we are trying to add two default attribute events in a row, just overwrite the last one.
if (CachedEvents.Last().bIsDefaultAttributes)
{
CachedEvents.Last() = FAnalyticsEventEntry(FString(), MoveTemp(Attributes), false, true);
}
else
{
CachedEvents.Emplace(FString(), MoveTemp(Attributes), false, true);
}
}
void FAnalyticsProviderET::EventRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
if (bSucceeded && HttpResponse.IsValid())
{
UE_LOG(LogAnalytics, VeryVerbose, TEXT("[%s] ET response for [%s]. Code: %d. Payload: %s"), *APIKey, *HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *HttpResponse->GetContentAsString());
}
else
{
UE_LOG(LogAnalytics, VeryVerbose, TEXT("[%s] ET response for [%s]. No response"), *APIKey, *HttpRequest->GetURL());
}
}