This commit is contained in:
Rambod Kermanizadeh 2017-12-18 15:15:25 -08:00
Родитель 135040dfda
Коммит e838b215d6
135 изменённых файлов: 9470 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c238225edea024c2b8df349394939c3f
folderAsset: yes
timeCreated: 1512691582
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 31d8d23c21c2346f489ea4b8ea895323
folderAsset: yes
timeCreated: 1438098821
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f21d9411463fe4c518583dc787a70979
folderAsset: yes
timeCreated: 1438293695
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 62249380d6a53419c8af2248825f2225
folderAsset: yes
timeCreated: 1463713534
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: d821bcec251614db69b44f63017fb25d
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 970254eaca62b48c19ba2b8a37e4be59
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 7906aa478f2864ef797fea65323bdb02
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: c043bd35ad4e247d8b78af8af7b7b540
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 2a10c22a4b3ba47eba457543b2797ccb
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: dbdd0a3bb4a5d49a883f6dac743718f7
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 955 B

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: c813ef568cfc54e89975e3cba1865aee
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 966 B

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 32974842b7e2246a39105589ec930963
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 999e7e026af4f4b5a8a3c6d5880bbabc
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 8820cc7d4dcda4e05aabae34844b5d04
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: a50bbedf15844489ba5279bc4405f663
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 5101704bcea19466ea3d7aa5e596f026
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 929eceb046d7843acbd78dfd41913446
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 35f6382bad4c94fe98f3bae4c615f790
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: c19831b708ada4c39b5e9a118c3e72be
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Просмотреть файл

@ -0,0 +1,77 @@
fileFormatVersion: 2
guid: 39ed6f06956bf4774809defcff5e0898
timeCreated: 1513116735
licenseType: Pro
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -1
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: fc1aae7c6c4fe4030b056a8d2df57df3
folderAsset: yes
timeCreated: 1444707777
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,150 @@
/// <summary>
/// Inspector for the Aggregation portion of the Heatmapper.
/// </summary>
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityAnalytics;
using System.Linq;
namespace UnityAnalytics360VideoHeatmap
{
public class AggregationInspector
{
const string k_UseCustomDataPathKey = "UnityAnalyticsHeatmapUsePersistentDataPathKey";
string m_DataPath = "./";
HeatmapDataProcessor m_Processor;
private GUIContent m_DataPathContent = new GUIContent("Input Path", "Where to retrieve data (defaults to Application.persistentDataPath");
private GUIContent m_DatesContent = new GUIContent("Dates", "ISO-8601 datetimes (YYYY-MM-DD)");
string m_StartDate = "";
string m_EndDate = "";
bool m_ValidDates = true;
GUIStyle m_ValidDateStyle;
GUIStyle m_InvalidDateStyle;
const int k_FetchInitValue = 30;
public AggregationInspector(HeatmapDataProcessor processor)
{
m_Processor = processor;
}
public static AggregationInspector Init(HeatmapDataProcessor processor)
{
return new AggregationInspector(processor);
}
public void OnEnable()
{
// Restore cached paths
m_DataPath = m_Processor.m_RawDataPath;
m_EndDate = m_Processor.m_EndDate;
m_StartDate = m_Processor.m_StartDate;
}
public void OnGUI()
{
if (m_ValidDateStyle == null)
{
m_ValidDateStyle = new GUIStyle("button");
m_InvalidDateStyle = new GUIStyle("button");
m_InvalidDateStyle.normal.textColor = Color.red;
}
using (new GUILayout.VerticalScope())
{
EditorGUILayout.LabelField("Data", EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
using (new GUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(m_DataPathContent, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
m_DataPath = Application.dataPath;
UseCustomDataPathChange(true);
EditorGUILayout.SelectableLabel(m_DataPath + "/RawDataFolder", EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
}
using (new GUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(m_DatesContent, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
GUIStyle dateFieldStyle = m_ValidDates ? m_ValidDateStyle : m_InvalidDateStyle;
dateFieldStyle.padding = new RectOffset(0, 0, ((int)EditorGUIUtility.singleLineHeight / 3), 0);
m_StartDate = AnalyticsDatePicker.DatePicker(m_StartDate, dateFieldStyle, StartDateChange, DateFailure, DateValidationStart);
m_EndDate = AnalyticsDatePicker.DatePicker(m_EndDate, dateFieldStyle, EndDateChange, DateFailure, DateValidationEnd);
}
EditorGUILayout.Space();
}
}
void UseCustomDataPathChange(bool value)
{
EditorPrefs.SetBool(k_UseCustomDataPathKey, value);
DataPathChange(m_DataPath);
}
void DataPathChange(string value)
{
if (string.IsNullOrEmpty(value))
{
m_DataPath = Application.persistentDataPath;
}
m_Processor.m_RawDataPath = value;
}
void StartDateChange(string value)
{
m_ValidDates = true;
m_Processor.m_StartDate = value;
HeatmapViewModel.startDate = value;
}
void EndDateChange(string value)
{
m_ValidDates = true;
m_Processor.m_EndDate = value;
HeatmapViewModel.endDate = value;
}
void DateFailure()
{
m_ValidDates = false;
}
bool DateValidationStart(string value)
{
return DateValidation(value, m_EndDate);
}
bool DateValidationEnd(string value)
{
return DateValidation(m_StartDate, value);
}
bool DateValidation(string start, string end)
{
DateTime startDate;
DateTime endDate;
try
{
startDate = DateTime.Parse(start);
endDate = DateTime.Parse(end);
}
catch
{
return false;
}
// Midnight tonight
var today = DateTime.Today.AddDays(1).ToUniversalTime();
return startDate < endDate && endDate <= today;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8d34ee6154c4743b1b5f0749c2c3eba4
timeCreated: 1512690865
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6238eb5270fde46bfb6f852753b8cbc0
folderAsset: yes
timeCreated: 1471146040
licenseType: Free
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,359 @@
using System;
using UnityEditor;
using UnityEngine;
namespace UnityAnalytics360VideoHeatmap
{
public static class AnalyticsDatePicker {
//private static GUIStyle fieldStyle;
private static Vector2 fieldOffset = new Vector2(0, -2f);
private static Vector2 winSize = new Vector2(300f, 175f);
public static string s_CachedValue;
private static int s_CachedControlId;
private static bool s_DoDropDown = false;
public static string DatePicker(string value,
GUIStyle fieldStyle,
EditorGUIBinding.TextFieldChangeHandler change,
EditorGUIBinding.TextFieldFailureHandler failure = null,
EditorGUIBinding.TextFieldValidationHandler validate = null)
{
int controlID = GUIUtility.GetControlID (FocusType.Keyboard);
Rect controlRect = EditorGUILayout.GetControlRect(false);
fieldStyle.contentOffset = fieldOffset;
fieldStyle.clipping = TextClipping.Overflow;
EditorGUI.BeginChangeCheck();
EditorGUI.LabelField(controlRect, value, fieldStyle);
DatePickerWindow window = null;
switch (Event.current.GetTypeForControl(controlID))
{
case EventType.MouseDown:
if (controlRect.Contains(Event.current.mousePosition) && Event.current.button == 0)
{
GUIUtility.hotControl = controlID;
Event.current.Use();
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == controlID && Event.current.button == 0
&& controlRect.Contains(Event.current.mousePosition))
{
s_DoDropDown = true;
Event.current.Use();
}
break;
case EventType.Repaint:
if (GUIUtility.hotControl == controlID && s_DoDropDown)
{
s_DoDropDown = false;
s_CachedControlId = controlID;
GUIUtility.hotControl = 0;
Vector2 position = EditorGUIUtility.GUIToScreenPoint(new Vector2(controlRect.x, controlRect.y+controlRect.height));
window = ScriptableObject.CreateInstance<DatePickerWindow>();
window.ShowAsDropDown(new Rect(position.x, position.y-winSize.y, winSize.x, winSize.y), winSize, value);
}
break;
}
if (s_CachedControlId == controlID && s_CachedValue != null)
{
value = s_CachedValue;
s_CachedControlId = 0;
s_CachedValue = null;
GUI.changed = true;
}
if (EditorGUI.EndChangeCheck())
{
DatePickerApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
private static void DatePickerApplyChangeHandlers(string text,
EditorGUIBinding.TextFieldChangeHandler change,
EditorGUIBinding.TextFieldFailureHandler failure,
EditorGUIBinding.TextFieldValidationHandler validate)
{
bool validated = (validate == null) ? true : validate(text);
if (validated)
{
change(text);
}
else if (!validated && failure != null)
{
failure();
}
}
}
public class DatePickerWindow : EditorWindow
{
public string value;
private DatePickerModel model;
private bool doCommit = false;
private GUILayoutOption itemWidth;
private static GUIStyle fieldStyle;
private static GUIStyle dateStyle;
private static RectOffset dateFieldRectOffset;
private static string[] m_MonthsOfTheYear = new string[12]
{"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"};
public void ShowAsDropDown(Rect buttonRect, Vector2 windowSize, string dateValue)
{
base.ShowAsDropDown(buttonRect, windowSize);
value = dateValue;
itemWidth = GUILayout.Width(35f);
}
void OnEnable()
{
model = new DatePickerModel();
dateFieldRectOffset = new RectOffset(0, 0, 2, 0);
if (fieldStyle == null)
{
fieldStyle = new GUIStyle();
fieldStyle.alignment = TextAnchor.MiddleCenter;
dateStyle = new GUIStyle();
dateStyle.alignment = TextAnchor.MiddleCenter;
dateStyle.margin = dateFieldRectOffset;
dateStyle.stretchWidth = true;
dateStyle.clipping = TextClipping.Overflow;
}
}
void OnGUI()
{
value = EditorGUILayout.TextField(value);
if (string.IsNullOrEmpty(value))
return;
model.Update(value);
using(new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("<"))
{
model.decrementMonth();
model.Calculate();
}
int monthIndex = Mathf.Clamp(model.m_Month - 1, 0, 11);
EditorGUILayout.LabelField(model.m_Year + " " + m_MonthsOfTheYear[monthIndex], dateStyle);
if (GUILayout.Button(">"))
{
model.incrementMonth();
model.Calculate();
}
}
using (new EditorGUILayout.VerticalScope("box"))
{
for (int a = 0; a < 6; a++)
{
using(new EditorGUILayout.HorizontalScope())
{
for (int b = a*7; b < (a*7)+7; b++)
{
var dt = model.m_MonthDays[b];
if (dt == 0)
{
EditorGUILayout.LabelField(" ", itemWidth);
}
else if (dt == model.m_Date)
{
EditorGUILayout.LabelField(dt.ToString(), fieldStyle, itemWidth);
}
else if (GUILayout.Button(dt.ToString(), itemWidth))
{
//TODO: Commit the new date
model.m_Date = dt;
doCommit = true;
}
}
}
}
}
value = model.dateString;
if (doCommit || Event.current.type == EventType.KeyDown && Event.current.keyCode == KeyCode.Return)
{
Commit();
}
}
void OnInspectorUpdate()
{
if (AnalyticsDatePicker.s_CachedValue != null)
{
Close();
}
}
void Commit()
{
AnalyticsDatePicker.s_CachedValue = value;
doCommit = false;
}
}
public class DatePickerModel
{
private int _year;
public int m_Year
{
get
{
return _year;
}
set
{
_year = value;
dateString = _year + "-" + MinFormat(m_Month) + "-" + MinFormat(m_Date);
}
}
private int _month;
public int m_Month
{
get
{
return _month;
}
set
{
_month = value;
dateString = m_Year + "-" + MinFormat(_month) + "-" + MinFormat(m_Date);
}
}
private int _date;
public int m_Date
{
get
{
return _date;
}
set
{
_date = value;
dateString = m_Year + "-" + MinFormat(m_Month) + "-" + MinFormat(_date);
}
}
private string _dateString;
public string dateString
{
get
{
return _dateString;
}
private set
{
_dateString = value;
}
}
public void decrementMonth()
{
if (m_Month - 1 < 1)
{
m_Year --;
m_Month = 12;
}
else
{
m_Month --;
}
}
public void incrementMonth()
{
if (m_Month + 1 > 12)
{
m_Year ++;
m_Month = 1;
}
else
{
m_Month ++;
}
}
int[] m_DaysInMonths = new int[12]{31, 28, 31, 30, 31, 30, 31, 30, 30, 31, 30, 31};
public int[] m_MonthDays;
public void Update(string date)
{
dateString = date;
string[] elements = date.Split('-');
try {
m_Year = int.Parse(elements[0]);
m_Month = int.Parse(elements[1]);
m_Date = int.Parse(elements[2]);
} catch {
//No-op
}
Calculate();
}
public void Calculate()
{
if (!CheckDateValidity())
{
return;
}
var date = new DateTime(m_Year, m_Month, 1);
int firstDay = (int)date.DayOfWeek;
int daysInMonth = GetDaysInMonth();
m_MonthDays = new int[42];
for(int a = 0; a < 42; a++)
{
if (a >= firstDay && a < daysInMonth+firstDay)
{
m_MonthDays[a] = a + 1 - firstDay;
}
}
}
int GetDaysInMonth()
{
int days = m_DaysInMonths[m_Month-1];
// leap year calculation
if (m_Month == 2 && m_Year % 4 == 0 && (m_Year % 100 != 0 || m_Year % 400 == 0))
{
days ++;
}
return days;
}
bool CheckDateValidity()
{
try
{
new DateTime(m_Year, m_Month, m_Date);
return true;
}
catch
{
return false;
}
}
string MinFormat(int number)
{
return number < 10 ? "0" + number : number.ToString();
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 5b5aa70313e0c4f88928766412f1bdbe
timeCreated: 1470758172
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,442 @@
/// <summary>
/// EditorGUI Components decorated with change, fail and validation handlers
/// </summary>
///
/// Decorates EditorGUILayout controls, adding three callback handlers
/// * change - Required. Calls back whenever the value changes. If a validation handler is included and validation fails,
/// change is not called.
/// * failure - Optional. Called if validation fails.
/// * validation - Optional. If provided, will prevent calls to change when validation fails. If failure is provided, will call
/// that handler instead.
using System;
using UnityEngine;
using UnityEditor;
namespace UnityAnalytics360VideoHeatmap
{
public class EditorGUIBinding
{
#region FloatField
public delegate void FloatChangeHandler(float value);
public delegate void FloatFailureHandler();
public delegate bool FloatValidationHandler(float value);
private static void FloatApplyChangeHandlers(float value, FloatChangeHandler change, FloatFailureHandler failure, FloatValidationHandler validate)
{
bool validated = (validate == null) ? true : validate(value);
if (validated)
{
change(value);
}
else if (!validated && failure != null)
{
failure();
}
}
public static float FloatField(float value,
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.FloatField(value, options);
if (EditorGUI.EndChangeCheck())
{
FloatApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static float FloatField(float value, GUIStyle style,
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.FloatField(value, style, options);
if (EditorGUI.EndChangeCheck())
{
FloatApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static float FloatField(string label, float value,
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.FloatField(label, value, options);
if (EditorGUI.EndChangeCheck())
{
FloatApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static float FloatField(string label, float value, GUIStyle style,
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.FloatField(label, value, style, options);
if (EditorGUI.EndChangeCheck())
{
FloatApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static float FloatField(GUIContent label, float value,
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.FloatField(label, value, options);
if (EditorGUI.EndChangeCheck())
{
FloatApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static float FloatField(GUIContent label, float value, GUIStyle style,
FloatChangeHandler change, FloatFailureHandler failure = null, FloatValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.FloatField(label, value, style, options);
if (EditorGUI.EndChangeCheck())
{
FloatApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
#endregion
#region Popup
public delegate void IntChangeHandler(int value);
public delegate void IntFailureHandler();
public delegate bool IntValidationHandler(int value);
private static void IntApplyChangeHandlers(int value, IntChangeHandler change, IntFailureHandler failure, IntValidationHandler validate)
{
bool validated = (validate == null) ? true : validate(value);
if (validated)
{
change(value);
}
else if (!validated && failure != null)
{
failure();
}
}
public static int Popup(int selectedIndex, string[] displayedOptions,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(int selectedIndex, string[] displayedOptions, GUIStyle style,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, style, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(int selectedIndex, GUIContent[] displayedOptions,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(int selectedIndex, GUIContent[] displayedOptions, GUIStyle style,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(selectedIndex, displayedOptions, style, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(string label, int selectedIndex, string[] displayedOptions,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(string label, int selectedIndex, string[] displayedOptions, GUIStyle style,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, style, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(GUIContent label, int selectedIndex, GUIContent[] displayedOptions,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
public static int Popup(GUIContent label, int selectedIndex, GUIContent[] displayedOptions, GUIStyle style,
IntChangeHandler change, IntFailureHandler failure = null, IntValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUILayout.Popup(label, selectedIndex, displayedOptions, style, options);
if (EditorGUI.EndChangeCheck())
{
IntApplyChangeHandlers(selectedIndex, change, failure, validate);
}
return selectedIndex;
}
#endregion
#region TextField
public delegate void TextFieldChangeHandler(string text);
public delegate void TextFieldFailureHandler();
public delegate bool TextFieldValidationHandler(string text);
private static void TextFieldApplyChangeHandlers(string text, TextFieldChangeHandler change, TextFieldFailureHandler failure, TextFieldValidationHandler validate)
{
bool validated = (validate == null) ? true : validate(text);
if (validated)
{
change(text);
}
else if (!validated && failure != null)
{
failure();
}
}
public static string TextField(string text,
TextFieldChangeHandler change,
TextFieldFailureHandler failure = null,
TextFieldValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
text = EditorGUILayout.TextField(text, options);
if (EditorGUI.EndChangeCheck())
{
TextFieldApplyChangeHandlers(text, change, failure, validate);
}
return text;
}
public static string TextField(string text, GUIStyle style,
TextFieldChangeHandler change,
TextFieldFailureHandler failure = null,
TextFieldValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
text = EditorGUILayout.TextField(text, style, options);
if (EditorGUI.EndChangeCheck())
{
TextFieldApplyChangeHandlers(text, change, failure, validate);
}
return text;
}
public static string TextField(string label, string text,
TextFieldChangeHandler change,
TextFieldFailureHandler failure = null,
TextFieldValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
text = EditorGUILayout.TextField(label, text, options);
if (EditorGUI.EndChangeCheck())
{
TextFieldApplyChangeHandlers(text, change, failure, validate);
}
return text;
}
public static string TextField(string label, string text, GUIStyle style,
TextFieldChangeHandler change,
TextFieldFailureHandler failure = null,
TextFieldValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
text = EditorGUILayout.TextField(label, text, style, options);
if (EditorGUI.EndChangeCheck())
{
TextFieldApplyChangeHandlers(text, change, failure, validate);
}
return text;
}
public static string TextField(GUIContent label, string text,
TextFieldChangeHandler change,
TextFieldFailureHandler failure = null,
TextFieldValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
text = EditorGUILayout.TextField(label, text, options);
if (EditorGUI.EndChangeCheck())
{
TextFieldApplyChangeHandlers(text, change, failure, validate);
}
return text;
}
public static string TextField(GUIContent label, string text, GUIStyle style,
TextFieldChangeHandler change,
TextFieldFailureHandler failure = null,
TextFieldValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
text = EditorGUILayout.TextField(label, text, style, options);
if (EditorGUI.EndChangeCheck())
{
TextFieldApplyChangeHandlers(text, change, failure, validate);
}
return text;
}
#endregion
#region Toggle
public delegate void ToggleChangeHandler(bool value);
public delegate void ToggleFailureHandler();
public delegate bool ToggleValidationHandler(bool value);
private static void ToggleApplyChangeHandlers(bool value,
ToggleChangeHandler change,
ToggleFailureHandler failure,
ToggleValidationHandler validate)
{
bool validated = (validate == null) ? true : validate(value);
if (validated)
{
change(value);
}
else if (!validated && failure != null)
{
failure();
}
}
public static bool Toggle(bool value,
ToggleChangeHandler change,
ToggleFailureHandler failure = null,
ToggleValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.ToggleLeft("", value, options);
if (EditorGUI.EndChangeCheck())
{
ToggleApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static bool Toggle(string label, bool value,
ToggleChangeHandler change,
ToggleFailureHandler failure = null,
ToggleValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.ToggleLeft(label, value, options);
if (EditorGUI.EndChangeCheck())
{
ToggleApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static bool Toggle(GUIContent label, bool value,
ToggleChangeHandler change,
ToggleFailureHandler failure = null,
ToggleValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.ToggleLeft(label, value, options);
if (EditorGUI.EndChangeCheck())
{
ToggleApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static bool Toggle(bool value, GUIStyle style,
ToggleChangeHandler change,
ToggleFailureHandler failure = null,
ToggleValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.ToggleLeft("", value, style, options);
if (EditorGUI.EndChangeCheck())
{
ToggleApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static bool Toggle(string label, bool value, GUIStyle style,
ToggleChangeHandler change,
ToggleFailureHandler failure = null,
ToggleValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.ToggleLeft(label, value, style, options);
if (EditorGUI.EndChangeCheck())
{
ToggleApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
public static bool Toggle(GUIContent label, bool value, GUIStyle style,
ToggleChangeHandler change,
ToggleFailureHandler failure = null,
ToggleValidationHandler validate = null,
params GUILayoutOption[] options)
{
EditorGUI.BeginChangeCheck();
value = EditorGUILayout.ToggleLeft(label, value, style, options);
if (EditorGUI.EndChangeCheck())
{
ToggleApplyChangeHandlers(value, change, failure, validate);
}
return value;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 43ea6d38276954c8db58acd019e1122c
timeCreated: 1471196349
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,20 @@
using UnityEngine;
using System.Collections;
namespace UnityAnalytics360VideoHeatmap
{
public class HeatmapClipNameList : MonoBehaviour
{
public delegate void ChangeHandler(string[] array);
public static void ListGroup(string[] array, ChangeHandler change)
{
if (array == null)
{
return;
}
change(array);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 07d2af98bf0104a96a2459bc72894088
timeCreated: 1511757496
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,61 @@
/// <summary>
/// Visual component for managing a list of popup lists.
/// </summary>
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace UnityAnalytics360VideoHeatmap
{
public class AnalyticsListGroup
{
public delegate void ChangeHandler(List<int> value);
public static List<int> ListGroup(List<int>value, List<List<string>> lists, ChangeHandler change)
{
////Debug.Log(value.ToString());
////Debug.Log(lists.ToString());
if (lists == null || value == null)
{
return null;
}
EditorGUI.BeginChangeCheck();
if (value.Count > 1)
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("Data Set Options", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
using (new EditorGUILayout.VerticalScope())
{
for (int a = 0; a < value.Count; a++)
{
////Debug.Log(value[a]);
////Debug.Log(lists);
if (lists[a].Contains("Heatmap.PlayerLook"))
{
continue;
}
var listArray = lists[a].ToArray();
value[a] = EditorGUILayout.Popup(value[a], listArray);
}
}
}
}
if (EditorGUI.EndChangeCheck())
{
change(value);
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 20e613089e0a74d51b7f242a94f6b824
timeCreated: 1471377655
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,73 @@
using System;
using UnityEditor;
using UnityEngine;
using System.Linq;
namespace UnityAnalytics360VideoHeatmap
{
public class AnalyticsSmootherControl
{
private static GUIContent[] s_SmootherOptionsContent;
private static Texture2D darkSkinUnionIcon = Resources.Load("unity_analytics_heatmaps_union_dark") as Texture2D;
private static Texture2D darkSkinNumberIcon = Resources.Load("unity_analytics_heatmaps_number_dark") as Texture2D;
private static Texture2D darkSkinNoneIcon = Resources.Load("unity_analytics_heatmaps_none_dark") as Texture2D;
private static Texture2D lightSkinUnionIcon = Resources.Load("unity_analytics_heatmaps_union_light") as Texture2D;
private static Texture2D lightSkinNumberIcon = Resources.Load("unity_analytics_heatmaps_number_light") as Texture2D;
private static Texture2D lightSkinNoneIcon = Resources.Load("unity_analytics_heatmaps_none_light") as Texture2D;
public delegate void ChangeHandler(int toggler, float value);
public static void SmootherControl (int toggler, float value,
string label, string tooltip, ChangeHandler change,
int endIndex = -1)
{
if (s_SmootherOptionsContent == null)
{
var unionIcon = lightSkinUnionIcon;
var smoothIcon = lightSkinNumberIcon;
var noneIcon = lightSkinNoneIcon;
if (EditorGUIUtility.isProSkin)
{
unionIcon = darkSkinUnionIcon;
smoothIcon = darkSkinNumberIcon;
noneIcon = darkSkinNoneIcon;
}
s_SmootherOptionsContent = new GUIContent[] {
new GUIContent(smoothIcon, "Smooth to value"),
new GUIContent(noneIcon, "No smoothing"),
new GUIContent(unionIcon, "Unify all")
};
}
using (new EditorGUILayout.VerticalScope())
{
var options = endIndex == -1 ? s_SmootherOptionsContent :
s_SmootherOptionsContent.Take(endIndex).ToArray();
EditorGUI.BeginChangeCheck();
int oldToggle = toggler;
toggler = GUILayout.Toolbar(toggler, options, GUILayout.MaxWidth(100));
float lw = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 50;
float fw = EditorGUIUtility.fieldWidth;
EditorGUIUtility.fieldWidth = 20;
EditorGUI.BeginDisabledGroup(toggler != HeatmapDataProcessor.SMOOTH_VALUE);
value = EditorGUILayout.FloatField(new GUIContent(label, tooltip), value);
value = Mathf.Max(0, value);
EditorGUI.EndDisabledGroup();
EditorGUIUtility.labelWidth = lw;
EditorGUIUtility.fieldWidth = fw;
if (EditorGUI.EndChangeCheck() || oldToggle != toggler)
{
change(toggler, value);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: fa489924348944ae0a643f341085edd3
timeCreated: 1471231413
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace UnityAnalytics360VideoHeatmap
{
public class AnalyticsTextFieldList
{
private static GUIContent s_AddFieldContent = new GUIContent("+", "Add field");
private static GUILayoutOption s_ButtonWidth = GUILayout.MaxWidth(20f);
public delegate void TextFieldListChangeHandler(List<string> list);
public static List<string> TextFieldList (List<string> m_ArbitraryFields, TextFieldListChangeHandler change)
{
if (m_ArbitraryFields.Count == 0)
{
m_ArbitraryFields.Add("Field name");
}
EditorGUI.BeginChangeCheck();
for (var a = 0; a < m_ArbitraryFields.Count; a++)
{
using (new GUILayout.HorizontalScope())
{
m_ArbitraryFields[a] = EditorGUILayout.TextField(m_ArbitraryFields[a]);
EditorGUI.BeginDisabledGroup(m_ArbitraryFields.Count == 1);
if (GUILayout.Button("-", s_ButtonWidth))
{
m_ArbitraryFields.RemoveAt(a);
break;
}
EditorGUI.EndDisabledGroup();
if (a == m_ArbitraryFields.Count-1 && GUILayout.Button(s_AddFieldContent, s_ButtonWidth))
{
m_ArbitraryFields.Add("Field name");
}
}
}
if (EditorGUI.EndChangeCheck())
{
change(m_ArbitraryFields);
}
return m_ArbitraryFields;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 26d9ebf15fbb74732a06602c84474b51
timeCreated: 1471232169
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,52 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace UnityAnalytics360VideoHeatmap
{
public class FlattenedHeatmapView : EditorWindow
{
RenderTexture _composite;
[MenuItem("Window/Unity Analytics/360 Video Heatmaps/Flattened Heatmap View")]
static void ShowPreviewWindow()
{
EditorWindow.GetWindow(typeof(FlattenedHeatmapView));
}
void OnGUI()
{
if (_composite == null)
{
var go = GameObject.Find("UnityAnalytics__Heatmap");
if (go)
{
var heatmap = go.GetComponent<Hotspots>();
if (heatmap)
{
_composite = heatmap.composite;
}
}
}
float x = 0;
float y = 0;
float w = position.width;
float h = 0;
if (_composite != null)
{
h = _composite.height * w / _composite.width;
EditorGUI.DrawPreviewTexture(new Rect(x, y, w, h), _composite);
}
y += h;
}
void OnInspectorUpdate()
{
Repaint();
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 33a5b2e52e86d4dea9be8bde90e20067
timeCreated: 1513107479
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,372 @@
/// <summary>
/// Heat map renderer inspector.
/// </summary>
/// This code manages the portion of the inspector that
/// controls the Heat Map renderer.
using System;
using System.Collections;
using UnityEditor;
using UnityEngine;
using UnityEngine.Video;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
namespace UnityAnalytics360VideoHeatmap
{
public class HeatmapRendererInspector
{
const string k_Renderer = "UnityAnalyticsHeatmapRenderer";
const string k_StartTimeKey = "UnityAnalyticsHeatmapStartTime";
const string k_EndTimeKey = "UnityAnalyticsHeatmapEndTime";
const string k_PlaySpeedKey = "UnityAnalyticsHeatmapPlaySpeed";
const string k_LowXKey = "UnityAnalyticsHeatmapLowX";
const string k_HighXKey = "UnityAnalyticsHeatmapHighX";
const string k_LowYKey = "UnityAnalyticsHeatmapLowY";
const string k_HighYKey = "UnityAnalyticsHeatmapHighY";
const string k_LowZKey = "UnityAnalyticsHeatmapLowZ";
const string k_HighZKey = "UnityAnalyticsHeatmapHighZ";
const string k_ShowTipsKey = "UnityAnalyticsHeatmapShowRendererTooltips";
const string k_ClipName = "UnityAnalyticsHeatmapClipName";
Heatmapper m_Heatmapper;
int m_MaxTime = -1;
int m_ClipNameIndex = 0;
Rect m_ClipDropdownRect;
int m_QualityIndex = 0;
float m_minRadius = 1.0f;
float m_maxRaidus = 50.0f;
float m_minDecay = 0.0f;
float m_maxDecay = 1.0f;
const int k_NoFollow = 0;
const int k_SceneFollow = 1;
const int k_MainCameraFollow = 2;
GameObject m_GameObject;
VideoRenderer videoRenderer;
Texture2D darkSkinPlayIcon = Resources.Load("unity_analytics_heatmaps_play_dark") as Texture2D;
Texture2D darkSkinPauseIcon = Resources.Load("unity_analytics_heatmaps_pause_dark") as Texture2D;
Texture2D darkSkinRewindIcon = Resources.Load("unity_analytics_heatmaps_rwd_dark") as Texture2D;
Texture2D lightSkinPlayIcon = Resources.Load("unity_analytics_heatmaps_play_light") as Texture2D;
Texture2D lightSkinPauseIcon = Resources.Load("unity_analytics_heatmaps_pause_light") as Texture2D;
Texture2D lightSkinRewindIcon = Resources.Load("unity_analytics_heatmaps_rwd_light") as Texture2D;
GUIContent m_RestartContent;
GUIContent m_PlayContent;
GUIContent m_PauseContent;
GUIContent m_ClipDropdown = new GUIContent("Video Clip", "Select the video clip Name");
GUIContent m_MinRadiusContent = new GUIContent(" Radius");
GUIContent m_DecayRateContent = new GUIContent(" Decay Rate");
GUIContent m_FrameContent = new GUIContent(" Frame");
GUIContent m_FunnelContent = new GUIContent("Funnel", "Display the player progression");
public delegate void FunnelDataChangeHandler(Dictionary<string, HeatPoint[]> points);
public HeatmapRendererInspector()
{
var playIcon = lightSkinPlayIcon;
var pauseIcon = lightSkinPauseIcon;
var rwdIcon = lightSkinRewindIcon;
if (EditorGUIUtility.isProSkin)
{
playIcon = darkSkinPlayIcon;
pauseIcon = darkSkinPauseIcon;
rwdIcon = darkSkinRewindIcon;
}
m_RestartContent = new GUIContent(rwdIcon, "Back to Start");
m_PlayContent = new GUIContent(playIcon, "Play");
m_PauseContent = new GUIContent(pauseIcon, "Pause");
HeatmapViewModel.HeatpointsUpdated += SetLimits;
HeatmapViewModel.FinalFrameUpdated += HeatmapViewModel_FinalFrameUpdated;
}
void HeatmapViewModel_FinalFrameUpdated(int endFrame)
{
m_MaxTime = endFrame;
}
public static HeatmapRendererInspector Init(Heatmapper heatmapper, HeatmapDataProcessor processor)
{
var inspector = new HeatmapRendererInspector();
inspector.m_Heatmapper = heatmapper;
return inspector;
}
int ConvertNormalizedTimeToFrame (float t)
{
if (HeatmapViewModel.videoPlayer != null && HeatmapViewModel.videoPlayer.isPrepared)
return Convert.ToInt32(t * (float)m_MaxTime);
else
return 0;
}
public void OnGUI()
{
if(m_MaxTime == -1)
{
m_MaxTime = HeatmapViewModel.endFrame;
}
using (new GUILayout.VerticalScope())
{
videoRenderer.videoMaterial = EditorGUILayout.ObjectField("Video Material", videoRenderer.videoMaterial, typeof(Material), true) as Material;
var separators = HeatmapViewModel.GetSeparators();
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(m_ClipDropdown, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
m_ClipDropdownRect = EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField("", EditorStyles.boldLabel);
EditorGUILayout.EndVertical();
var clipNameSep = separators["clipName"];
EditorGUI.BeginChangeCheck();
m_ClipNameIndex = EditorGUI.Popup(m_ClipDropdownRect, m_ClipNameIndex, clipNameSep.separatorValues.ToArray());
if (EditorGUI.EndChangeCheck())
{
clipNameSep.selectedValue = clipNameSep.separatorValues[m_ClipNameIndex];
HeatmapViewModel.UpdateSeparator("clipName", clipNameSep);
}
}
EditorGUILayout.LabelField("Render Options", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
var _player = HeatmapViewModel.videoPlayer;
//Disable render options if the videoplayer hasn't been assigned
EditorGUI.BeginDisabledGroup(_player == null);
using (new EditorGUILayout.VerticalScope())
{
if (videoRenderer != null)
{
videoRenderer.minRadius = EditorGUILayout.Slider(m_MinRadiusContent, videoRenderer.minRadius, m_minRadius, m_maxRaidus);
videoRenderer.maxRadius = videoRenderer.minRadius;
videoRenderer.decay = EditorGUILayout.Slider(m_DecayRateContent, videoRenderer.decay, m_minDecay, m_maxDecay);
m_QualityIndex = EditorGUILayout.Popup(" Quality", m_QualityIndex, new string[]{"1X", "2X", "5X"});
if (_player != null)
{
int m_HeatMapWidthBase = (int)_player.clip.width / 5;
int m_HeatMapHeightBase = (int)_player.clip.height / 5;
switch (m_QualityIndex)
{
case 0:
videoRenderer.heatMapWidth = m_HeatMapWidthBase;
videoRenderer.heatMapHeight = m_HeatMapHeightBase;
break; ;
case 1:
videoRenderer.heatMapWidth = m_HeatMapWidthBase * 2;
videoRenderer.heatMapHeight = m_HeatMapHeightBase * 2;
break;
case 2:
videoRenderer.heatMapWidth = m_HeatMapWidthBase * 5;
videoRenderer.heatMapHeight = m_HeatMapHeightBase * 5;
break;
}
}
videoRenderer.numPoints = EditorGUILayout.IntSlider(" Points", videoRenderer.numPoints, 1, 2000);
videoRenderer.gradientSize = EditorGUILayout.IntSlider(" Gradient Fidelity", videoRenderer.gradientSize, 1, 256);
EditorGUI.BeginDisabledGroup(_player != null && _player.isPrepared == false);
if (_player != null)
{
var oldStartTime = ConvertNormalizedTimeToFrame(HeatmapViewModel.heatpointShowStartTime);
var temp = ConvertNormalizedTimeToFrame(HeatmapViewModel.heatpointShowStartTime);
if(_player.isPlaying)
{
EditorGUI.BeginDisabledGroup(true);
temp = EditorGUILayout.IntSlider(m_FrameContent, Convert.ToInt32(_player.frame), 1, m_MaxTime);
EditorGUI.EndDisabledGroup();
}
else
{
temp = EditorGUILayout.IntSlider(m_FrameContent, (int)temp, 1, m_MaxTime);
if (temp != oldStartTime)
{
_player.frame = temp;
}
}
if (temp != oldStartTime)
{
HeatmapViewModel.UpdateHeatpointShowTimes(GetNormalizedTime(temp), GetNormalizedTime(temp + 1));
m_Heatmapper.Repaint();
}
}
EditorGUILayout.Space();
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField("", GUILayout.Width(EditorGUIUtility.labelWidth - 4));
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(m_RestartContent))
{
_player.Pause();
_player.frame = 1;
Restart();
}
GUIContent playButtonContent = _player != null && _player.isPlaying ? m_PauseContent : m_PlayContent;
if (GUILayout.Button(playButtonContent))
{
if (_player.isPlaying)
{
_player.Pause();
}
else
{
_player.Play();
}
}
}
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space();
}
}
EditorGUI.EndDisabledGroup();
DisplayFunnelGui();
}
}
public void SetLimits(Dictionary<string, HeatPoint[]> points)
{
float maxDensity = 0;
foreach (KeyValuePair<string, HeatPoint[]> entry in points)
{
for (int a = 0; a < entry.Value.Length; a++)
{
maxDensity = Mathf.Max(maxDensity, entry.Value[a].density);
}
}
}
float GetNormalizedTime(float frameNum)
{
return frameNum / (float)m_MaxTime;
}
void Restart()
{
HeatmapViewModel.UpdateHeatpointShowTimes(GetNormalizedTime(1), GetNormalizedTime(2));
}
public void SetGameObject(GameObject go)
{
m_GameObject = go;
if (m_GameObject != null)
{
videoRenderer = m_GameObject.GetComponent<VideoRenderer>();
}
}
public void UpdateClipNameDropDown(string[] clipNames)
{
EditorGUI.BeginChangeCheck();
m_ClipNameIndex = EditorGUI.Popup(m_ClipDropdownRect, m_ClipNameIndex, clipNames);
if (EditorGUI.EndChangeCheck())
{
string m_clipName = clipNames[m_ClipNameIndex];
// do something if clip changed
PlayerPrefs.SetString(k_ClipName, m_clipName);
}
}
void DisplayFunnelGui()
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.LabelField(m_FunnelContent, EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
using (new EditorGUILayout.VerticalScope())
{
AnimationCurve m_Curve = CreateFunnel();
EditorGUI.CurveField(EditorGUILayout.GetControlRect(), m_Curve);
var _player = HeatmapViewModel.videoPlayer;
if (_player != null && _player.isPrepared)
{
EditorGUI.BeginDisabledGroup(true);
float _StandardTime = _player.frame / (float)_player.frameCount;
EditorGUILayout.LabelField(string.Format("Total number of players present: {0}", GetPresentPlayer(m_Curve, _StandardTime)), EditorStyles.label);
EditorGUI.EndDisabledGroup();
}
}
}
if (HeatmapViewModel.GetHeatpointToSessionMapping() == null || HeatmapViewModel.GetHeatpointToSessionMapping().Count() == 0)
{
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.HelpBox("There is no data currently to display.", MessageType.Warning);
}
}
AnimationCurve CreateFunnel()
{
AnimationCurve curve = new AnimationCurve();
Dictionary<float, int> _CountTable = new Dictionary<float, int>();
foreach (KeyValuePair<string, HeatPoint[]> kv in HeatmapViewModel.GetHeatpointToSessionMapping())
{
for (int i = 0; i < kv.Value.Length; i++)
{
if (_CountTable.ContainsKey(kv.Value[i].time))
{
_CountTable[kv.Value[i].time] = _CountTable[kv.Value[i].time] + 1;
}
else
{
_CountTable.Add(kv.Value[i].time, 1);
}
}
}
foreach (float m_time in _CountTable.Keys)
{
curve.AddKey(m_time, _CountTable[m_time]);
}
return curve;
}
int GetPresentPlayer(AnimationCurve curve, float time)
{
if (curve.keys.Length == 0)
{
return 0;
}
if (time > 1f || time < 0f)
{
return 0;
}
return (int)curve.Evaluate(time);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 61597699cb653465786a93e272bef2fa
timeCreated: 1438296107
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,173 @@
/// <summary>
/// Heatmapper inspector.
/// </summary>
/// This code drives the Heatmapper inspector
/// The HeatmapDataParser handles loading and parsing the data.
/// The HeatmapRendererInspector speaks to the Renderer to achieve a desired look.
using System.Collections.Generic;
using UnityAnalytics360VideoHeatmap;
using UnityEditor;
using UnityEngine;
using UnityEngine.Video;
using System;
namespace UnityAnalytics360VideoHeatmap
{
public class Heatmapper : EditorWindow
{
[MenuItem("Window/Unity Analytics/360 Video Heatmaps/Heatmapper")]
static void HeatmapperMenuOption()
{
EditorWindow.GetWindow(typeof(Heatmapper));
}
static Texture m_HeatmapperIconTexture;
// Views
AggregationInspector m_AggregationView;
HeatmapRendererInspector m_RenderView;
// Data handler
HeatmapDataProcessor m_Processor;
//ViewModel
HeatmapViewModel viewModel;
GameObject m_HeatMapInstance;
Vector2 m_ScrollPosition;
void OnEnable()
{
EnsureHeatmapInstance();
viewModel = HeatmapViewModel.instance;
m_Processor = new HeatmapDataProcessor();
m_Processor.RestoreSettings();
m_RenderView = HeatmapRendererInspector.Init(this, m_Processor);
m_AggregationView = AggregationInspector.Init(m_Processor);
m_AggregationView.OnEnable();
m_HeatmapperIconTexture = Resources.Load("unity_analytics_heatmaps_heatmapper") as Texture;
viewModel.ManualOverride();
}
void OnFocus()
{
SystemProcess();
}
void OnGUI()
{
if (Event.current.type == EventType.Layout)
{
EnsureHeatmapInstance();
}
// Guistyle
GUIStyle m_boxStyle = new GUIStyle("box");
m_boxStyle.padding = new RectOffset(6, 6, 8, 8);
EditorGUILayout.Space();
EditorGUILayout.LabelField(new GUIContent(" 360 Video Heatmapper", m_HeatmapperIconTexture), EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope(m_boxStyle))
{
using (var scroll = new EditorGUILayout.ScrollViewScope(m_ScrollPosition))
{
m_ScrollPosition = scroll.scrollPosition;
using (new EditorGUILayout.VerticalScope())
{
m_AggregationView.OnGUI();
}
using (new EditorGUILayout.HorizontalScope())
{
//TODO: Clean up
EditorGUILayout.LabelField("Video Player", EditorStyles.boldLabel, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
var temp = EditorGUILayout.ObjectField(HeatmapViewModel.videoPlayer, typeof(VideoPlayer), allowSceneObjects: true) as VideoPlayer;
if(temp != null)
HeatmapViewModel.videoPlayer = temp;
}
using (new EditorGUILayout.VerticalScope())
{
if (m_RenderView != null)
{
m_RenderView.OnGUI();
}
}
}
}
}
void Update()
{
Repaint();
}
void SystemProcess()
{
EnsureHeatmapInstance();
}
public void SwapRenderer(Type renderer)
{
AttemptReconnectWithHeatmapInstance();
CreateHeatmapInstance(renderer);
}
void EnsureHeatmapInstance()
{
AttemptReconnectWithHeatmapInstance();
if (m_HeatMapInstance == null)
{
CreateHeatmapInstance();
}
if (m_RenderView != null)
{
m_RenderView.SetGameObject(m_HeatMapInstance);
}
}
/// <summary>
/// Attempts to reconnect with a heatmap instance.
/// </summary>
void AttemptReconnectWithHeatmapInstance()
{
m_HeatMapInstance = GameObject.Find("UnityAnalytics__Heatmap");
}
/// <summary>
/// Creates the heat map instance.
/// </summary>
void CreateHeatmapInstance(bool force = false)
{
if (force)
{
DestroyHeatmapInstance();
}
CreateHeatmapInstance(typeof(VideoRenderer));
}
void CreateHeatmapInstance(Type t)
{
DestroyHeatmapInstance();
m_HeatMapInstance = new GameObject();
m_HeatMapInstance.tag = "EditorOnly";
m_HeatMapInstance.name = "UnityAnalytics__Heatmap";
m_HeatMapInstance.AddComponent(t);
m_HeatMapInstance.GetComponent<IHeatmapRenderer>().allowRender = true;
}
void DestroyHeatmapInstance()
{
if (m_HeatMapInstance)
{
m_HeatMapInstance.transform.parent = null;
DestroyImmediate(m_HeatMapInstance);
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 37d29778284e24f8186804b8cfa2a858
timeCreated: 1437429523
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 4923726aa9e5a4d07a43247389e81ebc
folderAsset: yes
timeCreated: 1509999757
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,688 @@

using System;
using UnityEngine;
using UnityEditor;
using UnityAnalytics360VideoHeatmap;
using System.Collections.Generic;
using System.Collections;
using UnityAnalytics;
using System.Linq;
using System.Net;
namespace UnityAnalytics360VideoHeatmap
{
public class RawDataInspector : EditorWindow
{
private static string k_FetchKey = "UnityAnalyticsRawDataGenFetchKey";
private static string k_Installed = "UnityAnalyticsRawDataGenInstallKey";
private static string k_StartDate = "UnityAnalyticsRawDataStartDateKey";
private static string k_EndDate = "UnityAnalyticsRawDataEndDateKey";
private static string k_DataPathKey = "UnityAnalyticsRawDataGenDataPath";
private static string k_DeviceCountKey = "UnityAnalyticsRawDataGenDeviceCount";
private static string k_SessionCountKey = "UnityAnalyticsRawDataGenSessionCount";
private static string k_EventNamesKey = "UnityAnalyticsRawDataGenEventNames";
private static string k_CustomEventsKey = "UnityAnalyticsRawDataGenCustomEvents";
private static string k_EventCountKey = "UnityAnalyticsRawDataGenEventCount";
private static string k_IncludeTimeKey = "UnityAnalyticsRawDataGenIncludeTime";
private static string k_IncludeLevelKey = "UnityAnalyticsRawDataGenIncludeLevel";
private static string k_MinLevel = "UnityAnalyticsRawDataGenMinLevel";
private static string k_MaxLevel = "UnityAnalyticsRawDataGenMaxLevel";
private static string k_IncludeFPSKey = "UnityAnalyticsRawDataGenIncludeFPS";
private static string k_MinFPS = "UnityAnalyticsRawDataGenMinFPS";
private static string k_MaxFPS = "UnityAnalyticsRawDataGenMaxFPS";
private static string k_IncludeXKey = "UnityAnalyticsRawDataGenIncludeX";
private static string k_MinX = "UnityAnalyticsRawDataGenMinX";
private static string k_MaxX = "UnityAnalyticsRawDataGenMaxX";
private static string k_IncludeYKey = "UnityAnalyticsRawDataGenIncludeY";
private static string k_MinY = "UnityAnalyticsRawDataGenMinY";
private static string k_MaxY = "UnityAnalyticsRawDataGenMaxY";
private static string k_IncludeZKey = "UnityAnalyticsRawDataGenIncludeZ";
private static string k_MinZ = "UnityAnalyticsRawDataGenMinZ";
private static string k_MaxZ = "UnityAnalyticsRawDataGenMaxZ";
private static string k_RotationKey = "UnityAnalyticsRawDataGenRotation";
private static string k_MinRX = "UnityAnalyticsRawDataGenMinRX";
private static string k_MaxRX = "UnityAnalyticsRawDataGenMaxRX";
private static string k_MinRY = "UnityAnalyticsRawDataGenMinRY";
private static string k_MaxRY = "UnityAnalyticsRawDataGenMaxRY";
private static string k_MinRZ = "UnityAnalyticsRawDataGenMinRZ";
private static string k_MaxRZ = "UnityAnalyticsRawDataGenMaxRZ";
private static string k_MinDX = "UnityAnalyticsRawDataGenMinDX";
private static string k_MaxDX = "UnityAnalyticsRawDataGenMaxDX";
private static string k_MinDY = "UnityAnalyticsRawDataGenMinDY";
private static string k_MaxDY = "UnityAnalyticsRawDataGenMaxDY";
private static string k_MinDZ = "UnityAnalyticsRawDataGenMinDZ";
private static string k_MaxDZ = "UnityAnalyticsRawDataGenMaxDZ";
private static Color s_BoxColor = new Color(.9f, .9f, .9f);
private GUIContent m_AddEventContent = new GUIContent("+ Event Name", "Events to be randomly added into the created data.");
private GUIContent m_UpidContent = new GUIContent("UPID", "Copy the Unity Project ID from Services > Settings or the 'Editing Project' page of your project dashboard");
private GUIContent m_SecretKeyContent = new GUIContent("API Key", "Copy the key from the 'Editing Project' page of your project dashboard");
private GUIContent m_StartDateContent = new GUIContent("Start Date (YYYY-MM-DD)", "Start date as ISO-8601 datetime");
private GUIContent m_EndDateContent = new GUIContent("End Date (YYYY-MM-DD)", "End date as ISO-8601 datetime");
private GUIContent m_ContinueJobContent = new GUIContent(">", "Continue job");
private GUIContent m_DownloadJobContent = new GUIContent("Download", "Download job files");
private GUIContent m_GetJobsContent = new GUIContent("Get Jobs", "Load the manifest of job files");
private GUIContent m_DownloadAllContent = new GUIContent("Download All", "Download the files for all jobs");
private GUIContent m_FailedContent;
private GUIContent m_CompleteContent;
private GUIContent m_RunningContent;
private static int defaultEventCount = 100;
private static int defaultDeviceCount = 5;
private static int defaultSessionCount = 10;
private static float defaultMinAngle = 0f;
private static float defaultMaxAngle = 360f;
private static float defaultMinSpace = -100f;
private static float defaultMaxSpace = 100f;
private static int defaultRotational = 0;
private static int defaultMinLevel = 1;
private static int defaultMaxLevel = 99;
private static float defaultMinFPS = 1f;
private static float defaultMaxFPS = 99f;
public const string headers = "ts\tappid\ttype\tuserid\tsessionid\tremote_ip\tplatform\tsdk_ver\tdebug_device\tuser_agent\tsubmit_time\tname\tcustom_params\n";
[MenuItem("Window/Unity Analytics/360 Video Heatmaps/Raw Data")]
static void RawDataInspectorMenuOption()
{
EditorWindow.GetWindow(typeof(RawDataInspector));
}
string m_DataPath = "";
bool m_ValidManifest = false;
int m_EventCount = defaultEventCount;
int m_DeviceCount = defaultDeviceCount;
int m_SessionCount = defaultSessionCount;
string m_AppId = "";
string m_SecretKey = "";
string m_StartDate = "";
string m_EndDate = "";
List<RawDataReport> m_Jobs = null;
bool[] m_JobFoldouts;
int m_DataSource = 0;
static int FETCH = 0;
List<string> m_EventNames = new List<string> { };
bool m_IncludeTime = true;
bool m_IncludeX = true;
float m_MinX = defaultMinSpace;
float m_MaxX = defaultMaxSpace;
bool m_IncludeY = true;
float m_MinY = defaultMinSpace;
float m_MaxY = defaultMaxSpace;
bool m_IncludeZ = true;
float m_MinZ = defaultMinSpace;
float m_MaxZ = defaultMaxSpace;
// Flag for rotation vs destination
int m_Rotational = defaultRotational;
float m_MinRX = defaultMinAngle;
float m_MaxRX = defaultMaxAngle;
float m_MinRY = defaultMinAngle;
float m_MaxRY = defaultMaxAngle;
float m_MinRZ = defaultMinAngle;
float m_MaxRZ = defaultMaxAngle;
float m_MinDX = defaultMinSpace;
float m_MaxDX = defaultMaxSpace;
float m_MinDY = defaultMinSpace;
float m_MaxDY = defaultMaxSpace;
float m_MinDZ = defaultMinSpace;
float m_MaxDZ = defaultMaxSpace;
bool m_IncludeLevel = false;
int m_MinLevel = defaultMinLevel;
int m_MaxLevel = defaultMaxLevel;
bool m_IncludeFPS = false;
float m_MinFPS = defaultMinFPS;
float m_MaxFPS = defaultMaxFPS;
Vector2 m_ScrollPosition;
RawDataClient m_RawDataClient;
void OnEnable()
{
if (m_RawDataClient == null)
{
Texture2D failedIcon = Resources.Load("unity_analytics_heatmaps_failed") as Texture2D;
Texture2D completeIcon = Resources.Load("unity_analytics_heatmaps_success") as Texture2D;
Texture2D runningIcon = Resources.Load("unity_analytics_heatmaps_running") as Texture2D;
m_RawDataClient = RawDataClient.GetInstance();
if (m_DataSource == FETCH && !m_ValidManifest)
{
m_RawDataClient.GetJobs(GetJobsCompletionHandler);
m_ValidManifest = true;
}
titleContent = new GUIContent("Raw Data");
m_FailedContent = new GUIContent(failedIcon, "Status: Failed");
m_CompleteContent = new GUIContent(completeIcon, "Status: Completed");
m_RunningContent = new GUIContent(runningIcon, "Status: Running");
return;
}
}
void OnFocus()
{
if (EditorPrefs.GetBool(k_Installed))
{
RestoreValues();
}
else
{
SetInitValues();
}
}
void OnGUI()
{
EditorPrefs.SetString(k_DataPathKey, m_DataPath);
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button("Reset"))
{
if (EditorUtility.DisplayDialog("Resetting to factory defaults", "Are you sure?", "Reset", "Cancel"))
{
SetInitValues();
}
}
if (GUILayout.Button("Open Folder"))
{
EditorUtility.RevealInFinder(m_DataPath + "/RawDataFolder");
}
}
//output path
m_DataPath = Application.dataPath;
using (new GUILayout.VerticalScope("box"))
{
EditorGUILayout.LabelField("Output path", EditorStyles.boldLabel);
EditorGUILayout.SelectableLabel(m_DataPath + "/RawDataFolder");
}
if (m_DataSource == FETCH)
{
OnGUIFetchView();
}
}
void OnGUIFetchView()
{
if (Event.current.type == EventType.Layout)
{
m_RawDataClient.TestFilesAreLocal(m_Jobs);
}
using (new GUILayout.VerticalScope("box"))
{
string oldKey = m_SecretKey;
m_AppId = EditorGUILayout.TextField(m_UpidContent, m_AppId);
RestoreAppId();
m_SecretKey = EditorGUILayout.TextField(m_SecretKeyContent, m_SecretKey);
m_RawDataClient.m_DataPath = m_DataPath;
m_RawDataClient.m_AppId = m_AppId;
m_RawDataClient.m_SecretKey = m_SecretKey;
if (oldKey != m_SecretKey && !string.IsNullOrEmpty(m_SecretKey))
{
EditorPrefs.SetString(k_FetchKey, m_SecretKey);
}
}
using (new GUILayout.VerticalScope("box"))
{
GUILayout.Label("New Job", EditorStyles.boldLabel);
var oldStartDate = m_StartDate;
var oldEndDate = m_EndDate;
m_StartDate = EditorGUILayout.TextField(m_StartDateContent, m_StartDate);
m_EndDate = EditorGUILayout.TextField(m_EndDateContent, m_EndDate);
if (oldStartDate != m_StartDate || oldEndDate != m_EndDate)
{
EditorPrefs.SetString(k_StartDate, m_StartDate);
EditorPrefs.SetString(k_EndDate, m_EndDate);
}
if (GUILayout.Button("Create Job"))
{
RawDataReport report = null;
try
{
DateTime startDate = DateTime.Parse(m_StartDate).ToUniversalTime();
DateTime endDate = DateTime.Parse(m_EndDate).ToUniversalTime();
report = m_RawDataClient.CreateJob("custom", startDate, endDate);
}
catch (Exception ex)
{
string exText = "Unknown exception.";
if (ex is FormatException)
{
exText = "Date formats appear to be incorrect. Start and End Dates must be ISO-8601 format (YYYY-MM-DD).";
}
else if (ex is WebException)
{
WebException webEx = ex as WebException;
exText = webEx.Message;
}
EditorUtility.DisplayDialog("Can't create job", exText, "OK");
}
if (m_Jobs == null)
{
m_Jobs = new List<RawDataReport>();
}
if (report != null)
{
m_Jobs.Add(report);
}
m_JobFoldouts = m_Jobs.Select(fb => false).ToArray();
}
}
using (new GUILayout.VerticalScope("box"))
{
using (new EditorGUILayout.HorizontalScope())
{
if (GUILayout.Button(m_GetJobsContent))
{
m_RawDataClient.GetJobs(GetJobsCompletionHandler);
}
if (GUILayout.Button(m_DownloadAllContent))
{
m_RawDataClient.DownloadAll(m_Jobs);
}
}
m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
if (m_Jobs != null)
{
for (int a = m_Jobs.Count - 1; a > -1; a--)
{
var job = m_Jobs[a];
string start = String.Format("{0:yyyy-MM-dd}", job.request.startDate);
string end = String.Format("{0:yyyy-MM-dd}", job.request.endDate);
string shortStart = String.Format("{0:MM-dd}", job.request.startDate);
string shortEnd = String.Format("{0:MM-dd}", job.request.endDate);
string created = String.Format("{0:yyyy-MM-dd hh:mm:ss}", job.createdAt);
string type = job.request.dataset;
using (new EditorGUILayout.HorizontalScope())
{
float windowWidth = EditorGUIUtility.currentViewWidth;
float foldoutWidth = windowWidth * .5f;
float downloadButtonWidth = 75f;
float continueButtonWidth = 25f;
float downloadedWidth = downloadButtonWidth;
float statusWidth = 20f;
GUIContent foldoutContent = new GUIContent(type + ": " + shortStart + " to " + shortEnd, start + " — " + end + "\n" + job.id);
Rect pos = GUILayoutUtility.GetRect(foldoutContent, "foldout");
Rect rect = new Rect(pos.x, pos.y, foldoutWidth, 20f);
m_JobFoldouts[a] = EditorGUI.Foldout(
rect,
m_JobFoldouts[a],
foldoutContent,
true
);
var statusContent = m_CompleteContent;
switch (job.status)
{
case RawDataReport.Failed:
statusContent = m_FailedContent;
break;
case RawDataReport.Running:
statusContent = m_RunningContent;
break;
}
GUILayout.Label(statusContent, GUILayout.Width(statusWidth));
if (job.status == RawDataReport.Completed)
{
if (job.isLocal)
{
GUILayout.Label("Downloaded", GUILayout.Width(downloadedWidth));
}
else if (job.result != null && job.result.size == 0)
{
GUILayout.Label("No Data", GUILayout.Width(downloadedWidth));
}
else if (GUILayout.Button(m_DownloadJobContent, GUILayout.Width(downloadButtonWidth)))
{
m_RawDataClient.Download(job);
}
if (GUILayout.Button(m_ContinueJobContent, GUILayout.Width(continueButtonWidth)))
{
RawDataReport report = m_RawDataClient.ContinueFromJob(job);
m_Jobs.Add(report);
m_JobFoldouts = m_Jobs.Select(fb => false).ToArray();
}
}
}
if (m_JobFoldouts[a])
{
Color defaultColor = GUI.color;
GUI.backgroundColor = s_BoxColor;
using (new GUILayout.VerticalScope("box"))
{
GUILayout.Label("ID: " + job.id);
GUILayout.Label("Created: " + created);
GUILayout.Label("Duration: " + (job.duration / 1000) + " seconds");
if (job.result != null)
{
GUILayout.Label("# Events: " + job.result.eventCount);
GUILayout.Label("# Bytes: " + job.result.size);
GUILayout.Label("# Files: " + job.result.fileList.Count);
GUILayout.Label("Partial day: " + job.result.intraDay);
}
}
GUI.backgroundColor = defaultColor;
}
}
if (m_Jobs.Count == 0)
{
GUILayout.Label("No jobs found", EditorStyles.boldLabel);
}
}
else
{
GUILayout.Label("No data yet", EditorStyles.boldLabel);
}
GUILayout.Space(10f);
EditorGUILayout.EndScrollView();
}
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("Purge"))
{
PurgeData();
}
if (GUILayout.Button("Dashboard"))
{
Application.OpenURL(m_RawDataClient.DashboardPath);
}
if (GUILayout.Button("Project Config"))
{
Application.OpenURL(m_RawDataClient.ConfigPath);
}
}
}
private void GetJobsCompletionHandler(bool success, List<RawDataReport> list, string reason = "")
{
m_Jobs = list;
m_JobFoldouts = m_Jobs.Select(fb => false).ToArray();
}
void CreateHeadersFile()
{
SaveFile(headers, "custom_headers.gz", true);
}
void CreateManifestFile(List<RawDataReport> list)
{
var manifest = m_RawDataClient.GenerateManifest(list);
SaveFile(manifest, "manifest.json", false);
}
bool IncludeSet(ref bool value, string label, string key, bool force = false)
{
string tooltip = force ? label + " must be included" : null;
var content = new GUIContent(label, tooltip);
EditorGUI.BeginDisabledGroup(force);
value = EditorGUILayout.Toggle(content, value);
EditorGUI.EndDisabledGroup();
EditorPrefs.SetBool(key, value);
return value;
}
void DrawFloatRange(ref float min, ref float max, string minKey, string maxKey)
{
float oldMin = min;
min = EditorGUILayout.FloatField(min);
if (oldMin != min)
{
EditorPrefs.SetFloat(minKey, min);
}
float oldMax = max;
max = EditorGUILayout.FloatField(max);
if (oldMax != max)
{
EditorPrefs.SetFloat(maxKey, max);
}
}
void DrawIntRange(ref int min, ref int max, string minKey, string maxKey)
{
int oldMin = min;
min = EditorGUILayout.IntField(min);
if (oldMin != min)
{
EditorPrefs.SetInt(minKey, min);
}
int oldMax = max;
max = EditorGUILayout.IntField(max);
if (oldMax != max)
{
EditorPrefs.SetInt(maxKey, max);
}
}
int SaveCustomFile(string data, double firstDate)
{
return SaveFile(data, firstDate + "_custom.gz", true);
}
int SaveFile(string data, string fileName, bool compress)
{
string savePath = System.IO.Path.Combine(GetSavePath(), "RawDataFolder");
// Create the save path if necessary
if (!System.IO.Directory.Exists(savePath))
{
System.IO.Directory.CreateDirectory(savePath);
}
string outputFileName = fileName;
string path = System.IO.Path.Combine(savePath, outputFileName);
int size = 0;
if (compress)
{
IonicGZip.CompressAndSave(path, data);
}
else
{
using (System.IO.StreamWriter file =
new System.IO.StreamWriter(path))
{
file.Write(data);
}
}
System.IO.FileInfo fileInfo = new System.IO.FileInfo(path);
size = (int)fileInfo.Length;
return size;
}
string GetSavePath()
{
return m_DataPath;
}
public void PurgeData()
{
if (EditorUtility.DisplayDialog("Destroy local data?", "You are about to delete your local heatmaps data cache, meaning you'll have to reload from the server (or regenerate from this tool). Are you sure?", "Purge", "Cancel"))
{
string savePath = System.IO.Path.Combine(GetSavePath(), "RawDataFolder");
if (System.IO.Directory.Exists(savePath))
{
System.IO.Directory.Delete(savePath, true);
}
}
}
protected void SetInitValues()
{
m_DataPath = "";
m_IncludeTime = true;
m_IncludeX = m_IncludeY = m_IncludeZ = true;
m_IncludeLevel = m_IncludeFPS = false;
m_Rotational = defaultRotational;
m_MinX = m_MinY = m_MinZ = m_MinDX = m_MinDY = m_MinDZ = defaultMinSpace;
m_MaxX = m_MaxY = m_MaxZ = defaultMaxSpace;
m_MinRX = m_MinRY = m_MinRZ = defaultMinAngle;
m_MaxRX = m_MaxRY = m_MaxRZ = defaultMaxAngle;
m_MinLevel = defaultMinLevel;
m_MaxLevel = defaultMaxLevel;
m_MinFPS = defaultMinFPS;
m_MaxFPS = defaultMaxFPS;
string[] eventsList = new string[] { "PlayerPosition" };
m_EventNames = new List<string>(eventsList);
EditorPrefs.SetFloat(k_MinX, m_MinX);
EditorPrefs.SetFloat(k_MinY, m_MinY);
EditorPrefs.SetFloat(k_MinZ, m_MinZ);
EditorPrefs.SetFloat(k_MinDX, m_MinDX);
EditorPrefs.SetFloat(k_MinDY, m_MinDY);
EditorPrefs.SetFloat(k_MinDZ, m_MinDZ);
EditorPrefs.SetFloat(k_MaxX, m_MaxX);
EditorPrefs.SetFloat(k_MaxY, m_MaxY);
EditorPrefs.SetFloat(k_MaxZ, m_MaxZ);
EditorPrefs.SetFloat(k_MaxDX, m_MaxDX);
EditorPrefs.SetFloat(k_MaxDY, m_MaxDY);
EditorPrefs.SetFloat(k_MaxDZ, m_MaxDZ);
EditorPrefs.SetFloat(k_MinRX, m_MinRX);
EditorPrefs.SetFloat(k_MinRY, m_MinRY);
EditorPrefs.SetFloat(k_MinRZ, m_MinRZ);
EditorPrefs.SetFloat(k_MaxRX, m_MaxRX);
EditorPrefs.SetFloat(k_MaxRY, m_MaxRY);
EditorPrefs.SetFloat(k_MaxRZ, m_MaxRZ);
EditorPrefs.SetInt(k_MinLevel, m_MinLevel);
EditorPrefs.SetInt(k_MaxLevel, m_MaxLevel);
EditorPrefs.SetFloat(k_MinFPS, m_MinFPS);
EditorPrefs.SetFloat(k_MaxFPS, m_MaxFPS);
EditorPrefs.SetString(k_EventNamesKey, eventsList[0]);
EditorPrefs.SetString(k_CustomEventsKey, eventsList[0]);
EditorPrefs.SetInt(k_DeviceCountKey, m_DeviceCount);
EditorPrefs.SetInt(k_SessionCountKey, m_SessionCount);
EditorPrefs.SetBool(k_Installed, true);
}
protected void RestoreAppId()
{
if (string.IsNullOrEmpty(m_AppId) && !string.IsNullOrEmpty(Application.cloudProjectId))
{
m_AppId = Application.cloudProjectId;
}
}
protected void RestoreValues()
{
RestoreAppId();
m_SecretKey = EditorPrefs.GetString(k_FetchKey, m_SecretKey);
m_StartDate = EditorPrefs.GetString(k_StartDate, m_StartDate);
m_EndDate = EditorPrefs.GetString(k_EndDate, m_EndDate);
m_IncludeTime = EditorPrefs.GetBool(k_IncludeTimeKey, m_IncludeTime);
m_IncludeX = EditorPrefs.GetBool(k_IncludeXKey, m_IncludeX);
m_MinX = EditorPrefs.GetFloat(k_MinX, m_MinX);
m_MaxX = EditorPrefs.GetFloat(k_MaxX, m_MaxX);
m_IncludeY = EditorPrefs.GetBool(k_IncludeYKey, m_IncludeY);
m_MinY = EditorPrefs.GetFloat(k_MinY, m_MinY);
m_MaxY = EditorPrefs.GetFloat(k_MaxY, m_MaxY);
m_IncludeZ = EditorPrefs.GetBool(k_IncludeZKey, m_IncludeZ);
m_MinZ = EditorPrefs.GetFloat(k_MinZ, m_MinZ);
m_MaxZ = EditorPrefs.GetFloat(k_MaxZ, m_MaxZ);
m_Rotational = EditorPrefs.GetInt(k_RotationKey, m_Rotational);
m_MinRX = EditorPrefs.GetFloat(k_MinRX, m_MinRX);
m_MaxRX = EditorPrefs.GetFloat(k_MaxRX, m_MaxRX);
m_MinRY = EditorPrefs.GetFloat(k_MinRY, m_MinRY);
m_MaxRY = EditorPrefs.GetFloat(k_MaxRY, m_MaxRY);
m_MinRZ = EditorPrefs.GetFloat(k_MinRZ, m_MinRZ);
m_MaxRZ = EditorPrefs.GetFloat(k_MaxRZ, m_MaxRZ);
m_MinDX = EditorPrefs.GetFloat(k_MinDX, m_MinDX);
m_MaxDX = EditorPrefs.GetFloat(k_MaxDX, m_MaxDX);
m_MinDY = EditorPrefs.GetFloat(k_MinDY, m_MinDY);
m_MaxDY = EditorPrefs.GetFloat(k_MaxDY, m_MaxDY);
m_MinDZ = EditorPrefs.GetFloat(k_MinDZ, m_MinDZ);
m_MaxDZ = EditorPrefs.GetFloat(k_MaxDZ, m_MaxDZ);
m_IncludeLevel = EditorPrefs.GetBool(k_IncludeLevelKey, m_IncludeLevel);
m_MinLevel = EditorPrefs.GetInt(k_MinLevel, m_MinLevel);
m_MaxLevel = EditorPrefs.GetInt(k_MaxLevel, m_MaxLevel);
m_IncludeFPS = EditorPrefs.GetBool(k_IncludeFPSKey, m_IncludeFPS);
m_MinFPS = EditorPrefs.GetFloat(k_MinFPS, m_MinFPS);
m_MaxFPS = EditorPrefs.GetFloat(k_MaxFPS, m_MaxFPS);
m_EventCount = EditorPrefs.GetInt(k_EventCountKey, m_EventCount);
string loadedEventNames = EditorPrefs.GetString(k_EventNamesKey);
string[] eventNamesList;
if (string.IsNullOrEmpty(loadedEventNames))
{
eventNamesList = new string[] { };
}
else
{
eventNamesList = loadedEventNames.Split('|');
}
m_EventNames = new List<string>(eventNamesList);
}
void ViewEventNames()
{
string oldEventsString = string.Join("|", m_EventNames.ToArray());
if (GUILayout.Button(m_AddEventContent))
{
m_EventNames.Add("Event name");
}
for (var a = 0; a < m_EventNames.Count; a++)
{
using (new GUILayout.HorizontalScope())
{
if (GUILayout.Button("-", GUILayout.MaxWidth(20f)))
{
m_EventNames.RemoveAt(a);
break;
}
m_EventNames[a] = EditorGUILayout.TextField(m_EventNames[a]);
}
}
string currentEventsString = string.Join("|", m_EventNames.ToArray());
if (oldEventsString != currentEventsString)
{
EditorPrefs.SetString(k_EventNamesKey, currentEventsString);
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: d0c2ffc68c6f4488a8b8e328a9049f83
timeCreated: 1461961853
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6ee84e478a26b43ed897ed7b69c9b6ff
folderAsset: yes
timeCreated: 1437429523
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 539cd1dc7f3cb4859928b76482359a8f
folderAsset: yes
timeCreated: 1509999950
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,78 @@
using System;
using UnityEngine;
using System.IO;
using System.Text;
using Ionic.Zlib;
using System.Collections.Generic;
public class IonicGZip
{
public static string[] DecompressFiles(string[] args)
{
var results = new List<string>();
foreach(var fileName in args)
{
string response = DecompressFile(fileName);
results.Add(response);
}
return results.ToArray();
}
public static string DecompressFile(string fileName)
{
byte[] file = File.ReadAllBytes(fileName);
byte[] decompressed = Decompress(file);
return Encoding.UTF8.GetString(decompressed);
}
static byte[] Decompress(byte[] gzip)
{
// Create a GZIP stream with decompression mode.
// ... Then create a buffer and write into while reading from the GZIP stream.
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
{
const int size = 4096;
byte[] buffer = new byte[size];
using (MemoryStream memory = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, size);
if (count > 0)
{
memory.Write(buffer, 0, count);
}
}
while (count > 0);
return memory.ToArray();
}
}
}
public static void CompressAndSave(string savePath, string data)
{
// Write string to temporary file.
string temp = Path.GetTempFileName();
File.WriteAllText(temp, data);
// Read file into byte array buffer.
byte[] b;
using (FileStream f = new FileStream(temp, FileMode.Open))
{
b = new byte[f.Length];
f.Read(b, 0, (int)f.Length);
}
// Use GZipStream to write compressed bytes to target file.
using (FileStream f2 = new FileStream(savePath, FileMode.Create))
{
using (GZipStream gz = new GZipStream(f2, CompressionMode.Compress, false))
{
gz.Write(b, 0, b.Length);
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: f7fd47e454afe48218b7d4e1e5e221d3
timeCreated: 1464048959
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c5c608afd7add48c88e7fdc16c3a391e
folderAsset: yes
timeCreated: 1437429523
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 563986ea2eed04fdcb7b9b2fa6556ea3
folderAsset: yes
timeCreated: 1512760550
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,225 @@
/// <summary>
/// Adapter API for sending Heatmap analytics events
/// </summary>
/// This is <i>simply</i> an adapter. As such, you could choose not to
/// use it at all, but by passing your events through this API you gain type
/// safety and ensure that you're conforming to the data that the aggregator
/// and Heatmapper expect to receive.
///
/// The script is designed to work in Unity 4.6 > 5.x
using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using analyticsResultNamespace = UnityEngine.Analytics;
using analyticsEventNamespace = UnityEngine.Analytics.Analytics;
namespace UnityAnalytics360VideoHeatmap
{
public class HeatmapEvent
{
private static Dictionary<string, object> s_Dictionary = new Dictionary<string, object>();
private static bool s_SaveToLocal = false;
private static string s_LocalSavePath;
private static string s_SessionId;
/// <summary>
/// When set to true, HeatmapEvents are saved to a local file, instead of sent to the server.
/// </summary>
/// <param name="value">If set to <c>true</c> save to a local file.</param>
public static bool saveToLocal
{
get
{
return s_SaveToLocal;
}
set
{
s_SaveToLocal = value;
}
}
/// <summary>
/// Sets the local save path.
/// </summary>
/// <value>The path on the local drive where HeatmapEvents will be saved.</param>
public static string localSavePath
{
get
{
return s_LocalSavePath;
}
set
{
s_LocalSavePath = value;
}
}
/// <summary>
/// Send the event with position, rotation, time and an optional dictionary.
/// </summary>
public static analyticsResultNamespace.AnalyticsResult Send(string eventName, Transform trans, float time, Dictionary<string, object> options = null)
{
AddXY(trans.position.x, trans.position.y);
AddZ(trans.position.z);
AddRotation(trans.forward);
AddTime(time);
AddOptions(options);
return Commit(eventName);
}
/// <summary>
/// Transmit the event
/// </summary>
protected static analyticsResultNamespace.AnalyticsResult Commit(string eventName)
{
analyticsResultNamespace.AnalyticsResult result;
if (s_SaveToLocal)
{
string path = String.IsNullOrEmpty(s_LocalSavePath) ? System.IO.Path.Combine(Application.dataPath, "RawDataFolder") : s_LocalSavePath;
result = analyticsResultNamespace.AnalyticsResult.Ok;
using (var writer = new StreamWriter(path, true))
{
s_SessionId = (String.IsNullOrEmpty(s_SessionId)) ? System.Guid.NewGuid().ToString() : s_SessionId;
////Debug.Log(s_Dictionary.ContainsKey("x"));
string evt = WriteEvent("Heatmap." + eventName, s_Dictionary, "TestDevice-3", s_SessionId, Application.platform.ToString(), Debug.isDebugBuild);
writer.WriteLine(evt);
}
}
else
{
result = analyticsEventNamespace.CustomEvent("Heatmap." + eventName, s_Dictionary);
}
s_Dictionary.Clear();
return result;
}
/// <summary>
/// Convenience method for adding X/Y to dict
/// </summary>
protected static void AddXY(float x, float y)
{
////Debug.Log("x = " + x + " y = " + y);
s_Dictionary["x"] = x;
s_Dictionary["y"] = y;
}
/// <summary>
/// Convenience method for adding Z to dict
/// </summary>
protected static void AddZ(float z)
{
s_Dictionary["z"] = z;
}
/// <summary>
/// Convenience method for adding time to dict
/// </summary>
protected static void AddTime(float time)
{
s_Dictionary["t"] = time;
}
/// <summary>
/// Convenience method for adding rotation
/// </summary>
protected static void AddRotation(Vector3 r)
{
s_Dictionary["rx"] = r.x;
s_Dictionary["ry"] = r.y;
s_Dictionary["rz"] = r.z;
}
protected static void AddDestination(Vector3 v)
{
s_Dictionary["dx"] = v.x;
s_Dictionary["dy"] = v.y;
s_Dictionary["dz"] = v.z;
}
/// <summary>
/// Convenience method for adding options to dict
/// </summary>
protected static void AddOptions(Dictionary<string, object> options)
{
if (options != null)
{
foreach (KeyValuePair<string, object> entry in options)
{
s_Dictionary[entry.Key] = entry.Value;
}
}
}
public static string WriteEvent(string eventName, Dictionary<string, object> parameters, string deviceId, string sessionId, string platform, bool isDebug = false)
{
double currentMilliseconds = Math.Floor((DateTime.UtcNow - UnityAnalytics.DateTimeUtils.s_Epoch).TotalMilliseconds);
string evt = "";
evt += currentMilliseconds + "\t";
// AppID
#if UNITY_5
evt += (string.IsNullOrEmpty(Application.cloudProjectId)) ? "1234-abcd-5678-efgh" : Application.cloudProjectId;
#else
evt += "1234-abcd-5678-efgh";
#endif
evt += "\t";
// Event Type
evt += "custom\t";
// User ID, Session ID
evt += deviceId + "\t";
evt += sessionId + "\t";
// Remote IP
evt += "1.1.1.1\t";
// Platform
evt += platform + "\t";
// SDK Version
evt += "5.6,3f1\t";
// IsDebug
evt += isDebug + "\t";
// User agent
evt += "Corridor%20Z/3 CFNetwork/758.2.8 Darwin/15.0.0\t";
// Submit time
evt += currentMilliseconds + "\t";
// Event Name
evt += eventName + "\t";
evt += WriteParams(eventName, parameters);
return evt;
}
static string WriteParams(string eventName, Dictionary<string, object> parameters)
{
string json = "{";
foreach(KeyValuePair<string, object> kv in parameters)
{
json += Quotify(kv.Key) + ":" + Quotify(kv.Value.ToString());
json += ",";
}
json += Quotify("unity.name") + ":" + Quotify(eventName) + "}";
return json;
}
static string Quotify(string value)
{
return "\"" + value + "\"";
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0b2a6822dabcf433db9bbd852dfaee1f
timeCreated: 1437429523
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,121 @@
/// <summary>
/// Send Heatmap event based on VideoPlayer.
/// </summary>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
using UnityAnalytics360VideoHeatmap;
namespace UnityAnalytics360VideoHeatmap
{
public class HeatmapSender : MonoBehaviour
{
public VideoPlayer videoPlayer;
private int k_currentSendEventRatio;
private bool k_eventSender;
private int k_eventLimit = 5000;
private float k_eventInterval = 1.0f;
private WaitForSeconds k_waitForSecond;
private Dictionary<string, object> k_clipDict;
void Start()
{
if (videoPlayer == null)
{
videoPlayer = FindObjectOfType<VideoPlayer>();
}
EnsureRatio();
k_eventInterval = DetermineEventInterval(k_eventLimit);
k_waitForSecond = new WaitForSeconds(k_eventInterval);
#if UNITY_EDITOR
StartCoroutine(SendHeatmapEvent());
#else
if (k_eventSender)
StartCoroutine(SendHeatmapEvent());
#endif
}
/// <summary>
/// Make sure the ratio is most updated.
/// </summary>
private void EnsureRatio()
{
k_eventSender = PlayerPrefs.GetInt("_360VideoHeatMap_EventSender", 0) == 0 ? true : false;
k_currentSendEventRatio = PlayerPrefs.GetInt("_360VideoHeatMap_EventRatio", 10);
int m_newSendEventRatio = RemoteSettings.GetInt("heatmaps_sample_rate", 10);
// If the ratio has changed or the role has not been assigned before, reassign the user.
if (!PlayerPrefs.HasKey("_360VideoHeatMap_EventSender") || k_currentSendEventRatio != m_newSendEventRatio)
{
k_currentSendEventRatio = m_newSendEventRatio;
EnsureUserRole();
PlayerPrefs.SetInt("_360VideoHeatMap_EventSender", k_eventSender == true ? 0 : 1);
PlayerPrefs.SetInt("_360VideoHeatMap_EventRatio", k_currentSendEventRatio);
}
}
/// <summary>
/// Check if the user is allowed to send event based on the RemoteSetting key.
/// </summary>
private void EnsureUserRole()
{
if (k_currentSendEventRatio >= 100)
{
k_eventSender = true;
return;
}
if (k_currentSendEventRatio <= 0)
{
k_eventSender = false;
return;
}
int m_random = Random.Range(0, 100);
if (m_random <= k_currentSendEventRatio)
{
k_eventSender = true;
return;
}
k_eventSender = false;
}
/// <summary>
/// Send the event only when VideoPlayer, clip exist and the video is playing.
/// </summary>
IEnumerator SendHeatmapEvent()
{
if (k_clipDict == null)
k_clipDict = new Dictionary<string, object>();
while (true)
{
if (videoPlayer != null && videoPlayer.clip != null && videoPlayer.isPlaying)
{
float m_standardTime = videoPlayer.frame / (float)videoPlayer.frameCount;
k_clipDict["clipName"] = videoPlayer.clip.name;
HeatmapEvent.Send("PlayerLook", this.transform, m_standardTime, k_clipDict);
}
yield return k_waitForSecond;
}
}
/// <summary>
/// Determine what's the time interval for event sending to not exceed the event limit.
/// </summary>
float DetermineEventInterval(int eventLimit)
{
float m_minimumInterval = 3600 / (float)eventLimit;
return Mathf.Ceil(m_minimumInterval);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 334944594a826499d8df0f639515cca4
timeCreated: 1511216740
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 84f7580997b7341a1b4b9b21eebd5a49
folderAsset: yes
timeCreated: 1512760710
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,218 @@
Shader "Skybox/Panoramic-Heatmap" {
Properties {
_Tint ("Tint Color", Color) = (.5, .5, .5, .5)
[Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
_Rotation ("Rotation", Range(0, 360)) = 0
[NoScaleOffset] _MainTex ("Spherical (HDR)", 2D) = "grey" {}
[NoScaleOffset] _HeatmapTex ("Spherical Heatmap (HDR)", 2D) = "grey" {}
[NoScaleOffset] _HeatmapGradient ("Gradient Lookup", 2D) = "grey" {}
[KeywordEnum(6 Frames Layout, Latitude Longitude Layout)] _Mapping("Mapping", Float) = 1
[Enum(360 Degrees, 0, 180 Degrees, 1)] _ImageType("Image Type", Float) = 0
[Toggle] _MirrorOnBack("Mirror on Back", Float) = 0
[Enum(None, 0, Side by Side, 1, Over Under, 2)] _Layout("3D Layout", Float) = 0
}
SubShader {
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
Cull Off ZWrite Off
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#pragma multi_compile __ _MAPPING_6_FRAMES_LAYOUT
#include "UnityCG.cginc"
sampler2D _MainTex;
sampler2D _HeatmapTex;
sampler2D _HeatmapGradient;
float4 _MainTex_TexelSize;
half4 _MainTex_HDR;
half4 _Tint;
half _Exposure;
float _Rotation;
#ifndef _MAPPING_6_FRAMES_LAYOUT
bool _MirrorOnBack;
int _ImageType;
int _Layout;
#endif
#ifndef _MAPPING_6_FRAMES_LAYOUT
inline float2 ToRadialCoords(float3 coords)
{
float3 normalizedCoords = normalize(coords);
float latitude = acos(normalizedCoords.y);
float longitude = atan2(normalizedCoords.z, normalizedCoords.x);
float2 sphereCoords = float2(longitude, latitude) * float2(0.5/UNITY_PI, 1.0/UNITY_PI);
return float2(0.5,1.0) - sphereCoords;
}
#endif
#ifdef _MAPPING_6_FRAMES_LAYOUT
inline float2 ToCubeCoords(float3 coords, float3 layout, float4 edgeSize, float4 faceXCoordLayouts, float4 faceYCoordLayouts, float4 faceZCoordLayouts)
{
// Determine the primary axis of the normal
float3 absn = abs(coords);
float3 absdir = absn > float3(max(absn.y,absn.z), max(absn.x,absn.z), max(absn.x,absn.y)) ? 1 : 0;
// Convert the normal to a local face texture coord [-1,+1], note that tcAndLen.z==dot(coords,absdir)
// and thus its sign tells us whether the normal is pointing positive or negative
float3 tcAndLen = mul(absdir, float3x3(coords.zyx, coords.xzy, float3(-coords.xy,coords.z)));
tcAndLen.xy /= tcAndLen.z;
// Flip-flop faces for proper orientation and normalize to [-0.5,+0.5]
bool2 positiveAndVCross = float2(tcAndLen.z, layout.x) > 0;
tcAndLen.xy *= (positiveAndVCross[0] ? absdir.yx : (positiveAndVCross[1] ? float2(absdir[2],0) : float2(0,absdir[2]))) - 0.5;
// Clamp values which are close to the face edges to avoid bleeding/seams (ie. enforce clamp texture wrap mode)
tcAndLen.xy = clamp(tcAndLen.xy, edgeSize.xy, edgeSize.zw);
// Scale and offset texture coord to match the proper square in the texture based on layout.
float4 coordLayout = mul(float4(absdir,0), float4x4(faceXCoordLayouts, faceYCoordLayouts, faceZCoordLayouts, faceZCoordLayouts));
tcAndLen.xy = (tcAndLen.xy + (positiveAndVCross[0] ? coordLayout.xy : coordLayout.zw)) * layout.yz;
return tcAndLen.xy;
}
#endif
float3 RotateAroundYInDegrees (float3 vertex, float degrees)
{
float alpha = degrees * UNITY_PI / 180.0;
float sina, cosa;
sincos(alpha, sina, cosa);
float2x2 m = float2x2(cosa, -sina, sina, cosa);
return float3(mul(m, vertex.xz), vertex.y).xzy;
}
struct appdata_t {
float4 vertex : POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 vertex : SV_POSITION;
float3 texcoord : TEXCOORD0;
#ifdef _MAPPING_6_FRAMES_LAYOUT
float3 layout : TEXCOORD1;
float4 edgeSize : TEXCOORD2;
float4 faceXCoordLayouts : TEXCOORD3;
float4 faceYCoordLayouts : TEXCOORD4;
float4 faceZCoordLayouts : TEXCOORD5;
#else
float2 image180ScaleAndCutoff : TEXCOORD1;
float4 layout3DScaleAndOffset : TEXCOORD2;
#endif
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert (appdata_t v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation);
o.vertex = UnityObjectToClipPos(rotated);
o.texcoord = v.vertex.xyz;
#ifdef _MAPPING_6_FRAMES_LAYOUT
// layout and edgeSize are solely based on texture dimensions and can thus be precalculated in the vertex shader.
float sourceAspect = float(_MainTex_TexelSize.z) / float(_MainTex_TexelSize.w);
// Use the halfway point between the 1:6 and 3:4 aspect ratios of the strip and cross layouts to
// guess at the correct format.
bool3 aspectTest =
sourceAspect >
float3(1.0, 1.0f / 6.0f + (3.0f / 4.0f - 1.0f / 6.0f) / 2.0f, 6.0f / 1.0f + (4.0f / 3.0f - 6.0f / 1.0f) / 2.0f);
// For a given face layout, the coordinates of the 6 cube faces are fixed: build a compact representation of the
// coordinates of the center of each face where the first float4 represents the coordinates of the X axis faces,
// the second the Y, and the third the Z. The first two float componenents (xy) of each float4 represent the face
// coordinates on the positive axis side of the cube, and the second (zw) the negative.
// layout.x is a boolean flagging the vertical cross layout (for special handling of flip-flops later)
// layout.yz contains the inverse of the layout dimensions (ie. the scale factor required to convert from
// normalized face coords to full texture coordinates)
if (aspectTest[0]) // horizontal
{
if (aspectTest[2])
{ // horizontal strip
o.faceXCoordLayouts = float4(0.5,0.5,1.5,0.5);
o.faceYCoordLayouts = float4(2.5,0.5,3.5,0.5);
o.faceZCoordLayouts = float4(4.5,0.5,5.5,0.5);
o.layout = float3(-1,1.0/6.0,1.0/1.0);
}
else
{ // horizontal cross
o.faceXCoordLayouts = float4(2.5,1.5,0.5,1.5);
o.faceYCoordLayouts = float4(1.5,2.5,1.5,0.5);
o.faceZCoordLayouts = float4(1.5,1.5,3.5,1.5);
o.layout = float3(-1,1.0/4.0,1.0/3.0);
}
}
else
{
if (aspectTest[1])
{ // vertical cross
o.faceXCoordLayouts = float4(2.5,2.5,0.5,2.5);
o.faceYCoordLayouts = float4(1.5,3.5,1.5,1.5);
o.faceZCoordLayouts = float4(1.5,2.5,1.5,0.5);
o.layout = float3(1,1.0/3.0,1.0/4.0);
}
else
{ // vertical strip
o.faceXCoordLayouts = float4(0.5,5.5,0.5,4.5);
o.faceYCoordLayouts = float4(0.5,3.5,0.5,2.5);
o.faceZCoordLayouts = float4(0.5,1.5,0.5,0.5);
o.layout = float3(-1,1.0/1.0,1.0/6.0);
}
}
// edgeSize specifies the minimum (xy) and maximum (zw) normalized face texture coordinates that will be used for
// sampling in the texture. Setting these to the effective size of a half pixel horizontally and vertically
// effectively enforces clamp mode texture wrapping for each individual face.
o.edgeSize.xy = _MainTex_TexelSize.xy * 0.5 / o.layout.yz - 0.5;
o.edgeSize.zw = -o.edgeSize.xy;
#else // !_MAPPING_6_FRAMES_LAYOUT
// Calculate constant horizontal scale and cutoff for 180 (vs 360) image type
if (_ImageType == 0) // 360 degree
o.image180ScaleAndCutoff = float2(1.0, 1.0);
else // 180 degree
o.image180ScaleAndCutoff = float2(2.0, _MirrorOnBack ? 1.0 : 0.5);
// Calculate constant scale and offset for 3D layouts
if (_Layout == 0) // No 3D layout
o.layout3DScaleAndOffset = float4(0,0,1,1);
else if (_Layout == 1) // Side-by-Side 3D layout
o.layout3DScaleAndOffset = float4(unity_StereoEyeIndex,0,0.5,1);
else // Over-Under 3D layout
o.layout3DScaleAndOffset = float4(0, 1-unity_StereoEyeIndex,1,0.5);
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target
{
#ifdef _MAPPING_6_FRAMES_LAYOUT
float2 tc = ToCubeCoords(i.texcoord, i.layout, i.edgeSize, i.faceXCoordLayouts, i.faceYCoordLayouts, i.faceZCoordLayouts);
#else
float2 tc = ToRadialCoords(i.texcoord);
if (tc.x > i.image180ScaleAndCutoff[1])
return half4(0,0,0,1);
tc.x = fmod(tc.x*i.image180ScaleAndCutoff[0], 1);
tc = (tc + i.layout3DScaleAndOffset.xy) * i.layout3DScaleAndOffset.zw;
#endif
half4 tex = tex2D (_MainTex, tc);
// apply heat
float heat = tex2D (_HeatmapTex, tc);
float4 grad = tex2D (_HeatmapGradient, float2(heat, heat));
tex.rgb = (1 - grad.w) * tex.rgb + grad.w * tex.rgb * grad.xyz;
half3 c = DecodeHDR (tex, _MainTex_HDR);
c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
c *= _Exposure;
return half4(c, 1);
}
ENDCG
}
}
CustomEditor "SkyboxPanoramicShaderGUI"
Fallback Off
}

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c6bc35204d28841369e212c37e8b22c5
timeCreated: 1505407735
licenseType: Pro
ShaderImporter:
externalObjects: {}
defaultTextures: []
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Default</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ItemType>GenericProject</ItemType>
<ProjectGuid>{CB6F8974-2395-4B9E-B8AE-0705AC6509F2}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Default|AnyCPU' ">
<OutputPath>.\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Folder Include="Editor\" />
<Folder Include="Examples\" />
<Folder Include="Renderer\" />
</ItemGroup>
<ItemGroup>
<None Include="Editor\HeatMapDataParser.cs" />
<None Include="Editor\UnityAnalyticsIntegration.cs" />
<None Include="Examples\BotDeathTracker.cs" />
<None Include="Examples\HeatmapToggler.cs" />
<None Include="Examples\IAnalyticsDispatcher.cs" />
<None Include="Examples\LoginSubmissionForm.cs" />
<None Include="Examples\PositionTracker.cs" />
<None Include="Examples\UAUniqueUsername.cs" />
<None Include="Renderer\HeatMapRenderer.cs" />
<None Include="Renderer\HeatPoint.cs" />
<None Include="Renderer\IHeatmapRenderer.cs" />
<None Include="HeatMapEvent.cs" />
<None Include="Editor\HeatMapController.cs" />
<None Include="Editor\HeatMapInspector.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 3ca3c691e42eb48f0baff5a632e91350
timeCreated: 1437429523
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c823b6cdb9bf14ed8a0ad66690227c68
folderAsset: yes
timeCreated: 1512760561
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 0930d3a2e921d40bbb5f4bb4377c2b3f
folderAsset: yes
timeCreated: 1444707935
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,15 @@
using System;
namespace UnityAnalytics360VideoHeatmap
{
// Note variance from C# code standard. We need these to match consts on server.
public enum UnityAnalyticsEventType
{
appStart,
appRunning,
custom,
transaction,
userInfo,
deviceInfo,
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 440389feffcb2451697647ef5086b4cf
timeCreated: 1438818367
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1080133c164f04a9e8c95a4f35f374dd
folderAsset: yes
timeCreated: 1470595871
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,259 @@
/// <summary>
/// Manages the loading and processing of Heatmap data
/// </summary>
///
/// Heatmap data is loaded from GZip or text files and stored in the
/// HeatmapViewModel as a CustomRawData[]. From there, it is aggregated
/// into a HeatPoint[] before being sent to the renderer.
///
/// This class manages all that loading and processing, working out the
/// minimum work required to dynamically update the map.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityAnalytics;
using UnityEditor;
using System.Collections;
using System.Linq;
namespace UnityAnalytics360VideoHeatmap
{
public class HeatmapDataProcessor
{
const string k_DataPathKey = "UnityAnalyticsHeatmapDataPathKey";
const string k_SpaceKey = "UnityAnalyticsHeatmapAggregationSpace";
const string k_KeyToTime = "UnityAnalyticsHeatmapAggregationTime";
const string k_RotationKey = "UnityAnalyticsHeatmapAggregationRotation";
const string k_SmoothSpaceKey = "UnityAnalyticsHeatmapAggregationAggregateSpace";
const string k_SmoothTimeKey = "UnityAnalyticsHeatmapAggregationAggregateTime";
const string k_SmoothRotationKey = "UnityAnalyticsHeatmapAggregationAggregateRotation";
const string k_StartTimeKey = "UnityAnalyticsHeatmapAggregateStartTime";
const string k_EndTimeKey = "UnityAnalyticsHeatmapAggregateEndTime";
const string k_SeparateSessionKey = "UnityAnalyticsHeatmapAggregationAggregateSessionIDs";
const string k_SeparateDebugKey = "UnityAnalyticsHeatmapAggregationAggregateDebug";
const string k_SeparatePlatformKey = "UnityAnalyticsHeatmapAggregationAggregatePlatform";
const string k_SeparateCustomKey = "UnityAnalyticsHeatmapAggregationAggregateCustom";
const string k_ArbitraryFieldsKey = "UnityAnalyticsHeatmapAggregationArbitraryFields";
const float k_DefaultSpace = 10f;
const float k_DefaultTime = 10f;
const float k_DefaultRotation = 15f;
public const int SMOOTH_VALUE = 0;
public const int SMOOTH_NONE = 1;
public const int SMOOTH_UNION = 2;
public HeatmapViewModel m_ViewModel;
public HeatmapAggregator m_Aggregator;
bool m_DateChangeHasOccurred = true;
private string _rawDataPath = "";
public string m_RawDataPath
{
get{
return _rawDataPath;
}
set{
_rawDataPath = value;
m_Aggregator.SetDataPath(_rawDataPath);
EditorPrefs.SetString(k_DataPathKey, value);
}
}
[SerializeField]
string _startDate = "";
public string m_StartDate
{
get {
return _startDate;
}
set {
string oldDate = _startDate;
_startDate = value;
if (_startDate != oldDate)
{
EditorPrefs.SetString(Application.cloudProjectId + k_StartTimeKey, _startDate);
m_DateChangeHasOccurred = true;
}
}
}
[SerializeField]
string _endDate = "";
public string m_EndDate
{
get {
return _endDate;
}
set {
string oldDate = _endDate;
_endDate = value;
if (_endDate != oldDate)
{
EditorPrefs.SetString(Application.cloudProjectId + k_EndTimeKey, _endDate);
m_DateChangeHasOccurred = true;
}
}
}
bool _separateSessions = false;
public bool m_SeparateSessions{
get{
return _separateSessions;
}
set{
_separateSessions = value;
EditorPrefs.SetBool(k_SeparateSessionKey, _separateSessions);
}
}
bool _separatePlatform;
public bool m_SeparatePlatform
{
get {
return _separatePlatform;
}
set {
_separatePlatform = value;
EditorPrefs.SetBool(k_SeparateSessionKey, _separatePlatform);
}
}
bool _separateDebug;
public bool m_SeparateDebug
{
get {
return _separateDebug;
}
set {
_separateDebug = value;
EditorPrefs.SetBool(k_SeparateDebugKey, _separateDebug);
}
}
bool _separateCustomField;
public bool m_SeparateCustomField
{
get {
return _separateCustomField;
}
set {
_separateCustomField = value;
EditorPrefs.SetBool(k_SeparateCustomKey, _separateCustomField);
}
}
List<string> _separationFields = new List<string>();
public List<string> m_SeparationFields
{
get {
return _separationFields;
}
set {
_separationFields = value;
string currentArbitraryFieldsString = string.Join("|", _separationFields.ToArray());
EditorPrefs.SetString(k_ArbitraryFieldsKey, currentArbitraryFieldsString);
}
}
public delegate void AggregationHandler(string jsonPath);
public delegate void PointHandler(HeatPoint[] heatData);
static public AggregationMethod[] m_RemapOptionIds = new AggregationMethod[]{
AggregationMethod.Increment,
AggregationMethod.Cumulative,
AggregationMethod.Average,
AggregationMethod.Min,
AggregationMethod.Max,
AggregationMethod.First,
AggregationMethod.Last,
AggregationMethod.Percentile
};
public HeatmapDataProcessor()
{
m_Aggregator = new HeatmapAggregator(m_RawDataPath);
HeatmapViewModel.StartEndDateUpdated += HeatmapViewModel_StartEndDateUpdated;
}
void HeatmapViewModel_StartEndDateUpdated(string startDate, string endDate)
{
m_StartDate = startDate;
m_EndDate = endDate;
RawDataClient.GetInstance().m_DataPath = m_RawDataPath;
ProcessAggregation();
}
public void RestoreSettings()
{
// Restore cached paths
m_RawDataPath = EditorPrefs.GetString(k_DataPathKey);
// Set dates based on today (should this be cached?)
// Yes, yes it should.
m_EndDate = EditorPrefs.HasKey(Application.cloudProjectId+k_EndTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId+k_EndTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow);
m_StartDate = EditorPrefs.HasKey(Application.cloudProjectId + k_StartTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId + k_StartTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow.Subtract(new TimeSpan(5, 0, 0, 0)));
// Restore list of arbitrary separation fields
string loadedArbitraryFields = EditorPrefs.GetString(k_ArbitraryFieldsKey);
string[] arbitraryFieldsList;
if (string.IsNullOrEmpty(loadedArbitraryFields))
{
arbitraryFieldsList = new string[]{ };
}
else
{
arbitraryFieldsList = loadedArbitraryFields.Split('|');
}
m_SeparationFields = new List<string>(arbitraryFieldsList);
}
/// <summary>
/// Fetch the files within the currently specified date range.
/// </summary>
public void Fetch()
{
RawDataClient.GetInstance().m_DataPath = m_RawDataPath;
ProcessAggregation();
}
void ProcessAggregation()
{
//TODO: Where settings for aggregation go
DateTime start, end;
try
{
start = DateTime.Parse(m_StartDate).ToUniversalTime();
}
catch
{
start = DateTime.Parse("2000-01-01").ToUniversalTime();
}
try
{
end = DateTime.Parse(m_EndDate).ToUniversalTime().Add(new TimeSpan(24,0,0));
}
catch
{
end = DateTime.UtcNow;
}
if (m_DateChangeHasOccurred || RawDataClient.GetInstance().m_ManifestInvalidated ||
HeatmapViewModel.m_RawDataFileList == null || HeatmapViewModel.m_RawDataFileList.Count == 0)
{
RawDataClient.GetInstance().m_DataPath = m_RawDataPath;
HeatmapViewModel.m_RawDataFileList = RawDataClient.GetInstance().GetFiles(
new UnityAnalyticsEventType[]{ UnityAnalyticsEventType.custom }, start, end);
m_DateChangeHasOccurred = false;
if (HeatmapViewModel.m_RawDataFileList.Count == 0)
{
return;
}
}
m_Aggregator.Process(HeatmapViewModel.m_RawDataFileList, start, end);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 7534739c6188a4755a42197820728221
timeCreated: 1470595871
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: dfdf5ae6e9b3a41938676ed035d2e7e3
folderAsset: yes
timeCreated: 1438385450
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Двоичные данные
Assets/AssetStorePackage/Plugins/Heatmaps/Internal/Lib/Ionic.Zlib.dll Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,32 @@
fileFormatVersion: 2
guid: abd1f95c0baf24d4ba1711633693c8b0
timeCreated: 1463523671
licenseType: Pro
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,548 @@
/*
* Copyright (c) 2013 Calvin Rien
*
* Based on the JSON parser by Patrick van Bergen
* http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
*
* Simplified it so that it doesn't throw exceptions
* and can be used in Unity iPhone with maximum code stripping.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace MiniJSON {
// Example usage:
//
// using UnityEngine;
// using System.Collections;
// using System.Collections.Generic;
// using MiniJSON;
//
// public class MiniJSONTest : MonoBehaviour {
// void Start () {
// var jsonString = "{ \"array\": [1.44,2,3], " +
// "\"object\": {\"key1\":\"value1\", \"key2\":256}, " +
// "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " +
// "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " +
// "\"int\": 65536, " +
// "\"float\": 3.1415926, " +
// "\"bool\": true, " +
// "\"null\": null }";
//
// var dict = Json.Deserialize(jsonString) as Dictionary<string,object>;
//
// //Debug.Log("deserialized: " + dict.GetType());
// //Debug.Log("dict['array'][0]: " + ((List<object>) dict["array"])[0]);
// //Debug.Log("dict['string']: " + (string) dict["string"]);
// //Debug.Log("dict['float']: " + (double) dict["float"]); // floats come out as doubles
// //Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs
// //Debug.Log("dict['unicode']: " + (string) dict["unicode"]);
//
// var str = Json.Serialize(dict);
//
// //Debug.Log("serialized: " + str);
// }
// }
/// <summary>
/// This class encodes and decodes JSON strings.
/// Spec. details, see http://www.json.org/
///
/// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary.
/// All numbers are parsed to doubles.
/// </summary>
public static class Json {
/// <summary>
/// Parses the string json into a value
/// </summary>
/// <param name="json">A JSON string.</param>
/// <returns>An List&lt;object&gt;, a Dictionary&lt;string, object&gt;, a double, an integer,a string, null, true, or false</returns>
public static object Deserialize(string json) {
// save the string for debug information
if (json == null) {
return null;
}
return Parser.Parse(json);
}
sealed class Parser : IDisposable {
const string WORD_BREAK = "{}[],:\"";
public static bool IsWordBreak(char c) {
return Char.IsWhiteSpace(c) || WORD_BREAK.IndexOf(c) != -1;
}
enum TOKEN {
NONE,
CURLY_OPEN,
CURLY_CLOSE,
SQUARED_OPEN,
SQUARED_CLOSE,
COLON,
COMMA,
STRING,
NUMBER,
TRUE,
FALSE,
NULL
};
StringReader json;
Parser(string jsonString) {
json = new StringReader(jsonString);
}
public static object Parse(string jsonString) {
using (var instance = new Parser(jsonString)) {
return instance.ParseValue();
}
}
public void Dispose() {
json.Dispose();
json = null;
}
Dictionary<string, object> ParseObject() {
Dictionary<string, object> table = new Dictionary<string, object>();
// ditch opening brace
json.Read();
// {
while (true) {
switch (NextToken) {
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.CURLY_CLOSE:
return table;
default:
// name
string name = ParseString();
if (name == null) {
return null;
}
// :
if (NextToken != TOKEN.COLON) {
return null;
}
// ditch the colon
json.Read();
// value
table[name] = ParseValue();
break;
}
}
}
List<object> ParseArray() {
List<object> array = new List<object>();
// ditch opening bracket
json.Read();
// [
var parsing = true;
while (parsing) {
TOKEN nextToken = NextToken;
switch (nextToken) {
case TOKEN.NONE:
return null;
case TOKEN.COMMA:
continue;
case TOKEN.SQUARED_CLOSE:
parsing = false;
break;
default:
object value = ParseByToken(nextToken);
array.Add(value);
break;
}
}
return array;
}
object ParseValue() {
TOKEN nextToken = NextToken;
return ParseByToken(nextToken);
}
object ParseByToken(TOKEN token) {
switch (token) {
case TOKEN.STRING:
return ParseString();
case TOKEN.NUMBER:
return ParseNumber();
case TOKEN.CURLY_OPEN:
return ParseObject();
case TOKEN.SQUARED_OPEN:
return ParseArray();
case TOKEN.TRUE:
return true;
case TOKEN.FALSE:
return false;
case TOKEN.NULL:
return null;
default:
return null;
}
}
string ParseString() {
StringBuilder s = new StringBuilder();
char c;
// ditch opening quote
json.Read();
bool parsing = true;
while (parsing) {
if (json.Peek() == -1) {
parsing = false;
break;
}
c = NextChar;
switch (c) {
case '"':
parsing = false;
break;
case '\\':
if (json.Peek() == -1) {
parsing = false;
break;
}
c = NextChar;
switch (c) {
case '"':
case '\\':
case '/':
s.Append(c);
break;
case 'b':
s.Append('\b');
break;
case 'f':
s.Append('\f');
break;
case 'n':
s.Append('\n');
break;
case 'r':
s.Append('\r');
break;
case 't':
s.Append('\t');
break;
case 'u':
var hex = new char[4];
for (int i=0; i< 4; i++) {
hex[i] = NextChar;
}
s.Append((char) Convert.ToInt32(new string(hex), 16));
break;
}
break;
default:
s.Append(c);
break;
}
}
return s.ToString();
}
object ParseNumber() {
string number = NextWord;
if (number.IndexOf('.') == -1) {
long parsedInt;
Int64.TryParse(number, out parsedInt);
return parsedInt;
}
double parsedDouble;
Double.TryParse(number, out parsedDouble);
return parsedDouble;
}
void EatWhitespace() {
while (Char.IsWhiteSpace(PeekChar)) {
json.Read();
if (json.Peek() == -1) {
break;
}
}
}
char PeekChar {
get {
return Convert.ToChar(json.Peek());
}
}
char NextChar {
get {
return Convert.ToChar(json.Read());
}
}
string NextWord {
get {
StringBuilder word = new StringBuilder();
while (!IsWordBreak(PeekChar)) {
word.Append(NextChar);
if (json.Peek() == -1) {
break;
}
}
return word.ToString();
}
}
TOKEN NextToken {
get {
EatWhitespace();
if (json.Peek() == -1) {
return TOKEN.NONE;
}
switch (PeekChar) {
case '{':
return TOKEN.CURLY_OPEN;
case '}':
json.Read();
return TOKEN.CURLY_CLOSE;
case '[':
return TOKEN.SQUARED_OPEN;
case ']':
json.Read();
return TOKEN.SQUARED_CLOSE;
case ',':
json.Read();
return TOKEN.COMMA;
case '"':
return TOKEN.STRING;
case ':':
return TOKEN.COLON;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
return TOKEN.NUMBER;
}
switch (NextWord) {
case "false":
return TOKEN.FALSE;
case "true":
return TOKEN.TRUE;
case "null":
return TOKEN.NULL;
}
return TOKEN.NONE;
}
}
}
/// <summary>
/// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
/// </summary>
/// <param name="json">A Dictionary&lt;string, object&gt; / List&lt;object&gt;</param>
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
public static string Serialize(object obj) {
return Serializer.Serialize(obj);
}
sealed class Serializer {
StringBuilder builder;
Serializer() {
builder = new StringBuilder();
}
public static string Serialize(object obj) {
var instance = new Serializer();
instance.SerializeValue(obj);
return instance.builder.ToString();
}
void SerializeValue(object value) {
IList asList;
IDictionary asDict;
string asStr;
if (value == null) {
builder.Append("null");
} else if ((asStr = value as string) != null) {
SerializeString(asStr);
} else if (value is bool) {
builder.Append((bool) value ? "true" : "false");
} else if ((asList = value as IList) != null) {
SerializeArray(asList);
} else if ((asDict = value as IDictionary) != null) {
SerializeObject(asDict);
} else if (value is char) {
SerializeString(new string((char) value, 1));
} else {
SerializeOther(value);
}
}
void SerializeObject(IDictionary obj) {
bool first = true;
builder.Append('{');
foreach (object e in obj.Keys) {
if (!first) {
builder.Append(',');
}
SerializeString(e.ToString());
builder.Append(':');
SerializeValue(obj[e]);
first = false;
}
builder.Append('}');
}
void SerializeArray(IList anArray) {
builder.Append('[');
bool first = true;
foreach (object obj in anArray) {
if (!first) {
builder.Append(',');
}
SerializeValue(obj);
first = false;
}
builder.Append(']');
}
void SerializeString(string str) {
builder.Append('\"');
char[] charArray = str.ToCharArray();
foreach (var c in charArray) {
switch (c) {
case '"':
builder.Append("\\\"");
break;
case '\\':
builder.Append("\\\\");
break;
case '\b':
builder.Append("\\b");
break;
case '\f':
builder.Append("\\f");
break;
case '\n':
builder.Append("\\n");
break;
case '\r':
builder.Append("\\r");
break;
case '\t':
builder.Append("\\t");
break;
default:
int codepoint = Convert.ToInt32(c);
if ((codepoint >= 32) && (codepoint <= 126)) {
builder.Append(c);
} else {
builder.Append("\\u");
builder.Append(codepoint.ToString("x4"));
}
break;
}
}
builder.Append('\"');
}
void SerializeOther(object value) {
// NOTE: decimals lose precision during serialization.
// They always have, I'm just letting you know.
// Previously floats and doubles lost precision too.
if (value is float) {
builder.Append(((float) value).ToString("R"));
} else if (value is int
|| value is uint
|| value is long
|| value is sbyte
|| value is byte
|| value is short
|| value is ushort
|| value is ulong) {
builder.Append(value);
} else if (value is double
|| value is decimal) {
builder.Append(Convert.ToDouble(value).ToString("R"));
} else {
SerializeString(value.ToString());
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: adec011f8959049f5accb530c4586615
timeCreated: 1444699744
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 7d044b59d14c8483c8ddf2641f0995ea
folderAsset: yes
timeCreated: 1470590513
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,9 @@
using System;
namespace UnityAnalytics
{
public class DateTimeUtils
{
public static DateTime s_Epoch = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1d7a4f98487b14ea0adfacc0eeca3639
timeCreated: 1464232099
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,31 @@
/// <summary>
/// Heat point.
/// </summary>
/// This struct is used by the rendering system to define each individual
/// heat map datum.
using System;
using UnityEngine;
namespace UnityAnalytics360VideoHeatmap
{
public struct HeatPoint : IEquatable<HeatPoint>
{
public Vector3 position;
public Vector3 rotation;
public int density;
public float time;
public bool Equals(HeatPoint other)
{
if(position == other.position
&& rotation == other.rotation
&& density == other.density
&& time == other.time)
{
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1280ddf724987485a8cd8346a83f09f5
timeCreated: 1437429523
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,442 @@
/// <summary>
/// Heatmap view model.
/// </summary>
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Video;
namespace UnityAnalytics360VideoHeatmap
{
public class HeatmapViewModel
{
static HeatmapViewModel _instance;
public static HeatmapViewModel instance
{
get {
if (_instance == null)
{
_instance = new HeatmapViewModel();
}
else
{
Restore();
}
return _instance;
}
}
/// <summary>
/// The list of raw data files
/// </summary>
public static List<string> m_RawDataFileList = new List<string>();
///<summary>
/// The list of all the event names
/// </summary>
static public List<string> eventNames = new List<string>();
///<summary>
/// A mapping of a session's separators to event names
/// </summary>
//Dictionary of a Dictionary of HeatmapsSeparators
static Dictionary<string, object> separatorsToEvents = new Dictionary<string, object>();
///<summary>
/// A mapping of a session's point data to event names
/// </summary>
//Dictionary of a Dictionary of a list of Heatpoints
static Dictionary<string, object> heatpointsToEvents = new Dictionary<string, object>();
static Dictionary<string, SeparatorData> selectedSeparators = new Dictionary<string, SeparatorData>();
static Dictionary<string, HeatPoint[]> currentHeatpointsBySessions = new Dictionary<string, HeatPoint[]>();
public static float heatpointShowStartTime = 0.0f;
public static float heatpointShowEndTime = 0.01f;
[SerializeField]
private static VideoPlayer _videoPlayer;
public static VideoPlayer videoPlayer
{
get { return _videoPlayer; }
set
{
if (value != null &&_videoPlayer == null || _videoPlayer != value)
{
_videoPlayer = value;
if (_videoPlayer.isPrepared == false)
{
_videoPlayer.Prepare();
_videoPlayer.prepareCompleted += _videoPlayer_PrepareCompleted;
}
else
{
_videoPlayer_PrepareCompleted(_videoPlayer);
}
}
}
}
public static int endFrame = 1;
static string _startDate;
public static string startDate
{
get {
return _startDate;
}
set {
if(_startDate != value)
{
_startDate = value;
StartEndTimeUpdate();
}
}
}
static string _endDate;
public static string endDate
{
get
{
return _endDate;
}
set
{
if (_endDate != value)
{
_endDate = value;
StartEndTimeUpdate();
}
}
}
public delegate void UpdateSeparatorsHandler();
public static event UpdateSeparatorsHandler SeparatorsUpdated;
public delegate void UpdateEventNamesHandler();
public static event UpdateEventNamesHandler EventNamesUpdated;
public delegate void UpdateHeatpointsHandler(Dictionary<string, HeatPoint[]> currentHeatpointsBySessions);
public static event UpdateHeatpointsHandler HeatpointsUpdated;
public delegate void UpdateStartEndDateHandler(string startDate, string endDate);
public static event UpdateStartEndDateHandler StartEndDateUpdated;
public delegate void UpdateCurrentHeatpointsUpdatedHandler(List<HeatPoint[]> newHeatpoints);
public static event UpdateCurrentHeatpointsUpdatedHandler CurrentHeatpointsUpdated;
public delegate void UpdateVideoPlayerHandler(VideoPlayer newPlayer);
public static event UpdateVideoPlayerHandler VideoPlayerUpdated;
public delegate void UpdateVideoFinalFrameHandler(int endFrame);
public static event UpdateVideoFinalFrameHandler FinalFrameUpdated;
public HeatmapViewModel()
{
if(!HeatmapAggregator.IsEventHandlerRegistered_EventData(HeatmapAggregator_UpdateEventDataHandler))
{
HeatmapAggregator.UpdateEventData += HeatmapAggregator_UpdateEventDataHandler;
}
if (!HeatmapAggregator.IsEventHandlerRegistered_SepData(HeatmapAggregator_UpdateSeparators))
{
HeatmapAggregator.UpdateSeparators += HeatmapAggregator_UpdateSeparators;
}
if (!HeatmapAggregator.IsEventHandlerRegistered_EventNameData(HeatmapAggregator_UpdateEventNames))
{
HeatmapAggregator.UpdateEventNames += HeatmapAggregator_UpdateEventNames;
}
//initialize
//add separators
InitalizeSeperators();
//get start date/time
endDate = EditorPrefs.HasKey(Application.cloudProjectId + k_EndTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId + k_EndTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow);
startDate = EditorPrefs.HasKey(Application.cloudProjectId + k_StartTimeKey) ? EditorPrefs.GetString(Application.cloudProjectId + k_StartTimeKey) : String.Format("{0:yyyy-MM-dd}", DateTime.UtcNow.Subtract(new TimeSpan(5, 0, 0, 0)));
}
static void Restore ()
{
if(videoPlayer.isPrepared == false)
{
videoPlayer.Prepare();
videoPlayer.prepareCompleted += _videoPlayer_PrepareCompleted;
}
else{
_videoPlayer_PrepareCompleted(videoPlayer);
}
}
static void _videoPlayer_PrepareCompleted(VideoPlayer source)
{
_videoPlayer.prepareCompleted -= _videoPlayer_PrepareCompleted;
if (VideoPlayerUpdated != null)
VideoPlayerUpdated(_videoPlayer);
endFrame = (int)_videoPlayer.frameCount;
if (FinalFrameUpdated != null)
FinalFrameUpdated(endFrame);
_videoPlayer.frame = 0;
}
public void ManualOverride ()
{
if (StartEndDateUpdated != null)
StartEndDateUpdated(startDate, endDate);
InitalizeSeperators();
}
void HeatmapAggregator_UpdateSeparators(Dictionary<string, object> newSeparatorsToEvents)
{
separatorsToEvents = newSeparatorsToEvents;
if (SeparatorsUpdated != null)
SeparatorsUpdated();
}
void HeatmapAggregator_UpdateEventNames(List<string> newEventNames)
{
eventNames = newEventNames;
if (EventNamesUpdated != null)
EventNamesUpdated();
}
void HeatmapAggregator_UpdateEventDataHandler(Dictionary<string, object> newHeatpointsToEvents)
{
heatpointsToEvents = newHeatpointsToEvents;
InitalizeClipSeparator();
if (HeatpointsUpdated != null)
HeatpointsUpdated(currentHeatpointsBySessions);
}
static void StartEndTimeUpdate()
{
if (StartEndDateUpdated != null)
StartEndDateUpdated(startDate, endDate);
}
public static void UpdateHeatpointShowTimes(float startTime, float endTime)
{
heatpointShowStartTime = startTime;
heatpointShowEndTime = endTime;
UpdateCurrentHeatpoints();
}
//For 360 video purposes, this is hardcoded in
public static string[] GetEventNames()
{
return new string[] { "Heatmap.PlayerLook" };
}
public Dictionary<string, List<HeatmapSeparators>> GetSeparatorsForEvent(string eventName)
{
return (separatorsToEvents[eventName] as Dictionary<string, List<HeatmapSeparators>>);
}
void InitalizeSeperators()
{
SeparatorData sep = new SeparatorData();
sep.isActive = true;
sep.selectedValue = "Heatmap.PlayerLook";
sep.separatorValues = new List<string>();
sep.separatorValues.Add("Heatmap.PlayerLook");
sep.separatorKey = "eventName";
UpdateSeparator("eventName", sep);
sep = new SeparatorData();
sep.isActive = true;
sep.separatorKey = "clipName";
sep.separatorValues = new List<string>();
if (separatorsToEvents.ContainsKey("Heatmap.PlayerLook"))
{
Dictionary<string, List<HeatmapSeparators>> eventSeps = separatorsToEvents["Heatmap.PlayerLook"] as Dictionary<string, List<HeatmapSeparators>>;
foreach (KeyValuePair<string, List<HeatmapSeparators>> currSepList in eventSeps)
{
sep.separatorValues.AddRange(currSepList.Value.Where(x => !sep.separatorValues.Contains(x.clipName)).Select(x => x.clipName).ToList());
}
}
else
{
sep.separatorValues.Add("Unnamed");
}
sep.separatorKey = sep.separatorValues[0];
UpdateSeparator("clipName", sep);
}
void InitalizeClipSeparator()
{
var sep = new SeparatorData();
sep.isActive = true;
sep.separatorKey = "clipName";
sep.separatorValues = new List<string>();
if (separatorsToEvents.ContainsKey("Heatmap.PlayerLook"))
{
Dictionary<string, List<HeatmapSeparators>> eventSeps = separatorsToEvents["Heatmap.PlayerLook"] as Dictionary<string, List<HeatmapSeparators>>;
foreach (KeyValuePair<string, List<HeatmapSeparators>> currSepList in eventSeps)
{
sep.separatorValues.AddRange(currSepList.Value.Where(x => !sep.separatorValues.Contains(x.clipName)).Select(x => x.clipName).ToList());
}
}
else
{
sep.separatorValues.Add("Unnamed");
}
sep.separatorKey = sep.separatorValues[0];
UpdateSeparator("clipName", sep);
}
public static Dictionary<string, SeparatorData> GetSeparators()
{
return selectedSeparators;
}
public static void UpdateSeparator(string sep, SeparatorData value)
{
if (selectedSeparators.ContainsKey(sep))
{
selectedSeparators[sep] = value;
}
else
{
selectedSeparators.Add(sep, value);
}
UpdateCurrentHeatpoints();
//update appropriate settings objects
}
static void UpdateCurrentHeatpoints()
{
if (selectedSeparators.ContainsKey("eventName") && heatpointsToEvents.ContainsKey(selectedSeparators["eventName"].selectedValue))
{
var currEventHeatpoints = heatpointsToEvents[selectedSeparators["eventName"].selectedValue] as Dictionary<string, List<HeatPoint>>;
var currEventSeparators = separatorsToEvents[selectedSeparators["eventName"].selectedValue] as Dictionary<string, List<HeatmapSeparators>>;
List<string> visibleSessionIds = currEventSeparators.Where(currEventSepKV =>
{
return currEventSepKV.Value.Any(sessSep =>
{
return sessSep.clipName == selectedSeparators["clipName"].selectedValue;
});
}).Select(kv => kv.Key).ToList();
currentHeatpointsBySessions = currEventHeatpoints.Where(sessKV => visibleSessionIds.Contains(sessKV.Key)).Select(sessKV => new { sessionId = sessKV.Key, points = sessKV.Value }).ToDictionary(item => item.sessionId, item =>
{
//sorting hacky spot to put it
var array = item.points.ToArray(); Array.Sort(array, delegate (HeatPoint x, HeatPoint y)
{
return x.time.CompareTo(y.time);
}); return array;
}) as Dictionary<string, HeatPoint[]>;
if (CurrentHeatpointsUpdated != null)
CurrentHeatpointsUpdated(GetCurrentHeatpoints());
}
}
public List<string> GetCurrentSessions()
{
return currentHeatpointsBySessions.Keys.ToList();
}
static List<HeatPoint[]> GetCurrentHeatpoints()
{
List<HeatPoint[]> retList = new List<HeatPoint[]>();
foreach (HeatPoint[] heatpointArr in currentHeatpointsBySessions.Values.ToList())
{
List<HeatPoint> soonToBeRetArray = new List<HeatPoint>();
bool pointAddedForSession = false;
for (int a = 0; a < heatpointArr.Length; a++)
{
// FILTER FOR TIME & POSITION
var pt = heatpointArr[a];
if (FilterPoint(pt))
{
soonToBeRetArray.Add(pt);
pointAddedForSession = true;
}
}
if (pointAddedForSession == false)
{
soonToBeRetArray.Add(FilterForInterpolation(heatpointArr));
}
retList.Add(soonToBeRetArray.ToArray());
}
return retList;
}
static bool FilterPoint(HeatPoint pt)
{
if (pt.time < heatpointShowStartTime || pt.time > heatpointShowEndTime)
{
return false;
}
else
return true;
}
static HeatPoint FilterForInterpolation(HeatPoint[] pts)
{
//iterate through all the points, and take the two with the least difference before/after the bounds of timestamps
HeatPoint[] closestPoints = new HeatPoint[2];
if(videoPlayer != null)
{
for (int i = 1; i < pts.Length; i++)
{
if (pts[i].time > heatpointShowStartTime)
{
closestPoints[0] = pts[i - 1];
closestPoints[1] = pts[i];
break;
}
}
//special handling for VideoPlayer and film
int startFrame = (int)(heatpointShowStartTime * (int)videoPlayer.frameCount);
int dataStartFrame = (int)(closestPoints[0].time * (int)videoPlayer.frameCount);
int dataEndFrame = (int)(closestPoints[1].time * (int)videoPlayer.frameCount);
int dataNumFrames = dataEndFrame - dataStartFrame;
if (dataNumFrames == 0)
{
dataNumFrames = 1;
}
float T = ((float)startFrame - (float)dataStartFrame) / (float)dataNumFrames;
HeatPoint interpolatedPoint = new HeatPoint();
interpolatedPoint.rotation = Vector3.Slerp(closestPoints[0].rotation, closestPoints[1].rotation, T);
interpolatedPoint.density = (int)Mathf.Lerp(closestPoints[0].density, closestPoints[1].density, T);
return interpolatedPoint;
}
else
{
return new HeatPoint();
}
}
public static Dictionary<string, HeatPoint[]> GetHeatpointToSessionMapping ()
{
return currentHeatpointsBySessions;
}
const string k_StartTimeKey = "UnityAnalyticsHeatmapAggregateStartTime";
const string k_EndTimeKey = "UnityAnalyticsHeatmapAggregateEndTime";
}
public struct SeparatorData
{
public string separatorKey;
public bool isActive;
public List<string> separatorValues;
public string selectedValue;
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: dccd48c0fb03a4ce3bfed4cec201164d
timeCreated: 1470590513
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5ecd5096688ba475ea13c7b46da06db9
folderAsset: yes
timeCreated: 1437429523
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,17 @@
using System;
namespace UnityAnalytics360VideoHeatmap
{
public enum AggregationMethod
{
Increment,
Cumulative,
Average,
Max,
Min,
First,
Last,
Percentile
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 15515b3140cec4ea7b0c6348978fe058
timeCreated: 1461623559
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Просмотреть файл

@ -0,0 +1,38 @@
using System;
using UnityEngine;
namespace UnityAnalytics360VideoHeatmap
{
public class GradientContainer : MonoBehaviour
{
public Gradient ColorGradient;
static Color s_HighDensityColor = new Color(1f, 0, 0, 1f);
static Color s_MediumDensityColor = new Color(1f, 1f, 0, 1f);
static Color s_LowDensityColor = new Color(0, 1f, 1f, 1f);
public GradientContainer()
{
ColorGradient = new Gradient();
GradientColorKey[] colorKeys = new GradientColorKey[3];
colorKeys[0].color = s_LowDensityColor;
colorKeys[0].time = 0f;
colorKeys[1].color = s_MediumDensityColor;
colorKeys[1].time = 0.1f;
colorKeys[2].color = s_HighDensityColor;
colorKeys[2].time = 1f;
GradientAlphaKey[] alphaKeys = new GradientAlphaKey[3];
alphaKeys[0].alpha = .2f;
alphaKeys[0].time = 0f;
alphaKeys[1].alpha = .5f;
alphaKeys[1].time = .1f;
alphaKeys[2].alpha = 1f;
alphaKeys[2].time = 1f;
ColorGradient.SetKeys(colorKeys, alphaKeys);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 7fddd7b3aa09845f38cee8786e39337d
timeCreated: 1460506453
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше