diff --git a/Assets/Apple.Core.meta b/Assets/Apple.Core.meta index 9aa1722..2e5efe5 100644 --- a/Assets/Apple.Core.meta +++ b/Assets/Apple.Core.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8d26417a25e1944f1b7750a18abb2b4f +guid: 209d13b26698f40a6bd316b78a651e26 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Apple.Core/Editor.meta b/Assets/Apple.Core/Editor.meta index 45c0d3f..1b1fa94 100644 --- a/Assets/Apple.Core/Editor.meta +++ b/Assets/Apple.Core/Editor.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 440b602cefc764323afc8d5c9d3e961b +guid: 66bf582b1d4b34424b26e085b7c1fab3 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset b/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset index 8d10cbd..e1e1758 100644 --- a/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset +++ b/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset @@ -1,6 +1,6 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: ---- !u!114 &-8987626434458726503 +--- !u!114 &-8845562714357291400 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -9,32 +9,11 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 88a319fb99484804b632ce9bbec4cf6d, type: 3} - m_Name: AppleSecurityBuildStep + m_Script: {fileID: 11500000, guid: c6b8a8fe473224decaaecc9264d56e95, type: 3} + m_Name: AppleCoreBuildStep m_EditorClassIdentifier: IsEnabled: 1 - AppSandboxEntitlement: 1 - AllowNetworkServer: 0 - AllowNetworkClient: 0 - AllowCamera: 0 - AllowMicrophone: 0 - AllowUsb: 0 - AllowPrint: 0 - AllowBluetooth: 0 - AllowAddressBook: 0 - AllowLocation: 0 - AllowCalendars: 0 - AllowUserSelectedReadOnly: 0 - AllowUserSelectedReadWrite: 0 - AllowDownloadsReadOnly: 0 - AllowDownloadsReadWrite: 0 - AllowPicturesReadOnly: 0 - AllowPicturesReadWrite: 0 - AllowMusicReadOnly: 0 - AllowMusicReadWrite: 0 - AllowMoviesReadOnly: 0 - AllowMoviesReadWrite: 0 ---- !u!114 &-4631973922516641064 +--- !u!114 &-6584248542760643491 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -47,19 +26,6 @@ MonoBehaviour: m_Name: AppleGameKitBuildStep m_EditorClassIdentifier: IsEnabled: 1 ---- !u!114 &-1182492731493557681 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: c6b8a8fe473224decaaecc9264d56e95, type: 3} - m_Name: AppleCoreBuildStep - m_EditorClassIdentifier: - IsEnabled: 1 --- !u!114 &11400000 MonoBehaviour: m_ObjectHideFlags: 0 @@ -80,7 +46,7 @@ MonoBehaviour: AppUsesNonExemptEncryption: 0 AutomateEntitlements: 1 DefaultEntitlements: {fileID: 0} ---- !u!114 &750258044150326352 +--- !u!114 &755813747288564479 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -95,3 +61,37 @@ MonoBehaviour: IsEnabled: 0 AllowGetCurrentUser: 0 AllowRunsAsCurrentUser: 0 +--- !u!114 &8474646758244236940 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88a319fb99484804b632ce9bbec4cf6d, type: 3} + m_Name: AppleSecurityBuildStep + m_EditorClassIdentifier: + IsEnabled: 1 + AppSandboxEntitlement: 1 + AllowNetworkServer: 0 + AllowNetworkClient: 0 + AllowCamera: 0 + AllowMicrophone: 0 + AllowUsb: 0 + AllowPrint: 0 + AllowBluetooth: 0 + AllowAddressBook: 0 + AllowLocation: 0 + AllowCalendars: 0 + AllowUserSelectedReadOnly: 0 + AllowUserSelectedReadWrite: 0 + AllowDownloadsReadOnly: 0 + AllowDownloadsReadWrite: 0 + AllowPicturesReadOnly: 0 + AllowPicturesReadWrite: 0 + AllowMusicReadOnly: 0 + AllowMusicReadWrite: 0 + AllowMoviesReadOnly: 0 + AllowMoviesReadWrite: 0 diff --git a/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta b/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta index 5ac1fa9..713a880 100644 --- a/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta +++ b/Assets/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 97417ebe3a84845f5839ba872b72c9bf +guid: 07713a1f802534e6d93ff92c62ac2385 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Assets/GPGSIds.cs b/Assets/GPGSIds.cs new file mode 100644 index 0000000..2bb8a21 --- /dev/null +++ b/Assets/GPGSIds.cs @@ -0,0 +1,30 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// This file is automatically generated DO NOT EDIT! +/// +/// These are the constants defined in the Play Games Console for Game Services +/// Resources. +/// + + +public static class GPGSIds +{ + public const string achievement_test_achievement = "CgkIscfzgrYeEAIQAw"; // + +} + diff --git a/Assets/StashSamples/Scripts/AppleGameCenterExampleScript.cs.meta b/Assets/GPGSIds.cs.meta similarity index 83% rename from Assets/StashSamples/Scripts/AppleGameCenterExampleScript.cs.meta rename to Assets/GPGSIds.cs.meta index f52dee3..575b8c3 100644 --- a/Assets/StashSamples/Scripts/AppleGameCenterExampleScript.cs.meta +++ b/Assets/GPGSIds.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 11f3e06233e6b4e60bd0fa696dc1ff98 +guid: d93d5a37a0254457c9a58e8f8fd83b4c MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Stash/Images.meta b/Assets/Plugins.meta similarity index 77% rename from Assets/Stash/Images.meta rename to Assets/Plugins.meta index f1639d7..4d4e403 100644 --- a/Assets/Stash/Images.meta +++ b/Assets/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 342cd680cb37b4bcfa9583b0aff94ca5 +guid: 42b3327003e274d009cfecb2b4d997e1 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Plugins/Android.meta b/Assets/Plugins/Android.meta new file mode 100644 index 0000000..1457b3c --- /dev/null +++ b/Assets/Plugins/Android.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 55b3d3261cf89455a847d409d7e1e9bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar b/Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar new file mode 100644 index 0000000..0669512 Binary files /dev/null and b/Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar differ diff --git a/Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar.meta b/Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar.meta new file mode 100644 index 0000000..633f69e --- /dev/null +++ b/Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 0b6d151f3708d42c89d1e8364a787158 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar b/Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar new file mode 100644 index 0000000..98ec886 Binary files /dev/null and b/Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar differ diff --git a/Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar.meta b/Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar.meta new file mode 100644 index 0000000..e3216f4 --- /dev/null +++ b/Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 800ca5e3819ba4dd394d8f3e9253753a +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar b/Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar new file mode 100644 index 0000000..f876595 Binary files /dev/null and b/Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar.meta b/Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar.meta new file mode 100644 index 0000000..e3adc10 --- /dev/null +++ b/Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: d57d633f231bc47a1b13b7c1d8417a93 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar b/Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar new file mode 100644 index 0000000..337f4c4 Binary files /dev/null and b/Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar.meta new file mode 100644 index 0000000..77d504b --- /dev/null +++ b/Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 882b453f7b79547909e8bfb3c722dc55 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar b/Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar new file mode 100644 index 0000000..78ac06c Binary files /dev/null and b/Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar differ diff --git a/Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar.meta b/Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar.meta new file mode 100644 index 0000000..820e17d --- /dev/null +++ b/Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 1766686244d2644339183ee4d09276fe +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar b/Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar new file mode 100644 index 0000000..de447ec Binary files /dev/null and b/Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar.meta new file mode 100644 index 0000000..c8d5fd2 --- /dev/null +++ b/Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 06d91646b1e6147bb9252d43dab884f3 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.core.core-1.2.0.aar b/Assets/Plugins/Android/androidx.core.core-1.2.0.aar new file mode 100644 index 0000000..e8be07b Binary files /dev/null and b/Assets/Plugins/Android/androidx.core.core-1.2.0.aar differ diff --git a/Assets/Plugins/Android/androidx.core.core-1.2.0.aar.meta b/Assets/Plugins/Android/androidx.core.core-1.2.0.aar.meta new file mode 100644 index 0000000..117ffb5 --- /dev/null +++ b/Assets/Plugins/Android/androidx.core.core-1.2.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 12887a9ac677a447991ba3899905031a +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar b/Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar new file mode 100644 index 0000000..cd1494a Binary files /dev/null and b/Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar.meta new file mode 100644 index 0000000..0e4abaa --- /dev/null +++ b/Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 2f4de10d3746e43be99383c8dc6cc45a +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar b/Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar new file mode 100644 index 0000000..73e70ac Binary files /dev/null and b/Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar.meta new file mode 100644 index 0000000..d3cd8df --- /dev/null +++ b/Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 022c1f529c76246bdb6a01e5b1d70930 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar b/Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar new file mode 100644 index 0000000..79fd550 Binary files /dev/null and b/Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar.meta new file mode 100644 index 0000000..485c568 --- /dev/null +++ b/Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 2b5d03ddbb0344d1e8d9cfb77a230c56 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar b/Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar new file mode 100644 index 0000000..a9968c7 Binary files /dev/null and b/Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar.meta new file mode 100644 index 0000000..04ff0bf --- /dev/null +++ b/Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 7a3012c21ae7e46e6a1decdda7407484 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar b/Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar new file mode 100644 index 0000000..7a5c360 Binary files /dev/null and b/Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar.meta new file mode 100644 index 0000000..ab7186a --- /dev/null +++ b/Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 9373ccca7647d4b69a8e98320068b304 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar b/Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar new file mode 100644 index 0000000..bccf86f Binary files /dev/null and b/Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar.meta new file mode 100644 index 0000000..61d7cc2 --- /dev/null +++ b/Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: d8522e0a6f6c94d1f96bf468a7076e41 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar new file mode 100644 index 0000000..01275eb Binary files /dev/null and b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar.meta new file mode 100644 index 0000000..27b103a --- /dev/null +++ b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: bdd202ea1ae6844b78d51947c7048eee +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar new file mode 100644 index 0000000..2980f60 Binary files /dev/null and b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar.meta new file mode 100644 index 0000000..6ad1f8a --- /dev/null +++ b/Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 062cb22267a3845ccbb5d79045863561 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar new file mode 100644 index 0000000..6c3f095 Binary files /dev/null and b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar differ diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar.meta b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar.meta new file mode 100644 index 0000000..a700de7 --- /dev/null +++ b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 30fc668a6e8e74885945936e4b4e3aad +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar new file mode 100644 index 0000000..27b091c Binary files /dev/null and b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar.meta b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar.meta new file mode 100644 index 0000000..08cb3af --- /dev/null +++ b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: c57a7253739d44c49a85f7238c9df100 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar new file mode 100644 index 0000000..5583b9f Binary files /dev/null and b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar.meta b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar.meta new file mode 100644 index 0000000..66a0ae3 --- /dev/null +++ b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: d1a4964f6d41549eab31d2e09b0e8120 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar new file mode 100644 index 0000000..0809d72 Binary files /dev/null and b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar.meta b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar.meta new file mode 100644 index 0000000..6831a04 --- /dev/null +++ b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 7508c4f66108e4ae7b13ca9234b58577 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar new file mode 100644 index 0000000..b142a70 Binary files /dev/null and b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar.meta b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar.meta new file mode 100644 index 0000000..8f29489 --- /dev/null +++ b/Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: d63092b080c5848c2ace352a8a71d862 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar b/Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar new file mode 100644 index 0000000..32c5774 Binary files /dev/null and b/Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar.meta new file mode 100644 index 0000000..fcc080c --- /dev/null +++ b/Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 9da02505d0fc648c1baffeb30f6e1b9f +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar b/Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar new file mode 100644 index 0000000..e9074ee Binary files /dev/null and b/Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar.meta new file mode 100644 index 0000000..0e60d28 --- /dev/null +++ b/Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: f9911549d6a9440e18f60daf9c631b46 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.print.print-1.0.0.aar b/Assets/Plugins/Android/androidx.print.print-1.0.0.aar new file mode 100644 index 0000000..7bb51fd Binary files /dev/null and b/Assets/Plugins/Android/androidx.print.print-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.print.print-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.print.print-1.0.0.aar.meta new file mode 100644 index 0000000..ba332fd --- /dev/null +++ b/Assets/Plugins/Android/androidx.print.print-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: d383ca7d3f5744150a383a61a6fcd1d9 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar b/Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar new file mode 100644 index 0000000..ebee0ee Binary files /dev/null and b/Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar.meta new file mode 100644 index 0000000..301cb89 --- /dev/null +++ b/Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: dc3f4fec5d8e24183ac031a2177c8802 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar b/Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar new file mode 100644 index 0000000..71d4748 Binary files /dev/null and b/Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar.meta new file mode 100644 index 0000000..fb54ef9 --- /dev/null +++ b/Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 6ded873b85f854c07b10ff0544fc0561 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar b/Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar new file mode 100644 index 0000000..d4792e0 Binary files /dev/null and b/Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar differ diff --git a/Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar.meta b/Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar.meta new file mode 100644 index 0000000..c2fb82a --- /dev/null +++ b/Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: e274ced82682e454fb65898912f3b704 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar b/Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar new file mode 100644 index 0000000..a766729 Binary files /dev/null and b/Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar differ diff --git a/Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar.meta b/Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar.meta new file mode 100644 index 0000000..0ae1304 --- /dev/null +++ b/Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 740a342228dab4f8b9a1e5a5d90ec701 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar b/Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar new file mode 100644 index 0000000..e20a3b8 Binary files /dev/null and b/Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar differ diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar.meta b/Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar.meta new file mode 100644 index 0000000..37af73c --- /dev/null +++ b/Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: f1cb95c4c2f594411b381229b1d22b69 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar b/Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar new file mode 100644 index 0000000..f5da36f Binary files /dev/null and b/Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar differ diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar.meta b/Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar.meta new file mode 100644 index 0000000..e222553 --- /dev/null +++ b/Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 8bcd4a0daa881468592f2fbbde1098ba +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar b/Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar new file mode 100644 index 0000000..d2ae8e3 Binary files /dev/null and b/Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar differ diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar.meta b/Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar.meta new file mode 100644 index 0000000..6f89bf5 --- /dev/null +++ b/Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 4b0f31e8b5b794676b1110ba45f3cd03 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar b/Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar new file mode 100644 index 0000000..097ea9c Binary files /dev/null and b/Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar differ diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar.meta b/Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar.meta new file mode 100644 index 0000000..32b17de --- /dev/null +++ b/Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 615c929d44bdb4cf8a726e79d927c2fc +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar b/Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar new file mode 100644 index 0000000..e97035d Binary files /dev/null and b/Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar differ diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar.meta b/Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar.meta new file mode 100644 index 0000000..751a47e --- /dev/null +++ b/Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 3ac64b5c5b17e4ca6afe160300601a4c +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar b/Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar new file mode 100644 index 0000000..dca0eb6 Binary files /dev/null and b/Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar differ diff --git a/Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar.meta b/Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar.meta new file mode 100644 index 0000000..97f5562 --- /dev/null +++ b/Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 4abe934a11045440d92c619adb5ebffb +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar b/Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar new file mode 100644 index 0000000..c5baea5 Binary files /dev/null and b/Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar differ diff --git a/Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar.meta b/Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar.meta new file mode 100644 index 0000000..b0b9d59 --- /dev/null +++ b/Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 2224b5272b0534cb8bef107731b464c5 +labels: +- gpsr +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources.meta b/Assets/Resources.meta new file mode 100644 index 0000000..4305b15 --- /dev/null +++ b/Assets/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: afbacec031344484bae3e1ffb89f5f9c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/UnityPlayerAccountSettings.asset b/Assets/Resources/UnityPlayerAccountSettings.asset new file mode 100644 index 0000000..173ab5a --- /dev/null +++ b/Assets/Resources/UnityPlayerAccountSettings.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b58a3bc647e70774b8c7225eb3b51e7e, type: 3} + m_Name: UnityPlayerAccountSettings + m_EditorClassIdentifier: + clientId: + scopeMask: 7 + useCustomDeepLinkUri: 0 + customScheme: + customHost: diff --git a/Assets/Resources/UnityPlayerAccountSettings.asset.meta b/Assets/Resources/UnityPlayerAccountSettings.asset.meta new file mode 100644 index 0000000..3934cf7 --- /dev/null +++ b/Assets/Resources/UnityPlayerAccountSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80db9245fb7aa4f05a3c3845120f0fac +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StashSamples.meta b/Assets/Samples.meta similarity index 100% rename from Assets/StashSamples.meta rename to Assets/Samples.meta diff --git a/Assets/Samples/Assets.meta b/Assets/Samples/Assets.meta new file mode 100644 index 0000000..12330db --- /dev/null +++ b/Assets/Samples/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 970362c088de941e1b24321064143d1c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Assets/StashLogo.obj b/Assets/Samples/Assets/StashLogo.obj new file mode 100644 index 0000000..983e323 --- /dev/null +++ b/Assets/Samples/Assets/StashLogo.obj @@ -0,0 +1,3966 @@ +# WaveFront *.obj file (generated by Cinema 4D) + +mtllib ./STASH_LOGO.mtl + +v 13.798132 2.150625 0.000000 +v 13.798132 -2.143926 0.000000 +v 12.354844 -2.143926 0.000000 +v 12.354844 0.069275 0.000000 +v 11.388617 0.069275 0.000000 +v 11.388617 -2.145728 0.000000 +v 9.940592 -2.145728 0.000000 +v 9.940592 2.150625 0.000000 +v 11.387171 2.150625 0.000000 +v 11.387171 0.406964 0.000000 +v 12.351556 0.406964 0.000000 +v 12.351556 2.150625 0.000000 +v -10.043613 2.150625 0.000000 +v -9.817906 0.716375 0.000000 +v -9.970846 0.716375 0.000000 +v -12.676383 0.716044 0.000000 +v -12.726411 0.713477 0.000000 +v -12.773248 0.706050 0.000000 +v -12.816620 0.694043 0.000000 +v -12.846710 0.682201 0.000000 +v -12.874580 0.668057 0.000000 +v -12.900117 0.651729 0.000000 +v -12.923202 0.633336 0.000000 +v -12.943722 0.612994 0.000000 +v -12.961560 0.590823 0.000000 +v -12.976600 0.566940 0.000000 +v -12.988726 0.541462 0.000000 +v -12.997824 0.514508 0.000000 +v -13.003777 0.486196 0.000000 +v -13.006470 0.456643 0.000000 +v -13.006396 0.436309 0.000000 +v -13.003398 0.404950 0.000000 +v -12.997415 0.375357 0.000000 +v -12.988633 0.347261 0.000000 +v -12.977197 0.320772 0.000000 +v -12.963254 0.296001 0.000000 +v -12.946950 0.273058 0.000000 +v -12.928432 0.252053 0.000000 +v -12.907845 0.233096 0.000000 +v -12.885335 0.216298 0.000000 +v -12.861050 0.201768 0.000000 +v -12.835135 0.189617 0.000000 +v -12.807737 0.179955 0.000000 +v -12.779001 0.172892 0.000000 +v -12.749074 0.168538 0.000000 +v -12.718103 0.167004 0.000000 +v -12.686233 0.168400 0.000000 +v -12.664559 0.171012 0.000000 +v -12.631517 0.177535 0.000000 +v -11.387711 0.491197 0.000000 +v -11.216337 0.524496 0.000000 +v -11.046202 0.537939 0.000000 +v -10.878878 0.532301 0.000000 +v -10.715940 0.508355 0.000000 +v -10.558961 0.466877 0.000000 +v -10.409514 0.408639 0.000000 +v -10.269175 0.334417 0.000000 +v -10.170843 0.268727 0.000000 +v -10.079183 0.194807 0.000000 +v -9.994859 0.112984 0.000000 +v -9.918534 0.023586 0.000000 +v -9.850873 -0.073061 0.000000 +v -9.792539 -0.176632 0.000000 +v -9.759159 -0.249363 0.000000 +v -9.730417 -0.324929 0.000000 +v -9.691814 -0.463758 0.000000 +v -9.669907 -0.604045 0.000000 +v -9.664021 -0.744686 0.000000 +v -9.673482 -0.884573 0.000000 +v -9.697616 -1.022602 0.000000 +v -9.735747 -1.157666 0.000000 +v -9.787203 -1.288661 0.000000 +v -9.851307 -1.414481 0.000000 +v -9.927386 -1.534019 0.000000 +v -10.014766 -1.646170 0.000000 +v -10.112771 -1.749829 0.000000 +v -10.220727 -1.843890 0.000000 +v -10.337960 -1.927247 0.000000 +v -10.463796 -1.998794 0.000000 +v -10.597559 -2.057427 0.000000 +v -10.690806 -2.088794 0.000000 +v -10.836284 -2.123444 0.000000 +v -10.995176 -2.144199 0.000000 +v -11.155438 -2.150921 0.000000 +v -14.008306 -2.152124 0.000000 +v -14.008306 -0.717875 0.000000 +v -11.039995 -0.717695 0.000000 +v -10.972937 -0.717991 0.000000 +v -10.906681 -0.712675 0.000000 +v -10.876099 -0.705716 0.000000 +v -10.846988 -0.695759 0.000000 +v -10.819508 -0.683000 0.000000 +v -10.793820 -0.667633 0.000000 +v -10.770084 -0.649855 0.000000 +v -10.748462 -0.629860 0.000000 +v -10.729113 -0.607844 0.000000 +v -10.712198 -0.584002 0.000000 +v -10.697878 -0.558529 0.000000 +v -10.686314 -0.531621 0.000000 +v -10.677666 -0.503472 0.000000 +v -10.673191 -0.481665 0.000000 +v -10.670514 -0.459352 0.000000 +v -10.669875 -0.429548 0.000000 +v -10.672551 -0.400169 0.000000 +v -10.678440 -0.371488 0.000000 +v -10.687437 -0.343777 0.000000 +v -10.699439 -0.317307 0.000000 +v -10.714344 -0.292353 0.000000 +v -10.732048 -0.269186 0.000000 +v -10.747101 -0.253147 0.000000 +v -10.763627 -0.238381 0.000000 +v -10.781581 -0.225005 0.000000 +v -10.800922 -0.213131 0.000000 +v -10.821605 -0.202876 0.000000 +v -10.843586 -0.194354 0.000000 +v -10.858940 -0.189692 0.000000 +v -10.874839 -0.185886 0.000000 +v -10.913310 -0.179876 0.000000 +v -10.957971 -0.177230 0.000000 +v -11.008424 -0.178834 0.000000 +v -11.063737 -0.185356 0.000000 +v -11.122284 -0.197146 0.000000 +v -12.298731 -0.495498 0.000000 +v -12.445059 -0.525010 0.000000 +v -12.590419 -0.540174 0.000000 +v -12.733910 -0.541285 0.000000 +v -12.874628 -0.528640 0.000000 +v -13.011674 -0.502534 0.000000 +v -13.144144 -0.463263 0.000000 +v -13.271136 -0.411123 0.000000 +v -13.391750 -0.346409 0.000000 +v -13.505083 -0.269418 0.000000 +v -13.610234 -0.180446 0.000000 +v -13.706299 -0.079788 0.000000 +v -13.771844 0.003197 0.000000 +v -13.831392 0.092463 0.000000 +v -13.867260 0.158000 0.000000 +v -13.941281 0.342126 0.000000 +v -14.008306 0.530454 0.000000 +v -14.008306 0.928857 0.000000 +v -13.992352 0.970462 0.000000 +v -13.978853 1.012631 0.000000 +v -13.935353 1.167589 0.000000 +v -13.878712 1.314093 0.000000 +v -13.819300 1.432372 0.000000 +v -13.749506 1.543416 0.000000 +v -13.668994 1.646754 0.000000 +v -13.593470 1.726640 0.000000 +v -13.510075 1.800572 0.000000 +v -13.437560 1.855247 0.000000 +v -13.359784 1.905797 0.000000 +v -13.260569 1.959430 0.000000 +v -13.026520 2.056463 0.000000 +v -12.776036 2.150625 0.000000 +v 0.671779 2.150625 0.000000 +v 9.619130 2.150625 0.000000 +v 9.619130 0.084596 0.000000 +v 9.575981 0.080709 0.000000 +v 9.547357 0.079364 0.000000 +v 7.045027 0.162990 0.000000 +v 6.762906 0.183903 0.000000 +v 6.520190 0.225228 0.000000 +v 6.315087 0.280749 0.000000 +v 6.145371 0.343897 0.000000 +v 5.981845 0.422389 0.000000 +v 5.825052 0.517153 0.000000 +v 5.724529 0.589829 0.000000 +v 5.627400 0.670426 0.000000 +v 5.121098 1.150886 0.000000 +v 4.637777 1.654997 0.000000 +v 4.525953 1.764433 0.000000 +v 4.438288 1.835423 0.000000 +v 4.346810 1.895849 0.000000 +v 4.267304 1.937444 0.000000 +v 4.184512 1.970486 0.000000 +v 4.115717 1.990390 0.000000 +v 4.044484 2.004183 0.000000 +v 3.970665 2.011583 0.000000 +v 3.894111 2.012305 0.000000 +v 3.814673 2.006067 0.000000 +v 3.730424 1.992038 0.000000 +v 3.649413 1.970987 0.000000 +v 3.571918 1.943269 0.000000 +v 3.498216 1.909237 0.000000 +v 3.428586 1.869245 0.000000 +v 3.363305 1.823648 0.000000 +v 3.302650 1.772800 0.000000 +v 3.246901 1.717054 0.000000 +v 3.196334 1.656764 0.000000 +v 3.151227 1.592285 0.000000 +v 3.111858 1.523970 0.000000 +v 3.078506 1.452173 0.000000 +v 3.051447 1.377249 0.000000 +v 3.030959 1.299552 0.000000 +v 3.017321 1.219434 0.000000 +v 3.012171 1.164853 0.000000 +v 3.010565 1.081490 0.000000 +v 3.016384 0.997360 0.000000 +v 3.029322 0.915750 0.000000 +v 3.049119 0.836947 0.000000 +v 3.075515 0.761240 0.000000 +v 3.108250 0.688917 0.000000 +v 3.147065 0.620265 0.000000 +v 3.191699 0.555572 0.000000 +v 3.241893 0.495127 0.000000 +v 3.297387 0.439216 0.000000 +v 3.357922 0.388129 0.000000 +v 3.423236 0.342152 0.000000 +v 3.517309 0.289297 0.000000 +v 3.618802 0.246723 0.000000 +v 3.727100 0.215111 0.000000 +v 3.783608 0.203630 0.000000 +v 3.871103 0.192052 0.000000 +v 5.245469 0.082282 0.000000 +v 8.780164 -0.209942 0.000000 +v 8.872209 -0.222069 0.000000 +v 8.947368 -0.239407 0.000000 +v 9.019215 -0.263065 0.000000 +v 9.087878 -0.292955 0.000000 +v 9.153487 -0.328993 0.000000 +v 9.226343 -0.378693 0.000000 +v 9.285777 -0.427755 0.000000 +v 9.342566 -0.482692 0.000000 +v 9.405770 -0.555951 0.000000 +v 9.461526 -0.635776 0.000000 +v 9.509599 -0.721227 0.000000 +v 9.549751 -0.811365 0.000000 +v 9.581747 -0.905252 0.000000 +v 9.605351 -1.001949 0.000000 +v 9.620327 -1.100517 0.000000 +v 9.626438 -1.200016 0.000000 +v 9.623450 -1.299509 0.000000 +v 9.611126 -1.398056 0.000000 +v 9.589229 -1.494718 0.000000 +v 9.566383 -1.565413 0.000000 +v 9.537920 -1.634123 0.000000 +v 9.493678 -1.719839 0.000000 +v 9.444421 -1.797047 0.000000 +v 9.390221 -1.865990 0.000000 +v 9.331153 -1.926915 0.000000 +v 9.267289 -1.980064 0.000000 +v 9.198703 -2.025683 0.000000 +v 9.125468 -2.064015 0.000000 +v 9.047657 -2.095305 0.000000 +v 8.965343 -2.119798 0.000000 +v 8.856231 -2.141228 0.000000 +v 8.764055 -2.151320 0.000000 +v 8.642846 -2.155522 0.000000 +v 0.968239 -2.152124 0.000000 +v 0.805753 -2.152124 0.000000 +v 0.711589 -1.811389 0.000000 +v 0.589729 -1.488569 0.000000 +v 0.440273 -1.183195 0.000000 +v 0.263319 -0.894795 0.000000 +v 0.058967 -0.622900 0.000000 +v -0.172682 -0.367040 0.000000 +v -0.470724 -0.093659 0.000000 +v -0.646365 -0.585798 0.000000 +v -0.647913 -0.591906 0.000000 +v -0.648835 -0.598348 0.000000 +v -0.649159 -0.607380 0.000000 +v -0.648534 -0.616819 0.000000 +v -0.646559 -0.629031 0.000000 +v -0.642680 -0.644015 0.000000 +v -0.635464 -0.663964 0.000000 +v -0.626594 -0.683101 0.000000 +v -0.615567 -0.702599 0.000000 +v -0.488197 -0.928714 0.000000 +v -0.382971 -1.163122 0.000000 +v -0.300097 -1.405833 0.000000 +v -0.262158 -1.551256 0.000000 +v -0.231936 -1.699510 0.000000 +v -0.174443 -2.146007 0.000000 +v -1.622469 -2.146007 0.000000 +v -1.672719 -1.879184 0.000000 +v -1.846493 -1.969370 0.000000 +v -2.026254 -2.041358 0.000000 +v -2.256578 -2.107486 0.000000 +v -2.489809 -2.149186 0.000000 +v -2.722366 -2.168683 0.000000 +v -2.995500 -2.165906 0.000000 +v -3.256318 -2.138212 0.000000 +v -3.498630 -2.089446 0.000000 +v -3.646835 -2.047129 0.000000 +v -3.813865 -1.985204 0.000000 +v -3.970926 -1.909357 0.000000 +v -4.090571 -1.836716 0.000000 +v -4.199307 -1.755276 0.000000 +v -4.278002 -1.683648 0.000000 +v -4.348967 -1.606150 0.000000 +v -4.411866 -1.522674 0.000000 +v -4.466368 -1.433116 0.000000 +v -4.512140 -1.337368 0.000000 +v -4.548848 -1.235323 0.000000 +v -4.576160 -1.126877 0.000000 +v -4.590277 -1.041277 0.000000 +v -4.598781 -0.951971 0.000000 +v -4.600172 -0.805052 0.000000 +v -4.590011 -0.693076 0.000000 +v -4.570062 -0.586020 0.000000 +v -4.540543 -0.483865 0.000000 +v -4.501668 -0.386592 0.000000 +v -4.453656 -0.294181 0.000000 +v -4.396721 -0.206611 0.000000 +v -4.331081 -0.123865 0.000000 +v -4.237118 -0.027184 0.000000 +v -4.130312 0.062031 0.000000 +v -4.060240 0.111991 0.000000 +v -3.960013 0.174459 0.000000 +v -3.807338 0.252947 0.000000 +v -3.649988 0.315412 0.000000 +v -3.488626 0.362505 0.000000 +v -3.323917 0.394877 0.000000 +v -3.135447 0.414510 0.000000 +v -2.944529 0.417262 0.000000 +v -1.867015 0.322079 0.000000 +v -1.784944 0.704861 0.000000 +v -6.665110 0.704861 0.000000 +v -6.348960 -0.361413 0.000000 +v -6.203252 -1.100260 0.000000 +v -6.148009 -1.619401 0.000000 +v -6.137541 -2.146773 0.000000 +v -7.945884 -2.146773 0.000000 +v -7.356128 0.718813 0.000000 +v -9.359627 0.718813 0.000000 +v -9.909671 2.150625 0.000000 +v -1.015896 2.150625 0.000000 +v -0.991887 2.132377 0.000000 +v -0.988613 2.130740 0.000000 +v -0.986598 2.129937 0.000000 +v -0.984541 2.129286 0.000000 +v -0.869958 2.092467 0.000000 +v -0.764847 2.047508 0.000000 +v -0.669417 1.994611 0.000000 +v -0.583874 1.933975 0.000000 +v -0.526328 1.883540 0.000000 +v -0.474547 1.828950 0.000000 +v -0.428618 1.770289 0.000000 +v -0.388628 1.707642 0.000000 +v -0.354664 1.641093 0.000000 +v -0.326813 1.570727 0.000000 +v -0.305163 1.496629 0.000000 +v -0.286092 1.392171 0.000000 +v -0.278405 1.281429 0.000000 +v -0.278895 1.223764 0.000000 +v -0.285120 1.134470 0.000000 +v -0.441824 -0.076948 0.000000 +v -0.387168 -0.081749 0.000000 +v 1.820420 -0.135918 0.000000 +v 2.422276 -0.162786 0.000000 +v 3.021000 -0.219636 0.000000 +v 3.158569 -0.244507 0.000000 +v 3.316954 -0.288954 0.000000 +v 3.468452 -0.347868 0.000000 +v 3.637089 -0.432815 0.000000 +v 3.819982 -0.548266 0.000000 +v 4.014456 -0.697176 0.000000 +v 4.198428 -0.861194 0.000000 +v 5.034010 -1.737409 0.000000 +v 5.104636 -1.803536 0.000000 +v 5.179738 -1.860835 0.000000 +v 5.258723 -1.909240 0.000000 +v 5.340996 -1.948680 0.000000 +v 5.425961 -1.979088 0.000000 +v 5.513024 -2.000394 0.000000 +v 5.601591 -2.012532 0.000000 +v 5.691066 -2.015431 0.000000 +v 5.780855 -2.009024 0.000000 +v 5.870363 -1.993243 0.000000 +v 5.958996 -1.968018 0.000000 +v 6.024538 -1.942860 0.000000 +v 6.089003 -1.912324 0.000000 +v 6.171687 -1.863572 0.000000 +v 6.247783 -1.807188 0.000000 +v 6.316953 -1.743871 0.000000 +v 6.378856 -1.674324 0.000000 +v 6.433155 -1.599245 0.000000 +v 6.479510 -1.519337 0.000000 +v 6.517582 -1.435300 0.000000 +v 6.547032 -1.347834 0.000000 +v 6.567522 -1.257641 0.000000 +v 6.578713 -1.165421 0.000000 +v 6.580266 -1.071875 0.000000 +v 6.574901 -1.001267 0.000000 +v 6.563782 -0.930603 0.000000 +v 6.540810 -0.840268 0.000000 +v 6.508848 -0.753510 0.000000 +v 6.468458 -0.670931 0.000000 +v 6.420205 -0.593136 0.000000 +v 6.364653 -0.520728 0.000000 +v 6.302365 -0.454311 0.000000 +v 6.233905 -0.394487 0.000000 +v 6.159836 -0.341861 0.000000 +v 6.080723 -0.297037 0.000000 +v 5.997130 -0.260617 0.000000 +v 5.909620 -0.233205 0.000000 +v 5.841756 -0.218921 0.000000 +v 5.772243 -0.210298 0.000000 +v 1.757318 0.106680 0.000000 +v 0.733847 0.219160 0.000000 +v 0.628830 0.243128 0.000000 +v 0.530108 0.279137 0.000000 +v 0.438060 0.326291 0.000000 +v 0.353065 0.383694 0.000000 +v 0.275499 0.450451 0.000000 +v 0.205743 0.525666 0.000000 +v 0.144174 0.608443 0.000000 +v 0.091172 0.697887 0.000000 +v 0.047113 0.793102 0.000000 +v 0.012377 0.893193 0.000000 +v -0.012657 0.997263 0.000000 +v -0.027612 1.104418 0.000000 +v -0.032108 1.213762 0.000000 +v -0.025768 1.324398 0.000000 +v -0.008213 1.435432 0.000000 +v 0.009908 1.509233 0.000000 +v 0.046995 1.618940 0.000000 +v 0.084209 1.700547 0.000000 +v 0.127972 1.774900 0.000000 +v 0.177934 1.842349 0.000000 +v 0.233744 1.903244 0.000000 +v 0.295051 1.957937 0.000000 +v 0.361505 2.006777 0.000000 +v 0.447551 2.058154 0.000000 +v 0.555858 2.108888 0.000000 +v -2.343406 -1.101337 0.000000 +v -2.254269 -1.090359 0.000000 +v -2.142760 -1.066169 0.000000 +v -2.112463 -1.054410 0.000000 +v -2.086034 -1.040789 0.000000 +v -2.068769 -1.029402 0.000000 +v -2.053708 -1.017050 0.000000 +v -2.040863 -1.003768 0.000000 +v -2.030247 -0.989591 0.000000 +v -2.024414 -0.979661 0.000000 +v -2.019580 -0.969358 0.000000 +v -2.015749 -0.958695 0.000000 +v -2.012925 -0.947681 0.000000 +v -2.011112 -0.936327 0.000000 +v -2.010312 -0.924643 0.000000 +v -2.011021 -0.906521 0.000000 +v -2.014031 -0.887717 0.000000 +v -2.019355 -0.868264 0.000000 +v -2.027005 -0.848198 0.000000 +v -2.036993 -0.827555 0.000000 +v -2.049330 -0.806369 0.000000 +v -2.082584 -0.758563 0.000000 +v -2.120425 -0.713279 0.000000 +v -2.158766 -0.674608 0.000000 +v -2.199765 -0.639773 0.000000 +v -2.332829 -0.546368 0.000000 +v -2.471814 -0.467752 0.000000 +v -2.598129 -0.411150 0.000000 +v -2.728693 -0.365972 0.000000 +v -2.863374 -0.332268 0.000000 +v -2.981991 -0.312545 0.000000 +v -3.123965 -0.300274 0.000000 +v -3.233452 -0.299059 0.000000 +v -3.280167 -0.303618 0.000000 +v -3.310249 -0.309515 0.000000 +v -3.339018 -0.318240 0.000000 +v -3.359496 -0.326921 0.000000 +v -3.378845 -0.337651 0.000000 +v -3.396899 -0.350628 0.000000 +v -3.413488 -0.366046 0.000000 +v -3.428448 -0.384104 0.000000 +v -3.441609 -0.404996 0.000000 +v -3.449301 -0.420597 0.000000 +v -3.456070 -0.437603 0.000000 +v -3.463575 -0.463302 0.000000 +v -3.467622 -0.487922 0.000000 +v -3.468462 -0.511511 0.000000 +v -3.466341 -0.534115 0.000000 +v -3.461510 -0.555782 0.000000 +v -3.454217 -0.576559 0.000000 +v -3.444711 -0.596492 0.000000 +v -3.433240 -0.615630 0.000000 +v -3.415320 -0.639990 0.000000 +v -3.389530 -0.668738 0.000000 +v -3.343144 -0.711317 0.000000 +v -3.288596 -0.755167 0.000000 +v -3.157996 -0.847721 0.000000 +v -3.038093 -0.916771 0.000000 +v -2.912456 -0.974869 0.000000 +v -2.761262 -1.028087 0.000000 +v -2.601297 -1.067503 0.000000 +v -2.475155 -1.088170 0.000000 +v 13.798132 2.150625 1.000000 +v 13.798132 -2.143926 1.000000 +v 12.354844 -2.143926 1.000000 +v 12.354844 0.069275 1.000000 +v 11.388617 0.069275 1.000000 +v 11.388617 -2.145728 1.000000 +v 9.940592 -2.145728 1.000000 +v 9.940592 2.150625 1.000000 +v 11.387171 2.150625 1.000000 +v 11.387171 0.406964 1.000000 +v 12.351556 0.406964 1.000000 +v 12.351556 2.150625 1.000000 +v -10.043613 2.150625 1.000000 +v -9.817906 0.716375 1.000000 +v -9.970846 0.716375 1.000000 +v -12.676383 0.716044 1.000000 +v -12.726411 0.713477 1.000000 +v -12.773248 0.706050 1.000000 +v -12.816620 0.694043 1.000000 +v -12.846710 0.682201 1.000000 +v -12.874580 0.668057 1.000000 +v -12.900117 0.651729 1.000000 +v -12.923202 0.633336 1.000000 +v -12.943722 0.612994 1.000000 +v -12.961560 0.590823 1.000000 +v -12.976600 0.566940 1.000000 +v -12.988726 0.541462 1.000000 +v -12.997824 0.514508 1.000000 +v -13.003777 0.486196 1.000000 +v -13.006470 0.456643 1.000000 +v -13.006396 0.436309 1.000000 +v -13.003398 0.404950 1.000000 +v -12.997415 0.375357 1.000000 +v -12.988633 0.347261 1.000000 +v -12.977197 0.320772 1.000000 +v -12.963254 0.296001 1.000000 +v -12.946950 0.273058 1.000000 +v -12.928432 0.252053 1.000000 +v -12.907845 0.233096 1.000000 +v -12.885335 0.216298 1.000000 +v -12.861050 0.201768 1.000000 +v -12.835135 0.189617 1.000000 +v -12.807737 0.179955 1.000000 +v -12.779001 0.172892 1.000000 +v -12.749074 0.168538 1.000000 +v -12.718103 0.167004 1.000000 +v -12.686233 0.168400 1.000000 +v -12.664559 0.171012 1.000000 +v -12.631517 0.177535 1.000000 +v -11.387711 0.491197 1.000000 +v -11.216337 0.524496 1.000000 +v -11.046202 0.537939 1.000000 +v -10.878878 0.532301 1.000000 +v -10.715940 0.508355 1.000000 +v -10.558961 0.466877 1.000000 +v -10.409514 0.408639 1.000000 +v -10.269175 0.334417 1.000000 +v -10.170843 0.268727 1.000000 +v -10.079183 0.194807 1.000000 +v -9.994859 0.112984 1.000000 +v -9.918534 0.023586 1.000000 +v -9.850873 -0.073061 1.000000 +v -9.792539 -0.176632 1.000000 +v -9.759159 -0.249363 1.000000 +v -9.730417 -0.324929 1.000000 +v -9.691814 -0.463758 1.000000 +v -9.669907 -0.604045 1.000000 +v -9.664021 -0.744686 1.000000 +v -9.673482 -0.884573 1.000000 +v -9.697616 -1.022602 1.000000 +v -9.735747 -1.157666 1.000000 +v -9.787203 -1.288661 1.000000 +v -9.851307 -1.414481 1.000000 +v -9.927386 -1.534019 1.000000 +v -10.014766 -1.646170 1.000000 +v -10.112771 -1.749829 1.000000 +v -10.220727 -1.843890 1.000000 +v -10.337960 -1.927247 1.000000 +v -10.463796 -1.998794 1.000000 +v -10.597559 -2.057427 1.000000 +v -10.690806 -2.088794 1.000000 +v -10.836284 -2.123444 1.000000 +v -10.995176 -2.144199 1.000000 +v -11.155438 -2.150921 1.000000 +v -14.008306 -2.152124 1.000000 +v -14.008306 -0.717875 1.000000 +v -11.039995 -0.717695 1.000000 +v -10.972937 -0.717991 1.000000 +v -10.906681 -0.712675 1.000000 +v -10.876099 -0.705716 1.000000 +v -10.846988 -0.695759 1.000000 +v -10.819508 -0.683000 1.000000 +v -10.793820 -0.667633 1.000000 +v -10.770084 -0.649855 1.000000 +v -10.748462 -0.629860 1.000000 +v -10.729113 -0.607844 1.000000 +v -10.712198 -0.584002 1.000000 +v -10.697878 -0.558529 1.000000 +v -10.686314 -0.531621 1.000000 +v -10.677666 -0.503472 1.000000 +v -10.673191 -0.481665 1.000000 +v -10.670514 -0.459352 1.000000 +v -10.669875 -0.429548 1.000000 +v -10.672551 -0.400169 1.000000 +v -10.678440 -0.371488 1.000000 +v -10.687437 -0.343777 1.000000 +v -10.699439 -0.317307 1.000000 +v -10.714344 -0.292353 1.000000 +v -10.732048 -0.269186 1.000000 +v -10.747101 -0.253147 1.000000 +v -10.763627 -0.238381 1.000000 +v -10.781581 -0.225005 1.000000 +v -10.800922 -0.213131 1.000000 +v -10.821605 -0.202876 1.000000 +v -10.843586 -0.194354 1.000000 +v -10.858940 -0.189692 1.000000 +v -10.874839 -0.185886 1.000000 +v -10.913310 -0.179876 1.000000 +v -10.957971 -0.177230 1.000000 +v -11.008424 -0.178834 1.000000 +v -11.063737 -0.185356 1.000000 +v -11.122284 -0.197146 1.000000 +v -12.298731 -0.495498 1.000000 +v -12.445059 -0.525010 1.000000 +v -12.590419 -0.540174 1.000000 +v -12.733910 -0.541285 1.000000 +v -12.874628 -0.528640 1.000000 +v -13.011674 -0.502534 1.000000 +v -13.144144 -0.463263 1.000000 +v -13.271136 -0.411123 1.000000 +v -13.391750 -0.346409 1.000000 +v -13.505083 -0.269418 1.000000 +v -13.610234 -0.180446 1.000000 +v -13.706299 -0.079788 1.000000 +v -13.771844 0.003197 1.000000 +v -13.831392 0.092463 1.000000 +v -13.867260 0.158000 1.000000 +v -13.941281 0.342126 1.000000 +v -14.008306 0.530454 1.000000 +v -14.008306 0.928857 1.000000 +v -13.992352 0.970462 1.000000 +v -13.978853 1.012631 1.000000 +v -13.935353 1.167589 1.000000 +v -13.878712 1.314093 1.000000 +v -13.819300 1.432372 1.000000 +v -13.749506 1.543416 1.000000 +v -13.668994 1.646754 1.000000 +v -13.593470 1.726640 1.000000 +v -13.510075 1.800572 1.000000 +v -13.437560 1.855247 1.000000 +v -13.359784 1.905797 1.000000 +v -13.260569 1.959430 1.000000 +v -13.026520 2.056463 1.000000 +v -12.776036 2.150625 1.000000 +v 0.671779 2.150625 1.000000 +v 9.619130 2.150625 1.000000 +v 9.619130 0.084596 1.000000 +v 9.575981 0.080709 1.000000 +v 9.547357 0.079364 1.000000 +v 7.045027 0.162990 1.000000 +v 6.762906 0.183903 1.000000 +v 6.520190 0.225228 1.000000 +v 6.315087 0.280749 1.000000 +v 6.145371 0.343897 1.000000 +v 5.981845 0.422389 1.000000 +v 5.825052 0.517153 1.000000 +v 5.724529 0.589829 1.000000 +v 5.627400 0.670426 1.000000 +v 5.121098 1.150886 1.000000 +v 4.637777 1.654997 1.000000 +v 4.525953 1.764433 1.000000 +v 4.438288 1.835423 1.000000 +v 4.346810 1.895849 1.000000 +v 4.267304 1.937444 1.000000 +v 4.184512 1.970486 1.000000 +v 4.115717 1.990390 1.000000 +v 4.044484 2.004183 1.000000 +v 3.970665 2.011583 1.000000 +v 3.894111 2.012305 1.000000 +v 3.814673 2.006067 1.000000 +v 3.730424 1.992038 1.000000 +v 3.649413 1.970987 1.000000 +v 3.571918 1.943269 1.000000 +v 3.498216 1.909237 1.000000 +v 3.428586 1.869245 1.000000 +v 3.363305 1.823648 1.000000 +v 3.302650 1.772800 1.000000 +v 3.246901 1.717054 1.000000 +v 3.196334 1.656764 1.000000 +v 3.151227 1.592285 1.000000 +v 3.111858 1.523970 1.000000 +v 3.078506 1.452173 1.000000 +v 3.051447 1.377249 1.000000 +v 3.030959 1.299552 1.000000 +v 3.017321 1.219434 1.000000 +v 3.012171 1.164853 1.000000 +v 3.010565 1.081490 1.000000 +v 3.016384 0.997360 1.000000 +v 3.029322 0.915750 1.000000 +v 3.049119 0.836947 1.000000 +v 3.075515 0.761240 1.000000 +v 3.108250 0.688917 1.000000 +v 3.147065 0.620265 1.000000 +v 3.191699 0.555572 1.000000 +v 3.241893 0.495127 1.000000 +v 3.297387 0.439216 1.000000 +v 3.357922 0.388129 1.000000 +v 3.423236 0.342152 1.000000 +v 3.517309 0.289297 1.000000 +v 3.618802 0.246723 1.000000 +v 3.727100 0.215111 1.000000 +v 3.783608 0.203630 1.000000 +v 3.871103 0.192052 1.000000 +v 5.245469 0.082282 1.000000 +v 8.780164 -0.209942 1.000000 +v 8.872209 -0.222069 1.000000 +v 8.947368 -0.239407 1.000000 +v 9.019215 -0.263065 1.000000 +v 9.087878 -0.292955 1.000000 +v 9.153487 -0.328993 1.000000 +v 9.226343 -0.378693 1.000000 +v 9.285777 -0.427755 1.000000 +v 9.342566 -0.482692 1.000000 +v 9.405770 -0.555951 1.000000 +v 9.461526 -0.635776 1.000000 +v 9.509599 -0.721227 1.000000 +v 9.549751 -0.811365 1.000000 +v 9.581747 -0.905252 1.000000 +v 9.605351 -1.001949 1.000000 +v 9.620327 -1.100517 1.000000 +v 9.626438 -1.200016 1.000000 +v 9.623450 -1.299509 1.000000 +v 9.611126 -1.398056 1.000000 +v 9.589229 -1.494718 1.000000 +v 9.566383 -1.565413 1.000000 +v 9.537920 -1.634123 1.000000 +v 9.493678 -1.719839 1.000000 +v 9.444421 -1.797047 1.000000 +v 9.390221 -1.865990 1.000000 +v 9.331153 -1.926915 1.000000 +v 9.267289 -1.980064 1.000000 +v 9.198703 -2.025683 1.000000 +v 9.125468 -2.064015 1.000000 +v 9.047657 -2.095305 1.000000 +v 8.965343 -2.119798 1.000000 +v 8.856231 -2.141228 1.000000 +v 8.764055 -2.151320 1.000000 +v 8.642846 -2.155522 1.000000 +v 0.968239 -2.152124 1.000000 +v 0.805753 -2.152124 1.000000 +v 0.711589 -1.811389 1.000000 +v 0.589729 -1.488569 1.000000 +v 0.440273 -1.183195 1.000000 +v 0.263319 -0.894795 1.000000 +v 0.058967 -0.622900 1.000000 +v -0.172682 -0.367040 1.000000 +v -0.470724 -0.093659 1.000000 +v -0.646365 -0.585798 1.000000 +v -0.647913 -0.591906 1.000000 +v -0.648835 -0.598348 1.000000 +v -0.649159 -0.607380 1.000000 +v -0.648534 -0.616819 1.000000 +v -0.646559 -0.629031 1.000000 +v -0.642680 -0.644015 1.000000 +v -0.635464 -0.663964 1.000000 +v -0.626594 -0.683101 1.000000 +v -0.615567 -0.702599 1.000000 +v -0.488197 -0.928714 1.000000 +v -0.382971 -1.163122 1.000000 +v -0.300097 -1.405833 1.000000 +v -0.262158 -1.551256 1.000000 +v -0.231936 -1.699510 1.000000 +v -0.174443 -2.146007 1.000000 +v -1.622469 -2.146007 1.000000 +v -1.672719 -1.879184 1.000000 +v -1.846493 -1.969370 1.000000 +v -2.026254 -2.041358 1.000000 +v -2.256578 -2.107486 1.000000 +v -2.489809 -2.149186 1.000000 +v -2.722366 -2.168683 1.000000 +v -2.995500 -2.165906 1.000000 +v -3.256318 -2.138212 1.000000 +v -3.498630 -2.089446 1.000000 +v -3.646835 -2.047129 1.000000 +v -3.813865 -1.985204 1.000000 +v -3.970926 -1.909357 1.000000 +v -4.090571 -1.836716 1.000000 +v -4.199307 -1.755276 1.000000 +v -4.278002 -1.683648 1.000000 +v -4.348967 -1.606150 1.000000 +v -4.411866 -1.522674 1.000000 +v -4.466368 -1.433116 1.000000 +v -4.512140 -1.337368 1.000000 +v -4.548848 -1.235323 1.000000 +v -4.576160 -1.126877 1.000000 +v -4.590277 -1.041277 1.000000 +v -4.598781 -0.951971 1.000000 +v -4.600172 -0.805052 1.000000 +v -4.590011 -0.693076 1.000000 +v -4.570062 -0.586020 1.000000 +v -4.540543 -0.483865 1.000000 +v -4.501668 -0.386592 1.000000 +v -4.453656 -0.294181 1.000000 +v -4.396721 -0.206611 1.000000 +v -4.331081 -0.123865 1.000000 +v -4.237118 -0.027184 1.000000 +v -4.130312 0.062031 1.000000 +v -4.060240 0.111991 1.000000 +v -3.960013 0.174459 1.000000 +v -3.807338 0.252947 1.000000 +v -3.649988 0.315412 1.000000 +v -3.488626 0.362505 1.000000 +v -3.323917 0.394877 1.000000 +v -3.135447 0.414510 1.000000 +v -2.944529 0.417262 1.000000 +v -1.867015 0.322079 1.000000 +v -1.784944 0.704861 1.000000 +v -6.665110 0.704861 1.000000 +v -6.348960 -0.361413 1.000000 +v -6.203252 -1.100260 1.000000 +v -6.148009 -1.619401 1.000000 +v -6.137541 -2.146773 1.000000 +v -7.945884 -2.146773 1.000000 +v -7.356128 0.718813 1.000000 +v -9.359627 0.718813 1.000000 +v -9.909671 2.150625 1.000000 +v -1.015896 2.150625 1.000000 +v -0.991887 2.132377 1.000000 +v -0.988613 2.130740 1.000000 +v -0.986598 2.129937 1.000000 +v -0.984541 2.129286 1.000000 +v -0.869958 2.092467 1.000000 +v -0.764847 2.047508 1.000000 +v -0.669417 1.994611 1.000000 +v -0.583874 1.933975 1.000000 +v -0.526328 1.883540 1.000000 +v -0.474547 1.828950 1.000000 +v -0.428618 1.770289 1.000000 +v -0.388628 1.707642 1.000000 +v -0.354664 1.641093 1.000000 +v -0.326813 1.570727 1.000000 +v -0.305163 1.496629 1.000000 +v -0.286092 1.392171 1.000000 +v -0.278405 1.281429 1.000000 +v -0.278895 1.223764 1.000000 +v -0.285120 1.134470 1.000000 +v -0.441824 -0.076948 1.000000 +v -0.387168 -0.081749 1.000000 +v 1.820420 -0.135918 1.000000 +v 2.422276 -0.162786 1.000000 +v 3.021000 -0.219636 1.000000 +v 3.158569 -0.244507 1.000000 +v 3.316954 -0.288954 1.000000 +v 3.468452 -0.347868 1.000000 +v 3.637089 -0.432815 1.000000 +v 3.819982 -0.548266 1.000000 +v 4.014456 -0.697176 1.000000 +v 4.198428 -0.861194 1.000000 +v 5.034010 -1.737409 1.000000 +v 5.104636 -1.803536 1.000000 +v 5.179738 -1.860835 1.000000 +v 5.258723 -1.909240 1.000000 +v 5.340996 -1.948680 1.000000 +v 5.425961 -1.979088 1.000000 +v 5.513024 -2.000394 1.000000 +v 5.601591 -2.012532 1.000000 +v 5.691066 -2.015431 1.000000 +v 5.780855 -2.009024 1.000000 +v 5.870363 -1.993243 1.000000 +v 5.958996 -1.968018 1.000000 +v 6.024538 -1.942860 1.000000 +v 6.089003 -1.912324 1.000000 +v 6.171687 -1.863572 1.000000 +v 6.247783 -1.807188 1.000000 +v 6.316953 -1.743871 1.000000 +v 6.378856 -1.674324 1.000000 +v 6.433155 -1.599245 1.000000 +v 6.479510 -1.519337 1.000000 +v 6.517582 -1.435300 1.000000 +v 6.547032 -1.347834 1.000000 +v 6.567522 -1.257641 1.000000 +v 6.578713 -1.165421 1.000000 +v 6.580266 -1.071875 1.000000 +v 6.574901 -1.001267 1.000000 +v 6.563782 -0.930603 1.000000 +v 6.540810 -0.840268 1.000000 +v 6.508848 -0.753510 1.000000 +v 6.468458 -0.670931 1.000000 +v 6.420205 -0.593136 1.000000 +v 6.364653 -0.520728 1.000000 +v 6.302365 -0.454311 1.000000 +v 6.233905 -0.394487 1.000000 +v 6.159836 -0.341861 1.000000 +v 6.080723 -0.297037 1.000000 +v 5.997130 -0.260617 1.000000 +v 5.909620 -0.233205 1.000000 +v 5.841756 -0.218921 1.000000 +v 5.772243 -0.210298 1.000000 +v 1.757318 0.106680 1.000000 +v 0.733847 0.219160 1.000000 +v 0.628830 0.243128 1.000000 +v 0.530108 0.279137 1.000000 +v 0.438060 0.326291 1.000000 +v 0.353065 0.383694 1.000000 +v 0.275499 0.450451 1.000000 +v 0.205743 0.525666 1.000000 +v 0.144174 0.608443 1.000000 +v 0.091172 0.697887 1.000000 +v 0.047113 0.793102 1.000000 +v 0.012377 0.893193 1.000000 +v -0.012657 0.997263 1.000000 +v -0.027612 1.104418 1.000000 +v -0.032108 1.213762 1.000000 +v -0.025768 1.324398 1.000000 +v -0.008213 1.435432 1.000000 +v 0.009908 1.509233 1.000000 +v 0.046995 1.618940 1.000000 +v 0.084209 1.700547 1.000000 +v 0.127972 1.774900 1.000000 +v 0.177934 1.842349 1.000000 +v 0.233744 1.903244 1.000000 +v 0.295051 1.957937 1.000000 +v 0.361505 2.006777 1.000000 +v 0.447551 2.058154 1.000000 +v 0.555858 2.108888 1.000000 +v -2.343406 -1.101337 1.000000 +v -2.254269 -1.090359 1.000000 +v -2.142760 -1.066169 1.000000 +v -2.112463 -1.054410 1.000000 +v -2.086034 -1.040789 1.000000 +v -2.068769 -1.029402 1.000000 +v -2.053708 -1.017050 1.000000 +v -2.040863 -1.003768 1.000000 +v -2.030247 -0.989591 1.000000 +v -2.024414 -0.979661 1.000000 +v -2.019580 -0.969358 1.000000 +v -2.015749 -0.958695 1.000000 +v -2.012925 -0.947681 1.000000 +v -2.011112 -0.936327 1.000000 +v -2.010312 -0.924643 1.000000 +v -2.011021 -0.906521 1.000000 +v -2.014031 -0.887717 1.000000 +v -2.019355 -0.868264 1.000000 +v -2.027005 -0.848198 1.000000 +v -2.036993 -0.827555 1.000000 +v -2.049330 -0.806369 1.000000 +v -2.082584 -0.758563 1.000000 +v -2.120425 -0.713279 1.000000 +v -2.158766 -0.674608 1.000000 +v -2.199765 -0.639773 1.000000 +v -2.332829 -0.546368 1.000000 +v -2.471814 -0.467752 1.000000 +v -2.598129 -0.411150 1.000000 +v -2.728693 -0.365972 1.000000 +v -2.863374 -0.332268 1.000000 +v -2.981991 -0.312545 1.000000 +v -3.123965 -0.300274 1.000000 +v -3.233452 -0.299059 1.000000 +v -3.280167 -0.303618 1.000000 +v -3.310249 -0.309515 1.000000 +v -3.339018 -0.318240 1.000000 +v -3.359496 -0.326921 1.000000 +v -3.378845 -0.337651 1.000000 +v -3.396899 -0.350628 1.000000 +v -3.413488 -0.366046 1.000000 +v -3.428448 -0.384104 1.000000 +v -3.441609 -0.404996 1.000000 +v -3.449301 -0.420597 1.000000 +v -3.456070 -0.437603 1.000000 +v -3.463575 -0.463302 1.000000 +v -3.467622 -0.487922 1.000000 +v -3.468462 -0.511511 1.000000 +v -3.466341 -0.534115 1.000000 +v -3.461510 -0.555782 1.000000 +v -3.454217 -0.576559 1.000000 +v -3.444711 -0.596492 1.000000 +v -3.433240 -0.615630 1.000000 +v -3.415320 -0.639990 1.000000 +v -3.389530 -0.668738 1.000000 +v -3.343144 -0.711317 1.000000 +v -3.288596 -0.755167 1.000000 +v -3.157996 -0.847721 1.000000 +v -3.038093 -0.916771 1.000000 +v -2.912456 -0.974869 1.000000 +v -2.761262 -1.028087 1.000000 +v -2.601297 -1.067503 1.000000 +v -2.475155 -1.088170 1.000000 +# 974 vertices + +vn 1.000000 0.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.987843 0.155456 0.000000 +vn 0.000061 -1.000000 0.000000 +vn 0.025691 -0.999670 0.000000 +vn 0.104070 -0.994570 0.000000 +vn 0.212038 -0.977261 0.000000 +vn 0.316954 -0.948441 0.000000 +vn 0.409851 -0.912153 0.000000 +vn 0.496227 -0.868193 0.000000 +vn 0.581698 -0.813405 0.000000 +vn 0.664554 -0.747240 0.000000 +vn 0.742750 -0.669569 0.000000 +vn 0.814022 -0.580834 0.000000 +vn 0.876079 -0.482168 0.000000 +vn 0.926845 -0.375444 0.000000 +vn 0.964729 -0.263245 0.000000 +vn 0.988912 -0.148506 0.000000 +vn 0.999049 -0.043604 0.000000 +vn 0.998777 0.049447 0.000000 +vn 0.989157 0.146861 0.000000 +vn 0.968612 0.248579 0.000000 +vn 0.937559 0.347827 0.000000 +vn 0.895999 0.444056 0.000000 +vn 0.844457 0.535624 0.000000 +vn 0.783701 0.621139 0.000000 +vn 0.714703 0.699428 0.000000 +vn 0.638590 0.769547 0.000000 +vn 0.556485 0.830858 0.000000 +vn 0.469569 0.882896 0.000000 +vn 0.379017 0.925390 0.000000 +vn 0.285972 0.958238 0.000000 +vn 0.191547 0.981483 0.000000 +vn 0.096824 0.995302 0.000000 +vn 0.002866 0.999996 0.000000 +vn -0.081767 0.996651 0.000000 +vn -0.156786 0.987633 0.000000 +vn -0.219178 0.975685 0.000000 +vn -0.217714 0.976013 0.000000 +vn -0.134969 0.990850 0.000000 +vn -0.022581 0.999745 0.000000 +vn 0.089680 0.995971 0.000000 +vn 0.200748 0.979643 0.000000 +vn 0.309775 0.950810 0.000000 +vn 0.415990 0.909369 0.000000 +vn 0.512179 0.858878 0.000000 +vn 0.592223 0.805774 0.000000 +vn 0.662763 0.748829 0.000000 +vn 0.729254 0.684243 0.000000 +vn 0.790773 0.612110 0.000000 +vn 0.846263 0.532765 0.000000 +vn 0.890840 0.454318 0.000000 +vn 0.922279 0.386525 0.000000 +vn 0.950070 0.312036 0.000000 +vn 0.977388 0.211453 0.000000 +vn 0.995166 0.098208 0.000000 +vn 0.999917 -0.012852 0.000000 +vn 0.992771 -0.120024 0.000000 +vn 0.974988 -0.222256 0.000000 +vn 0.947739 -0.319048 0.000000 +vn 0.911964 -0.410271 0.000000 +vn 0.868316 -0.496012 0.000000 +vn 0.817158 -0.576414 0.000000 +vn 0.758606 -0.651549 0.000000 +vn 0.692591 -0.721330 0.000000 +vn 0.618953 -0.785428 0.000000 +vn 0.537563 -0.843224 0.000000 +vn 0.448468 -0.893799 0.000000 +vn 0.360497 -0.932761 0.000000 +vn 0.275548 -0.961287 0.000000 +vn 0.180858 -0.983509 0.000000 +vn 0.085800 -0.996312 0.000000 +vn 0.021169 -0.999776 0.000000 +vn 0.000422 -1.000000 0.000000 +vn -0.000061 1.000000 0.000000 +vn 0.002176 0.999998 0.000000 +vn -0.037815 0.999285 0.000000 +vn -0.151319 0.988485 0.000000 +vn -0.273129 0.961977 0.000000 +vn -0.372892 0.927875 0.000000 +vn -0.467884 0.883790 0.000000 +vn -0.557170 0.830398 0.000000 +vn -0.640066 0.768320 0.000000 +vn -0.715993 0.698107 0.000000 +vn -0.784430 0.620217 0.000000 +vn -0.844809 0.535068 0.000000 +vn -0.896485 0.443074 0.000000 +vn -0.938689 0.344764 0.000000 +vn -0.968851 0.247643 0.000000 +vn -0.987082 0.160218 0.000000 +vn -0.997523 0.070345 0.000000 +vn -0.999397 -0.034709 0.000000 +vn -0.989265 -0.146131 0.000000 +vn -0.966846 -0.255358 0.000000 +vn -0.932388 -0.361459 0.000000 +vn -0.886040 -0.463608 0.000000 +vn -0.827886 -0.560897 0.000000 +vn -0.762838 -0.646590 0.000000 +vn -0.698387 -0.715720 0.000000 +vn -0.632478 -0.774579 0.000000 +vn -0.560884 -0.827895 0.000000 +vn -0.484207 -0.874954 0.000000 +vn -0.403270 -0.915081 0.000000 +vn -0.326230 -0.945291 0.000000 +vn -0.261790 -0.965125 0.000000 +vn -0.193743 -0.981052 0.000000 +vn -0.106861 -0.994274 0.000000 +vn -0.013689 -0.999906 0.000000 +vn 0.074503 -0.997221 0.000000 +vn 0.157385 -0.987537 0.000000 +vn 0.221688 -0.975118 0.000000 +vn 0.221831 -0.975085 0.000000 +vn 0.150901 -0.988549 0.000000 +vn 0.055816 -0.998441 0.000000 +vn -0.040926 -0.999162 0.000000 +vn -0.138482 -0.990365 0.000000 +vn -0.235971 -0.971760 0.000000 +vn -0.332445 -0.943123 0.000000 +vn -0.426861 -0.904317 0.000000 +vn -0.518062 -0.855343 0.000000 +vn -0.604778 -0.796394 0.000000 +vn -0.685648 -0.727933 0.000000 +vn -0.754903 -0.655837 0.000000 +vn -0.808968 -0.587853 0.000000 +vn -0.855375 -0.518009 0.000000 +vn -0.904113 -0.427295 0.000000 +vn -0.935162 -0.354220 0.000000 +vn -0.985422 -0.170129 0.000000 +vn -0.983285 0.182073 0.000000 +vn -0.943423 0.331593 0.000000 +vn -0.957745 0.287618 0.000000 +vn -0.948827 0.315796 0.000000 +vn -0.914228 0.405201 0.000000 +vn -0.871123 0.491065 0.000000 +vn -0.818785 0.574101 0.000000 +vn -0.758617 0.651537 0.000000 +vn -0.695698 0.718335 0.000000 +vn -0.633205 0.773984 0.000000 +vn -0.573844 0.818965 0.000000 +vn -0.510662 0.859781 0.000000 +vn -0.429823 0.902913 0.000000 +vn -0.367478 0.930032 0.000000 +vn -0.178821 0.983882 0.000000 +vn -0.171939 0.985108 0.000000 +vn 0.089724 -0.995967 0.000000 +vn 0.068338 -0.997662 0.000000 +vn 0.006766 -0.999977 0.000000 +vn -0.053673 -0.998559 0.000000 +vn -0.121020 -0.992650 0.000000 +vn -0.214816 -0.976655 0.000000 +vn -0.305331 -0.952246 0.000000 +vn -0.391133 -0.920334 0.000000 +vn -0.475539 -0.879695 0.000000 +vn -0.552043 -0.833816 0.000000 +vn -0.612576 -0.790412 0.000000 +vn -0.663831 -0.747882 0.000000 +vn -0.705290 -0.708919 0.000000 +vn -0.710725 -0.703470 0.000000 +vn -0.665111 -0.746745 0.000000 +vn -0.590934 -0.806720 0.000000 +vn -0.508018 -0.861346 0.000000 +vn -0.417661 -0.908603 0.000000 +vn -0.324687 -0.945821 0.000000 +vn -0.234254 -0.972175 0.000000 +vn -0.145073 -0.989421 0.000000 +vn -0.054644 -0.998506 0.000000 +vn 0.034456 -0.999406 0.000000 +vn 0.121386 -0.992605 0.000000 +vn 0.208088 -0.978110 0.000000 +vn 0.294435 -0.955671 0.000000 +vn 0.378377 -0.925652 0.000000 +vn 0.459081 -0.888394 0.000000 +vn 0.535853 -0.844311 0.000000 +vn 0.608120 -0.793845 0.000000 +vn 0.675413 -0.737440 0.000000 +vn 0.737340 -0.675522 0.000000 +vn 0.793552 -0.608503 0.000000 +vn 0.843724 -0.536777 0.000000 +vn 0.887529 -0.460751 0.000000 +vn 0.924631 -0.380864 0.000000 +vn 0.954685 -0.297617 0.000000 +vn 0.977356 -0.211603 0.000000 +vn 0.991387 -0.130967 0.000000 +vn 0.998395 -0.056635 0.000000 +vn 0.999690 0.024897 0.000000 +vn 0.993606 0.112899 0.000000 +vn 0.979732 0.200313 0.000000 +vn 0.958014 0.286722 0.000000 +vn 0.928569 0.371159 0.000000 +vn 0.891656 0.452714 0.000000 +vn 0.847647 0.530560 0.000000 +vn 0.797005 0.603972 0.000000 +vn 0.740264 0.672316 0.000000 +vn 0.678010 0.735052 0.000000 +vn 0.610873 0.791729 0.000000 +vn 0.533408 0.845858 0.000000 +vn 0.439048 0.898463 0.000000 +vn 0.334049 0.942556 0.000000 +vn 0.239870 0.970805 0.000000 +vn 0.165245 0.986252 0.000000 +vn 0.105432 0.994426 0.000000 +vn 0.081004 0.996714 0.000000 +vn 0.106539 0.994308 0.000000 +vn 0.177909 0.984047 0.000000 +vn 0.269054 0.963125 0.000000 +vn 0.356332 0.934360 0.000000 +vn 0.440753 0.897628 0.000000 +vn 0.523089 0.852278 0.000000 +vn 0.600695 0.799479 0.000000 +vn 0.666464 0.745537 0.000000 +vn 0.726961 0.686678 0.000000 +vn 0.789515 0.613731 0.000000 +vn 0.846683 0.532097 0.000000 +vn 0.893485 0.449092 0.000000 +vn 0.930962 0.365115 0.000000 +vn 0.959960 0.280136 0.000000 +vn 0.981028 0.193866 0.000000 +vn 0.994380 0.105866 0.000000 +vn 0.999877 0.015659 0.000000 +vn 0.997020 -0.077142 0.000000 +vn 0.984971 -0.172720 0.000000 +vn 0.964390 -0.264484 0.000000 +vn 0.938462 -0.345382 0.000000 +vn 0.907037 -0.421052 0.000000 +vn 0.866731 -0.498776 0.000000 +vn 0.815585 -0.578637 0.000000 +vn 0.753069 -0.657942 0.000000 +vn 0.679788 -0.733408 0.000000 +vn 0.597606 -0.801790 0.000000 +vn 0.509469 -0.860489 0.000000 +vn 0.418934 -0.908017 0.000000 +vn 0.329504 -0.944154 0.000000 +vn 0.239230 -0.970963 0.000000 +vn 0.150913 -0.988547 0.000000 +vn 0.071790 -0.997420 0.000000 +vn 0.017104 -0.999854 0.000000 +vn -0.000221 -1.000000 0.000000 +vn -0.963871 -0.266371 0.000000 +vn -0.950707 -0.310089 0.000000 +vn -0.917897 -0.396819 0.000000 +vn -0.876264 -0.481832 0.000000 +vn -0.826786 -0.562516 0.000000 +vn -0.771154 -0.636649 0.000000 +vn -0.709398 -0.704808 0.000000 +vn -0.675962 -0.736937 0.000000 +vn 0.941816 -0.336128 0.000000 +vn 0.956657 -0.291218 0.000000 +vn 0.981011 -0.193951 0.000000 +vn 0.996040 -0.088909 0.000000 +vn 0.999885 0.015130 0.000000 +vn 0.993597 0.112978 0.000000 +vn 0.978692 0.205334 0.000000 +vn 0.955277 0.295712 0.000000 +vn 0.924695 0.380710 0.000000 +vn 0.889588 0.456763 0.000000 +vn 0.870865 0.491522 0.000000 +vn 0.892712 0.450628 0.000000 +vn 0.930328 0.366728 0.000000 +vn 0.957636 0.287983 0.000000 +vn 0.974087 0.226175 0.000000 +vn 0.986488 0.163836 0.000000 +vn 0.991812 0.127708 0.000000 +vn -0.982725 -0.185072 0.000000 +vn 0.460644 -0.887585 0.000000 +vn 0.416701 -0.909044 0.000000 +vn 0.324277 -0.945962 0.000000 +vn 0.226278 -0.974063 0.000000 +vn 0.129914 -0.991525 0.000000 +vn 0.036731 -0.999325 0.000000 +vn -0.057943 -0.998320 0.000000 +vn -0.151606 -0.988441 0.000000 +vn -0.236114 -0.971725 0.000000 +vn -0.311320 -0.950305 0.000000 +vn -0.391681 -0.920101 0.000000 +vn -0.477465 -0.878651 0.000000 +vn -0.559887 -0.828569 0.000000 +vn -0.637023 -0.770844 0.000000 +vn -0.706044 -0.708168 0.000000 +vn -0.768962 -0.639294 0.000000 +vn -0.827465 -0.561517 0.000000 +vn -0.879347 -0.476182 0.000000 +vn -0.922758 -0.385380 0.000000 +vn -0.956506 -0.291712 0.000000 +vn -0.979044 -0.203648 0.000000 +vn -0.991666 -0.128836 0.000000 +vn -0.998638 -0.052180 0.000000 +vn -0.999179 0.040505 0.000000 +vn -0.990581 0.136930 0.000000 +vn -0.973032 0.230669 0.000000 +vn -0.945799 0.324753 0.000000 +vn -0.909099 0.416581 0.000000 +vn -0.863902 0.503659 0.000000 +vn -0.811806 0.583927 0.000000 +vn -0.751223 0.660049 0.000000 +vn -0.680008 0.733204 0.000000 +vn -0.611253 0.791435 0.000000 +vn -0.555007 0.831845 0.000000 +vn -0.493493 0.869750 0.000000 +vn -0.413573 0.910471 0.000000 +vn -0.324923 0.945740 0.000000 +vn -0.236746 0.971572 0.000000 +vn -0.148382 0.988930 0.000000 +vn -0.059070 0.998254 0.000000 +vn 0.036839 0.999321 0.000000 +vn 0.087993 0.996121 0.000000 +vn -0.977779 0.209641 0.000000 +vn 0.958745 0.284268 0.000000 +vn 0.970986 0.239137 0.000000 +vn 0.988717 0.149796 0.000000 +vn 0.998021 0.062889 0.000000 +vn 0.999803 0.019846 0.000000 +vn -0.979472 0.201582 0.000000 +vn -0.933488 -0.358608 0.000000 +vn 0.319267 0.947665 0.000000 +vn 0.528408 0.848990 0.000000 +vn 0.409099 0.912490 0.000000 +vn 0.336291 0.941758 0.000000 +vn 0.303852 0.952719 0.000000 +vn 0.349973 0.936760 0.000000 +vn 0.439606 0.898191 0.000000 +vn 0.532359 0.846519 0.000000 +vn 0.619523 0.784979 0.000000 +vn 0.693058 0.720882 0.000000 +vn 0.757300 0.653068 0.000000 +vn 0.816082 0.577936 0.000000 +vn 0.867810 0.496896 0.000000 +vn 0.911289 0.411766 0.000000 +vn 0.945856 0.324588 0.000000 +vn 0.973110 0.230342 0.000000 +vn 0.992205 0.124620 0.000000 +vn 0.999538 0.030395 0.000000 +vn 0.999238 -0.039043 0.000000 +vn 0.995091 -0.098960 0.000000 +vn 0.991737 -0.128287 0.000000 +vn 0.087509 0.996164 0.000000 +vn 0.056048 0.998428 0.000000 +vn 0.034565 0.999402 0.000000 +vn 0.069584 0.997576 0.000000 +vn 0.136337 0.990663 0.000000 +vn 0.224300 0.974520 0.000000 +vn 0.316686 0.948530 0.000000 +vn 0.406620 0.913597 0.000000 +vn 0.492408 0.870365 0.000000 +vn 0.571455 0.820633 0.000000 +vn 0.637153 0.770737 0.000000 +vn 0.695148 0.718866 0.000000 +vn 0.703862 0.710336 0.000000 +vn 0.645840 0.763473 0.000000 +vn 0.565276 0.824902 0.000000 +vn 0.478029 0.878344 0.000000 +vn 0.385132 0.922862 0.000000 +vn 0.287721 0.957714 0.000000 +vn 0.186995 0.982361 0.000000 +vn 0.084196 0.996449 0.000000 +vn -0.019418 0.999811 0.000000 +vn -0.122569 0.992460 0.000000 +vn -0.223980 0.974594 0.000000 +vn -0.316353 0.948641 0.000000 +vn -0.393503 0.919323 0.000000 +vn -0.468476 0.883476 0.000000 +vn -0.552380 0.833592 0.000000 +vn -0.636129 0.771583 0.000000 +vn -0.712018 0.702161 0.000000 +vn -0.779627 0.626244 0.000000 +vn -0.838702 0.544590 0.000000 +vn -0.889055 0.457799 0.000000 +vn -0.930477 0.366351 0.000000 +vn -0.962672 0.270671 0.000000 +vn -0.985232 0.171227 0.000000 +vn -0.997643 0.068624 0.000000 +vn -0.999561 -0.029616 0.000000 +vn -0.993285 -0.115696 0.000000 +vn -0.979558 -0.201164 0.000000 +vn -0.955041 -0.296473 0.000000 +vn -0.919521 -0.393040 0.000000 +vn -0.875157 -0.483839 0.000000 +vn -0.822614 -0.568600 0.000000 +vn -0.762339 -0.647178 0.000000 +vn -0.694569 -0.719426 0.000000 +vn -0.619384 -0.785088 0.000000 +vn -0.536781 -0.843722 0.000000 +vn -0.446802 -0.894633 0.000000 +vn -0.349672 -0.936872 0.000000 +vn -0.252736 -0.967535 0.000000 +vn -0.164682 -0.986347 0.000000 +vn -0.100930 -0.994894 0.000000 +vn -0.093985 -0.995574 0.000000 +vn -0.166152 -0.986100 0.000000 +vn -0.283148 -0.959076 0.000000 +vn -0.400066 -0.916486 0.000000 +vn -0.508731 -0.860926 0.000000 +vn -0.607034 -0.794675 0.000000 +vn -0.693863 -0.720107 0.000000 +vn -0.768925 -0.639339 0.000000 +vn -0.832478 -0.554058 0.000000 +vn -0.885063 -0.465471 0.000000 +vn -0.927281 -0.374365 0.000000 +vn -0.959647 -0.281208 0.000000 +vn -0.982498 -0.186272 0.000000 +vn -0.995963 -0.089762 0.000000 +vn -0.999967 0.008071 0.000000 +vn -0.994278 0.106821 0.000000 +vn -0.980306 0.197483 0.000000 +vn -0.960114 0.279610 0.000000 +vn -0.929802 0.368060 0.000000 +vn -0.887035 0.461701 0.000000 +vn -0.833842 0.552003 0.000000 +vn -0.771439 0.636303 0.000000 +vn -0.702349 0.711832 0.000000 +vn -0.629661 0.776870 0.000000 +vn -0.553063 0.833139 0.000000 +vn -0.469014 0.883190 0.000000 +vn -0.381885 0.924210 0.000000 +vn -0.011464 0.999934 0.000000 +vn -0.167293 0.985907 0.000000 +vn -0.287797 0.957691 0.000000 +vn -0.410540 0.911842 0.000000 +vn -0.505067 0.863080 0.000000 +vn -0.593156 0.805088 0.000000 +vn -0.677618 0.735414 0.000000 +vn -0.761153 0.648573 0.000000 +vn -0.832642 0.553811 0.000000 +vn -0.884720 0.466122 0.000000 +vn -0.924228 0.381842 0.000000 +vn -0.955943 0.293552 0.000000 +vn -0.979122 0.203272 0.000000 +vn -0.993580 0.113133 0.000000 +vn -0.999893 0.014622 0.000000 +vn -0.995111 -0.098759 0.000000 +vn -0.977413 -0.211337 0.000000 +vn -0.950584 -0.310469 0.000000 +vn -0.918146 -0.396242 0.000000 +vn -0.882811 -0.469728 0.000000 +vn -0.843218 -0.537572 0.000000 +vn -0.794915 -0.606721 0.000000 +vn -0.739409 -0.673256 0.000000 +vn -0.679429 -0.733741 0.000000 +vn -0.611664 -0.791118 0.000000 +vn -0.534070 -0.845440 0.000000 +vn -0.451126 -0.892461 0.000000 +vn -0.368318 -0.929700 0.000000 +vn -0.285157 -0.958481 0.000000 +vn -0.203557 -0.979063 0.000000 +vn -0.125161 -0.992136 0.000000 +vn -0.048639 -0.998816 0.000000 +vn 0.043083 -0.999072 0.000000 +vn 0.144915 -0.989444 0.000000 +vn 0.241604 -0.970375 0.000000 +vn 0.340745 -0.940156 0.000000 +vn 0.438241 -0.898857 0.000000 +vn 0.535229 -0.844707 0.000000 +vn 0.633465 -0.773772 0.000000 +vn 0.726965 -0.686675 0.000000 +vn 0.809799 -0.586708 0.000000 +vn 0.872685 -0.488284 0.000000 +vn 0.913715 -0.406357 0.000000 +vn 0.945566 -0.325430 0.000000 +vn 0.975121 -0.221673 0.000000 +vn 0.995079 -0.099086 0.000000 +vn 0.999580 0.028982 0.000000 +vn 0.987786 0.155816 0.000000 +vn 0.961473 0.274901 0.000000 +vn 0.924417 0.381384 0.000000 +vn 0.881163 0.472813 0.000000 +vn 0.832550 0.553949 0.000000 +vn 0.775856 0.630911 0.000000 +vn 0.711129 0.703061 0.000000 +vn 0.651732 0.758449 0.000000 +vn 0.602650 0.798006 0.000000 +vn 0.539223 0.842163 0.000000 +vn 0.459842 0.888001 0.000000 +vn 0.376292 0.926501 0.000000 +vn 0.285969 0.958239 0.000000 +vn 0.200622 0.979669 0.000000 +vn 0.130627 0.991432 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +# 484 normals + +vt 0.000000 1.000000 0.000000 +vt 0.177303 1.000000 0.000000 +vt 0.177303 0.000000 0.000000 +vt 0.000000 0.000000 0.000000 +vt 0.236890 1.000000 0.000000 +vt 0.236890 0.000000 0.000000 +vt 0.328264 1.000000 0.000000 +vt 0.328264 0.000000 0.000000 +vt 0.368155 1.000000 0.000000 +vt 0.368155 0.000000 0.000000 +vt 0.459603 1.000000 0.000000 +vt 0.459603 0.000000 0.000000 +vt 0.519385 1.000000 0.000000 +vt 0.519385 0.000000 0.000000 +vt 0.696763 1.000000 0.000000 +vt 0.696763 0.000000 0.000000 +vt 0.756486 1.000000 0.000000 +vt 0.756486 0.000000 0.000000 +vt 0.828474 1.000000 0.000000 +vt 0.828474 0.000000 0.000000 +vt 0.868289 1.000000 0.000000 +vt 0.868289 0.000000 0.000000 +vt 0.940277 1.000000 0.000000 +vt 0.940277 0.000000 0.000000 +vt 1.000000 1.000000 0.000000 +vt 1.000000 0.000000 0.000000 +vt 0.051602 1.000000 0.000000 +vt 0.051602 0.000000 0.000000 +vt 0.057038 1.000000 0.000000 +vt 0.057038 0.000000 0.000000 +vt 0.153196 1.000000 0.000000 +vt 0.153196 0.000000 0.000000 +vt 0.154977 1.000000 0.000000 +vt 0.154977 0.000000 0.000000 +vt 0.156662 1.000000 0.000000 +vt 0.156662 0.000000 0.000000 +vt 0.158262 1.000000 0.000000 +vt 0.158262 0.000000 0.000000 +vt 0.159411 1.000000 0.000000 +vt 0.159411 0.000000 0.000000 +vt 0.160522 1.000000 0.000000 +vt 0.160522 0.000000 0.000000 +vt 0.161599 1.000000 0.000000 +vt 0.161599 0.000000 0.000000 +vt 0.162648 1.000000 0.000000 +vt 0.162648 0.000000 0.000000 +vt 0.163675 1.000000 0.000000 +vt 0.163675 0.000000 0.000000 +vt 0.164686 1.000000 0.000000 +vt 0.164686 0.000000 0.000000 +vt 0.165689 1.000000 0.000000 +vt 0.165689 0.000000 0.000000 +vt 0.166692 1.000000 0.000000 +vt 0.166692 0.000000 0.000000 +vt 0.167703 1.000000 0.000000 +vt 0.167703 0.000000 0.000000 +vt 0.168732 1.000000 0.000000 +vt 0.168732 0.000000 0.000000 +vt 0.169786 1.000000 0.000000 +vt 0.169786 0.000000 0.000000 +vt 0.170509 1.000000 0.000000 +vt 0.170509 0.000000 0.000000 +vt 0.171629 1.000000 0.000000 +vt 0.171629 0.000000 0.000000 +vt 0.172702 1.000000 0.000000 +vt 0.172702 0.000000 0.000000 +vt 0.173748 1.000000 0.000000 +vt 0.173748 0.000000 0.000000 +vt 0.174773 1.000000 0.000000 +vt 0.174773 0.000000 0.000000 +vt 0.175784 1.000000 0.000000 +vt 0.175784 0.000000 0.000000 +vt 0.176784 1.000000 0.000000 +vt 0.176784 0.000000 0.000000 +vt 0.177779 1.000000 0.000000 +vt 0.177779 0.000000 0.000000 +vt 0.178774 1.000000 0.000000 +vt 0.178774 0.000000 0.000000 +vt 0.179772 1.000000 0.000000 +vt 0.179772 0.000000 0.000000 +vt 0.180778 1.000000 0.000000 +vt 0.180778 0.000000 0.000000 +vt 0.181795 1.000000 0.000000 +vt 0.181795 0.000000 0.000000 +vt 0.182828 1.000000 0.000000 +vt 0.182828 0.000000 0.000000 +vt 0.183879 1.000000 0.000000 +vt 0.183879 0.000000 0.000000 +vt 0.184954 1.000000 0.000000 +vt 0.184954 0.000000 0.000000 +vt 0.186056 1.000000 0.000000 +vt 0.186056 0.000000 0.000000 +vt 0.187190 1.000000 0.000000 +vt 0.187190 0.000000 0.000000 +vt 0.187966 1.000000 0.000000 +vt 0.187966 0.000000 0.000000 +vt 0.189163 1.000000 0.000000 +vt 0.189163 0.000000 0.000000 +vt 0.234753 1.000000 0.000000 +vt 0.234753 0.000000 0.000000 +vt 0.240958 1.000000 0.000000 +vt 0.240958 0.000000 0.000000 +vt 0.247024 1.000000 0.000000 +vt 0.247024 0.000000 0.000000 +vt 0.252974 1.000000 0.000000 +vt 0.252974 0.000000 0.000000 +vt 0.258827 1.000000 0.000000 +vt 0.258827 0.000000 0.000000 +vt 0.264598 1.000000 0.000000 +vt 0.264598 0.000000 0.000000 +vt 0.270299 1.000000 0.000000 +vt 0.270299 0.000000 0.000000 +vt 0.275941 1.000000 0.000000 +vt 0.275941 0.000000 0.000000 +vt 0.280144 1.000000 0.000000 +vt 0.280144 0.000000 0.000000 +vt 0.284329 1.000000 0.000000 +vt 0.284329 0.000000 0.000000 +vt 0.288505 1.000000 0.000000 +vt 0.288505 0.000000 0.000000 +vt 0.292683 1.000000 0.000000 +vt 0.292683 0.000000 0.000000 +vt 0.296876 1.000000 0.000000 +vt 0.296876 0.000000 0.000000 +vt 0.301101 1.000000 0.000000 +vt 0.301101 0.000000 0.000000 +vt 0.303945 1.000000 0.000000 +vt 0.303945 0.000000 0.000000 +vt 0.306818 1.000000 0.000000 +vt 0.306818 0.000000 0.000000 +vt 0.311940 1.000000 0.000000 +vt 0.311940 0.000000 0.000000 +vt 0.316986 1.000000 0.000000 +vt 0.316986 0.000000 0.000000 +vt 0.321989 1.000000 0.000000 +vt 0.321989 0.000000 0.000000 +vt 0.326972 1.000000 0.000000 +vt 0.326972 0.000000 0.000000 +vt 0.331952 1.000000 0.000000 +vt 0.331952 0.000000 0.000000 +vt 0.336940 1.000000 0.000000 +vt 0.336940 0.000000 0.000000 +vt 0.341942 1.000000 0.000000 +vt 0.341942 0.000000 0.000000 +vt 0.346961 1.000000 0.000000 +vt 0.346961 0.000000 0.000000 +vt 0.351997 1.000000 0.000000 +vt 0.351997 0.000000 0.000000 +vt 0.357050 1.000000 0.000000 +vt 0.357050 0.000000 0.000000 +vt 0.362120 1.000000 0.000000 +vt 0.362120 0.000000 0.000000 +vt 0.367209 1.000000 0.000000 +vt 0.367209 0.000000 0.000000 +vt 0.372322 1.000000 0.000000 +vt 0.372322 0.000000 0.000000 +vt 0.377466 1.000000 0.000000 +vt 0.377466 0.000000 0.000000 +vt 0.382657 1.000000 0.000000 +vt 0.382657 0.000000 0.000000 +vt 0.386154 1.000000 0.000000 +vt 0.386154 0.000000 0.000000 +vt 0.391469 1.000000 0.000000 +vt 0.391469 0.000000 0.000000 +vt 0.397164 1.000000 0.000000 +vt 0.397164 0.000000 0.000000 +vt 0.402865 1.000000 0.000000 +vt 0.402865 0.000000 0.000000 +vt 0.504259 1.000000 0.000000 +vt 0.504259 0.000000 0.000000 +vt 0.555234 1.000000 0.000000 +vt 0.555234 0.000000 0.000000 +vt 0.660732 1.000000 0.000000 +vt 0.660732 0.000000 0.000000 +vt 0.663115 1.000000 0.000000 +vt 0.663115 0.000000 0.000000 +vt 0.665478 1.000000 0.000000 +vt 0.665478 0.000000 0.000000 +vt 0.666592 1.000000 0.000000 +vt 0.666592 0.000000 0.000000 +vt 0.667686 1.000000 0.000000 +vt 0.667686 0.000000 0.000000 +vt 0.668763 1.000000 0.000000 +vt 0.668763 0.000000 0.000000 +vt 0.669827 1.000000 0.000000 +vt 0.669827 0.000000 0.000000 +vt 0.670880 1.000000 0.000000 +vt 0.670880 0.000000 0.000000 +vt 0.671927 1.000000 0.000000 +vt 0.671927 0.000000 0.000000 +vt 0.672969 1.000000 0.000000 +vt 0.672969 0.000000 0.000000 +vt 0.674008 1.000000 0.000000 +vt 0.674008 0.000000 0.000000 +vt 0.675047 1.000000 0.000000 +vt 0.675047 0.000000 0.000000 +vt 0.676087 1.000000 0.000000 +vt 0.676087 0.000000 0.000000 +vt 0.677134 1.000000 0.000000 +vt 0.677134 0.000000 0.000000 +vt 0.677925 1.000000 0.000000 +vt 0.677925 0.000000 0.000000 +vt 0.678724 1.000000 0.000000 +vt 0.678724 0.000000 0.000000 +vt 0.679783 1.000000 0.000000 +vt 0.679783 0.000000 0.000000 +vt 0.680832 1.000000 0.000000 +vt 0.680832 0.000000 0.000000 +vt 0.681873 1.000000 0.000000 +vt 0.681873 0.000000 0.000000 +vt 0.682908 1.000000 0.000000 +vt 0.682908 0.000000 0.000000 +vt 0.683941 1.000000 0.000000 +vt 0.683941 0.000000 0.000000 +vt 0.684974 1.000000 0.000000 +vt 0.684974 0.000000 0.000000 +vt 0.686010 1.000000 0.000000 +vt 0.686010 0.000000 0.000000 +vt 0.686792 1.000000 0.000000 +vt 0.686792 0.000000 0.000000 +vt 0.687580 1.000000 0.000000 +vt 0.687580 0.000000 0.000000 +vt 0.688376 1.000000 0.000000 +vt 0.688376 0.000000 0.000000 +vt 0.689182 1.000000 0.000000 +vt 0.689182 0.000000 0.000000 +vt 0.690003 1.000000 0.000000 +vt 0.690003 0.000000 0.000000 +vt 0.690841 1.000000 0.000000 +vt 0.690841 0.000000 0.000000 +vt 0.691411 1.000000 0.000000 +vt 0.691411 0.000000 0.000000 +vt 0.691992 1.000000 0.000000 +vt 0.691992 0.000000 0.000000 +vt 0.693376 1.000000 0.000000 +vt 0.693376 0.000000 0.000000 +vt 0.694966 1.000000 0.000000 +vt 0.694966 0.000000 0.000000 +vt 0.696760 1.000000 0.000000 +vt 0.696760 0.000000 0.000000 +vt 0.698739 1.000000 0.000000 +vt 0.698739 0.000000 0.000000 +vt 0.700862 1.000000 0.000000 +vt 0.700862 0.000000 0.000000 +vt 0.743998 1.000000 0.000000 +vt 0.743998 0.000000 0.000000 +vt 0.749303 1.000000 0.000000 +vt 0.749303 0.000000 0.000000 +vt 0.754498 1.000000 0.000000 +vt 0.754498 0.000000 0.000000 +vt 0.759598 1.000000 0.000000 +vt 0.759598 0.000000 0.000000 +vt 0.764619 1.000000 0.000000 +vt 0.764619 0.000000 0.000000 +vt 0.769578 1.000000 0.000000 +vt 0.769578 0.000000 0.000000 +vt 0.774488 1.000000 0.000000 +vt 0.774488 0.000000 0.000000 +vt 0.779367 1.000000 0.000000 +vt 0.779367 0.000000 0.000000 +vt 0.784232 1.000000 0.000000 +vt 0.784232 0.000000 0.000000 +vt 0.789102 1.000000 0.000000 +vt 0.789102 0.000000 0.000000 +vt 0.793997 1.000000 0.000000 +vt 0.793997 0.000000 0.000000 +vt 0.798943 1.000000 0.000000 +vt 0.798943 0.000000 0.000000 +vt 0.802701 1.000000 0.000000 +vt 0.802701 0.000000 0.000000 +vt 0.806515 1.000000 0.000000 +vt 0.806515 0.000000 0.000000 +vt 0.809170 1.000000 0.000000 +vt 0.809170 0.000000 0.000000 +vt 0.816223 1.000000 0.000000 +vt 0.816223 0.000000 0.000000 +vt 0.823328 1.000000 0.000000 +vt 0.823328 0.000000 0.000000 +vt 0.837487 1.000000 0.000000 +vt 0.837487 0.000000 0.000000 +vt 0.839071 1.000000 0.000000 +vt 0.839071 0.000000 0.000000 +vt 0.840645 1.000000 0.000000 +vt 0.840645 0.000000 0.000000 +vt 0.846365 1.000000 0.000000 +vt 0.846365 0.000000 0.000000 +vt 0.851948 1.000000 0.000000 +vt 0.851948 0.000000 0.000000 +vt 0.856652 1.000000 0.000000 +vt 0.856652 0.000000 0.000000 +vt 0.861313 1.000000 0.000000 +vt 0.861313 0.000000 0.000000 +vt 0.865969 1.000000 0.000000 +vt 0.865969 0.000000 0.000000 +vt 0.869877 1.000000 0.000000 +vt 0.869877 0.000000 0.000000 +vt 0.873838 1.000000 0.000000 +vt 0.873838 0.000000 0.000000 +vt 0.877065 1.000000 0.000000 +vt 0.877065 0.000000 0.000000 +vt 0.880362 1.000000 0.000000 +vt 0.880362 0.000000 0.000000 +vt 0.884371 1.000000 0.000000 +vt 0.884371 0.000000 0.000000 +vt 0.893376 1.000000 0.000000 +vt 0.893376 0.000000 0.000000 +vt 0.902886 1.000000 0.000000 +vt 0.902886 0.000000 0.000000 +vt 0.094679 1.000000 0.000000 +vt 0.094679 0.000000 0.000000 +vt 0.116541 1.000000 0.000000 +vt 0.116541 0.000000 0.000000 +vt 0.116999 1.000000 0.000000 +vt 0.116999 0.000000 0.000000 +vt 0.117303 1.000000 0.000000 +vt 0.117303 0.000000 0.000000 +vt 0.143796 1.000000 0.000000 +vt 0.143796 0.000000 0.000000 +vt 0.146790 1.000000 0.000000 +vt 0.146790 0.000000 0.000000 +vt 0.149395 1.000000 0.000000 +vt 0.149395 0.000000 0.000000 +vt 0.151644 1.000000 0.000000 +vt 0.151644 0.000000 0.000000 +vt 0.153560 1.000000 0.000000 +vt 0.153560 0.000000 0.000000 +vt 0.155479 1.000000 0.000000 +vt 0.155479 0.000000 0.000000 +vt 0.157418 1.000000 0.000000 +vt 0.157418 0.000000 0.000000 +vt 0.158731 1.000000 0.000000 +vt 0.158731 0.000000 0.000000 +vt 0.160066 1.000000 0.000000 +vt 0.160066 0.000000 0.000000 +vt 0.167452 1.000000 0.000000 +vt 0.167452 0.000000 0.000000 +vt 0.174842 1.000000 0.000000 +vt 0.174842 0.000000 0.000000 +vt 0.176498 1.000000 0.000000 +vt 0.176498 0.000000 0.000000 +vt 0.177691 1.000000 0.000000 +vt 0.177691 0.000000 0.000000 +vt 0.178852 1.000000 0.000000 +vt 0.178852 0.000000 0.000000 +vt 0.179801 1.000000 0.000000 +vt 0.179801 0.000000 0.000000 +vt 0.180744 1.000000 0.000000 +vt 0.180744 0.000000 0.000000 +vt 0.181502 1.000000 0.000000 +vt 0.181502 0.000000 0.000000 +vt 0.182270 1.000000 0.000000 +vt 0.182270 0.000000 0.000000 +vt 0.183055 1.000000 0.000000 +vt 0.183055 0.000000 0.000000 +vt 0.183865 1.000000 0.000000 +vt 0.183865 0.000000 0.000000 +vt 0.184708 1.000000 0.000000 +vt 0.184708 0.000000 0.000000 +vt 0.185612 1.000000 0.000000 +vt 0.185612 0.000000 0.000000 +vt 0.186498 1.000000 0.000000 +vt 0.186498 0.000000 0.000000 +vt 0.187369 1.000000 0.000000 +vt 0.187369 0.000000 0.000000 +vt 0.188228 1.000000 0.000000 +vt 0.188228 0.000000 0.000000 +vt 0.189077 1.000000 0.000000 +vt 0.189077 0.000000 0.000000 +vt 0.189920 1.000000 0.000000 +vt 0.189920 0.000000 0.000000 +vt 0.190757 1.000000 0.000000 +vt 0.190757 0.000000 0.000000 +vt 0.191592 1.000000 0.000000 +vt 0.191592 0.000000 0.000000 +vt 0.192424 1.000000 0.000000 +vt 0.192424 0.000000 0.000000 +vt 0.193257 1.000000 0.000000 +vt 0.193257 0.000000 0.000000 +vt 0.194091 1.000000 0.000000 +vt 0.194091 0.000000 0.000000 +vt 0.194929 1.000000 0.000000 +vt 0.194929 0.000000 0.000000 +vt 0.195772 1.000000 0.000000 +vt 0.195772 0.000000 0.000000 +vt 0.196622 1.000000 0.000000 +vt 0.196622 0.000000 0.000000 +vt 0.197482 1.000000 0.000000 +vt 0.197482 0.000000 0.000000 +vt 0.198062 1.000000 0.000000 +vt 0.198062 0.000000 0.000000 +vt 0.198945 1.000000 0.000000 +vt 0.198945 0.000000 0.000000 +vt 0.199837 1.000000 0.000000 +vt 0.199837 0.000000 0.000000 +vt 0.200711 1.000000 0.000000 +vt 0.200711 0.000000 0.000000 +vt 0.201571 1.000000 0.000000 +vt 0.201571 0.000000 0.000000 +vt 0.202420 1.000000 0.000000 +vt 0.202420 0.000000 0.000000 +vt 0.203260 1.000000 0.000000 +vt 0.203260 0.000000 0.000000 +vt 0.204094 1.000000 0.000000 +vt 0.204094 0.000000 0.000000 +vt 0.204926 1.000000 0.000000 +vt 0.204926 0.000000 0.000000 +vt 0.205757 1.000000 0.000000 +vt 0.205757 0.000000 0.000000 +vt 0.206591 1.000000 0.000000 +vt 0.206591 0.000000 0.000000 +vt 0.207429 1.000000 0.000000 +vt 0.207429 0.000000 0.000000 +vt 0.208274 1.000000 0.000000 +vt 0.208274 0.000000 0.000000 +vt 0.209416 1.000000 0.000000 +vt 0.209416 0.000000 0.000000 +vt 0.210581 1.000000 0.000000 +vt 0.210581 0.000000 0.000000 +vt 0.211775 1.000000 0.000000 +vt 0.211775 0.000000 0.000000 +vt 0.212385 1.000000 0.000000 +vt 0.212385 0.000000 0.000000 +vt 0.213319 1.000000 0.000000 +vt 0.213319 0.000000 0.000000 +vt 0.227908 1.000000 0.000000 +vt 0.227908 0.000000 0.000000 +vt 0.265439 1.000000 0.000000 +vt 0.265439 0.000000 0.000000 +vt 0.266421 1.000000 0.000000 +vt 0.266421 0.000000 0.000000 +vt 0.267238 1.000000 0.000000 +vt 0.267238 0.000000 0.000000 +vt 0.268038 1.000000 0.000000 +vt 0.268038 0.000000 0.000000 +vt 0.268831 1.000000 0.000000 +vt 0.268831 0.000000 0.000000 +vt 0.269623 1.000000 0.000000 +vt 0.269623 0.000000 0.000000 +vt 0.270556 1.000000 0.000000 +vt 0.270556 0.000000 0.000000 +vt 0.271371 1.000000 0.000000 +vt 0.271371 0.000000 0.000000 +vt 0.272208 1.000000 0.000000 +vt 0.272208 0.000000 0.000000 +vt 0.273231 1.000000 0.000000 +vt 0.273231 0.000000 0.000000 +vt 0.274262 1.000000 0.000000 +vt 0.274262 0.000000 0.000000 +vt 0.275299 1.000000 0.000000 +vt 0.275299 0.000000 0.000000 +vt 0.276343 1.000000 0.000000 +vt 0.276343 0.000000 0.000000 +vt 0.277393 1.000000 0.000000 +vt 0.277393 0.000000 0.000000 +vt 0.278446 1.000000 0.000000 +vt 0.278446 0.000000 0.000000 +vt 0.279501 1.000000 0.000000 +vt 0.279501 0.000000 0.000000 +vt 0.280556 1.000000 0.000000 +vt 0.280556 0.000000 0.000000 +vt 0.281609 1.000000 0.000000 +vt 0.281609 0.000000 0.000000 +vt 0.282660 1.000000 0.000000 +vt 0.282660 0.000000 0.000000 +vt 0.283709 1.000000 0.000000 +vt 0.283709 0.000000 0.000000 +vt 0.284495 1.000000 0.000000 +vt 0.284495 0.000000 0.000000 +vt 0.285282 1.000000 0.000000 +vt 0.285282 0.000000 0.000000 +vt 0.286303 1.000000 0.000000 +vt 0.286303 0.000000 0.000000 +vt 0.287272 1.000000 0.000000 +vt 0.287272 0.000000 0.000000 +vt 0.288200 1.000000 0.000000 +vt 0.288200 0.000000 0.000000 +vt 0.289098 1.000000 0.000000 +vt 0.289098 0.000000 0.000000 +vt 0.289977 1.000000 0.000000 +vt 0.289977 0.000000 0.000000 +vt 0.290849 1.000000 0.000000 +vt 0.290849 0.000000 0.000000 +vt 0.291724 1.000000 0.000000 +vt 0.291724 0.000000 0.000000 +vt 0.292611 1.000000 0.000000 +vt 0.292611 0.000000 0.000000 +vt 0.293520 1.000000 0.000000 +vt 0.293520 0.000000 0.000000 +vt 0.294696 1.000000 0.000000 +vt 0.294696 0.000000 0.000000 +vt 0.295678 1.000000 0.000000 +vt 0.295678 0.000000 0.000000 +vt 0.296961 1.000000 0.000000 +vt 0.296961 0.000000 0.000000 +vt 0.378172 1.000000 0.000000 +vt 0.378172 0.000000 0.000000 +vt 0.379891 1.000000 0.000000 +vt 0.379891 0.000000 0.000000 +vt 0.383632 1.000000 0.000000 +vt 0.383632 0.000000 0.000000 +vt 0.387283 1.000000 0.000000 +vt 0.387283 0.000000 0.000000 +vt 0.390881 1.000000 0.000000 +vt 0.390881 0.000000 0.000000 +vt 0.394461 1.000000 0.000000 +vt 0.394461 0.000000 0.000000 +vt 0.398060 1.000000 0.000000 +vt 0.398060 0.000000 0.000000 +vt 0.401713 1.000000 0.000000 +vt 0.401713 0.000000 0.000000 +vt 0.405992 1.000000 0.000000 +vt 0.405992 0.000000 0.000000 +vt 0.411522 1.000000 0.000000 +vt 0.411522 0.000000 0.000000 +vt 0.411588 1.000000 0.000000 +vt 0.411588 0.000000 0.000000 +vt 0.411657 1.000000 0.000000 +vt 0.411657 0.000000 0.000000 +vt 0.411753 1.000000 0.000000 +vt 0.411753 0.000000 0.000000 +vt 0.411853 1.000000 0.000000 +vt 0.411853 0.000000 0.000000 +vt 0.411984 1.000000 0.000000 +vt 0.411984 0.000000 0.000000 +vt 0.412148 1.000000 0.000000 +vt 0.412148 0.000000 0.000000 +vt 0.412372 1.000000 0.000000 +vt 0.412372 0.000000 0.000000 +vt 0.412595 1.000000 0.000000 +vt 0.412595 0.000000 0.000000 +vt 0.412832 1.000000 0.000000 +vt 0.412832 0.000000 0.000000 +vt 0.415579 1.000000 0.000000 +vt 0.415579 0.000000 0.000000 +vt 0.418297 1.000000 0.000000 +vt 0.418297 0.000000 0.000000 +vt 0.421011 1.000000 0.000000 +vt 0.421011 0.000000 0.000000 +vt 0.422602 1.000000 0.000000 +vt 0.422602 0.000000 0.000000 +vt 0.424203 1.000000 0.000000 +vt 0.424203 0.000000 0.000000 +vt 0.428967 1.000000 0.000000 +vt 0.428967 0.000000 0.000000 +vt 0.444289 1.000000 0.000000 +vt 0.444289 0.000000 0.000000 +vt 0.447162 1.000000 0.000000 +vt 0.447162 0.000000 0.000000 +vt 0.449234 1.000000 0.000000 +vt 0.449234 0.000000 0.000000 +vt 0.451283 1.000000 0.000000 +vt 0.451283 0.000000 0.000000 +vt 0.453819 1.000000 0.000000 +vt 0.453819 0.000000 0.000000 +vt 0.456326 1.000000 0.000000 +vt 0.456326 0.000000 0.000000 +vt 0.458795 1.000000 0.000000 +vt 0.458795 0.000000 0.000000 +vt 0.461686 1.000000 0.000000 +vt 0.461686 0.000000 0.000000 +vt 0.464461 1.000000 0.000000 +vt 0.464461 0.000000 0.000000 +vt 0.467077 1.000000 0.000000 +vt 0.467077 0.000000 0.000000 +vt 0.468708 1.000000 0.000000 +vt 0.468708 0.000000 0.000000 +vt 0.470593 1.000000 0.000000 +vt 0.470593 0.000000 0.000000 +vt 0.472438 1.000000 0.000000 +vt 0.472438 0.000000 0.000000 +vt 0.473919 1.000000 0.000000 +vt 0.473919 0.000000 0.000000 +vt 0.475357 1.000000 0.000000 +vt 0.475357 0.000000 0.000000 +vt 0.476483 1.000000 0.000000 +vt 0.476483 0.000000 0.000000 +vt 0.477595 1.000000 0.000000 +vt 0.477595 0.000000 0.000000 +vt 0.478701 1.000000 0.000000 +vt 0.478701 0.000000 0.000000 +vt 0.479810 1.000000 0.000000 +vt 0.479810 0.000000 0.000000 +vt 0.480933 1.000000 0.000000 +vt 0.480933 0.000000 0.000000 +vt 0.482081 1.000000 0.000000 +vt 0.482081 0.000000 0.000000 +vt 0.483264 1.000000 0.000000 +vt 0.483264 0.000000 0.000000 +vt 0.484182 1.000000 0.000000 +vt 0.484182 0.000000 0.000000 +vt 0.485132 1.000000 0.000000 +vt 0.485132 0.000000 0.000000 +vt 0.486686 1.000000 0.000000 +vt 0.486686 0.000000 0.000000 +vt 0.487876 1.000000 0.000000 +vt 0.487876 0.000000 0.000000 +vt 0.489028 1.000000 0.000000 +vt 0.489028 0.000000 0.000000 +vt 0.490154 1.000000 0.000000 +vt 0.490154 0.000000 0.000000 +vt 0.491262 1.000000 0.000000 +vt 0.491262 0.000000 0.000000 +vt 0.492364 1.000000 0.000000 +vt 0.492364 0.000000 0.000000 +vt 0.493469 1.000000 0.000000 +vt 0.493469 0.000000 0.000000 +vt 0.494587 1.000000 0.000000 +vt 0.494587 0.000000 0.000000 +vt 0.496014 1.000000 0.000000 +vt 0.496014 0.000000 0.000000 +vt 0.497486 1.000000 0.000000 +vt 0.497486 0.000000 0.000000 +vt 0.498397 1.000000 0.000000 +vt 0.498397 0.000000 0.000000 +vt 0.499647 1.000000 0.000000 +vt 0.499647 0.000000 0.000000 +vt 0.501463 1.000000 0.000000 +vt 0.501463 0.000000 0.000000 +vt 0.503255 1.000000 0.000000 +vt 0.503255 0.000000 0.000000 +vt 0.505033 1.000000 0.000000 +vt 0.505033 0.000000 0.000000 +vt 0.506810 1.000000 0.000000 +vt 0.506810 0.000000 0.000000 +vt 0.508815 1.000000 0.000000 +vt 0.508815 0.000000 0.000000 +vt 0.510835 1.000000 0.000000 +vt 0.510835 0.000000 0.000000 +vt 0.522282 1.000000 0.000000 +vt 0.522282 0.000000 0.000000 +vt 0.526424 1.000000 0.000000 +vt 0.526424 0.000000 0.000000 +vt 0.578065 1.000000 0.000000 +vt 0.578065 0.000000 0.000000 +vt 0.589833 1.000000 0.000000 +vt 0.589833 0.000000 0.000000 +vt 0.597802 1.000000 0.000000 +vt 0.597802 0.000000 0.000000 +vt 0.603327 1.000000 0.000000 +vt 0.603327 0.000000 0.000000 +vt 0.608908 1.000000 0.000000 +vt 0.608908 0.000000 0.000000 +vt 0.628044 1.000000 0.000000 +vt 0.628044 0.000000 0.000000 +vt 0.659002 1.000000 0.000000 +vt 0.659002 0.000000 0.000000 +vt 0.680203 1.000000 0.000000 +vt 0.680203 0.000000 0.000000 +vt 0.696433 1.000000 0.000000 +vt 0.696433 0.000000 0.000000 +vt 0.790545 1.000000 0.000000 +vt 0.790545 0.000000 0.000000 +vt 0.790864 1.000000 0.000000 +vt 0.790864 0.000000 0.000000 +vt 0.790903 1.000000 0.000000 +vt 0.790903 0.000000 0.000000 +vt 0.790926 1.000000 0.000000 +vt 0.790926 0.000000 0.000000 +vt 0.790949 1.000000 0.000000 +vt 0.790949 0.000000 0.000000 +vt 0.792222 1.000000 0.000000 +vt 0.792222 0.000000 0.000000 +vt 0.793432 1.000000 0.000000 +vt 0.793432 0.000000 0.000000 +vt 0.794587 1.000000 0.000000 +vt 0.794587 0.000000 0.000000 +vt 0.795696 1.000000 0.000000 +vt 0.795696 0.000000 0.000000 +vt 0.796506 1.000000 0.000000 +vt 0.796506 0.000000 0.000000 +vt 0.797302 1.000000 0.000000 +vt 0.797302 0.000000 0.000000 +vt 0.798090 1.000000 0.000000 +vt 0.798090 0.000000 0.000000 +vt 0.798877 1.000000 0.000000 +vt 0.798877 0.000000 0.000000 +vt 0.799668 1.000000 0.000000 +vt 0.799668 0.000000 0.000000 +vt 0.800468 1.000000 0.000000 +vt 0.800468 0.000000 0.000000 +vt 0.801285 1.000000 0.000000 +vt 0.801285 0.000000 0.000000 +vt 0.802409 1.000000 0.000000 +vt 0.802409 0.000000 0.000000 +vt 0.803584 1.000000 0.000000 +vt 0.803584 0.000000 0.000000 +vt 0.804194 1.000000 0.000000 +vt 0.804194 0.000000 0.000000 +vt 0.805141 1.000000 0.000000 +vt 0.805141 0.000000 0.000000 +vt 0.818067 1.000000 0.000000 +vt 0.818067 0.000000 0.000000 +vt 0.818647 1.000000 0.000000 +vt 0.818647 0.000000 0.000000 +vt 0.842014 1.000000 0.000000 +vt 0.842014 0.000000 0.000000 +vt 0.848389 1.000000 0.000000 +vt 0.848389 0.000000 0.000000 +vt 0.854753 1.000000 0.000000 +vt 0.854753 0.000000 0.000000 +vt 0.856233 1.000000 0.000000 +vt 0.856233 0.000000 0.000000 +vt 0.857974 1.000000 0.000000 +vt 0.857974 0.000000 0.000000 +vt 0.859694 1.000000 0.000000 +vt 0.859694 0.000000 0.000000 +vt 0.861692 1.000000 0.000000 +vt 0.861692 0.000000 0.000000 +vt 0.863980 1.000000 0.000000 +vt 0.863980 0.000000 0.000000 +vt 0.866572 1.000000 0.000000 +vt 0.866572 0.000000 0.000000 +vt 0.869180 1.000000 0.000000 +vt 0.869180 0.000000 0.000000 +vt 0.881992 1.000000 0.000000 +vt 0.881992 0.000000 0.000000 +vt 0.883016 1.000000 0.000000 +vt 0.883016 0.000000 0.000000 +vt 0.884016 1.000000 0.000000 +vt 0.884016 0.000000 0.000000 +vt 0.884996 1.000000 0.000000 +vt 0.884996 0.000000 0.000000 +vt 0.885961 1.000000 0.000000 +vt 0.885961 0.000000 0.000000 +vt 0.886916 1.000000 0.000000 +vt 0.886916 0.000000 0.000000 +vt 0.887865 1.000000 0.000000 +vt 0.887865 0.000000 0.000000 +vt 0.888811 1.000000 0.000000 +vt 0.888811 0.000000 0.000000 +vt 0.889758 1.000000 0.000000 +vt 0.889758 0.000000 0.000000 +vt 0.890711 1.000000 0.000000 +vt 0.890711 0.000000 0.000000 +vt 0.891672 1.000000 0.000000 +vt 0.891672 0.000000 0.000000 +vt 0.892648 1.000000 0.000000 +vt 0.892648 0.000000 0.000000 +vt 0.893390 1.000000 0.000000 +vt 0.893390 0.000000 0.000000 +vt 0.894145 1.000000 0.000000 +vt 0.894145 0.000000 0.000000 +vt 0.895161 1.000000 0.000000 +vt 0.895161 0.000000 0.000000 +vt 0.896163 1.000000 0.000000 +vt 0.896163 0.000000 0.000000 +vt 0.897155 1.000000 0.000000 +vt 0.897155 0.000000 0.000000 +vt 0.898141 1.000000 0.000000 +vt 0.898141 0.000000 0.000000 +vt 0.899121 1.000000 0.000000 +vt 0.899121 0.000000 0.000000 +vt 0.900099 1.000000 0.000000 +vt 0.900099 0.000000 0.000000 +vt 0.901075 1.000000 0.000000 +vt 0.901075 0.000000 0.000000 +vt 0.902052 1.000000 0.000000 +vt 0.902052 0.000000 0.000000 +vt 0.903030 1.000000 0.000000 +vt 0.903030 0.000000 0.000000 +vt 0.904013 1.000000 0.000000 +vt 0.904013 0.000000 0.000000 +vt 0.905003 1.000000 0.000000 +vt 0.905003 0.000000 0.000000 +vt 0.905753 1.000000 0.000000 +vt 0.905753 0.000000 0.000000 +vt 0.906510 1.000000 0.000000 +vt 0.906510 0.000000 0.000000 +vt 0.907496 1.000000 0.000000 +vt 0.907496 0.000000 0.000000 +vt 0.908474 1.000000 0.000000 +vt 0.908474 0.000000 0.000000 +vt 0.909447 1.000000 0.000000 +vt 0.909447 0.000000 0.000000 +vt 0.910416 1.000000 0.000000 +vt 0.910416 0.000000 0.000000 +vt 0.911381 1.000000 0.000000 +vt 0.911381 0.000000 0.000000 +vt 0.912345 1.000000 0.000000 +vt 0.912345 0.000000 0.000000 +vt 0.913307 1.000000 0.000000 +vt 0.913307 0.000000 0.000000 +vt 0.914268 1.000000 0.000000 +vt 0.914268 0.000000 0.000000 +vt 0.915231 1.000000 0.000000 +vt 0.915231 0.000000 0.000000 +vt 0.916196 1.000000 0.000000 +vt 0.916196 0.000000 0.000000 +vt 0.917166 1.000000 0.000000 +vt 0.917166 0.000000 0.000000 +vt 0.917900 1.000000 0.000000 +vt 0.917900 0.000000 0.000000 +vt 0.918641 1.000000 0.000000 +vt 0.918641 0.000000 0.000000 +vt 0.961258 1.000000 0.000000 +vt 0.961258 0.000000 0.000000 +vt 0.972153 1.000000 0.000000 +vt 0.972153 0.000000 0.000000 +vt 0.973293 1.000000 0.000000 +vt 0.973293 0.000000 0.000000 +vt 0.974405 1.000000 0.000000 +vt 0.974405 0.000000 0.000000 +vt 0.975500 1.000000 0.000000 +vt 0.975500 0.000000 0.000000 +vt 0.976585 1.000000 0.000000 +vt 0.976585 0.000000 0.000000 +vt 0.977668 1.000000 0.000000 +vt 0.977668 0.000000 0.000000 +vt 0.978753 1.000000 0.000000 +vt 0.978753 0.000000 0.000000 +vt 0.979845 1.000000 0.000000 +vt 0.979845 0.000000 0.000000 +vt 0.980945 1.000000 0.000000 +vt 0.980945 0.000000 0.000000 +vt 0.982055 1.000000 0.000000 +vt 0.982055 0.000000 0.000000 +vt 0.983177 1.000000 0.000000 +vt 0.983177 0.000000 0.000000 +vt 0.984309 1.000000 0.000000 +vt 0.984309 0.000000 0.000000 +vt 0.985454 1.000000 0.000000 +vt 0.985454 0.000000 0.000000 +vt 0.986612 1.000000 0.000000 +vt 0.986612 0.000000 0.000000 +vt 0.987785 1.000000 0.000000 +vt 0.987785 0.000000 0.000000 +vt 0.988974 1.000000 0.000000 +vt 0.988974 0.000000 0.000000 +vt 0.989778 1.000000 0.000000 +vt 0.989778 0.000000 0.000000 +vt 0.991004 1.000000 0.000000 +vt 0.991004 0.000000 0.000000 +vt 0.991953 1.000000 0.000000 +vt 0.991953 0.000000 0.000000 +vt 0.992866 1.000000 0.000000 +vt 0.992866 0.000000 0.000000 +vt 0.993754 1.000000 0.000000 +vt 0.993754 0.000000 0.000000 +vt 0.994628 1.000000 0.000000 +vt 0.994628 0.000000 0.000000 +vt 0.995498 1.000000 0.000000 +vt 0.995498 0.000000 0.000000 +vt 0.996370 1.000000 0.000000 +vt 0.996370 0.000000 0.000000 +vt 0.997431 1.000000 0.000000 +vt 0.997431 0.000000 0.000000 +vt 0.998696 1.000000 0.000000 +vt 0.998696 0.000000 0.000000 +vt 0.025197 1.000000 0.000000 +vt 0.025197 0.000000 0.000000 +vt 0.057210 1.000000 0.000000 +vt 0.057210 0.000000 0.000000 +vt 0.066328 1.000000 0.000000 +vt 0.066328 0.000000 0.000000 +vt 0.074669 1.000000 0.000000 +vt 0.074669 0.000000 0.000000 +vt 0.080472 1.000000 0.000000 +vt 0.080472 0.000000 0.000000 +vt 0.085937 1.000000 0.000000 +vt 0.085937 0.000000 0.000000 +vt 0.091121 1.000000 0.000000 +vt 0.091121 0.000000 0.000000 +vt 0.096090 1.000000 0.000000 +vt 0.096090 0.000000 0.000000 +vt 0.099321 1.000000 0.000000 +vt 0.099321 0.000000 0.000000 +vt 0.102514 1.000000 0.000000 +vt 0.102514 0.000000 0.000000 +vt 0.105693 1.000000 0.000000 +vt 0.105693 0.000000 0.000000 +vt 0.108883 1.000000 0.000000 +vt 0.108883 0.000000 0.000000 +vt 0.112108 1.000000 0.000000 +vt 0.112108 0.000000 0.000000 +vt 0.115394 1.000000 0.000000 +vt 0.115394 0.000000 0.000000 +vt 0.120482 1.000000 0.000000 +vt 0.120482 0.000000 0.000000 +vt 0.125825 1.000000 0.000000 +vt 0.125825 0.000000 0.000000 +vt 0.131484 1.000000 0.000000 +vt 0.131484 0.000000 0.000000 +vt 0.137509 1.000000 0.000000 +vt 0.137509 0.000000 0.000000 +vt 0.143942 1.000000 0.000000 +vt 0.143942 0.000000 0.000000 +vt 0.150821 1.000000 0.000000 +vt 0.150821 0.000000 0.000000 +vt 0.167159 1.000000 0.000000 +vt 0.167159 0.000000 0.000000 +vt 0.183716 1.000000 0.000000 +vt 0.183716 0.000000 0.000000 +vt 0.198994 1.000000 0.000000 +vt 0.198994 0.000000 0.000000 +vt 0.214088 1.000000 0.000000 +vt 0.214088 0.000000 0.000000 +vt 0.259700 1.000000 0.000000 +vt 0.259700 0.000000 0.000000 +vt 0.304499 1.000000 0.000000 +vt 0.304499 0.000000 0.000000 +vt 0.343333 1.000000 0.000000 +vt 0.343333 0.000000 0.000000 +vt 0.382095 1.000000 0.000000 +vt 0.382095 0.000000 0.000000 +vt 0.421047 1.000000 0.000000 +vt 0.421047 0.000000 0.000000 +vt 0.454783 1.000000 0.000000 +vt 0.454783 0.000000 0.000000 +vt 0.494764 1.000000 0.000000 +vt 0.494764 0.000000 0.000000 +vt 0.525483 1.000000 0.000000 +vt 0.525483 0.000000 0.000000 +vt 0.538652 1.000000 0.000000 +vt 0.538652 0.000000 0.000000 +vt 0.547252 1.000000 0.000000 +vt 0.547252 0.000000 0.000000 +vt 0.555687 1.000000 0.000000 +vt 0.555687 0.000000 0.000000 +vt 0.561927 1.000000 0.000000 +vt 0.561927 0.000000 0.000000 +vt 0.568134 1.000000 0.000000 +vt 0.568134 0.000000 0.000000 +vt 0.574372 1.000000 0.000000 +vt 0.574372 0.000000 0.000000 +vt 0.580726 1.000000 0.000000 +vt 0.580726 0.000000 0.000000 +vt 0.587305 1.000000 0.000000 +vt 0.587305 0.000000 0.000000 +vt 0.594233 1.000000 0.000000 +vt 0.594233 0.000000 0.000000 +vt 0.599113 1.000000 0.000000 +vt 0.599113 0.000000 0.000000 +vt 0.604248 1.000000 0.000000 +vt 0.604248 0.000000 0.000000 +vt 0.611759 1.000000 0.000000 +vt 0.611759 0.000000 0.000000 +vt 0.618759 1.000000 0.000000 +vt 0.618759 0.000000 0.000000 +vt 0.625382 1.000000 0.000000 +vt 0.625382 0.000000 0.000000 +vt 0.631751 1.000000 0.000000 +vt 0.631751 0.000000 0.000000 +vt 0.637980 1.000000 0.000000 +vt 0.637980 0.000000 0.000000 +vt 0.644157 1.000000 0.000000 +vt 0.644157 0.000000 0.000000 +vt 0.650353 1.000000 0.000000 +vt 0.650353 0.000000 0.000000 +vt 0.656613 1.000000 0.000000 +vt 0.656613 0.000000 0.000000 +vt 0.665098 1.000000 0.000000 +vt 0.665098 0.000000 0.000000 +vt 0.675933 1.000000 0.000000 +vt 0.675933 0.000000 0.000000 +vt 0.693598 1.000000 0.000000 +vt 0.693598 0.000000 0.000000 +vt 0.713234 1.000000 0.000000 +vt 0.713234 0.000000 0.000000 +vt 0.758144 1.000000 0.000000 +vt 0.758144 0.000000 0.000000 +vt 0.796963 1.000000 0.000000 +vt 0.796963 0.000000 0.000000 +vt 0.835798 1.000000 0.000000 +vt 0.835798 0.000000 0.000000 +vt 0.880768 1.000000 0.000000 +vt 0.880768 0.000000 0.000000 +vt 0.926990 1.000000 0.000000 +vt 0.926990 0.000000 0.000000 +vt 0.962852 1.000000 0.000000 +vt 0.962852 0.000000 0.000000 +vt 0.947977 0.937293 0.000000 +vt 0.913295 0.937293 0.000000 +vt 0.913347 0.925149 0.000000 +vt 0.948095 0.925149 0.000000 +vt 0.861272 1.000000 0.000000 +vt 0.861272 0.845491 0.000000 +vt 1.000000 0.845556 0.000000 +vt 0.947977 1.000000 0.000000 +vt 0.913295 1.000000 0.000000 +vt 0.948095 0.845556 0.000000 +vt 0.913347 0.845491 0.000000 +vt 0.050991 0.903231 0.000000 +vt 0.048325 0.928807 0.000000 +vt 0.047546 0.928713 0.000000 +vt 0.045831 0.903191 0.000000 +vt 0.113813 0.915668 0.000000 +vt 0.114603 0.915361 0.000000 +vt 0.124048 0.939448 0.000000 +vt 0.118403 0.940939 0.000000 +vt 0.119307 0.847538 0.000000 +vt 0.122660 0.848666 0.000000 +vt 0.111543 0.897027 0.000000 +vt 0.109161 0.896836 0.000000 +vt 0.000574 0.957558 0.000000 +vt 0.000000 0.956062 0.000000 +vt 0.036667 0.942130 0.000000 +vt 0.037103 0.943046 0.000000 +vt 0.031078 0.905997 0.000000 +vt 0.035842 0.904585 0.000000 +vt 0.042191 0.929476 0.000000 +vt 0.041259 0.929913 0.000000 +vt 0.111305 0.916188 0.000000 +vt 0.112689 0.915972 0.000000 +vt 0.112543 0.941800 0.000000 +vt 0.109699 0.916284 0.000000 +vt 0.106526 0.942003 0.000000 +vt 0.107884 0.916226 0.000000 +vt 0.040770 0.903646 0.000000 +vt 0.044209 0.928875 0.000000 +vt 0.043176 0.929129 0.000000 +vt 0.026891 0.993124 0.000000 +vt 0.023323 0.991195 0.000000 +vt 0.042857 0.947617 0.000000 +vt 0.044416 0.948049 0.000000 +vt 0.108361 0.845546 0.000000 +vt 0.114075 0.846292 0.000000 +vt 0.106749 0.896847 0.000000 +vt 0.046399 0.928663 0.000000 +vt 0.045286 0.928718 0.000000 +vt 0.120060 0.907210 0.000000 +vt 0.120037 0.906138 0.000000 +vt 0.152812 0.913689 0.000000 +vt 0.151611 0.916305 0.000000 +vt 0.020526 0.989377 0.000000 +vt 0.041774 0.947191 0.000000 +vt 0.017918 0.987411 0.000000 +vt 0.040772 0.946683 0.000000 +vt 0.119468 0.903539 0.000000 +vt 0.119053 0.902571 0.000000 +vt 0.153845 0.910972 0.000000 +vt 0.115347 0.914992 0.000000 +vt 0.116042 0.914565 0.000000 +vt 0.129423 0.937353 0.000000 +vt 0.005072 0.928339 0.000000 +vt 0.006362 0.925983 0.000000 +vt 0.036355 0.936156 0.000000 +vt 0.036139 0.937220 0.000000 +vt 0.035308 0.996614 0.000000 +vt 0.046101 0.948316 0.000000 +vt 0.105895 0.915991 0.000000 +vt 0.100407 0.941520 0.000000 +vt 0.026511 0.907872 0.000000 +vt 0.040385 0.930436 0.000000 +vt 0.118460 0.912143 0.000000 +vt 0.118996 0.911246 0.000000 +vt 0.141303 0.929663 0.000000 +vt 0.138006 0.932321 0.000000 +vt 0.127471 0.850775 0.000000 +vt 0.112643 0.897278 0.000000 +vt 0.014919 0.984752 0.000000 +vt 0.012203 0.981879 0.000000 +vt 0.039854 0.946095 0.000000 +vt 0.056219 0.903776 0.000000 +vt 0.049513 0.929042 0.000000 +vt 0.119428 0.910294 0.000000 +vt 0.144335 0.926721 0.000000 +vt 0.119963 0.908266 0.000000 +vt 0.149513 0.920030 0.000000 +vt 0.136212 0.856346 0.000000 +vt 0.140095 0.859728 0.000000 +vt 0.114678 0.898095 0.000000 +vt 0.113690 0.897636 0.000000 +vt 0.119752 0.909298 0.000000 +vt 0.147080 0.923506 0.000000 +vt 0.131996 0.853348 0.000000 +vt 0.143619 0.863456 0.000000 +vt 0.115602 0.898647 0.000000 +vt 0.018097 0.912968 0.000000 +vt 0.022173 0.910199 0.000000 +vt 0.038835 0.931722 0.000000 +vt 0.038169 0.932477 0.000000 +vt 0.146762 0.867490 0.000000 +vt 0.116456 0.899287 0.000000 +vt 0.009307 0.978163 0.000000 +vt 0.039023 0.945434 0.000000 +vt 0.149498 0.871789 0.000000 +vt 0.117233 0.900006 0.000000 +vt 0.117282 0.913553 0.000000 +vt 0.117824 0.912977 0.000000 +vt 0.134470 0.934684 0.000000 +vt 0.006797 0.974170 0.000000 +vt 0.004661 0.969916 0.000000 +vt 0.038286 0.944702 0.000000 +vt 0.151803 0.876313 0.000000 +vt 0.117929 0.900797 0.000000 +vt 0.039576 0.931040 0.000000 +vt 0.153654 0.881024 0.000000 +vt 0.118538 0.901655 0.000000 +vt 0.008504 0.922772 0.000000 +vt 0.036670 0.935146 0.000000 +vt 0.010861 0.919788 0.000000 +vt 0.037082 0.934193 0.000000 +vt 0.155025 0.885882 0.000000 +vt 0.014316 0.916168 0.000000 +vt 0.037583 0.933302 0.000000 +vt 0.002624 0.964647 0.000000 +vt 0.001059 0.959074 0.000000 +vt 0.037644 0.943905 0.000000 +vt 0.116688 0.914084 0.000000 +vt 0.103790 0.915567 0.000000 +vt 0.094244 0.940322 0.000000 +vt 0.102597 0.845304 0.000000 +vt 0.000000 0.896840 0.000000 +vt 0.000000 0.845261 0.000000 +vt 0.044316 1.000000 0.000000 +vt 0.047900 0.948408 0.000000 +vt 0.002410 0.934961 0.000000 +vt 0.036340 0.941161 0.000000 +vt 0.000000 0.941734 0.000000 +vt 0.036032 0.938348 0.000000 +vt 0.142582 1.000000 0.000000 +vt 0.145199 0.948420 0.000000 +vt 0.061481 0.904838 0.000000 +vt 0.150699 0.948420 0.000000 +vt 0.155893 0.890846 0.000000 +vt 0.156233 0.895876 0.000000 +vt 0.156021 0.900934 0.000000 +vt 0.155234 0.905979 0.000000 +vt 0.036126 0.940142 0.000000 +vt 0.036029 0.939079 0.000000 +vt 0.113260 0.915835 0.000000 +vt 0.119940 0.905335 0.000000 +vt 0.119779 0.904551 0.000000 +vt 0.480456 0.900475 0.000000 +vt 0.480434 0.900814 0.000000 +vt 0.431157 0.891432 0.000000 +vt 0.431349 0.890732 0.000000 +vt 0.366622 0.851264 0.000000 +vt 0.390209 0.892171 0.000000 +vt 0.385512 0.895499 0.000000 +vt 0.360973 0.853991 0.000000 +vt 0.480527 0.900036 0.000000 +vt 0.431457 0.890056 0.000000 +vt 0.352760 0.859533 0.000000 +vt 0.356670 0.856604 0.000000 +vt 0.383550 0.897076 0.000000 +vt 0.480445 0.901139 0.000000 +vt 0.430882 0.892154 0.000000 +vt 0.349930 0.862108 0.000000 +vt 0.381882 0.898608 0.000000 +vt 0.347378 0.864896 0.000000 +vt 0.480478 0.901371 0.000000 +vt 0.430523 0.892896 0.000000 +vt 0.387495 0.911902 0.000000 +vt 0.391432 0.911859 0.000000 +vt 0.391019 0.937564 0.000000 +vt 0.384242 0.936858 0.000000 +vt 0.480534 0.901590 0.000000 +vt 0.430079 0.893658 0.000000 +vt 0.849423 0.872379 0.000000 +vt 0.818960 0.845290 0.000000 +vt 0.822275 0.845653 0.000000 +vt 0.848636 0.868903 0.000000 +vt 0.396538 0.911417 0.000000 +vt 0.397885 0.937663 0.000000 +vt 0.383698 0.911212 0.000000 +vt 0.378318 0.935694 0.000000 +vt 0.372515 0.934000 0.000000 +vt 0.382962 0.910900 0.000000 +vt 0.343156 0.871118 0.000000 +vt 0.380954 0.899641 0.000000 +vt 0.341510 0.874562 0.000000 +vt 0.841479 0.855551 0.000000 +vt 0.831957 0.848429 0.000000 +vt 0.834591 0.849808 0.000000 +vt 0.839355 0.853360 0.000000 +vt 0.843428 0.858030 0.000000 +vt 0.829159 0.847304 0.000000 +vt 0.845199 0.860807 0.000000 +vt 0.826199 0.846423 0.000000 +vt 0.385815 0.911738 0.000000 +vt 0.384733 0.911526 0.000000 +vt 0.379556 0.901923 0.000000 +vt 0.379293 0.902670 0.000000 +vt 0.361366 0.928931 0.000000 +vt 0.357761 0.926685 0.000000 +vt 0.849974 0.879501 0.000000 +vt 0.849754 0.883080 0.000000 +vt 0.814601 0.845139 0.000000 +vt 0.338700 0.885210 0.000000 +vt 0.380310 0.900517 0.000000 +vt 0.379897 0.901206 0.000000 +vt 0.338394 0.888422 0.000000 +vt 0.430909 0.849244 0.000000 +vt 0.437374 0.851833 0.000000 +vt 0.426719 0.884315 0.000000 +vt 0.422709 0.883445 0.000000 +vt 0.340190 0.878231 0.000000 +vt 0.339207 0.882132 0.000000 +vt 0.443623 0.855076 0.000000 +vt 0.427809 0.884738 0.000000 +vt 0.422626 0.846866 0.000000 +vt 0.419504 0.883050 0.000000 +vt 0.414766 0.883524 0.000000 +vt 0.414238 0.845366 0.000000 +vt 0.377958 0.847515 0.000000 +vt 0.386673 0.845761 0.000000 +vt 0.399039 0.887598 0.000000 +vt 0.394521 0.889688 0.000000 +vt 0.846790 0.863890 0.000000 +vt 0.396052 0.844765 0.000000 +vt 0.404476 0.885684 0.000000 +vt 0.405875 0.844665 0.000000 +vt 0.410229 0.884267 0.000000 +vt 0.372628 0.849037 0.000000 +vt 0.530171 0.930539 0.000000 +vt 0.519533 0.934392 0.000000 +vt 0.522843 0.932696 0.000000 +vt 0.526394 0.931401 0.000000 +vt 0.495438 0.861538 0.000000 +vt 0.494351 0.866870 0.000000 +vt 0.445431 0.845481 0.000000 +vt 0.382266 0.910514 0.000000 +vt 0.366856 0.931754 0.000000 +vt 0.381617 0.910048 0.000000 +vt 0.338344 0.893705 0.000000 +vt 0.819539 0.915107 0.000000 +vt 0.740425 0.884110 0.000000 +vt 0.740369 0.880745 0.000000 +vt 0.381020 0.909493 0.000000 +vt 0.380482 0.908844 0.000000 +vt 0.642995 0.929564 0.000000 +vt 0.639849 0.929980 0.000000 +vt 0.566978 0.926494 0.000000 +vt 0.711366 0.915094 0.000000 +vt 0.538600 0.845261 0.000000 +vt 0.590891 0.916803 0.000000 +vt 0.569247 0.917769 0.000000 +vt 0.529370 0.857515 0.000000 +vt 0.430975 0.887426 0.000000 +vt 0.480667 0.899497 0.000000 +vt 0.436636 0.934240 0.000000 +vt 0.487890 0.919890 0.000000 +vt 0.493525 0.963456 0.000000 +vt 0.439587 0.948006 0.000000 +vt 0.612257 0.958525 0.000000 +vt 0.527938 1.000000 0.000000 +vt 0.523769 0.998499 0.000000 +vt 0.486851 0.919289 0.000000 +vt 0.427523 0.897006 0.000000 +vt 0.428883 0.895377 0.000000 +vt 0.405648 0.909496 0.000000 +vt 0.410343 0.907871 0.000000 +vt 0.275452 0.909660 0.000000 +vt 0.264083 0.948006 0.000000 +vt 0.239232 0.948508 0.000000 +vt 0.280692 0.883089 0.000000 +vt 0.283055 0.845453 0.000000 +vt 0.282679 0.864419 0.000000 +vt 0.218022 0.845453 0.000000 +vt 0.503324 0.958522 0.000000 +vt 0.504224 0.954779 0.000000 +vt 0.467245 1.000000 0.000000 +vt 0.147399 1.000000 0.000000 +vt 0.513687 0.938857 0.000000 +vt 0.516476 0.936456 0.000000 +vt 0.508964 0.944539 0.000000 +vt 0.511178 0.941562 0.000000 +vt 0.692421 0.925616 0.000000 +vt 0.713866 0.914784 0.000000 +vt 0.505474 0.951180 0.000000 +vt 0.507058 0.947755 0.000000 +vt 0.497569 0.909457 0.000000 +vt 0.489856 0.919717 0.000000 +vt 0.497506 0.845481 0.000000 +vt 0.492987 0.872099 0.000000 +vt 0.490007 0.880828 0.000000 +vt 0.486222 0.889258 0.000000 +vt 0.355241 0.924888 0.000000 +vt 0.848159 0.925560 0.000000 +vt 0.849711 0.925700 0.000000 +vt 0.849711 1.000000 0.000000 +vt 0.847130 0.925511 0.000000 +vt 0.757139 0.928519 0.000000 +vt 0.351400 0.921680 0.000000 +vt 0.348021 0.918203 0.000000 +vt 0.481642 0.897390 0.000000 +vt 0.345660 0.915227 0.000000 +vt 0.343613 0.912078 0.000000 +vt 0.341886 0.908754 0.000000 +vt 0.340488 0.905256 0.000000 +vt 0.339427 0.901582 0.000000 +vt 0.338709 0.897732 0.000000 +vt 0.345116 0.867898 0.000000 +vt 0.428759 0.885228 0.000000 +vt 0.429380 0.885637 0.000000 +vt 0.429922 0.886081 0.000000 +vt 0.532756 0.845261 0.000000 +vt 0.481245 0.898091 0.000000 +vt 0.430384 0.886559 0.000000 +vt 0.167180 0.948508 0.000000 +vt 0.468108 0.999344 0.000000 +vt 0.468226 0.999285 0.000000 +vt 0.468298 0.999256 0.000000 +vt 0.468372 0.999233 0.000000 +vt 0.472493 0.997908 0.000000 +vt 0.476273 0.996292 0.000000 +vt 0.479705 0.994389 0.000000 +vt 0.482781 0.992209 0.000000 +vt 0.484851 0.990395 0.000000 +vt 0.486713 0.988432 0.000000 +vt 0.488365 0.986322 0.000000 +vt 0.489803 0.984069 0.000000 +vt 0.491024 0.981676 0.000000 +vt 0.492026 0.979145 0.000000 +vt 0.492805 0.976480 0.000000 +vt 0.493491 0.972724 0.000000 +vt 0.493767 0.968741 0.000000 +vt 0.493749 0.966667 0.000000 +vt 0.480926 0.898779 0.000000 +vt 0.430766 0.887069 0.000000 +vt 0.431149 0.887796 0.000000 +vt 0.431287 0.888180 0.000000 +vt 0.431389 0.888576 0.000000 +vt 0.431454 0.888984 0.000000 +vt 0.431483 0.889404 0.000000 +vt 0.426144 0.898396 0.000000 +vt 0.424669 0.899649 0.000000 +vt 0.419884 0.903008 0.000000 +vt 0.414886 0.905836 0.000000 +vt 0.746993 0.929271 0.000000 +vt 0.738264 0.930757 0.000000 +vt 0.730888 0.932754 0.000000 +vt 0.724785 0.935025 0.000000 +vt 0.718904 0.937848 0.000000 +vt 0.713265 0.941256 0.000000 +vt 0.709650 0.943869 0.000000 +vt 0.706157 0.946768 0.000000 +vt 0.687949 0.964046 0.000000 +vt 0.670567 0.982176 0.000000 +vt 0.666546 0.986111 0.000000 +vt 0.663393 0.988664 0.000000 +vt 0.379120 0.903449 0.000000 +vt 0.379043 0.904262 0.000000 +vt 0.379074 0.905110 0.000000 +vt 0.379219 0.905996 0.000000 +vt 0.379489 0.906920 0.000000 +vt 0.379732 0.907531 0.000000 +vt 0.380009 0.908092 0.000000 +vt 0.400804 0.910708 0.000000 +vt 0.505900 0.900256 0.000000 +vt 0.513249 0.890478 0.000000 +vt 0.519613 0.880106 0.000000 +vt 0.524988 0.869124 0.000000 +vt 0.612423 0.914759 0.000000 +vt 0.617370 0.913864 0.000000 +vt 0.623066 0.912266 0.000000 +vt 0.628515 0.910147 0.000000 +vt 0.634579 0.907092 0.000000 +vt 0.641157 0.902940 0.000000 +vt 0.648151 0.897585 0.000000 +vt 0.654767 0.891686 0.000000 +vt 0.684817 0.860175 0.000000 +vt 0.687357 0.857797 0.000000 +vt 0.690058 0.855736 0.000000 +vt 0.692898 0.853996 0.000000 +vt 0.837058 0.851448 0.000000 +vt 0.847814 0.866361 0.000000 +vt 0.849866 0.875923 0.000000 +vt 0.849215 0.886624 0.000000 +vt 0.848367 0.890102 0.000000 +vt 0.847216 0.893478 0.000000 +vt 0.845772 0.896720 0.000000 +vt 0.844043 0.899793 0.000000 +vt 0.842038 0.902664 0.000000 +vt 0.839765 0.905298 0.000000 +vt 0.837723 0.907274 0.000000 +vt 0.835585 0.909038 0.000000 +vt 0.832965 0.910826 0.000000 +vt 0.830606 0.912122 0.000000 +vt 0.828136 0.913197 0.000000 +vt 0.825552 0.914048 0.000000 +vt 0.822850 0.914671 0.000000 +vt 0.502786 0.962375 0.000000 +vt 0.502625 0.966308 0.000000 +vt 0.502853 0.970286 0.000000 +vt 0.503484 0.974280 0.000000 +vt 0.504136 0.976934 0.000000 +vt 0.505469 0.980879 0.000000 +vt 0.506808 0.983814 0.000000 +vt 0.508381 0.986488 0.000000 +vt 0.510178 0.988913 0.000000 +vt 0.512185 0.991103 0.000000 +vt 0.514390 0.993070 0.000000 +vt 0.516780 0.994827 0.000000 +vt 0.519874 0.996674 0.000000 +vt 0.660103 0.990838 0.000000 +vt 0.695857 0.852577 0.000000 +vt 0.657244 0.992333 0.000000 +vt 0.698913 0.851484 0.000000 +vt 0.654266 0.993522 0.000000 +vt 0.702044 0.850717 0.000000 +vt 0.651792 0.994237 0.000000 +vt 0.705229 0.850281 0.000000 +vt 0.708446 0.850177 0.000000 +vt 0.711676 0.850407 0.000000 +vt 0.714894 0.850975 0.000000 +vt 0.718082 0.851882 0.000000 +vt 0.720439 0.852786 0.000000 +vt 0.722757 0.853885 0.000000 +vt 0.725731 0.855638 0.000000 +vt 0.728468 0.857666 0.000000 +vt 0.730955 0.859943 0.000000 +vt 0.733181 0.862444 0.000000 +vt 0.735134 0.865144 0.000000 +vt 0.736801 0.868018 0.000000 +vt 0.738170 0.871040 0.000000 +vt 0.739230 0.874185 0.000000 +vt 0.739966 0.877429 0.000000 +vt 0.740232 0.886649 0.000000 +vt 0.739832 0.889190 0.000000 +vt 0.739006 0.892439 0.000000 +vt 0.737856 0.895559 0.000000 +vt 0.736404 0.898529 0.000000 +vt 0.734668 0.901326 0.000000 +vt 0.732671 0.903930 0.000000 +vt 0.730431 0.906319 0.000000 +vt 0.727969 0.908470 0.000000 +vt 0.725305 0.910363 0.000000 +vt 0.722460 0.911975 0.000000 +vt 0.719453 0.913285 0.000000 +vt 0.716306 0.914271 0.000000 +vt 0.637817 0.930393 0.000000 +vt 0.633922 0.931530 0.000000 +vt 0.630272 0.933061 0.000000 +vt 0.626889 0.934962 0.000000 +vt 0.624540 0.936616 0.000000 +vt 0.622363 0.938453 0.000000 +vt 0.620367 0.940463 0.000000 +vt 0.618562 0.942637 0.000000 +vt 0.616957 0.944964 0.000000 +vt 0.615561 0.947433 0.000000 +vt 0.614384 0.950034 0.000000 +vt 0.613434 0.952756 0.000000 +vt 0.612722 0.955590 0.000000 +vt 0.612048 0.961551 0.000000 +vt 0.612106 0.964549 0.000000 +vt 0.612291 0.966512 0.000000 +vt 0.612781 0.969393 0.000000 +vt 0.613518 0.972187 0.000000 +vt 0.614491 0.974882 0.000000 +vt 0.615691 0.977464 0.000000 +vt 0.617106 0.979920 0.000000 +vt 0.618729 0.982239 0.000000 +vt 0.620547 0.984408 0.000000 +vt 0.622552 0.986412 0.000000 +vt 0.624733 0.988241 0.000000 +vt 0.627081 0.989881 0.000000 +vt 0.629585 0.991319 0.000000 +vt 0.632236 0.992543 0.000000 +vt 0.635023 0.993540 0.000000 +vt 0.637936 0.994297 0.000000 +vt 0.640966 0.994801 0.000000 +vt 0.643823 0.995026 0.000000 +vt 0.646576 0.995000 0.000000 +vt 0.649231 0.994734 0.000000 +# 1456 texture coordinates + +o Extrude +usemtl default +f 488/4/1 489/3/1 2/2/1 1/1/1 +f 489/3/2 490/6/2 3/5/2 2/2/2 +f 490/6/3 491/8/3 4/7/3 3/5/3 +f 491/8/2 492/10/2 5/9/2 4/7/2 +f 492/10/1 493/12/1 6/11/1 5/9/1 +f 493/12/2 494/14/2 7/13/2 6/11/2 +f 494/14/3 495/16/3 8/15/3 7/13/3 +f 495/16/4 496/18/4 9/17/4 8/15/4 +f 496/18/1 497/20/1 10/19/1 9/17/1 +f 497/20/4 498/22/4 11/21/4 10/19/4 +f 498/22/3 499/24/3 12/23/3 11/21/3 +f 499/24/4 488/26/4 1/25/4 12/23/4 +f 500/4/5 501/28/5 14/27/5 13/1/5 +f 501/28/2 502/30/6 15/29/6 14/27/2 +f 502/30/6 503/32/7 16/31/7 15/29/6 +f 503/32/7 504/34/8 17/33/8 16/31/7 +f 504/34/8 505/36/9 18/35/9 17/33/8 +f 505/36/9 506/38/10 19/37/10 18/35/9 +f 506/38/10 507/40/11 20/39/11 19/37/10 +f 507/40/11 508/42/12 21/41/12 20/39/11 +f 508/42/12 509/44/13 22/43/13 21/41/12 +f 509/44/13 510/46/14 23/45/14 22/43/13 +f 510/46/14 511/48/15 24/47/15 23/45/14 +f 511/48/15 512/50/16 25/49/16 24/47/15 +f 512/50/16 513/52/17 26/51/17 25/49/16 +f 513/52/17 514/54/18 27/53/18 26/51/17 +f 514/54/18 515/56/19 28/55/19 27/53/18 +f 515/56/19 516/58/20 29/57/20 28/55/19 +f 516/58/20 517/60/21 30/59/21 29/57/20 +f 517/60/21 518/62/22 31/61/22 30/59/21 +f 518/62/22 519/64/23 32/63/23 31/61/22 +f 519/64/23 520/66/24 33/65/24 32/63/23 +f 520/66/24 521/68/25 34/67/25 33/65/24 +f 521/68/25 522/70/26 35/69/26 34/67/25 +f 522/70/26 523/72/27 36/71/27 35/69/26 +f 523/72/27 524/74/28 37/73/28 36/71/27 +f 524/74/28 525/76/29 38/75/29 37/73/28 +f 525/76/29 526/78/30 39/77/30 38/75/29 +f 526/78/30 527/80/31 40/79/31 39/77/30 +f 527/80/31 528/82/32 41/81/32 40/79/31 +f 528/82/32 529/84/33 42/83/33 41/81/32 +f 529/84/33 530/86/34 43/85/34 42/83/33 +f 530/86/34 531/88/35 44/87/35 43/85/34 +f 531/88/35 532/90/36 45/89/36 44/87/35 +f 532/90/36 533/92/37 46/91/37 45/89/36 +f 533/92/37 534/94/38 47/93/38 46/91/37 +f 534/94/38 535/96/39 48/95/39 47/93/38 +f 535/96/39 536/98/40 49/97/40 48/95/39 +f 536/98/40 537/100/41 50/99/41 49/97/40 +f 537/100/41 538/102/42 51/101/42 50/99/41 +f 538/102/42 539/104/43 52/103/43 51/101/42 +f 539/104/43 540/106/44 53/105/44 52/103/43 +f 540/106/44 541/108/45 54/107/45 53/105/44 +f 541/108/45 542/110/46 55/109/46 54/107/45 +f 542/110/46 543/112/47 56/111/47 55/109/46 +f 543/112/47 544/114/48 57/113/48 56/111/47 +f 544/114/48 545/116/49 58/115/49 57/113/48 +f 545/116/49 546/118/50 59/117/50 58/115/49 +f 546/118/50 547/120/51 60/119/51 59/117/50 +f 547/120/51 548/122/52 61/121/52 60/119/51 +f 548/122/52 549/124/53 62/123/53 61/121/52 +f 549/124/53 550/126/54 63/125/54 62/123/53 +f 550/126/54 551/128/55 64/127/55 63/125/54 +f 551/128/55 552/130/56 65/129/56 64/127/55 +f 552/130/56 553/132/57 66/131/57 65/129/56 +f 553/132/57 554/134/58 67/133/58 66/131/57 +f 554/134/58 555/136/59 68/135/59 67/133/58 +f 555/136/59 556/138/60 69/137/60 68/135/59 +f 556/138/60 557/140/61 70/139/61 69/137/60 +f 557/140/61 558/142/62 71/141/62 70/139/61 +f 558/142/62 559/144/63 72/143/63 71/141/62 +f 559/144/63 560/146/64 73/145/64 72/143/63 +f 560/146/64 561/148/65 74/147/65 73/145/64 +f 561/148/65 562/150/66 75/149/66 74/147/65 +f 562/150/66 563/152/67 76/151/67 75/149/66 +f 563/152/67 564/154/68 77/153/68 76/151/67 +f 564/154/68 565/156/69 78/155/69 77/153/68 +f 565/156/69 566/158/70 79/157/70 78/155/69 +f 566/158/70 567/160/71 80/159/71 79/157/70 +f 567/160/71 568/162/72 81/161/72 80/159/71 +f 568/162/72 569/164/73 82/163/73 81/161/72 +f 569/164/73 570/166/74 83/165/74 82/163/73 +f 570/166/74 571/168/75 84/167/75 83/165/74 +f 571/168/75 572/170/76 85/169/76 84/167/75 +f 572/170/3 573/172/3 86/171/3 85/169/3 +f 573/172/77 574/174/78 87/173/78 86/171/77 +f 574/174/78 575/176/79 88/175/79 87/173/78 +f 575/176/79 576/178/80 89/177/80 88/175/79 +f 576/178/80 577/180/81 90/179/81 89/177/80 +f 577/180/81 578/182/82 91/181/82 90/179/81 +f 578/182/82 579/184/83 92/183/83 91/181/82 +f 579/184/83 580/186/84 93/185/84 92/183/83 +f 580/186/84 581/188/85 94/187/85 93/185/84 +f 581/188/85 582/190/86 95/189/86 94/187/85 +f 582/190/86 583/192/87 96/191/87 95/189/86 +f 583/192/87 584/194/88 97/193/88 96/191/87 +f 584/194/88 585/196/89 98/195/89 97/193/88 +f 585/196/89 586/198/90 99/197/90 98/195/89 +f 586/198/90 587/200/91 100/199/91 99/197/90 +f 587/200/91 588/202/92 101/201/92 100/199/91 +f 588/202/92 589/204/93 102/203/93 101/201/92 +f 589/204/93 590/206/94 103/205/94 102/203/93 +f 590/206/94 591/208/95 104/207/95 103/205/94 +f 591/208/95 592/210/96 105/209/96 104/207/95 +f 592/210/96 593/212/97 106/211/97 105/209/96 +f 593/212/97 594/214/98 107/213/98 106/211/97 +f 594/214/98 595/216/99 108/215/99 107/213/98 +f 595/216/99 596/218/100 109/217/100 108/215/99 +f 596/218/100 597/220/101 110/219/101 109/217/100 +f 597/220/101 598/222/102 111/221/102 110/219/101 +f 598/222/102 599/224/103 112/223/103 111/221/102 +f 599/224/103 600/226/104 113/225/104 112/223/103 +f 600/226/104 601/228/105 114/227/105 113/225/104 +f 601/228/105 602/230/106 115/229/106 114/227/105 +f 602/230/106 603/232/107 116/231/107 115/229/106 +f 603/232/107 604/234/108 117/233/108 116/231/107 +f 604/234/108 605/236/109 118/235/109 117/233/108 +f 605/236/109 606/238/110 119/237/110 118/235/109 +f 606/238/110 607/240/111 120/239/111 119/237/110 +f 607/240/111 608/242/112 121/241/112 120/239/111 +f 608/242/112 609/244/113 122/243/113 121/241/112 +f 609/244/113 610/246/114 123/245/114 122/243/113 +f 610/246/114 611/248/115 124/247/115 123/245/114 +f 611/248/115 612/250/116 125/249/116 124/247/115 +f 612/250/116 613/252/117 126/251/117 125/249/116 +f 613/252/117 614/254/118 127/253/118 126/251/117 +f 614/254/118 615/256/119 128/255/119 127/253/118 +f 615/256/119 616/258/120 129/257/120 128/255/119 +f 616/258/120 617/260/121 130/259/121 129/257/120 +f 617/260/121 618/262/122 131/261/122 130/259/121 +f 618/262/122 619/264/123 132/263/123 131/261/122 +f 619/264/123 620/266/124 133/265/124 132/263/123 +f 620/266/124 621/268/125 134/267/125 133/265/124 +f 621/268/125 622/270/126 135/269/126 134/267/125 +f 622/270/126 623/272/127 136/271/127 135/269/126 +f 623/272/127 624/274/128 137/273/128 136/271/127 +f 624/274/128 625/276/129 138/275/129 137/273/128 +f 625/276/129 626/278/130 139/277/130 138/275/129 +f 626/278/130 627/280/131 140/279/131 139/277/130 +f 627/280/131 628/282/132 141/281/132 140/279/131 +f 628/282/132 629/284/133 142/283/133 141/281/132 +f 629/284/133 630/286/134 143/285/134 142/283/133 +f 630/286/134 631/288/135 144/287/135 143/285/134 +f 631/288/135 632/290/136 145/289/136 144/287/135 +f 632/290/136 633/292/137 146/291/137 145/289/136 +f 633/292/137 634/294/138 147/293/138 146/291/137 +f 634/294/138 635/296/139 148/295/139 147/293/138 +f 635/296/139 636/298/140 149/297/140 148/295/139 +f 636/298/140 637/300/141 150/299/141 149/297/140 +f 637/300/141 638/302/142 151/301/142 150/299/141 +f 638/302/142 639/304/143 152/303/143 151/301/142 +f 639/304/143 640/306/144 153/305/144 152/303/143 +f 640/306/144 641/308/145 154/307/145 153/305/144 +f 641/308/145 500/26/4 13/25/4 154/307/145 +f 642/4/146 643/310/4 156/309/4 155/1/146 +f 643/310/1 644/312/1 157/311/1 156/309/1 +f 644/312/147 645/314/148 158/313/148 157/311/147 +f 645/314/148 646/316/149 159/315/149 158/313/148 +f 646/316/149 647/318/150 160/317/150 159/315/149 +f 647/318/150 648/320/151 161/319/151 160/317/150 +f 648/320/151 649/322/152 162/321/152 161/319/151 +f 649/322/152 650/324/153 163/323/153 162/321/152 +f 650/324/153 651/326/154 164/325/154 163/323/153 +f 651/326/154 652/328/155 165/327/155 164/325/154 +f 652/328/155 653/330/156 166/329/156 165/327/155 +f 653/330/156 654/332/157 167/331/157 166/329/156 +f 654/332/157 655/334/158 168/333/158 167/331/157 +f 655/334/158 656/336/159 169/335/159 168/333/158 +f 656/336/159 657/338/160 170/337/160 169/335/159 +f 657/338/160 658/340/161 171/339/161 170/337/160 +f 658/340/161 659/342/162 172/341/162 171/339/161 +f 659/342/162 660/344/163 173/343/163 172/341/162 +f 660/344/163 661/346/164 174/345/164 173/343/163 +f 661/346/164 662/348/165 175/347/165 174/345/164 +f 662/348/165 663/350/166 176/349/166 175/347/165 +f 663/350/166 664/352/167 177/351/167 176/349/166 +f 664/352/167 665/354/168 178/353/168 177/351/167 +f 665/354/168 666/356/169 179/355/169 178/353/168 +f 666/356/169 667/358/170 180/357/170 179/355/169 +f 667/358/170 668/360/171 181/359/171 180/357/170 +f 668/360/171 669/362/172 182/361/172 181/359/171 +f 669/362/172 670/364/173 183/363/173 182/361/172 +f 670/364/173 671/366/174 184/365/174 183/363/173 +f 671/366/174 672/368/175 185/367/175 184/365/174 +f 672/368/175 673/370/176 186/369/176 185/367/175 +f 673/370/176 674/372/177 187/371/177 186/369/176 +f 674/372/177 675/374/178 188/373/178 187/371/177 +f 675/374/178 676/376/179 189/375/179 188/373/178 +f 676/376/179 677/378/180 190/377/180 189/375/179 +f 677/378/180 678/380/181 191/379/181 190/377/180 +f 678/380/181 679/382/182 192/381/182 191/379/181 +f 679/382/182 680/384/183 193/383/183 192/381/182 +f 680/384/183 681/386/184 194/385/184 193/383/183 +f 681/386/184 682/388/185 195/387/185 194/385/184 +f 682/388/185 683/390/186 196/389/186 195/387/185 +f 683/390/186 684/392/187 197/391/187 196/389/186 +f 684/392/187 685/394/188 198/393/188 197/391/187 +f 685/394/188 686/396/189 199/395/189 198/393/188 +f 686/396/189 687/398/190 200/397/190 199/395/189 +f 687/398/190 688/400/191 201/399/191 200/397/190 +f 688/400/191 689/402/192 202/401/192 201/399/191 +f 689/402/192 690/404/193 203/403/193 202/401/192 +f 690/404/193 691/406/194 204/405/194 203/403/193 +f 691/406/194 692/408/195 205/407/195 204/405/194 +f 692/408/195 693/410/196 206/409/196 205/407/195 +f 693/410/196 694/412/197 207/411/197 206/409/196 +f 694/412/197 695/414/198 208/413/198 207/411/197 +f 695/414/198 696/416/199 209/415/199 208/413/198 +f 696/416/199 697/418/200 210/417/200 209/415/199 +f 697/418/200 698/420/201 211/419/201 210/417/200 +f 698/420/201 699/422/202 212/421/202 211/419/201 +f 699/422/202 700/424/203 213/423/203 212/421/202 +f 700/424/203 701/426/204 214/425/204 213/423/203 +f 701/426/204 702/428/205 215/427/205 214/425/204 +f 702/428/205 703/430/206 216/429/206 215/427/205 +f 703/430/206 704/432/207 217/431/207 216/429/206 +f 704/432/207 705/434/208 218/433/208 217/431/207 +f 705/434/208 706/436/209 219/435/209 218/433/208 +f 706/436/209 707/438/210 220/437/210 219/435/209 +f 707/438/210 708/440/211 221/439/211 220/437/210 +f 708/440/211 709/442/212 222/441/212 221/439/211 +f 709/442/212 710/444/213 223/443/213 222/441/212 +f 710/444/213 711/446/214 224/445/214 223/443/213 +f 711/446/214 712/448/215 225/447/215 224/445/214 +f 712/448/215 713/450/216 226/449/216 225/447/215 +f 713/450/216 714/452/217 227/451/217 226/449/216 +f 714/452/217 715/454/218 228/453/218 227/451/217 +f 715/454/218 716/456/219 229/455/219 228/453/218 +f 716/456/219 717/458/220 230/457/220 229/455/219 +f 717/458/220 718/460/221 231/459/221 230/457/220 +f 718/460/221 719/462/222 232/461/222 231/459/221 +f 719/462/222 720/464/223 233/463/223 232/461/222 +f 720/464/223 721/466/224 234/465/224 233/463/223 +f 721/466/224 722/468/225 235/467/225 234/465/224 +f 722/468/225 723/470/226 236/469/226 235/467/225 +f 723/470/226 724/472/227 237/471/227 236/469/226 +f 724/472/227 725/474/228 238/473/228 237/471/227 +f 725/474/228 726/476/229 239/475/229 238/473/228 +f 726/476/229 727/478/230 240/477/230 239/475/229 +f 727/478/230 728/480/231 241/479/231 240/477/230 +f 728/480/231 729/482/232 242/481/232 241/479/231 +f 729/482/232 730/484/233 243/483/233 242/481/232 +f 730/484/233 731/486/234 244/485/234 243/483/233 +f 731/486/234 732/488/235 245/487/235 244/485/234 +f 732/488/235 733/490/236 246/489/236 245/487/235 +f 733/490/236 734/492/237 247/491/237 246/489/236 +f 734/492/237 735/494/238 248/493/238 247/491/237 +f 735/494/238 736/496/239 249/495/239 248/493/238 +f 736/496/239 737/498/2 250/497/2 249/495/239 +f 737/498/240 738/500/241 251/499/241 250/497/240 +f 738/500/241 739/502/242 252/501/242 251/499/241 +f 739/502/242 740/504/243 253/503/243 252/501/242 +f 740/504/243 741/506/244 254/505/244 253/503/243 +f 741/506/244 742/508/245 255/507/245 254/505/244 +f 742/508/245 743/510/246 256/509/246 255/507/245 +f 743/510/246 744/512/247 257/511/247 256/509/246 +f 744/512/248 745/514/249 258/513/249 257/511/248 +f 745/514/249 746/516/250 259/515/250 258/513/249 +f 746/516/250 747/518/251 260/517/251 259/515/250 +f 747/518/251 748/520/252 261/519/252 260/517/251 +f 748/520/252 749/522/253 262/521/253 261/519/252 +f 749/522/253 750/524/254 263/523/254 262/521/253 +f 750/524/254 751/526/255 264/525/255 263/523/254 +f 751/526/255 752/528/256 265/527/256 264/525/255 +f 752/528/256 753/530/257 266/529/257 265/527/256 +f 753/530/257 754/532/258 267/531/258 266/529/257 +f 754/532/258 755/534/259 268/533/259 267/531/258 +f 755/534/259 756/536/260 269/535/260 268/533/259 +f 756/536/260 757/538/261 270/537/261 269/535/260 +f 757/538/261 758/540/262 271/539/262 270/537/261 +f 758/540/262 759/542/263 272/541/263 271/539/262 +f 759/542/263 760/544/264 273/543/264 272/541/263 +f 760/544/2 761/546/2 274/545/2 273/543/2 +f 761/546/265 762/548/265 275/547/265 274/545/265 +f 762/548/266 763/550/267 276/549/267 275/547/266 +f 763/550/267 764/552/268 277/551/268 276/549/267 +f 764/552/268 765/554/269 278/553/269 277/551/268 +f 765/554/269 766/556/270 279/555/270 278/553/269 +f 766/556/270 767/558/271 280/557/271 279/555/270 +f 767/558/271 768/560/272 281/559/272 280/557/271 +f 768/560/272 769/562/273 282/561/273 281/559/272 +f 769/562/273 770/564/274 283/563/274 282/561/273 +f 770/564/274 771/566/275 284/565/275 283/563/274 +f 771/566/275 772/568/276 285/567/276 284/565/275 +f 772/568/276 773/570/277 286/569/277 285/567/276 +f 773/570/277 774/572/278 287/571/278 286/569/277 +f 774/572/278 775/574/279 288/573/279 287/571/278 +f 775/574/279 776/576/280 289/575/280 288/573/279 +f 776/576/280 777/578/281 290/577/281 289/575/280 +f 777/578/281 778/580/282 291/579/282 290/577/281 +f 778/580/282 779/582/283 292/581/283 291/579/282 +f 779/582/283 780/584/284 293/583/284 292/581/283 +f 780/584/284 781/586/285 294/585/285 293/583/284 +f 781/586/285 782/588/286 295/587/286 294/585/285 +f 782/588/286 783/590/287 296/589/287 295/587/286 +f 783/590/287 784/592/288 297/591/288 296/589/287 +f 784/592/288 785/594/289 298/593/289 297/591/288 +f 785/594/289 786/596/290 299/595/290 298/593/289 +f 786/596/290 787/598/291 300/597/291 299/595/290 +f 787/598/291 788/600/292 301/599/292 300/597/291 +f 788/600/292 789/602/293 302/601/293 301/599/292 +f 789/602/293 790/604/294 303/603/294 302/601/293 +f 790/604/294 791/606/295 304/605/295 303/603/294 +f 791/606/295 792/608/296 305/607/296 304/605/295 +f 792/608/296 793/610/297 306/609/297 305/607/296 +f 793/610/297 794/612/298 307/611/298 306/609/297 +f 794/612/298 795/614/299 308/613/299 307/611/298 +f 795/614/299 796/616/300 309/615/300 308/613/299 +f 796/616/300 797/618/301 310/617/301 309/615/300 +f 797/618/301 798/620/302 311/619/302 310/617/301 +f 798/620/302 799/622/303 312/621/303 311/619/302 +f 799/622/303 800/624/304 313/623/304 312/621/303 +f 800/624/304 801/626/305 314/625/305 313/623/304 +f 801/626/305 802/628/306 315/627/306 314/625/305 +f 802/628/306 803/630/307 316/629/307 315/627/306 +f 803/630/308 804/632/308 317/631/308 316/629/308 +f 804/632/2 805/634/2 318/633/2 317/631/2 +f 805/634/309 806/636/310 319/635/310 318/633/309 +f 806/636/310 807/638/311 320/637/311 319/635/310 +f 807/638/311 808/640/312 321/639/312 320/637/311 +f 808/640/312 809/642/313 322/641/313 321/639/312 +f 809/642/2 810/644/2 323/643/2 322/641/2 +f 810/644/314 811/646/314 324/645/314 323/643/314 +f 811/646/2 812/648/2 325/647/2 324/645/2 +f 812/648/315 813/650/315 326/649/315 325/647/315 +f 813/650/4 814/652/316 327/651/316 326/649/4 +f 814/652/316 815/654/317 328/653/317 327/651/316 +f 815/654/317 816/656/318 329/655/318 328/653/317 +f 816/656/318 817/658/319 330/657/319 329/655/318 +f 817/658/319 818/660/320 331/659/320 330/657/319 +f 818/660/320 819/662/321 332/661/321 331/659/320 +f 819/662/321 820/664/322 333/663/322 332/661/321 +f 820/664/322 821/666/323 334/665/323 333/663/322 +f 821/666/323 822/668/324 335/667/324 334/665/323 +f 822/668/324 823/670/325 336/669/325 335/667/324 +f 823/670/325 824/672/326 337/671/326 336/669/325 +f 824/672/326 825/674/327 338/673/327 337/671/326 +f 825/674/327 826/676/328 339/675/328 338/673/327 +f 826/676/328 827/678/329 340/677/329 339/675/328 +f 827/678/329 828/680/330 341/679/330 340/677/329 +f 828/680/330 829/682/331 342/681/331 341/679/330 +f 829/682/331 830/684/332 343/683/332 342/681/331 +f 830/684/332 831/686/333 344/685/333 343/683/332 +f 831/686/333 832/688/334 345/687/334 344/685/333 +f 832/688/334 833/690/335 346/689/335 345/687/334 +f 833/690/335 834/692/336 347/691/336 346/689/335 +f 834/692/337 835/694/338 348/693/338 347/691/337 +f 835/694/338 836/696/339 349/695/339 348/693/338 +f 836/696/339 837/698/340 350/697/340 349/695/339 +f 837/698/340 838/700/341 351/699/341 350/697/340 +f 838/700/341 839/702/342 352/701/342 351/699/341 +f 839/702/342 840/704/343 353/703/343 352/701/342 +f 840/704/343 841/706/344 354/705/344 353/703/343 +f 841/706/344 842/708/345 355/707/345 354/705/344 +f 842/708/345 843/710/346 356/709/346 355/707/345 +f 843/710/346 844/712/347 357/711/347 356/709/346 +f 844/712/347 845/714/348 358/713/348 357/711/347 +f 845/714/348 846/716/349 359/715/349 358/713/348 +f 846/716/349 847/718/350 360/717/350 359/715/349 +f 847/718/350 848/720/351 361/719/351 360/717/350 +f 848/720/351 849/722/352 362/721/352 361/719/351 +f 849/722/352 850/724/353 363/723/353 362/721/352 +f 850/724/353 851/726/354 364/725/354 363/723/353 +f 851/726/354 852/728/355 365/727/355 364/725/354 +f 852/728/355 853/730/356 366/729/356 365/727/355 +f 853/730/356 854/732/357 367/731/357 366/729/356 +f 854/732/357 855/734/358 368/733/358 367/731/357 +f 855/734/358 856/736/359 369/735/359 368/733/358 +f 856/736/359 857/738/360 370/737/360 369/735/359 +f 857/738/360 858/740/361 371/739/361 370/737/360 +f 858/740/361 859/742/362 372/741/362 371/739/361 +f 859/742/362 860/744/363 373/743/363 372/741/362 +f 860/744/363 861/746/364 374/745/364 373/743/363 +f 861/746/364 862/748/365 375/747/365 374/745/364 +f 862/748/365 863/750/366 376/749/366 375/747/365 +f 863/750/366 864/752/367 377/751/367 376/749/366 +f 864/752/367 865/754/368 378/753/368 377/751/367 +f 865/754/368 866/756/369 379/755/369 378/753/368 +f 866/756/369 867/758/370 380/757/370 379/755/369 +f 867/758/370 868/760/371 381/759/371 380/757/370 +f 868/760/371 869/762/372 382/761/372 381/759/371 +f 869/762/372 870/764/373 383/763/373 382/761/372 +f 870/764/373 871/766/374 384/765/374 383/763/373 +f 871/766/374 872/768/375 385/767/375 384/765/374 +f 872/768/375 873/770/376 386/769/376 385/767/375 +f 873/770/376 874/772/377 387/771/377 386/769/376 +f 874/772/377 875/774/378 388/773/378 387/771/377 +f 875/774/378 876/776/379 389/775/379 388/773/378 +f 876/776/379 877/778/380 390/777/380 389/775/379 +f 877/778/380 878/780/381 391/779/381 390/777/380 +f 878/780/381 879/782/382 392/781/382 391/779/381 +f 879/782/382 880/784/383 393/783/383 392/781/382 +f 880/784/383 881/786/384 394/785/384 393/783/383 +f 881/786/384 882/788/385 395/787/385 394/785/384 +f 882/788/385 883/790/386 396/789/386 395/787/385 +f 883/790/386 884/792/387 397/791/387 396/789/386 +f 884/792/387 885/794/388 398/793/388 397/791/387 +f 885/794/388 886/796/389 399/795/389 398/793/388 +f 886/796/389 887/798/390 400/797/390 399/795/389 +f 887/798/390 888/800/391 401/799/391 400/797/390 +f 888/800/391 889/802/392 402/801/392 401/799/391 +f 889/802/392 890/804/393 403/803/393 402/801/392 +f 890/804/393 891/806/394 404/805/394 403/803/393 +f 891/806/394 892/808/395 405/807/395 404/805/394 +f 892/808/395 893/810/396 406/809/396 405/807/395 +f 893/810/396 894/812/397 407/811/397 406/809/396 +f 894/812/397 895/814/398 408/813/398 407/811/397 +f 895/814/398 896/816/399 409/815/399 408/813/398 +f 896/816/399 897/818/400 410/817/400 409/815/399 +f 897/818/400 898/820/401 411/819/401 410/817/400 +f 898/820/401 899/822/402 412/821/402 411/819/401 +f 899/822/402 900/824/403 413/823/403 412/821/402 +f 900/824/403 901/826/404 414/825/404 413/823/403 +f 901/826/404 902/828/405 415/827/405 414/825/404 +f 902/828/405 903/830/406 416/829/406 415/827/405 +f 903/830/406 904/832/407 417/831/407 416/829/406 +f 904/832/407 905/834/408 418/833/408 417/831/407 +f 905/834/408 906/836/409 419/835/409 418/833/408 +f 906/836/409 907/838/410 420/837/410 419/835/409 +f 907/838/410 908/840/411 421/839/411 420/837/410 +f 908/840/411 909/842/412 422/841/412 421/839/411 +f 909/842/412 910/844/413 423/843/413 422/841/412 +f 910/844/413 911/846/414 424/845/414 423/843/413 +f 911/846/414 912/848/415 425/847/415 424/845/414 +f 912/848/415 642/26/146 155/25/146 425/847/415 +f 913/4/416 914/850/417 427/849/417 426/1/416 +f 914/850/417 915/852/418 428/851/418 427/849/417 +f 915/852/418 916/854/419 429/853/419 428/851/418 +f 916/854/419 917/856/420 430/855/420 429/853/419 +f 917/856/420 918/858/421 431/857/421 430/855/420 +f 918/858/421 919/860/422 432/859/422 431/857/421 +f 919/860/422 920/862/423 433/861/423 432/859/422 +f 920/862/423 921/864/424 434/863/424 433/861/423 +f 921/864/424 922/866/425 435/865/425 434/863/424 +f 922/866/425 923/868/426 436/867/426 435/865/425 +f 923/868/426 924/870/427 437/869/427 436/867/426 +f 924/870/427 925/872/428 438/871/428 437/869/427 +f 925/872/428 926/874/429 439/873/429 438/871/428 +f 926/874/429 927/876/430 440/875/430 439/873/429 +f 927/876/430 928/878/431 441/877/431 440/875/430 +f 928/878/431 929/880/432 442/879/432 441/877/431 +f 929/880/432 930/882/433 443/881/433 442/879/432 +f 930/882/433 931/884/434 444/883/434 443/881/433 +f 931/884/434 932/886/435 445/885/435 444/883/434 +f 932/886/435 933/888/436 446/887/436 445/885/435 +f 933/888/436 934/890/437 447/889/437 446/887/436 +f 934/890/437 935/892/438 448/891/438 447/889/437 +f 935/892/438 936/894/439 449/893/439 448/891/438 +f 936/894/439 937/896/440 450/895/440 449/893/439 +f 937/896/440 938/898/441 451/897/441 450/895/440 +f 938/898/441 939/900/442 452/899/442 451/897/441 +f 939/900/442 940/902/443 453/901/443 452/899/442 +f 940/902/443 941/904/444 454/903/444 453/901/443 +f 941/904/444 942/906/445 455/905/445 454/903/444 +f 942/906/445 943/908/446 456/907/446 455/905/445 +f 943/908/446 944/910/447 457/909/447 456/907/446 +f 944/910/447 945/912/448 458/911/448 457/909/447 +f 945/912/448 946/914/449 459/913/449 458/911/448 +f 946/914/449 947/916/450 460/915/450 459/913/449 +f 947/916/450 948/918/451 461/917/451 460/915/450 +f 948/918/451 949/920/452 462/919/452 461/917/451 +f 949/920/452 950/922/453 463/921/453 462/919/452 +f 950/922/453 951/924/454 464/923/454 463/921/453 +f 951/924/454 952/926/455 465/925/455 464/923/454 +f 952/926/455 953/928/456 466/927/456 465/925/455 +f 953/928/456 954/930/457 467/929/457 466/927/456 +f 954/930/457 955/932/458 468/931/458 467/929/457 +f 955/932/458 956/934/459 469/933/459 468/931/458 +f 956/934/459 957/936/460 470/935/460 469/933/459 +f 957/936/460 958/938/461 471/937/461 470/935/460 +f 958/938/461 959/940/462 472/939/462 471/937/461 +f 959/940/462 960/942/463 473/941/463 472/939/462 +f 960/942/463 961/944/464 474/943/464 473/941/463 +f 961/944/464 962/946/465 475/945/465 474/943/464 +f 962/946/465 963/948/466 476/947/466 475/945/465 +f 963/948/466 964/950/467 477/949/467 476/947/466 +f 964/950/467 965/952/468 478/951/468 477/949/467 +f 965/952/468 966/954/469 479/953/469 478/951/468 +f 966/954/469 967/956/470 480/955/470 479/953/469 +f 967/956/470 968/958/471 481/957/471 480/955/470 +f 968/958/471 969/960/472 482/959/472 481/957/471 +f 969/960/472 970/962/473 483/961/473 482/959/472 +f 970/962/473 971/964/474 484/963/474 483/961/473 +f 971/964/474 972/966/475 485/965/475 484/963/474 +f 972/966/475 973/968/476 486/967/476 485/965/475 +f 973/968/476 974/970/477 487/969/477 486/967/476 +f 974/970/477 913/26/416 426/25/416 487/969/477 +f 1/25/478 2/977/478 3/980/478 4/974/478 5/973/478 6/981/478 7/976/478 8/975/478 9/979/478 10/972/478 11/971/478 12/978/478 +f 13/1111/478 14/1114/478 15/1112/478 16/1106/478 17/1039/478 18/1014/478 19/1013/478 20/1025/478 21/1027/478 22/1052/478 23/1075/478 24/1083/478 25/1098/478 26/997/478 27/996/478 28/1108/478 29/1119/479 30/1120/478 31/1110/478 32/1037/478 33/1036/478 34/1090/478 35/1092/478 36/1095/478 37/1071/478 38/1070/478 39/1086/478 40/1043/478 41/1001/478 42/1000/478 43/1010/478 44/1009/478 45/1019/478 46/1018/478 47/984/478 48/983/478 49/1054/478 50/1101/478 51/1041/478 52/1006/478 53/1004/478 54/989/478 55/988/478 56/1033/478 57/1080/478 58/1047/478 59/1046/478 60/1056/478 61/1064/478 62/1058/478 63/1023/478 64/1022/478 65/1030/478 66/1118/478 67/1117/478 68/1116/478 69/1115/478 70/1093/478 71/1087/478 72/1084/478 73/1076/478 74/1072/478 75/1066/478 76/1060/478 77/1059/478 78/1065/478 79/1048/478 80/991/478 81/990/478 82/1016/478 83/1015/478 84/1102/478 85/1104/478 86/1103/478 87/1017/478 88/993/478 89/992/478 90/1049/478 91/1062/478 92/1061/478 93/1067/478 94/1073/478 95/1077/478 96/1085/478 97/1088/478 98/1029/478 99/1028/478 100/1123/478 101/1122/478 102/1021/478 103/1020/478 104/1057/478 105/1063/478 106/1055/478 107/1045/478 108/1044/478 109/1079/478 110/1078/478 111/1099/478 112/1032/478 113/1031/478 114/987/478 115/986/478 116/1121/478 117/1003/478 118/1002/478 119/1005/478 120/1007/478 121/1040/478 122/1100/478 123/1113/478 124/1053/478 125/982/478 126/985/478 127/1008/478 128/999/478 129/998/478 130/1042/478 131/1069/478 132/1068/478 133/1094/478 134/1091/478 135/1089/478 136/1035/478 137/1034/478 138/1107/478 139/1109/478 140/995/478 141/994/478 142/1097/478 143/1096/478 144/1082/478 145/1081/478 146/1074/478 147/1051/478 148/1050/478 149/1026/478 150/1024/478 151/1012/478 152/1011/478 153/1038/478 154/1105/478 +f 442/1127/478 443/1126/478 261/1125/478 262/1124/478 +f 286/1131/478 481/1130/478 482/1129/478 285/1128/478 +f 441/1133/478 442/1127/478 262/1124/478 263/1132/478 +f 480/1136/478 481/1130/478 287/1135/478 288/1134/478 +f 443/1126/478 444/1138/478 260/1137/478 261/1125/478 +f 290/1141/478 479/1140/478 480/1136/478 289/1139/478 +f 444/1138/478 445/1143/478 259/1142/478 260/1137/478 +f 313/1147/478 314/1146/478 457/1145/478 458/1144/478 +f 445/1143/478 446/1149/478 258/1148/478 259/1142/478 +f 234/1153/478 246/1152/478 247/1151/478 233/1150/478 +f 314/1146/478 315/1155/478 456/1154/478 457/1145/478 +f 462/1159/478 311/1158/478 312/1157/478 461/1156/478 +f 293/1162/478 478/1161/478 479/1140/478 292/1160/478 +f 240/1166/478 242/1165/478 243/1164/478 239/1163/478 +f 239/1163/478 243/1164/478 244/1168/478 238/1167/478 +f 238/1167/478 244/1168/478 245/1170/478 237/1169/478 +f 460/1172/478 312/1157/478 313/1147/478 459/1171/478 +f 308/1176/478 309/1175/478 474/1174/478 475/1173/478 +f 247/1151/478 248/1179/478 230/1178/478 231/1177/478 +f 297/1183/478 476/1182/478 477/1181/478 296/1180/478 +f 427/1187/478 428/1186/478 276/1185/478 277/1184/478 +f 295/1189/478 477/1181/478 478/1161/478 294/1188/478 +f 428/1186/478 429/1191/478 275/1190/478 276/1185/478 +f 279/1195/478 487/1194/478 426/1193/478 278/1192/478 +f 483/1199/478 484/1198/478 282/1197/478 283/1196/478 +f 245/1170/478 246/1152/478 236/1200/478 237/1169/478 +f 484/1198/478 485/1202/478 281/1201/478 282/1197/478 +f 486/1204/478 487/1194/478 279/1195/478 280/1203/478 +f 482/1129/478 483/1199/478 284/1205/478 285/1128/478 +f 401/1209/478 402/1208/478 403/1207/478 400/1206/478 +f 274/1212/478 275/1190/478 271/1211/478 272/1210/478 +f 485/1202/478 486/1204/478 280/1203/478 281/1201/478 +f 464/1215/478 310/1214/478 311/1158/478 463/1213/478 +f 426/1193/478 427/1187/478 277/1184/478 278/1192/478 +f 298/1216/478 475/1173/478 476/1182/478 297/1183/478 +f 248/1179/478 382/1219/478 383/1218/478 215/1217/478 +f 466/1221/478 309/1175/478 310/1214/478 465/1220/478 +f 398/1225/478 399/1224/478 212/1223/478 213/1222/478 +f 251/1229/478 349/1228/478 350/1227/478 249/1226/478 +f 264/1231/478 275/1190/478 435/1230/478 263/1132/478 +f 317/1235/478 346/1234/478 347/1233/478 316/1232/478 +f 425/1238/478 155/1237/478 198/1236/478 399/1224/478 +f 258/1148/478 447/1241/478 448/1240/478 257/1239/478 +f 315/1155/478 316/1232/478 453/1243/478 454/1242/478 +f 320/1247/478 324/1246/478 318/1245/478 319/1244/478 +f 453/1243/478 316/1232/478 347/1233/478 257/1239/478 +f 323/1250/478 324/1246/478 321/1249/478 322/1248/478 +f 400/1206/478 410/1252/478 411/1251/478 399/1224/478 +f 326/1254/478 327/1253/478 318/1245/478 324/1246/478 +f 403/1207/478 404/1256/478 405/1255/478 400/1206/478 +f 405/1255/478 406/1258/478 407/1257/478 400/1206/478 +f 397/1260/478 398/1225/478 213/1222/478 214/1259/478 +f 407/1257/478 408/1262/478 409/1261/478 400/1206/478 +f 257/1239/478 347/1233/478 348/1264/478 256/1263/478 +f 320/1247/478 321/1249/478 324/1246/478 +f 272/1210/478 273/1265/478 274/1212/478 +f 270/1266/478 271/1211/478 275/1190/478 +f 269/1267/478 270/1266/478 275/1190/478 +f 268/1268/478 269/1267/478 275/1190/478 +f 307/1269/478 308/1176/478 475/1173/478 +f 156/1272/478 157/1271/478 158/1270/478 +f 156/1272/478 158/1270/478 159/1273/478 +f 156/1272/478 159/1273/478 160/1274/480 +f 306/1275/478 307/1269/478 475/1173/478 +f 305/1276/478 306/1275/478 475/1173/478 +f 267/1277/478 268/1268/478 275/1190/478 +f 304/1278/478 305/1276/478 475/1173/478 +f 303/1279/478 304/1278/478 475/1173/478 +f 302/1280/478 303/1279/478 475/1173/478 +f 301/1281/478 302/1280/478 475/1173/478 +f 300/1282/478 301/1281/478 475/1173/478 +f 299/1283/478 300/1282/478 475/1173/478 +f 298/1216/478 299/1283/478 475/1173/478 +f 295/1189/478 296/1180/478 477/1181/478 +f 293/1162/478 294/1188/478 478/1161/478 +f 291/1284/478 292/1160/478 479/1140/478 +f 290/1141/478 291/1284/478 479/1140/478 +f 288/1134/478 289/1139/478 480/1136/478 +f 286/1131/478 287/1135/478 481/1130/478 +f 283/1196/478 284/1205/478 483/1199/478 +f 275/1190/478 429/1191/478 430/1285/478 +f 275/1190/478 430/1285/478 431/1286/478 +f 275/1190/478 431/1286/478 432/1287/478 +f 249/1226/478 250/1288/478 251/1229/478 +f 266/1289/478 267/1277/478 275/1190/478 +f 275/1190/478 432/1287/478 433/1290/478 +f 324/1246/478 325/1291/478 326/1254/478 +f 317/1235/478 318/1245/478 327/1253/478 +f 317/1235/478 327/1253/478 328/1292/478 +f 317/1235/478 328/1292/478 329/1293/478 +f 317/1235/478 329/1293/478 330/1294/478 +f 317/1235/478 330/1294/478 331/1295/478 +f 317/1235/478 331/1295/478 332/1296/478 +f 317/1235/478 332/1296/478 333/1297/478 +f 317/1235/478 333/1297/478 334/1298/478 +f 317/1235/478 334/1298/478 335/1299/478 +f 317/1235/478 335/1299/478 336/1300/478 +f 317/1235/478 336/1300/478 337/1301/478 +f 317/1235/478 337/1301/478 338/1302/478 +f 317/1235/478 338/1302/478 339/1303/478 +f 317/1235/478 339/1303/478 340/1304/478 +f 317/1235/478 340/1304/478 341/1305/478 +f 317/1235/478 341/1305/478 342/1306/478 +f 317/1235/478 342/1306/478 343/1307/478 +f 317/1235/478 343/1307/478 344/1308/478 +f 317/1235/478 344/1308/478 345/1309/479 +f 317/1235/478 345/1309/479 346/1234/478 +f 265/1310/478 266/1289/478 275/1190/478 +f 275/1190/478 433/1290/478 434/1311/478 +f 264/1231/478 265/1310/478 275/1190/478 +f 275/1190/478 434/1311/478 435/1230/478 +f 263/1132/478 435/1230/478 436/1312/480 +f 263/1132/478 436/1312/480 437/1313/480 +f 263/1132/478 437/1313/480 438/1314/480 +f 263/1132/478 438/1314/480 439/1315/480 +f 263/1132/478 439/1315/480 440/1316/480 +f 263/1132/478 440/1316/480 441/1133/478 +f 258/1148/478 446/1149/478 447/1241/478 +f 257/1239/478 448/1240/478 449/1317/480 +f 257/1239/478 449/1317/480 450/1318/480 +f 257/1239/478 450/1318/480 451/1319/480 +f 257/1239/478 451/1319/480 452/1320/480 +f 156/1272/478 160/1274/480 161/1321/480 +f 156/1272/478 161/1321/480 162/1322/480 +f 156/1272/478 162/1322/480 163/1323/480 +f 156/1272/478 163/1323/480 164/1324/480 +f 156/1272/478 164/1324/480 165/1325/480 +f 156/1272/478 165/1325/480 166/1326/480 +f 156/1272/478 166/1326/480 167/1327/480 +f 156/1272/478 167/1327/480 168/1328/480 +f 156/1272/478 168/1328/480 169/1329/480 +f 156/1272/478 169/1329/480 170/1330/480 +f 156/1272/478 170/1330/480 171/1331/480 +f 257/1239/478 452/1320/480 453/1243/478 +f 156/1272/478 171/1331/480 172/1332/480 +f 473/1333/478 474/1174/478 309/1175/478 +f 472/1334/478 473/1333/478 309/1175/478 +f 471/1335/478 472/1334/478 309/1175/478 +f 470/1336/478 471/1335/478 309/1175/478 +f 469/1337/478 470/1336/478 309/1175/478 +f 468/1338/478 469/1337/478 309/1175/478 +f 467/1339/478 468/1338/478 309/1175/478 +f 466/1221/478 467/1339/478 309/1175/478 +f 464/1215/478 465/1220/478 310/1214/478 +f 462/1159/478 463/1213/478 311/1158/478 +f 460/1172/478 461/1156/478 312/1157/478 +f 458/1144/478 459/1171/478 313/1147/478 +f 455/1340/478 456/1154/478 315/1155/478 +f 454/1242/478 455/1340/478 315/1155/478 +f 256/1263/478 348/1264/478 349/1228/478 +f 255/1341/478 256/1263/478 349/1228/478 +f 254/1342/478 255/1341/478 349/1228/478 +f 253/1343/478 254/1342/478 349/1228/478 +f 252/1344/478 253/1343/478 349/1228/478 +f 251/1229/478 252/1344/478 349/1228/478 +f 249/1226/478 350/1227/478 351/1345/478 +f 249/1226/478 351/1345/478 352/1346/478 +f 249/1226/478 352/1346/478 353/1347/478 +f 249/1226/478 353/1347/478 354/1348/478 +f 249/1226/478 354/1348/478 355/1349/478 +f 249/1226/478 355/1349/478 356/1350/478 +f 249/1226/478 356/1350/478 357/1351/478 +f 249/1226/478 357/1351/478 358/1352/478 +f 249/1226/478 358/1352/478 359/1353/478 +f 249/1226/478 359/1353/478 360/1354/478 +f 249/1226/478 360/1354/478 361/1355/478 +f 249/1226/478 361/1355/478 362/1356/478 +f 240/1166/478 241/1357/478 242/1165/478 +f 235/1358/478 236/1200/478 246/1152/478 +f 234/1153/478 235/1358/478 246/1152/478 +f 232/1359/478 233/1150/478 247/1151/478 +f 231/1177/478 232/1359/478 247/1151/478 +f 229/1360/478 230/1178/478 248/1179/478 +f 228/1361/478 229/1360/478 248/1179/478 +f 227/1362/478 228/1361/478 248/1179/478 +f 226/1363/478 227/1362/478 248/1179/478 +f 225/1364/478 226/1363/478 248/1179/478 +f 224/1365/478 225/1364/478 248/1179/478 +f 223/1366/478 224/1365/478 248/1179/478 +f 222/1367/478 223/1366/478 248/1179/478 +f 221/1368/478 222/1367/478 248/1179/478 +f 220/1369/478 221/1368/478 248/1179/478 +f 219/1370/478 220/1369/478 248/1179/478 +f 218/1371/478 219/1370/478 248/1179/478 +f 217/1372/478 218/1371/478 248/1179/478 +f 216/1373/478 217/1372/478 248/1179/478 +f 215/1217/478 216/1373/478 248/1179/478 +f 400/1206/478 409/1261/478 410/1252/478 +f 399/1224/478 411/1251/478 412/1374/478 +f 399/1224/478 412/1374/478 413/1375/478 +f 399/1224/478 413/1375/478 414/1376/478 +f 399/1224/478 414/1376/478 415/1377/478 +f 399/1224/478 415/1377/478 416/1378/478 +f 399/1224/478 416/1378/478 417/1379/478 +f 399/1224/478 417/1379/478 418/1380/478 +f 399/1224/478 418/1380/478 419/1381/478 +f 399/1224/478 419/1381/478 420/1382/478 +f 399/1224/478 420/1382/478 421/1383/478 +f 399/1224/478 421/1383/478 422/1384/478 +f 399/1224/478 422/1384/478 423/1385/478 +f 399/1224/478 423/1385/478 424/1386/478 +f 399/1224/478 424/1386/478 425/1238/478 +f 156/1272/478 172/1332/480 173/1387/480 +f 249/1226/478 362/1356/478 363/1388/478 +f 156/1272/478 173/1387/480 174/1389/480 +f 249/1226/478 363/1388/478 364/1390/478 +f 156/1272/478 174/1389/480 175/1391/480 +f 249/1226/478 364/1390/478 365/1392/478 +f 156/1272/478 175/1391/480 176/1393/480 +f 249/1226/478 365/1392/478 366/1394/478 +f 248/1179/478 249/1226/478 366/1394/478 +f 248/1179/478 366/1394/478 367/1395/478 +f 248/1179/478 367/1395/478 368/1396/478 +f 248/1179/478 368/1396/478 369/1397/478 +f 248/1179/478 369/1397/478 370/1398/478 +f 248/1179/478 370/1398/478 371/1399/478 +f 248/1179/478 371/1399/478 372/1400/478 +f 248/1179/478 372/1400/478 373/1401/478 +f 248/1179/478 373/1401/478 374/1402/478 +f 248/1179/478 374/1402/478 375/1403/478 +f 248/1179/478 375/1403/478 376/1404/478 +f 248/1179/478 376/1404/478 377/1405/478 +f 248/1179/478 377/1405/478 378/1406/478 +f 248/1179/478 378/1406/478 379/1407/478 +f 248/1179/478 379/1407/478 380/1408/478 +f 248/1179/478 380/1408/478 381/1409/478 +f 248/1179/478 381/1409/478 382/1219/478 +f 215/1217/478 383/1218/478 384/1410/480 +f 215/1217/478 384/1410/480 385/1411/480 +f 215/1217/478 385/1411/480 386/1412/480 +f 215/1217/478 386/1412/480 387/1413/480 +f 215/1217/478 387/1413/480 388/1414/480 +f 215/1217/478 388/1414/480 389/1415/480 +f 215/1217/478 389/1415/480 390/1416/480 +f 215/1217/478 390/1416/480 391/1417/480 +f 215/1217/478 391/1417/480 392/1418/480 +f 215/1217/478 392/1418/480 393/1419/480 +f 215/1217/478 393/1419/480 394/1420/480 +f 215/1217/478 394/1420/480 395/1421/478 +f 214/1259/478 215/1217/478 395/1421/478 +f 214/1259/478 395/1421/478 396/1422/481 +f 214/1259/478 396/1422/481 397/1260/478 +f 211/1423/478 212/1223/478 399/1224/478 +f 210/1424/478 211/1423/478 399/1224/478 +f 209/1425/478 210/1424/478 399/1224/478 +f 208/1426/478 209/1425/478 399/1224/478 +f 207/1427/478 208/1426/478 399/1224/478 +f 206/1428/478 207/1427/478 399/1224/478 +f 205/1429/478 206/1428/478 399/1224/478 +f 204/1430/478 205/1429/478 399/1224/478 +f 203/1431/478 204/1430/478 399/1224/478 +f 202/1432/478 203/1431/478 399/1224/478 +f 201/1433/478 202/1432/478 399/1224/478 +f 200/1434/478 201/1433/478 399/1224/478 +f 199/1435/478 200/1434/478 399/1224/478 +f 198/1236/478 199/1435/478 399/1224/478 +f 197/1436/478 198/1236/478 155/1237/478 +f 196/1437/478 197/1436/478 155/1237/478 +f 195/1438/478 196/1437/478 155/1237/478 +f 194/1439/478 195/1438/478 155/1237/478 +f 193/1440/478 194/1439/478 155/1237/478 +f 192/1441/478 193/1440/478 155/1237/478 +f 191/1442/478 192/1441/478 155/1237/478 +f 190/1443/478 191/1442/478 155/1237/478 +f 189/1444/478 190/1443/478 155/1237/478 +f 188/1445/478 189/1444/478 155/1237/478 +f 187/1446/478 188/1445/478 155/1237/478 +f 186/1447/478 187/1446/478 155/1237/478 +f 185/1448/478 186/1447/478 155/1237/478 +f 184/1449/478 185/1448/478 155/1237/478 +f 183/1450/478 184/1449/478 155/1237/478 +f 182/1451/478 183/1450/478 155/1237/478 +f 181/1452/478 182/1451/478 155/1237/478 +f 180/1453/478 181/1452/478 155/1237/478 +f 179/1454/478 180/1453/478 155/1237/478 +f 178/1455/478 179/1454/478 155/1237/478 +f 156/1272/478 176/1393/480 177/1456/478 +f 178/1455/478 155/1237/478 156/1272/478 +f 177/1456/478 178/1455/478 156/1272/478 +f 499/978/482 498/971/482 497/972/482 496/979/482 495/975/482 494/976/482 493/981/482 492/973/482 491/974/482 490/980/482 489/977/482 488/25/482 +f 641/1105/482 640/1038/482 639/1011/482 638/1012/482 637/1024/482 636/1026/482 635/1050/482 634/1051/482 633/1074/482 632/1081/482 631/1082/482 630/1096/482 629/1097/482 628/994/482 627/995/482 626/1109/482 625/1107/482 624/1034/482 623/1035/482 622/1089/482 621/1091/482 620/1094/482 619/1068/482 618/1069/482 617/1042/482 616/998/482 615/999/482 614/1008/482 613/985/482 612/982/482 611/1053/482 610/1113/482 609/1100/482 608/1040/482 607/1007/482 606/1005/482 605/1002/482 604/1003/482 603/1121/482 602/986/482 601/987/482 600/1031/482 599/1032/482 598/1099/482 597/1078/482 596/1079/482 595/1044/482 594/1045/482 593/1055/482 592/1063/482 591/1057/482 590/1020/482 589/1021/482 588/1122/482 587/1123/482 586/1028/482 585/1029/482 584/1088/482 583/1085/482 582/1077/482 581/1073/482 580/1067/482 579/1061/482 578/1062/482 577/1049/482 576/992/482 575/993/482 574/1017/482 573/1103/482 572/1104/482 571/1102/482 570/1015/482 569/1016/482 568/990/482 567/991/482 566/1048/482 565/1065/482 564/1059/482 563/1060/482 562/1066/482 561/1072/482 560/1076/482 559/1084/482 558/1087/482 557/1093/482 556/1115/482 555/1116/482 554/1117/482 553/1118/482 552/1030/482 551/1022/482 550/1023/482 549/1058/482 548/1064/482 547/1056/482 546/1046/482 545/1047/483 544/1080/482 543/1033/482 542/988/482 541/989/482 540/1004/482 539/1006/482 538/1041/482 537/1101/482 536/1054/482 535/983/482 534/984/482 533/1018/482 532/1019/482 531/1009/482 530/1010/482 529/1000/482 528/1001/482 527/1043/482 526/1086/482 525/1070/482 524/1071/482 523/1095/482 522/1092/482 521/1090/482 520/1036/482 519/1037/482 518/1110/482 517/1120/482 516/1119/482 515/1108/482 514/996/482 513/997/482 512/1098/482 511/1083/482 510/1075/482 509/1052/482 508/1027/482 507/1025/482 506/1013/482 505/1014/482 504/1039/482 503/1106/482 502/1112/482 501/1114/482 500/1111/482 +f 772/1128/482 969/1129/482 968/1130/482 773/1131/482 +f 774/1135/482 968/1130/482 967/1136/482 775/1134/482 +f 930/1126/482 748/1125/482 747/1137/482 931/1138/482 +f 967/1136/482 966/1140/482 777/1141/482 776/1139/482 +f 770/1196/482 970/1199/482 969/1129/482 771/1205/482 +f 931/1138/482 747/1137/482 746/1142/482 932/1143/482 +f 800/1147/482 945/1144/482 944/1145/482 801/1146/482 +f 932/1143/482 746/1142/482 745/1148/482 933/1149/482 +f 721/1153/482 720/1150/482 734/1151/482 733/1152/482 +f 801/1146/482 944/1145/482 943/1154/482 802/1155/482 +f 949/1159/482 948/1156/482 799/1157/482 798/1158/482 +f 966/1140/482 965/1161/482 779/1160/482 778/1284/482 +f 727/1166/482 726/1163/482 730/1164/482 729/1165/482 +f 726/1163/482 725/1167/482 731/1168/482 730/1164/482 +f 725/1167/482 724/1169/482 732/1170/482 731/1168/482 +f 947/1172/482 946/1171/482 800/1147/482 799/1157/482 +f 734/1151/482 718/1177/482 717/1178/482 735/1179/482 +f 763/1185/482 915/1186/482 914/1187/482 764/1184/482 +f 965/1161/482 964/1181/482 780/1162/482 779/1160/482 +f 762/1190/482 916/1191/482 915/1186/482 763/1185/482 +f 765/1192/482 913/1193/482 974/1194/482 766/1195/482 +f 769/1197/482 971/1198/482 970/1199/482 770/1196/482 +f 963/1182/482 962/1173/482 783/1180/482 782/1189/482 +f 732/1170/482 724/1169/482 723/1200/482 733/1152/482 +f 768/1201/482 972/1202/482 971/1198/482 769/1197/482 +f 780/1162/482 964/1181/482 963/1182/482 781/1188/482 +f 766/1195/482 974/1194/482 973/1204/482 767/1203/482 +f 783/1180/482 962/1173/482 961/1174/482 784/1183/482 +f 888/1209/482 887/1206/482 890/1207/482 889/1208/482 +f 761/1212/482 759/1210/482 758/1211/482 762/1190/482 +f 767/1203/482 973/1204/482 972/1202/482 768/1201/482 +f 951/1215/482 950/1213/482 798/1158/482 797/1214/482 +f 764/1184/482 914/1187/482 913/1193/482 765/1192/482 +f 961/1174/482 960/1333/482 786/1283/482 785/1216/482 +f 960/1333/482 959/1334/482 788/1281/482 787/1282/482 +f 735/1179/482 702/1217/482 870/1218/482 869/1219/482 +f 959/1334/482 958/1335/482 789/1280/482 788/1281/482 +f 954/1339/482 953/1221/482 795/1176/482 794/1269/482 +f 958/1335/482 957/1336/482 791/1278/482 790/1279/482 +f 957/1336/482 956/1337/482 792/1276/482 791/1278/482 +f 885/1225/482 700/1222/482 699/1223/482 886/1224/482 +f 953/1221/482 952/1220/482 796/1175/482 795/1176/482 +f 952/1220/482 951/1215/482 797/1214/482 796/1175/482 +f 956/1337/482 955/1338/482 793/1275/482 792/1276/482 +f 955/1338/482 954/1339/482 794/1269/482 793/1275/482 +f 756/1267/482 755/1268/482 928/1133/482 927/1316/482 +f 738/1229/482 736/1226/482 837/1227/482 836/1228/482 +f 929/1127/482 755/1268/482 754/1277/482 930/1126/482 +f 810/1250/482 807/1247/482 806/1244/482 811/1246/482 +f 804/1235/482 803/1232/482 834/1233/482 833/1234/482 +f 912/1238/482 886/1224/482 685/1236/482 642/1237/482 +f 745/1148/482 744/1239/482 935/1240/482 934/1241/482 +f 757/1266/482 756/1267/482 927/1316/482 762/1190/482 +f 802/1155/482 941/1242/482 940/1243/482 803/1232/482 +f 940/1243/482 744/1239/482 834/1233/482 803/1232/482 +f 887/1206/482 886/1224/482 899/1374/482 898/1251/482 +f 809/1248/482 808/1249/482 807/1247/482 810/1250/482 +f 813/1254/482 811/1246/482 805/1245/482 814/1253/482 +f 890/1207/482 887/1206/482 892/1255/482 891/1256/482 +f 892/1255/482 887/1206/482 894/1257/482 893/1258/482 +f 884/1260/482 701/1259/482 700/1222/482 885/1225/482 +f 894/1257/482 887/1206/482 896/1261/482 895/1262/482 +f 896/1261/482 887/1206/482 898/1251/482 897/1252/482 +f 744/1239/482 743/1263/482 835/1264/482 834/1233/482 +f 761/1212/482 760/1265/482 759/1210/482 +f 762/1190/482 758/1211/482 757/1266/482 +f 645/1270/482 644/1271/483 643/1272/482 +f 646/1273/482 645/1270/482 643/1272/482 +f 647/1274/482 646/1273/482 643/1272/482 +f 929/1127/482 928/1133/482 755/1268/482 +f 738/1229/482 737/1288/482 736/1226/482 +f 811/1246/482 806/1244/482 805/1245/482 +f 930/1126/482 754/1277/482 753/1289/483 +f 930/1126/482 753/1289/483 752/1310/483 +f 930/1126/482 752/1310/483 751/1231/483 +f 930/1126/482 751/1231/483 750/1132/483 +f 930/1126/482 750/1132/483 749/1124/483 +f 930/1126/482 749/1124/483 748/1125/482 +f 813/1254/482 812/1291/482 811/1246/482 +f 934/1241/482 933/1149/482 745/1148/482 +f 936/1317/482 935/1240/482 744/1239/482 +f 937/1318/482 936/1317/482 744/1239/482 +f 938/1319/482 937/1318/482 744/1239/482 +f 814/1253/482 805/1245/482 804/1235/482 +f 815/1292/482 814/1253/482 804/1235/482 +f 816/1293/482 815/1292/482 804/1235/482 +f 817/1294/482 816/1293/482 804/1235/482 +f 818/1295/482 817/1294/482 804/1235/482 +f 819/1296/482 818/1295/482 804/1235/482 +f 820/1297/482 819/1296/482 804/1235/482 +f 821/1298/482 820/1297/482 804/1235/482 +f 822/1299/482 821/1298/482 804/1235/482 +f 823/1300/482 822/1299/482 804/1235/482 +f 824/1301/482 823/1300/482 804/1235/482 +f 825/1302/482 824/1301/482 804/1235/482 +f 826/1303/482 825/1302/482 804/1235/482 +f 827/1304/482 826/1303/482 804/1235/482 +f 828/1305/482 827/1304/482 804/1235/482 +f 829/1306/482 828/1305/482 804/1235/482 +f 830/1307/482 829/1306/482 804/1235/482 +f 831/1308/482 830/1307/482 804/1235/482 +f 832/1309/482 831/1308/482 804/1235/482 +f 833/1234/482 832/1309/482 804/1235/482 +f 939/1320/482 938/1319/482 744/1239/482 +f 648/1321/482 647/1274/482 643/1272/482 +f 649/1322/482 648/1321/482 643/1272/482 +f 650/1323/482 649/1322/482 643/1272/482 +f 651/1324/482 650/1323/482 643/1272/482 +f 652/1325/482 651/1324/482 643/1272/482 +f 653/1326/482 652/1325/482 643/1272/482 +f 654/1327/482 653/1326/482 643/1272/482 +f 655/1328/482 654/1327/482 643/1272/482 +f 656/1329/482 655/1328/482 643/1272/482 +f 657/1330/482 656/1329/482 643/1272/482 +f 658/1331/482 657/1330/482 643/1272/482 +f 940/1243/482 939/1320/482 744/1239/482 +f 762/1190/482 927/1316/482 926/1315/482 +f 762/1190/482 926/1315/482 925/1314/482 +f 762/1190/482 925/1314/482 924/1313/482 +f 762/1190/482 924/1313/482 923/1312/482 +f 762/1190/482 923/1312/482 922/1230/482 +f 762/1190/482 922/1230/482 921/1311/482 +f 762/1190/482 921/1311/482 920/1290/482 +f 762/1190/482 920/1290/482 919/1287/482 +f 762/1190/482 919/1287/482 918/1286/482 +f 762/1190/482 918/1286/482 917/1285/482 +f 762/1190/482 917/1285/482 916/1191/482 +f 772/1128/482 771/1205/482 969/1129/482 +f 774/1135/482 773/1131/482 968/1130/482 +f 776/1139/482 775/1134/482 967/1136/482 +f 778/1284/482 777/1141/482 966/1140/482 +f 782/1189/482 781/1188/482 963/1182/482 +f 785/1216/482 784/1183/482 961/1174/482 +f 787/1282/482 786/1283/482 960/1333/482 +f 790/1279/482 789/1280/482 958/1335/482 +f 798/1158/482 950/1213/482 949/1159/482 +f 799/1157/482 948/1156/482 947/1172/482 +f 800/1147/482 946/1171/482 945/1144/482 +f 802/1155/482 943/1154/482 942/1340/482 +f 802/1155/482 942/1340/482 941/1242/482 +f 836/1228/482 835/1264/482 743/1263/482 +f 836/1228/482 743/1263/482 742/1341/482 +f 836/1228/482 742/1341/482 741/1342/482 +f 836/1228/482 741/1342/482 740/1343/482 +f 836/1228/482 740/1343/482 739/1344/482 +f 836/1228/482 739/1344/482 738/1229/482 +f 838/1345/482 837/1227/482 736/1226/482 +f 839/1346/482 838/1345/482 736/1226/482 +f 840/1347/482 839/1346/482 736/1226/482 +f 841/1348/482 840/1347/482 736/1226/482 +f 842/1349/482 841/1348/482 736/1226/482 +f 843/1350/482 842/1349/482 736/1226/482 +f 844/1351/482 843/1350/482 736/1226/482 +f 845/1352/482 844/1351/482 736/1226/482 +f 846/1353/482 845/1352/482 736/1226/482 +f 847/1354/482 846/1353/482 736/1226/482 +f 848/1355/482 847/1354/482 736/1226/482 +f 659/1332/482 658/1331/482 643/1272/482 +f 849/1356/482 848/1355/482 736/1226/482 +f 729/1165/482 728/1357/482 727/1166/482 +f 733/1152/482 723/1200/482 722/1358/482 +f 733/1152/482 722/1358/482 721/1153/482 +f 734/1151/482 720/1150/482 719/1359/482 +f 734/1151/482 719/1359/482 718/1177/482 +f 735/1179/482 717/1178/482 716/1360/483 +f 735/1179/482 716/1360/483 715/1361/483 +f 735/1179/482 715/1361/483 714/1362/483 +f 735/1179/482 714/1362/483 713/1363/483 +f 735/1179/482 713/1363/483 712/1364/483 +f 735/1179/482 712/1364/483 711/1365/483 +f 735/1179/482 711/1365/483 710/1366/483 +f 735/1179/482 710/1366/483 709/1367/483 +f 735/1179/482 709/1367/483 708/1368/483 +f 735/1179/482 708/1368/483 707/1369/483 +f 735/1179/482 707/1369/483 706/1370/483 +f 735/1179/482 706/1370/483 705/1371/483 +f 735/1179/482 705/1371/483 704/1372/483 +f 735/1179/482 704/1372/483 703/1373/483 +f 735/1179/482 703/1373/483 702/1217/482 +f 900/1375/482 899/1374/482 886/1224/482 +f 901/1376/482 900/1375/482 886/1224/482 +f 902/1377/482 901/1376/482 886/1224/482 +f 903/1378/482 902/1377/482 886/1224/482 +f 904/1379/482 903/1378/482 886/1224/482 +f 905/1380/482 904/1379/482 886/1224/482 +f 906/1381/482 905/1380/482 886/1224/482 +f 907/1382/482 906/1381/482 886/1224/482 +f 908/1383/482 907/1382/482 886/1224/482 +f 909/1384/482 908/1383/482 886/1224/482 +f 910/1385/482 909/1384/482 886/1224/482 +f 911/1386/482 910/1385/482 886/1224/482 +f 912/1238/482 911/1386/482 886/1224/482 +f 660/1387/482 659/1332/482 643/1272/482 +f 850/1388/482 849/1356/482 736/1226/482 +f 661/1389/482 660/1387/482 643/1272/482 +f 851/1390/482 850/1388/482 736/1226/482 +f 662/1391/482 661/1389/482 643/1272/482 +f 852/1392/482 851/1390/482 736/1226/482 +f 663/1393/482 662/1391/482 643/1272/482 +f 853/1394/482 852/1392/482 736/1226/482 +f 853/1394/482 736/1226/482 735/1179/482 +f 854/1395/482 853/1394/482 735/1179/482 +f 855/1396/482 854/1395/482 735/1179/482 +f 856/1397/482 855/1396/482 735/1179/482 +f 857/1398/482 856/1397/482 735/1179/482 +f 858/1399/482 857/1398/482 735/1179/482 +f 859/1400/482 858/1399/482 735/1179/482 +f 860/1401/482 859/1400/482 735/1179/482 +f 861/1402/482 860/1401/482 735/1179/482 +f 862/1403/482 861/1402/482 735/1179/482 +f 863/1404/482 862/1403/482 735/1179/482 +f 864/1405/482 863/1404/482 735/1179/482 +f 865/1406/482 864/1405/482 735/1179/482 +f 866/1407/482 865/1406/482 735/1179/482 +f 867/1408/482 866/1407/482 735/1179/482 +f 868/1409/482 867/1408/482 735/1179/482 +f 869/1219/482 868/1409/482 735/1179/482 +f 871/1410/482 870/1218/482 702/1217/482 +f 872/1411/482 871/1410/482 702/1217/482 +f 873/1412/482 872/1411/482 702/1217/482 +f 874/1413/482 873/1412/482 702/1217/482 +f 875/1414/482 874/1413/482 702/1217/482 +f 876/1415/482 875/1414/482 702/1217/482 +f 877/1416/482 876/1415/482 702/1217/482 +f 878/1417/482 877/1416/482 702/1217/482 +f 879/1418/482 878/1417/482 702/1217/482 +f 880/1419/482 879/1418/482 702/1217/482 +f 881/1420/482 880/1419/482 702/1217/482 +f 882/1421/482 881/1420/482 702/1217/482 +f 882/1421/482 702/1217/482 701/1259/482 +f 883/1422/482 882/1421/482 701/1259/482 +f 884/1260/482 883/1422/482 701/1259/482 +f 886/1224/482 699/1223/482 698/1423/483 +f 886/1224/482 698/1423/483 697/1424/483 +f 886/1224/482 697/1424/483 696/1425/483 +f 886/1224/482 696/1425/483 695/1426/483 +f 886/1224/482 695/1426/483 694/1427/483 +f 886/1224/482 694/1427/483 693/1428/483 +f 886/1224/482 693/1428/483 692/1429/483 +f 886/1224/482 692/1429/483 691/1430/483 +f 886/1224/482 691/1430/483 690/1431/483 +f 886/1224/482 690/1431/483 689/1432/483 +f 886/1224/482 689/1432/483 688/1433/483 +f 886/1224/482 688/1433/483 687/1434/483 +f 886/1224/482 687/1434/483 686/1435/483 +f 886/1224/482 686/1435/483 685/1236/482 +f 642/1237/482 685/1236/482 684/1436/484 +f 642/1237/482 684/1436/484 683/1437/484 +f 642/1237/482 683/1437/484 682/1438/484 +f 642/1237/482 682/1438/484 681/1439/484 +f 642/1237/482 681/1439/484 680/1440/484 +f 642/1237/482 680/1440/484 679/1441/484 +f 642/1237/482 679/1441/484 678/1442/484 +f 642/1237/482 678/1442/484 677/1443/484 +f 642/1237/482 677/1443/484 676/1444/484 +f 642/1237/482 676/1444/484 675/1445/484 +f 642/1237/482 675/1445/484 674/1446/484 +f 642/1237/482 674/1446/484 673/1447/484 +f 642/1237/482 673/1447/484 672/1448/484 +f 642/1237/482 672/1448/484 671/1449/484 +f 642/1237/482 671/1449/484 670/1450/484 +f 642/1237/482 670/1450/484 669/1451/484 +f 642/1237/482 669/1451/484 668/1452/484 +f 642/1237/482 668/1452/484 667/1453/484 +f 642/1237/482 667/1453/484 666/1454/482 +f 642/1237/482 666/1454/482 665/1455/482 +f 664/1456/482 663/1393/482 643/1272/482 +f 665/1455/482 664/1456/482 643/1272/482 +f 642/1237/482 665/1455/482 643/1272/482 + diff --git a/Assets/Samples/Assets/StashLogo.obj.meta b/Assets/Samples/Assets/StashLogo.obj.meta new file mode 100644 index 0000000..d1df939 --- /dev/null +++ b/Assets/Samples/Assets/StashLogo.obj.meta @@ -0,0 +1,114 @@ +fileFormatVersion: 2 +guid: 3890e353e9a8b44989fdcec78d682777 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: + - first: + type: UnityEngine:Material + assembly: UnityEngine.CoreModule + name: defaultMat + second: {fileID: 2100000, guid: 23a8ea9b4bff34a3ca6fbc9d4bac338c, type: 2} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Assets/StashMaterial.mat b/Assets/Samples/Assets/StashMaterial.mat new file mode 100644 index 0000000..29ab11d --- /dev/null +++ b/Assets/Samples/Assets/StashMaterial.mat @@ -0,0 +1,84 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: StashMaterial + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _EMISSION + m_InvalidKeywords: [] + m_LightmapFlags: 2 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: -1 + stringTagMap: {} + disabledShaderPasses: [] + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 0 + - _GlossMapScale: 1 + - _Glossiness: 0.88 + - _GlossyReflections: 1 + - _Metallic: 1 + - _Mode: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 1 + m_Colors: + - _Color: {r: 1, g: 0.9333334, b: 0, a: 1} + - _EmissionColor: {r: 0.03773582, g: 0.032100324, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Samples/Assets/StashMaterial.mat.meta b/Assets/Samples/Assets/StashMaterial.mat.meta new file mode 100644 index 0000000..77e51ad --- /dev/null +++ b/Assets/Samples/Assets/StashMaterial.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 23a8ea9b4bff34a3ca6fbc9d4bac338c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies.meta b/Assets/Samples/Dependencies.meta new file mode 100644 index 0000000..4909b09 --- /dev/null +++ b/Assets/Samples/Dependencies.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6d161ba6ee51e43b0980d987c02d9ea8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Apple.Core.meta b/Assets/Samples/Dependencies/Apple.Core.meta new file mode 100644 index 0000000..9aa1722 --- /dev/null +++ b/Assets/Samples/Dependencies/Apple.Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8d26417a25e1944f1b7750a18abb2b4f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Apple.Core/Editor.meta b/Assets/Samples/Dependencies/Apple.Core/Editor.meta new file mode 100644 index 0000000..45c0d3f --- /dev/null +++ b/Assets/Samples/Dependencies/Apple.Core/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 440b602cefc764323afc8d5c9d3e961b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Apple.Core/Editor/DefaultAppleBuildProfile.asset b/Assets/Samples/Dependencies/Apple.Core/Editor/DefaultAppleBuildProfile.asset new file mode 100644 index 0000000..8d10cbd --- /dev/null +++ b/Assets/Samples/Dependencies/Apple.Core/Editor/DefaultAppleBuildProfile.asset @@ -0,0 +1,97 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8987626434458726503 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88a319fb99484804b632ce9bbec4cf6d, type: 3} + m_Name: AppleSecurityBuildStep + m_EditorClassIdentifier: + IsEnabled: 1 + AppSandboxEntitlement: 1 + AllowNetworkServer: 0 + AllowNetworkClient: 0 + AllowCamera: 0 + AllowMicrophone: 0 + AllowUsb: 0 + AllowPrint: 0 + AllowBluetooth: 0 + AllowAddressBook: 0 + AllowLocation: 0 + AllowCalendars: 0 + AllowUserSelectedReadOnly: 0 + AllowUserSelectedReadWrite: 0 + AllowDownloadsReadOnly: 0 + AllowDownloadsReadWrite: 0 + AllowPicturesReadOnly: 0 + AllowPicturesReadWrite: 0 + AllowMusicReadOnly: 0 + AllowMusicReadWrite: 0 + AllowMoviesReadOnly: 0 + AllowMoviesReadWrite: 0 +--- !u!114 &-4631973922516641064 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 24e6011bb95664520aa4858e4c359e06, type: 3} + m_Name: AppleGameKitBuildStep + m_EditorClassIdentifier: + IsEnabled: 1 +--- !u!114 &-1182492731493557681 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c6b8a8fe473224decaaecc9264d56e95, type: 3} + m_Name: AppleCoreBuildStep + m_EditorClassIdentifier: + IsEnabled: 1 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6b2797781d18e4c5987f2acb206f9e7b, type: 3} + m_Name: DefaultAppleBuildProfile + m_EditorClassIdentifier: + AutomateInfoPlist: 1 + DefaultInfoPlist: {fileID: 0} + MinimumOSVersion_iOS: + MinimumOSVersion_tvOS: + MinimumOSVersion_macOS: + AppUsesNonExemptEncryption: 0 + AutomateEntitlements: 1 + DefaultEntitlements: {fileID: 0} +--- !u!114 &750258044150326352 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe2e2f0820ab4779ac857f0e06bac5fb, type: 3} + m_Name: AppleUserManagementBuildStep + m_EditorClassIdentifier: + IsEnabled: 0 + AllowGetCurrentUser: 0 + AllowRunsAsCurrentUser: 0 diff --git a/Assets/Samples/Dependencies/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta b/Assets/Samples/Dependencies/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta new file mode 100644 index 0000000..5ac1fa9 --- /dev/null +++ b/Assets/Samples/Dependencies/Apple.Core/Editor/DefaultAppleBuildProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 97417ebe3a84845f5839ba872b72c9bf +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager.meta b/Assets/Samples/Dependencies/ExternalDependencyManager.meta new file mode 100644 index 0000000..2bca98e --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1823bf77a280153a7ac7dc8f36992da0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor.meta new file mode 100644 index 0000000..da33852 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28dc314a271982f84bce39c140774128 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169.meta new file mode 100644 index 0000000..ac29514 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 915c158b06079337fb2ca40f56727c1d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll new file mode 100755 index 0000000..214390d Binary files /dev/null and b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll differ diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll.meta new file mode 100644 index 0000000..396b966 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll.meta @@ -0,0 +1,38 @@ +fileFormatVersion: 2 +guid: e2b1894e7d784825bf9719c33331fae8 +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll +- gvhp_targets-editor +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + 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: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll new file mode 100755 index 0000000..4761399 Binary files /dev/null and b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll differ diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll.meta new file mode 100644 index 0000000..05bf9c0 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll.meta @@ -0,0 +1,38 @@ +fileFormatVersion: 2 +guid: 2730c87d98d4480884d11cfb29ff72cb +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll +- gvhp_targets-editor +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + 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: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll new file mode 100755 index 0000000..b23356b Binary files /dev/null and b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll differ diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll.meta new file mode 100644 index 0000000..7676ed7 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll.meta @@ -0,0 +1,38 @@ +fileFormatVersion: 2 +guid: 3ed19a202c4b4b439183dc00efee3c4a +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll +- gvhp_targets-editor +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + 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: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll new file mode 100755 index 0000000..215b999 Binary files /dev/null and b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll differ diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll.meta new file mode 100644 index 0000000..d26a581 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll.meta @@ -0,0 +1,38 @@ +fileFormatVersion: 2 +guid: 14338063180a4626be53643cb2ab5d69 +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll +- gvhp_targets-editor +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + 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: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/CHANGELOG.md b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/CHANGELOG.md new file mode 100755 index 0000000..79d7b94 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/CHANGELOG.md @@ -0,0 +1,1338 @@ +# Version 1.2.169 - Jan 20, 2021 +* General - Fixes #425 - Change to save `GvhProjectSettings.xml` without + Unicode byte order mark (BoM). +* Android Resolver - Remove reference to `jcenter()` +* iOS Resolver - Force setting `LANG` when executing Cocoapods in shell mode on + Mac. + +# Version 1.2.168 - Dec 9, 2021 +* All - Fixes #472 by removing the use of `System.Diagnostics.Debug.Assert` +* All - Fixed #477 by properly enabling EDM4U libraries for Unity 2021.2+ when + the package is installed through `.tgz` + +# Version 1.2.167 - Oct 6, 2021 +* All - Moved versioned `.dll` in EDM4U to a versioned folder and remove their + version postfix in their filename. For instance, `IOSResolver.dll` will be + placed at `ExternalDependencyManager/Editor/1.2.167/Google.IOSResolver.dll`. +* Android Resolver - Fixed #243 by only using the highest version in + `mainTemplate.gradle` when duplicated dependencies are presented. +* Android Resolver - Added supports to x86_64 to ABI list for Android apps on + Chrome OS. + +# Version 1.2.166 - Jun 30, 2021 +* All - Fixed #440 and fixed #447 by specifying the parameter type while calling + `GetApplicationIdentifier()` Unity API using reflection, due to a new + overloaded method introduced in Unity 2021.2. +* Android Resolver - Fixed #442 by patching `Dependency.IsGreater()` when the + version strings end '+'. + +# Version 1.2.165 - Apr 28, 2021 +## Bug Fixes +* Version Handler - Fixed #431 by replacing the use of `HttpUtility.UrlEncode()` + which causes NullReferenceException in certain version of Unity. +* Android Resolver - Check that androidSdkRootPath directory exists before using + as sdkPath. +* Android Resolver - Fixed Android Resolver integration tests with Unity + 2019.3+. + +# Version 1.2.164 - Feb 4, 2021 +## New Features +* Android Resolver - Added support for Android packages with classifier in their + namespaces. +* iOS Resolver - Added new settings in iOS Resolver to configure generated + Podfile. +* iOS Resolver - Added a new attribute `addToAllTargets` in Dependencies.xml. + +## Bug Fixes +* iOS Resolver - Fixed XML parsing for `bitcodeEnabled` attribute in + Dependencies.xml. + +# Version 1.2.163 - Dec 15, 2020 +## Bug Fixes +* Version Handler - Fixed measurement reporting + +# Version 1.2.162 - Nov 19, 2020 +## Bug Fixes +* Version Handler - Improved #413 by preventing Version Handler from running + from static constructor when it is disabled. +* Package Manager Resolver - Remove GPR + +# Version 1.2.161 - Oct 12, 2020 +## Bug Fixes +* Android Resolver - Fixed the issue that Android Resolver does not resolve + again before build in Unity 2020 if it failed to resolve previously. + +# Version 1.2.160 - Sep 30, 2020 +## Bug Fixes +* Android Resolver - Fixed a regression that gradleResolver can be null until + Initialize() is called. +* Android Resolver - Fixed a regression that Android Resolver failed in Unity + 2019.3+ due to `gradleTemplate.properties` not enabled when + `mainTemplate.gradle` is not enabled at all. + +# Version 1.2.159 - Sep 11, 2020 +## Bug Fixes +* Android Resolver - Fixed #322 where the Unity editor will lose its target SDK + setting between Unity restarts if `>28` is selected in 2019. This is due to + Unity AndroidSdkVersions enum does not contain values above 28. +* Android Resolver - Fixed #360 where building Android app with Untiy 2019.3+ + may fail due to Jetifier and AndroidX not enabled properly in generated + Gradle project. This fix requires the user to enable + `Custom Gradle Properties Template` found under + `Player Settings > Settings for Android > Publishing Settings`. + +# Version 1.2.158 - Sep 3, 2020 +## Bug Fixes +* Version Handler: Fixed editor freeze when `-executeMethod` is used in + non-batch mode. +* Android Resolver: Normalized file paths when generating local Maven repo + since the path may contains a mix of forward and backward slash on Windows. +* Export Unity Package: Fixed generation of .unitypackage with tarfile on + Windows. + +# Version 1.2.157 - Aug 6, 2020 +## Bug Fixes +* Android Resolver: Delay initialization until active build target is Android + and the editor is not in play mode. +* iOS Resolver: Delay initialization until active build target is iOS + and the editor is not in play mode. +* Export Unity Package: Workaround directory creation racy if multiple export + operations are spawned at the same time. + +# Version 1.2.156 - June 10, 2020 +## Bug Fixes +* Android Resolver: Fixed that the generated local repo assets contains + redundent labels which are causing Version Handler to failed while + uninstalling packages. +* Android Resolver: Fixed that the repo url injected into mainTemplate.gradle + is incorrect when Unity is configured to export gradle project. +* Android Resolver: Limited to only create local Maven repo when the source + repo contains ".srcaar" file. + +## Changes +* All: Described EDM4U analytics data usage in readme. + +# Version 1.2.155 - May 14, 2020 +## Bug Fixes +* All: Fixed compiler error when build with Unity 5.4 or below due to the + usage of Rect.zero. +* All: Ignore cases when checking command line arguments. + +# Version 1.2.154 - May 14, 2020 +## Bug Fixes +* All: Make each MultiSelectWindow for different purposes to have its own + unique window. + +## Changes +* All: Replace all dialog with DialogWindow which is implemented from + EditorWindow. +* Package Manager Resolver: Clarify how manifest.json will be changed in Package + Manager Resolver window. + +# Version 1.2.153 - Apr 24, 2020 +## Bug Fixes +* Android Resolver: Fixed an exception when repainting the Android resolution + window in Unity 2019.3.x. + +# Version 1.2.152 - Apr 17, 2020 +## Bug Fixes +* Version Handler: Fixed exception when waiting for enabled editor DLLs to + load. +* Android Resolver: Fixed regression when using a Custom Gradle Template + on Windows. + +# Version 1.2.151 - Apr 16, 2020 +## Bug Fixes +* Version Handler: When waiting for newly enabled editor DLLs to load, ignore + all DLLs that do not have a file-system location. +* Android Resolver: Fixed resolution when using a Custom Gradle Template with + libraries stored in a local maven repository distributed with a plugin + installed with the Unity Package Manager. + +# Version 1.2.150 - Apr 9, 2020 +## Bug Fixes +* All: The new packaging script when run on MacOS was generating a + .unitypackage archive that could not be read by Unity on Windows. + This release simply repackages the plugin with tar/gzip to fix the problem. + +# Version 1.2.149 - Apr 8, 2020 +## Bug Fixes +* Package Manager Resolver: Fixed spurious error message when resuming + migration after installing a UPM package. + +# Version 1.2.148 - Apr 8, 2020 +## Bug Fixes +* Package Manager Resolver: Fixed an exception when resuming migration + after installing a UPM package. + +# Version 1.2.147 - Apr 8, 2020 +## Bug Fixes +* Version Handler: Fixed alias traversal bug which caused problems when + migrating from installed .unitypackage files to UPM packages. + +# Version 1.2.146 - Apr 8, 2020 +## Bug Fixes +* Version Handler: Fixed exception in manifest parsing when a manifest is + detected with no aliases. + +# Version 1.2.145 - Apr 2, 2020 +## New Features +* Package Manager Resolver: Added a method to migrate Version Handler + managed packages installed via `.unitypackage` to Unity Package Manager + packages. This is initially used to migrate the External Dependency Manager + to UPM. + +## Changes +* All: Verbose logging is now no longer automatically enabled in batch mode + across all components. Instead logging can be configured using each + component's verbose logging setting or by using the `-gvh_log_debug` command + line flag when starting Unity. +* Version Handler: Sped up version handler updates when the app domain isn't + reloaded. + +## Bug Fixes +* Version Handler: Fixed the display of the obsolete files clean up dialog + when the asset database refreshes. +* Version Handler: Improved reliability of callback from + the VersionHandler.UpdateCompleteMethods event when an asset database + refresh occurs. +* Version Handler: Fixed duplicate exportPath labels when 'Assets/' is the + root of paths assigned to files. +* Version Handler: Handle empty lines in manifest files. + +# Version 1.2.144 - Mar 23, 2020 +## Changed +* iOS Resolver: Removed the ability to configure the Xcode target a Cocoapod + is added to. + +## Bug Fixes +* iOS Resolver: Reverted support for adding Cocoapods to multiple targets as + it caused a regression (exception thrown during post-build step) in some + versions of Unity. + +# Version 1.2.143 - Mar 20, 2020 +## Bug Fixes +* Android Resolver: Fixed caching of resolution state which was causing + the resolver to always run when no dependencies had changed. + +# Version 1.2.142 - Mar 19, 2020 +## Changes +* Package Manager Resolver: Enabled auto-add by default. + +# Version 1.2.141 - Mar 19, 2020 +## Bug Fixes +* Fixed a bug when retrieving project settings. If a plugin was configured + to fetch project settings, if a setting was fetched (e.g "foo") and this + setting existed in the system settings but not the project settings the + system value would override the default value leading to unexpected + behavior. +* Fixed a warning when caching web request classes in Unity 5.6. + +# Version 1.2.140 - Mar 19, 2020 +## Bug Fixes +* Fixed measurement reporting in Unity 5.x. +* Version Handler: Fixed NullReferenceException when an asset doesn't have + an AssetImporter. + +# Version 1.2.139 - Mar 18, 2020 +## Changed +* Added documentation to the built plugin. + +# Version 1.2.138 - Mar 17, 2020 +## New Features +* Package Manager Resolver: Added the Package Manager Resolver + component that allows developers to easily boostrap Unity Package Manager + (UPM) registry addition using unitypackage plugins. +* Version Handler: Added a window that allows plugins to managed by the + Version Handler to be uninstalled. +* Version Handler: Added support for displaying installed plugins. +* Version Handler: Added support for moving files in plugins to their install + locations (if the plugin has been configured to support this). +* iOS Resolver: Added the ability to configure the Xcode target a Cocoapod is + added to. + +## Bug Fixes +* Fixed upgrade from version 1.2.137 and below after the plugin rename to + EDM4U broke the upgrade process. +* Android Resolver: Worked around PlayerSettings.Android.targetSdkVersion + returning empty names for some values in 2019.x. +* Version Handler: Fixed the display of the obsolete files clean up window. +* Version Handler: Fixed managed file check when assets are modified in the + project after plugin import. + +# Version 1.2.137 - Mar 6, 2020 +## Changed +* Renamed package to External Package Manager for Unity (EDM4U). + We changed this to reflect what this plugin is doing today which is far more + than the original scope which just consisted of importing jar files from the + Android SDK maven repository. + Scripts that used to pull `play-services-resolver*.unitypackage` will now have + to request `external-dependency-manager*.unitypackage` instead. + We'll still be shipping a `play-services-resolver*_manifest.txt` file to + handle upgrading from older versions of the plugin. + +## New Features +* All Components: Added reporting of usage so that we can remotely detect + errors and target improvements. +* Android Resolver: Added support for *Dependencies.xml files in Unity Package + Manager packages. +* iOS Resolver: Added support for *Dependencies.xml files in Unity Package + Manager packages. + +## Bug Fixes +* Version Handler: Disabled attempts to disable asset metadata modification + when assets are in a Unity Package Manager managed package. + +# Version 1.2.136 - Feb 19, 2019 +## Bug Fixes +* Android Resolver: Fixed OpenJDK path discovery in Unity 2019.3.1. + +# Version 1.2.135 - Dec 5, 2019 +## Bug Fixes +* All Components: Fixed stack overflow when loading project settings. + +# Version 1.2.134 - Dec 4, 2019 +## Bug Fixes +* All Components: Fixed an issue which caused project settings to be cleared + when running in batch mode. + +# Version 1.2.133 - Nov 18, 2019 +## Bug Fixes +* All Components: Failure to save project settings will now report an error + to the log rather than throwing an exception. + +# Version 1.2.132 - Nov 11, 2019 +## Bug Fixes +* Android Resolver: Worked around expansion of DIR_UNITYPROJECT on Windows + breaking Gradle builds when used as part of a file URI. +* Android Resolver: mainTemplate.gradle is only written if it needs to be + modified. + +# Version 1.2.131 - Oct 29, 2019 +## Bug Fixes +* Version Handler: Improved execution of events on the main thread in batch + mode. +* Version Handler: Improved log level configuration at startup. +* Version Handler: Improved performance of class lookup in deferred method + calls. +* Version Handler: Fixed rename to enable / disable for editor assets. +* iOS Resolver: Improved log level configuration at startup. +* Android Resolver: Improved local maven repo path reference in + mainTemplate.gradle using DIR_UNITYPROJECT. DIR_UNITYPROJECT by Unity + to point to the local filesystem path of the Unity project when Unity + generates the Gradle project. + +# Version 1.2.130 - Oct 23, 2019 +## New Features +* iOS Resolver: Added support for modifying the Podfile before `pod install` + is executed. + +## Bug Fixes +* Version Handler: Fixed invalid classname error when calling + `VersionHandler.UpdateVersionedAssets()`. + +# Version 1.2.129 - Oct 2, 2019 +## Bug Fixes +* iOS Resolver: Changed Cocoapod integration in Unity 2019.3+ to + only add Pods to the UnityFramework target. + +# Version 1.2.128 - Oct 1, 2019 +## Bug Fixes +* iOS Resolver: Fixed Cocoapod project integration mode with Unity + 2019.3+. + +# Version 1.2.127 - Sep 30, 2019 +## Changes +* Android Resolver: All Android Resolver settings File paths are now + serialized with POSIX directory separators. + +# Version 1.2.126 - Sep 27, 2019 +## Changes +* Android Resolver: File paths are now serialized with POSIX directory + separators. +## Bug Fixes +* Android Resolver: Fixed resolution when the parent directory of a Unity + project contains a Gradle project (i.e `settings.gradle` file). + +# Version 1.2.125 - Sep 23, 2019 +## Bug Fixes +* All components: Silenced a warning about not being able to set the console + encoding to UTF8. +* Android Resolver: Worked around broken AndroidSDKTools class in some + versions of Unity. +* iOS Resolver: Fixed iOS target SDK version check +* Version Handler: Changed clean up obsolete files window so that it doesn't + exceed the screen size. + +# Version 1.2.124 - Jul 28, 2019 +## Bug Fixes +* All components: Fixed regression with source control integration when using + Unity 2019.1+. + +# Version 1.2.123 - Jul 23, 2019 +## New Features +* All components: Source control integration for project settings. +## Changes +* Android Resolver: Removed AAR cache as it now makes little difference to + incremental resolution performance. +* Android Resolver: Improved embedded resource management so that embedded + resources should upgrade when the plugin is updated without restarting + the Unity editor. +## Bug Fixes +* Version Handler: Fixed InvokeMethod() and InvokeStaticMethod() when calling + methods that have interface typed arguments. + +# Version 1.2.122 - Jul 2, 2019 +## Bug Fixes +* iOS Resolver: Worked around Unity not loading the iOS Resolver DLL as it + referenced the Xcode extension in a public interface. The iOS Resolver + DLL still references the Xcode extension internally and just handles + missing type exceptions dynamically. + +# Version 1.2.121 - Jun 27, 2019 +## Bug Fixes +* Android Resolver: Fixed warning about missing Packages folder when loading + XML dependencies files in versions of Unity without the package manager. +* Android Resolver: Fixed resolution window progress bar exceeding 100%. +* Android Resolver: If AndroidX is detected in the set of resolved libraries, + the user will be prompted to enable the Jetifier. +* Android Resolver: Improved text splitting in text area windows. +* iOS Resolver: Added support for Unity's breaking changes to the Xcode API + in 2019.3.+. Cocoapods are now added to build targets, Unity-iPhone and + UnityFramework in Unity 2019.3+. + +# Version 1.2.120 - Jun 26, 2019 +## New Features +* Android Resolver: Added support for loading *Dependencies.xml files from + Unity Package Manager packages. +* Android Resolver: Resolution window is now closed if resolution runs as + a pre-build step. +* iOS Resolver: Added support for loading *Dependencies.xml files from + Unity Package Manager packages. +## Bug Fixes +* Android Resolver: Fixed generation of relative repo paths when using + mainTemplate.gradle resolver. +* Android Resolver: Fixed copy of .srcaar to .aar files in repos embedded in a + project when a project path has characters (e.g whitespace) that are escaped + during conversion to URIs. +* Android Resolver: Fixed auto-resolution always running if the Android SDK + is managed by Unity Hub. + +# Version 1.2.119 - Jun 19, 2019 +## Bug Fixes +* Android Resolver: Fixed error reported when using Jetifier integration + in Unity 2018+ if the target SDK is set to "highest installed". + +# Version 1.2.118 - Jun 18, 2019 +## New Features +* Android Resolver: Added initial + [Jetifier](https://developer.android.com/studio/command-line/jetifier) + integration which simplifies + [migration](ttps://developer.android.com/jetpack/androidx/migrate) + to Jetpack ([AndroidX](https://developer.android.com/jetpack/androidx)) + libraries in cases where all dependencies are managed by the Android + Resolver. + This can be enabled via the `Use Jetifier` option in the + `Assets > Play Services Resolver > Android Resolver > Settings` menu. + Caveats: + - If your project contains legacy Android Support Library .jar and .aar + files, these files will need to be removed and replaced with references to + artifacts on Maven via `*Dependencies.xml` files so that the Jetifier + can map them to Jetpack (AndroidX) libraries. + For example, remove the file `support-v4-27.0.2.jar` and replace it with + `` in a + `*Dependencies.xml` file. + - If your project contains .jar or .aar files that use the legacy Android + Support Libraries, these will need to be moved into a local Maven repo + [See this guide](https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html) + and then these files should be removed from your Unity project and instead + referenced via `*Dependencies.xml` files so that the Jetifier can + patch them to reference the Jetpack lirbaries. + +## Bug Fixes +* Android Resolver: Disabled version locking of com.android.support:multidex + does not use the same versioning scheme as other legacy Android support + libraries. +* Version Handler: Made Google.VersionHandler.dll's asset GUID stable across + releases. This faciliates error-free import into projects where + Google.VersionHandler.dll is moved from the default install location. + +# Version 1.2.117 - Jun 12, 2019 +## Bug Fixes +* Android Resolver: Fix copying of .srcaar to .aar files for + mainTemplate.gradle resolution. PluginImporter configuration was previously + not being applied to .aar files unless the Unity project was saved. + +# Version 1.2.116 - Jun 7, 2019 +## Bug Fixes +* Android Resolver: Fixed resolution of Android dependencies without version + specifiers. +* Android Resolver: Fixed Maven repo not found warning in Android Resolver. +* Android Resolver: Fixed Android Player directory not found exception in + Unity 2019.x when the Android Player isn't installed. + +# Version 1.2.115 - May 28, 2019 +## Bug Fixes +* Android Resolver: Fixed exception due to Unity 2019.3.0a4 removing + x86 from the set of supported ABIs. + +# Version 1.2.114 - May 27, 2019 +## New Features +* Android Resolver: Added support for ABI stripping when using + mainTemplate.gradle. This only works with AARs stored in repos + on the local filesystem. + +# Version 1.2.113 - May 24, 2019 +## New Features +* Android Resolver: If local repos are moved, the plugin will search the + project for matching directories in an attempt to correct the error. +* Version Handler: Files can be now targeted to multiple build targets + using multiple "gvh_" asset labels. +## Bug Fixes +* Android Resolver: "implementation" or "compile" are now added correctly + to mainTemplate.gradle in Unity versions prior to 2019. + +# Version 1.2.112 - May 22, 2019 +## New Features +* Android Resolver: Added option to disable addition of dependencies to + mainTemplate.gradle. + See `Assets > Play Services Resolver > Android Resolver > Settings`. +* Android Resolver: Made paths to local maven repositories in + mainTemplate.gradle relative to the Unity project when a project is not + being exported. +## Bug Fixes +* Android Resolver: Fixed builds with mainTemplate.gradle integration in + Unity 2019. +* Android Resolver: Changed dependency inclusion in mainTemplate.gradle to + use "implementation" or "compile" depending upon the version of Gradle + included with Unity. +* Android Resolver: Gracefully handled exceptions if the console encoding + can't be modified. +* Android Resolver: Now gracefully fails if the AndroidPlayer directory + can't be found. + +# Version 1.2.111 - May 9, 2019 +## Bug Fixes +* Version Handler: Fixed invocation of methods with named arguments. +* Version Handler: Fixed occasional hang when the editor is compiling + while activating plugins. + +# Version 1.2.110 - May 7, 2019 +## Bug Fixes +* Android Resolver: Fixed inclusion of some srcaar artifacts in builds with + Gradle builds when using mainTemplate.gradle. + +# Version 1.2.109 - May 6, 2019 +## New Features: +* Added links to documentation from menu. +* Android Resolver: Added option to auto-resolve Android libraries on build. +* Android Resolver: Added support for packaging specs of Android libraries. +* Android Resolver: Pop up a window when displaying Android dependencies. + +## Bug Fixes +* Android Resolver: Support for Unity 2019 Android SDK and JDK install locations +* Android Resolver: e-enable AAR explosion if internal builds are enabled. +* Android Resolver: Gracefully handle exceptions on file deletion. +* Android Resolver: Fixed Android Resolver log spam on load. +* Android Resolver: Fixed save of Android Resolver PromptBeforeAutoResolution + setting. +* Android Resolver: Fixed AAR processing failure when an AAR without + classes.jar is found. +* Android Resolver: Removed use of EditorUtility.DisplayProgressBar which + was occasionally left displayed when resolution had completed. +* Version Handler: Fixed asset rename to disable when a disabled file exists. + +# Version 1.2.108 - May 3, 2019 +## Bug Fixes: +* Version Handler: Fixed occasional hang on startup. + +# Version 1.2.107 - May 3, 2019 +## New Features: +* Version Handler: Added support for enabling / disabling assets that do not + support the PluginImporter, based upon build target selection. +* Android Resolver: Added support for the global specification of maven repos. +* iOS Resolver: Added support for the global specification of Cocoapod sources. + +# Version 1.2.106 - May 1, 2019 +## New Features +* iOS Resolver: Added support for development pods in Xcode project integration + mode. +* iOS Resolver: Added support for source pods with resources in Xcode project + integration mode. + +# Version 1.2.105 - Apr 30, 2019 +## Bug fixes +* Android Resolver: Fixed reference to Java tool path in logs. +* Android and iOS Resolvers: Changed command line execution to emit a warning + rather than throwing an exception and failing, when it is not possible to + change the console input and output encoding to UTF-8. +* Android Resolver: Added menu option and API to delete resolved libraries. +* Android Resolver: Added menu option and API to log the repos and libraries + currently included in the project. +* Android Resolver: If Plugins/Android/mainTemplate.gradle file is present and + Gradle is selected as the build type, resolution will simply patch the file + with Android dependencies specified by plugins in the project. + +# Version 1.2.104 - Apr 10, 2019 +## Bug Fixes +* Android Resolver: Changed Android ABI selection method from using whitelisted + Unity versions to type availability. This fixes an exception on resolution + in some versions of Unity 2017.4. + +# Version 1.2.103 - Apr 2, 2019 +## Bug Fixes +* Android Resolver: Whitelisted Unity 2017.4 and above with ARM64 support. +* Android Resolver: Fixed Java version check to work with Java SE 12 and above. + +# Version 1.2.102 - Feb 13, 2019 +## Bug Fixes +* Android Resolver: Fixed the text overflow on the Android Resolver + prompt before initial run to fit inside the buttons for + smaller screens. + +# Version 1.2.101 - Feb 12, 2019 +## New Features +* Android Resolver: Prompt the user before the resolver runs for the + first time and allow the user to elect to disable from the prompt. +* Android Resolver: Change popup warning when resolver is disabled + to be a console warning. + +# Version 1.2.100 - Jan 25, 2019 +## Bug Fixes +* Android Resolver: Fixed AAR processing sometimes failing on Windows + due to file permissions. + +# Version 1.2.99 - Jan 23, 2019 +## Bug Fixes +* Android Resolver: Improved performance of project property polling. +* Version Handler: Fixed callback of VersionHandler.UpdateCompleteMethods + when the update process is complete. + +# Version 1.2.98 - Jan 9, 2019 +## New Features +* iOS Resolver: Pod declaration properties can now be set via XML pod + references. For example, this can enable pods for a subset of build + configurations. +## Bug Fixes +* iOS Resolver: Fixed incremental builds after local pods support caused + regression in 1.2.96. + +# Version 1.2.97 - Dec 17, 2018 +## Bug Fixes +* Android Resolver: Reduced memory allocation for logic that monitors build + settings when auto-resolution is enabled. If auto-resolution is disabled, + almost all build settings are no longer polled for changes. + +# Version 1.2.96 - Dec 17, 2018 +## Bug Fixes +* Android Resolver: Fixed repacking of AARs to exclude .meta files. +* Android Resolver: Only perform auto-resolution on the first scene while + building. +* Android Resolver: Fixed parsing of version ranges that include whitespace. +* iOS Resolver: Added support for local development pods. +* Version Handler: Fixed Version Handler failing to rename some files. + +# Version 1.2.95 - Oct 23, 2018 +## Bug Fixes: +* Android Resolver: Fixed auto-resolution running in a loop in some scenarios. + +# Version 1.2.94 - Oct 22, 2018 +## Bug Fixes +* iOS Resolver: Added support for PODS_TARGET_SRCROOT in source Cocoapods. + +# Version 1.2.93 - Oct 22, 2018 +## Bug Fixes +* Android Resolver: Fixed removal of Android libraries on auto-resolution when + `*Dependencies.xml` files are deleted. + +# Version 1.2.92 - Oct 2, 2018 +## Bug Fixes +* Android Resolver: Worked around auto-resolution hang on Windows if + resolution starts before compilation is finished. + +# Version 1.2.91 - Sep 27, 2018 +## Bug Fixes +* Android Resolver: Fixed Android Resolution when the selected build target + isn't Android. +* Added C# assembly symbols the plugin to simplify debugging bug reports. + +# Version 1.2.90 - Sep 21, 2018 +## Bug Fixes +* Android Resolver: Fixed transitive dependency selection of version locked + packages. + +# Version 1.2.89 - Aug 31, 2018 +## Bug Fixes +* Fixed FileLoadException in ResolveUnityEditoriOSXcodeExtension an assembly + can't be loaded. + +# Version 1.2.88 - Aug 29, 2018 +## Changed +* Improved reporting of resolution attempts and conflicts found in the Android + Resolver. +## Bug Fixes +* iOS Resolver now correctly handles sample code in CocoaPods. Previously it + would add all sample code to the project when using project level + integration. +* Android Resolver now correctly handles Gradle conflict resolution when the + resolution results in a package that is compatible with all requested + dependencies. + +# Version 1.2.87 - Aug 23, 2018 +## Bug Fixes +* Fixed Android Resolver "Processing AARs" dialog getting stuck in Unity 5.6. + +# Version 1.2.86 - Aug 22, 2018 +## Bug Fixes +* Fixed Android Resolver exception in OnPostProcessScene() when the Android + platform isn't selected. + +# Version 1.2.85 - Aug 17, 2018 +## Changes +* Added support for synchronous resolution in the Android Resolver. + PlayServicesResolver.ResolveSync() now performs resolution synchronously. +* Auto-resolution in the Android Resolver now results in synchronous resolution + of Android dependencies before the Android application build starts via + UnityEditor.Callbacks.PostProcessSceneAttribute. + +# Version 1.2.84 - Aug 16, 2018 +## Bug Fixes +* Fixed Android Resolver crash when the AndroidResolverDependencies.xml + file can't be written. +* Reduced log spam when a conflicting Android library is pinned to a + specific version. + +# Version 1.2.83 - Aug 15, 2018 +## Bug Fixes +* Fixed Android Resolver failures due to an in-accessible AAR / JAR explode + cache file. If the cache can't be read / written the resolver now continues + with reduced performance following recompilation / DLL reloads. +* Fixed incorrect version number in plugin manifest on install. + This was a minor issue since the version handler rewrote the metadata + after installation. + +# Version 1.2.82 - Aug 14, 2018 +## Changed +* Added support for alphanumeric versions in the Android Resolver. + +## Bug Fixes +* Fixed Android Resolver selection of latest duplicated library. +* Fixed Android Resolver conflict resolution when version locked and non-version + locked dependencies are specified. +* Fixed Android Resolver conflict resolution when non-existent artifacts are + referenced. + +# Version 1.2.81 - Aug 9, 2018 +## Bug Fixes +* Fixed editor error that would occur when when + `PlayerSettings.Android.targetArchitectures` was set to + `AndroidArchitecture.All`. + +# Version 1.2.80 - Jul 24, 2018 +## Bug Fixes +* Fixed project level settings incorrectly falling back to system wide settings + when default property values were set. + +# Version 1.2.79 - Jul 23, 2018 +## Bug Fixes +* Fixed AndroidManifest.xml patching on Android Resolver load in Unity 2018.x. + +# Version 1.2.78 - Jul 19, 2018 +## Changed +* Added support for overriding conflicting dependencies. + +# Version 1.2.77 - Jul 19, 2018 +## Changed +* Android Resolver now supports Unity's 2018 ABI filter (i.e arm64-v8a). +* Reduced Android Resolver build option polling frequency. +* Disabled Android Resolver auto-resolution in batch mode. Users now need + to explicitly kick off resolution through the API. +* All Android Resolver and Version Handler dialogs are now disabled in batch + mode. +* Verbose logging for all plugins is now enabled by default in batch mode. +* Version Handler bootstrapper has been improved to no longer call + UpdateComplete multiple times. However, since Unity can still reload the + app domain after plugins have been enabled, users still need to store their + plugin state to persistent storage to handle reloads. + +## Bug Fixes +* Android Resolver no longer incorrectly adds MANIFEST.MF files to AARs. +* Android Resolver auto-resolution jobs are now unscheduled when an explicit + resolve job is started. + +# Version 1.2.76 - Jul 16, 2018 +## Bug Fixes +* Fixed variable replacement in AndroidManifest.xml files in the Android + Resolver. + Version 1.2.75 introduced a regression which caused all variable replacement + to replace the *entire* property value rather than the component of the + property that referenced a variable. For example, + given "applicationId = com.my.app", "${applicationId}.foo" would be + incorrectly expanded as "com.my.app" rather than "com.my.app.foo". This + resulted in numerous issues for Android builds where content provider + initialization would fail and services may not start. + +## Changed +* Gradle prebuild experimental feature has been removed from the Android + Resolver. The feature has been broken for some time and added around 8MB + to the plugin size. +* Added better support for execution of plugin components in batch mode. + In batch mode UnityEditor.update is sometimes never called - like when a + single method is executed - so the new job scheduler will execute all jobs + synchronously from the main thread. + +# Version 1.2.75 - Jun 20, 2018 +## New Features +* Android Resolver now monitors the Android SDK path when + auto-resolution is enabled and triggers resolution when the path is + modified. + +## Changed +* Android auto-resolution is now delayed by 3 seconds when the following build + settings are changed: + - Target ABI. + - Gradle build vs. internal build. + - Project export. +* Added a progress bar display when AARs are being processed during Android + resolution. + +## Bug Fixes +* Fixed incorrect Android package version selection when a mix of + version-locked and non-version-locked packages are specified. +* Fixed non-deterministic Android package version selection to select + the highest version of a specified package rather than the last + package specification passed to the Gradle resolution script. + +# Version 1.2.74 - Jun 19, 2018 +## New Features +* Added workaround for broken AndroidManifest.xml variable replacement in + Unity 2018.x. By default ${applicationId} variables will be replaced by + the bundle ID in the Plugins/Android/AndroidManifest.xml file. The + behavior can be disabled via the Android Resolver settings menu. + +# Version 1.2.73 - May 30, 2018 +## Bug Fixes +* Fixed spurious warning message about missing Android plugins directory on + Windows. + +# Version 1.2.72 - May 23, 2018 +## Bug Fixes +* Fixed spurious warning message about missing Android plugins directory. + +# Version 1.2.71 - May 10, 2018 +## Bug Fixes +* Fixed resolution of Android dependencies when the `Assets/Plugins/Android` + directory is named in a different case e.g `Assets/plugins/Android`. + +# Version 1.2.70 - May 7, 2018 +## Bug Fixes +* Fixed bitcode flag being ignored for iOS pods. + +# Version 1.2.69 - May 7, 2018 +## Bug Fixes +* Fixed escaping of local repository paths in Android Resolver. + +# Version 1.2.68 - May 3, 2018 +## Changes +* Added support for granular builds of Google Play Services. + +# Version 1.2.67 - May 1, 2018 +## Changes +* Improved support for iOS source-only pods in Unity 5.5 and below. + +# Version 1.2.66 - April 27, 2018 +## Bug Fixes +* Fixed Version Handler renaming of Linux libraries with hyphens in filenames. + Previously, libraries named Foo-1.2.3.so were not being renamed to + libFoo-1.2.3.so on Linux which could break native library loading on some + versions of Unity. + +# Version 1.2.65 - April 26, 2018 +## Bug Fixes +* Fix CocoaPods casing in logs and comments. + +# Version 1.2.64 - Mar 16, 2018 +## Bug Fixes +* Fixed bug in download_artifacts.gradle (used by Android Resolver) which + reported a failure if required artifacts already exist. + +# Version 1.2.63 - Mar 15, 2018 +## Bug Fixes +* Fixed iOS Resolver include search paths taking precedence over system headers + when using project level resolution. +* Fixed iOS Resolver includes relative to library root, when using project level + resolution. + +# Version 1.2.62 - Mar 12, 2018 +## Changes +* Improved error reporting when a file can't be moved to trash by the + Version Handler. +## Bug Fixes +* Fixed Android Resolver throwing NullReferenceException when the Android SDK + path isn't set. +* Fixed Version Handler renaming files with underscores if the + "Rename to Canonical Filenames" setting is enabled. + +# Version 1.2.61 - Jan 22, 2018 +## Bug Fixes +* Fixed Android Resolver reporting non-existent conflicting dependencies when + Gradle build system is enabled. + +# Version 1.2.60 - Jan 12, 2018 +## Changes +* Added support for Maven / Ivy version specifications for Android packages. +* Added support for Android SNAPSHOT packages. + +## Bug Fixes +* Fixed Openjdk version check. +* Fixed non-deterministic Android package resolution when two packages contain + an artifact with the same name. + +# Version 1.2.59 - Oct 19, 2017 +## Bug Fixes +* Fixed execution of Android Gradle resolution script when it's located + in a path with whitespace. + +# Version 1.2.58 - Oct 19, 2017 +## Changes +* Removed legacy resolution method from Android Resolver. + It is now only possible to use the Gradle or Gradle prebuild resolution + methods. + +# Version 1.2.57 - Oct 18, 2017 +## Bug Fixes +* Updated Gradle wrapper to 4.2.1 to fix issues using Gradle with the + latest Openjdk. +* Android Gradle resolution now also uses gradle.properties to pass + parameters to Gradle in an attempt to workaround problems with + command line argument parsing on Windows 10. + +# Version 1.2.56 - Oct 12, 2017 +## Bug Fixes +* Fixed Gradle artifact download with non-version locked artifacts. +* Changed iOS resolver to only load dependencies at build time. + +# Version 1.2.55 - Oct 4, 2017 +## Bug Fixes +* Force Android Resolution when the "Install Android Packages" setting changes. + +# Version 1.2.54 - Oct 4, 2017 +## Bug Fixes +* Fixed execution of command line tools on Windows when the path to the tool + contains a single quote (apostrophe). In this case we fallback to executing + the tool via the system shell. + +# Version 1.2.53 - Oct 2, 2017 +## New Features +* Changed Android Resolver "resolution complete" dialog so that it now displays + failures. +* Android Resolver now detects conflicting libraries that it does not manage + warning the user if they're newer than the managed libraries and prompting + the user to clean them up if they're older or at the same version. + +## Bug Fixes +* Improved Android Resolver auto-resolution speed. +* Fixed bug in the Gradle Android Resolver which would result in resolution + succeeding when some dependencies are not found. + +# Version 1.2.52 - Sep 25, 2017 +## New Features +* Changed Android Resolver's Gradle resolution to resolve conflicting + dependencies across Google Play services and Android Support library packages. + +# Version 1.2.51 - Sep 20, 2017 +## Changes +* Changed iOS Resolver to execute the CocoaPods "pod" command via the shell + by default. Some developers customize their shell environment to use + custom ssh certs to access internal git repositories that host pods so + executing "pod" via the shell will work for these scenarios. + The drawback of executing "pod" via the shell could potentially cause + users problems if they break their shell environment. Though users who + customize their shell environments will be able to resolve these issues. + +# Version 1.2.50 - Sep 18, 2017 +## New Features +* Added option to disable the Gradle daemon in the Android Resolver. + This daemon is now disabled by default as some users are getting into a state + where multiple daemon instances are being spawned when changing dependencies + which eventually results in Android resolution failing until all daemon + processes are manually killed. + +## Bug Fixes +* Android resolution is now always executed if the user declines the update + of their Android SDK. This ensure users can continue to use out of date + Android SDK packages if they desire. + +# Version 1.2.49 - Sep 18, 2017 +## Bug Fixes +* Removed modulemap parsing in iOS Resolver. + The framework *.modulemap did not need to be parsed by the iOS Resolver + when injecting Cocoapods into a Xcode project. Simply adding a modular + framework to a Xcode project results in Xcode's Clang parsing the associated + modulemap and injecting any compile and link flags into the build process. + +# Version 1.2.48 - Sep 12, 2017 +## New Features +* Changed settings to be per-project by default. + +## Bug Fixes +* Added Google maven repository to fix GradlePrebuild resolution with Google + components. +* Fixed Android Resolution failure with spaces in paths. + +# Version 1.2.47 - Aug 29, 2017 +## New Features +* Android and iOS dependencies can now be specified using *Dependencies.xml + files. This is now the preferred method for registering dependencies, + we may remove the API for dependency addition in future. +* Added "Reset to Defaults" button to each settings dialog to restore default + settings. +* Android Resolver now validates the configured JDK is new enough to build + recently released Android libraries. +## Bug Fixes +* Fixed a bug that caused dependencies with the "LATEST" version specification + to be ignored when using the Gradle mode of the Android Resolver. +* Fixed a race condition when running Android Resolution. +* Fixed Android Resolver logging if a PlayServicesSupport instance is created + with no logging enabled before the Android Resolver is initialized. +* Fixed iOS resolver dialog in Unity 4. +* Fixed iOS Cocoapod Xcode project integration in Unity 4. + +# Version 1.2.46 - Aug 22, 2017 +## Bug Fixes +* GradlePrebuild Android resolver on Windows now correctly locates dependent + data files. + +# Version 1.2.45 - Aug 22, 2017 +## Bug Fixes +* Improved Android package auto-resolution and fixed clean up of stale + dependencies when using Gradle dependency resolution. + +# Version 1.2.44 - Aug 21, 2017 +## Bug Fixes +* Enabled autoresolution for Gradle Prebuild. +* Made the command line dialog windows have selectable text. +* Fixed incorrect "Android Settings" dialog disabled groups. +* Updated PlayServicesResolver android platform detection to use the package + manager instead of the 'android' tool. +* UnityCompat reflection methods 'GetAndroidPlatform' and + 'GetAndroidBuildToolsVersion' are now Obsolete due to dependence on the + obsolete 'android' build tool. + +# Version 1.2.43 - Aug 18, 2017 +## Bug Fixes +* Fixed Gradle resolution in the Android Resolver when running + PlayServicesResolver.Resolve() in parallel or spawning multiple + resolutions before the previous resolve completed. + +# Version 1.2.42 - Aug 17, 2017 +## Bug Fixes +* Fixed Xcode project level settings not being applied by IOS Resolver when + Xcode project pod integration is enabled. + +# Version 1.2.41 - Aug 15, 2017 +## Bug Fixes +* IOS Resolver's Xcode workspace pod integration is now disabled when Unity + Cloud Build is detected. Unity Cloud Build does not follow the same build + process as the Unity editor and fails to open the generated xcworkspace at + this time. + +# Version 1.2.40 - Aug 15, 2017 +## Bug Fixes +* Moved Android Resolver Gradle Prebuild scripts into Google.JarResolver.dll. + They are now extracted from the DLL when required. +* AARs / JARs are now cleaned up when switching the Android resolution + strategy. + +# Version 1.2.39 - Aug 10, 2017 +## New Features +* Android Resolver now supports resolution with Gradle. This enables support + for non-local artifacts. +## Bug Fixes +* Android Resolver's Gradle Prebuild now uses Android build tools to determine + the Android platform tools version rather than relying upon internal Unity + APIs. +* Android Resolver's Gradle Prebuild now correctly strips binaries that are + not required for the target ABI. + +# Version 1.2.38 - Aug 7, 2017 +## Bug Fixes +* Fixed an issue in VersionHandler where disabled targets are ignored if + the "Any Platform" flag is set on a plugin DLL. + +# Version 1.2.37 - Aug 3, 2017 +## New Features +* Exposed GooglePlayServices.PlayServicesResolver.Resolve() so that it's + possible for a script to be notified when AAR / Jar resolution is complete. + This makes it easier to setup a project to build from the command line. + +# Version 1.2.36 - Aug 3, 2017 +## New Features +* VersionHandler.UpdateCompleteMethods allows a user to provide a list of + methods to be called when VersionHandlerImpl has completed an update. + This makes it easier to import a plugin and wait for VersionHandler to + execute prior executing a build. + +# Version 1.2.35 - Jul 28, 2017 +## New Features +* VersionHandler will now rename Linux libraries so they can target Unity + versions that require different file naming. Libraries need to be labelled + gvh_linuxlibname-${basename} in order to be considered for renaming. + e.g gvh\_linuxlibname-MyLib will be named MyLib.so in Unity 5.5 and below and + libMyLib.so in Unity 5.6 and above. + +# Version 1.2.34 - Jul 28, 2017 +## Bug Fixes +* Made VersionHandler bootstrap module more robust when calling static + methods before the implementation DLL is loaded. + +# Version 1.2.33 - Jul 27, 2017 +## New Features +* Added a bootstrap module for VersionHandler so the implementation + of the VersionHandler module can be versioned without resulting in + a compile error when imported at different versions across multiple + plugins. + +# Version 1.2.32 - Jul 20, 2017 +## New Features +* Added support for build target selection based upon .NET framework + version in the VersionHandler. + When applying either gvh\_dotnet-3.5 or gvh\_dotnet-4.5 labels to + assets, the VersionHandler will only enable the asset for the + specified set of build targets when the matching .NET framework version + is selected in Unity 2017's project settings. This allows assets + to be provided in a plugin that need to differ based upon .NET version. + +# Version 1.2.31 - Jul 5, 2017 +## Bug Fixes +* Force expansion of AARs with native components when using Unity 2017 + with the internal build system. In contrast to Unity 5.x, Unity 2017's + internal build system does not include native libraries included in AARs. + Forcing expansion of AARs with native components generates an + Ant / Eclipse project for each AAR which is correctly included by Unity + 2017's internal build system. + +# Version 1.2.30 - Jul 5, 2017 +## Bug Fixes +* Fixed Cocoapods being installed when the build target isn't iOS. +* Added support for malformed AARs with missing classes.jar. + +# Version 1.2.29 - Jun 16, 2017 +## New Features +* Added support for the Android sdkmanager tool. + +# Version 1.2.28 - Jun 8, 2017 +## Bug Fixes +* Fixed non-shell command line execution (regression from + Cocoapod installation patch). + +# Version 1.2.27 - Jun 7, 2017 +## Bug Fixes +* Added support for stdout / stderr redirection when executing + commands in shell mode. + This fixes CocoaPod tool installation when shell mode is + enabled. +* Fixed incremental builds when additional sources are specified + in the Podfile. + +# Version 1.2.26 - Jun 7, 2017 +## Bug Fixes +* Fixed a crash when importing Version Handler into Unity 4.7.x. + +# Version 1.2.25 - Jun 7, 2017 +## Bug Fixes +* Fixed an issue in the Jar Resolver which incorrectly notified + event handlers of bundle ID changes when the currently selected + (not active) build target changed in Unity 5.6 and above. + +# Version 1.2.24 - Jun 6, 2017 +## New Features +* Added option to control file renaming in Version Handler settings. + Disabling file renaming (default option) significantly increases + the speed of file version management operations with the downside + that any files that are referenced directly by canonical filename + rather than asset ID will no longer be valid. +* Improved logging in the Version Handler. +## Bug Fixes +* Fixed an issue in the Version Handler which caused it to not + re-enable plugins when re-importing a custom package with disabled + version managed files. + +# Version 1.2.23 - May 26, 2017 +## Bug Fixes +* Fixed a bug with gradle prebuild resolver on windows. + +# Version 1.2.22 - May 19, 2017 +## Bug Fixes +* Fixed a bug in the iOS resolver with incremental builds. +* Fixed misdetection of Cocoapods support with Unity beta 5.6. + +# Version 1.2.21 - May 8, 2017 +## Bug Fixes +* Fix for https://github.com/googlesamples/unity-jar-resolver/issues/48 + Android dependency version number parsing when "-alpha" (etc.) are + included in dependency (AAR / JAR) versions. + +# Version 1.2.20 - May 8, 2017 +## Bug Fixes +* Attempted to fix + https://github.com/googlesamples/unity-jar-resolver/issues/48 + where a NullReferenceException could occur if a target file does not + have a valid version string. + +# Version 1.2.19 - May 4, 2017 +## Bug Fixes +* Fixed Jar Resolver exploding and deleting AAR files it isn't managing. + +# Version 1.2.18 - May 4, 2017 +## New Features +* Added support for preserving Unity pods such as when GVR is enabled. + +# Version 1.2.17 - Apr 20, 2017 +## Bug Fixes +* Fixed auto-resolution when an Android application ID is modified. + +# Version 1.2.16 - Apr 17, 2017 +## Bug Fixes +* Fixed Unity version number parsing on machines with a locale that uses + "," for decimal points. +* Fixed null reference exception if JDK path isn't set. + +# Version 1.2.15 - Mar 17, 2017 +## New Features +* Added warning when the Jar Resolver's background resolution is disabled. +## Bug Fixes +* Fixed support of AARs with native libraries when using Gradle. +* Fixed extra repository paths when resolving dependencies. + +# Version 1.2.14 - Mar 7, 2017 +## New Features +* Added experimental Android resolution using Gradle. + This alternative resolver supports proguard stripping with Unity's + internal build system. +* Added Android support for single ABI builds when using AARs include + native libraries. +* Disabled Android resolution on changes to all .cs and .js files. + File patterns that are monitored for auto-resolution can be added + using PlayServicesResolver.AddAutoResolutionFilePatterns(). +* Added tracking of resolved AARs and JARs so they can be cleaned up + if they're no longer referenced by a project. +* Added persistence of AAR / JAR version replacement for each Unity + session. +* Added settings dialog to the iOS resolver. +* Integrated Cocoapod tool installation in the iOS resolver. +* Added option to run pod tool via the shell. +## Bug Fixes +* Fixed build of some source Cocoapods (e.g Protobuf). +* VersionHandler no longer prompts to delete obsolete manifests. +* iOS resolver handles Cocoapod installation when using Ruby < 2.2.2. +* Added workaround for package version selection when including + Google Play Services on Android. +* Fixed support for pods that reference static libraries. +* Fixed support for resource-only pods. + +# Version 1.2.12 - Feb 14, 2017 +## Bug Fixes +* Fixed re-explosion of AARs when the bundle ID is modified. + +# Version 1.2.11 - Jan 30, 2017 +## New Features +* Added support for Android Studio builds. +* Added support for native (C/C++) shared libraries in AARs. + +# Version 1.2.10 - Jan 11, 2017 +## Bug Fixes +* Fixed SDK manager path retrieval. +* Also, report stderr when it's not possible to run the "pod" tool. +* Handle exceptions thrown by Unity.Cecil on asset rename +* Fixed IOSResolver to handle PlayerSettings.iOS.targetOSVersionString + +# Version 1.2.9 - Dec 7, 2016 +## Bug Fixes +* Improved error reporting when "pod repo update" fails. +* Added detection of xml format xcode projects generated by old Cocoapods + installations. + +# Version 1.2.8 - Dec 6, 2016 +## Bug Fixes +* Increased speed of JarResolver resolution. +* Fixed JarResolver caches getting out of sync with requested dependencies + by removing the caches. +* Fixed JarResolver explode cache always being rewritten even when no + dependencies change. + +# Version 1.2.7 - Dec 2, 2016 +## Bug Fixes +* Fixed VersionHandler build errors with Unity 5.5, due to the constantly + changing BuildTarget enum. +* Added support for Unity configured JDK Path rather than requiring + JAVA_HOME to be set in the Jar Resolver. + +# Version 1.2.6 - Nov 15, 2016 +## Bug Fixes +* Fixed IOSResolver errors when iOS support is not installed. +* Added fallback to "pod" executable search which queries the Ruby Gems + package manager for the binary install location. + +# Version 1.2.5 - Nov 3, 2016 +## Bug Fixes +* Added crude support for source only Cocoapods to the IOSResolver. + +# Version 1.2.4 - Oct 27, 2016 +## Bug Fixes +* Automated resolution of out of date pod repositories. + +# Version 1.2.3 - Oct 25, 2016 +## Bug Fixes +* Fixed exception when reporting conflicting dependencies. + +# Version 1.2.2 - Oct 17, 2016 +## Bug Fixes +* Fixed issue working with Unity 5.5 +* Fixed issue with PlayServicesResolver corrupting other iOS dependencies. +* Updated build script to use Unity distributed tools for building. + +# Version 1.2.1 - Jul 25, 2016 +## Bug Fixes +* Removed 1.2 Resolver and hardcoded whitelist of AARs to expand. +* Improved error reporting when the "jar" executable can't be found. +* Removed the need to set JAVA_HOME if "jar" is in the user's path. +* Fixed spurious copying of partially matching AARs. +* Changed resolver to only copy / expand when source AARs change. +* Auto-resolution of dependencies is now performed when the Android + build target is selected. + +## New Features +* Expand AARs that contain manifests with variable expansion like + ${applicationId}. +* Added optional logging in the JarResolverLib module. +* Integration with the Android SDK manager for dependencies that + declare required Android SDK packages. + +# Version 1.2.0 - May 11 2016 +## Bug Fixes +* Handles resolving dependencies when the artifacts are split across 2 repos. +* #4 Misdetecting version for versions like 1.2-alpha. These are now string + compared if alphanumeric +* Removed resolver creation via reflection since it did not work all the time. + Now a resolver needs to be loaded externally (which is existing behavior). + +## New Features +* Expose PlayServicesResolver properties to allow for script access. +* Explodes firebase-common and firebase-measurement aar files to support + ${applicationId} substitution. + +# Version 1.1.1 - 25 Feb 2016 +## Bug Fixes +* #1 Spaces in project path not handled when exploding Aar file. +* #2 Script compilation error: TypeLoadException. + +# Version 1.1.0 - 5 Feb 2016 +## New Features +* Adds friendly alert when JAVA_HOME is not set on Windows platforms. +* Adds flag for disabling background resolution. +* Expands play-services-measurement and replaces ${applicationId} with the + bundle Id. + + ## Bug Fixes +* Fixes infinite loop of resolution triggered by resolution. diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/CHANGELOG.md.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/CHANGELOG.md.meta new file mode 100644 index 0000000..93230e5 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/CHANGELOG.md.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: deafbeef1ed04f639e3195087b6d2e9f +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/CHANGELOG.md +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/Google.VersionHandler.dll b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/Google.VersionHandler.dll new file mode 100755 index 0000000..bcf0890 Binary files /dev/null and b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/Google.VersionHandler.dll differ diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/Google.VersionHandler.dll.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/Google.VersionHandler.dll.meta new file mode 100644 index 0000000..6781b96 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/Google.VersionHandler.dll.meta @@ -0,0 +1,38 @@ +fileFormatVersion: 2 +guid: 17e39196248d458daa69b514bc09b6a7 +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/Google.VersionHandler.dll +- gvhp_targets-editor +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + 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: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/LICENSE b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/LICENSE new file mode 100755 index 0000000..6258cc4 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/LICENSE @@ -0,0 +1,245 @@ +Copyright (C) 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +==================================================================================================== +This package uses MiniJSON + +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. diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/LICENSE.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/LICENSE.meta new file mode 100644 index 0000000..4de234f --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/LICENSE.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61e923e8fff245a9bf5cfcf0774e75df +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/LICENSE +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/README.md b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/README.md new file mode 100755 index 0000000..cbc98e1 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/README.md @@ -0,0 +1,768 @@ +External Dependency Manager for Unity +======== + +# Overview + +The External Dependency Manager for Unity (EDM4U) +(formerly Play Services Resolver / Jar Resolver) is intended to be used by any +Unity plugin that requires: + + * Android specific libraries (e.g + [AARs](https://developer.android.com/studio/projects/android-library.html)). + * iOS [CocoaPods](https://cocoapods.org/). + * Version management of transitive dependencies. + * Management of Package Manager (PM) Registries. + +Updated releases are available on +[GitHub](https://github.com/googlesamples/unity-jar-resolver) + +# Background + +Many Unity plugins have dependencies upon Android specific libraries, iOS +CocoaPods, and sometimes have transitive dependencies upon other Unity plugins. +This causes the following problems: + + * Integrating platform specific (e.g Android and iOS) libraries within a + Unity project can be complex and a burden on a Unity plugin maintainer. + * The process of resolving conflicting dependencies on platform specific + libraries is pushed to the developer attempting to use a Unity plugin. + The developer trying to use you plugin is very likely to give up when + faced with Android or iOS specific build errors. + * The process of resolving conflicting Unity plugins (due to shared Unity + plugin components) is pushed to the developer attempting to use your Unity + plugin. In an effort to resolve conflicts, the developer will very likely + attempt to resolve problems by deleting random files in your plugin, + report bugs when that doesn't work and finally give up. + +EDM provides solutions for each of these problems. + +## Android Dependency Management + +The *Android Resolver* component of this plugin will download and integrate +Android library dependencies and handle any conflicts between plugins that share +the same dependencies. + +Without the Android Resolver, typically Unity plugins bundle their AAR and +JAR dependencies, e.g. a Unity plugin `SomePlugin` that requires the Google +Play Games Android library would redistribute the library and its transitive +dependencies in the folder `SomePlugin/Android/`. When a user imports +`SomeOtherPlugin` that includes the same libraries (potentially at different +versions) in `SomeOtherPlugin/Android/`, the developer using `SomePlugin` and +`SomeOtherPlugin` will see an error when building for Android that can be hard +to interpret. + +Using the Android Resolver to manage Android library dependencies: + + * Solves Android library conflicts between plugins. + * Handles all of the various processing steps required to use Android + libraries (AARs, JARs) in Unity 4.x and above projects. Almost all + versions of Unity have - at best - partial support for AARs. + * (Experimental) Supports minification of included Java components without + exporting a project. + +## iOS Dependency Management + +The *iOS Resolver* component of this plugin integrates with +[CocoaPods](https://cocoapods.org/) to download and integrate iOS libraries +and frameworks into the Xcode project Unity generates when building for iOS. +Using CocoaPods allows multiple plugins to utilize shared components without +forcing developers to fix either duplicate or incompatible versions of +libraries included through multiple Unity plugins in their project. + +## Package Manager Registry Setup + +The [Package Manager](https://docs.unity3d.com/Manual/Packages.html) +(PM) makes use of [NPM](https://www.npmjs.com/) registry servers for package +hosting and provides ways to discover, install, upgrade and uninstall packages. +This makes it easier for developers to manage plugins within their projects. + +However, installing additional package registries requires a few manual steps +that can potentially be error prone. The *Package Manager Resolver* +component of this plugin integrates with +[PM](https://docs.unity3d.com/Manual/Packages.html) to provide a way to +auto-install PM package registries when a `.unitypackage` is installed which +allows plugin maintainers to ship a `.unitypackage` that can provide access +to their own PM registry server to make it easier for developers to +manage their plugins. + +## Unity Plugin Version Management + +Finally, the *Version Handler* component of this plugin simplifies the process +of managing transitive dependencies of Unity plugins and each plugin's upgrade +process. + +For example, without the Version Handler plugin, if: + + * Unity plugin `SomePlugin` includes `EDM4U` plugin at + version 1.1. + * Unity plugin `SomeOtherPlugin` includes `EDM4U` + plugin at version 1.2. + +The version of `EDM4U` included in the developer's project depends upon the +order the developer imports `SomePlugin` or `SomeOtherPlugin`. + +This results in: + + * `EDM4U` at version 1.2, if `SomePlugin` is imported then `SomeOtherPlugin` + is imported. + * `EDM4U` at version 1.1, if `SomeOtherPlugin` is imported then + `SomePlugin` is imported. + +The Version Handler solves the problem of managing transitive dependencies by: + + * Specifying a set of packaging requirements that enable a plugin at + different versions to be imported into a Unity project. + * Providing activation logic that selects the latest version of a plugin + within a project. + +When using the Version Handler to manage `EDM4U` included in `SomePlugin` and +`SomeOtherPlugin`, from the prior example, version 1.2 will always be the +version activated in a developer's Unity project. + +Plugin creators are encouraged to adopt this library to ease integration for +their customers. For more information about integrating EDM4U +into your own plugin, see the [Plugin Redistribution](#plugin-redistribution) +section of this document. + +# Analytics + +The External Dependency Manager for Unity plugin by default logs usage to Google +Analytics. The purpose of the logging is to quantitatively measure the usage of +functionality, to gather reports on integration failures and to inform future +improvements to the developer experience of the External Dependency Manager +plugin. Note that the analytics collected are limited to the scope of the EDM4U +plugin’s usage. + +For details of what is logged, please refer to the usage of +`EditorMeasurement.Report()` in the source code. + +# Requirements + +The *Android Resolver* and *iOS Resolver* components of the plugin only work +with Unity version 4.6.8 or higher. + +The *Version Handler* component only works with Unity 5.x or higher as it +depends upon the `PluginImporter` UnityEditor API. + +The *Package Manager Resolver* component only works with +Unity 2018.4 or above, when +[scoped registry](https://docs.unity3d.com/Manual/upm-scoped.html) +support was added to the Package Manager. + +# Getting Started + +Before you import EDM4U into your plugin project, you first +need to consider whether you intend to *redistribute* `EDM4U` +along with your own plugin. + +## Plugin Redistribution + +If you're a plugin maintainer, redistributing `EDM4U` inside your own plugin +will ease the integration process for your users, by resolving dependency +conflicts between your plugin and other plugins in a user's project. + +If you wish to redistribute `EDM4U` inside your plugin, +you **must** follow these steps when importing the +`external-dependency-manager-*.unitypackage`, and when exporting your own plugin +package: + + 1. Import the `external-dependency-manager-*.unitypackage` into your plugin + project by + [running Unity from the command line](https://docs.unity3d.com/Manual/CommandLineArguments.html), ensuring that + you add the `-gvh_disable` option. + 1. Export your plugin by [running Unity from the command line](https://docs.unity3d.com/Manual/CommandLineArguments.html), ensuring that + you: + - Include the contents of the `Assets/PlayServicesResolver` and + `Assets/ExternalDependencyManager` directory. + - Add the `-gvh_disable` option. + +You **must** specify the `-gvh_disable` option in order for the Version +Handler to work correctly! + +For example, the following command will import the +`external-dependency-manager-1.2.46.0.unitypackage` into the project +`MyPluginProject` and export the entire Assets folder to +`MyPlugin.unitypackage`: + +``` +Unity -gvh_disable \ + -batchmode \ + -importPackage external-dependency-manager-1.2.46.0.unitypackage \ + -projectPath MyPluginProject \ + -exportPackage Assets MyPlugin.unitypackage \ + -quit +``` + +### Background + +The *Version Handler* component relies upon deferring the load of editor DLLs +so that it can run first and determine the latest version of a plugin component +to activate. The build of `EDM4U` plugin has Unity asset metadata that is +configured so that the editor components are not initially enabled when it's +imported into a Unity project. To maintain this configuration when importing +the `external-dependency-manager.unitypackage` into a Unity plugin project, you +*must* specify the command line option `-gvh_disable` which will prevent the +Version Handler component from running and changing the Unity asset metadata. + +# Android Resolver Usage + +The Android Resolver copies specified dependencies from local or remote Maven +repositories into the Unity project when a user selects Android as the build +target in the Unity editor. + + 1. Add the `external-dependency-manager-*.unitypackage` to your plugin + project (assuming you are developing a plugin). If you are redistributing + EDM4U with your plugin, you **must** follow the + import steps in the [Getting Started](#getting-started) section! + + 2. Copy and rename the + [SampleDependencies.xml](https://github.com/googlesamples/unity-jar-resolver/blob/master/sample/Assets/ExternalDependencyManager/Editor/SampleDependencies.xml) + file into your plugin and add the dependencies your plugin requires. + + The XML file just needs to be under an `Editor` directory and match the + name `*Dependencies.xml`. For example, + `MyPlugin/Editor/MyPluginDependencies.xml`. + + 3. Follow the steps in the [Getting Started](#getting-started) + section when you are exporting your plugin package. + +For example, to add the Google Play Games library +(`com.google.android.gms:play-services-games` package) at version `9.8.0` to +the set of a plugin's Android dependencies: + +``` + + + + + extra-google-m2repository + + + + +``` + +The version specification (last component) supports: + + * Specific versions e.g `9.8.0` + * Partial matches e.g `9.8.+` would match 9.8.0, 9.8.1 etc. choosing the most + recent version. + * Latest version using `LATEST` or `+`. We do *not* recommend using this + unless you're 100% sure the library you depend upon will not break your + Unity plugin in future. + +The above example specifies the dependency as a component of the Android SDK +manager such that the Android SDK manager will be executed to install the +package if it's not found. If your Android dependency is located on Maven +central it's possible to specify the package simply using the `androidPackage` +element: + +``` + + + + + +``` + +## Auto-resolution + +By default the Android Resolver automatically monitors the dependencies you have +specified and the `Plugins/Android` folder of your Unity project. The +resolution process runs when the specified dependencies are not present in your +project. + +The *auto-resolution* process can be disabled via the +`Assets > External Dependency Manager > Android Resolver > Settings` menu. + +Manual resolution can be performed using the following menu options: + + * `Assets > External Dependency Manager > Android Resolver > Resolve` + * `Assets > External Dependency Manager > Android Resolver > Force Resolve` + +## Deleting libraries + +Resolved packages are tracked via asset labels by the Android Resolver. +They can easily be deleted using the +`Assets > External Dependency Manager > Android Resolver > Delete Resolved Libraries` +menu item. + +## Android Manifest Variable Processing + +Some AAR files (for example play-services-measurement) contain variables that +are processed by the Android Gradle plugin. Unfortunately, Unity does not +perform the same processing when using Unity's Internal Build System, so the +Android Resolver plugin handles known cases of this variable substitution +by exploding the AAR into a folder and replacing `${applicationId}` with the +`bundleID`. + +Disabling AAR explosion and therefore Android manifest processing can be done +via the `Assets > External Dependency Manager > Android Resolver > Settings` +menu. You may want to disable explosion of AARs if you're exporting a project +to be built with Gradle / Android Studio. + +## ABI Stripping + +Some AAR files contain native libraries (.so files) for each ABI supported +by Android. Unfortunately, when targeting a single ABI (e.g x86), Unity does +not strip native libraries for unused ABIs. To strip unused ABIs, the Android +Resolver plugin explodes an AAR into a folder and removes unused ABIs to +reduce the built APK size. Furthermore, if native libraries are not stripped +from an APK (e.g you have a mix of Unity's x86 library and some armeabi-v7a +libraries) Android may attempt to load the wrong library for the current +runtime ABI completely breaking your plugin when targeting some architectures. + +AAR explosion and therefore ABI stripping can be disabled via the +`Assets > External Dependency Manager > Android Resolver > Settings` menu. +You may want to disable explosion of AARs if you're exporting a project to be +built with Gradle / Android Studio. + +## Resolution Strategies + +By default the Android Resolver will use Gradle to download dependencies prior +to integrating them into a Unity project. This works with Unity's internal +build system and Gradle / Android Studio project export. + +It's possible to change the resolution strategy via the +`Assets > External Dependency Manager > Android Resolver > Settings` menu. + +### Download Artifacts with Gradle + +Using the default resolution strategy, the Android resolver executes the +following operations: + + - Remove the result of previous Android resolutions. + e.g Delete all files and directories labeled with "gpsr" under + `Plugins/Android` from the project. + - Collect the set of Android dependencies (libraries) specified by a + project's `*Dependencies.xml` files. + - Run `download_artifacts.gradle` with Gradle to resolve conflicts and, + if successful, download the set of resolved Android libraries (AARs, JARs). + - Process each AAR / JAR so that it can be used with the currently selected + Unity build system (e.g Internal vs. Gradle, Export vs. No Export). + This involves patching each reference to `applicationId` in the + AndroidManifest.xml with the project's bundle ID. This means resolution + must be run if the bundle ID is changed again. + - Move the processed AARs to `Plugins/Android` so they will be included when + Unity invokes the Android build. + +### Integrate into mainTemplate.gradle + +Unity 5.6 introduced support for customizing the `build.gradle` used to build +Unity projects with Gradle. When the *Patch mainTemplate.gradle* setting is +enabled, rather than downloading artifacts before the build, Android resolution +results in the execution of the following operations: + + - Remove the result of previous Android resolutions. + e.g Delete all files and directories labeled with "gpsr" under + `Plugins/Android` from the project and remove sections delimited with + `// Android Resolver * Start` and `// Android Resolver * End` lines. + - Collect the set of Android dependencies (libraries) specified by a + project's `*Dependencies.xml` files. + - Rename any `.srcaar` files in the build to `.aar` and exclude them from + being included directly by Unity in the Android build as + `mainTemplate.gradle` will be patched to include them instead from their + local maven repositories. + - Inject the required Gradle repositories into `mainTemplate.gradle` at the + line matching the pattern + `.*apply plugin: 'com\.android\.(application|library)'.*` or the section + starting at the line `// Android Resolver Repos Start`. + If you want to control the injection point in the file, the section + delimited by the lines `// Android Resolver Repos Start` and + `// Android Resolver Repos End` should be placed in the global scope + before the `dependencies` section. + - Inject the required Android dependencies (libraries) into + `mainTemplate.gradle` at the line matching the pattern `***DEPS***` or + the section starting at the line `// Android Resolver Dependencies Start`. + If you want to control the injection point in the file, the section + delimited by the lines `// Android Resolver Dependencies Start` and + `// Android Resolver Dependencies End` should be placed in the + `dependencies` section. + - Inject the packaging options logic, which excludes architecture specific + libraries based upon the selected build target, into `mainTemplate.gradle` + at the line matching the pattern `android +{` or the section starting at + the line `// Android Resolver Exclusions Start`. + If you want to control the injection point in the file, the section + delimited by the lines `// Android Resolver Exclusions Start` and + `// Android Resolver Exclusions End` should be placed in the global + scope before the `android` section. + +## Dependency Tracking + +The Android Resolver creates the +`ProjectSettings/AndroidResolverDependencies.xml` to quickly determine the set +of resolved dependencies in a project. This is used by the auto-resolution +process to only run the expensive resolution process when necessary. + +## Displaying Dependencies + +It's possible to display the set of dependencies the Android Resolver +would download and process in your project via the +`Assets > External Dependency Manager > Android Resolver > Display Libraries` +menu item. + +# iOS Resolver Usage + +The iOS resolver component of this plugin manages +[CocoaPods](https://cocoapods.org/). A CocoaPods `Podfile` is generated and +the `pod` tool is executed as a post build process step to add dependencies +to the Xcode project exported by Unity. + +Dependencies for iOS are added by referring to CocoaPods. + + 1. Add the `external-dependency-manager-*.unitypackage` to your plugin + project (assuming you are developing a plugin). If you are redistributing + EDM4U with your plugin, you **must** follow the + import steps in the [Getting Started](#getting-started) section! + + 2. Copy and rename the + [SampleDependencies.xml](https://github.com/googlesamples/unity-jar-resolver/blob/master/sample/Assets/ExternalDependencyManager/Editor/SampleDependencies.xml) + file into your plugin and add the dependencies your plugin requires. + + The XML file just needs to be under an `Editor` directory and match the + name `*Dependencies.xml`. For example, + `MyPlugin/Editor/MyPluginDependencies.xml`. + + 3. Follow the steps in the [Getting Started](#getting-started) + section when you are exporting your plugin package. + +For example, to add the AdMob pod, version 7.0 or greater with bitcode enabled: + +``` + + + + + +``` + +## Integration Strategies + +The `CocoaPods` are either: + * Downloaded and injected into the Xcode project file directly, rather than + creating a separate xcworkspace. We call this `Xcode project` integration. + * If the Unity version supports opening a xcworkspace file, the `pod` tool + is used as intended to generate a xcworkspace which references the + CocoaPods. We call this `Xcode workspace` integration. + +The resolution strategy can be changed via the +`Assets > External Dependency Manager > iOS Resolver > Settings` menu. + +### Appending text to generated Podfile +In order to modify the generated Podfile you can create a script like this: +``` +using System.IO; +public class PostProcessIOS : MonoBehaviour { +[PostProcessBuildAttribute(45)]//must be between 40 and 50 to ensure that it's not overriden by Podfile generation (40) and that it's added before "pod install" (50) +private static void PostProcessBuild_iOS(BuildTarget target, string buildPath) +{ + if (target == BuildTarget.iOS) + { + + using (StreamWriter sw = File.AppendText(buildPath + "/Podfile")) + { + //in this example I'm adding an app extension + sw.WriteLine("\ntarget 'NSExtension' do\n pod 'Firebase/Messaging', '6.6.0'\nend"); + } + } +} +``` + +# Package Manager Resolver Usage + +Adding registries to the +[Package Manager](https://docs.unity3d.com/Manual/Packages.html) +(PM) is a manual process. The Package Manager Resolver (PMR) component +of this plugin makes it easy for plugin maintainers to distribute new PM +registry servers and easy for plugin users to manage PM registry servers. + +## Adding Registries + + 1. Add the `external-dependency-manager-*.unitypackage` to your plugin + project (assuming you are developing a plugin). If you are redistributing + EDM4U with your plugin, you **must** follow the + import steps in the [Getting Started](#getting-started) section! + + 2. Copy and rename the + [SampleRegistries.xml](https://github.com/googlesamples/unity-jar-resolver/blob/master/sample/Assets/ExternalDependencyManager/Editor/sample/Assets/ExternalDependencyManager/Editor/SampleRegistries.xml) + file into your plugin and add the registries your plugin requires. + + The XML file just needs to be under an `Editor` directory and match the + name `*Registries.xml` or labeled with `gumpr_registries`. For example, + `MyPlugin/Editor/MyPluginRegistries.xml`. + + 3. Follow the steps in the [Getting Started](#getting-started) + section when you are exporting your plugin package. + +For example, to add a registry for plugins in the scope `com.coolstuff`: + +``` + + + + com.coolstuff + + + +``` + +When PMR is loaded it will prompt the developer to add the registry to their +project if it isn't already present in the `Packages/manifest.json` file. + +For more information, see Unity's documentation on +[scoped package registries](https://docs.unity3d.com/Manual/upm-scoped.html). + +## Managing Registries + +It's possible to add and remove registries that are specified via PMR +XML configuration files via the following menu options: + +* `Assets > External Dependency Manager > Package Manager Resolver > + Add Registries` will prompt the user with a window which allows them to + add registries discovered in the project to the Package Manager. +* `Assets > External Dependency Manager > Package Manager Resolver > + Remove Registries` will prompt the user with a window which allows them to + remove registries discovered in the project from the Package Manager. +* `Assets > External Dependency Manager > Package Manager Resolver > + Modify Registries` will prompt the user with a window which allows them to + add or remove registries discovered in the project. + +## Migration + +PMR can migrate Version Handler packages installed in the `Assets` folder +to PM packages. This requires the plugins to implement the following: + +* `.unitypackage` must include a Version Handler manifests that describes + the components of the plugin. If the plugin has no dependencies + the manifest would just include the files in the plugin. +* The PM package JSON provided by the registry must include a keyword + (in the `versions.VERSION.keyword` list) that maps the PM package + to a Version Handler package using the format + `vh-name:VERSION_HANDLER_MANIFEST_NAME` where `VERSION_HANDLER_MANIFEST_NAME` + is the name of the manifest defined in the `.unitypackage`. For + more information see the description of the `gvhp_manifestname` asset label + in the *Version Handler Usage* section. + +When using the `Assets > External Dependency Manager > +Package Manager Resolver > Migrate Packages` menu option, PMR then +will: + +* List all Version Handler manager packages in the project. +* Search all available packages in the PM registries and fetch keywords + associated with each package parsing the Version Handler manifest names + for each package. +* Map each installed Version Handler package to a PM package. +* Prompt the user to migrate the discovered packages. +* Perform package migration for all selected packages if the user clicks + the `Apply` button. + +## Configuration + +PMR can be configured via the `Assets > External Dependency Manager > +Package Manager Resolver > Settings` menu option: + +* `Add package registries` when enabled, when the plugin loads or registry + configuration files change, this will prompt the user to add registries + that are not present in the Package Manager. +* `Prompt to add package registries` will cause a developer to be prompted + with a window that will ask for confirmation before adding registries. + When this is disabled registries are added silently to the project. +* `Prompt to migrate packages` will cause a developer to be prompted + with a window that will ask for confirmation before migrating packages + installed in the `Assets` directory to PM packages. +* `Enable Analytics Reporting` when enabled, reports the use of the plugin + to the developers so they can make imrpovements. +* `Verbose logging` when enabled prints debug information to the console + which can be useful when filing bug reports. + +# Version Handler Usage + +The Version Handler component of this plugin manages: + +* Shared Unity plugin dependencies. +* Upgrading Unity plugins by cleaning up old files from previous versions. +* Uninstallation of plugins that are distributed with manifest files. +* Restoration of plugin assets to their original install locations if assets + are tagged with the `exportpath` label. + +Since the Version Handler needs to modify Unity asset metadata (`.meta` files), +to enable / disable components, rename and delete asset files it does not +work with Package Manager installed packages. It's still possible to +include EDM4U in Package Manager packages, the Version Handler component +simply won't do anything to PM plugins in this case. + +## Using Version Handler Managed Plugins + +If a plugin is imported at multiple different versions into a project, if +the Version Handler is enabled, it will automatically check all managed +assets to determine the set of assets that are out of date and assets that +should be removed. To disable automatic checking managed assets disable +the `Enable version management` option in the +`Assets > External Dependency Manager > Version Handler > Settings` menu. + +If version management is disabled, it's possible to check managed assets +manually using the +`Assets > External Dependency Manager > Version Handler > Update` menu option. + +### Listing Managed Plugins + +Plugins managed by the Version Handler, those that ship with manifest files, +can displayed using the `Assets > External Dependency Manager > +Version Handler > Display Managed Packages` menu option. The list of plugins +are written to the console window along with the set of files used by each +plugin. + +### Uninstalling Managed Plugins + +Plugins managed by the Version Handler, those that ship with manifest files, +can be removed using the `Assets > External Dependency Manager > +Version Handler > Uninstall Managed Packages` menu option. This operation +will display a window that allows a developer to select a set of plugins to +remove which will remove all files owned by each plugin excluding those that +are in use by other installed plugins. + +Files managed by the Version Handler, those labeled with the `gvh` asset label, +can be checked to see whether anything needs to be upgraded, disabled or +removed using the `Assets > External Dependency Manager > +Version Handler > Update` menu option. + +### Restore Install Paths + +Some developers move assets around in their project which can make it +harder for plugin maintainers to debug issues if this breaks Unity's +[special folders](https://docs.unity3d.com/Manual/SpecialFolders.html) rules. +If assets are labeled with their original install / export path +(see `gvhp_exportpath` below), Version Handler can restore assets to their +original locations when using the `Assets > External Dependency Manager > +Version Handler > Move Files To Install Locations` menu option. + +### Settings + +Some behavior of the Version Handler can be configured via the +`Assets > External Dependency Manager > Version Handler > Settings` menu +option. + +* `Enable version management` controls whether the plugin should automatically + check asset versions and apply changes. If this is disabled the process + should be run manually when installing or upgrading managed plugins using + `Assets > External Dependency Manager > Version Handler > Update`. +* `Rename to canonical filenames` is a legacy option that will rename files to + remove version numbers and other labels from filenames. +* `Prompt for obsolete file deletion` enables the display of a window when + obsolete files are deleted allowing the developer to select which files to + delete and those to keep. +* `Allow disabling files via renaming` controls whether obsolete or disabled + files should be disabled by renaming them to `myfilename_DISABLED`. + Renaming to disable files is required in some scenarios where Unity doesn't + support removing files from the build via the PluginImporter. +* `Enable Analytics Reporting` enables / disables usage reporting to plugin + developers to improve the product. +* `Verbose logging` enables _very_ noisy log output that is useful for + debugging while filing a bug report or building a new managed plugin. +* `Use project settings` saves settings for the plugin in the project rather + than system-wide. + +## Redistributing a Managed Plugin + +The Version Handler employs a couple of methods for managing version +selection, upgrade and removal of plugins. + +* Each plugin can ship with a manifest file that lists the files it includes. + This makes it possible for Version Handler to calculate the difference + in assets between the most recent release of a plugin and the previous + release installed in a project. If a files are removed the Version Handler + will prompt the user to clean up obsolete files. +* Plugins can ship using assets with unique names, unique GUIDs and version + number labels. Version numbers can be attached to assets using labels or + added to the filename (e.g `myfile.txt` would be `myfile_version-x.y.z.txt). + This allows the Version Handler to determine which set of files are the + same file at different versions, select the most recent version and prompt + the developer to clean up old versions. + +Unity plugins can be managed by the Version Handler using the following steps: + + 1. Add the `gvh` asset label to each asset (file) you want Version Handler + to manage. + 1. Add the `gvh_version-VERSION` label to each asset where `VERSION` is the + version of the plugin you're releasing (e.g 1.2.3). + 1. Add the `gvhp_exportpath-PATH` label to each asset where `PATH` is the + export path of the file when the `.unitypackage` is created. This is + used to track files if they're moved around in a project by developers. + 1. Optional: Add `gvh_targets-editor` label to each editor DLL in your + plugin and disable `editor` as a target platform for the DLL. + The Version Handler will enable the most recent version of this DLL when + the plugin is imported. + 1. Optional: If your plugin is included in other Unity plugins, you should + add the version number to each filename and change the GUID of each asset. + This allows multiple versions of your plugin to be imported into a Unity + project, with the Version Handler component activating only the most + recent version. + 1. Create a manifest text file named `MY_UNIQUE_PLUGIN_NAME_VERSION.txt` + that lists all the files in your plugin relative to the project root. + Then add the `gvh_manifest` label to the asset to indicate this file is + a plugin manifest. + 1. Optional: Add a `gvhp_manifestname-NAME` label to your manifest file + to provide a human readable name for your package. If this isn't provided + the name of the manifest file will be used as the package name. + NAME can match the pattern `[0-9]+[a-zA-Z -]' where a leading integer + will set the priority of the name where `0` is the highest priority + and preferably used as the display name. The lowest value (i.e highest + priority name) will be used as the display name and all other specified + names will be aliases of the display name. Aliases can refer to previous + names of the package allowing renaming across published versions. + 1. Redistribute EDM4U Unity plugin with your plugin. + See the [Plugin Redistribution](#plugin-redistribution) for the details. + +If you follow these steps: + + * When users import a newer version of your plugin, files referenced by the + older version's manifest are cleaned up. + * The latest version of the plugin will be selected when users import + multiple packages that include your plugin, assuming the steps in + [Plugin Redistribution](#plugin-redistribution) are followed. + +# Building from Source + +To build this plugin from source you need the following tools installed: + * Unity (with iOS and Android modules installed) + +You can build the plugin by running the following from your shell +(Linux / OSX): + +``` +./gradlew build +``` + +or Windows: + +``` +./gradlew.bat build +``` + +# Releasing + +Each time a new build of this plugin is checked into the source tree you +need to do the following: + + * Bump the plugin version variable `pluginVersion` in `build.gradle` + * Update `CHANGELOG.md` with the new version number and changes included in + the release. + * Build the release using `./gradlew release` which performs the following: + * Updates `external-dependency-manager-*.unitypackage` + * Copies the unpacked plugin to the `exploded` directory. + * Updates template metadata files in the `plugin` directory. + The GUIDs of all asset metadata is modified due to the version number + change. Each file within the plugin is versioned to allow multiple + versions of the plugin to be imported into a Unity project which allows + the most recent version to be activated by the Version Handler + component. + * Create release commit using `./gradlew gitCreateReleaseCommit` which + performs `git commit -a -m "description from CHANGELOG.md"` + * Once the release commit is merge, tag the release using + `./gradlew gitTagRelease` which performs the following: + * `git tag -a pluginVersion -m "version RELEASE"` to tag the release. + * Update tags on remote branch using `git push --tag REMOTE HEAD:master` diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/README.md.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/README.md.meta new file mode 100644 index 0000000..dc57bb6 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/README.md.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57b5c3f72b65480eba2cc96380835972 +labels: +- gvh +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/README.md +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt new file mode 100755 index 0000000..63e8150 --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt @@ -0,0 +1,13 @@ +Assets/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll.mdb +Assets/ExternalDependencyManager/Editor/CHANGELOG.md +Assets/ExternalDependencyManager/Editor/Google.VersionHandler.dll +Assets/ExternalDependencyManager/Editor/Google.VersionHandler.dll.mdb +Assets/ExternalDependencyManager/Editor/LICENSE +Assets/ExternalDependencyManager/Editor/README.md diff --git a/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt.meta b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt.meta new file mode 100644 index 0000000..55660ac --- /dev/null +++ b/Assets/Samples/Dependencies/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f0ebd68c0b4541ada7e16bfce4ef4155 +labels: +- gvh +- gvh_manifest +- gvh_version-1.2.169 +- gvhp_exportpath-ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt +- gvhp_manifestname-0External Dependency Manager +- gvhp_manifestname-play-services-resolver +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames.meta b/Assets/Samples/Dependencies/GooglePlayGames.meta new file mode 100644 index 0000000..a5aab89 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ad5542892e7045a292e79c8d825de22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games.meta new file mode 100644 index 0000000..c9f7b5f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 07c584f6dabcf1c52bdb6a9f07429cde +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor.meta new file mode 100644 index 0000000..00da255 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 11083f74e79584f50ad394be94e2caec +folderAsset: yes +timeCreated: 1435699548 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs new file mode 100644 index 0000000..8413846 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs @@ -0,0 +1,460 @@ +// +// Copyright (C) Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +namespace GooglePlayGames.Editor +{ + using System; + using System.Collections; + using System.IO; + using System.Xml; + using UnityEditor; + using UnityEngine; + + /// + /// Google Play Game Services Setup dialog for Android. + /// + public class GPGSAndroidSetupUI : EditorWindow + { + /// + /// The configuration data from the play games console "resource data" + /// + private string mConfigData = string.Empty; + + /// + /// The name of the class to generate containing the resource constants. + /// + private string mClassName = "GPGSIds"; + + /// + /// The scroll position + /// + private Vector2 scroll; + + /// + /// The directory for the constants class. + /// + private string mConstantDirectory = "Assets"; + + /// + /// The web client identifier. + /// + private string mWebClientId = string.Empty; + + /// + /// Menus the item for GPGS android setup. + /// + [MenuItem("Window/Google Play Games/Setup/Android setup...", false, 1)] + public static void MenuItemFileGPGSAndroidSetup() + { + EditorWindow window = EditorWindow.GetWindow( + typeof(GPGSAndroidSetupUI), true, GPGSStrings.AndroidSetup.Title); + window.minSize = new Vector2(500, 400); + } + + [MenuItem("Window/Google Play Games/Setup/Android setup...", true)] + public static bool EnableAndroidMenuItem() + { +#if UNITY_ANDROID + return true; +#else + return false; +#endif + } + + /// + /// Performs setup using the Android resources downloaded XML file + /// from the play console. + /// + /// true, if setup was performed, false otherwise. + /// The web client id. + /// the directory to write the constants file to. + /// Fully qualified class name for the resource Ids. + /// Resource xml data. + /// Nearby svc identifier. + /// Indicates this app requires G+ + public static bool PerformSetup( + string clientId, + string classDirectory, + string className, + string resourceXmlData, + string nearbySvcId) + { + if (string.IsNullOrEmpty(resourceXmlData) && + !string.IsNullOrEmpty(nearbySvcId)) + { + return PerformSetup( + clientId, + GPGSProjectSettings.Instance.Get(GPGSUtil.APPIDKEY), + nearbySvcId); + } + + if (ParseResources(classDirectory, className, resourceXmlData)) + { + GPGSProjectSettings.Instance.Set(GPGSUtil.CLASSDIRECTORYKEY, classDirectory); + GPGSProjectSettings.Instance.Set(GPGSUtil.CLASSNAMEKEY, className); + GPGSProjectSettings.Instance.Set(GPGSUtil.ANDROIDRESOURCEKEY, resourceXmlData); + + // check the bundle id and set it if needed. + CheckBundleId(); + + GPGSUtil.CheckAndFixDependencies(); + GPGSUtil.CheckAndFixVersionedAssestsPaths(); + AssetDatabase.Refresh(); + + Google.VersionHandler.VerboseLoggingEnabled = true; + Google.VersionHandler.UpdateVersionedAssets(forceUpdate: true); + Google.VersionHandler.Enabled = true; + AssetDatabase.Refresh(); + + Google.VersionHandler.InvokeStaticMethod( + Google.VersionHandler.FindClass( + "Google.JarResolver", + "GooglePlayServices.PlayServicesResolver"), + "MenuResolve", null); + + return PerformSetup( + clientId, + GPGSProjectSettings.Instance.Get(GPGSUtil.APPIDKEY), + nearbySvcId); + } + + return false; + } + + /// + /// Provide static access to setup for facilitating automated builds. + /// + /// The oauth2 client id for the game. This is only + /// needed if the ID Token or access token are needed. + /// App identifier. + /// Optional nearby connection serviceId + /// Indicates that GooglePlus should be enabled + /// true if successful + public static bool PerformSetup(string webClientId, string appId, string nearbySvcId) + { + if (!string.IsNullOrEmpty(webClientId)) + { + if (!GPGSUtil.LooksLikeValidClientId(webClientId)) + { + GPGSUtil.Alert(GPGSStrings.Setup.ClientIdError); + return false; + } + + string serverAppId = webClientId.Split('-')[0]; + if (!serverAppId.Equals(appId)) + { + GPGSUtil.Alert(GPGSStrings.Setup.AppIdMismatch); + return false; + } + } + + // check for valid app id + if (!GPGSUtil.LooksLikeValidAppId(appId) && string.IsNullOrEmpty(nearbySvcId)) + { + GPGSUtil.Alert(GPGSStrings.Setup.AppIdError); + return false; + } + + if (nearbySvcId != null) + { +#if UNITY_ANDROID + if (!NearbyConnectionUI.PerformSetup(nearbySvcId, true)) + { + return false; + } +#endif + } + + GPGSProjectSettings.Instance.Set(GPGSUtil.APPIDKEY, appId); + GPGSProjectSettings.Instance.Set(GPGSUtil.WEBCLIENTIDKEY, webClientId); + GPGSProjectSettings.Instance.Save(); + GPGSUtil.UpdateGameInfo(); + + // check that Android SDK is there + if (!GPGSUtil.HasAndroidSdk()) + { + Debug.LogError("Android SDK not found."); + EditorUtility.DisplayDialog( + GPGSStrings.AndroidSetup.SdkNotFound, + GPGSStrings.AndroidSetup.SdkNotFoundBlurb, + GPGSStrings.Ok); + return false; + } + + // Generate AndroidManifest.xml + GPGSUtil.GenerateAndroidManifest(); + + // refresh assets, and we're done + AssetDatabase.Refresh(); + GPGSProjectSettings.Instance.Set(GPGSUtil.ANDROIDSETUPDONEKEY, true); + GPGSProjectSettings.Instance.Save(); + + return true; + } + + /// + /// Called when this object is enabled by Unity editor. + /// + public void OnEnable() + { + GPGSProjectSettings settings = GPGSProjectSettings.Instance; + mConstantDirectory = settings.Get(GPGSUtil.CLASSDIRECTORYKEY, mConstantDirectory); + mClassName = settings.Get(GPGSUtil.CLASSNAMEKEY, mClassName); + mConfigData = settings.Get(GPGSUtil.ANDROIDRESOURCEKEY); + mWebClientId = settings.Get(GPGSUtil.WEBCLIENTIDKEY); + } + + /// + /// Called when the GUI should be rendered. + /// + public void OnGUI() + { + GUI.skin.label.wordWrap = true; + GUILayout.BeginVertical(); + + GUIStyle link = new GUIStyle(GUI.skin.label); + link.normal.textColor = new Color(0f, 0f, 1f); + + GUILayout.Space(10); + GUILayout.Label(GPGSStrings.AndroidSetup.Blurb); + if (GUILayout.Button("Open Play Games Console", link, GUILayout.ExpandWidth(false))) + { + Application.OpenURL("https://play.google.com/apps/publish"); + } + + Rect last = GUILayoutUtility.GetLastRect(); + last.y += last.height - 2; + last.x += 3; + last.width -= 6; + last.height = 2; + + GUI.Box(last, string.Empty); + + GUILayout.Space(15); + GUILayout.Label("Constants class name", EditorStyles.boldLabel); + GUILayout.Label("Enter the fully qualified name of the class to create containing the constants"); + GUILayout.Space(10); + + mConstantDirectory = EditorGUILayout.TextField( + "Directory to save constants", + mConstantDirectory, + GUILayout.MinWidth(480)); + + mClassName = EditorGUILayout.TextField( + "Constants class name", + mClassName, + GUILayout.MinWidth(480)); + + GUILayout.Label("Resources Definition", EditorStyles.boldLabel); + GUILayout.Label("Paste in the Android Resources from the Play Console"); + GUILayout.Space(10); + + scroll = GUILayout.BeginScrollView(scroll); + mConfigData = EditorGUILayout.TextArea( + mConfigData, + GUILayout.MinWidth(475), + GUILayout.Height(Screen.height)); + GUILayout.EndScrollView(); + GUILayout.Space(10); + + // Client ID field + GUILayout.Label(GPGSStrings.Setup.WebClientIdTitle, EditorStyles.boldLabel); + GUILayout.Label(GPGSStrings.AndroidSetup.WebClientIdBlurb); + + mWebClientId = EditorGUILayout.TextField( + GPGSStrings.Setup.ClientId, + mWebClientId, + GUILayout.MinWidth(450)); + + GUILayout.Space(10); + + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(GPGSStrings.Setup.SetupButton, GUILayout.Width(100))) + { + // check that the classname entered is valid + try + { + if (GPGSUtil.LooksLikeValidPackageName(mClassName)) + { + DoSetup(); + return; + } + } + catch (Exception e) + { + GPGSUtil.Alert( + GPGSStrings.Error, + "Invalid classname: " + e.Message); + } + } + + if (GUILayout.Button("Cancel", GUILayout.Width(100))) + { + Close(); + } + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + GUILayout.Space(20); + GUILayout.EndVertical(); + } + + /// + /// Starts the setup process. + /// + public void DoSetup() + { + if (PerformSetup(mWebClientId, mConstantDirectory, mClassName, mConfigData, null)) + { + CheckBundleId(); + + EditorUtility.DisplayDialog( + GPGSStrings.Success, + GPGSStrings.AndroidSetup.SetupComplete, + GPGSStrings.Ok); + + GPGSProjectSettings.Instance.Set(GPGSUtil.ANDROIDSETUPDONEKEY, true); + Close(); + } + else + { + GPGSUtil.Alert( + GPGSStrings.Error, + "Invalid or missing XML resource data. Make sure the data is" + + " valid and contains the app_id element"); + } + } + + /// + /// Checks the bundle identifier. + /// + /// + /// Check the package id. If one is set the gpgs properties, + /// and the player settings are the default or empty, set it. + /// if the player settings is not the default, then prompt before + /// overwriting. + /// + public static void CheckBundleId() + { + string packageName = GPGSProjectSettings.Instance.Get( + GPGSUtil.ANDROIDBUNDLEIDKEY, string.Empty); + string currentId; +#if UNITY_5_6_OR_NEWER + currentId = PlayerSettings.GetApplicationIdentifier( + BuildTargetGroup.Android); +#else + currentId = PlayerSettings.bundleIdentifier; +#endif + if (!string.IsNullOrEmpty(packageName)) + { + if (string.IsNullOrEmpty(currentId) || + currentId == "com.Company.ProductName") + { +#if UNITY_5_6_OR_NEWER + PlayerSettings.SetApplicationIdentifier( + BuildTargetGroup.Android, packageName); +#else + PlayerSettings.bundleIdentifier = packageName; +#endif + } + else if (currentId != packageName) + { + if (EditorUtility.DisplayDialog( + "Set Bundle Identifier?", + "The server configuration is using " + + packageName + ", but the player settings is set to " + + currentId + ".\nSet the Bundle Identifier to " + + packageName + "?", + "OK", + "Cancel")) + { +#if UNITY_5_6_OR_NEWER + PlayerSettings.SetApplicationIdentifier( + BuildTargetGroup.Android, packageName); +#else + PlayerSettings.bundleIdentifier = packageName; +#endif + } + } + } + else + { + Debug.Log("NULL package!!"); + } + } + + /// + /// Parses the resources xml and set the properties. Also generates the + /// constants file. + /// + /// true, if resources was parsed, false otherwise. + /// Class directory. + /// Class name. + /// Res. the data to parse. + private static bool ParseResources(string classDirectory, string className, string res) + { + XmlTextReader reader = new XmlTextReader(new StringReader(res)); + bool inResource = false; + string lastProp = null; + Hashtable resourceKeys = new Hashtable(); + string appId = null; + while (reader.Read()) + { + if (reader.Name == "resources") + { + inResource = true; + } + + if (inResource && reader.Name == "string") + { + lastProp = reader.GetAttribute("name"); + } + else if (inResource && !string.IsNullOrEmpty(lastProp)) + { + if (reader.HasValue) + { + if (lastProp == "app_id") + { + appId = reader.Value; + GPGSProjectSettings.Instance.Set(GPGSUtil.APPIDKEY, appId); + } + else if (lastProp == "package_name") + { + GPGSProjectSettings.Instance.Set(GPGSUtil.ANDROIDBUNDLEIDKEY, reader.Value); + } + else + { + resourceKeys[lastProp] = reader.Value; + } + + lastProp = null; + } + } + } + + reader.Close(); + if (resourceKeys.Count > 0) + { + GPGSUtil.WriteResourceIds(classDirectory, className, resourceKeys); + } + + return appId != null; + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs.meta new file mode 100644 index 0000000..9ee31be --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 41fe658b93aa24c709c540575965fdff +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs new file mode 100644 index 0000000..4d7c39d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs @@ -0,0 +1,53 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.Editor +{ + using UnityEngine; + using UnityEditor; + + public class GPGSDocsUI + { + [MenuItem("Window/Google Play Games/Documentation/Plugin Getting Started Guide...", false, 100)] + public static void MenuItemGettingStartedGuide() + { + Application.OpenURL(GPGSStrings.ExternalLinks.GettingStartedGuideURL); + } + + [MenuItem("Window/Google Play Games/Documentation/Google Play Games API...", false, 101)] + public static void MenuItemPlayGamesServicesAPI() + { + Application.OpenURL(GPGSStrings.ExternalLinks.PlayGamesServicesApiURL); + } + + [MenuItem("Window/Google Play Games/About/About the Plugin...", false, 300)] + public static void MenuItemAbout() + { + string msg = GPGSStrings.AboutText + + PluginVersion.VersionString + " (" + + string.Format("0x{0:X8}", GooglePlayGames.PluginVersion.VersionInt) + ")"; + EditorUtility.DisplayDialog(GPGSStrings.AboutTitle, msg, + GPGSStrings.Ok); + } + + [MenuItem("Window/Google Play Games/About/License...", false, 301)] + public static void MenuItemLicense() + { + EditorUtility.DisplayDialog(GPGSStrings.LicenseTitle, GPGSStrings.LicenseText, + GPGSStrings.Ok); + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs.meta new file mode 100644 index 0000000..befa646 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 73cbcab28a27446ff9e06e06a040814f +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs new file mode 100644 index 0000000..fb55c43 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs @@ -0,0 +1,42 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID +namespace GooglePlayGames.Editor +{ + using System.Collections.Generic; + using System.IO; + using UnityEditor.Callbacks; + using UnityEditor; + using UnityEngine; + + public static class GPGSPostBuild + { + [PostProcessBuild(99999)] + public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject) + { + if (!GPGSProjectSettings.Instance.GetBool(GPGSUtil.ANDROIDSETUPDONEKEY, false)) + { + EditorUtility.DisplayDialog("Google Play Games not configured!", + "Warning!! Google Play Games was not configured, Game Services will not work correctly.", + "OK"); + } + + return; + } + } +} +#endif //UNITY_ANDROID \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs.meta new file mode 100644 index 0000000..9be83cb --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 1a7b050a8e8214613893df7d81dcc13c +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs new file mode 100644 index 0000000..ea6ae5d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs @@ -0,0 +1,197 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Keep this file even on unsupported configurations. + +namespace GooglePlayGames.Editor +{ + using System.Collections.Generic; + using System.IO; +#if UNITY_2017_3_OR_NEWER + using UnityEngine.Networking; +#else + using UnityEngine; + +#endif + + public class GPGSProjectSettings + { + private static GPGSProjectSettings sInstance = null; + + public static GPGSProjectSettings Instance + { + get + { + if (sInstance == null) + { + sInstance = new GPGSProjectSettings(); + } + + return sInstance; + } + } + + private bool mDirty = false; + private readonly string mFile; + private Dictionary mDict = new Dictionary(); + + private GPGSProjectSettings() + { + mFile = GPGSUtil.SlashesToPlatformSeparator("ProjectSettings/GooglePlayGameSettings.txt"); + + StreamReader rd = null; + + // read the settings file, this list is all the locations it can be in order of precedence. + string[] fileLocations = + { + mFile, + GPGSUtil.SlashesToPlatformSeparator(Path.Combine(GPGSUtil.RootPath, "Editor/projsettings.txt")), + GPGSUtil.SlashesToPlatformSeparator("Assets/Editor/projsettings.txt") + }; + + foreach (string f in fileLocations) + { + if (File.Exists(f)) + { + // assign the reader and break out of the loop + rd = new StreamReader(f); + break; + } + } + + if (rd != null) + { + while (!rd.EndOfStream) + { + string line = rd.ReadLine(); + if (line == null || line.Trim().Length == 0) + { + break; + } + + line = line.Trim(); + string[] p = line.Split(new char[] {'='}, 2); + if (p.Length >= 2) + { + mDict[p[0].Trim()] = p[1].Trim(); + } + } + + rd.Close(); + } + } + + public string Get(string key, Dictionary overrides) + { + if (overrides.ContainsKey(key)) + { + return overrides[key]; + } + else if (mDict.ContainsKey(key)) + { +#if UNITY_2017_3_OR_NEWER + return UnityWebRequest.UnEscapeURL(mDict[key]); +#else + return WWW.UnEscapeURL(mDict[key]); +#endif + } + else + { + return string.Empty; + } + } + + public string Get(string key, string defaultValue) + { + if (mDict.ContainsKey(key)) + { +#if UNITY_2017_3_OR_NEWER + return UnityWebRequest.UnEscapeURL(mDict[key]); +#else + return WWW.UnEscapeURL(mDict[key]); +#endif + } + else + { + return defaultValue; + } + } + + public string Get(string key) + { + return Get(key, string.Empty); + } + + public bool GetBool(string key, bool defaultValue) + { + return Get(key, defaultValue ? "true" : "false").Equals("true"); + } + + public bool GetBool(string key) + { + return Get(key, "false").Equals("true"); + } + + public void Set(string key, string val) + { +#if UNITY_2017_3_OR_NEWER + string escaped = UnityWebRequest.EscapeURL(val); +#else + string escaped = WWW.EscapeURL(val); +#endif + mDict[key] = escaped; + mDirty = true; + } + + public void Set(string key, bool val) + { + Set(key, val ? "true" : "false"); + } + + public void Save() + { + // See if we are building the plugin, and don't write the settings file + string[] args = System.Environment.GetCommandLineArgs(); + foreach (string a in args) + { + if (a == "-g.building") + { + mDirty = false; + break; + } + } + + if (!mDirty) + { + return; + } + + StreamWriter wr = new StreamWriter(mFile, false); + foreach (string key in mDict.Keys) + { + wr.WriteLine(key + "=" + mDict[key]); + } + + wr.Close(); + mDirty = false; + } + + public static void Reload() + { + sInstance = new GPGSProjectSettings(); + } + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs.meta new file mode 100644 index 0000000..3856a57 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: cf234a050ba25433f9386e20578ccf19 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs new file mode 100644 index 0000000..268e882 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs @@ -0,0 +1,174 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Keep the strings all the time even if on an unsupported configuration. + +namespace GooglePlayGames.Editor +{ + public class GPGSStrings + { + public const string Error = "Error"; + public const string Ok = "OK"; + public const string Cancel = "Cancel"; + public const string Yes = "Yes"; + public const string No = "No"; + public const string Success = "Success"; + public const string Warning = "Warning"; + + public class PostInstall + { + public const string Title = "Google Play Games Plugin for Unity"; + + public const string Text = "The Google Play Games Plugin for Unity version $VERSION " + + "is now ready to use. If this is a new installation or if you have " + + "just upgraded from a previous version, please click the 'Google Play Games' " + + "menu and select 'Android Setup' to set up your project."; + } + + public class Setup + { + public const string AppIdTitle = "Google Play Games Application ID"; + public const string AppId = "Application ID"; + + public const string AppIdBlurb = "Enter your application ID below. This is the numeric\n" + + "identifier provided by the Developer Console (for example, 123456789012)."; + + public const string AppIdError = "The App Id does not appear to be valid. " + + "It must consist solely of digits, usually 10 or more."; + + public const string WebClientIdTitle = "Web App Client ID (Optional)"; + public const string ClientId = "Client ID"; + + public const string ClientIdError = "The Client ID does not appear to be valid. " + + "It should end in .apps.googleusercontent.com."; + + public const string AppIdMismatch = "Web app client ID not associated with this game!"; + + public const string NearbyServiceId = "Nearby Connection Service ID"; + + public const string NearbyServiceBlurb = "Enter the service id that identifies the " + + "nearby connections service scope"; + + public const string SetupButton = "Setup"; + } + + public class NearbyConnections + { + public const string Title = "Google Play Games - Nearby Connections Setup"; + + public const string Blurb = "To configure Nearby Connections in this project,\n" + + "please enter the information below and click on the Setup button."; + + public const string SetupComplete = "Nearby connections configured successfully."; + } + + public class AndroidSetup + { + public const string Title = "Google Play Games - Android Configuration"; + + public const string Blurb = "To configure Google Play Games in this project,\n" + + "go to the Play Game console, then enter the information below and click on the Setup button."; + + public const string WebClientIdBlurb = + "The web app client ID is needed to access the user's ID token and " + + "call other APIs onbehalf of the user." + + " It is not required for Game Services. Enter your oauth2 client ID below.\nTo obtain this " + + "ID, generate a web linked app in Developer Console. Example:\n" + + "123456789012-abcdefghijklm.apps.googleusercontent.com"; + + public const string PkgName = "Package name"; + + public const string PkgNameBlurb = "Enter your application's package name below.\n" + + "(for example, com.example.lorem.ipsum)."; + + public const string PackageNameError = "The package name does not appear to be valid. " + + "Enter a valid Android package name (for example, com.example.lorem.ipsum)."; + + public const string SdkNotFound = "Android SDK Not found"; + + public const string SdkNotFoundBlurb = "The Android SDK path was not found. " + + "Please configure it in the Unity preferences window (under External Tools)."; + + public const string LibProjNotFound = "Google Play Services Library Project Not Found"; + + public const string LibProjNotFoundBlurb = "Google Play Services library project " + + "could not be found your SDK installation. Make sure it is installed (open " + + "the SDK manager and go to Extras, and select Google Play Services)."; + + public const string SupportJarNotFound = "Android Support Library v4 Not Found"; + + public const string SupportJarNotFoundBlurb = "Android Support Library v4 " + + "could not be found your SDK installation. Make sure it is installed (open " + + "the SDK manager and go to Extras, and select 'Android Support Library')."; + + public const string LibProjVerNotFound = "The version of your copy of the Google Play " + + "Services Library Project could not be determined. Please make sure it is " + + "at least version {0}. Continue?"; + + public const string LibProjVerTooOld = "Your copy of the Google Play " + + "Services Library Project is out of date. Please launch the Android SDK manager " + + "and upgrade your Google Play Services bundle to the latest version (your version: " + + "{0}; required version: {1}). Proceeding may cause problems. Proceed anyway?"; + + public const string SetupComplete = "Google Play Games configured successfully."; + } + + public class ExternalLinks + { + public const string GettingStartedGuideURL = + "https://github.com/playgameservices/play-games-plugin-for-unity"; + + public const string PlayGamesServicesApiURL = + "https://developers.google.com/games/services"; + + public const string GooglePlayGamesAndroidSdkTitle = "Google Play Games Android SDK Download"; + + public const string GooglePlayGamesAndroidSdkBlurb = "The Google Play Games SDK for " + + "Android must be downloaded via the Android SDK Manager. Do you wish to " + + "start the SDK manager now?"; + + public const string GooglePlayGamesAndroidSdkInstructions = "The Android SDK manager " + + "will be launched. Install or upgrade the 'Google Play Services' package, " + + "which can be found under the 'Extras' " + + "category."; + + public const string GooglePlayGamesAndroidSdkManagerFailed = "Failed to find the " + + "Android SDK manager executable. Make sure the Android SDK is properly installed " + + "and that its path is correctly configured in the Unity preferences window " + + "(under External Tools)."; + } + + public const string AboutTitle = "Google Play Games Plugin for Unity"; + + public const string AboutText = "Copyright (C) 2014 Google Inc.\n\nThis is an open-source " + + "plugin that allows cross-platform integration with Google Play games services. " + + "For more information, visit the official site on Github:\n\n" + + "https://github.com/playgameservices/play-games-plugin-for-unity\n\nPlugin version: "; + + public const string LicenseTitle = "Google Play Games Plugin for Unity"; + + public const string LicenseText = "Copyright (C) 2014 Google Inc. All Rights Reserved.\n\n" + + "Licensed under the Apache License, Version 2.0 (the \"License\"); " + + "you may not use this file except in compliance with the License. " + + "You may obtain a copy of the License at\n\n" + + " http://www.apache.org/licenses/LICENSE-2.0\n\n" + + "Unless required by applicable law or agreed to in writing, software " + + "distributed under the License is distributed on an \"AS IS\" BASIS, " + + "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. " + + "See the License for the specific language governing permissions and " + + "limitations under the License."; + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs.meta new file mode 100644 index 0000000..bf933fd --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 992ecb564cf02408d9c5a1b44d958334 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs new file mode 100644 index 0000000..ada7ed1 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs @@ -0,0 +1,61 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.Editor +{ + using System.IO; + using UnityEditor; + using UnityEngine; + + /// + /// GPGS upgrader handles performing and upgrade tasks. + /// + [InitializeOnLoad] + public class GPGSUpgrader + { + /// + /// Initializes static members of the class. + /// + static GPGSUpgrader() + { + if (EditorApplication.isPlayingOrWillChangePlaymode) + return; + Debug.Log("GPGSUpgrader start"); + + GPGSProjectSettings.Instance.Set(GPGSUtil.LASTUPGRADEKEY, PluginVersion.VersionKey); + GPGSProjectSettings.Instance.Set(GPGSUtil.PLUGINVERSIONKEY, + PluginVersion.VersionString); + GPGSProjectSettings.Instance.Save(); + + bool isChanged = false; + // Check that there is a AndroidManifest.xml file + if (!GPGSUtil.AndroidManifestExists()) + { + isChanged = true; + GPGSUtil.GenerateAndroidManifest(); + } + + if (isChanged) + { + AssetDatabase.Refresh(); + } + Debug.Log("GPGSUpgrader done"); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs.meta new file mode 100644 index 0000000..8ef2612 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 357a64420a0c44b61a0ed7ca22c7f10f +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs new file mode 100644 index 0000000..4eadb15 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs @@ -0,0 +1,798 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Keep this even on unsupported configurations. + +namespace GooglePlayGames.Editor +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Xml; + using UnityEditor; + using UnityEngine; + + /// + /// Utility class to perform various tasks in the editor. + /// + public static class GPGSUtil + { + /// Property key for project settings. + public const string SERVICEIDKEY = "App.NearbdServiceId"; + + /// Property key for project settings. + public const string APPIDKEY = "proj.AppId"; + + /// Property key for project settings. + public const string CLASSDIRECTORYKEY = "proj.classDir"; + + /// Property key for project settings. + public const string CLASSNAMEKEY = "proj.ConstantsClassName"; + + /// Property key for project settings. + public const string WEBCLIENTIDKEY = "and.ClientId"; + + /// Property key for project settings. + public const string ANDROIDRESOURCEKEY = "and.ResourceData"; + + /// Property key for project settings. + public const string ANDROIDSETUPDONEKEY = "android.SetupDone"; + + /// Property key for project settings. + public const string ANDROIDBUNDLEIDKEY = "and.BundleId"; + + /// Property key for plugin version. + public const string PLUGINVERSIONKEY = "proj.pluginVersion"; + + /// Property key for nearby settings done. + public const string NEARBYSETUPDONEKEY = "android.NearbySetupDone"; + + /// Property key for project settings. + public const string LASTUPGRADEKEY = "lastUpgrade"; + + /// Constant for token replacement + private const string SERVICEIDPLACEHOLDER = "__NEARBY_SERVICE_ID__"; + + private const string SERVICEID_ELEMENT_PLACEHOLDER = "__NEARBY_SERVICE_ELEMENT__"; + + private const string NEARBY_PERMISSIONS_PLACEHOLDER = "__NEARBY_PERMISSIONS__"; + + /// Constant for token replacement + private const string APPIDPLACEHOLDER = "__APP_ID__"; + + /// Constant for token replacement + private const string CLASSNAMEPLACEHOLDER = "__Class__"; + + /// Constant for token replacement + private const string WEBCLIENTIDPLACEHOLDER = "__WEB_CLIENTID__"; + + /// Constant for token replacement + private const string PLUGINVERSIONPLACEHOLDER = "__PLUGIN_VERSION__"; + + /// Constant for require google plus token replacement + private const string REQUIREGOOGLEPLUSPLACEHOLDER = "__REQUIRE_GOOGLE_PLUS__"; + + /// Property key for project settings. + private const string TOKENPERMISSIONKEY = "proj.tokenPermissions"; + + /// Constant for token replacement + private const string NAMESPACESTARTPLACEHOLDER = "__NameSpaceStart__"; + + /// Constant for token replacement + private const string NAMESPACEENDPLACEHOLDER = "__NameSpaceEnd__"; + + /// Constant for token replacement + private const string CONSTANTSPLACEHOLDER = "__Constant_Properties__"; + + /// + /// The game info file path, relative to the plugin root directory. This is a generated file. + /// + private const string GameInfoRelativePath = "Runtime/Scripts/GameInfo.cs"; + + /// + /// The manifest path, relative to the plugin root directory. + /// + /// The Games SDK requires additional metadata in the AndroidManifest.xml + /// file. + private const string ManifestRelativePath = + "../../Plugins/Android/GooglePlayGamesManifest.androidlib/AndroidManifest.xml"; + + private const string RootFolderName = "com.google.play.games"; + + /// + /// The root path of the Google Play Games plugin + /// + public static string RootPath + { + get + { + if (string.IsNullOrEmpty(mRootPath)) + { +#if UNITY_2018_4_OR_NEWER + // Search for root path in plugin locations for both Asset packages and UPM packages + string[] dirs = Directory.GetDirectories("Packages", RootFolderName, SearchOption.AllDirectories); + string[] dir1 = Directory.GetDirectories("Assets", RootFolderName, SearchOption.AllDirectories); + int dirsLength = dirs.Length; + Array.Resize(ref dirs, dirsLength + dir1.Length); + Array.Copy(dir1, 0, dirs, dirsLength, dir1.Length); +#else + string[] dirs = Directory.GetDirectories("Assets", RootFolderName, SearchOption.AllDirectories); +#endif + switch (dirs.Length) + { + case 0: + Alert("Plugin error: com.google.play.games folder was renamed"); + throw new Exception("com.google.play.games folder was renamed"); + + case 1: + mRootPath = SlashesToPlatformSeparator(dirs[0]); + break; + + default: + for (int i = 0; i < dirs.Length; i++) + { + if (File.Exists(SlashesToPlatformSeparator(Path.Combine(dirs[i], GameInfoRelativePath))) + ) + { + mRootPath = SlashesToPlatformSeparator(dirs[i]); + break; + } + } + + if (string.IsNullOrEmpty(mRootPath)) + { + Alert("Plugin error: com.google.play.games folder was renamed"); + throw new Exception("com.google.play.games folder was renamed"); + } + + break; + } + } + // UPM package root path is 'Library/PackageCache/com.google.play.games@.*/ + // where the suffix can be a version number if installed with URS + // or a hash if from disk or tarball + if (mRootPath.Contains(RootFolderName + '@')) + { + mRootPath = mRootPath.Replace("Packages", "Library/PackageCache"); + } + return mRootPath; + } + } + + /// + /// The game info file path. This is a generated file. + /// + private static string GameInfoPath + { + get { return SlashesToPlatformSeparator(Path.Combine(RootPath, GameInfoRelativePath)); } + } + + /// + /// The manifest path. + /// + /// The Games SDK requires additional metadata in the AndroidManifest.xml + /// file. + private static string ManifestPath + { + get { return SlashesToPlatformSeparator(Path.Combine(RootPath, ManifestRelativePath)); } + } + + /// + /// The root path of the Google Play Games plugin + /// + private static string mRootPath = ""; + + /// + /// The map of replacements for filling in code templates. The + /// key is the string that appears in the template as a placeholder, + /// the value is the key into the GPGSProjectSettings. + /// + private static Dictionary replacements = + new Dictionary() + { + // Put this element placeholder first, since it has embedded placeholder + {SERVICEID_ELEMENT_PLACEHOLDER, SERVICEID_ELEMENT_PLACEHOLDER}, + {SERVICEIDPLACEHOLDER, SERVICEIDKEY}, + {APPIDPLACEHOLDER, APPIDKEY}, + {CLASSNAMEPLACEHOLDER, CLASSNAMEKEY}, + {WEBCLIENTIDPLACEHOLDER, WEBCLIENTIDKEY}, + {PLUGINVERSIONPLACEHOLDER, PLUGINVERSIONKEY}, + // Causes the placeholder to be replaced with overridden value at runtime. + {NEARBY_PERMISSIONS_PLACEHOLDER, NEARBY_PERMISSIONS_PLACEHOLDER} + }; + + /// + /// Replaces / in file path to be the os specific separator. + /// + /// The path. + /// Path with correct separators. + public static string SlashesToPlatformSeparator(string path) + { + return path.Replace("/", System.IO.Path.DirectorySeparatorChar.ToString()); + } + + /// + /// Reads the file. + /// + /// The file contents. The slashes are corrected. + /// File path. + public static string ReadFile(string filePath) + { + filePath = SlashesToPlatformSeparator(filePath); + if (!File.Exists(filePath)) + { + Alert("Plugin error: file not found: " + filePath); + return null; + } + + StreamReader sr = new StreamReader(filePath); + string body = sr.ReadToEnd(); + sr.Close(); + return body; + } + + /// + /// Reads the editor template. + /// + /// The editor template contents. + /// Name of the template in the editor directory. + public static string ReadEditorTemplate(string name) + { + return ReadFile( + Path.Combine(RootPath, string.Format("Editor{0}{1}.txt", Path.DirectorySeparatorChar, name))); + } + + /// + /// Writes the file. + /// + /// File path - the slashes will be corrected. + /// Body of the file to write. + public static void WriteFile(string file, string body) + { + file = SlashesToPlatformSeparator(file); + DirectoryInfo dir = Directory.GetParent(file); + dir.Create(); + using (var wr = new StreamWriter(file, false)) + { + wr.Write(body); + } + } + + /// + /// Validates the string to be a valid nearby service id. + /// + /// true, if like valid service identifier was looksed, false otherwise. + /// string to test. + public static bool LooksLikeValidServiceId(string s) + { + if (s.Length < 3) + { + return false; + } + + foreach (char c in s) + { + if (!char.IsLetterOrDigit(c) && c != '.') + { + return false; + } + } + + return true; + } + + /// + /// Looks the like valid app identifier. + /// + /// true, if valid app identifier, false otherwise. + /// the string to test. + public static bool LooksLikeValidAppId(string s) + { + if (s.Length < 5) + { + return false; + } + + foreach (char c in s) + { + if (c < '0' || c > '9') + { + return false; + } + } + + return true; + } + + /// + /// Looks the like valid client identifier. + /// + /// true, if valid client identifier, false otherwise. + /// the string to test. + public static bool LooksLikeValidClientId(string s) + { + return s.EndsWith(".googleusercontent.com"); + } + + /// + /// Looks the like a valid bundle identifier. + /// + /// true, if valid bundle identifier, false otherwise. + /// the string to test. + public static bool LooksLikeValidBundleId(string s) + { + return s.Length > 3; + } + + /// + /// Looks like a valid package. + /// + /// true, if valid package name, false otherwise. + /// the string to test. + public static bool LooksLikeValidPackageName(string s) + { + if (string.IsNullOrEmpty(s)) + { + throw new Exception("cannot be empty"); + } + + string[] parts = s.Split(new char[] {'.'}); + foreach (string p in parts) + { + char[] bytes = p.ToCharArray(); + for (int i = 0; i < bytes.Length; i++) + { + if (i == 0 && !char.IsLetter(bytes[i])) + { + throw new Exception("each part must start with a letter"); + } + else if (char.IsWhiteSpace(bytes[i])) + { + throw new Exception("cannot contain spaces"); + } + else if (!char.IsLetterOrDigit(bytes[i]) && bytes[i] != '_') + { + throw new Exception("must be alphanumeric or _"); + } + } + } + + return parts.Length >= 1; + } + + /// + /// Determines if is setup done. + /// + /// true if is setup done; otherwise, false. + public static bool IsSetupDone() + { + bool doneSetup = true; +#if UNITY_ANDROID + doneSetup = GPGSProjectSettings.Instance.GetBool(ANDROIDSETUPDONEKEY, false); + // check gameinfo + if (File.Exists(GameInfoPath)) + { + string contents = ReadFile(GameInfoPath); + if (contents.Contains(APPIDPLACEHOLDER)) + { + Debug.Log("GameInfo not initialized with AppId. " + + "Run Window > Google Play Games > Setup > Android Setup..."); + return false; + } + } + else + { + Debug.Log("GameInfo.cs does not exist. Run Window > Google Play Games > Setup > Android Setup..."); + return false; + } +#endif + + return doneSetup; + } + + /// + /// Makes legal identifier from string. + /// Returns a legal C# identifier from the given string. The transformations are: + /// - spaces => underscore _ + /// - punctuation => empty string + /// - leading numbers are prefixed with underscore. + /// + /// the id + /// Key to convert to an identifier. + public static string MakeIdentifier(string key) + { + string s; + string retval = string.Empty; + if (string.IsNullOrEmpty(key)) + { + return "_"; + } + + s = key.Trim().Replace(' ', '_'); + + foreach (char c in s) + { + if (char.IsLetterOrDigit(c) || c == '_') + { + retval += c; + } + } + + return retval; + } + + /// + /// Displays an error dialog. + /// + /// the message + public static void Alert(string s) + { + Alert(GPGSStrings.Error, s); + } + + /// + /// Displays a dialog with the given title and message. + /// + /// the title. + /// the message. + public static void Alert(string title, string message) + { + EditorUtility.DisplayDialog(title, message, GPGSStrings.Ok); + } + + /// + /// Gets the android sdk path. + /// + /// The android sdk path. + public static string GetAndroidSdkPath() + { + string sdkPath = EditorPrefs.GetString("AndroidSdkRoot"); +#if UNITY_2019_1_OR_NEWER + // Unity 2019.x added installation of the Android SDK in the AndroidPlayer directory + // so fallback to searching for it there. + if (string.IsNullOrEmpty(sdkPath) || EditorPrefs.GetBool("SdkUseEmbedded")) + { + string androidPlayerDir = BuildPipeline.GetPlaybackEngineDirectory(BuildTarget.Android, BuildOptions.None); + if (!string.IsNullOrEmpty(androidPlayerDir)) + { + string androidPlayerSdkDir = Path.Combine(androidPlayerDir, "SDK"); + if (Directory.Exists(androidPlayerSdkDir)) + { + sdkPath = androidPlayerSdkDir; + } + } + } +#endif + if (sdkPath != null && (sdkPath.EndsWith("/") || sdkPath.EndsWith("\\"))) + { + sdkPath = sdkPath.Substring(0, sdkPath.Length - 1); + } + + return sdkPath; + } + + /// + /// Determines if the android sdk exists. + /// + /// true if android sdk exists; otherwise, false. + public static bool HasAndroidSdk() + { + string sdkPath = GetAndroidSdkPath(); + return sdkPath != null && sdkPath.Trim() != string.Empty && System.IO.Directory.Exists(sdkPath); + } + + /// + /// Gets the unity major version. + /// + /// The unity major version. + public static int GetUnityMajorVersion() + { +#if UNITY_5 + string majorVersion = Application.unityVersion.Split('.')[0]; + int ver; + if (!int.TryParse(majorVersion, out ver)) + { + ver = 0; + } + + return ver; +#elif UNITY_4_6 + return 4; +#else + return 0; +#endif + } + + /// + /// Checks for the android manifest file exsistance. + /// + /// true, if the file exists false otherwise. + public static bool AndroidManifestExists() + { + string destFilename = ManifestPath; + + return File.Exists(destFilename); + } + + /// + /// Generates the android manifest. + /// + public static void GenerateAndroidManifest() + { + string destFilename = ManifestPath; + + // Generate AndroidManifest.xml + string manifestBody = GPGSUtil.ReadEditorTemplate("template-AndroidManifest"); + + Dictionary overrideValues = + new Dictionary(); + + if (!string.IsNullOrEmpty(GPGSProjectSettings.Instance.Get(SERVICEIDKEY))) + { + overrideValues[NEARBY_PERMISSIONS_PLACEHOLDER] = + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n"; + overrideValues[SERVICEID_ELEMENT_PLACEHOLDER] = + " \n" + + " \n"; + } + else + { + overrideValues[NEARBY_PERMISSIONS_PLACEHOLDER] = ""; + overrideValues[SERVICEID_ELEMENT_PLACEHOLDER] = ""; + } + + foreach (KeyValuePair ent in replacements) + { + string value = + GPGSProjectSettings.Instance.Get(ent.Value, overrideValues); + manifestBody = manifestBody.Replace(ent.Key, value); + } + + GPGSUtil.WriteFile(destFilename, manifestBody); + GPGSUtil.UpdateGameInfo(); + } + + /// + /// Writes the resource identifiers file. This file contains the + /// resource ids copied (downloaded?) from the play game app console. + /// + /// Class directory. + /// Class name. + /// Resource keys. + public static void WriteResourceIds(string classDirectory, string className, Hashtable resourceKeys) + { + string constantsValues = string.Empty; + string[] parts = className.Split('.'); + string dirName = classDirectory; + if (string.IsNullOrEmpty(dirName)) + { + dirName = "Assets"; + } + + string nameSpace = string.Empty; + for (int i = 0; i < parts.Length - 1; i++) + { + dirName += "/" + parts[i]; + if (nameSpace != string.Empty) + { + nameSpace += "."; + } + + nameSpace += parts[i]; + } + + EnsureDirExists(dirName); + foreach (DictionaryEntry ent in resourceKeys) + { + string key = MakeIdentifier((string) ent.Key); + constantsValues += " public const string " + + key + " = \"" + ent.Value + "\"; // \n"; + } + + string fileBody = GPGSUtil.ReadEditorTemplate("template-Constants"); + if (nameSpace != string.Empty) + { + fileBody = fileBody.Replace( + NAMESPACESTARTPLACEHOLDER, + "namespace " + nameSpace + "\n{"); + } + else + { + fileBody = fileBody.Replace(NAMESPACESTARTPLACEHOLDER, string.Empty); + } + + fileBody = fileBody.Replace(CLASSNAMEPLACEHOLDER, parts[parts.Length - 1]); + fileBody = fileBody.Replace(CONSTANTSPLACEHOLDER, constantsValues); + if (nameSpace != string.Empty) + { + fileBody = fileBody.Replace( + NAMESPACEENDPLACEHOLDER, + "}"); + } + else + { + fileBody = fileBody.Replace(NAMESPACEENDPLACEHOLDER, string.Empty); + } + + WriteFile(Path.Combine(dirName, parts[parts.Length - 1] + ".cs"), fileBody); + } + + /// + /// Updates the game info file. This is a generated file containing the + /// app and client ids. + /// + public static void UpdateGameInfo() + { + string fileBody = GPGSUtil.ReadEditorTemplate("template-GameInfo"); + + foreach (KeyValuePair ent in replacements) + { + string value = + GPGSProjectSettings.Instance.Get(ent.Value); + fileBody = fileBody.Replace(ent.Key, value); + } + + GPGSUtil.WriteFile(GameInfoPath, fileBody); + } + + /// + /// Checks the dependencies file and fixes repository paths + /// if they are incorrect (for example if the user moved plugin + /// into some subdirectory). This is a generated file containing + /// the list of dependencies that are needed for the plugin to work. + /// + public static void CheckAndFixDependencies() + { + string depPath = + SlashesToPlatformSeparator(Path.Combine(GPGSUtil.RootPath, + "Editor/GooglePlayGamesPluginDependencies.xml")); + + XmlDocument doc = new XmlDocument(); + doc.Load(depPath); + + XmlNodeList repos = doc.SelectNodes("//androidPackage[contains(@spec,'com.google.games')]//repository"); + foreach (XmlNode repo in repos) + { + if (!Directory.Exists(repo.InnerText)) + { + int pos = repo.InnerText.IndexOf(RootFolderName); + if (pos != -1) + { + repo.InnerText = + Path.Combine(RootPath, repo.InnerText.Substring(pos + RootFolderName.Length + 1)) + .Replace("\\", "/"); + } + } + } + + doc.Save(depPath); + } + + /// + /// Checks the file containing the list of versioned assets and fixes + /// paths to them if they are incorrect (for example if the user moved + /// plugin into some subdirectory). This is a generated file. + /// + public static void CheckAndFixVersionedAssestsPaths() + { + string[] foundPaths = + Directory.GetFiles(RootPath, "GooglePlayGamesPlugin_v*.txt", SearchOption.AllDirectories); + + if (foundPaths.Length == 1) + { + string tmpFilePath = Path.GetTempFileName(); + + StreamWriter writer = new StreamWriter(tmpFilePath); + using (StreamReader reader = new StreamReader(foundPaths[0])) + { + string assetPath; + while ((assetPath = reader.ReadLine()) != null) + { + int pos = assetPath.IndexOf(RootFolderName); + if (pos != -1) + { + assetPath = Path.Combine(RootPath, assetPath.Substring(pos + RootFolderName.Length + 1)) + .Replace("\\", "/"); + } + + writer.WriteLine(assetPath); + } + } + + writer.Flush(); + writer.Close(); + + try + { + File.Copy(tmpFilePath, foundPaths[0], true); + } + finally + { + File.Delete(tmpFilePath); + } + } + } + + /// + /// Ensures the dir exists. + /// + /// Directory to check. + public static void EnsureDirExists(string dir) + { + dir = SlashesToPlatformSeparator(dir); + if (!Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + } + + /// + /// Deletes the dir if exists. + /// + /// Directory to delete. + public static void DeleteDirIfExists(string dir) + { + dir = SlashesToPlatformSeparator(dir); + if (Directory.Exists(dir)) + { + Directory.Delete(dir, true); + } + } + + /// + /// Gets the Google Play Services library version. This is only + /// needed for Unity versions less than 5. + /// + /// The GPS version. + /// Lib proj path. + private static int GetGPSVersion(string libProjPath) + { + string versionFile = libProjPath + "/res/values/version.xml"; + + XmlTextReader reader = new XmlTextReader(new StreamReader(versionFile)); + bool inResource = false; + int version = -1; + + while (reader.Read()) + { + if (reader.Name == "resources") + { + inResource = true; + } + + if (inResource && reader.Name == "integer") + { + if ("google_play_services_version".Equals( + reader.GetAttribute("name"))) + { + reader.Read(); + Debug.Log("Read version string: " + reader.Value); + version = Convert.ToInt32(reader.Value); + } + } + } + + reader.Close(); + return version; + } + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs.meta new file mode 100644 index 0000000..1b70d2c --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: fd01714f9ee99447996b878b1ac67540 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef new file mode 100644 index 0000000..6dc51ca --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef @@ -0,0 +1,9 @@ +{ + "name": "Google.Play.Games.Editor", + "references": [ + "Google.Play.Games" + ], + "includePlatforms": [ + "Editor" + ] +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef.meta new file mode 100644 index 0000000..8d1f97a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9172e27a923a34eb8b02dc3ab88d3dcd +labels: +- gvh +- gvh_version-0.11.01 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml new file mode 100644 index 0000000..00029d7 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml @@ -0,0 +1,13 @@ + + + + + + + Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository + + + + \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml.meta new file mode 100644 index 0000000..80c4646 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 56e4f40c267bfa268afda2ea9f4846a0 +labels: +- gvh +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPlugin_v0.11.01.txt b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPlugin_v0.11.01.txt new file mode 100644 index 0000000..22e8f92 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPlugin_v0.11.01.txt @@ -0,0 +1,90 @@ +Assets/Plugins/Android/GooglePlayGamesManifest.androidlib/project.properties +Assets/ExternalDependencyManager/Editor/README.md +Assets/ExternalDependencyManager/Editor/Google.VersionHandler.dll.mdb +Assets/ExternalDependencyManager/Editor/external-dependency-manager_version-1.2.169_manifest.txt +Assets/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.VersionHandlerImpl.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll +Assets/ExternalDependencyManager/Editor/1.2.169/Google.IOSResolver.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.PackageManagerResolver.dll.mdb +Assets/ExternalDependencyManager/Editor/1.2.169/Google.JarResolver.dll +Assets/ExternalDependencyManager/Editor/Google.VersionHandler.dll +Assets/ExternalDependencyManager/Editor/CHANGELOG.md +Assets/ExternalDependencyManager/Editor/LICENSE +Assets/GooglePlayGames/AssemblyInfo.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1 +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1 +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5 +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1 +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5 +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5 +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUtil.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSStrings.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPluginDependencies.xml +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSPostBuild.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSDocsUI.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/Google.Play.Games.Editor.asmdef +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSProjectSettings.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSUpgrader.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GPGSAndroidSetupUI.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs +Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs +Assets/PlayServicesResolver/Editor/play-services-resolver_v1.2.137.0.txt diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPlugin_v0.11.01.txt.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPlugin_v0.11.01.txt.meta new file mode 100644 index 0000000..bb7d115 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/GooglePlayGamesPlugin_v0.11.01.txt.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 693a823b8f0ad41fe8231a1b1c8a50da +labels: +- gvh +- gvh_manifest +- gvh_version-0.11.01 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs new file mode 100644 index 0000000..f4cc487 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs @@ -0,0 +1,153 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.Editor +{ + using UnityEngine; + using UnityEditor; + + public class NearbyConnectionUI : EditorWindow + { + private string mNearbyServiceId = string.Empty; + + [MenuItem("Window/Google Play Games/Setup/Nearby Connections setup...", false, 3)] + public static void MenuItemNearbySetup() + { + EditorWindow window = EditorWindow.GetWindow( + typeof(NearbyConnectionUI), true, GPGSStrings.NearbyConnections.Title); + window.minSize = new Vector2(400, 200); + } + + [MenuItem("Window/Google Play Games/Setup/Nearby Connections setup...", true)] + public static bool EnableNearbyMenuItem() + { +#if UNITY_ANDROID + return true; +#else + return false; +#endif + } + + public void OnEnable() + { + mNearbyServiceId = GPGSProjectSettings.Instance.Get(GPGSUtil.SERVICEIDKEY); + } + + public void OnGUI() + { + GUI.skin.label.wordWrap = true; + GUILayout.BeginVertical(); + GUILayout.Space(10); + GUILayout.Label(GPGSStrings.NearbyConnections.Blurb); + GUILayout.Space(10); + + GUILayout.Label(GPGSStrings.Setup.NearbyServiceId, EditorStyles.boldLabel); + GUILayout.Space(10); + GUILayout.Label(GPGSStrings.Setup.NearbyServiceBlurb); + mNearbyServiceId = EditorGUILayout.TextField(GPGSStrings.Setup.NearbyServiceId, + mNearbyServiceId, GUILayout.Width(350)); + + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button(GPGSStrings.Setup.SetupButton, + GUILayout.Width(100))) + { + DoSetup(); + } + + if (GUILayout.Button("Cancel", GUILayout.Width(100))) + { + this.Close(); + } + + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + GUILayout.Space(20); + GUILayout.EndVertical(); + } + + private void DoSetup() + { + if (PerformSetup(mNearbyServiceId, true)) + { + EditorUtility.DisplayDialog(GPGSStrings.Success, + GPGSStrings.NearbyConnections.SetupComplete, GPGSStrings.Ok); + this.Close(); + } + } + + /// Provide static access to setup for facilitating automated builds. + /// The nearby connections service Id + /// true if building android + public static bool PerformSetup(string nearbyServiceId, bool androidBuild) + { + // check for valid app id + if (!GPGSUtil.LooksLikeValidServiceId(nearbyServiceId)) + { + if (EditorUtility.DisplayDialog( + "Remove Nearby connection permissions? ", + "The service Id is invalid. It must follow package naming rules. " + + "Do you want to remove the AndroidManifest entries for Nearby connections?", + "Yes", + "No")) + { + GPGSProjectSettings.Instance.Set(GPGSUtil.SERVICEIDKEY, null); + GPGSProjectSettings.Instance.Save(); + } + else + { + return false; + } + } + else + { + GPGSProjectSettings.Instance.Set(GPGSUtil.SERVICEIDKEY, nearbyServiceId); + GPGSProjectSettings.Instance.Save(); + } + + if (androidBuild) + { + // create needed directories + GPGSUtil.EnsureDirExists("Assets/Plugins"); + GPGSUtil.EnsureDirExists("Assets/Plugins/Android"); + + // Generate AndroidManifest.xml + GPGSUtil.GenerateAndroidManifest(); + + GPGSProjectSettings.Instance.Set(GPGSUtil.NEARBYSETUPDONEKEY, true); + GPGSProjectSettings.Instance.Save(); + + // Resolve the dependencies + Google.VersionHandler.VerboseLoggingEnabled = true; + Google.VersionHandler.UpdateVersionedAssets(forceUpdate: true); + Google.VersionHandler.Enabled = true; + AssetDatabase.Refresh(); + + Google.VersionHandler.InvokeStaticMethod( + Google.VersionHandler.FindClass( + "Google.JarResolver", + "GooglePlayServices.PlayServicesResolver"), + "MenuResolve", null); + } + + return true; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs.meta new file mode 100644 index 0000000..686a2c0 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/NearbyConnectionUI.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b64332a502e18436da5652adbf7e24a3 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository.meta new file mode 100644 index 0000000..b57f758 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a1aac54589c4640cd89900056af3a094 +folderAsset: yes +timeCreated: 1515000812 +licenseType: Free +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com.meta new file mode 100644 index 0000000..fbaa447 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6bfd2e0bf6a79efa5a524c758a029a97 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google.meta new file mode 100644 index 0000000..5468f34 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 44f501fdbcc7ecb3a9d935d48385fcd7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games.meta new file mode 100644 index 0000000..1f44553 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab2c8702a5ac8186e833079b0c2b97eb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support.meta new file mode 100644 index 0000000..369c14d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7aad2f859f18616f6b634cecc92785db +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01.meta new file mode 100644 index 0000000..8916fc4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 270a1b374befae139bb007ed9fe42c0a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom new file mode 100644 index 0000000..9ceb6a0 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom @@ -0,0 +1,23 @@ + + + 4.0.0 + com.google.games + gpgs-plugin-support + 0.11.01 + srcaar + + + com.google.android.gms + play-services-games-v2 + 17.0.0 + compile + + + com.google.android.gms + play-services-nearby + 18.0.2 + compile + + + diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5 b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5 new file mode 100644 index 0000000..40046e4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5 @@ -0,0 +1 @@ +9964a15c4931746b3709a528c241829e \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5.meta new file mode 100644 index 0000000..ed108cf --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.md5.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 021d4ecf67ff30875941d1d1d3e4273f +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.meta new file mode 100644 index 0000000..34f141e --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3a8de8e589297f83cbf708663d04784d +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1 b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1 new file mode 100644 index 0000000..894689e --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1 @@ -0,0 +1 @@ +f543dbb0a4147fcdb6adf7d44092e41aeed42ffc \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1.meta new file mode 100644 index 0000000..37e5807 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.pom.sha1.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2ace5c923ae5a5e4182561bb8b0e47ad +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar new file mode 100644 index 0000000..c5baea5 Binary files /dev/null and b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar differ diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5 b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5 new file mode 100644 index 0000000..e49060f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5 @@ -0,0 +1 @@ +ad17f2aceed310327b5dcb1badc6df2e \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5.meta new file mode 100644 index 0000000..9bee6f3 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.md5.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 6a5d6cd742873c73f8f0c9a1ac445182 +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.meta new file mode 100644 index 0000000..ee5ace2 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8a7a2dcd7d551e040938c69456bd0643 +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1 b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1 new file mode 100644 index 0000000..cfa688c --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1 @@ -0,0 +1 @@ +920847b24a3063aa866d56a3815cdf9ce09d142c \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1.meta new file mode 100644 index 0000000..02964a4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/0.11.01/gpgs-plugin-support-0.11.01.srcaar.sha1.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b8fc53361999b1f4a830505b47234b73 +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml new file mode 100644 index 0000000..a30f6a1 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml @@ -0,0 +1,12 @@ + + + com.google.games + gpgs-plugin-support + + 0.11.01 + + 0.11.01 + + 20220321142410 + + diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5 b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5 new file mode 100644 index 0000000..3cda54a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5 @@ -0,0 +1 @@ +317c4c73ab9be4443cbce8d57a8df3e4 \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5.meta new file mode 100644 index 0000000..1f62e87 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.md5.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b99ac5f1bd7ba77d390d8508c2c3b8cc +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.meta new file mode 100644 index 0000000..550ae32 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e9ae03af85334796fa074f4f75bd5426 +labels: +- gvh +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1 b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1 new file mode 100644 index 0000000..b11328c --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1 @@ -0,0 +1 @@ +a86be37d1603c23020fbbcdf93e73062682cad0b \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1.meta new file mode 100644 index 0000000..af063c3 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/m2repository/com/google/games/gpgs-plugin-support/maven-metadata.xml.sha1.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 75441663f29e7a430af793277d746c7e +labels: +- gvh +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt new file mode 100644 index 0000000..d32616f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt @@ -0,0 +1,27 @@ + + + + + __NEARBY_PERMISSIONS__ + + + + __NEARBY_SERVICE_ELEMENT__ + + + + + + + + + + + diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt.meta new file mode 100644 index 0000000..58c9d9d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-AndroidManifest.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0e1f3c150256848b1ba98702cfb71220 +labels: +- gvh +- gvh_version-0.11.01 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt new file mode 100644 index 0000000..a1a6180 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt @@ -0,0 +1,29 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// +/// This file is automatically generated DO NOT EDIT! +/// +/// These are the constants defined in the Play Games Console for Game Services +/// Resources. +/// + +__NameSpaceStart__ +public static class __Class__ +{ +__Constant_Properties__ +} +__NameSpaceEnd__ diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt.meta new file mode 100644 index 0000000..02600dc --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-Constants.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7f2719cb8be514661b7b6aa9986bfe5f +labels: +- gvh +- gvh_version-0.11.01 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt new file mode 100644 index 0000000..47bb16a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt @@ -0,0 +1,71 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#if UNITY_ANDROID + +namespace GooglePlayGames { + /// + /// This file is automatically generated DO NOT EDIT! + /// + /// These are the constants defined in the Play Games Console for Game Services + /// Resources. + /// + /// + /// File containing information about the game. This is automatically updated by running the + /// platform-appropriate setup commands in the Unity editor (which does a simple search / replace + /// on the IDs in the form "__ID__"). We can check whether any particular field has been updated + /// by checking whether it still retains its initial value - we prevent the constants from being + /// replaced in the aforementioned search/replace by stripping off the leading and trailing "__". + /// + public static class GameInfo { + + private const string UnescapedApplicationId = "APP_ID"; + private const string UnescapedIosClientId = "IOS_CLIENTID"; + private const string UnescapedWebClientId = "WEB_CLIENTID"; + private const string UnescapedNearbyServiceId = "NEARBY_SERVICE_ID"; + + public const string ApplicationId = "__APP_ID__"; // Filled in automatically + public const string IosClientId = "__IOS_CLIENTID__"; // Filled in automatically + public const string WebClientId = "__WEB_CLIENTID__"; // Filled in automatically + public const string NearbyConnectionServiceId = "__NEARBY_SERVICE_ID__"; + + public static bool ApplicationIdInitialized() { + return !string.IsNullOrEmpty(ApplicationId) && !ApplicationId.Equals(ToEscapedToken(UnescapedApplicationId)); + } + + public static bool IosClientIdInitialized() { + return !string.IsNullOrEmpty(IosClientId) && !IosClientId.Equals(ToEscapedToken(UnescapedIosClientId)); + } + + public static bool WebClientIdInitialized() { + return !string.IsNullOrEmpty(WebClientId) && !WebClientId.Equals(ToEscapedToken(UnescapedWebClientId)); + } + + public static bool NearbyConnectionsInitialized() { + return !string.IsNullOrEmpty(NearbyConnectionServiceId) && + !NearbyConnectionServiceId.Equals(ToEscapedToken(UnescapedNearbyServiceId)); + } + + /// + /// Returns an escaped token (i.e. one flanked with "__") for the passed token + /// + /// The escaped token. + /// The Token + private static string ToEscapedToken(string token) { + return string.Format("__{0}__", token); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt.meta new file mode 100644 index 0000000..46c07f3 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Editor/template-GameInfo.txt.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c6fa1c0456d174d298bf8dd66f584e9e +labels: +- gvh +- gvh_version-0.11.01 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard.meta new file mode 100644 index 0000000..df88b87 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 484e9bbdd408c50d993232965d92e0cb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt new file mode 100644 index 0000000..63c7b08 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt @@ -0,0 +1,20 @@ +-keep class com.google.android.gms.games.leaderboard.** { *; } +-keep class com.google.android.gms.games.snapshot.** { *; } +-keep class com.google.android.gms.games.achievement.** { *; } +-keep class com.google.android.gms.games.event.** { *; } +-keep class com.google.android.gms.games.stats.** { *; } +-keep class com.google.android.gms.games.* { *; } +-keep class com.google.android.gms.common.api.ResultCallback { *; } +-keep class com.google.android.gms.signin.** { *; } +-keep class com.google.android.gms.dynamic.** { *; } +-keep class com.google.android.gms.dynamite.** { *; } +-keep class com.google.android.gms.tasks.** { *; } +-keep class com.google.android.gms.security.** { *; } +-keep class com.google.android.gms.base.** { *; } +-keep class com.google.android.gms.actions.** { *; } +-keep class com.google.games.bridge.** { *; } +-keep class com.google.android.gms.common.ConnectionResult { *; } +-keep class com.google.android.gms.common.GooglePlayServicesUtil { *; } +-keep class com.google.android.gms.common.api.** { *; } +-keep class com.google.android.gms.common.data.DataBufferUtils { *; } +-keep class com.google.android.gms.nearby.** { *; } diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt.meta new file mode 100644 index 0000000..1d27bd3 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Proguard/games.txt.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4176788a1a4cdec9e8100aceecddd212 +labels: +- gvh +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime.meta new file mode 100644 index 0000000..a47f66a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 831a102b513bb304da26f7ca18913f3e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef new file mode 100644 index 0000000..887a518 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef @@ -0,0 +1,7 @@ +{ + "name": "Google.Play.Games", + "includePlatforms": [ + "Android", + "Editor" + ] +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef.meta new file mode 100644 index 0000000..2d75bae --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Google.Play.Games.asmdef.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 1ed07ff861e5f468287b0baef844706d +labels: +- gvh +- gvh_version-0.11.01 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts.meta new file mode 100644 index 0000000..519d189 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ac644c502fda71c8a1a146903d950de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi.meta new file mode 100644 index 0000000..80e1ea0 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 0a565e85253b345878939982a360e0b6 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs new file mode 100644 index 0000000..738e6fb --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs @@ -0,0 +1,201 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + using System; + + /// Data interface for retrieving achievement information. + /// + /// There are 3 states an achievement can be in: + /// + /// Hidden - indicating the name and description of the achievement is + /// not visible to the player. + /// + /// Revealed - indicating the name and description of the achievement is + /// visible to the player. + /// Unlocked - indicating the player has unlocked, or achieved, the achievment. + /// + /// Achievements has two types, standard which is unlocked in one step, + /// and incremental, which require multiple steps to unlock. + /// + /// + public class Achievement + { + static readonly DateTime UnixEpoch = + new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + + private string mId = string.Empty; + private bool mIsIncremental = false; + private bool mIsRevealed = false; + private bool mIsUnlocked = false; + private int mCurrentSteps = 0; + private int mTotalSteps = 0; + private string mDescription = string.Empty; + private string mName = string.Empty; + private long mLastModifiedTime = 0; + private ulong mPoints; + private string mRevealedImageUrl; + private string mUnlockedImageUrl; + + /// + /// Returns a that represents the current . + /// + /// A that represents the current . + public override string ToString() + { + return string.Format( + "[Achievement] id={0}, name={1}, desc={2}, type={3}, revealed={4}, unlocked={5}, steps={6}/{7}", + mId, mName, mDescription, mIsIncremental ? "INCREMENTAL" : "STANDARD", + mIsRevealed, mIsUnlocked, mCurrentSteps, mTotalSteps); + } + + public Achievement() + { + } + + /// + /// Indicates whether this achievement is incremental. + /// + public bool IsIncremental + { + get { return mIsIncremental; } + + set { mIsIncremental = value; } + } + + /// + /// The number of steps the user has gone towards unlocking this achievement. + /// + public int CurrentSteps + { + get { return mCurrentSteps; } + + set { mCurrentSteps = value; } + } + + /// + /// The total number of steps needed to unlock this achievement. + /// + public int TotalSteps + { + get { return mTotalSteps; } + + set { mTotalSteps = value; } + } + + /// + /// Indicates whether the achievement is unlocked or not. + /// + public bool IsUnlocked + { + get { return mIsUnlocked; } + + set { mIsUnlocked = value; } + } + + /// + /// Indicates whether the achievement is revealed or not (hidden). + /// + public bool IsRevealed + { + get { return mIsRevealed; } + + set { mIsRevealed = value; } + } + + /// + /// The ID string of this achievement. + /// + public string Id + { + get { return mId; } + + set { mId = value; } + } + + /// + /// The description of this achievement. + /// + public string Description + { + get { return this.mDescription; } + + set { mDescription = value; } + } + + /// + /// The name of this achievement. + /// + public string Name + { + get { return this.mName; } + + set { mName = value; } + } + + /// + /// The date and time the state of the achievement was modified. + /// + /// + /// The value is invalid (-1 long) if the achievement state has + /// never been updated. + /// + public DateTime LastModifiedTime + { + get { return UnixEpoch.AddMilliseconds(mLastModifiedTime); } + + set + { + TimeSpan ts = value - UnixEpoch; + mLastModifiedTime = (long) ts.TotalMilliseconds; + } + } + + /// + /// The number of experience points earned for unlocking this Achievement. + /// + public ulong Points + { + get { return mPoints; } + + set { mPoints = value; } + } + + /// + /// The URL to the image to display when the achievement is revealed. + /// + public string RevealedImageUrl + { + get { return mRevealedImageUrl; } + + set { mRevealedImageUrl = value; } + } + + /// + /// The URL to the image to display when the achievement is unlocked. + /// + public string UnlockedImageUrl + { + get { return mUnlockedImageUrl; } + + set { mUnlockedImageUrl = value; } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs.meta new file mode 100644 index 0000000..3d3860a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Achievement.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b20fc2fda369044ba962d1d9115c4c63 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs new file mode 100644 index 0000000..a40cc4b --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs @@ -0,0 +1,100 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + /// + /// Common status codes. + /// See https://developers.google.com/android/reference/com/google/android/gms/common/api/CommonStatusCodes + /// + public enum CommonStatusCodes + { + /// The operation was successful, but the device's cache was used. + SuccessCached = -1, + + /// The operation was successful. + Success = 0, + + /// Google Play services is missing on this device. + ServiceMissing = 1, + + /// The installed version of Google Play services is out of date. + ServiceVersionUpdateRequired = 2, + + /// The installed version of Google Play services has been disabled on this device. + ServiceDisabled = 3, + + /// The client attempted to connect to the service but the user is not signed in. + SignInRequired = 4, + + /// The client attempted to connect to the service with an invalid account name specified. + InvalidAccount = 5, + + /// Completing the operation requires some form of resolution. + ResolutionRequired = 6, + + /// A network error occurred. + NetworkError = 7, + + /// An internal error occurred. + InternalError = 8, + + /// The version of the Google Play services installed on this device is not authentic. + ServiceInvalid = 9, + + /// The application is misconfigured. + DeveloperError = 10, + + /// The application is not licensed to the user. + LicenseCheckFailed = 11, + + /// The operation failed with no more detailed information. + Error = 13, + + /// A blocking call was interrupted while waiting and did not run to completion. + Interrupted = 14, + + /// Timed out while awaiting the result. + Timeout = 15, + + /// The result was canceled either due to client disconnect or cancel(). + Canceled = 16, + + /// The client attempted to call a method from an API that failed to connect. + ApiNotConnected = 17, + + /// Invalid credentials were provided. + AuthApiInvalidCredentials = 3000, + + /// Access is forbidden. + AuthApiAccessForbidden = 3001, + + /// Error related to the client. + AuthApiClientError = 3002, + + /// Error related to the server. + AuthApiServerError = 3003, + + /// Error related to token. + AuthTokenError = 3004, + + /// Error related to auth URL resolution. + AuthUrlResolution = 3005 + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs.meta new file mode 100644 index 0000000..2b50788 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonStatusCodes.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: cd54f7a2763f74ce191bdd3efa0a44d5 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs new file mode 100644 index 0000000..e7ae3ce --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs @@ -0,0 +1,205 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi +{ + /// + /// A enum describing where game data can be fetched from. + /// + public enum DataSource + { + /// + /// Allow a read from either a local cache, or the network. + /// + /// Values from the cache may be + /// stale (potentially producing more write conflicts), but reading from cache may still + /// allow reads to succeed if the device does not have internet access and may complete more + /// quickly (as the reads can occur locally rather requiring network roundtrips). + /// + ReadCacheOrNetwork, + + /// + /// Only allow reads from network. + /// + /// This guarantees any returned values were current at the time + /// the read succeeded, but prevents reads from succeeding if the network is unavailable for + /// any reason. + /// + ReadNetworkOnly + } + + /// Native response status codes + /// These values are returned by the native SDK API. + /// NOTE: These values are different than the CommonStatusCodes. + /// + public enum ResponseStatus + { + /// The operation was successful. + Success = 1, + + /// The operation was successful, but the device's cache was used. + SuccessWithStale = 2, + + /// The application is not licensed to the user. + LicenseCheckFailed = -1, + + /// An internal error occurred. + InternalError = -2, + + /// The player is not authorized to perform the operation. + NotAuthorized = -3, + + /// The installed version of Google Play services is out of date. + VersionUpdateRequired = -4, + + /// Timed out while awaiting the result. + Timeout = -5, + + ///< summary> + /// Constant indicating that the developer does not have access to the friends list, but can + /// call the AskForLoadFriendsResolution API to show a consent dialog. + /// + ResolutionRequired = -6, + } + + /// Native response status codes for UI operations. + /// These values are returned by the native SDK API. + /// + public enum UIStatus + { + /// The result is valid. + Valid = 1, + + /// An internal error occurred. + InternalError = -2, + + /// The player is not authorized to perform the operation. + NotAuthorized = -3, + + /// The installed version of Google Play services is out of date. + VersionUpdateRequired = -4, + + /// Timed out while awaiting the result. + Timeout = -5, + + /// UI closed by user. + UserClosedUI = -6, + UiBusy = -12, + + /// An network error occurred. + NetworkError = -20, + } + + /// Values specifying the start location for fetching scores. + public enum LeaderboardStart + { + /// Start fetching scores from the top of the list. + TopScores = 1, + + /// Start fetching relative to the player's score. + PlayerCentered = 2, + } + + /// Values specifying which leaderboard timespan to use. + public enum LeaderboardTimeSpan + { + /// Daily scores. The day resets at 11:59 PM PST. + Daily = 1, + + /// Weekly scores. The week resets at 11:59 PM PST on Sunday. + Weekly = 2, + + /// All time scores. + AllTime = 3, + } + + /// Values specifying which leaderboard collection to use. + public enum LeaderboardCollection + { + /// Public leaderboards contain the scores of players who are sharing their gameplay publicly. + Public = 1, + + /// Social leaderboards contain the scores of players in the viewing player's circles. + Social = 2, + } + + public enum FriendsListVisibilityStatus + { + ///< summary> + /// Constant indicating that currently it's unknown if the friends list is visible to the + /// game, game can ask for permission from user. + /// + Unknown = 0, + + /// Constant indicating that the friends list is currently visible to the game. + Visible = 1, + + ///< summary> + /// Constant indicating that the developer does not have access to the friends list, but can + /// call the AskForLoadFriendsResolution API to show a consent dialog. + /// + ResolutionRequired = 2, + + ///< summary> + /// Constant indicating that the friends list is currently unavailable for this user, and it + /// is not possible to request access at this time, either because the user has permanently + /// declined or the friends feature is not available to them. In this state, any attempts to + /// request + /// access to the friends list will be unsuccessful. + /// + Unavailable = 3, + + /// An network error occurred. + NetworkError = -4, + + /// The player is not authorized to perform the operation. + NotAuthorized = -5, + } + + public enum LoadFriendsStatus + { + /// An unknown value to return when loadFriends is not available. + Unknown = 0, + + /// All the friends have been loaded. + Completed = 1, + + /// There are more friends to load. + LoadMore = 2, + + /// + /// The game doesn't have permission to access the player's friends list. No friends loaded. + /// + ResolutionRequired = -3, + + /// An internal error occurred. + InternalError = -4, + + /// The player is not authorized to perform the operation. + NotAuthorized = -5, + + /// An network error occurred. + NetworkError = -6, + } + + public class CommonTypesUtil + { + public static bool StatusIsSuccess(ResponseStatus status) + { + return ((int) status) > 0; + } + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs.meta new file mode 100644 index 0000000..412ee57 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/CommonTypes.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 1c5d1cb1974d14c0c8b32fcf00089556 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs new file mode 100644 index 0000000..6d2ed77 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs @@ -0,0 +1,298 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + using System; + using GooglePlayGames.OurUtils; + using UnityEngine.SocialPlatforms; + + /// + /// Dummy client used in Editor. + /// + /// Google Play Game Services are not supported in the Editor + /// environment, so this client is used as a placeholder. + /// + public class DummyClient : IPlayGamesClient + { + public void Authenticate(Action callback) + { + LogUsage(); + if (callback != null) + { + callback(SignInStatus.Canceled); + } + } + + public void ManuallyAuthenticate(Action callback) + { + LogUsage(); + if (callback != null) + { + callback(SignInStatus.Canceled); + } + } + + public bool IsAuthenticated() + { + LogUsage(); + return false; + } + + public void RequestServerSideAccess(bool forceRefreshToken, Action callback) + { + LogUsage(); + if (callback != null) + { + callback(null); + } + } + + public string GetUserId() + { + LogUsage(); + return "DummyID"; + } + + public void GetPlayerStats(Action callback) + { + LogUsage(); + callback(CommonStatusCodes.ApiNotConnected, new PlayerStats()); + } + + public string GetUserDisplayName() + { + LogUsage(); + return "Player"; + } + + public string GetUserImageUrl() + { + LogUsage(); + return null; + } + + public void LoadUsers(string[] userIds, Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(null); + } + } + + public void LoadAchievements(Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(null); + } + } + + public void UnlockAchievement(string achId, Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(false); + } + } + + public void RevealAchievement(string achId, Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(false); + } + } + + public void IncrementAchievement(string achId, int steps, Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(false); + } + } + + public void SetStepsAtLeast(string achId, int steps, Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(false); + } + } + + public void ShowAchievementsUI(Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(UIStatus.VersionUpdateRequired); + } + } + + public void AskForLoadFriendsResolution(Action callback) { + LogUsage(); + if (callback != null) { + callback.Invoke(UIStatus.VersionUpdateRequired); + } + } + + public LoadFriendsStatus GetLastLoadFriendsStatus() { + LogUsage(); + return LoadFriendsStatus.Unknown; + } + + public void LoadFriends(int pageSize, bool forceReload, + Action callback) { + LogUsage(); + if (callback != null) { + callback.Invoke(LoadFriendsStatus.Unknown); + } + } + + public void LoadMoreFriends(int pageSize, Action callback) { + LogUsage(); + if (callback != null) { + callback.Invoke(LoadFriendsStatus.Unknown); + } + } + + public void ShowCompareProfileWithAlternativeNameHintsUI(string userId, + string otherPlayerInGameName, + string currentPlayerInGameName, + Action callback) { + LogUsage(); + if (callback != null) { + callback.Invoke(UIStatus.VersionUpdateRequired); + } + } + + public void GetFriendsListVisibility(bool forceReload, + Action callback) { + LogUsage(); + if (callback != null) { + callback.Invoke(FriendsListVisibilityStatus.Unknown); + } + } + + public void ShowLeaderboardUI( + string leaderboardId, + LeaderboardTimeSpan span, + Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(UIStatus.VersionUpdateRequired); + } + } + + public int LeaderboardMaxResults() + { + return 25; + } + + public void LoadScores( + string leaderboardId, + LeaderboardStart start, + int rowCount, + LeaderboardCollection collection, + LeaderboardTimeSpan timeSpan, + Action callback) + { + LogUsage(); + if (callback != null) + { + callback(new LeaderboardScoreData( + leaderboardId, + ResponseStatus.LicenseCheckFailed)); + } + } + + public void LoadMoreScores( + ScorePageToken token, + int rowCount, + Action callback) + { + LogUsage(); + if (callback != null) + { + callback(new LeaderboardScoreData( + token.LeaderboardId, + ResponseStatus.LicenseCheckFailed)); + } + } + + public void SubmitScore(string leaderboardId, long score, Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(false); + } + } + + public void SubmitScore( + string leaderboardId, + long score, + string metadata, + Action callback) + { + LogUsage(); + if (callback != null) + { + callback.Invoke(false); + } + } + + public SavedGame.ISavedGameClient GetSavedGameClient() + { + LogUsage(); + return null; + } + + public GooglePlayGames.BasicApi.Events.IEventsClient GetEventsClient() + { + LogUsage(); + return null; + } + + public void LoadFriends(Action callback) + { + LogUsage(); + callback(false); + } + + public IUserProfile[] GetFriends() + { + LogUsage(); + return new IUserProfile[0]; + } + + private static void LogUsage() + { + Logger.d("Received method call on DummyClient - using stub implementation."); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs.meta new file mode 100644 index 0000000..0d968f6 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/DummyClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2c600182c9892457e92f885549bd838a +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events.meta new file mode 100644 index 0000000..fa1d608 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 672ea858ca3b74efb9d0981849563065 +folderAsset: yes +timeCreated: 1435699548 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs new file mode 100644 index 0000000..4938bce --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs @@ -0,0 +1,53 @@ +namespace GooglePlayGames.BasicApi.Events +{ + internal class Event : IEvent + { + private string mId; + private string mName; + private string mDescription; + private string mImageUrl; + private ulong mCurrentCount; + private EventVisibility mVisibility; + + internal Event(string id, string name, string description, string imageUrl, + ulong currentCount, EventVisibility visibility) + { + mId = id; + mName = name; + mDescription = description; + mImageUrl = imageUrl; + mCurrentCount = currentCount; + mVisibility = visibility; + } + + public string Id + { + get { return mId; } + } + + public string Name + { + get { return mName; } + } + + public string Description + { + get { return mDescription; } + } + + public string ImageUrl + { + get { return mImageUrl; } + } + + public ulong CurrentCount + { + get { return mCurrentCount; } + } + + public EventVisibility Visibility + { + get { return mVisibility; } + } + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs.meta new file mode 100644 index 0000000..e0c92e0 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/Event.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ce7f6801baead4bbda584bb96882e78b +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs new file mode 100644 index 0000000..73d8477 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs @@ -0,0 +1,60 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +namespace GooglePlayGames.BasicApi.Events +{ + public enum EventVisibility + { + Hidden = 1, + Revealed = 2, + } + + /// + /// Data object representing an Event. for more. + /// + public interface IEvent + { + /// + /// The ID of the event. + /// + string Id { get; } + + /// + /// The name of the event. + /// + string Name { get; } + + /// + /// The description of the event. + /// + string Description { get; } + + /// + /// The URL of the image for the event. Empty if there is no image for this event. + /// + /// The image URL. + string ImageUrl { get; } + + /// + /// The current count for this event. + /// + ulong CurrentCount { get; } + + /// + /// The visibility of the event. + /// + EventVisibility Visibility { get; } + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs.meta new file mode 100644 index 0000000..00d4db3 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEvent.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7e4f4f47218d14208a8ae0f676e1bca4 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs new file mode 100644 index 0000000..ccdd55f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs @@ -0,0 +1,60 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#if UNITY_ANDROID +namespace GooglePlayGames.BasicApi.Events +{ + using System; + using System.Collections.Generic; + + /// + /// An interface for interacting with events. + /// + /// See online + /// documentation for Events for more information. + /// + /// All callbacks in this interface must be invoked on the game thread. + /// + public interface IEventsClient + { + /// + /// Fetches all events defined for this game. + /// + /// The source of the event (i.e. whether we can return stale cached + /// values). + /// A callback for the results of the request. The passed list will only + /// be non-empty if the request succeeded. This callback will be invoked on the game thread. + /// + void FetchAllEvents(DataSource source, Action> callback); + + /// + /// Fetchs the event with the specified ID. + /// + /// The source of the event (i.e. whether we can return stale cached + /// values). + /// The ID of the event. + /// A callback for the result of the event. If the request failed, the + /// passed event will be null. This callback will be invoked on the game thread. + void FetchEvent(DataSource source, string eventId, Action callback); + + /// + /// Increments the indicated event. + /// + /// The ID of the event to increment. + /// The number of steps to increment by. + void IncrementEvent(string eventId, uint stepsToIncrement); + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs.meta new file mode 100644 index 0000000..7aecf9c --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Events/IEventsClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: da57ba264ec114c57b8352923847ec34 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs new file mode 100644 index 0000000..e47826d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs @@ -0,0 +1,362 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + using System; + using UnityEngine.SocialPlatforms; + + /// + /// Defines an abstract interface for a Play Games Client. + /// + /// Concrete implementations + /// might be, for example, the client for Android or for iOS. One fundamental concept + /// that implementors of this class must adhere to is stable authentication state. + /// This means that once Authenticate() returns true through its callback, the user is + /// considered to be forever after authenticated while the app is running. The implementation + /// must make sure that this is the case -- for example, it must try to silently + /// re-authenticate the user if authentication is lost or wait for the authentication + /// process to get fixed if it is temporarily in a bad state (such as when the + /// Activity in Android has just been brought to the foreground and the connection to + /// the Games services hasn't yet been established). To the user of this + /// interface, once the user is authenticated, they're forever authenticated. + /// Unless, of course, there is an unusual permanent failure such as the underlying + /// service dying, in which it's acceptable that API method calls will fail. + /// + /// All methods can be called from the game thread. The user of this interface + /// DOES NOT NEED to call them from the UI thread of the game. Transferring to the UI + /// thread when necessary is a responsibility of the implementors of this interface. + /// + /// CALLBACKS: all callbacks must be invoked in Unity's main thread. + /// Implementors of this interface must guarantee that (suggestion: use + /// ). + /// + public interface IPlayGamesClient + { + /// + /// Returns the result of the automatic sign-in attempt. + /// + /// This returns the result + /// + /// Callback + void Authenticate(Action callback); + + /// + /// Manually requests that your game performs sign in with Play Games Services. + /// + /// + /// Note that a sign-in attempt will be made automatically when your game's application + /// started. For this reason most games will not need to manually request to perform sign-in + /// unless the automatic sign-in attempt failed and your game requires access to Play Games + /// Services. + /// + /// + void ManuallyAuthenticate(Action callback); + + /// + /// Returns whether or not user is authenticated. + /// + /// true if the user is authenticated; otherwise, false. + bool IsAuthenticated(); + + /// + /// Requests server-side access to Player Games Services for the currently signed in player. + /// + /// When requested an authorization code is returned that can be used by your game-server to + /// exchange for an access token and conditionally a refresh token (when {@code forceRefreshToken} + /// is true). The access token may then be used by your game-server to access the Play Games + /// Services web APIs. This is commonly used to complete a sign-in flow by verifying the Play Games + /// Services player id. + /// + ///

If {@code forceRefreshToken} is true, when exchanging the authorization code a refresh token + /// will be returned in addition to the access token. The refresh token allows the game-server to + /// request additional access tokens, allowing your game-server to continue accesses Play Games + /// Services while the user is not actively playing your app. + /// + /// + /// + /// If {@code true} when the returned authorization code is exchanged a + /// refresh token will be included in addition to an access token. + /// + void RequestServerSideAccess(bool forceRefreshToken, Action callback); + + ///

+ /// Returns the authenticated user's ID. Note that this value may change if a user signs + /// on and signs in with a different account. + /// + /// The user's ID, null if the user is not logged in. + string GetUserId(); + + /// + /// Loads friends of the authenticated user. This loads the entire list of friends. + /// + /// Callback invoked when complete. bool argument + /// indicates success. + void LoadFriends(Action callback); + + /// + /// Returns a human readable name for the user, if they are logged in. + /// + /// The user's human-readable name. null if they are not logged + /// in + string GetUserDisplayName(); + + /// + /// Returns the user's avatar url, if they are logged in and have an avatar. + /// + /// The URL to load the avatar image. null if they are not logged + /// in + string GetUserImageUrl(); + + /// Gets the player stats. + /// Callback for response. + void GetPlayerStats(Action callback); + + /// + /// Loads the users specified. This is mainly used by the leaderboard + /// APIs to get the information of a high scorer. + /// + /// User identifiers. + /// Callback. + void LoadUsers(string[] userIds, Action callback); + + /// + /// Loads the achievements for the current signed in user and invokes + /// the callback. + /// + void LoadAchievements(Action callback); + + /// + /// Unlocks the achievement with the passed identifier. + /// + /// If the operation succeeds, the callback + /// will be invoked on the game thread with true. If the operation fails, the + /// callback will be invoked with false. This operation will immediately fail if + /// the user is not authenticated (i.e. the callback will immediately be invoked with + /// false). If the achievement is already unlocked, this call will + /// succeed immediately. + /// + /// The ID of the achievement to unlock. + /// Callback used to indicate whether the operation + /// succeeded or failed. + void UnlockAchievement(string achievementId, Action successOrFailureCalllback); + + /// + /// Reveals the achievement with the passed identifier. + /// + /// If the operation succeeds, the callback + /// will be invoked on the game thread with true. If the operation fails, the + /// callback will be invoked with false. This operation will immediately fail if + /// the user is not authenticated (i.e. the callback will immediately be invoked with + /// false). If the achievement is already in a revealed state, this call will + /// succeed immediately. + /// + /// The ID of the achievement to reveal. + /// Callback used to indicate whether the operation + /// succeeded or failed. + void RevealAchievement(string achievementId, Action successOrFailureCalllback); + + /// + /// Increments the achievement with the passed identifier. + /// + /// If the operation succeeds, the + /// callback will be invoked on the game thread with true. If the operation + /// fails, the callback will be invoked with false. This operation will + /// immediately fail if the user is not authenticated (i.e. the callback will immediately be + /// invoked with false). + /// + /// The ID of the achievement to increment. + /// The number of steps to increment by. + /// Callback used to indicate whether the operation + /// succeeded or failed. + void IncrementAchievement(string achievementId, int steps, + Action successOrFailureCalllback); + + /// + /// Set an achievement to have at least the given number of steps completed. + /// + /// + /// Calling this method while the achievement already has more steps than + /// the provided value is a no-op. Once the achievement reaches the + /// maximum number of steps, the achievement is automatically unlocked, + /// and any further mutation operations are ignored. + /// + /// Ach identifier. + /// Steps. + /// Callback. + void SetStepsAtLeast(string achId, int steps, Action callback); + + /// + /// Shows the appropriate platform-specific achievements UI. + /// The callback to invoke when complete. If null, + /// no callback is called. + /// + void ShowAchievementsUI(Action callback); + + /// + /// Shows the appropriate platform-specific friends sharing UI. + /// The callback to invoke when complete. If null, + /// no callback is called. + /// + void AskForLoadFriendsResolution(Action callback); + + /// + /// Returns the latest LoadFriendsStatus obtained from loading friends. + /// + LoadFriendsStatus GetLastLoadFriendsStatus(); + + /// + /// Shows the Play Games Player Profile UI for a specific user identifier. + /// + /// User Identifier. + /// + /// The game's own display name of the player referred to by userId. + /// + /// + /// The game's own display name of the current player. + /// + /// Callback invoked upon completion. + void ShowCompareProfileWithAlternativeNameHintsUI( + string otherUserId, string otherPlayerInGameName, string currentPlayerInGameName, + Action callback); + + /// + /// Returns if the user has allowed permission for the game to access the friends list. + /// + /// If true, this call will clear any locally cached data and + /// attempt to fetch the latest data from the server. Normally, this should be set to {@code + /// false} to gain advantages of data caching. Callback + /// invoked upon completion. + void GetFriendsListVisibility(bool forceReload, Action callback); + + /// + /// Loads the first page of the user's friends + /// + /// + /// The number of entries to request for this initial page. Note that if cached + /// data already exists, the returned buffer may contain more than this size, but it is + /// guaranteed to contain at least this many if the collection contains enough records. + /// + /// + /// If true, this call will clear any locally cached data and attempt to + /// fetch the latest data from the server. This would commonly be used for something like a + /// user-initiated refresh. Normally, this should be set to {@code false} to gain advantages + /// of data caching. + /// Callback invoked upon completion. + void LoadFriends(int pageSize, bool forceReload, Action callback); + + /// + /// Loads the friends list page + /// + /// + /// The number of entries to request for this page. Note that if cached data already + /// exists, the returned buffer may contain more than this size, but it is guaranteed + /// to contain at least this many if the collection contains enough records. + /// + /// + void LoadMoreFriends(int pageSize, Action callback); + + /// + /// Shows the leaderboard UI for a specific leaderboard. + /// + /// If the passed ID is null, all leaderboards are displayed. + /// + /// The leaderboard to display. null to display + /// all. + /// Timespan to display for the leaderboard + /// If non-null, the callback to invoke when the + /// leaderboard is dismissed. + /// + void ShowLeaderboardUI(string leaderboardId, LeaderboardTimeSpan span, + Action callback); + + /// + /// Loads the score data for the given leaderboard. + /// + /// Leaderboard identifier. + /// Start indicating the top scores or player centric + /// max number of scores to return. non-positive indicates + /// no rows should be returned. This causes only the summary info to + /// be loaded. This can be limited + /// by the SDK. + /// leaderboard collection: public or social + /// leaderboard timespan + /// callback with the scores, and a page token. + /// The token can be used to load next/prev pages. + void LoadScores(string leaderboardId, LeaderboardStart start, int rowCount, + LeaderboardCollection collection, LeaderboardTimeSpan timeSpan, + Action callback); + + /// + /// Loads the more scores for the leaderboard. + /// + /// The token is accessed + /// by calling LoadScores() with a positive row count. + /// + /// Token for tracking the score loading. + /// max number of scores to return. + /// This can be limited by the SDK. + /// Callback. + void LoadMoreScores(ScorePageToken token, int rowCount, + Action callback); + + /// + /// Returns the max number of scores returned per call. + /// + /// The max results. + int LeaderboardMaxResults(); + + /// + /// Submits the passed score to the passed leaderboard. + /// + /// This operation will immediately fail + /// if the user is not authenticated (i.e. the callback will immediately be invoked with + /// false). + /// + /// Leaderboard identifier. + /// Score. + /// Callback used to indicate whether the operation + /// succeeded or failed. + void SubmitScore(string leaderboardId, long score, Action successOrFailureCalllback); + + /// + /// Submits the score for the currently signed-in player. + /// + /// Score. + /// leaderboard id. + /// metadata about the score. + /// Callback upon completion. + void SubmitScore(string leaderboardId, long score, string metadata, + Action successOrFailureCalllback); + + /// + /// Gets the saved game client. + /// + /// The saved game client. + SavedGame.ISavedGameClient GetSavedGameClient(); + + /// + /// Gets the events client. + /// + /// The events client. + Events.IEventsClient GetEventsClient(); + + IUserProfile[] GetFriends(); + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs.meta new file mode 100644 index 0000000..21ffabe --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/IPlayGamesClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9138e04e4459148c680055b40ad324c0 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs new file mode 100644 index 0000000..1c80761 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs @@ -0,0 +1,129 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + using System.Collections.Generic; + using UnityEngine.SocialPlatforms; + + /// + /// Leaderboard score data. This is the callback data + /// when loading leaderboard scores. There are several SDK + /// API calls needed to be made to collect all the required data, + /// so this class is used to simplify the response. + /// + public class LeaderboardScoreData + { + private string mId; + private ResponseStatus mStatus; + private ulong mApproxCount; + private string mTitle; + private IScore mPlayerScore; + private ScorePageToken mPrevPage; + private ScorePageToken mNextPage; + private List mScores = new List(); + + internal LeaderboardScoreData(string leaderboardId) + { + mId = leaderboardId; + } + + internal LeaderboardScoreData(string leaderboardId, ResponseStatus status) + { + mId = leaderboardId; + mStatus = status; + } + + public bool Valid + { + get + { + return mStatus == ResponseStatus.Success || + mStatus == ResponseStatus.SuccessWithStale; + } + } + + public ResponseStatus Status + { + get { return mStatus; } + + internal set { mStatus = value; } + } + + public ulong ApproximateCount + { + get { return mApproxCount; } + + internal set { mApproxCount = value; } + } + + public string Title + { + get { return mTitle; } + + internal set { mTitle = value; } + } + + public string Id + { + get { return mId; } + + internal set { mId = value; } + } + + public IScore PlayerScore + { + get { return mPlayerScore; } + + internal set { mPlayerScore = value; } + } + + public IScore[] Scores + { + get { return mScores.ToArray(); } + } + + internal int AddScore(PlayGamesScore score) + { + mScores.Add(score); + return mScores.Count; + } + + public ScorePageToken PrevPageToken + { + get { return mPrevPage; } + + internal set { mPrevPage = value; } + } + + public ScorePageToken NextPageToken + { + get { return mNextPage; } + + internal set { mNextPage = value; } + } + + public override string ToString() + { + return string.Format("[LeaderboardScoreData: mId={0}, " + + " mStatus={1}, mApproxCount={2}, mTitle={3}]", + mId, mStatus, mApproxCount, mTitle); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs.meta new file mode 100644 index 0000000..1fb80aa --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/LeaderboardScoreData.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 8e369c64e8c9f4571a8847f37848c37e +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby.meta new file mode 100644 index 0000000..0286871 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c980790a380df4850b17a208e544d062 +folderAsset: yes +timeCreated: 1435699549 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs new file mode 100644 index 0000000..1220501 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs @@ -0,0 +1,49 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.Nearby +{ + using System; + using System.Collections.Generic; + using GooglePlayGames.OurUtils; + + public struct AdvertisingResult + { + private readonly ResponseStatus mStatus; + private readonly string mLocalEndpointName; + + public AdvertisingResult(ResponseStatus status, string localEndpointName) + { + this.mStatus = status; + this.mLocalEndpointName = Misc.CheckNotNull(localEndpointName); + } + + public bool Succeeded + { + get { return mStatus == ResponseStatus.Success; } + } + + public ResponseStatus Status + { + get { return mStatus; } + } + + public string LocalEndpointName + { + get { return mLocalEndpointName; } + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs.meta new file mode 100644 index 0000000..4d1472e --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/AdvertisingResult.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 941324a6338664af6a9faf5b88cad408 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs new file mode 100644 index 0000000..e7183af --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs @@ -0,0 +1,44 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.Nearby +{ + using GooglePlayGames.OurUtils; + + public struct ConnectionRequest + { + private readonly EndpointDetails mRemoteEndpoint; + private readonly byte[] mPayload; + + public ConnectionRequest(string remoteEndpointId, + string remoteEndpointName, string serviceId, byte[] payload) + { + Logger.d("Constructing ConnectionRequest"); + mRemoteEndpoint = new EndpointDetails(remoteEndpointId, remoteEndpointName, serviceId); + this.mPayload = Misc.CheckNotNull(payload); + } + + public EndpointDetails RemoteEndpoint + { + get { return mRemoteEndpoint; } + } + + public byte[] Payload + { + get { return mPayload; } + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs.meta new file mode 100644 index 0000000..04b0414 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionRequest.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c7f9bb6b249224f99ad05a87d3e4ee34 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs new file mode 100644 index 0000000..4a915ad --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs @@ -0,0 +1,108 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.Nearby +{ + using GooglePlayGames.OurUtils; + + public struct ConnectionResponse + { + private static readonly byte[] EmptyPayload = new byte[0]; + + public enum Status + { + Accepted, + Rejected, + ErrorInternal, + ErrorNetworkNotConnected, + ErrorEndpointNotConnected, + ErrorAlreadyConnected + } + + private readonly long mLocalClientId; + private readonly string mRemoteEndpointId; + private readonly Status mResponseStatus; + private readonly byte[] mPayload; + + private ConnectionResponse(long localClientId, string remoteEndpointId, Status code, + byte[] payload) + { + this.mLocalClientId = localClientId; + this.mRemoteEndpointId = Misc.CheckNotNull(remoteEndpointId); + this.mResponseStatus = code; + this.mPayload = Misc.CheckNotNull(payload); + } + + public long LocalClientId + { + get { return mLocalClientId; } + } + + public string RemoteEndpointId + { + get { return mRemoteEndpointId; } + } + + public Status ResponseStatus + { + get { return mResponseStatus; } + } + + public byte[] Payload + { + get { return mPayload; } + } + + public static ConnectionResponse Rejected(long localClientId, string remoteEndpointId) + { + return new ConnectionResponse(localClientId, remoteEndpointId, Status.Rejected, + EmptyPayload); + } + + public static ConnectionResponse NetworkNotConnected(long localClientId, string remoteEndpointId) + { + return new ConnectionResponse(localClientId, remoteEndpointId, Status.ErrorNetworkNotConnected, + EmptyPayload); + } + + public static ConnectionResponse InternalError(long localClientId, string remoteEndpointId) + { + return new ConnectionResponse(localClientId, remoteEndpointId, Status.ErrorInternal, + EmptyPayload); + } + + public static ConnectionResponse EndpointNotConnected(long localClientId, string remoteEndpointId) + { + return new ConnectionResponse(localClientId, remoteEndpointId, Status.ErrorEndpointNotConnected, + EmptyPayload); + } + + public static ConnectionResponse Accepted(long localClientId, string remoteEndpointId, + byte[] payload) + { + return new ConnectionResponse(localClientId, remoteEndpointId, Status.Accepted, + payload); + } + + public static ConnectionResponse AlreadyConnected(long localClientId, + string remoteEndpointId) + { + return new ConnectionResponse(localClientId, remoteEndpointId, + Status.ErrorAlreadyConnected, + EmptyPayload); + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs.meta new file mode 100644 index 0000000..1f22253 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/ConnectionResponse.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ad6611af8d0204d0d8922a327d3d9ec0 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs new file mode 100644 index 0000000..af90358 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs @@ -0,0 +1,121 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi.Nearby +{ + using UnityEngine; + + public class DummyNearbyConnectionClient : INearbyConnectionClient + { + public int MaxUnreliableMessagePayloadLength() + { + return NearbyConnectionConfiguration.MaxUnreliableMessagePayloadLength; + } + + public int MaxReliableMessagePayloadLength() + { + return NearbyConnectionConfiguration.MaxReliableMessagePayloadLength; + } + + public void SendReliable(System.Collections.Generic.List recipientEndpointIds, byte[] payload) + { + OurUtils.Logger.d("SendReliable called from dummy implementation"); + } + + public void SendUnreliable(System.Collections.Generic.List recipientEndpointIds, byte[] payload) + { + OurUtils.Logger.d("SendUnreliable called from dummy implementation"); + } + + public void StartAdvertising(string name, System.Collections.Generic.List appIdentifiers, + System.TimeSpan? advertisingDuration, System.Action resultCallback, + System.Action connectionRequestCallback) + { + AdvertisingResult obj = new AdvertisingResult(ResponseStatus.LicenseCheckFailed, string.Empty); + resultCallback.Invoke(obj); + } + + public void StopAdvertising() + { + OurUtils.Logger.d("StopAvertising in dummy implementation called"); + } + + public void SendConnectionRequest(string name, string remoteEndpointId, byte[] payload, + System.Action responseCallback, IMessageListener listener) + { + OurUtils.Logger.d("SendConnectionRequest called from dummy implementation"); + + if (responseCallback != null) + { + ConnectionResponse obj = ConnectionResponse.Rejected(0, string.Empty); + responseCallback.Invoke(obj); + } + } + + public void AcceptConnectionRequest(string remoteEndpointId, byte[] payload, IMessageListener listener) + { + OurUtils.Logger.d("AcceptConnectionRequest in dummy implementation called"); + } + + public void StartDiscovery(string serviceId, System.TimeSpan? advertisingTimeout, IDiscoveryListener listener) + { + OurUtils.Logger.d("StartDiscovery in dummy implementation called"); + } + + public void StopDiscovery(string serviceId) + { + OurUtils.Logger.d("StopDiscovery in dummy implementation called"); + } + + public void RejectConnectionRequest(string requestingEndpointId) + { + OurUtils.Logger.d("RejectConnectionRequest in dummy implementation called"); + } + + public void DisconnectFromEndpoint(string remoteEndpointId) + { + OurUtils.Logger.d("DisconnectFromEndpoint in dummy implementation called"); + } + + public void StopAllConnections() + { + OurUtils.Logger.d("StopAllConnections in dummy implementation called"); + } + + public string LocalEndpointId() + { + return string.Empty; + } + + public string LocalDeviceId() + { + return "DummyDevice"; + } + + public string GetAppBundleId() + { + return "dummy.bundle.id"; + } + + public string GetServiceId() + { + return "dummy.service.id"; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs.meta new file mode 100644 index 0000000..cfee748 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/DummyNearbyConnectionClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9b3f34a2bba13428789d02b53fd89a47 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs new file mode 100644 index 0000000..84d5c5d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs @@ -0,0 +1,49 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.Nearby +{ + using GooglePlayGames.OurUtils; + + public struct EndpointDetails + { + private readonly string mEndpointId; + private readonly string mName; + private readonly string mServiceId; + + public EndpointDetails(string endpointId, string name, string serviceId) + { + this.mEndpointId = Misc.CheckNotNull(endpointId); + this.mName = Misc.CheckNotNull(name); + this.mServiceId = Misc.CheckNotNull(serviceId); + } + + public string EndpointId + { + get { return mEndpointId; } + } + + public string Name + { + get { return mName; } + } + + public string ServiceId + { + get { return mServiceId; } + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs.meta new file mode 100644 index 0000000..6dd55d9 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/EndpointDetails.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 9d9a087b0e20d4752b24f33a4a2bf977 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs new file mode 100644 index 0000000..c25e519 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs @@ -0,0 +1,78 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.Nearby +{ + using System; + using System.Collections.Generic; + + // move this inside IMessageListener and IDiscoveryListener are always declared. +#if UNITY_ANDROID + + public interface INearbyConnectionClient + { + int MaxUnreliableMessagePayloadLength(); + + int MaxReliableMessagePayloadLength(); + + void SendReliable(List recipientEndpointIds, byte[] payload); + + void SendUnreliable(List recipientEndpointIds, byte[] payload); + + void StartAdvertising(string name, List appIdentifiers, + TimeSpan? advertisingDuration, Action resultCallback, + Action connectionRequestCallback); + + void StopAdvertising(); + + void SendConnectionRequest(string name, string remoteEndpointId, byte[] payload, + Action responseCallback, IMessageListener listener); + + void AcceptConnectionRequest(string remoteEndpointId, byte[] payload, + IMessageListener listener); + + void StartDiscovery(string serviceId, TimeSpan? advertisingTimeout, + IDiscoveryListener listener); + + void StopDiscovery(string serviceId); + + void RejectConnectionRequest(string requestingEndpointId); + + void DisconnectFromEndpoint(string remoteEndpointId); + + void StopAllConnections(); + + string GetAppBundleId(); + + string GetServiceId(); + } +#endif + + public interface IMessageListener + { + void OnMessageReceived(string remoteEndpointId, byte[] data, + bool isReliableMessage); + + void OnRemoteEndpointDisconnected(string remoteEndpointId); + } + + public interface IDiscoveryListener + { + void OnEndpointFound(EndpointDetails discoveredEndpoint); + + void OnEndpointLost(string lostEndpointId); + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs.meta new file mode 100644 index 0000000..e54bb65 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/INearbyConnectionClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: cb64b5b444dd34de5bd308c7eed6e509 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs new file mode 100644 index 0000000..e789630 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs @@ -0,0 +1,54 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.Nearby +{ + using System; + using GooglePlayGames.OurUtils; + + public enum InitializationStatus + { + Success, + VersionUpdateRequired, + InternalError + } + + public struct NearbyConnectionConfiguration + { + public const int MaxUnreliableMessagePayloadLength = 1168; + public const int MaxReliableMessagePayloadLength = 4096; + + private readonly Action mInitializationCallback; + private readonly long mLocalClientId; + + public NearbyConnectionConfiguration(Action callback, + long localClientId) + { + this.mInitializationCallback = Misc.CheckNotNull(callback); + this.mLocalClientId = localClientId; + } + + public long LocalClientId + { + get { return mLocalClientId; } + } + + public Action InitializationCallback + { + get { return mInitializationCallback; } + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs.meta new file mode 100644 index 0000000..2c54d2d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Nearby/NearbyConnectionConfiguration.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 968ac90e4a9094a4a92df9da1ee1f884 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs new file mode 100644 index 0000000..094645f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs @@ -0,0 +1,33 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#if UNITY_ANDROID +namespace GooglePlayGames.BasicApi +{ + /// + /// Represents a player. A player is different from a participant! The participant is + /// an entity that takes part in a particular match; a Player is a real-world person + /// (tied to a Games account). The player exists across matches, the Participant + /// only exists in the context of a particular match. + /// + public class Player : PlayGamesUserProfile + { + internal Player(string displayName, string playerId, string avatarUrl) + : base(displayName, playerId, avatarUrl) + { + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs.meta new file mode 100644 index 0000000..d338234 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/Player.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: a6dfb529ed3bfc58ea80e1e100af33fd +labels: +- gvh +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs new file mode 100644 index 0000000..fae6b68 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs @@ -0,0 +1,32 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + /// + /// Represents a player, a real-world person (tied to a Games account). + /// + public class PlayerProfile : PlayGamesUserProfile + { + internal PlayerProfile(string displayName, string playerId, string avatarUrl, bool isFriend) : base(displayName, + playerId, avatarUrl, isFriend) + { + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs.meta new file mode 100644 index 0000000..800ecfa --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerProfile.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 12cfec295ecf76a6fb0d0d48f59d374c +labels: +- gvh +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs new file mode 100644 index 0000000..a7e8c5f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs @@ -0,0 +1,268 @@ +// +// Copyright (C) 2015 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + using System; + + /// + /// Player stats. See https://developers.google.com/games/services/android/stats + /// + public class PlayerStats + { + private static float UNSET_VALUE = -1.0f; + + public PlayerStats( + int numberOfPurchases, + float avgSessionLength, + int daysSinceLastPlayed, + int numberOfSessions, + float sessPercentile, + float spendPercentile, + float spendProbability, + float churnProbability, + float highSpenderProbability, + float totalSpendNext28Days) + { + mValid = true; + mNumberOfPurchases = numberOfPurchases; + mAvgSessionLength = avgSessionLength; + mDaysSinceLastPlayed = daysSinceLastPlayed; + mNumberOfSessions = numberOfSessions; + mSessPercentile = sessPercentile; + mSpendPercentile = spendPercentile; + mSpendProbability = spendProbability; + mChurnProbability = churnProbability; + mHighSpenderProbability = highSpenderProbability; + mTotalSpendNext28Days = totalSpendNext28Days; + } + + public PlayerStats() + { + mValid = false; + } + + private bool mValid; + private int mNumberOfPurchases; + private float mAvgSessionLength; + private int mDaysSinceLastPlayed; + private int mNumberOfSessions; + private float mSessPercentile; + private float mSpendPercentile; + private float mSpendProbability; + private float mChurnProbability; + private float mHighSpenderProbability; + private float mTotalSpendNext28Days; + + /// + /// If this PlayerStats object is valid (i.e. successfully retrieved from games services). + /// + /// + /// Note that a PlayerStats with all stats unset may still be valid. + /// + public bool Valid + { + get { return mValid; } + } + + /// + /// The number of in-app purchases. + /// + public int NumberOfPurchases + { + get { return mNumberOfPurchases; } + } + + /// + /// The length of the avg session in minutes. + /// + public float AvgSessionLength + { + get { return mAvgSessionLength; } + } + + /// + /// The days since last played. + /// + public int DaysSinceLastPlayed + { + get { return mDaysSinceLastPlayed; } + } + + /// + /// The number of sessions based on sign-ins. + /// + public int NumberOfSessions + { + get { return mNumberOfSessions; } + } + + /// + /// The approximation of sessions percentile for the player. + /// + /// + /// This value is given as a decimal value between 0 and 1 (inclusive). + /// It indicates how many sessions the current player has + /// played in comparison to the rest of this game's player base. + /// Higher numbers indicate that this player has played more sessions. + /// A return value less than zero indicates this value is not available. + /// + public float SessPercentile + { + get { return mSessPercentile; } + } + + /// + /// The approximate spend percentile of the player. + /// + /// + /// This value is given as a decimal value between 0 and 1 (inclusive). + /// It indicates how much the current player has spent in + /// comparison to the rest of this game's player base. Higher + /// numbers indicate that this player has spent more. + /// A return value less than zero indicates this value is not available. + /// + public float SpendPercentile + { + get { return mSpendPercentile; } + } + + /// + /// The approximate probability of the player choosing to spend in this game. + /// + /// + /// This value is given as a decimal value between 0 and 1 (inclusive). + /// Higher values indicate that a player is more likely to spend. + /// A return value less than zero indicates this value is not available. + /// + public float SpendProbability + { + get { return mSpendProbability; } + } + + /// + /// The approximate probability of the player not returning to play the game. + /// + /// + /// Higher values indicate that a player is less likely to return. + /// A return value less than zero indicates this value is not available. + /// + public float ChurnProbability + { + get { return mChurnProbability; } + } + + /// + /// The high spender probability of this player. + /// + public float HighSpenderProbability + { + get { return mHighSpenderProbability; } + } + + /// + /// The predicted total spend of this player over the next 28 days. + /// + public float TotalSpendNext28Days + { + get { return mTotalSpendNext28Days; } + } + + /// + /// Determines whether this instance has NumberOfPurchases. + /// + /// true if this instance has NumberOfPurchases; otherwise, false. + public bool HasNumberOfPurchases() + { + return NumberOfPurchases != (int) UNSET_VALUE; + } + + /// + /// Determines whether this instance has AvgSessionLength. + /// + /// true if this instance has AvgSessionLength; otherwise, false. + public bool HasAvgSessionLength() + { + return AvgSessionLength != UNSET_VALUE; + } + + /// + /// Determines whether this instance has DaysSinceLastPlayed. + /// + /// true if this instance has DaysSinceLastPlayed; otherwise, false. + public bool HasDaysSinceLastPlayed() + { + return DaysSinceLastPlayed != (int) UNSET_VALUE; + } + + /// + /// Determines whether this instance has NumberOfSessions. + /// + /// true if this instance has NumberOfSessions; otherwise, false. + public bool HasNumberOfSessions() + { + return NumberOfSessions != (int) UNSET_VALUE; + } + + /// + /// Determines whether this instance has SessPercentile. + /// + /// true if this instance has SessPercentile; otherwise, false. + public bool HasSessPercentile() + { + return SessPercentile != UNSET_VALUE; + } + + /// + /// Determines whether this instance has SpendPercentile. + /// + /// true if this instance has SpendPercentile; otherwise, false. + public bool HasSpendPercentile() + { + return SpendPercentile != UNSET_VALUE; + } + + /// + /// Determines whether this instance has ChurnProbability. + /// + /// true if this instance has ChurnProbability; otherwise, false. + public bool HasChurnProbability() + { + return ChurnProbability != UNSET_VALUE; + } + + /// + /// Determines whether this instance has HighSpenderProbability. + /// + /// true if this instance has HighSpenderProbability; otherwise, false. + public bool HasHighSpenderProbability() + { + return HighSpenderProbability != UNSET_VALUE; + } + + /// + /// Determines whether this instance has TotalSpendNext28Days. + /// + /// true if this instance has TotalSpendNext28Days; otherwise, false. + public bool HasTotalSpendNext28Days() + { + return TotalSpendNext28Days != UNSET_VALUE; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs.meta new file mode 100644 index 0000000..f39fae4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/PlayerStats.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0cf73f44d6d524deab1717d6e71e2c6d +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame.meta new file mode 100644 index 0000000..599cdc6 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 1bc47bd5631b849f88f2785c2d44019b +folderAsset: yes +timeCreated: 1435699548 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs new file mode 100644 index 0000000..f7391a6 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs @@ -0,0 +1,373 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.SavedGame +{ + using System; + using System.Collections.Generic; + + /// + /// An enum for the different strategies that can be used to resolve saved game conflicts (i.e. + /// conflicts produced by two or more separate writes to the same saved game at once). + /// + public enum ConflictResolutionStrategy + { + /// + /// Choose which saved game should be used on the basis of which one has the longest recorded + /// play time. In other words, in the case of a conflicting write, the saved game with the + /// longest play time will be considered cannonical. If play time has not been provided by the + /// developer, or in the case of two saved games with equal play times, + /// will be used instead. + /// + UseLongestPlaytime, + + /// + /// Choose the version of the saved game that existed before any conflicting write occurred. + /// Consider the following case: + /// - An initial version of a save game ("X") is written from a device ("Dev_A") + /// - The save game X is downloaded by another device ("Dev_B"). + /// - Dev_A writes a new version of the save game to the cloud ("Y") + /// - Dev_B does not see the new save game Y, and attempts to write a new save game ("Z"). + /// - Since Dev_B is performing a write using out of date information, a conflict is generated. + /// + /// In this situation, we can resolve the conflict by declaring either keeping Y as the + /// canonical version of the saved game (i.e. choose "original" aka ), + /// or by overwriting it with conflicting value, Z (i.e. choose "unmerged" aka + /// ). + /// + /// + UseOriginal, + + /// + /// See the documentation for + /// + UseUnmerged, + + /// + /// Manual resolution, no automatic resolution is attempted. + /// + UseManual, + + /// + /// The use last known good snapshot to resolve conflicts automatically. + /// + UseLastKnownGood, + + /// + /// The use most recently saved snapshot to resolve conflicts automatically. + /// + UseMostRecentlySaved + } + + public enum SavedGameRequestStatus + { + Success = 1, + + /// + /// The request failed due to a timeout. + /// + /// + TimeoutError = -1, + + /// + /// An unexpected internal error. Check the log for error messages. + /// + /// + InternalError = -2, + + /// + /// A error related to authentication. This is probably due to the user being signed out + /// before the request could be issued. + /// + /// + AuthenticationError = -3, + + /// + /// The request failed because it was given bad input (e.g. a filename with 200 characters). + /// + /// + BadInputError = -4 + } + + public enum SelectUIStatus + { + /// + /// The user selected a saved game. + /// + SavedGameSelected = 1, + + /// + /// The user closed the UI without selecting a saved game. + /// + /// + UserClosedUI = 2, + + /// + /// An unexpected internal error. Check the log for error messages. + /// + /// + InternalError = -1, + + /// + /// There was a timeout while displaying the UI. + /// + /// + TimeoutError = -2, + + /// + /// A error related to authentication. This is probably due to the user being signed out + /// before the request could be issued. + /// + /// + AuthenticationError = -3, + + /// + /// The request failed because it was given bad input (e.g. a filename with 200 characters). + /// + /// + BadInputError = -4, + + UiBusy = -5 + } + + /// + /// + /// A delegate that is invoked when we encounter a conflict during execution of + /// . The caller must resolve the + /// conflict using the passed . All passed metadata is open. + /// If was invoked with + /// prefetchDataOnConflict set to true, the and + /// will be equal to the binary data of the "original" and + /// "unmerged" saved game respectively (and null otherwise). Since conflict files may be generated + /// by other clients, it is possible that neither of the passed saved games were originally written + /// by the current device. Consequently, any conflict resolution strategy should not rely on local + /// data that is not part of the binary data of the passed saved games - this data will not be + /// present if conflict resolution occurs on a different device. In addition, since a given saved + /// game may have multiple conflicts, this callback must be designed to handle multiple invocations. + /// + public delegate void ConflictCallback(IConflictResolver resolver, ISavedGameMetadata original, + byte[] originalData, ISavedGameMetadata unmerged, byte[] unmergedData); + + /// + /// The main entry point for interacting with saved games. Saved games are persisted in the cloud + /// along with several game-specific properties ( for more + /// information). There are several core concepts involved with saved games: + /// + /// Filenames - act as unique identifiers for saved games. Two devices + /// performing a read or write using the same filename will end up reading or modifying the same + /// file (i.e. filenames are not device specific). + /// + /// + /// Saved Game Metadata are represented by . + /// The instances allow access to metadata properties about the underlying saved game (e.g. + /// description). In addition, metadata functions as a handle that are required to read and + /// manipulate saved game contents. Lastly, metadata may be "Open". Open metadata instances are + /// required to manipulate the underlying binary data of the saved game. See method comments to + /// determine whether a specific method requires or returns an open saved game. + /// + /// + /// Conflicts occur when multiple devices attempt to write to the same file + /// at the same time. The saved game system guarantees that no conflicting writes will be lost or + /// silently overwritten. Instead, they must be handled the next time the file with a conflict is + /// Opened. Conflicts can be handled automatically ( + /// ) or can be manuallyhandled by the developer + /// (). See the Open methods for more discussion. + /// + /// + /// Saved games will generally be used in the following workflow: + /// + /// Determine which saved game to use (either using a hardcoded filename or + /// ShowSelectSavedGameUI) + /// Open the file using OpenWithManualConflictResolution or + /// OpenWithAutomaticConflictResolution + /// Read the binary data of the saved game using ReadBinaryData handle it + /// as appropriate for your game. + /// When you have updates, persist them in the cloud using CommitUpdate. Note + /// that writing to the cloud is relatively expensive, and shouldn't be done frequently. + /// + /// + /// + /// See online + /// documentation for Saved Games for more information. + /// + public interface ISavedGameClient + { + /// + /// Opens the file with the indicated name and data source. If the file has an outstanding + /// conflict, it will be resolved using the specified conflict resolution strategy. The + /// metadata returned by this method will be "Open" - it can be used as a parameter for + /// and . + /// + /// The name of the file to open. Filenames must consist of + /// only non-URL reserved characters (i.e. a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~") + /// be between 1 and 100 characters in length (inclusive). + /// The data source to use. for a description + /// of the available options here. + /// The conflict resolution that should be used if any + /// conflicts are encountered while opening the file. + /// for a description of these strategies. + /// The callback that is invoked when this operation finishes. The + /// returned metadata will only be non-null if the open succeeded. This callback will always + /// execute on the game thread and the returned metadata (if any) will be "Open". + void OpenWithAutomaticConflictResolution(string filename, DataSource source, + ConflictResolutionStrategy resolutionStrategy, + Action callback); + + /// + /// Opens the file with the indicated name and data source. If there is a conflict that + /// requires resolution, it will be resolved manually using the passed conflict callback. Once + /// all pending conflicts are resolved, the completed callback will be invoked with the + /// retrieved data. In the event of an error, the completed callback will be invoked with the + /// corresponding error status. All callbacks will be executed on the game thread. + /// + /// The name of the file to open. Filenames must consist of + /// only non-URL reserved characters (i.e. a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~") + /// be between 1 and 100 characters in length (inclusive). + /// The data source to use. for a description + /// of the available options here. + /// If set to true, the data for the two + /// conflicting files will be automatically retrieved and passed as parameters in + /// . If set to false, null binary data + /// will be passed into and the caller will have to fetch + /// it themselves. + /// The callback that will be invoked if one or more conflict is + /// encountered while executing this method. Note that more than one conflict may be present + /// and that this callback might be executed more than once to resolve multiple conflicts. + /// This callback is always executed on the game thread. + /// The callback that is invoked when this operation finishes. + /// The returned metadata will only be non-null if the open succeeded. If an error is + /// encountered during conflict resolution, that error will be reflected here. This callback + /// will always execute on the game thread and the returned metadata (if any) will be "Open". + /// + void OpenWithManualConflictResolution(string filename, DataSource source, + bool prefetchDataOnConflict, ConflictCallback conflictCallback, + Action completedCallback); + + /// + /// Reads the binary data of the passed saved game. The passed metadata must be opened (i.e. + /// returns true). The callback will always be executed + /// on the game thread. + /// + /// The metadata for the saved game whose binary data we want to read. + /// This metadata must be open. If it is not open, the method will immediately fail with status + /// . + /// + /// The callback that is invoked when the read finishes. If the + /// read completed without error, the passed status will be and the passed + /// bytes will correspond to the binary data for the file. In the case of + /// + void ReadBinaryData(ISavedGameMetadata metadata, + Action completedCallback); + + /// + /// Shows the select saved game UI with the indicated configuration. If the user selects a + /// saved game in that UI, it will be returned in the passed callback. This metadata will be + /// unopened and must be passed to either or + /// in order to retrieve the binary data. + /// The callback will always be executed on the game thread. + /// + /// The user-visible title of the displayed selection UI. + /// The maximum number of saved games the UI may display. + /// This value must be greater than 0. + /// If set to true, show UI that will allow the user to + /// create a new saved game. + /// If set to true show UI that will allow the user to + /// delete a saved game. + /// The callback that is invoked when an error occurs or if the user + /// finishes interacting with the UI. If the user selected a saved game, this will be passed + /// into the callback along with the status. This saved game + /// will not be Open, and must be opened before it can be written to or its binary data can be + /// read. If the user backs out of the UI without selecting a saved game, this callback will + /// receive and a null saved game. This callback will always execute + /// on the game thread. + void ShowSelectSavedGameUI(string uiTitle, uint maxDisplayedSavedGames, bool showCreateSaveUI, + bool showDeleteSaveUI, Action callback); + + /// + /// Durably commits an update to the passed saved game. When this method returns successfully, + /// the data is durably persisted to disk and will eventually be uploaded to the cloud (in + /// practice, this will happen very quickly unless the device does not have a network + /// connection). If an update to the saved game has occurred after the metadata was retrieved + /// from the cloud, this update will produce a conflict (this commonly occurs if two different + /// devices are writing to the cloud at the same time). All conflicts must be handled the next + /// time this saved game is opened. See and + /// for more information. + /// + /// The metadata for the saved game to update. This metadata must be + /// Open (i.e. returns true)."/> If it is not open, the + /// method will immediately fail with status + /// All updates that should be applied to the saved game + /// metadata. + /// The new binary content of the saved game + /// The callback that is invoked when this operation finishes. + /// The returned metadata will only be non-null if the commit succeeded. If an error is + /// encountered during conflict resolution, that error will be reflected here. This callback + /// will always execute on the game thread and the returned metadata (if any) will NOT be + /// "Open" (i.e. commiting an update closes the metadata). + void CommitUpdate(ISavedGameMetadata metadata, SavedGameMetadataUpdate updateForMetadata, + byte[] updatedBinaryData, Action callback); + + /// + /// Returns the metadata for all known saved games for this game. All returned saved games are + /// not open, and must be opened before they can be used for writes or binary data reads. The + /// callback will always occur on the game thread. + /// + /// The data source to use. for a description + /// of the available options here. + /// The callback that is invoked when this operation finishes. + /// The returned metadata will only be non-empty if the commit succeeded. If an error is + /// encountered during the fetch, that error will be reflected here. This callback + /// will always execute on the game thread and the returned metadata (if any) will NOT be + /// "Open". + void FetchAllSavedGames(DataSource source, + Action> callback); + + /// + /// Delete the specified snapshot. + /// This will delete the data of the snapshot locally and on the server. + /// + /// the saved game metadata identifying the data to + /// delete. + void Delete(ISavedGameMetadata metadata); + } + + /// + /// An interface that allows developers to resolve metadata conflicts that may be encountered while + /// opening saved games. + /// + public interface IConflictResolver + { + /// + /// Resolves the conflict by choosing the passed metadata to be canonical. The passed metadata + /// must be one of the two instances passed as parameters into - + /// this instance will be kept as the cannonical value in the cloud. + /// + /// The chosen metadata. This metadata must be open. If it is not + /// open, the invokation of that produced this + /// ConflictResolver will immediately fail with . + void ChooseMetadata(ISavedGameMetadata chosenMetadata); + + /// + /// Resolves the conflict and updates the data. + /// + /// Metadata for the chosen version. This is either the + /// original or unmerged metadata provided when the callback is invoked. + /// Metadata update, same as when committing changes. + /// Updated data to use when resolving the conflict. + void ResolveConflict(ISavedGameMetadata chosenMetadata, SavedGameMetadataUpdate metadataUpdate, + byte[] updatedData); + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs.meta new file mode 100644 index 0000000..9d9606b --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 5d4ff89980bdd4c9780aa3ceee54a51b +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs new file mode 100644 index 0000000..7b80eac --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs @@ -0,0 +1,77 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.SavedGame +{ + using System; + + /// + /// Interface representing the metadata for a saved game. These instances are also used as handles + /// for reading and writing the content of the underlying file. + /// + public interface ISavedGameMetadata + { + /// + /// Returns true if this metadata can be used for operations related to raw file data (i.e. + /// the binary data contained in the underlying file). Metadata returned by Open operations + /// will be "Open". After an update to the file is committed or the metadata is used to resolve + /// a conflict, the corresponding Metadata is closed, and IsOpen will return false. + /// + /// + /// true if this instance is open; otherwise, false. + bool IsOpen { get; } + + /// + /// Returns the filename for this saved game. A saved game filename will only consist of + /// non-URL reserved characters (i.e. a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~") + /// and will between 1 and 100 characters in length (inclusive). + /// + /// The filename. + string Filename { get; } + + /// + /// Returns a human-readable description of what the saved game contains. This may be null. + /// + /// The description. + string Description { get; } + + /// + /// A URL corresponding to the PNG-encoded image corresponding to this saved game. null if + /// the saved game does not have a cover image. + /// + /// The cover image URL. + string CoverImageURL { get; } + + /// + /// Returns the total time played by the player for this saved game. This value is + /// developer-specified and may be tracked in any way that is appropriate to the game. Note + /// that this value is specific to this specific saved game (unless the developer intentionally + /// sets the same value on all saved games). If the value was not set, this will be equal to + /// TimeSpan.FromMilliseconds(0) + /// + /// The total time played. + TimeSpan TotalTimePlayed { get; } + + /// + /// A timestamp corresponding to the last modification to the underlying saved game. If the + /// saved game is newly created, this value will correspond to the time the first Open + /// occurred. Otherwise, this corresponds to time the last successful write occurred (either by + /// CommitUpdate or Resolve methods). + /// + /// The last modified timestamp. + DateTime LastModifiedTimestamp { get; } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs.meta new file mode 100644 index 0000000..1c141d2 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/ISavedGameMetadata.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a94650f478358403ea166d374b2a950c +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs new file mode 100644 index 0000000..7d84a84 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs @@ -0,0 +1,115 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.BasicApi.SavedGame +{ + using System; + using GooglePlayGames.OurUtils; + + /// + /// A struct representing the mutation of saved game metadata. Fields can either have a new value + /// or be untouched (in which case the corresponding field in the saved game metadata will be + /// untouched). Instances must be built using + /// and once created, these instances are immutable and threadsafe. + /// + public struct SavedGameMetadataUpdate + { + private readonly bool mDescriptionUpdated; + private readonly string mNewDescription; + private readonly bool mCoverImageUpdated; + private readonly byte[] mNewPngCoverImage; + private readonly TimeSpan? mNewPlayedTime; + + private SavedGameMetadataUpdate(Builder builder) + { + mDescriptionUpdated = builder.mDescriptionUpdated; + mNewDescription = builder.mNewDescription; + mCoverImageUpdated = builder.mCoverImageUpdated; + mNewPngCoverImage = builder.mNewPngCoverImage; + mNewPlayedTime = builder.mNewPlayedTime; + } + + public bool IsDescriptionUpdated + { + get { return mDescriptionUpdated; } + } + + public string UpdatedDescription + { + get { return mNewDescription; } + } + + public bool IsCoverImageUpdated + { + get { return mCoverImageUpdated; } + } + + public byte[] UpdatedPngCoverImage + { + get { return mNewPngCoverImage; } + } + + public bool IsPlayedTimeUpdated + { + get { return mNewPlayedTime.HasValue; } + } + + public TimeSpan? UpdatedPlayedTime + { + get { return mNewPlayedTime; } + } + + public struct Builder + { + internal bool mDescriptionUpdated; + internal string mNewDescription; + internal bool mCoverImageUpdated; + internal byte[] mNewPngCoverImage; + internal TimeSpan? mNewPlayedTime; + + public Builder WithUpdatedDescription(string description) + { + mNewDescription = Misc.CheckNotNull(description); + mDescriptionUpdated = true; + return this; + } + + public Builder WithUpdatedPngCoverImage(byte[] newPngCoverImage) + { + mCoverImageUpdated = true; + mNewPngCoverImage = newPngCoverImage; + return this; + } + + public Builder WithUpdatedPlayedTime(TimeSpan newPlayedTime) + { + if (newPlayedTime.TotalMilliseconds > ulong.MaxValue) + { + throw new InvalidOperationException("Timespans longer than ulong.MaxValue " + + "milliseconds are not allowed"); + } + + mNewPlayedTime = newPlayedTime; + return this; + } + + public SavedGameMetadataUpdate Build() + { + return new SavedGameMetadataUpdate(this); + } + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs.meta new file mode 100644 index 0000000..631b9b5 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SavedGame/SavedGameMetadataUpdate.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 602d9e1c90f0144e79536115f3614478 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs new file mode 100644 index 0000000..b4ab076 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs @@ -0,0 +1,78 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames.BasicApi +{ + public enum ScorePageDirection + { + Forward = 1, + Backward = 2, + } + + /// + /// Score page token. This holds the internal token used + /// to page through the score pages. The id, collection, and + /// timespan are added as a convience, and not actually part of the + /// page token returned from the SDK. + /// + public class ScorePageToken + { + private string mId; + private object mInternalObject; + private LeaderboardCollection mCollection; + private LeaderboardTimeSpan mTimespan; + private ScorePageDirection mDirection; + + internal ScorePageToken(object internalObject, string id, + LeaderboardCollection collection, LeaderboardTimeSpan timespan, + ScorePageDirection direction) + { + mInternalObject = internalObject; + mId = id; + mCollection = collection; + mTimespan = timespan; + mDirection = direction; + } + + public LeaderboardCollection Collection + { + get { return mCollection; } + } + + public LeaderboardTimeSpan TimeSpan + { + get { return mTimespan; } + } + + public ScorePageDirection Direction + { + get { return mDirection; } + } + + public string LeaderboardId + { + get { return mId; } + } + + internal object InternalObject + { + get { return mInternalObject; } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs.meta new file mode 100644 index 0000000..9f270dd --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/ScorePageToken.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 3eade9d49f3e341ddb2ba8209e7ddf42 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs new file mode 100644 index 0000000..d6d48e2 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs @@ -0,0 +1,26 @@ +namespace GooglePlayGames.BasicApi +{ + public enum SignInInteractivity + { + /// no UIs will be shown (if UIs are needed, it will fail rather than show them). + NoPrompt, + + /// + /// This may show UIs, consent dialogs, etc. + /// At the end of the process, callback will be invoked to notify of the result. + /// Once the callback returns true, the user is considered to be authenticated. + /// + CanPromptAlways, + + /// When this is selected, PlayGamesPlatform.Authenticate does the followings in order: + /// 1. Attempt to silent sign in. + /// 2. If silent sign in fails, check if user has previously declined to sign in and don’t prompt interactive + /// sign in if they have. + /// 3. Check the internet connection and fail with NO_INTERNET_CONNECTION if there is no internet connection. + /// 4. Prompt interactive sign in. + /// 5. If the interactive sign in is not successful (user declines or cancels), then + /// remember this for step 2 the next time the user opens the game and don’t ask for sign-in. + /// + CanPromptOnce + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs.meta new file mode 100644 index 0000000..c0a5467 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInInteractivity.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: f5c7733064f2b09dc8df0009b3bbb1d6 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs new file mode 100644 index 0000000..159f49b --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs @@ -0,0 +1,14 @@ +namespace GooglePlayGames.BasicApi +{ + public enum SignInStatus + { + /// The operation was successful. + Success, + + /// An internal error occurred. + InternalError, + + /// The sign in was canceled. + Canceled, + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs.meta new file mode 100644 index 0000000..ab20fbf --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/BasicApi/SignInStatus.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 0992bc2597d741e59dc3f8c963a3ca25 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs new file mode 100644 index 0000000..f9e238f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs @@ -0,0 +1,71 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#if UNITY_ANDROID + +namespace GooglePlayGames { + /// + /// This file is automatically generated DO NOT EDIT! + /// + /// These are the constants defined in the Play Games Console for Game Services + /// Resources. + /// + /// + /// File containing information about the game. This is automatically updated by running the + /// platform-appropriate setup commands in the Unity editor (which does a simple search / replace + /// on the IDs in the form "__ID__"). We can check whether any particular field has been updated + /// by checking whether it still retains its initial value - we prevent the constants from being + /// replaced in the aforementioned search/replace by stripping off the leading and trailing "__". + /// + public static class GameInfo { + + private const string UnescapedApplicationId = "APP_ID"; + private const string UnescapedIosClientId = "IOS_CLIENTID"; + private const string UnescapedWebClientId = "WEB_CLIENTID"; + private const string UnescapedNearbyServiceId = "NEARBY_SERVICE_ID"; + + public const string ApplicationId = "1045293753265"; // Filled in automatically + public const string IosClientId = "__IOS_CLIENTID__"; // Filled in automatically + public const string WebClientId = "1045293753265-ejh4ifdimiqfqhj2msj2c3h7oib9r7aq.apps.googleusercontent.com"; // Filled in automatically + public const string NearbyConnectionServiceId = ""; + + public static bool ApplicationIdInitialized() { + return !string.IsNullOrEmpty(ApplicationId) && !ApplicationId.Equals(ToEscapedToken(UnescapedApplicationId)); + } + + public static bool IosClientIdInitialized() { + return !string.IsNullOrEmpty(IosClientId) && !IosClientId.Equals(ToEscapedToken(UnescapedIosClientId)); + } + + public static bool WebClientIdInitialized() { + return !string.IsNullOrEmpty(WebClientId) && !WebClientId.Equals(ToEscapedToken(UnescapedWebClientId)); + } + + public static bool NearbyConnectionsInitialized() { + return !string.IsNullOrEmpty(NearbyConnectionServiceId) && + !NearbyConnectionServiceId.Equals(ToEscapedToken(UnescapedNearbyServiceId)); + } + + /// + /// Returns an escaped token (i.e. one flanked with "__") for the passed token + /// + /// The escaped token. + /// The Token + private static string ToEscapedToken(string token) { + return string.Format("__{0}__", token); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs.meta new file mode 100644 index 0000000..c814181 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/GameInfo.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a722d413080904cc1bd07f4db21e1af1 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform.meta new file mode 100644 index 0000000..b7673b5 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: ef66268ee929544fb82bbef6ac13bafe +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs new file mode 100644 index 0000000..278535d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs @@ -0,0 +1,286 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using System; + using GooglePlayGames.BasicApi; + using UnityEngine; +#if UNITY_2017_1_OR_NEWER + using UnityEngine.Networking; +#endif + using UnityEngine.SocialPlatforms; + + internal delegate void ReportProgress(string id, double progress, Action callback); + + /// + /// Represents a Google Play Games achievement. It can be used to report an achievement + /// to the API, offering identical functionality as . + /// + internal class PlayGamesAchievement : IAchievement, IAchievementDescription + { + private readonly ReportProgress mProgressCallback; + private string mId = string.Empty; + private bool mIsIncremental = false; + private int mCurrentSteps = 0; + private int mTotalSteps = 0; + private double mPercentComplete = 0.0; + private bool mCompleted = false; + private bool mHidden = false; + private DateTime mLastModifiedTime = new DateTime(1970, 1, 1, 0, 0, 0, 0); + private string mTitle = string.Empty; + private string mRevealedImageUrl = string.Empty; + private string mUnlockedImageUrl = string.Empty; +#if UNITY_2017_1_OR_NEWER + private UnityWebRequest mImageFetcher = null; +#else + private WWW mImageFetcher = null; +#endif + private Texture2D mImage = null; + private string mDescription = string.Empty; + private ulong mPoints = 0; + + internal PlayGamesAchievement() + : this(PlayGamesPlatform.Instance.ReportProgress) + { + } + + internal PlayGamesAchievement(ReportProgress progressCallback) + { + mProgressCallback = progressCallback; + } + + internal PlayGamesAchievement(Achievement ach) : this() + { + this.mId = ach.Id; + this.mIsIncremental = ach.IsIncremental; + this.mCurrentSteps = ach.CurrentSteps; + this.mTotalSteps = ach.TotalSteps; + if (ach.IsIncremental) + { + if (ach.TotalSteps > 0) + { + this.mPercentComplete = + ((double) ach.CurrentSteps / (double) ach.TotalSteps) * 100.0; + } + else + { + this.mPercentComplete = 0.0; + } + } + else + { + this.mPercentComplete = ach.IsUnlocked ? 100.0 : 0.0; + } + + this.mCompleted = ach.IsUnlocked; + this.mHidden = !ach.IsRevealed; + this.mLastModifiedTime = ach.LastModifiedTime; + this.mTitle = ach.Name; + this.mDescription = ach.Description; + this.mPoints = ach.Points; + this.mRevealedImageUrl = ach.RevealedImageUrl; + this.mUnlockedImageUrl = ach.UnlockedImageUrl; + } + + /// + /// Reveals, unlocks or increment achievement. + /// + /// + /// Call after setting , , + /// as well as and + /// for incremental achievements. Equivalent to calling + /// . + /// + public void ReportProgress(Action callback) + { + mProgressCallback.Invoke(mId, mPercentComplete, callback); + } + + /// + /// Loads the local user's image from the url. Loading urls + /// is asynchronous so the return from this call is fast, + /// the image is returned once it is loaded. null is returned + /// up to that point. + /// + private Texture2D LoadImage() + { + if (hidden) + { + // return null, we dont have images for hidden achievements. + return null; + } + + string url = completed ? mUnlockedImageUrl : mRevealedImageUrl; + + // the url can be null if the image is not configured. + if (!string.IsNullOrEmpty(url)) + { + if (mImageFetcher == null || mImageFetcher.url != url) + { +#if UNITY_2017_1_OR_NEWER + mImageFetcher = UnityWebRequestTexture.GetTexture(url); +#else + mImageFetcher = new WWW(url); +#endif + mImage = null; + } + + // if we have the texture, just return, this avoids excessive + // memory usage calling www.texture repeatedly. + if (mImage != null) + { + return mImage; + } + + if (mImageFetcher.isDone) + { +#if UNITY_2017_1_OR_NEWER + mImage = DownloadHandlerTexture.GetContent(mImageFetcher); +#else + mImage = mImageFetcher.texture; +#endif + return mImage; + } + } + + // if there is no url, always return null. + return null; + } + + + /// + /// Gets or sets the id of this achievement. + /// + /// + /// The identifier. + /// + public string id + { + get { return mId; } + + set { mId = value; } + } + + /// + /// Gets a value indicating whether this achievement is incremental. + /// + /// + /// This value is only set by PlayGamesPlatform.LoadAchievements + /// + /// true if incremental; otherwise, false. + public bool isIncremental + { + get { return mIsIncremental; } + } + + /// + /// Gets the current steps completed of this achievement. + /// + /// + /// Undefined for standard (i.e. non-incremental) achievements. + /// This value is only set by PlayGamesPlatform.LoadAchievements, changing the + /// percentComplete will not affect this. + /// + /// The current steps. + public int currentSteps + { + get { return mCurrentSteps; } + } + + /// + /// Gets the total steps of this achievement. + /// + /// + /// Undefined for standard (i.e. non-incremental) achievements. + /// This value is only set by PlayGamesPlatform.LoadAchievements, changing the + /// percentComplete will not affect this. + /// + /// The total steps. + public int totalSteps + { + get { return mTotalSteps; } + } + + /// + /// Gets or sets the percent completed. + /// + /// + /// The percent completed. + /// + public double percentCompleted + { + get { return mPercentComplete; } + + set { mPercentComplete = value; } + } + + /// + /// Gets a value indicating whether this achievement is completed. + /// + /// + /// This value is only set by PlayGamesPlatform.LoadAchievements, changing the + /// percentComplete will not affect this. + /// + /// true if completed; otherwise, false. + public bool completed + { + get { return this.mCompleted; } + } + + /// + /// Gets a value indicating whether this achievement is hidden. + /// + /// true if hidden; otherwise, false. + public bool hidden + { + get { return this.mHidden; } + } + + public DateTime lastReportedDate + { + get { return mLastModifiedTime; } + } + + public String title + { + get { return mTitle; } + } + + public Texture2D image + { + get { return LoadImage(); } + } + + public string achievedDescription + { + get { return mDescription; } + } + + public string unachievedDescription + { + get { return mDescription; } + } + + public int points + { + get { return (int) mPoints; } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs.meta new file mode 100644 index 0000000..f9ae214 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesAchievement.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: e5354c32a5dc64372ba5102f7f787adf +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs new file mode 100644 index 0000000..7659217 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs @@ -0,0 +1,180 @@ +// +// Copyright (C) 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using System.Collections.Generic; + using GooglePlayGames.BasicApi; + using UnityEngine; + using UnityEngine.SocialPlatforms; + + public class PlayGamesLeaderboard : ILeaderboard + { + private string mId; + private UserScope mUserScope; + private Range mRange; + private TimeScope mTimeScope; + private string[] mFilteredUserIds; + private bool mLoading; + + private IScore mLocalUserScore; + private uint mMaxRange; + private List mScoreList = new List(); + private string mTitle; + + public PlayGamesLeaderboard(string id) + { + mId = id; + } + + #region ILeaderboard implementation + + public void SetUserFilter(string[] userIDs) + { + mFilteredUserIds = userIDs; + } + + public void LoadScores(System.Action callback) + { + PlayGamesPlatform.Instance.LoadScores(this, callback); + } + + public bool loading + { + get { return mLoading; } + internal set { mLoading = value; } + } + + public string id + { + get { return mId; } + set { mId = value; } + } + + public UserScope userScope + { + get { return mUserScope; } + set { mUserScope = value; } + } + + public Range range + { + get { return mRange; } + set { mRange = value; } + } + + public TimeScope timeScope + { + get { return mTimeScope; } + set { mTimeScope = value; } + } + + public IScore localUserScore + { + get { return mLocalUserScore; } + } + + public uint maxRange + { + get { return mMaxRange; } + } + + public IScore[] scores + { + get + { + PlayGamesScore[] arr = new PlayGamesScore[mScoreList.Count]; + mScoreList.CopyTo(arr); + return arr; + } + } + + public string title + { + get { return mTitle; } + } + + #endregion + + internal bool SetFromData(LeaderboardScoreData data) + { + if (data.Valid) + { + OurUtils.Logger.d("Setting leaderboard from: " + data); + SetMaxRange(data.ApproximateCount); + SetTitle(data.Title); + SetLocalUserScore((PlayGamesScore) data.PlayerScore); + foreach (IScore score in data.Scores) + { + AddScore((PlayGamesScore) score); + } + + mLoading = data.Scores.Length == 0 || HasAllScores(); + } + + return data.Valid; + } + + internal void SetMaxRange(ulong val) + { + mMaxRange = (uint) val; + } + + internal void SetTitle(string value) + { + mTitle = value; + } + + internal void SetLocalUserScore(PlayGamesScore score) + { + mLocalUserScore = score; + } + + internal int AddScore(PlayGamesScore score) + { + if (mFilteredUserIds == null || mFilteredUserIds.Length == 0) + { + mScoreList.Add(score); + } + else + { + foreach (string fid in mFilteredUserIds) + { + if (fid.Equals(score.userID)) + { + mScoreList.Add(score); + break; + } + } + } + + return mScoreList.Count; + } + + public int ScoreCount + { + get { return mScoreList.Count; } + } + + internal bool HasAllScores() + { + return mScoreList.Count >= mRange.count || mScoreList.Count >= maxRange; + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs.meta new file mode 100644 index 0000000..4d18c03 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLeaderboard.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a027e4767bd0f41509b9ef6bd2f6080e +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs new file mode 100644 index 0000000..1a76760 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs @@ -0,0 +1,207 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using System; + using GooglePlayGames.BasicApi; + using UnityEngine.SocialPlatforms; + + /// + /// Represents the Google Play Games local user. + /// + public class PlayGamesLocalUser : PlayGamesUserProfile, ILocalUser + { + internal PlayGamesPlatform mPlatform; + + private PlayerStats mStats; + + internal PlayGamesLocalUser(PlayGamesPlatform plaf) + : base("localUser", string.Empty, string.Empty) + { + mPlatform = plaf; + mStats = null; + } + + /// + /// Authenticates the local user. Equivalent to calling + /// . + /// + public void Authenticate(Action callback) + { + mPlatform.Authenticate(status => callback(status == SignInStatus.Success)); + } + + /// + /// Authenticates the local user. Equivalent to calling + /// . + /// + public void Authenticate(Action callback) + { + mPlatform.Authenticate(status => callback(status == SignInStatus.Success, status.ToString())); + } + + /// + /// Loads all friends of the authenticated user. + /// + public void LoadFriends(Action callback) + { + mPlatform.LoadFriends(this, callback); + } + + /// + /// Synchronous version of friends, returns null until loaded. + /// + public IUserProfile[] friends + { + get { return mPlatform.GetFriends(); } + } + + /// + /// Returns whether or not the local user is authenticated to Google Play Games. + /// + /// + /// true if authenticated; otherwise, false. + /// + public bool authenticated + { + get { return mPlatform.IsAuthenticated(); } + } + + /// + /// Not implemented. As safety placeholder, returns true. + /// + public bool underage + { + get { return true; } + } + + /// + /// Gets the display name of the user. + /// + /// + /// The display name of the user. + /// + public new string userName + { + get + { + string retval = string.Empty; + if (authenticated) + { + retval = mPlatform.GetUserDisplayName(); + if (!base.userName.Equals(retval)) + { + ResetIdentity(retval, mPlatform.GetUserId(), mPlatform.GetUserImageUrl()); + } + } + + return retval; + } + } + + /// + /// Gets the user's Google id. + /// + /// This id is persistent and uniquely identifies the user + /// across all games that use Google Play Game Services. It is + /// the preferred method of uniquely identifying a player instead + /// of email address. + /// + /// + /// The user's Google id. + /// + public new string id + { + get + { + string retval = string.Empty; + if (authenticated) + { + retval = mPlatform.GetUserId(); + if (!base.id.Equals(retval)) + { + ResetIdentity(mPlatform.GetUserDisplayName(), retval, mPlatform.GetUserImageUrl()); + } + } + + return retval; + } + } + + + /// + /// Returns true (since this is the local user). + /// + public new bool isFriend + { + get { return true; } + } + + /// + /// Gets the local user's state. This is always UserState.Online for + /// the local user. + /// + public new UserState state + { + get { return UserState.Online; } + } + + + public new string AvatarURL + { + get + { + string retval = string.Empty; + if (authenticated) + { + retval = mPlatform.GetUserImageUrl(); + if (!base.id.Equals(retval)) + { + ResetIdentity(mPlatform.GetUserDisplayName(), + mPlatform.GetUserId(), retval); + } + } + + return retval; + } + } + + /// + /// Gets the player's stats. + /// + /// Callback when they are available. + public void GetStats(Action callback) + { + if (mStats == null || !mStats.Valid) + { + mPlatform.GetPlayerStats((rc, stats) => + { + mStats = stats; + callback(rc, stats); + }); + } + else + { + // 0 = success + callback(CommonStatusCodes.Success, mStats); + } + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs.meta new file mode 100644 index 0000000..26e6de2 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesLocalUser.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 3b5f03fe051cb4a41a3b5489bd63c24c +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs new file mode 100644 index 0000000..3e519f1 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs @@ -0,0 +1,1358 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using System; + using System.Collections.Generic; + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.Events; + using GooglePlayGames.BasicApi.Nearby; + using GooglePlayGames.BasicApi.SavedGame; + using GooglePlayGames.OurUtils; + using UnityEngine; + using UnityEngine.SocialPlatforms; + + /// + /// Provides access to the Google Play Games platform. This is an implementation of + /// UnityEngine.SocialPlatforms.ISocialPlatform. Activate this platform by calling + /// the method, then authenticate by calling + /// the method. After authentication + /// completes, you may call the other methods of this class. This is not a complete + /// implementation of the ISocialPlatform interface. Methods lacking an implementation + /// or whose behavior is at variance with the standard are noted as such. + /// + public class PlayGamesPlatform : ISocialPlatform + { + /// Singleton instance + private static volatile PlayGamesPlatform sInstance = null; + + /// status of nearby connection initialization. + private static volatile bool sNearbyInitializePending; + + /// Reference to the nearby client. + /// This is static since it can be used without using play game services. + private static volatile INearbyConnectionClient sNearbyConnectionClient; + + /// The local user. + private PlayGamesLocalUser mLocalUser = null; + + /// Reference to the platform specific implementation. + private IPlayGamesClient mClient = null; + + /// the default leaderboard we show on ShowLeaderboardUI + private string mDefaultLbUi = null; + + /// the mapping table from alias to leaderboard/achievement id. + private Dictionary mIdMap = new Dictionary(); + + /// + /// Initializes a new instance of the class. + /// + /// Implementation client to use for this instance. + internal PlayGamesPlatform(IPlayGamesClient client) + { + this.mClient = Misc.CheckNotNull(client); + this.mLocalUser = new PlayGamesLocalUser(this); + } + + /// + /// Initializes a new instance of the class. + /// + private PlayGamesPlatform() + { + GooglePlayGames.OurUtils.Logger.d("Creating new PlayGamesPlatform"); + this.mLocalUser = new PlayGamesLocalUser(this); + } + + /// + /// Gets or sets a value indicating whether debug logs are enabled. This property + /// may be set before calling method. + /// + /// + /// true if debug log enabled; otherwise, false. + /// + public static bool DebugLogEnabled + { + get { return GooglePlayGames.OurUtils.Logger.DebugLogEnabled; } + + set { GooglePlayGames.OurUtils.Logger.DebugLogEnabled = value; } + } + + /// + /// Gets the singleton instance of the Play Games platform. + /// + /// + /// The instance. + /// + public static PlayGamesPlatform Instance + { + get + { + if (sInstance == null) + { + OurUtils.Logger.d("Initializing the PlayGamesPlatform instance."); + sInstance = + new PlayGamesPlatform(PlayGamesClientFactory.GetPlatformPlayGamesClient()); + } + + return sInstance; + } + } + + /// + /// Gets the nearby connection client. NOTE: Can be null until the nearby client + /// is initialized. Call InitializeNearby to use callback to be notified when initialization + /// is complete. + /// + /// The nearby. + public static INearbyConnectionClient Nearby + { + get + { + if (sNearbyConnectionClient == null && !sNearbyInitializePending) + { + sNearbyInitializePending = true; + InitializeNearby(null); + } + + return sNearbyConnectionClient; + } + } + + /// Gets the saved game client object. + /// The saved game client. + public ISavedGameClient SavedGame + { + get { return mClient.GetSavedGameClient(); } + } + + /// Gets the events client object. + /// The events client. + public IEventsClient Events + { + get { return mClient.GetEventsClient(); } + } + + /// + /// Gets the local user. + /// + /// + /// The local user. + /// + public ILocalUser localUser + { + get { return mLocalUser; } + } + + /// + /// Initializes the nearby connection platform. + /// + /// This call initializes the nearby connection platform. This + /// is independent of the Play Game Services initialization. Multiple + /// calls to this method are ignored. + /// + /// Callback invoked when complete. + public static void InitializeNearby(Action callback) + { + OurUtils.Logger.d("Calling InitializeNearby!"); + if (sNearbyConnectionClient == null) + { +#if UNITY_ANDROID && !UNITY_EDITOR + NearbyConnectionClientFactory.Create(client => { + OurUtils.Logger.d("Nearby Client Created!!"); + sNearbyConnectionClient = client; + if (callback != null) { + callback.Invoke(client); + } + else { + OurUtils.Logger.d("Initialize Nearby callback is null"); + } + }); +#else + sNearbyConnectionClient = new DummyNearbyConnectionClient(); + if (callback != null) + { + callback.Invoke(sNearbyConnectionClient); + } + +#endif + } + else if (callback != null) + { + OurUtils.Logger.d("Nearby Already initialized: calling callback directly"); + callback.Invoke(sNearbyConnectionClient); + } + else + { + OurUtils.Logger.d("Nearby Already initialized"); + } + } + + /// + /// Activates the Play Games platform as the implementation of Social.Active. + /// After calling this method, you can call methods on Social.Active. For + /// example, Social.Active.Authenticate(). + /// + /// The singleton instance. + public static PlayGamesPlatform Activate() + { + GooglePlayGames.OurUtils.Logger.d("Activating PlayGamesPlatform."); + + Social.Active = PlayGamesPlatform.Instance; + GooglePlayGames.OurUtils.Logger.d( + "PlayGamesPlatform activated: " + Social.Active); + return PlayGamesPlatform.Instance; + } + + /// + /// Specifies that the ID fromId should be implicitly replaced by toId + /// on any calls that take a leaderboard or achievement ID. + /// + /// After a mapping is + /// registered, you can use fromId instead of toId when making a call. + /// For example, the following two snippets are equivalent: + /// + /// ReportProgress("Cfiwjew894_AQ", 100.0, callback); + /// + /// ...is equivalent to: + /// + /// AddIdMapping("super-combo", "Cfiwjew894_AQ"); + /// ReportProgress("super-combo", 100.0, callback); + /// + /// + /// + /// The identifier to map. + /// + /// + /// The identifier that fromId will be mapped to. + /// + public void AddIdMapping(string fromId, string toId) + { + mIdMap[fromId] = toId; + } + + /// + /// Returns the result of the automatic sign-in attempt. Play Games SDK automatically + /// prompts users to sign in when the game is started. This API is useful for understanding + /// if your game has access to Play Games Services and should be used when your game is + /// started in order to conditionally enable or disable your Play Games Services + /// integration. + /// + /// The callback to call when authentication finishes. + public void Authenticate(Action callback) + { + mClient.Authenticate(callback); + } + + /// + /// Provided for compatibility with ISocialPlatform. + /// + /// + /// Unused parameter for this implementation. + /// Callback invoked when complete. + public void Authenticate(ILocalUser unused, Action callback) + { + Authenticate(status => callback(status == SignInStatus.Success)); + } + + /// + /// Provided for compatibility with ISocialPlatform. + /// + /// + /// Unused parameter for this implementation. + /// Callback invoked when complete. + public void Authenticate(ILocalUser unused, Action callback) + { + Authenticate(status => callback(status == SignInStatus.Success, status.ToString())); + } + + /// + /// Manually requests that your game performs sign in with Play Games Services. + /// + /// + /// Note that a sign-in attempt will be made automatically when your game's application + /// started. For this reason most games will not need to manually request to perform sign-in + /// unless the automatic sign-in attempt failed and your game requires access to Play Games + /// Services. + /// + /// + public void ManuallyAuthenticate(Action callback) { + mClient.ManuallyAuthenticate(callback); + } + + /// + /// Determines whether the user is authenticated. + /// + /// + /// true if the user is authenticated; otherwise, false. + /// + public bool IsAuthenticated() + { + return mClient != null && mClient.IsAuthenticated(); + } + + /// + /// Requests server-side access to Player Games Services for the currently signed in player. + /// + /// When requested an authorization code is returned that can be used by your game-server to + /// exchange for an access token and conditionally a refresh token (when {@code + /// forceRefreshToken} is true). The access token may then be used by your game-server to + /// access the Play Games Services web APIs. This is commonly used to complete a sign-in flow + /// by verifying the Play Games Services player id. + /// + ///

If {@code forceRefreshToken} is true, when exchanging the authorization code a refresh + /// token will be returned in addition to the access token. The refresh token allows the + /// game-server to request additional access tokens, allowing your game-server to continue + /// accesses Play Games Services while the user is not actively playing your app. + /// + /// + /// If {@code true} when the returned authorization code is + /// exchanged a refresh token will be included in addition to an access token. + public void RequestServerSideAccess(bool forceRefreshToken, Action callback) + { + Misc.CheckNotNull(callback); + + if (!IsAuthenticated()) + { + OurUtils.Logger.e("RequestServerSideAccess() can only be called after authentication."); + InvokeCallbackOnGameThread(callback, null); + return; + } + + mClient.RequestServerSideAccess(forceRefreshToken, callback); + } + + ///

+ /// Loads the users. + /// + /// User identifiers. + /// Callback invoked when complete. + public void LoadUsers(string[] userIds, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "GetUserId() can only be called after authentication."); + callback(new IUserProfile[0]); + + return; + } + + mClient.LoadUsers(userIds, callback); + } + + /// + /// Returns the user's Google ID. + /// + /// + /// The user's Google ID. No guarantees are made as to the meaning or format of + /// this identifier except that it is unique to the user who is signed in. + /// + public string GetUserId() + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "GetUserId() can only be called after authentication."); + return "0"; + } + + return mClient.GetUserId(); + } + + /// + /// Gets the player stats. + /// + /// Callback invoked when completed. + public void GetPlayerStats(Action callback) + { + if (mClient != null && mClient.IsAuthenticated()) + { + mClient.GetPlayerStats(callback); + } + else + { + GooglePlayGames.OurUtils.Logger.e( + "GetPlayerStats can only be called after authentication."); + + callback(CommonStatusCodes.SignInRequired, new PlayerStats()); + } + } + + /// + /// Returns the user's display name. + /// + /// + /// The user display name (e.g. "Bruno Oliveira") + /// + public string GetUserDisplayName() + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "GetUserDisplayName can only be called after authentication."); + return string.Empty; + } + + return mClient.GetUserDisplayName(); + } + + /// + /// Returns the user's avatar URL if they have one. + /// + /// + /// The URL, or null if the user is not authenticated or does not have + /// an avatar. + /// + public string GetUserImageUrl() + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "GetUserImageUrl can only be called after authentication."); + return null; + } + + return mClient.GetUserImageUrl(); + } + + /// + /// Reports the progress of an achievement (reveal, unlock or increment). This method attempts + /// to implement the expected behavior of ISocialPlatform.ReportProgress as closely as possible, + /// as described below. Although this method works with incremental achievements for compatibility + /// purposes, calling this method for incremental achievements is not recommended, + /// since the Play Games API exposes incremental achievements in a very different way + /// than the interface presented by ISocialPlatform.ReportProgress. The implementation of this + /// method for incremental achievements attempts to produce the correct result, but may be + /// imprecise. If possible, call instead. + /// + /// + /// The ID of the achievement to unlock, reveal or increment. This can be a raw Google Play + /// Games achievement ID (alphanumeric string), or an alias that was previously configured + /// by a call to . + /// + /// + /// Progress of the achievement. If the achievement is standard (not incremental), then + /// a progress of 0.0 will reveal the achievement and 100.0 will unlock it. Behavior of other + /// values is undefined. If the achievement is incremental, then this value is interpreted + /// as the total percentage of the achievement's progress that the player should have + /// as a result of this call (regardless of the progress they had before). So if the + /// player's previous progress was 30% and this call specifies 50.0, the new progress will + /// be 50% (not 80%). + /// + /// + /// Callback that will be called to report the result of the operation: true on + /// success, false otherwise. + /// + public void ReportProgress(string achievementID, double progress, Action callback) + { + callback = ToOnGameThread(callback); + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "ReportProgress can only be called after authentication."); + callback.Invoke(false); + + return; + } + + // map ID, if it's in the dictionary + GooglePlayGames.OurUtils.Logger.d("ReportProgress, " + achievementID + ", " + progress); + achievementID = MapId(achievementID); + + // if progress is 0.0, we just want to reveal it + if (progress < 0.000001) + { + GooglePlayGames.OurUtils.Logger.d( + "Progress 0.00 interpreted as request to reveal."); + mClient.RevealAchievement(achievementID, callback); + return; + } + + mClient.LoadAchievements(ach => + { + for (int i = 0; i < ach.Length; i++) + { + if (ach[i].Id == achievementID) + { + if (ach[i].IsIncremental) + { + GooglePlayGames.OurUtils.Logger.d("Progress " + progress + + " interpreted as incremental target (approximate)."); + + if (progress >= 0.0 && progress <= 1.0) + { + // in a previous version, incremental progress was reported by using the range [0-1] + GooglePlayGames.OurUtils.Logger.w( + "Progress " + progress + + " is less than or equal to 1. You might be trying to use values in the range of [0,1], while values are expected to be within the range [0,100]. If you are using the latter, you can safely ignore this message."); + } + + mClient.SetStepsAtLeast(achievementID, progressToSteps(progress, ach[i].TotalSteps), callback); + } + else + { + if (progress >= 100) + { + // unlock it! + GooglePlayGames.OurUtils.Logger.d("Progress " + progress + " interpreted as UNLOCK."); + mClient.UnlockAchievement(achievementID, callback); + } + else + { + // not enough to unlock + GooglePlayGames.OurUtils.Logger.d( + "Progress " + progress + " not enough to unlock non-incremental achievement."); + callback.Invoke(false); + } + } + + return; + } + } + + // Achievement not found + GooglePlayGames.OurUtils.Logger.e("Unable to locate achievement " + achievementID); + callback.Invoke(false); + }); + } + + internal static int progressToSteps(double progress, int totalSteps) { + return (progress >= 100.0) ? totalSteps : (int) (progress * totalSteps / 100.0); + } + + /// + /// Reveals the achievement with the passed identifier. This is a Play Games extension of the ISocialPlatform API. + /// + /// If the operation succeeds, the callback + /// will be invoked on the game thread with true. If the operation fails, the + /// callback will be invoked with false. This operation will immediately fail if + /// the user is not authenticated (i.e. the callback will immediately be invoked with + /// false). If the achievement is already in a revealed state, this call will + /// succeed immediately. + /// + /// + /// The ID of the achievement to increment. This can be a raw Google Play + /// Games achievement ID (alphanumeric string), or an alias that was previously configured + /// by a call to . + /// + /// + /// The callback to call to report the success or failure of the operation. The callback + /// will be called with true to indicate success or false for failure. + /// + public void RevealAchievement(string achievementID, Action callback = null) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "RevealAchievement can only be called after authentication."); + if (callback != null) + { + callback.Invoke(false); + } + + return; + } + + // map ID, if it's in the dictionary + GooglePlayGames.OurUtils.Logger.d( + "RevealAchievement: " + achievementID); + achievementID = MapId(achievementID); + mClient.RevealAchievement(achievementID, callback); + } + + /// + /// Unlocks the achievement with the passed identifier. This is a Play Games extension of the ISocialPlatform API. + /// + /// If the operation succeeds, the callback + /// will be invoked on the game thread with true. If the operation fails, the + /// callback will be invoked with false. This operation will immediately fail if + /// the user is not authenticated (i.e. the callback will immediately be invoked with + /// false). If the achievement is already unlocked, this call will + /// succeed immediately. + /// + /// + /// The ID of the achievement to increment. This can be a raw Google Play + /// Games achievement ID (alphanumeric string), or an alias that was previously configured + /// by a call to . + /// + /// + /// The callback to call to report the success or failure of the operation. The callback + /// will be called with true to indicate success or false for failure. + /// + public void UnlockAchievement(string achievementID, Action callback = null) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "UnlockAchievement can only be called after authentication."); + if (callback != null) + { + callback.Invoke(false); + } + + return; + } + + // map ID, if it's in the dictionary + GooglePlayGames.OurUtils.Logger.d( + "UnlockAchievement: " + achievementID); + achievementID = MapId(achievementID); + mClient.UnlockAchievement(achievementID, callback); + } + + /// + /// Increments an achievement. This is a Play Games extension of the ISocialPlatform API. + /// + /// + /// The ID of the achievement to increment. This can be a raw Google Play + /// Games achievement ID (alphanumeric string), or an alias that was previously configured + /// by a call to . + /// + /// + /// The number of steps to increment the achievement by. + /// + /// + /// The callback to call to report the success or failure of the operation. The callback + /// will be called with true to indicate success or false for failure. + /// + public void IncrementAchievement(string achievementID, int steps, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "IncrementAchievement can only be called after authentication."); + if (callback != null) + { + callback.Invoke(false); + } + + return; + } + + // map ID, if it's in the dictionary + GooglePlayGames.OurUtils.Logger.d( + "IncrementAchievement: " + achievementID + ", steps " + steps); + achievementID = MapId(achievementID); + mClient.IncrementAchievement(achievementID, steps, callback); + } + + /// + /// Set an achievement to have at least the given number of steps completed. + /// Calling this method while the achievement already has more steps than + /// the provided value is a no-op. Once the achievement reaches the + /// maximum number of steps, the achievement is automatically unlocked, + /// and any further mutation operations are ignored. + /// + /// + /// The ID of the achievement to increment. This can be a raw Google Play + /// Games achievement ID (alphanumeric string), or an alias that was previously configured + /// by a call to . + /// + /// + /// The number of steps to increment the achievement by. + /// + /// + /// The callback to call to report the success or failure of the operation. The callback + /// will be called with true to indicate success or false for failure. + /// + public void SetStepsAtLeast(string achievementID, int steps, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "SetStepsAtLeast can only be called after authentication."); + if (callback != null) + { + callback.Invoke(false); + } + + return; + } + + // map ID, if it's in the dictionary + GooglePlayGames.OurUtils.Logger.d( + "SetStepsAtLeast: " + achievementID + ", steps " + steps); + achievementID = MapId(achievementID); + mClient.SetStepsAtLeast(achievementID, steps, callback); + } + + /// + /// Loads the Achievement descriptions. + /// + /// The callback to receive the descriptions + public void LoadAchievementDescriptions(Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "LoadAchievementDescriptions can only be called after authentication."); + if (callback != null) + { + callback.Invoke(null); + } + + return; + } + + mClient.LoadAchievements(ach => + { + IAchievementDescription[] data = new IAchievementDescription[ach.Length]; + for (int i = 0; i < data.Length; i++) + { + data[i] = new PlayGamesAchievement(ach[i]); + } + + callback.Invoke(data); + }); + } + + /// + /// Loads the achievement state for the current user. + /// + /// The callback to receive the achievements + public void LoadAchievements(Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("LoadAchievements can only be called after authentication."); + callback.Invoke(null); + + return; + } + + mClient.LoadAchievements(ach => + { + IAchievement[] data = new IAchievement[ach.Length]; + for (int i = 0; i < data.Length; i++) + { + data[i] = new PlayGamesAchievement(ach[i]); + } + + callback.Invoke(data); + }); + } + + /// + /// Creates an achievement object which may be subsequently used to report an + /// achievement. + /// + /// + /// The achievement object. + /// + public IAchievement CreateAchievement() + { + return new PlayGamesAchievement(); + } + + /// + /// Reports a score to a leaderboard. + /// + /// + /// The score to report. + /// + /// + /// The ID of the leaderboard on which the score is to be posted. This may be a raw + /// Google Play Games leaderboard ID or an alias configured through a call to + /// . + /// + /// + /// The callback to call to report the success or failure of the operation. The callback + /// will be called with true to indicate success or false for failure. + /// + public void ReportScore(long score, string board, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("ReportScore can only be called after authentication."); + if (callback != null) + { + callback.Invoke(false); + } + + return; + } + + GooglePlayGames.OurUtils.Logger.d("ReportScore: score=" + score + ", board=" + board); + string leaderboardId = MapId(board); + mClient.SubmitScore(leaderboardId, score, callback); + } + + /// + /// Submits the score for the currently signed-in player + /// to the leaderboard associated with a specific id + /// and metadata (such as something the player did to earn the score). + /// + /// Score to report. + /// leaderboard id. + /// metadata about the score. + /// Callback invoked upon completion. + public void ReportScore(long score, string board, string metadata, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("ReportScore can only be called after authentication."); + if (callback != null) + { + callback.Invoke(false); + } + + return; + } + + GooglePlayGames.OurUtils.Logger.d("ReportScore: score=" + score + + ", board=" + board + + " metadata=" + metadata); + string leaderboardId = MapId(board); + mClient.SubmitScore(leaderboardId, score, metadata, callback); + } + + /// + /// Loads the scores relative the player. + /// + /// This returns the 25 + /// (which is the max results returned by the SDK per call) scores + /// that are around the player's score on the Public, all time leaderboard. + /// Use the overloaded methods which are specific to GPGS to modify these + /// parameters. + /// + /// Leaderboard Id + /// Callback to invoke when completed. + public void LoadScores(string leaderboardId, Action callback) + { + LoadScores( + leaderboardId, + LeaderboardStart.PlayerCentered, + mClient.LeaderboardMaxResults(), + LeaderboardCollection.Public, + LeaderboardTimeSpan.AllTime, + (scoreData) => callback(scoreData.Scores)); + } + + /// + /// Loads the scores using the provided parameters. This call may fail when trying to load friends with + /// ResponseCode.ResolutionRequired if the user has not share the friends list with the game. In this case, use + /// AskForLoadFriendsResolution to request access. + /// + /// Leaderboard identifier. + /// Start either top scores, or player centered. + /// Row count. the number of rows to return. + /// Collection. social or public + /// Time span. daily, weekly, all-time + /// Callback to invoke when completed. + public void LoadScores( + string leaderboardId, + LeaderboardStart start, + int rowCount, + LeaderboardCollection collection, + LeaderboardTimeSpan timeSpan, + Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("LoadScores can only be called after authentication."); + callback(new LeaderboardScoreData( + leaderboardId, + ResponseStatus.NotAuthorized)); + return; + } + + mClient.LoadScores( + leaderboardId, + start, + rowCount, + collection, + timeSpan, + callback); + } + + /// + /// Loads more scores. This call may fail when trying to load friends with + /// ResponseCode.ResolutionRequired if the user has not share the friends list with the game. In this case, use + /// AskForLoadFriendsResolution to request access. + /// + /// This is used to load the next "page" of scores. + /// Token used to recording the loading. + /// Row count. + /// Callback invoked when complete. + public void LoadMoreScores( + ScorePageToken token, + int rowCount, + Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("LoadMoreScores can only be called after authentication."); + callback( + new LeaderboardScoreData( + token.LeaderboardId, + ResponseStatus.NotAuthorized)); + return; + } + + mClient.LoadMoreScores(token, rowCount, callback); + } + + /// + /// Returns a leaderboard object that can be configured to + /// load scores. + /// + /// The leaderboard object. + public ILeaderboard CreateLeaderboard() + { + return new PlayGamesLeaderboard(mDefaultLbUi); + } + + /// + /// Shows the standard Google Play Games achievements user interface, + /// which allows the player to browse their achievements. + /// + public void ShowAchievementsUI() + { + ShowAchievementsUI(null); + } + + /// + /// Shows the standard Google Play Games achievements user interface, + /// which allows the player to browse their achievements. + /// + /// If non-null, the callback is invoked when + /// the achievement UI is dismissed + public void ShowAchievementsUI(Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("ShowAchievementsUI can only be called after authentication."); + return; + } + + GooglePlayGames.OurUtils.Logger.d("ShowAchievementsUI callback is " + callback); + mClient.ShowAchievementsUI(callback); + } + + /// + /// Shows the standard Google Play Games leaderboards user interface, + /// which allows the player to browse their leaderboards. If you have + /// configured a specific leaderboard as the default through a call to + /// , the UI will show that + /// specific leaderboard only. Otherwise, a list of all the leaderboards + /// will be shown. + /// + public void ShowLeaderboardUI() + { + GooglePlayGames.OurUtils.Logger.d("ShowLeaderboardUI with default ID"); + ShowLeaderboardUI(MapId(mDefaultLbUi), null); + } + + /// + /// Shows the standard Google Play Games leaderboard UI for the given + /// leaderboard. + /// + /// + /// The ID of the leaderboard to display. This may be a raw + /// Google Play Games leaderboard ID or an alias configured through a call to + /// . + /// + public void ShowLeaderboardUI(string leaderboardId) + { + if (leaderboardId != null) + { + leaderboardId = MapId(leaderboardId); + } + + ShowLeaderboardUI(leaderboardId, LeaderboardTimeSpan.AllTime, null); + } + + /// + /// Shows the leaderboard UI and calls the specified callback upon + /// completion. + /// + /// leaderboard ID, can be null meaning all leaderboards. + /// Callback to call. If null, nothing is called. + public void ShowLeaderboardUI(string leaderboardId, Action callback) + { + ShowLeaderboardUI(leaderboardId, LeaderboardTimeSpan.AllTime, callback); + } + + /// + /// Shows the leaderboard UI and calls the specified callback upon + /// completion. + /// + /// leaderboard ID, can be null meaning all leaderboards. + /// Timespan to display scores in the leaderboard. + /// Callback to call. If null, nothing is called. + public void ShowLeaderboardUI( + string leaderboardId, + LeaderboardTimeSpan span, + Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("ShowLeaderboardUI can only be called after authentication."); + if (callback != null) + { + callback(UIStatus.NotAuthorized); + } + + return; + } + + GooglePlayGames.OurUtils.Logger.d("ShowLeaderboardUI, lbId=" + + leaderboardId + " callback is " + callback); + mClient.ShowLeaderboardUI(leaderboardId, span, callback); + } + + /// + /// Sets the default leaderboard for the leaderboard UI. After calling this + /// method, a call to will show only the specified + /// leaderboard instead of showing the list of all leaderboards. + /// + /// + /// The ID of the leaderboard to display on the default UI. This may be a raw + /// Google Play Games leaderboard ID or an alias configured through a call to + /// . + /// + public void SetDefaultLeaderboardForUI(string lbid) + { + GooglePlayGames.OurUtils.Logger.d("SetDefaultLeaderboardForUI: " + lbid); + if (lbid != null) + { + lbid = MapId(lbid); + } + + mDefaultLbUi = lbid; + } + + /// + /// Loads the friends that also play this game. See loadConnectedPlayers. + /// + /// This is a callback variant of LoadFriends. When completed, + /// the friends list set in the user object, so they can accessed via the + /// friends property as needed. + /// + /// The current local user + /// Callback invoked when complete. + public void LoadFriends(ILocalUser user, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "LoadScores can only be called after authentication."); + if (callback != null) + { + callback(false); + } + + return; + } + + mClient.LoadFriends(callback); + } + + /// + /// Loads the leaderboard based on the constraints in the leaderboard + /// object. + /// + /// The leaderboard object. This is created by + /// calling CreateLeaderboard(), and then initialized appropriately. + /// Callback invoked when complete. + public void LoadScores(ILeaderboard board, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e("LoadScores can only be called after authentication."); + if (callback != null) + { + callback(false); + } + + return; + } + + LeaderboardTimeSpan timeSpan; + switch (board.timeScope) + { + case TimeScope.AllTime: + timeSpan = LeaderboardTimeSpan.AllTime; + break; + case TimeScope.Week: + timeSpan = LeaderboardTimeSpan.Weekly; + break; + case TimeScope.Today: + timeSpan = LeaderboardTimeSpan.Daily; + break; + default: + timeSpan = LeaderboardTimeSpan.AllTime; + break; + } + + ((PlayGamesLeaderboard) board).loading = true; + GooglePlayGames.OurUtils.Logger.d("LoadScores, board=" + board + + " callback is " + callback); + mClient.LoadScores( + board.id, + LeaderboardStart.PlayerCentered, + board.range.count > 0 ? board.range.count : mClient.LeaderboardMaxResults(), + board.userScope == UserScope.FriendsOnly ? LeaderboardCollection.Social : LeaderboardCollection.Public, + timeSpan, + (scoreData) => HandleLoadingScores( + (PlayGamesLeaderboard) board, scoreData, callback)); + } + + /// + /// Check if the leaderboard is currently loading. + /// + /// true, if loading was gotten, false otherwise. + /// The leaderboard to check for loading in progress + public bool GetLoading(ILeaderboard board) + { + return board != null && board.loading; + } + + /// + /// Shows the Player Profile UI for the given user identifier. + /// + /// User Identifier. + /// + /// The game's own display name of the player referred to by userId. + /// + /// + /// The game's own display name of the current player. + /// + /// Callback invoked upon completion. + public void ShowCompareProfileWithAlternativeNameHintsUI(string userId, + string otherPlayerInGameName, + string currentPlayerInGameName, + Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "ShowCompareProfileWithAlternativeNameHintsUI can only be called after authentication."); + InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized); + + return; + } + + GooglePlayGames.OurUtils.Logger.d( + "ShowCompareProfileWithAlternativeNameHintsUI, userId=" + userId + " callback is " + + callback); + mClient.ShowCompareProfileWithAlternativeNameHintsUI(userId, otherPlayerInGameName, + currentPlayerInGameName, callback); + } + + /// + /// Returns if the user has allowed permission for the game to access the friends list. + /// + /// If true, this call will clear any locally cached data and + /// attempt to fetch the latest data from the server. Normally, this should be set to {@code + /// false} to gain advantages of data caching. + /// Callback invoked upon completion. + public void GetFriendsListVisibility(bool forceReload, + Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "GetFriendsListVisibility can only be called after authentication."); + InvokeCallbackOnGameThread(callback, FriendsListVisibilityStatus.NotAuthorized); + return; + } + + GooglePlayGames.OurUtils.Logger.d("GetFriendsListVisibility, callback is " + callback); + mClient.GetFriendsListVisibility(forceReload, callback); + } + + /// + /// Shows the appropriate platform-specific friends sharing UI. + /// The callback to invoke when complete. If null, + /// no callback is called. + /// + public void AskForLoadFriendsResolution(Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "AskForLoadFriendsResolution can only be called after authentication."); + InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized); + return; + } + + GooglePlayGames.OurUtils.Logger.d("AskForLoadFriendsResolution callback is " + callback); + mClient.AskForLoadFriendsResolution(callback); + } + + /// + /// Gets status of the last call to load friends. + /// + public LoadFriendsStatus GetLastLoadFriendsStatus() + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "GetLastLoadFriendsStatus can only be called after authentication."); + return LoadFriendsStatus.NotAuthorized; + } + + return mClient.GetLastLoadFriendsStatus(); + } + + /// + /// Loads the first page of the user's friends + /// + /// + /// The number of entries to request for this initial page. Note that if cached + /// data already exists, the returned buffer may contain more than this size, but it is + /// guaranteed to contain at least this many if the collection contains enough records. + /// + /// + /// If true, this call will clear any locally cached data and attempt to + /// fetch the latest data from the server. This would commonly be used for something like a + /// user-initiated refresh. Normally, this should be set to {@code false} to gain advantages + /// of data caching. Callback invoked upon + /// completion. + public void LoadFriends(int pageSize, bool forceReload, + Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "LoadFriends can only be called after authentication."); + InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NotAuthorized); + return; + } + + mClient.LoadFriends(pageSize, forceReload, callback); + } + + /// + /// Loads the friends list page + /// + /// + /// The number of entries to request for this initial page. Note that if cached + /// data already exists, the returned buffer may contain more than this size, but it is + /// guaranteed to contain at least this many if the collection contains enough records. + /// + /// + public void LoadMoreFriends(int pageSize, Action callback) + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.e( + "LoadMoreFriends can only be called after authentication."); + InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NotAuthorized); + return; + } + + mClient.LoadMoreFriends(pageSize, callback); + } + + /// + /// Handles the processing of scores during loading. + /// + /// leaderboard being loaded + /// Score data. + /// Callback invoked when complete. + internal void HandleLoadingScores( + PlayGamesLeaderboard board, + LeaderboardScoreData scoreData, + Action callback) + { + bool ok = board.SetFromData(scoreData); + if (ok && !board.HasAllScores() && scoreData.NextPageToken != null) + { + int rowCount = board.range.count - board.ScoreCount; + + // need to load more scores + mClient.LoadMoreScores( + scoreData.NextPageToken, + rowCount, + (nextScoreData) => + HandleLoadingScores(board, nextScoreData, callback)); + } + else + { + callback(ok); + } + } + + /// + /// Internal implmentation of getFriends.Gets the friends. + /// + /// The friends. + internal IUserProfile[] GetFriends() + { + if (!IsAuthenticated()) + { + GooglePlayGames.OurUtils.Logger.d("Cannot get friends when not authenticated!"); + return new IUserProfile[0]; + } + + return mClient.GetFriends(); + } + + /// + /// Maps the alias to the identifier. + /// + /// This maps an aliased ID to the actual id. The intent of + /// this method is to allow easy to read constants to be used instead of + /// the generated ids. + /// + /// The identifier, or null if not found. + /// Alias to map + private string MapId(string id) + { + if (id == null) + { + return null; + } + + if (mIdMap.ContainsKey(id)) + { + string result = mIdMap[id]; + GooglePlayGames.OurUtils.Logger.d("Mapping alias " + id + " to ID " + result); + return result; + } + + return id; + } + + private static void InvokeCallbackOnGameThread(Action callback, T data) + { + if (callback == null) + { + return; + } + + PlayGamesHelperObject.RunOnGameThread(() => { callback(data); }); + } + + private static Action ToOnGameThread(Action toConvert) + { + if (toConvert == null) + { + return delegate { }; + } + + return (val) => PlayGamesHelperObject.RunOnGameThread(() => toConvert(val)); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs.meta new file mode 100644 index 0000000..b448e45 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesPlatform.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c1de7754a6e7f4fb08b76780a184b3ca +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs new file mode 100644 index 0000000..d44dfba --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs @@ -0,0 +1,126 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using System; + using UnityEngine.SocialPlatforms; + + /// + /// Represents a Google Play Games score that can be sent to a leaderboard. + /// + public class PlayGamesScore : IScore + { + private string mLbId = null; + private long mValue = 0; + private ulong mRank = 0; + private string mPlayerId = string.Empty; + private string mMetadata = string.Empty; + + private DateTime mDate = new DateTime(1970, 1, 1, 0, 0, 0); + + internal PlayGamesScore(DateTime date, string leaderboardId, + ulong rank, string playerId, ulong value, string metadata) + { + this.mDate = date; + mLbId = leaderboardID; + this.mRank = rank; + this.mPlayerId = playerId; + this.mValue = (long) value; + this.mMetadata = metadata; + } + + /// + /// Reports the score. Equivalent to . + /// + public void ReportScore(Action callback) + { + PlayGamesPlatform.Instance.ReportScore(mValue, mLbId, mMetadata, callback); + } + + /// + /// Gets or sets the leaderboard id. + /// + /// + /// The leaderboard id. + /// + public string leaderboardID + { + get { return mLbId; } + + set { mLbId = value; } + } + + /// + /// Gets or sets the score value. + /// + /// + /// The value. + /// + public long value + { + get { return mValue; } + + set { mValue = value; } + } + + /// + /// Not implemented. Returns Jan 01, 1970, 00:00:00 + /// + public DateTime date + { + get { return mDate; } + } + + /// + /// Not implemented. Returns the value converted to a string, unformatted. + /// + public string formattedValue + { + get { return mValue.ToString(); } + } + + /// + /// Not implemented. Returns the empty string. + /// + public string userID + { + get { return mPlayerId; } + } + + /// + /// Not implemented. Returns 1. + /// + public int rank + { + get { return (int) mRank; } + } + + /// + /// Gets the metaData (scoreTag). + /// + /// + /// The metaData. + /// + public string metaData + { + get { return mMetadata; } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs.meta new file mode 100644 index 0000000..1168228 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesScore.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 2a6e2425305ab455a91061b1eb955b38 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs new file mode 100644 index 0000000..62820e4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs @@ -0,0 +1,217 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using System; + using System.Collections; + using GooglePlayGames.OurUtils; + using UnityEngine; +#if UNITY_2017_2_OR_NEWER + using UnityEngine.Networking; +#endif + using UnityEngine.SocialPlatforms; + + /// + /// Represents a Google Play Games user profile. In the current implementation, + /// this is only used as a base class of + /// and should not be used directly. + /// + public class PlayGamesUserProfile : IUserProfile + { + private string mDisplayName; + private string mPlayerId; + private string mAvatarUrl; + private bool mIsFriend; + + private volatile bool mImageLoading = false; + private Texture2D mImage; + + internal PlayGamesUserProfile(string displayName, string playerId, + string avatarUrl) + { + mDisplayName = displayName; + mPlayerId = playerId; + setAvatarUrl(avatarUrl); + mImageLoading = false; + mIsFriend = false; + } + + internal PlayGamesUserProfile(string displayName, string playerId, string avatarUrl, + bool isFriend) + { + mDisplayName = displayName; + mPlayerId = playerId; + mAvatarUrl = avatarUrl; + mImageLoading = false; + mIsFriend = isFriend; + } + + protected void ResetIdentity(string displayName, string playerId, + string avatarUrl) + { + mDisplayName = displayName; + mPlayerId = playerId; + mIsFriend = false; + if (mAvatarUrl != avatarUrl) + { + mImage = null; + setAvatarUrl(avatarUrl); + } + + mImageLoading = false; + } + + #region IUserProfile implementation + + public string userName + { + get { return mDisplayName; } + } + + public string id + { + get { return mPlayerId; } + } + + public string gameId + { + get { return mPlayerId; } + } + + public bool isFriend + { + get { return mIsFriend; } + } + + public UserState state + { + get { return UserState.Online; } + } + + public Texture2D image + { + get + { + if (!mImageLoading && mImage == null && !string.IsNullOrEmpty(AvatarURL)) + { + OurUtils.Logger.d("Starting to load image: " + AvatarURL); + mImageLoading = true; + PlayGamesHelperObject.RunCoroutine(LoadImage()); + } + + return mImage; + } + } + + #endregion + + public string AvatarURL + { + get { return mAvatarUrl; } + } + + /// + /// Loads the local user's image from the url. Loading urls + /// is asynchronous so the return from this call is fast, + /// the image is returned once it is loaded. null is returned + /// up to that point. + /// + internal IEnumerator LoadImage() + { + // the url can be null if the user does not have an + // avatar configured. + if (!string.IsNullOrEmpty(AvatarURL)) + { +#if UNITY_2017_2_OR_NEWER + UnityWebRequest www = UnityWebRequestTexture.GetTexture(AvatarURL); + www.SendWebRequest(); +#else + WWW www = new WWW(AvatarURL); +#endif + while (!www.isDone) + { + yield return null; + } + + if (www.error == null) + { +#if UNITY_2017_2_OR_NEWER + this.mImage = DownloadHandlerTexture.GetContent(www); +#else + this.mImage = www.texture; +#endif + } + else + { + mImage = Texture2D.blackTexture; + OurUtils.Logger.e("Error downloading image: " + www.error); + } + + mImageLoading = false; + } + else + { + OurUtils.Logger.e("No URL found."); + mImage = Texture2D.blackTexture; + mImageLoading = false; + } + } + + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + PlayGamesUserProfile other = obj as PlayGamesUserProfile; + if (other == null) + { + return false; + } + + return StringComparer.Ordinal.Equals(mPlayerId, other.mPlayerId); + } + + public override int GetHashCode() + { + return typeof(PlayGamesUserProfile).GetHashCode() ^ mPlayerId.GetHashCode(); + } + + public override string ToString() + { + return string.Format("[Player: '{0}' (id {1})]", mDisplayName, mPlayerId); + } + + private void setAvatarUrl(string avatarUrl) + { + mAvatarUrl = avatarUrl; + if (!avatarUrl.StartsWith("https") && avatarUrl.StartsWith("http")) + { + mAvatarUrl = avatarUrl.Insert(4, "s"); + } + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs.meta new file mode 100644 index 0000000..b5bc517 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/ISocialPlatform/PlayGamesUserProfile.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ab1b90315f37e498a849765260dd436c +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils.meta new file mode 100644 index 0000000..01304aa --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: dc34e4ac2f7e6420da72898e7b511098 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs new file mode 100644 index 0000000..af8b8c3 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs @@ -0,0 +1,92 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.OurUtils +{ + using System; + using UnityEngine; + + public class Logger + { + private static bool debugLogEnabled = false; + + public static bool DebugLogEnabled + { + get { return debugLogEnabled; } + + set { debugLogEnabled = value; } + } + + private static bool warningLogEnabled = true; + + public static bool WarningLogEnabled + { + get { return warningLogEnabled; } + + set { warningLogEnabled = value; } + } + + public static void d(string msg) + { + if (debugLogEnabled) + { + PlayGamesHelperObject.RunOnGameThread(() => + Debug.Log(ToLogMessage(string.Empty, "DEBUG", msg))); + } + } + + public static void w(string msg) + { + if (warningLogEnabled) + { + PlayGamesHelperObject.RunOnGameThread(() => + Debug.LogWarning(ToLogMessage("!!!", "WARNING", msg))); + } + } + + public static void e(string msg) + { + if (warningLogEnabled) + { + PlayGamesHelperObject.RunOnGameThread(() => + Debug.LogWarning(ToLogMessage("***", "ERROR", msg))); + } + } + + public static string describe(byte[] b) + { + return b == null ? "(null)" : "byte[" + b.Length + "]"; + } + + private static string ToLogMessage(string prefix, string logType, string msg) + { + string timeString = null; + try + { + timeString = DateTime.Now.ToString("MM/dd/yy H:mm:ss zzz"); + } + catch (Exception) + { + PlayGamesHelperObject.RunOnGameThread(() => + Debug.LogWarning("*** [Play Games Plugin " + PluginVersion.VersionString + "] ERROR: Failed to format DateTime.Now")); + timeString = string.Empty; + } + + return string.Format("{0} [Play Games Plugin " + PluginVersion.VersionString+ "] {1} {2}: {3}", + prefix, timeString, logType, msg); + } + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs.meta new file mode 100644 index 0000000..ab9a2a2 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Logger.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: cde7cfd197b4a47edac2efe305e22e78 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs new file mode 100644 index 0000000..8af6ea8 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs @@ -0,0 +1,100 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.OurUtils +{ + using System; + + public static class Misc + { + public static bool BuffersAreIdentical(byte[] a, byte[] b) + { + if (a == b) + { + // not only identical but the very same! + return true; + } + + if (a == null || b == null) + { + // one of them is null, the other one isn't + return false; + } + + if (a.Length != b.Length) + { + return false; + } + + for (int i = 0; i < a.Length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + public static byte[] GetSubsetBytes(byte[] array, int offset, int length) + { + if (array == null) + { + throw new ArgumentNullException("array"); + } + + if (offset < 0 || offset >= array.Length) + { + throw new ArgumentOutOfRangeException("offset"); + } + + if (length < 0 || (array.Length - offset) < length) + { + throw new ArgumentOutOfRangeException("length"); + } + + if (offset == 0 && length == array.Length) + { + return array; + } + + byte[] piece = new byte[length]; + Array.Copy(array, offset, piece, 0, length); + return piece; + } + + public static T CheckNotNull(T value) + { + if (value == null) + { + throw new ArgumentNullException(); + } + + return value; + } + + public static T CheckNotNull(T value, string paramName) + { + if (value == null) + { + throw new ArgumentNullException(paramName); + } + + return value; + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs.meta new file mode 100644 index 0000000..b340ef4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/Misc.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ee52269f55933442fa5ea52e688ebec2 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs new file mode 100644 index 0000000..3b09327 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs @@ -0,0 +1,104 @@ +#if UNITY_ANDROID + +namespace GooglePlayGames.OurUtils +{ + using BasicApi.Nearby; + using System; + using UnityEngine; + + public class NearbyHelperObject : MonoBehaviour + { + // our (singleton) instance + private static NearbyHelperObject instance = null; + + // timers to keep track of discovery and advertising + private static double mAdvertisingRemaining = 0; + private static double mDiscoveryRemaining = 0; + + // nearby client to stop discovery and to stop advertising + private static INearbyConnectionClient mClient = null; + + public static void CreateObject(INearbyConnectionClient client) + { + if (instance != null) + { + return; + } + + mClient = client; + if (Application.isPlaying) + { + // add an invisible game object to the scene + GameObject obj = new GameObject("PlayGames_NearbyHelper"); + DontDestroyOnLoad(obj); + instance = obj.AddComponent(); + } + else + { + instance = new NearbyHelperObject(); + } + } + + private static double ToSeconds(TimeSpan? span) + { + if (!span.HasValue) + { + return 0; + } + + if (span.Value.TotalSeconds < 0) + { + return 0; + } + + return span.Value.TotalSeconds; + } + + public static void StartAdvertisingTimer(TimeSpan? span) + { + mAdvertisingRemaining = ToSeconds(span); + } + + public static void StartDiscoveryTimer(TimeSpan? span) + { + mDiscoveryRemaining = ToSeconds(span); + } + + public void Awake() + { + DontDestroyOnLoad(gameObject); + } + + public void OnDisable() + { + if (instance == this) + { + instance = null; + } + } + + public void Update() + { + // check if currently advertising + if (mAdvertisingRemaining > 0) + { + mAdvertisingRemaining -= Time.deltaTime; + if (mAdvertisingRemaining < 0) + { + mClient.StopAdvertising(); + } + } + + // check if currently discovering + if (mDiscoveryRemaining > 0) + { + mDiscoveryRemaining -= Time.deltaTime; + if (mDiscoveryRemaining < 0) + { + mClient.StopDiscovery(mClient.GetServiceId()); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs.meta new file mode 100644 index 0000000..7e4b250 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/NearbyHelperObject.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b66cca4a5a1f4a5092a280c452185308 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs new file mode 100644 index 0000000..5fce45b --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs @@ -0,0 +1,58 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID +namespace GooglePlayGames.OurUtils +{ + using UnityEngine; + using System; + + public static class PlatformUtils + { + /// + /// Check if the Google Play Games platform is supported at runtime. + /// + /// If the platform is supported. + public static bool Supported + { + get + { +#if UNITY_EDITOR + return false; +#else + var up = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); + var ca = up.GetStatic("currentActivity"); + var packageManager = ca.Call("getPackageManager"); + + AndroidJavaObject launchIntent = null; + //if the app is installed, no errors. Else, doesn't get past next line + try + { + launchIntent = + packageManager.Call("getLaunchIntentForPackage", "com.google.android.play.games"); + } + catch (Exception) + { + return false; + } + + return launchIntent != null; +#endif + } + } + } +} +#endif //UNITY_ANDROID \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs.meta new file mode 100644 index 0000000..7b6bedf --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlatformUtils.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 053811e778f3d4e3e98065f5db5bd005 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs new file mode 100644 index 0000000..6c8551c --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs @@ -0,0 +1,222 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames.OurUtils +{ + using System; + using System.Collections; + using UnityEngine; + using System.Collections.Generic; + + public class PlayGamesHelperObject : MonoBehaviour + { + // our (singleton) instance + private static PlayGamesHelperObject instance = null; + + // are we a dummy instance (used in the editor?) + private static bool sIsDummy = false; + + // queue of actions to run on the game thread + private static List sQueue = new List(); + + // member variable used to copy actions from the sQueue and + // execute them on the game thread. It is a member variable + // to help minimize memory allocations. + List localQueue = new List(); + + // flag that alerts us that we should check the queue + // (we do this just so we don't have to lock() the queue every + // frame to check if it's empty or not). + private volatile static bool sQueueEmpty = true; + + // callback for application pause and focus events + private static List> sPauseCallbackList = + new List>(); + + private static List> sFocusCallbackList = + new List>(); + + // Call this once from the game thread + public static void CreateObject() + { + if (instance != null) + { + return; + } + + if (Application.isPlaying) + { + // add an invisible game object to the scene + GameObject obj = new GameObject("PlayGames_QueueRunner"); + DontDestroyOnLoad(obj); + instance = obj.AddComponent(); + } + else + { + instance = new PlayGamesHelperObject(); + sIsDummy = true; + } + } + + public void Awake() + { + DontDestroyOnLoad(gameObject); + } + + public void OnDisable() + { + if (instance == this) + { + instance = null; + } + } + + public static void RunCoroutine(IEnumerator action) + { + if (instance != null) + { + RunOnGameThread(() => instance.StartCoroutine(action)); + } + } + + public static void RunOnGameThread(System.Action action) + { + if (action == null) + { + throw new ArgumentNullException("action"); + } + + if (sIsDummy) + { + return; + } + + lock (sQueue) + { + sQueue.Add(action); + sQueueEmpty = false; + } + } + + public void Update() + { + if (sIsDummy || sQueueEmpty) + { + return; + } + + // first copy the shared queue into a local queue + localQueue.Clear(); + lock (sQueue) + { + // transfer the whole queue to our local queue + localQueue.AddRange(sQueue); + sQueue.Clear(); + sQueueEmpty = true; + } + + // execute queued actions (from local queue) + // use a loop to avoid extra memory allocations using the + // forEach + for (int i = 0; i < localQueue.Count; i++) + { + localQueue[i].Invoke(); + } + } + + public void OnApplicationFocus(bool focused) + { + foreach (Action cb in sFocusCallbackList) + { + try + { + cb(focused); + } + catch (Exception e) + { + Logger.e("Exception in OnApplicationFocus:" + + e.Message + "\n" + e.StackTrace); + } + } + } + + public void OnApplicationPause(bool paused) + { + foreach (Action cb in sPauseCallbackList) + { + try + { + cb(paused); + } + catch (Exception e) + { + Logger.e("Exception in OnApplicationPause:" + + e.Message + "\n" + e.StackTrace); + } + } + } + + /// + /// Adds a callback that is called when the Unity method OnApplicationFocus + /// is called. + /// + /// + /// Callback. + public static void AddFocusCallback(Action callback) + { + if (!sFocusCallbackList.Contains(callback)) + { + sFocusCallbackList.Add(callback); + } + } + + /// + /// Removes the callback from the list to call when handling OnApplicationFocus + /// is called. + /// + /// true, if focus callback was removed, false otherwise. + /// Callback. + public static bool RemoveFocusCallback(Action callback) + { + return sFocusCallbackList.Remove(callback); + } + + /// + /// Adds a callback that is called when the Unity method OnApplicationPause + /// is called. + /// + /// + /// Callback. + public static void AddPauseCallback(Action callback) + { + if (!sPauseCallbackList.Contains(callback)) + { + sPauseCallbackList.Add(callback); + } + } + + /// + /// Removes the callback from the list to call when handling OnApplicationPause + /// is called. + /// + /// true, if focus callback was removed, false otherwise. + /// Callback. + public static bool RemovePauseCallback(Action callback) + { + return sPauseCallbackList.Remove(callback); + } + } +} \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs.meta new file mode 100644 index 0000000..fa51c96 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/OurUtils/PlayGamesHelperObject.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 7dd6f93ee6cb54945aea72a87542f720 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms.meta new file mode 100644 index 0000000..dd9d70b --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 58fac82a81a11415b99606841f6040a6 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android.meta new file mode 100644 index 0000000..a8981c4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5c9032ae026414e1bbe872da53708edd +folderAsset: yes +timeCreated: 1441206393 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs new file mode 100644 index 0000000..ec9c53e --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs @@ -0,0 +1,1024 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID +#pragma warning disable 0642 // Possible mistaken empty statement + +namespace GooglePlayGames.Android +{ + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.Events; + using GooglePlayGames.BasicApi.SavedGame; + using GooglePlayGames.OurUtils; + using System; + using UnityEngine; + using UnityEngine.SocialPlatforms; + + public class AndroidClient : IPlayGamesClient + { + private enum AuthState + { + Unauthenticated, + Authenticated + } + + private readonly object GameServicesLock = new object(); + private readonly object AuthStateLock = new object(); + private readonly static String PlayGamesSdkClassName = + "com.google.android.gms.games.PlayGamesSdk"; + + private volatile ISavedGameClient mSavedGameClient; + private volatile IEventsClient mEventsClient; + private volatile Player mUser = null; + private volatile AuthState mAuthState = AuthState.Unauthenticated; + private IUserProfile[] mFriends = new IUserProfile[0]; + private LoadFriendsStatus mLastLoadFriendsStatus = LoadFriendsStatus.Unknown; + + AndroidJavaClass mGamesClass = new AndroidJavaClass("com.google.android.gms.games.PlayGames"); + private static string TasksClassName = "com.google.android.gms.tasks.Tasks"; + + private AndroidJavaObject mFriendsResolutionException = null; + + private readonly int mLeaderboardMaxResults = 25; // can be from 1 to 25 + + private readonly int mFriendsMaxResults = 200; // the maximum load friends page size + + internal AndroidClient() + { + PlayGamesHelperObject.CreateObject(); + InitializeSdk(); + } + + private static void InitializeSdk() { + using (var playGamesSdkClass = new AndroidJavaClass(PlayGamesSdkClassName)) { + playGamesSdkClass.CallStatic("initialize", AndroidHelperFragment.GetActivity()); + } + } + + public void Authenticate(Action callback) + { + Authenticate( /* isAutoSignIn= */ true, callback); + } + + public void ManuallyAuthenticate(Action callback) + { + Authenticate( /* isAutoSignIn= */ false, callback); + } + + private void Authenticate(bool isAutoSignIn, Action callback) + { + callback = AsOnGameThreadCallback(callback); + lock (AuthStateLock) + { + // If the user is already authenticated, just fire the callback, we don't need + // any additional work. + if (mAuthState == AuthState.Authenticated) + { + OurUtils.Logger.d("Already authenticated."); + InvokeCallbackOnGameThread(callback, SignInStatus.Success); + return; + } + } + + string methodName = isAutoSignIn ? "isAuthenticated" : "signIn"; + + OurUtils.Logger.d("Starting Auth using the method " + methodName); + using (var client = getGamesSignInClient()) + using ( + var task = client.Call(methodName)) + { + AndroidTaskUtils.AddOnSuccessListener(task, authenticationResult => + { + bool isAuthenticated = authenticationResult.Call("isAuthenticated"); + SignInOnResult(isAuthenticated, callback); + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("Authentication failed - " + exception.Call("toString")); + callback(SignInStatus.InternalError); + }); + } + } + + private void SignInOnResult(bool isAuthenticated, Action callback) + { + if (isAuthenticated) + { + using (var signInTasks = new AndroidJavaObject("java.util.ArrayList")) + { + AndroidJavaObject taskGetPlayer = + getPlayersClient().Call("getCurrentPlayer"); + signInTasks.Call("add", taskGetPlayer); + + using (var tasks = new AndroidJavaClass(TasksClassName)) + using (var allTask = tasks.CallStatic("whenAll", signInTasks)) + { + AndroidTaskUtils.AddOnCompleteListener( + allTask, + completeTask => + { + if (completeTask.Call("isSuccessful")) + { + using (var resultObject = taskGetPlayer.Call("getResult")) + { + mUser = AndroidJavaConverter.ToPlayer(resultObject); + } + + lock (GameServicesLock) + { + mSavedGameClient = new AndroidSavedGameClient(this); + mEventsClient = new AndroidEventsClient(); + } + + mAuthState = AuthState.Authenticated; + InvokeCallbackOnGameThread(callback, SignInStatus.Success); + OurUtils.Logger.d("Authentication succeeded"); + LoadAchievements(ignore => { }); + } + else + { + if (completeTask.Call("isCanceled")) + { + InvokeCallbackOnGameThread(callback, SignInStatus.Canceled); + return; + } + + using (var exception = completeTask.Call("getException")) + { + OurUtils.Logger.e( + "Authentication failed - " + exception.Call("toString")); + InvokeCallbackOnGameThread(callback, SignInStatus.InternalError); + } + } + } + ); + } + } + } + else + { + lock (AuthStateLock) + { + OurUtils.Logger.e("Returning an error code."); + InvokeCallbackOnGameThread(callback, SignInStatus.Canceled); + } + } + } + + public void RequestServerSideAccess(bool forceRefreshToken, Action callback) + { + callback = AsOnGameThreadCallback(callback); + + if (!GameInfo.WebClientIdInitialized()) + { + throw new InvalidOperationException("Requesting server side access requires web " + + "client id to be configured."); + } + + using (var client = getGamesSignInClient()) + using (var task = client.Call("requestServerSideAccess", + GameInfo.WebClientId, forceRefreshToken)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + authCode => callback(authCode) + ); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("Requesting server side access task failed - " + + exception.Call("toString")); + callback(null); + }); + } + } + + private static Action AsOnGameThreadCallback(Action callback) + { + if (callback == null) + { + return delegate { }; + } + + return result => InvokeCallbackOnGameThread(callback, result); + } + + private static void InvokeCallbackOnGameThread(Action callback) + { + if (callback == null) + { + return; + } + + PlayGamesHelperObject.RunOnGameThread(() => { callback(); }); + } + + private static void InvokeCallbackOnGameThread(Action callback, T data) + { + if (callback == null) + { + return; + } + + PlayGamesHelperObject.RunOnGameThread(() => { callback(data); }); + } + + + private static Action AsOnGameThreadCallback( + Action toInvokeOnGameThread) + { + return (result1, result2) => + { + if (toInvokeOnGameThread == null) + { + return; + } + + PlayGamesHelperObject.RunOnGameThread(() => toInvokeOnGameThread(result1, result2)); + }; + } + + private static void InvokeCallbackOnGameThread(Action callback, T1 t1, T2 t2) + { + if (callback == null) + { + return; + } + + PlayGamesHelperObject.RunOnGameThread(() => { callback(t1, t2); }); + } + + public bool IsAuthenticated() + { + lock (AuthStateLock) + { + return mAuthState == AuthState.Authenticated; + } + } + + public void LoadFriends(Action callback) + { + LoadAllFriends(mFriendsMaxResults, /* forceReload= */ false, /* loadMore= */ false, callback); + } + + private void LoadAllFriends(int pageSize, bool forceReload, bool loadMore, + Action callback) + { + LoadFriendsPaginated(pageSize, loadMore, forceReload, result => + { + mLastLoadFriendsStatus = result; + switch (result) + { + case LoadFriendsStatus.Completed: + InvokeCallbackOnGameThread(callback, true); + break; + case LoadFriendsStatus.LoadMore: + // There are more friends to load. + LoadAllFriends(pageSize, /* forceReload= */ false, /* loadMore= */ true, callback); + break; + case LoadFriendsStatus.ResolutionRequired: + case LoadFriendsStatus.InternalError: + case LoadFriendsStatus.NotAuthorized: + InvokeCallbackOnGameThread(callback, false); + break; + default: + GooglePlayGames.OurUtils.Logger.d("There was an error when loading friends." + result); + InvokeCallbackOnGameThread(callback, false); + break; + } + }); + } + + public void LoadFriends(int pageSize, bool forceReload, + Action callback) + { + LoadFriendsPaginated(pageSize, /* isLoadMore= */ false, /* forceReload= */ forceReload, + callback); + } + + public void LoadMoreFriends(int pageSize, Action callback) + { + LoadFriendsPaginated(pageSize, /* isLoadMore= */ true, /* forceReload= */ false, + callback); + } + + private void LoadFriendsPaginated(int pageSize, bool isLoadMore, bool forceReload, + Action callback) + { + mFriendsResolutionException = null; + using (var playersClient = getPlayersClient()) + using (var task = isLoadMore + ? playersClient.Call("loadMoreFriends", pageSize) + : playersClient.Call("loadFriends", pageSize, + forceReload)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, annotatedData => + { + using (var playersBuffer = annotatedData.Call("get")) + { + AndroidJavaObject metadata = playersBuffer.Call("getMetadata"); + var areMoreFriendsToLoad = metadata != null && + metadata.Call("getString", + "next_page_token") != null; + mFriends = AndroidJavaConverter.playersBufferToArray(playersBuffer); + mLastLoadFriendsStatus = areMoreFriendsToLoad + ? LoadFriendsStatus.LoadMore + : LoadFriendsStatus.Completed; + InvokeCallbackOnGameThread(callback, mLastLoadFriendsStatus); + } + }); + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired => + { + if (resolutionRequired) + { + mFriendsResolutionException = + exception.Call("getResolution"); + mLastLoadFriendsStatus = LoadFriendsStatus.ResolutionRequired; + mFriends = new IUserProfile[0]; + InvokeCallbackOnGameThread(callback, LoadFriendsStatus.ResolutionRequired); + } + else + { + mFriendsResolutionException = null; + + if (IsApiException(exception)) + { + var statusCode = exception.Call("getStatusCode"); + if (statusCode == /* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504) + { + mLastLoadFriendsStatus = LoadFriendsStatus.NetworkError; + InvokeCallbackOnGameThread(callback, LoadFriendsStatus.NetworkError); + return; + } + } + + mLastLoadFriendsStatus = LoadFriendsStatus.InternalError; + OurUtils.Logger.e("LoadFriends failed: " + + exception.Call("toString")); + InvokeCallbackOnGameThread(callback, LoadFriendsStatus.InternalError); + } + }); + return; + }); + } + } + + private static bool IsApiException(AndroidJavaObject exception) { + var exceptionClassName = exception.Call("getClass") + .Call("getName"); + return exceptionClassName == "com.google.android.gms.common.api.ApiException"; + } + + public LoadFriendsStatus GetLastLoadFriendsStatus() + { + return mLastLoadFriendsStatus; + } + + public void AskForLoadFriendsResolution(Action callback) + { + if (mFriendsResolutionException == null) + { + GooglePlayGames.OurUtils.Logger.d("The developer asked for access to the friends " + + "list but there is no intent to trigger the UI. This may be because the user " + + "has granted access already or the game has not called loadFriends() before."); + using (var playersClient = getPlayersClient()) + using ( + var task = playersClient.Call("loadFriends", /* pageSize= */ 1, + /* forceReload= */ false)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, annotatedData => { InvokeCallbackOnGameThread(callback, UIStatus.Valid); }); + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired => + { + if (resolutionRequired) + { + mFriendsResolutionException = + exception.Call("getResolution"); + AndroidHelperFragment.AskForLoadFriendsResolution( + mFriendsResolutionException, AsOnGameThreadCallback(callback)); + return; + } + + if (IsApiException(exception)) + { + var statusCode = exception.Call("getStatusCode"); + if (statusCode == + /* GamesClientStatusCodes.NETWORK_ERROR_NO_DATA */ 26504) + { + InvokeCallbackOnGameThread(callback, UIStatus.NetworkError); + return; + } + } + + OurUtils.Logger.e("LoadFriends failed: " + + exception.Call("toString")); + InvokeCallbackOnGameThread(callback, UIStatus.InternalError); + }); + }); + } + } + else + { + AndroidHelperFragment.AskForLoadFriendsResolution(mFriendsResolutionException, + AsOnGameThreadCallback(callback)); + } + } + + public void ShowCompareProfileWithAlternativeNameHintsUI(string playerId, + string otherPlayerInGameName, + string currentPlayerInGameName, + Action callback) + { + AndroidHelperFragment.ShowCompareProfileWithAlternativeNameHintsUI( + playerId, otherPlayerInGameName, currentPlayerInGameName, + AsOnGameThreadCallback(callback)); + } + + public void GetFriendsListVisibility(bool forceReload, + Action callback) + { + using (var playersClient = getPlayersClient()) + using ( + var task = playersClient.Call("getCurrentPlayer", forceReload)) + { + AndroidTaskUtils.AddOnSuccessListener(task, annotatedData => + { + AndroidJavaObject currentPlayerInfo = + annotatedData.Call("get").Call( + "getCurrentPlayerInfo"); + int playerListVisibility = + currentPlayerInfo.Call("getFriendsListVisibilityStatus"); + InvokeCallbackOnGameThread(callback, + AndroidJavaConverter.ToFriendsListVisibilityStatus(playerListVisibility)); + }); + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + InvokeCallbackOnGameThread(callback, FriendsListVisibilityStatus.NetworkError); + return; + }); + } + } + + public IUserProfile[] GetFriends() + { + return mFriends; + } + + public string GetUserId() + { + if (mUser == null) + { + return null; + } + + return mUser.id; + } + + public string GetUserDisplayName() + { + if (mUser == null) + { + return null; + } + + return mUser.userName; + } + + public string GetUserImageUrl() + { + if (mUser == null) + { + return null; + } + + return mUser.AvatarURL; + } + + public void GetPlayerStats(Action callback) + { + using (var playerStatsClient = getPlayerStatsClient()) + using (var task = playerStatsClient.Call("loadPlayerStats", /* forceReload= */ false)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var playerStatsJava = annotatedData.Call("get")) + { + int numberOfPurchases = playerStatsJava.Call("getNumberOfPurchases"); + float avgSessionLength = playerStatsJava.Call("getAverageSessionLength"); + int daysSinceLastPlayed = playerStatsJava.Call("getDaysSinceLastPlayed"); + int numberOfSessions = playerStatsJava.Call("getNumberOfSessions"); + float sessionPercentile = playerStatsJava.Call("getSessionPercentile"); + float spendPercentile = playerStatsJava.Call("getSpendPercentile"); + float spendProbability = playerStatsJava.Call("getSpendProbability"); + float churnProbability = playerStatsJava.Call("getChurnProbability"); + float highSpenderProbability = playerStatsJava.Call("getHighSpenderProbability"); + float totalSpendNext28Days = playerStatsJava.Call("getTotalSpendNext28Days"); + + PlayerStats result = new PlayerStats( + numberOfPurchases, + avgSessionLength, + daysSinceLastPlayed, + numberOfSessions, + sessionPercentile, + spendPercentile, + spendProbability, + churnProbability, + highSpenderProbability, + totalSpendNext28Days); + + InvokeCallbackOnGameThread(callback, CommonStatusCodes.Success, result); + } + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("GetPlayerStats failed: " + exception.Call("toString")); + var statusCode = IsAuthenticated() + ? CommonStatusCodes.InternalError + : CommonStatusCodes.SignInRequired; + InvokeCallbackOnGameThread(callback, statusCode, new PlayerStats()); + }); + } + } + + public void LoadUsers(string[] userIds, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, new IUserProfile[0]); + return; + } + + using (var playersClient = getPlayersClient()) + { + object countLock = new object(); + int count = userIds.Length; + int resultCount = 0; + IUserProfile[] users = new IUserProfile[count]; + for (int i = 0; i < count; ++i) + { + using (var task = playersClient.Call("loadPlayer", userIds[i])) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var player = annotatedData.Call("get")) + { + string playerId = player.Call("getPlayerId"); + for (int j = 0; j < count; ++j) + { + if (playerId == userIds[j]) + { + users[j] = AndroidJavaConverter.ToPlayer(player); + break; + } + } + + lock (countLock) + { + ++resultCount; + if (resultCount == count) + { + InvokeCallbackOnGameThread(callback, users); + } + } + } + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("LoadUsers failed for index " + i + + " with: " + exception.Call("toString")); + lock (countLock) + { + ++resultCount; + if (resultCount == count) + { + InvokeCallbackOnGameThread(callback, users); + } + } + }); + } + } + } + } + + public void LoadAchievements(Action callback) + { + using (var achievementsClient = getAchievementsClient()) + using (var task = achievementsClient.Call("load", /* forceReload= */ false)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var achievementBuffer = annotatedData.Call("get")) + { + int count = achievementBuffer.Call("getCount"); + Achievement[] result = new Achievement[count]; + for (int i = 0; i < count; ++i) + { + Achievement achievement = new Achievement(); + using (var javaAchievement = achievementBuffer.Call("get", i)) + { + achievement.Id = javaAchievement.Call("getAchievementId"); + achievement.Description = javaAchievement.Call("getDescription"); + achievement.Name = javaAchievement.Call("getName"); + achievement.Points = javaAchievement.Call("getXpValue"); + + long timestamp = javaAchievement.Call("getLastUpdatedTimestamp"); + achievement.LastModifiedTime = AndroidJavaConverter.ToDateTime(timestamp); + + achievement.RevealedImageUrl = javaAchievement.Call("getRevealedImageUrl"); + achievement.UnlockedImageUrl = javaAchievement.Call("getUnlockedImageUrl"); + achievement.IsIncremental = + javaAchievement.Call("getType") == 1 /* TYPE_INCREMENTAL */; + if (achievement.IsIncremental) + { + achievement.CurrentSteps = javaAchievement.Call("getCurrentSteps"); + achievement.TotalSteps = javaAchievement.Call("getTotalSteps"); + } + + int state = javaAchievement.Call("getState"); + achievement.IsUnlocked = state == 0 /* STATE_UNLOCKED */; + achievement.IsRevealed = state == 1 /* STATE_REVEALED */; + } + + result[i] = achievement; + } + + achievementBuffer.Call("release"); + InvokeCallbackOnGameThread(callback, result); + } + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("LoadAchievements failed: " + exception.Call("toString")); + InvokeCallbackOnGameThread(callback, new Achievement[0]); + }); + } + } + + public void UnlockAchievement(string achId, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, false); + return; + } + + using (var achievementsClient = getAchievementsClient()) + { + achievementsClient.Call("unlock", achId); + InvokeCallbackOnGameThread(callback, true); + } + } + + public void RevealAchievement(string achId, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, false); + return; + } + + using (var achievementsClient = getAchievementsClient()) + { + achievementsClient.Call("reveal", achId); + InvokeCallbackOnGameThread(callback, true); + } + } + + public void IncrementAchievement(string achId, int steps, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, false); + return; + } + + using (var achievementsClient = getAchievementsClient()) + { + achievementsClient.Call("increment", achId, steps); + InvokeCallbackOnGameThread(callback, true); + } + } + + public void SetStepsAtLeast(string achId, int steps, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, false); + return; + } + + using (var achievementsClient = getAchievementsClient()) + { + achievementsClient.Call("setSteps", achId, steps); + InvokeCallbackOnGameThread(callback, true); + } + } + + public void ShowAchievementsUI(Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized); + return; + } + + AndroidHelperFragment.ShowAchievementsUI(AsOnGameThreadCallback(callback)); + } + + public int LeaderboardMaxResults() + { + return mLeaderboardMaxResults; + } + + public void ShowLeaderboardUI(string leaderboardId, LeaderboardTimeSpan span, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, UIStatus.NotAuthorized); + return; + } + + if (leaderboardId == null) + { + AndroidHelperFragment.ShowAllLeaderboardsUI(AsOnGameThreadCallback(callback)); + } + else + { + AndroidHelperFragment.ShowLeaderboardUI(leaderboardId, span, + AsOnGameThreadCallback(callback)); + } + } + + public void LoadScores(string leaderboardId, LeaderboardStart start, + int rowCount, LeaderboardCollection collection, + LeaderboardTimeSpan timeSpan, + Action callback) + { + using (var client = getLeaderboardsClient()) + { + string loadScoresMethod = + start == LeaderboardStart.TopScores ? "loadTopScores" : "loadPlayerCenteredScores"; + using (var task = client.Call( + loadScoresMethod, + leaderboardId, + AndroidJavaConverter.ToLeaderboardVariantTimeSpan(timeSpan), + AndroidJavaConverter.ToLeaderboardVariantCollection(collection), + rowCount)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var leaderboardScores = annotatedData.Call("get")) + { + InvokeCallbackOnGameThread(callback, CreateLeaderboardScoreData( + leaderboardId, + collection, + timeSpan, + annotatedData.Call("isStale") + ? ResponseStatus.SuccessWithStale + : ResponseStatus.Success, + leaderboardScores)); + leaderboardScores.Call("release"); + } + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + AndroidHelperFragment.IsResolutionRequired( + exception, resolutionRequired => + { + if (resolutionRequired) + { + mFriendsResolutionException = exception.Call( + "getResolution"); + InvokeCallbackOnGameThread( + callback, new LeaderboardScoreData(leaderboardId, + ResponseStatus.ResolutionRequired)); + } + else + { + mFriendsResolutionException = null; + } + }); + OurUtils.Logger.e("LoadScores failed: " + exception.Call("toString")); + InvokeCallbackOnGameThread( + callback, new LeaderboardScoreData(leaderboardId, + ResponseStatus.InternalError)); + }); + } + } + } + + public void LoadMoreScores(ScorePageToken token, int rowCount, + Action callback) + { + using (var client = getLeaderboardsClient()) + using (var task = client.Call("loadMoreScores", + token.InternalObject, rowCount, AndroidJavaConverter.ToPageDirection(token.Direction))) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var leaderboardScores = annotatedData.Call("get")) + { + InvokeCallbackOnGameThread(callback, CreateLeaderboardScoreData( + token.LeaderboardId, + token.Collection, + token.TimeSpan, + annotatedData.Call("isStale") + ? ResponseStatus.SuccessWithStale + : ResponseStatus.Success, + leaderboardScores)); + leaderboardScores.Call("release"); + } + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + AndroidHelperFragment.IsResolutionRequired(exception, resolutionRequired => + { + if (resolutionRequired) + { + mFriendsResolutionException = + exception.Call("getResolution"); + InvokeCallbackOnGameThread( + callback, new LeaderboardScoreData(token.LeaderboardId, + ResponseStatus.ResolutionRequired)); + } + else + { + mFriendsResolutionException = null; + } + }); + OurUtils.Logger.e("LoadMoreScores failed: " + exception.Call("toString")); + InvokeCallbackOnGameThread( + callback, new LeaderboardScoreData(token.LeaderboardId, + ResponseStatus.InternalError)); + }); + } + } + + private LeaderboardScoreData CreateLeaderboardScoreData( + string leaderboardId, + LeaderboardCollection collection, + LeaderboardTimeSpan timespan, + ResponseStatus status, + AndroidJavaObject leaderboardScoresJava) + { + LeaderboardScoreData leaderboardScoreData = new LeaderboardScoreData(leaderboardId, status); + var scoresBuffer = leaderboardScoresJava.Call("getScores"); + int count = scoresBuffer.Call("getCount"); + for (int i = 0; i < count; ++i) + { + using (var leaderboardScore = scoresBuffer.Call("get", i)) + { + long timestamp = leaderboardScore.Call("getTimestampMillis"); + System.DateTime date = AndroidJavaConverter.ToDateTime(timestamp); + + ulong rank = (ulong) leaderboardScore.Call("getRank"); + string scoreHolderId = ""; + using (var scoreHolder = leaderboardScore.Call("getScoreHolder")) + { + scoreHolderId = scoreHolder.Call("getPlayerId"); + } + + ulong score = (ulong) leaderboardScore.Call("getRawScore"); + string metadata = leaderboardScore.Call("getScoreTag"); + + leaderboardScoreData.AddScore(new PlayGamesScore(date, leaderboardId, + rank, scoreHolderId, score, metadata)); + } + } + + leaderboardScoreData.NextPageToken = new ScorePageToken(scoresBuffer, leaderboardId, collection, + timespan, ScorePageDirection.Forward); + leaderboardScoreData.PrevPageToken = new ScorePageToken(scoresBuffer, leaderboardId, collection, + timespan, ScorePageDirection.Backward); + + using (var leaderboard = leaderboardScoresJava.Call("getLeaderboard")) + using (var variants = leaderboard.Call("getVariants")) + using (var variant = variants.Call("get", 0)) + { + leaderboardScoreData.Title = leaderboard.Call("getDisplayName"); + if (variant.Call("hasPlayerInfo")) + { + System.DateTime date = AndroidJavaConverter.ToDateTime(0); + ulong rank = (ulong) variant.Call("getPlayerRank"); + ulong score = (ulong) variant.Call("getRawPlayerScore"); + string metadata = variant.Call("getPlayerScoreTag"); + leaderboardScoreData.PlayerScore = new PlayGamesScore(date, leaderboardId, + rank, mUser.id, score, metadata); + } + + leaderboardScoreData.ApproximateCount = (ulong) variant.Call("getNumScores"); + } + + return leaderboardScoreData; + } + + public void SubmitScore(string leaderboardId, long score, Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, false); + } + + using (var client = getLeaderboardsClient()) + { + client.Call("submitScore", leaderboardId, score); + InvokeCallbackOnGameThread(callback, true); + } + } + + public void SubmitScore(string leaderboardId, long score, string metadata, + Action callback) + { + if (!IsAuthenticated()) + { + InvokeCallbackOnGameThread(callback, false); + } + + using (var client = getLeaderboardsClient()) + { + client.Call("submitScore", leaderboardId, score, metadata); + InvokeCallbackOnGameThread(callback, true); + } + } + + public ISavedGameClient GetSavedGameClient() + { + lock (GameServicesLock) + { + return mSavedGameClient; + } + } + + public IEventsClient GetEventsClient() + { + lock (GameServicesLock) + { + return mEventsClient; + } + } + + private AndroidJavaObject getAchievementsClient() + { + return mGamesClass.CallStatic("getAchievementsClient", + AndroidHelperFragment.GetActivity()); + } + + private AndroidJavaObject getPlayersClient() + { + return mGamesClass.CallStatic("getPlayersClient", AndroidHelperFragment.GetActivity()); + } + + private AndroidJavaObject getLeaderboardsClient() + { + return mGamesClass.CallStatic("getLeaderboardsClient", + AndroidHelperFragment.GetActivity()); + } + + private AndroidJavaObject getPlayerStatsClient() + { + return mGamesClass.CallStatic("getPlayerStatsClient", + AndroidHelperFragment.GetActivity()); + } + + private AndroidJavaObject getGamesSignInClient() + { + return mGamesClass.CallStatic("getGamesSignInClient", + AndroidHelperFragment.GetActivity()); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs.meta new file mode 100644 index 0000000..22bce66 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 32e99ad5da22248a28a9ca51282b121f +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs new file mode 100644 index 0000000..799205d --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs @@ -0,0 +1,136 @@ +#if UNITY_ANDROID +namespace GooglePlayGames.Android +{ + using System; + using System.Collections.Generic; + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.Events; + using GooglePlayGames.OurUtils; + using UnityEngine; + internal class AndroidEventsClient : IEventsClient + { + private volatile AndroidJavaObject mEventsClient; + + public AndroidEventsClient() + { + using (var gamesClass = new AndroidJavaClass("com.google.android.gms.games.PlayGames")) + { + mEventsClient = gamesClass.CallStatic("getEventsClient", + AndroidHelperFragment.GetActivity()); + } + } + + public void FetchAllEvents(DataSource source, Action> callback) + { + callback = ToOnGameThread(callback); + using (var task = + mEventsClient.Call("load", source == DataSource.ReadNetworkOnly ? true : false)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var buffer = annotatedData.Call("get")) + { + int count = buffer.Call("getCount"); + List result = new List(); + for (int i = 0; i < count; ++i) + { + using (var eventJava = buffer.Call("get", i)) + { + result.Add(CreateEvent(eventJava)); + } + } + buffer.Call("release"); + callback.Invoke( + annotatedData.Call("isStale") + ? ResponseStatus.SuccessWithStale + : ResponseStatus.Success, + result + ); + } + }); + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + Debug.Log("FetchAllEvents failed"); + callback.Invoke(ResponseStatus.InternalError, null); + }); + } + } + + public void FetchEvent(DataSource source, string eventId, Action callback) + { + callback = ToOnGameThread(callback); + string[] ids = new string[1]; + ids[0] = eventId; + using (var task = mEventsClient.Call("loadByIds", + source == DataSource.ReadNetworkOnly ? true : false, ids)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var buffer = annotatedData.Call("get")) + { + int count = buffer.Call("getCount"); + if (count > 0) + { + using (var eventJava = buffer.Call("get", 0)) + { + callback.Invoke( + annotatedData.Call("isStale") + ? ResponseStatus.SuccessWithStale + : ResponseStatus.Success, + CreateEvent(eventJava) + ); + } + } + else + { + callback.Invoke( + annotatedData.Call("isStale") + ? ResponseStatus.SuccessWithStale + : ResponseStatus.Success, + null + ); + } + buffer.Call("release"); + } + }); + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + Debug.Log("FetchEvent failed"); + callback.Invoke(ResponseStatus.InternalError, null); + }); + } + } + + public void IncrementEvent(string eventId, uint stepsToIncrement) + { + mEventsClient.Call("increment", eventId, (int) stepsToIncrement); + } + + private static Action ToOnGameThread(Action toConvert) + { + return (val1, val2) => PlayGamesHelperObject.RunOnGameThread(() => toConvert(val1, val2)); + } + + private static BasicApi.Events.Event CreateEvent(AndroidJavaObject eventJava) + { + string id = eventJava.Call("getEventId"); + string name = eventJava.Call("getName"); + string description = eventJava.Call("getDescription"); + string imageUrl = eventJava.Call("getIconImageUrl"); + ulong currentCount = (ulong) eventJava.Call("getValue"); + EventVisibility visibility = eventJava.Call("isVisible") + ? EventVisibility.Revealed + : EventVisibility.Hidden; + return new BasicApi.Events.Event(id, name, description, imageUrl, currentCount, visibility); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs.meta new file mode 100644 index 0000000..c614c38 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidEventsClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 311e1761661a341bebebd422a144b5e8 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs new file mode 100644 index 0000000..4b770e1 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs @@ -0,0 +1,223 @@ +// +// Copyright (C) 2015 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID +namespace GooglePlayGames.Android +{ + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.SavedGame; + using OurUtils; + using UnityEngine; + using System; + using System.Collections.Generic; + + internal class AndroidHelperFragment + { + private const string HelperFragmentClass = "com.google.games.bridge.HelperFragment"; + + public static AndroidJavaObject GetActivity() + { + using (var jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) + { + return jc.GetStatic("currentActivity"); + } + } + + public static AndroidJavaObject GetDefaultPopupView() + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using (var activity = AndroidHelperFragment.GetActivity()) + { + return helperFragment.CallStatic("getDecorView", activity); + } + } + + public static void ShowAchievementsUI(Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using (var task = + helperFragment.CallStatic("showAchievementUi", AndroidHelperFragment.GetActivity())) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + uiCode => + { + OurUtils.Logger.d("ShowAchievementsUI result " + uiCode); + cb.Invoke((UIStatus) uiCode); + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + OurUtils.Logger.e("ShowAchievementsUI failed with exception"); + cb.Invoke(UIStatus.InternalError); + }); + } + } + + public static void ShowCaptureOverlayUI() + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + { + helperFragment.CallStatic("showCaptureOverlayUi", AndroidHelperFragment.GetActivity()); + } + } + + public static void ShowAllLeaderboardsUI(Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using (var task = + helperFragment.CallStatic("showAllLeaderboardsUi", + AndroidHelperFragment.GetActivity())) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + uiCode => + { + OurUtils.Logger.d("ShowAllLeaderboardsUI result " + uiCode); + cb.Invoke((UIStatus) uiCode); + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + OurUtils.Logger.e("ShowAllLeaderboardsUI failed with exception"); + cb.Invoke(UIStatus.InternalError); + }); + } + } + + public static void ShowLeaderboardUI(string leaderboardId, LeaderboardTimeSpan timeSpan, Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using (var task = helperFragment.CallStatic("showLeaderboardUi", + AndroidHelperFragment.GetActivity(), leaderboardId, + AndroidJavaConverter.ToLeaderboardVariantTimeSpan(timeSpan))) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + uiCode => + { + OurUtils.Logger.d("ShowLeaderboardUI result " + uiCode); + cb.Invoke((UIStatus) uiCode); + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + OurUtils.Logger.e("ShowLeaderboardUI failed with exception"); + cb.Invoke(UIStatus.InternalError); + }); + } + } + + public static void ShowCompareProfileWithAlternativeNameHintsUI( + string playerId, string otherPlayerInGameName, string currentPlayerInGameName, + Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using ( + var task = helperFragment.CallStatic( + "showCompareProfileWithAlternativeNameHintsUI", + AndroidHelperFragment.GetActivity(), playerId, otherPlayerInGameName, + currentPlayerInGameName)) + { + AndroidTaskUtils.AddOnSuccessListener(task, uiCode => + { + OurUtils.Logger.d("ShowCompareProfileWithAlternativeNameHintsUI result " + uiCode); + cb.Invoke((UIStatus) uiCode); + }); + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("ShowCompareProfileWithAlternativeNameHintsUI failed with exception"); + cb.Invoke(UIStatus.InternalError); + }); + } + } + + public static void IsResolutionRequired( + AndroidJavaObject friendsSharingConsentException, Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + { + var isResolutionRequired = helperFragment.CallStatic( + "isResolutionRequired", friendsSharingConsentException); + cb.Invoke(isResolutionRequired); + } + } + + public static void AskForLoadFriendsResolution( + AndroidJavaObject friendsSharingConsentException, Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using ( + var task = helperFragment.CallStatic( + "askForLoadFriendsResolution", AndroidHelperFragment.GetActivity(), + friendsSharingConsentException)) + { + AndroidTaskUtils.AddOnSuccessListener(task, uiCode => + { + OurUtils.Logger.d("AskForLoadFriendsResolution result " + uiCode); + cb.Invoke((UIStatus) uiCode); + }); + + AndroidTaskUtils.AddOnFailureListener(task, exception => + { + OurUtils.Logger.e("AskForLoadFriendsResolution failed with exception"); + cb.Invoke(UIStatus.InternalError); + }); + } + } + + public static void ShowSelectSnapshotUI(bool showCreateSaveUI, bool showDeleteSaveUI, + int maxDisplayedSavedGames, string uiTitle, Action cb) + { + using (var helperFragment = new AndroidJavaClass(HelperFragmentClass)) + using (var task = helperFragment.CallStatic("showSelectSnapshotUi", + AndroidHelperFragment.GetActivity(), uiTitle, showCreateSaveUI, showDeleteSaveUI, + maxDisplayedSavedGames)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + result => + { + SelectUIStatus status = (SelectUIStatus) result.Get("status"); + OurUtils.Logger.d("ShowSelectSnapshotUI result " + status); + + AndroidJavaObject javaMetadata = result.Get("metadata"); + AndroidSnapshotMetadata metadata = + javaMetadata == null + ? null + : new AndroidSnapshotMetadata(javaMetadata, /* contents= */null); + + cb.Invoke(status, metadata); + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + OurUtils.Logger.e("ShowSelectSnapshotUI failed with exception"); + cb.Invoke(SelectUIStatus.InternalError, null); + }); + } + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs.meta new file mode 100644 index 0000000..e3c70f4 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidHelperFragment.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 6eb353a6ffa554bacb374cfaf0cc45e7 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs new file mode 100644 index 0000000..f4bd067 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs @@ -0,0 +1,165 @@ +// +// Copyright (C) 2015 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID +namespace GooglePlayGames.Android +{ + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.SavedGame; + using OurUtils; + using UnityEngine; + using UnityEngine.SocialPlatforms; + using System; + using System.Collections.Generic; + + internal class AndroidJavaConverter + { + internal static System.DateTime ToDateTime(long milliseconds) + { + System.DateTime result = new System.DateTime(1970, 1, 1, 0, 0, 0, 0); + return result.AddMilliseconds(milliseconds); + } + + // Convert to LeaderboardVariant.java#TimeSpan + internal static int ToLeaderboardVariantTimeSpan(LeaderboardTimeSpan span) + { + switch (span) + { + case LeaderboardTimeSpan.Daily: + return 0 /* TIME_SPAN_DAILY */; + case LeaderboardTimeSpan.Weekly: + return 1 /* TIME_SPAN_WEEKLY */; + case LeaderboardTimeSpan.AllTime: + default: + return 2 /* TIME_SPAN_ALL_TIME */; + } + } + + // Convert to LeaderboardVariant.java#Collection + internal static int ToLeaderboardVariantCollection(LeaderboardCollection collection) + { + switch (collection) + { + case LeaderboardCollection.Social: + return 3 /* COLLECTION_FRIENDS */; + case LeaderboardCollection.Public: + default: + return 0 /* COLLECTION_PUBLIC */; + } + } + + // Convert to PageDirection.java#Direction + internal static int ToPageDirection(ScorePageDirection direction) + { + switch (direction) + { + case ScorePageDirection.Forward: + return 0 /* NEXT */; + case ScorePageDirection.Backward: + return 1 /* PREV */; + default: + return -1 /* NONE */; + } + } + + internal static Player ToPlayer(AndroidJavaObject player) + { + if (player == null) + { + return null; + } + + string displayName = player.Call("getDisplayName"); + string playerId = player.Call("getPlayerId"); + string avatarUrl = player.Call("getIconImageUrl"); + return new Player(displayName, playerId, avatarUrl); + } + + internal static PlayerProfile ToPlayerProfile(AndroidJavaObject player) { + if (player == null) { + return null; + } + + string displayName = player.Call("getDisplayName"); + string playerId = player.Call("getPlayerId"); + string avatarUrl = player.Call("getIconImageUrl"); + bool isFriend = + player.Call("getRelationshipInfo").Call("getFriendStatus") == + 4 /* PlayerFriendStatus.Friend*/; + return new PlayerProfile(displayName, playerId, avatarUrl, isFriend); + } + + internal static List ToStringList(AndroidJavaObject stringList) + { + if (stringList == null) + { + return new List(); + } + + int size = stringList.Call("size"); + List converted = new List(size); + + for (int i = 0; i < size; i++) + { + converted.Add(stringList.Call("get", i)); + } + + return converted; + } + + // from C#: List to Java: ArrayList + internal static AndroidJavaObject ToJavaStringList(List list) + { + AndroidJavaObject converted = new AndroidJavaObject("java.util.ArrayList"); + for (int i = 0; i < list.Count; i++) + { + converted.Call("add", list[i]); + } + + return converted; + } + + internal static FriendsListVisibilityStatus ToFriendsListVisibilityStatus(int playerListVisibility) { + switch (playerListVisibility) + { + case /* FriendsListVisibilityStatus.UNKNOWN */ 0: + return FriendsListVisibilityStatus.Unknown; + case /* FriendsListVisibilityStatus.VISIBLE */ 1: + return FriendsListVisibilityStatus.Visible; + case /* FriendsListVisibilityStatus.REQUEST_REQUIRED */ 2: + return FriendsListVisibilityStatus.ResolutionRequired; + case /* FriendsListVisibilityStatus.FEATURE_UNAVAILABLE */ 3: + return FriendsListVisibilityStatus.Unavailable; + default: + return FriendsListVisibilityStatus.Unknown; + } + } + + internal static IUserProfile[] playersBufferToArray(AndroidJavaObject playersBuffer) { + int count = playersBuffer.Call("getCount"); + IUserProfile[] users = new IUserProfile[count]; + for (int i = 0; i < count; ++i) { + using (var player = playersBuffer.Call("get", i)) { + users[i] = AndroidJavaConverter.ToPlayerProfile(player); + } + } + + playersBuffer.Call("release"); + return users; + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs.meta new file mode 100644 index 0000000..5e0d641 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidJavaConverter.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: d498c17d61b504b4f984a99b4542d02f +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs new file mode 100644 index 0000000..654488c --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs @@ -0,0 +1,443 @@ +#if UNITY_ANDROID +#pragma warning disable 0642 // Possible mistaken empty statement + +namespace GooglePlayGames.Android +{ + using System; + using System.Collections.Generic; + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.Nearby; + using GooglePlayGames.OurUtils; + using UnityEngine; + + public class AndroidNearbyConnectionClient : INearbyConnectionClient + { + private volatile AndroidJavaObject mClient; + private readonly static long NearbyClientId = 0L; + private readonly static int ApplicationInfoFlags = 0x00000080; + private readonly static string ServiceId = ReadServiceId(); + protected IMessageListener mAdvertisingMessageListener; + + public AndroidNearbyConnectionClient() + { + PlayGamesHelperObject.CreateObject(); + NearbyHelperObject.CreateObject(this); + using (var nearbyClass = new AndroidJavaClass("com.google.android.gms.nearby.Nearby")) + { + mClient = nearbyClass.CallStatic("getConnectionsClient", + AndroidHelperFragment.GetActivity()); + } + } + + public int MaxUnreliableMessagePayloadLength() + { + return NearbyConnectionConfiguration.MaxUnreliableMessagePayloadLength; + } + + public int MaxReliableMessagePayloadLength() + { + return NearbyConnectionConfiguration.MaxReliableMessagePayloadLength; + } + + public void SendReliable(List recipientEndpointIds, byte[] payload) + { + InternalSend(recipientEndpointIds, payload); + } + + public void SendUnreliable(List recipientEndpointIds, byte[] payload) + { + InternalSend(recipientEndpointIds, payload); + } + + private void InternalSend(List recipientEndpointIds, byte[] payload) + { + Misc.CheckNotNull(recipientEndpointIds); + Misc.CheckNotNull(payload); + + using (var payloadClass = new AndroidJavaClass("com.google.android.gms.nearby.connection.Payload")) + using (var payloadObject = payloadClass.CallStatic("fromBytes", payload)) + using (var task = mClient.Call("sendPayload", + AndroidJavaConverter.ToJavaStringList(recipientEndpointIds), + payloadObject)) + ; + } + + public void StartAdvertising(string name, List appIdentifiers, + TimeSpan? advertisingDuration, Action resultCallback, + Action connectionRequestCallback) + { + Misc.CheckNotNull(resultCallback, "resultCallback"); + Misc.CheckNotNull(connectionRequestCallback, "connectionRequestCallback"); + + if (advertisingDuration.HasValue && advertisingDuration.Value.Ticks < 0) + { + throw new InvalidOperationException("advertisingDuration must be positive"); + } + + connectionRequestCallback = ToOnGameThread(connectionRequestCallback); + resultCallback = ToOnGameThread(resultCallback); + + AdvertisingConnectionLifecycleCallbackProxy callbackProxy = + new AdvertisingConnectionLifecycleCallbackProxy(resultCallback, connectionRequestCallback, this); + using (var connectionLifecycleCallback = + new AndroidJavaObject("com.google.games.bridge.ConnectionLifecycleCallbackProxy", callbackProxy)) + using (var advertisingOptions = CreateAdvertisingOptions()) + using (var task = mClient.Call("startAdvertising", name, GetServiceId(), + connectionLifecycleCallback, advertisingOptions)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + v => NearbyHelperObject.StartAdvertisingTimer(advertisingDuration) + ); + } + } + + private AndroidJavaObject CreateAdvertisingOptions() + { + using (var strategy = new AndroidJavaClass("com.google.android.gms.nearby.connection.Strategy") + .GetStatic("P2P_CLUSTER")) + using (var builder = + new AndroidJavaObject("com.google.android.gms.nearby.connection.AdvertisingOptions$Builder")) + using (builder.Call("setStrategy", strategy)) + { + return builder.Call("build"); + } + } + + private class AdvertisingConnectionLifecycleCallbackProxy : AndroidJavaProxy + { + private Action mResultCallback; + private Action mConnectionRequestCallback; + private AndroidNearbyConnectionClient mClient; + private string mLocalEndpointName; + + public AdvertisingConnectionLifecycleCallbackProxy(Action resultCallback, + Action connectionRequestCallback, AndroidNearbyConnectionClient client) : base( + "com/google/games/bridge/ConnectionLifecycleCallbackProxy$Callback") + { + mResultCallback = resultCallback; + mConnectionRequestCallback = connectionRequestCallback; + mClient = client; + } + + public void onConnectionInitiated(string endpointId, AndroidJavaObject connectionInfo) + { + mLocalEndpointName = connectionInfo.Call("getEndpointName"); + mConnectionRequestCallback(new ConnectionRequest(endpointId, mLocalEndpointName, mClient.GetServiceId(), + new byte[0])); + } + + public void onConnectionResult(string endpointId, AndroidJavaObject connectionResolution) + { + int statusCode; + using (var status = connectionResolution.Call("getStatus")) + { + statusCode = status.Call("getStatusCode"); + } + + if (statusCode == 0) // STATUS_OK + { + mResultCallback(new AdvertisingResult(ResponseStatus.Success, mLocalEndpointName)); + return; + } + + if (statusCode == 8001) // STATUS_ALREADY_ADVERTISING + { + mResultCallback(new AdvertisingResult(ResponseStatus.NotAuthorized, mLocalEndpointName)); + return; + } + + mResultCallback(new AdvertisingResult(ResponseStatus.InternalError, mLocalEndpointName)); + } + + public void onDisconnected(string endpointId) + { + if (mClient.mAdvertisingMessageListener != null) + { + mClient.mAdvertisingMessageListener.OnRemoteEndpointDisconnected(endpointId); + } + } + } + + public void StopAdvertising() + { + mClient.Call("stopAdvertising"); + mAdvertisingMessageListener = null; + } + + public void SendConnectionRequest(string name, string remoteEndpointId, byte[] payload, + Action responseCallback, IMessageListener listener) + { + Misc.CheckNotNull(listener, "listener"); + var listenerOnGameThread = new OnGameThreadMessageListener(listener); + DiscoveringConnectionLifecycleCallback cb = + new DiscoveringConnectionLifecycleCallback(responseCallback, listenerOnGameThread, mClient); + using (var connectionLifecycleCallback = + new AndroidJavaObject("com.google.games.bridge.ConnectionLifecycleCallbackProxy", cb)) + using (mClient.Call("requestConnection", name, remoteEndpointId, + connectionLifecycleCallback)) + ; + } + + public void AcceptConnectionRequest(string remoteEndpointId, byte[] payload, IMessageListener listener) + { + Misc.CheckNotNull(listener, "listener"); + mAdvertisingMessageListener = new OnGameThreadMessageListener(listener); + + using (var payloadCallback = new AndroidJavaObject("com.google.games.bridge.PayloadCallbackProxy", + new PayloadCallback(listener))) + using (mClient.Call("acceptConnection", remoteEndpointId, payloadCallback)) + ; + } + + private class PayloadCallback : AndroidJavaProxy + { + private IMessageListener mListener; + + public PayloadCallback(IMessageListener listener) : base( + "com/google/games/bridge/PayloadCallbackProxy$Callback") + { + mListener = listener; + } + + public void onPayloadReceived(String endpointId, AndroidJavaObject payload) + { + if (payload.Call("getType") != 1) // 1 for BYTES + { + return; + } + + mListener.OnMessageReceived(endpointId, payload.Call("asBytes"), /* isReliableMessage */ true); + } + } + + public void StartDiscovery(string serviceId, TimeSpan? advertisingDuration, + IDiscoveryListener listener) + { + Misc.CheckNotNull(serviceId, "serviceId"); + Misc.CheckNotNull(listener, "listener"); + + var listenerOnGameThread = new OnGameThreadDiscoveryListener(listener); + + if (advertisingDuration.HasValue && advertisingDuration.Value.Ticks < 0) + { + throw new InvalidOperationException("advertisingDuration must be positive"); + } + + using (var endpointDiscoveryCallback = new AndroidJavaObject( + "com.google.games.bridge.EndpointDiscoveryCallbackProxy", + new EndpointDiscoveryCallback(listenerOnGameThread))) + using (var discoveryOptions = CreateDiscoveryOptions()) + using (var task = mClient.Call("startDiscovery", serviceId, endpointDiscoveryCallback, + discoveryOptions)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + v => NearbyHelperObject.StartDiscoveryTimer(advertisingDuration) + ); + } + } + + private class DiscoveringConnectionLifecycleCallback : AndroidJavaProxy + { + private Action mResponseCallback; + private IMessageListener mListener; + private AndroidJavaObject mClient; + + public DiscoveringConnectionLifecycleCallback(Action responseCallback, + IMessageListener listener, AndroidJavaObject client) : base( + "com/google/games/bridge/ConnectionLifecycleCallbackProxy$Callback") + { + mResponseCallback = responseCallback; + mListener = listener; + mClient = client; + } + + public void onConnectionInitiated(string endpointId, AndroidJavaObject connectionInfo) + { + using (var payloadCallback = new AndroidJavaObject("com.google.games.bridge.PayloadCallbackProxy", + new PayloadCallback(mListener))) + using (mClient.Call("acceptConnection", endpointId, payloadCallback)) + ; + } + + public void onConnectionResult(string endpointId, AndroidJavaObject connectionResolution) + { + int statusCode; + using (var status = connectionResolution.Call("getStatus")) + { + statusCode = status.Call("getStatusCode"); + } + + if (statusCode == 0) // STATUS_OK + { + mResponseCallback(ConnectionResponse.Accepted(NearbyClientId, endpointId, new byte[0])); + return; + } + + if (statusCode == 8002) // STATUS_ALREADY_DISCOVERING + { + mResponseCallback(ConnectionResponse.AlreadyConnected(NearbyClientId, endpointId)); + return; + } + + mResponseCallback(ConnectionResponse.Rejected(NearbyClientId, endpointId)); + } + + public void onDisconnected(string endpointId) + { + mListener.OnRemoteEndpointDisconnected(endpointId); + } + } + + private AndroidJavaObject CreateDiscoveryOptions() + { + using (var strategy = + new AndroidJavaClass("com.google.android.gms.nearby.connection.Strategy").GetStatic( + "P2P_CLUSTER")) + using (var builder = + new AndroidJavaObject("com.google.android.gms.nearby.connection.DiscoveryOptions$Builder")) + using (builder.Call("setStrategy", strategy)) + { + return builder.Call("build"); + } + } + + private class EndpointDiscoveryCallback : AndroidJavaProxy + { + private IDiscoveryListener mListener; + + public EndpointDiscoveryCallback(IDiscoveryListener listener) : base( + "com/google/games/bridge/EndpointDiscoveryCallbackProxy$Callback") + { + mListener = listener; + } + + public void onEndpointFound(string endpointId, AndroidJavaObject endpointInfo) + { + mListener.OnEndpointFound(CreateEndPointDetails(endpointId, endpointInfo)); + } + + public void onEndpointLost(string endpointId) + { + mListener.OnEndpointLost(endpointId); + } + + private EndpointDetails CreateEndPointDetails(string endpointId, AndroidJavaObject endpointInfo) + { + return new EndpointDetails( + endpointId, + endpointInfo.Call("getEndpointName"), + endpointInfo.Call("getServiceId") + ); + } + } + + private class OnGameThreadMessageListener : IMessageListener + { + private readonly IMessageListener mListener; + + public OnGameThreadMessageListener(IMessageListener listener) + { + mListener = Misc.CheckNotNull(listener); + } + + public void OnMessageReceived(string remoteEndpointId, byte[] data, + bool isReliableMessage) + { + PlayGamesHelperObject.RunOnGameThread(() => mListener.OnMessageReceived( + remoteEndpointId, data, isReliableMessage)); + } + + public void OnRemoteEndpointDisconnected(string remoteEndpointId) + { + PlayGamesHelperObject.RunOnGameThread( + () => mListener.OnRemoteEndpointDisconnected(remoteEndpointId)); + } + } + + private class OnGameThreadDiscoveryListener : IDiscoveryListener + { + private readonly IDiscoveryListener mListener; + + public OnGameThreadDiscoveryListener(IDiscoveryListener listener) + { + mListener = listener; + } + + public void OnEndpointFound(EndpointDetails discoveredEndpoint) + { + PlayGamesHelperObject.RunOnGameThread(() => mListener.OnEndpointFound(discoveredEndpoint)); + } + + public void OnEndpointLost(string lostEndpointId) + { + PlayGamesHelperObject.RunOnGameThread(() => mListener.OnEndpointLost(lostEndpointId)); + } + } + + public void StopDiscovery(string serviceId) + { + mClient.Call("stopDiscovery"); + } + + public void RejectConnectionRequest(string requestingEndpointId) + { + Misc.CheckNotNull(requestingEndpointId, "requestingEndpointId"); + using (var task = mClient.Call("rejectConnection", requestingEndpointId)) ; + } + + public void DisconnectFromEndpoint(string remoteEndpointId) + { + mClient.Call("disconnectFromEndpoint", remoteEndpointId); + } + + public void StopAllConnections() + { + mClient.Call("stopAllEndpoints"); + mAdvertisingMessageListener = null; + } + + public string GetAppBundleId() + { + using (var activity = AndroidHelperFragment.GetActivity()) + { + return activity.Call("getPackageName"); + } + } + + public string GetServiceId() + { + return ServiceId; + } + + private static string ReadServiceId() + { + using (var activity = AndroidHelperFragment.GetActivity()) + { + string packageName = activity.Call("getPackageName"); + using (var pm = activity.Call("getPackageManager")) + using (var appInfo = + pm.Call("getApplicationInfo", packageName, ApplicationInfoFlags)) + using (var bundle = appInfo.Get("metaData")) + { + string sysId = bundle.Call("getString", + "com.google.android.gms.nearby.connection.SERVICE_ID"); + OurUtils.Logger.d("SystemId from Manifest: " + sysId); + return sysId; + } + } + } + + private static Action ToOnGameThread(Action toConvert) + { + return (val) => PlayGamesHelperObject.RunOnGameThread(() => toConvert(val)); + } + + private static Action ToOnGameThread(Action toConvert) + { + return (val1, val2) => PlayGamesHelperObject.RunOnGameThread(() => toConvert(val1, val2)); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs.meta new file mode 100644 index 0000000..44c87b9 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidNearbyConnectionClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: d69ac0a61e8943ff82b14f7469f0fe97 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs new file mode 100644 index 0000000..0a0616f --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs @@ -0,0 +1,526 @@ +#if UNITY_ANDROID +#pragma warning disable 0642 // Possible mistaken empty statement + +namespace GooglePlayGames.Android +{ + using System; + using System.Collections.Generic; + using System.Text.RegularExpressions; + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.SavedGame; + using GooglePlayGames.OurUtils; + using UnityEngine; + + internal class AndroidSavedGameClient : ISavedGameClient + { + // Regex for a valid filename. Valid file names are between 1 and 100 characters (inclusive) + // and only include URL-safe characters: a-z, A-Z, 0-9, or the symbols "-", ".", "_", or "~". + // This regex is guarded by \A and \Z which guarantee that the entire string matches this + // regex. If these were omitted, then illegal strings containing legal subsequences would be + // allowed (since the regex would match those subsequences). + private static readonly Regex ValidFilenameRegex = new Regex(@"\A[a-zA-Z0-9-._~]{1,100}\Z"); + + private volatile AndroidJavaObject mSnapshotsClient; + private volatile AndroidClient mAndroidClient; + + public AndroidSavedGameClient(AndroidClient androidClient) + { + mAndroidClient = androidClient; + using (var gamesClass = new AndroidJavaClass("com.google.android.gms.games.PlayGames")) + { + mSnapshotsClient = gamesClass.CallStatic("getSnapshotsClient", + AndroidHelperFragment.GetActivity()); + } + } + + public void OpenWithAutomaticConflictResolution(string filename, DataSource source, + ConflictResolutionStrategy resolutionStrategy, + Action completedCallback) + { + Misc.CheckNotNull(filename); + Misc.CheckNotNull(completedCallback); + bool prefetchDataOnConflict = false; + ConflictCallback conflictCallback = null; + completedCallback = ToOnGameThread(completedCallback); + + if (conflictCallback == null) + { + conflictCallback = (resolver, original, originalData, unmerged, unmergedData) => + { + switch (resolutionStrategy) + { + case ConflictResolutionStrategy.UseOriginal: + resolver.ChooseMetadata(original); + return; + case ConflictResolutionStrategy.UseUnmerged: + resolver.ChooseMetadata(unmerged); + return; + case ConflictResolutionStrategy.UseLongestPlaytime: + if (original.TotalTimePlayed >= unmerged.TotalTimePlayed) + { + resolver.ChooseMetadata(original); + } + else + { + resolver.ChooseMetadata(unmerged); + } + + return; + default: + OurUtils.Logger.e("Unhandled strategy " + resolutionStrategy); + completedCallback(SavedGameRequestStatus.InternalError, null); + return; + } + }; + } + + conflictCallback = ToOnGameThread(conflictCallback); + + if (!IsValidFilename(filename)) + { + OurUtils.Logger.e("Received invalid filename: " + filename); + completedCallback(SavedGameRequestStatus.BadInputError, null); + return; + } + + InternalOpen(filename, source, resolutionStrategy, prefetchDataOnConflict, conflictCallback, + completedCallback); + } + + public void OpenWithManualConflictResolution(string filename, DataSource source, bool prefetchDataOnConflict, + ConflictCallback conflictCallback, Action completedCallback) + { + Misc.CheckNotNull(filename); + Misc.CheckNotNull(conflictCallback); + Misc.CheckNotNull(completedCallback); + + conflictCallback = ToOnGameThread(conflictCallback); + completedCallback = ToOnGameThread(completedCallback); + + if (!IsValidFilename(filename)) + { + OurUtils.Logger.e("Received invalid filename: " + filename); + completedCallback(SavedGameRequestStatus.BadInputError, null); + return; + } + + InternalOpen(filename, source, ConflictResolutionStrategy.UseManual, prefetchDataOnConflict, + conflictCallback, completedCallback); + } + + private void InternalOpen(string filename, DataSource source, ConflictResolutionStrategy resolutionStrategy, + bool prefetchDataOnConflict, ConflictCallback conflictCallback, + Action completedCallback) + { + int conflictPolicy; // SnapshotsClient.java#RetentionPolicy + switch (resolutionStrategy) + { + case ConflictResolutionStrategy.UseLastKnownGood: + conflictPolicy = 2 /* RESOLUTION_POLICY_LAST_KNOWN_GOOD */; + break; + case ConflictResolutionStrategy.UseMostRecentlySaved: + conflictPolicy = 3 /* RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED */; + break; + case ConflictResolutionStrategy.UseLongestPlaytime: + conflictPolicy = 1 /* RESOLUTION_POLICY_LONGEST_PLAYTIME*/; + break; + case ConflictResolutionStrategy.UseManual: + conflictPolicy = -1 /* RESOLUTION_POLICY_MANUAL */; + break; + default: + conflictPolicy = 3 /* RESOLUTION_POLICY_MOST_RECENTLY_MODIFIED */; + break; + } + + using (var task = + mSnapshotsClient.Call("open", filename, /* createIfNotFound= */ true, + conflictPolicy)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + dataOrConflict => + { + if (dataOrConflict.Call("isConflict")) + { + var conflict = dataOrConflict.Call("getConflict"); + AndroidSnapshotMetadata original = + new AndroidSnapshotMetadata(conflict.Call("getSnapshot")); + AndroidSnapshotMetadata unmerged = + new AndroidSnapshotMetadata( + conflict.Call("getConflictingSnapshot")); + + // Instantiate the conflict resolver. Note that the retry callback closes over + // all the parameters we need to retry the open attempt. Once the conflict is + // resolved by invoking the appropriate resolution method on + // AndroidConflictResolver, the resolver will invoke this callback, which will + // result in this method being re-executed. This recursion will continue until + // all conflicts are resolved or an error occurs. + AndroidConflictResolver resolver = new AndroidConflictResolver( + this, + mSnapshotsClient, + conflict, + original, + unmerged, + completedCallback, + () => InternalOpen(filename, source, resolutionStrategy, + prefetchDataOnConflict, + conflictCallback, completedCallback)); + + var originalBytes = original.JavaContents.Call("readFully"); + var unmergedBytes = unmerged.JavaContents.Call("readFully"); + conflictCallback(resolver, original, originalBytes, unmerged, unmergedBytes); + } + else + { + using (var snapshot = dataOrConflict.Call("getData")) + { + AndroidJavaObject metadata = snapshot.Call("freeze"); + completedCallback(SavedGameRequestStatus.Success, + new AndroidSnapshotMetadata(metadata)); + } + } + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => { + OurUtils.Logger.d("InternalOpen has failed: " + exception.Call("toString")); + var status = mAndroidClient.IsAuthenticated() ? + SavedGameRequestStatus.InternalError : + SavedGameRequestStatus.AuthenticationError; + completedCallback(status, null); + } + ); + } + } + + public void ReadBinaryData(ISavedGameMetadata metadata, + Action completedCallback) + { + Misc.CheckNotNull(metadata); + Misc.CheckNotNull(completedCallback); + completedCallback = ToOnGameThread(completedCallback); + + AndroidSnapshotMetadata convertedMetadata = metadata as AndroidSnapshotMetadata; + + if (convertedMetadata == null) + { + OurUtils.Logger.e("Encountered metadata that was not generated by this ISavedGameClient"); + completedCallback(SavedGameRequestStatus.BadInputError, null); + return; + } + + if (!convertedMetadata.IsOpen) + { + OurUtils.Logger.e("This method requires an open ISavedGameMetadata."); + completedCallback(SavedGameRequestStatus.BadInputError, null); + return; + } + + byte[] data = convertedMetadata.JavaContents.Call("readFully"); + if (data == null) + { + completedCallback(SavedGameRequestStatus.BadInputError, null); + } + else + { + completedCallback(SavedGameRequestStatus.Success, data); + } + } + + public void ShowSelectSavedGameUI(string uiTitle, uint maxDisplayedSavedGames, bool showCreateSaveUI, + bool showDeleteSaveUI, Action callback) + { + Misc.CheckNotNull(uiTitle); + Misc.CheckNotNull(callback); + + callback = ToOnGameThread(callback); + + if (!(maxDisplayedSavedGames > 0)) + { + OurUtils.Logger.e("maxDisplayedSavedGames must be greater than 0"); + callback(SelectUIStatus.BadInputError, null); + return; + } + + AndroidHelperFragment.ShowSelectSnapshotUI( + showCreateSaveUI, showDeleteSaveUI, (int) maxDisplayedSavedGames, uiTitle, callback); + } + + public void CommitUpdate(ISavedGameMetadata metadata, SavedGameMetadataUpdate updateForMetadata, + byte[] updatedBinaryData, Action callback) + { + Misc.CheckNotNull(metadata); + Misc.CheckNotNull(updatedBinaryData); + Misc.CheckNotNull(callback); + + callback = ToOnGameThread(callback); + + AndroidSnapshotMetadata convertedMetadata = metadata as AndroidSnapshotMetadata; + + if (convertedMetadata == null) + { + OurUtils.Logger.e("Encountered metadata that was not generated by this ISavedGameClient"); + callback(SavedGameRequestStatus.BadInputError, null); + return; + } + + if (!convertedMetadata.IsOpen) + { + OurUtils.Logger.e("This method requires an open ISavedGameMetadata."); + callback(SavedGameRequestStatus.BadInputError, null); + return; + } + + if (!convertedMetadata.JavaContents.Call("writeBytes", updatedBinaryData)) + { + OurUtils.Logger.e("This method requires an open ISavedGameMetadata."); + callback(SavedGameRequestStatus.BadInputError, null); + } + + using (var convertedMetadataChange = AsMetadataChange(updateForMetadata)) + using (var task = mSnapshotsClient.Call("commitAndClose", convertedMetadata.JavaSnapshot, + convertedMetadataChange)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + /* disposeResult= */ false, + snapshotMetadata => + { + OurUtils.Logger.d("commitAndClose.succeed"); + callback(SavedGameRequestStatus.Success, + new AndroidSnapshotMetadata(snapshotMetadata, /* contents= */null)); + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => + { + OurUtils.Logger.e("commitAndClose.failed: " + exception.Call("toString")); + var status = mAndroidClient.IsAuthenticated() ? + SavedGameRequestStatus.InternalError : + SavedGameRequestStatus.AuthenticationError; + callback(status, null); + }); + } + } + + public void FetchAllSavedGames(DataSource source, + Action> callback) + { + Misc.CheckNotNull(callback); + + callback = ToOnGameThread(callback); + + using (var task = + mSnapshotsClient.Call("load", /* forecReload= */ + source == DataSource.ReadNetworkOnly)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + annotatedData => + { + using (var buffer = annotatedData.Call("get")) + { + int count = buffer.Call("getCount"); + List result = new List(); + for (int i = 0; i < count; ++i) + { + using (var metadata = buffer.Call("get", i)) + { + result.Add(new AndroidSnapshotMetadata( + metadata.Call("freeze"), /* contents= */null)); + } + } + + buffer.Call("release"); + callback(SavedGameRequestStatus.Success, result); + } + }); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => { + OurUtils.Logger.d("FetchAllSavedGames failed: " + exception.Call("toString")); + var status = mAndroidClient.IsAuthenticated() ? + SavedGameRequestStatus.InternalError : + SavedGameRequestStatus.AuthenticationError; + callback(status, new List()); + } + ); + } + } + + public void Delete(ISavedGameMetadata metadata) + { + AndroidSnapshotMetadata androidMetadata = metadata as AndroidSnapshotMetadata; + Misc.CheckNotNull(androidMetadata); + using (mSnapshotsClient.Call("delete", androidMetadata.JavaMetadata)) ; + } + + private ConflictCallback ToOnGameThread(ConflictCallback conflictCallback) + { + return (resolver, original, originalData, unmerged, unmergedData) => + { + OurUtils.Logger.d("Invoking conflict callback"); + PlayGamesHelperObject.RunOnGameThread(() => + conflictCallback(resolver, original, originalData, unmerged, unmergedData)); + }; + } + + /// + /// A helper class that encapsulates the state around resolving a file conflict. It holds all + /// the state that is necessary to invoke as well as a + /// callback that will re-attempt to open the file after the resolution concludes. + /// + private class AndroidConflictResolver : IConflictResolver + { + private readonly AndroidJavaObject mSnapshotsClient; + private readonly AndroidJavaObject mConflict; + private readonly AndroidSnapshotMetadata mOriginal; + private readonly AndroidSnapshotMetadata mUnmerged; + private readonly Action mCompleteCallback; + private readonly Action mRetryFileOpen; + + private readonly AndroidSavedGameClient mAndroidSavedGameClient; + + internal AndroidConflictResolver(AndroidSavedGameClient androidSavedGameClient, AndroidJavaObject snapshotClient, AndroidJavaObject conflict, + AndroidSnapshotMetadata original, AndroidSnapshotMetadata unmerged, + Action completeCallback, Action retryOpen) + { + this.mAndroidSavedGameClient = androidSavedGameClient; + this.mSnapshotsClient = Misc.CheckNotNull(snapshotClient); + this.mConflict = Misc.CheckNotNull(conflict); + this.mOriginal = Misc.CheckNotNull(original); + this.mUnmerged = Misc.CheckNotNull(unmerged); + this.mCompleteCallback = Misc.CheckNotNull(completeCallback); + this.mRetryFileOpen = Misc.CheckNotNull(retryOpen); + } + + public void ResolveConflict(ISavedGameMetadata chosenMetadata, SavedGameMetadataUpdate metadataUpdate, + byte[] updatedData) + { + AndroidSnapshotMetadata convertedMetadata = chosenMetadata as AndroidSnapshotMetadata; + + if (convertedMetadata != mOriginal && convertedMetadata != mUnmerged) + { + OurUtils.Logger.e("Caller attempted to choose a version of the metadata that was not part " + + "of the conflict"); + mCompleteCallback(SavedGameRequestStatus.BadInputError, null); + return; + } + + using (var contentUpdate = mConflict.Call("getResolutionSnapshotContents")) + { + if (!contentUpdate.Call("writeBytes", updatedData)) + { + OurUtils.Logger.e("Can't update snapshot contents during conflict resolution."); + mCompleteCallback(SavedGameRequestStatus.BadInputError, null); + } + + using (var convertedMetadataChange = AsMetadataChange(metadataUpdate)) + using (var task = mSnapshotsClient.Call( + "resolveConflict", + mConflict.Call("getConflictId"), + convertedMetadata.JavaMetadata.Call("getSnapshotId"), + convertedMetadataChange, + contentUpdate)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + dataOrConflict => mRetryFileOpen()); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => { + OurUtils.Logger.d("ResolveConflict failed: " + exception.Call("toString")); + var status = mAndroidSavedGameClient.mAndroidClient.IsAuthenticated() ? + SavedGameRequestStatus.InternalError : + SavedGameRequestStatus.AuthenticationError; + mCompleteCallback(status, null); + } + ); + } + } + } + + public void ChooseMetadata(ISavedGameMetadata chosenMetadata) + { + AndroidSnapshotMetadata convertedMetadata = chosenMetadata as AndroidSnapshotMetadata; + + if (convertedMetadata != mOriginal && convertedMetadata != mUnmerged) + { + OurUtils.Logger.e("Caller attempted to choose a version of the metadata that was not part " + + "of the conflict"); + mCompleteCallback(SavedGameRequestStatus.BadInputError, null); + return; + } + + using (var task = mSnapshotsClient.Call( + "resolveConflict", mConflict.Call("getConflictId"), convertedMetadata.JavaSnapshot)) + { + AndroidTaskUtils.AddOnSuccessListener( + task, + dataOrConflict => mRetryFileOpen()); + + AndroidTaskUtils.AddOnFailureListener( + task, + exception => { + OurUtils.Logger.d("ChooseMetadata failed: " + exception.Call("toString")); + var status = mAndroidSavedGameClient.mAndroidClient.IsAuthenticated() ? + SavedGameRequestStatus.InternalError : + SavedGameRequestStatus.AuthenticationError; + mCompleteCallback(status, null); + } + ); + } + } + } + + internal static bool IsValidFilename(string filename) + { + if (filename == null) + { + return false; + } + + return ValidFilenameRegex.IsMatch(filename); + } + + private static AndroidJavaObject AsMetadataChange(SavedGameMetadataUpdate update) + { + using (var builder = + new AndroidJavaObject("com.google.android.gms.games.snapshot.SnapshotMetadataChange$Builder")) + { + if (update.IsCoverImageUpdated) + { + using (var bitmapFactory = new AndroidJavaClass("android.graphics.BitmapFactory")) + using (var bitmap = bitmapFactory.CallStatic( + "decodeByteArray", update.UpdatedPngCoverImage, /* offset= */0, + update.UpdatedPngCoverImage.Length)) + using (builder.Call("setCoverImage", bitmap)) + ; + } + + if (update.IsDescriptionUpdated) + { + using (builder.Call("setDescription", update.UpdatedDescription)) ; + } + + if (update.IsPlayedTimeUpdated) + { + using (builder.Call("setPlayedTimeMillis", + Convert.ToInt64(update.UpdatedPlayedTime.Value.TotalMilliseconds))) ; + } + + return builder.Call("build"); + } + } + + private static Action ToOnGameThread(Action toConvert) + { + return (val1, val2) => PlayGamesHelperObject.RunOnGameThread(() => toConvert(val1, val2)); + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs.meta new file mode 100644 index 0000000..3e7d014 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSavedGameClient.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a52ca79a06d83464e89d0d052c9af7d9 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs new file mode 100644 index 0000000..23623fb --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs @@ -0,0 +1,90 @@ +#if UNITY_ANDROID + +namespace GooglePlayGames.Android +{ + using System; + using System.Collections.Generic; + using GooglePlayGames.BasicApi; + using GooglePlayGames.BasicApi.SavedGame; + using UnityEngine; + + internal class AndroidSnapshotMetadata : ISavedGameMetadata + { + private AndroidJavaObject mJavaSnapshot; + private AndroidJavaObject mJavaMetadata; + private AndroidJavaObject mJavaContents; + + public AndroidSnapshotMetadata(AndroidJavaObject javaSnapshot) + { + mJavaSnapshot = javaSnapshot; + mJavaMetadata = javaSnapshot.Call("getMetadata"); + mJavaContents = javaSnapshot.Call("getSnapshotContents"); + } + + public AndroidSnapshotMetadata(AndroidJavaObject javaMetadata, AndroidJavaObject javaContents) + { + mJavaSnapshot = null; + mJavaMetadata = javaMetadata; + mJavaContents = javaContents; + } + + public AndroidJavaObject JavaSnapshot + { + get { return mJavaSnapshot; } + } + + public AndroidJavaObject JavaMetadata + { + get { return mJavaMetadata; } + } + + public AndroidJavaObject JavaContents + { + get { return mJavaContents; } + } + + public bool IsOpen + { + get + { + if (mJavaContents == null) + { + return false; + } + + return !mJavaContents.Call("isClosed"); + } + } + + public string Filename + { + get { return mJavaMetadata.Call("getUniqueName"); } + } + + public string Description + { + get { return mJavaMetadata.Call("getDescription"); } + } + + public string CoverImageURL + { + get { return mJavaMetadata.Call("getCoverImageUrl"); } + } + + public TimeSpan TotalTimePlayed + { + get { return TimeSpan.FromMilliseconds(mJavaMetadata.Call("getPlayedTime")); } + } + + public DateTime LastModifiedTimestamp + { + get + { + long timestamp = mJavaMetadata.Call("getLastModifiedTimestamp"); + System.DateTime lastModifiedTime = AndroidJavaConverter.ToDateTime(timestamp); + return lastModifiedTime; + } + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs.meta new file mode 100644 index 0000000..f8b9599 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidSnapshotMetadata.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 330ac7fa11d9a4bc099f0db5a3c26ad7 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs new file mode 100644 index 0000000..4740cae --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs @@ -0,0 +1,111 @@ +#if UNITY_ANDROID +#pragma warning disable 0642 // Possible mistaken empty statement + +namespace GooglePlayGames.Android +{ + using UnityEngine; + using System; + + class AndroidTaskUtils + { + private AndroidTaskUtils() + { + } + + public static void AddOnSuccessListener(AndroidJavaObject task, Action callback) + { + using (task.Call("addOnSuccessListener", + new TaskOnSuccessProxy(callback, /* disposeResult= */ true))) ; + } + + public static void AddOnSuccessListener(AndroidJavaObject task, bool disposeResult, Action callback) + { + using (task.Call("addOnSuccessListener", + new TaskOnSuccessProxy(callback, disposeResult))) ; + } + + public static void AddOnFailureListener(AndroidJavaObject task, Action callback) + { + using (task.Call("addOnFailureListener", new TaskOnFailedProxy(callback))) ; + } + + public static void AddOnCompleteListener(AndroidJavaObject task, Action callback) + { + using (task.Call("addOnCompleteListener", new TaskOnCompleteProxy(callback))) ; + } + + private class TaskOnCompleteProxy : AndroidJavaProxy + { + private Action mCallback; + + public TaskOnCompleteProxy(Action callback) + : base("com/google/android/gms/tasks/OnCompleteListener") + { + mCallback = callback; + } + + public void onComplete(T result) + { + if (result is IDisposable) + { + using ((IDisposable) result) + { + mCallback(result); + } + } + else + { + mCallback(result); + } + } + } + + private class TaskOnSuccessProxy : AndroidJavaProxy + { + private Action mCallback; + private bool mDisposeResult; + + public TaskOnSuccessProxy(Action callback, bool disposeResult) + : base("com/google/android/gms/tasks/OnSuccessListener") + { + mCallback = callback; + mDisposeResult = disposeResult; + } + + public void onSuccess(T result) + { + if (result is IDisposable && mDisposeResult) + { + using ((IDisposable) result) + { + mCallback(result); + } + } + else + { + mCallback(result); + } + } + } + + private class TaskOnFailedProxy : AndroidJavaProxy + { + private Action mCallback; + + public TaskOnFailedProxy(Action callback) + : base("com/google/android/gms/tasks/OnFailureListener") + { + mCallback = callback; + } + + public void onFailure(AndroidJavaObject exception) + { + using (exception) + { + mCallback(exception); + } + } + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs.meta new file mode 100644 index 0000000..20d0150 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/Android/AndroidTaskUtils.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 5d045a29538404b2da664bb55de949de +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs new file mode 100644 index 0000000..2122714 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs @@ -0,0 +1,41 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Android only feature + +#if (UNITY_ANDROID) +namespace GooglePlayGames +{ + using UnityEngine; + using System; + using GooglePlayGames.OurUtils; + using GooglePlayGames.BasicApi.Nearby; + + public static class NearbyConnectionClientFactory + { + public static void Create(Action callback) + { + if (Application.isEditor) + { + GooglePlayGames.OurUtils.Logger.d("Creating INearbyConnection in editor, using DummyClient."); + callback.Invoke(new GooglePlayGames.BasicApi.Nearby.DummyNearbyConnectionClient()); + } + + callback.Invoke(new GooglePlayGames.Android.AndroidNearbyConnectionClient()); + } + } +} +#endif //UNITY_ANDROID \ No newline at end of file diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs.meta new file mode 100644 index 0000000..4376426 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/NearbyConnectionClientFactory.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: ff1201bd0205943ba9c881e50e38156b +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs new file mode 100644 index 0000000..0c1ca52 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs @@ -0,0 +1,44 @@ +// +// Copyright (C) 2014 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if UNITY_ANDROID + +namespace GooglePlayGames +{ + using UnityEngine; + using GooglePlayGames.BasicApi; + using GooglePlayGames.OurUtils; + + internal class PlayGamesClientFactory + { + internal static IPlayGamesClient GetPlatformPlayGamesClient() + { + if (Application.isEditor) + { + GooglePlayGames.OurUtils.Logger.d("Creating IPlayGamesClient in editor, using DummyClient."); + return new GooglePlayGames.BasicApi.DummyClient(); + } +#if UNITY_ANDROID + GooglePlayGames.OurUtils.Logger.d("Creating Android IPlayGamesClient Client"); + return new GooglePlayGames.Android.AndroidClient(); +#else + GooglePlayGames.OurUtils.Logger.d("Cannot create IPlayGamesClient for unknown platform, returning DummyClient"); + return new GooglePlayGames.BasicApi.DummyClient(); +#endif + } + } +} +#endif diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs.meta new file mode 100644 index 0000000..5955d82 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/Platforms/PlayGamesClientFactory.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 435fc2d0dc0ba475e9c8b0796303d6dd +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs new file mode 100644 index 0000000..eaf6820 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs @@ -0,0 +1,26 @@ +// +// Copyright (C) 2014 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +namespace GooglePlayGames +{ + public class PluginVersion + { + // Current Version. + public const int VersionInt = 0x01101; + public const string VersionString = "0.11.01"; + public const string VersionKey = "01101" ; + } +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs.meta new file mode 100644 index 0000000..156d4e6 --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/Runtime/Scripts/PluginVersion.cs.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 4539142948daf4a26bf9cd6870ffa0b2 +labels: +- gvh +- gvh_version-0.11.01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json new file mode 100644 index 0000000..5b29d7a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json @@ -0,0 +1,11 @@ +{ + "name": "com.google.play.games", + "displayName": "Google Play Games", + "description": "The Google Play Games plugin for Unity allows you to access the Google Play Games API through Unity's social interface.", + "version": "0.11.01", + "unity": "2018.4", + "author": { + "name": "Google LLC" + }, + "dependencies": {} +} diff --git a/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json.meta b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json.meta new file mode 100644 index 0000000..ce3f10a --- /dev/null +++ b/Assets/Samples/Dependencies/GooglePlayGames/com.google.play.games/package.json.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 51dd7d46faed94b31a71d5f4cec6ce14 +labels: +- gvh +- gvh_version-0.11.01 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Plugins.meta b/Assets/Samples/Dependencies/Plugins.meta new file mode 100644 index 0000000..a89ab6c --- /dev/null +++ b/Assets/Samples/Dependencies/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 19bfd950d9e6d4bb1b13ecb8dc739b73 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Plugins/Android.meta b/Assets/Samples/Dependencies/Plugins/Android.meta new file mode 100644 index 0000000..6f6f734 --- /dev/null +++ b/Assets/Samples/Dependencies/Plugins/Android.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e6b37cd2cb2484dcab0f936296cbd572 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Plugins/Android/GooglePlayGamesManifest.androidlib.meta b/Assets/Samples/Dependencies/Plugins/Android/GooglePlayGamesManifest.androidlib.meta new file mode 100644 index 0000000..5aa7f48 --- /dev/null +++ b/Assets/Samples/Dependencies/Plugins/Android/GooglePlayGamesManifest.androidlib.meta @@ -0,0 +1,27 @@ +fileFormatVersion: 2 +guid: 42ea4fa720b3e4b0fa39a2c65e9a46f1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Dependencies/Plugins/Android/GooglePlayGamesManifest.androidlib/AndroidManifest.xml b/Assets/Samples/Dependencies/Plugins/Android/GooglePlayGamesManifest.androidlib/AndroidManifest.xml new file mode 100644 index 0000000..62b24a0 --- /dev/null +++ b/Assets/Samples/Dependencies/Plugins/Android/GooglePlayGamesManifest.androidlib/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Stash/Scenes.meta b/Assets/Samples/Scenes.meta similarity index 100% rename from Assets/Stash/Scenes.meta rename to Assets/Samples/Scenes.meta diff --git a/Assets/Stash/Scenes/StashGameCenterSample.unity b/Assets/Samples/Scenes/StashSample.unity similarity index 65% rename from Assets/Stash/Scenes/StashGameCenterSample.unity rename to Assets/Samples/Scenes/StashSample.unity index b8518d5..09566b3 100644 --- a/Assets/Stash/Scenes/StashGameCenterSample.unity +++ b/Assets/Samples/Scenes/StashSample.unity @@ -157,7 +157,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 48, y: 446} + m_AnchoredPosition: {x: 48, y: 352} m_SizeDelta: {x: 940.425, y: 187.542} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &261568836 @@ -207,15 +207,15 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 100 - m_fontSizeBase: 100 + m_fontSize: 50 + m_fontSizeBase: 50 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 0 - m_HorizontalAlignment: 1 - m_VerticalAlignment: 256 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 @@ -243,7 +243,7 @@ MonoBehaviour: m_VertexBufferAutoSizeReduction: 0 m_useMaxVisibleDescender: 1 m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 69.33189} + m_margin: {x: 22.691956, y: 0, z: 119.76254, w: 69.33189} m_isUsingLegacyAnimationComponent: 0 m_isVolumetricText: 0 m_hasFontAssetChanged: 0 @@ -257,7 +257,39 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 261568834} m_CullTransparentMesh: 1 ---- !u!1 &337360901 +--- !u!1 &294736975 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 294736976} + m_Layer: 0 + m_Name: Logo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &294736976 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 294736975} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.10508728, y: -0.009028912, z: 0.5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1289161923} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &523908575 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -265,57 +297,152 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 337360902} - - component: {fileID: 337360904} - - component: {fileID: 337360903} + - component: {fileID: 523908576} m_Layer: 5 - m_Name: StashLogo + m_Name: UserName m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &337360902 +--- !u!224 &523908576 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 337360901} + m_GameObject: {fileID: 523908575} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 4.1742, y: 3.6522, z: 1} + m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 1751549685} + - {fileID: 1702200495} m_Father: {fileID: 1428247368} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 14, y: 129} + m_AnchoredPosition: {x: 0, y: -44} m_SizeDelta: {x: 100, y: 100} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &337360903 +--- !u!1 &738422954 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 738422955} + - component: {fileID: 738422958} + - component: {fileID: 738422957} + - component: {fileID: 738422956} + m_Layer: 5 + m_Name: Accept + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &738422955 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 738422954} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 3.43315, y: 6.3990917, z: 5} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1699005017} + m_Father: {fileID: 854196020} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &738422956 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 337360901} + m_GameObject: {fileID: 738422954} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 738422957} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1368933213} + m_TargetAssemblyTypeName: DeeplinkHandler, Assembly-CSharp + m_MethodName: DoLinking + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &738422957 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 738422954} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Color: {r: 0.64441717, g: 0.9150943, b: 0.48776254, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2bc96997168164a369465e891b768670, type: 3} - m_Type: 0 + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 4 @@ -324,15 +451,15 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &337360904 +--- !u!222 &738422958 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 337360901} + m_GameObject: {fileID: 738422954} m_CullTransparentMesh: 1 ---- !u!1 &373790624 +--- !u!1 &768659695 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -340,9 +467,9 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 373790627} - - component: {fileID: 373790626} - - component: {fileID: 373790625} + - component: {fileID: 768659698} + - component: {fileID: 768659697} + - component: {fileID: 768659696} m_Layer: 0 m_Name: EventSystem m_TagString: Untagged @@ -350,13 +477,13 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &373790625 +--- !u!114 &768659696 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 373790624} + m_GameObject: {fileID: 768659695} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} @@ -370,13 +497,13 @@ MonoBehaviour: m_InputActionsPerSecond: 10 m_RepeatDelay: 0.5 m_ForceModuleActive: 0 ---- !u!114 &373790626 +--- !u!114 &768659697 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 373790624} + m_GameObject: {fileID: 768659695} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} @@ -385,13 +512,13 @@ MonoBehaviour: m_FirstSelected: {fileID: 0} m_sendNavigationEvents: 1 m_DragThreshold: 10 ---- !u!4 &373790627 +--- !u!4 &768659698 Transform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 373790624} + m_GameObject: {fileID: 768659695} serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} @@ -400,7 +527,7 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &523908575 +--- !u!1 &777598071 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -408,81 +535,44 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 523908576} + - component: {fileID: 777598072} + - component: {fileID: 777598075} + - component: {fileID: 777598074} + - component: {fileID: 777598073} m_Layer: 5 - m_Name: UserName + m_Name: DebugButton m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &523908576 +--- !u!224 &777598072 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 523908575} + m_GameObject: {fileID: 777598071} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 1751549685} - - {fileID: 1702200495} + - {fileID: 1461408497} m_Father: {fileID: 1428247368} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 100, y: 100} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!1 &738422954 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 738422955} - - component: {fileID: 738422958} - - component: {fileID: 738422957} - - component: {fileID: 738422956} - m_Layer: 5 - m_Name: Accept - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &738422955 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 738422954} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 5, y: 8.672501, z: 5} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1699005017} - m_Father: {fileID: 854196020} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 160, y: 30} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 85.1, y: -88} + m_SizeDelta: {x: 96.2861, y: 97.8376} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &738422956 +--- !u!114 &777598073 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 738422954} + m_GameObject: {fileID: 777598071} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} @@ -516,24 +606,36 @@ MonoBehaviour: m_SelectedTrigger: Selected m_DisabledTrigger: Disabled m_Interactable: 1 - m_TargetGraphic: {fileID: 738422957} + m_TargetGraphic: {fileID: 777598074} m_OnClick: m_PersistentCalls: - m_Calls: [] ---- !u!114 &738422957 + m_Calls: + - m_Target: {fileID: 1404623901} + m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 +--- !u!114 &777598074 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 738422954} + m_GameObject: {fileID: 777598071} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 0.64441717, g: 0.9150943, b: 0.48776254, a: 1} + m_Color: {r: 0.9969328, g: 1, b: 0.15566039, a: 0.13333334} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -550,13 +652,13 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 ---- !u!222 &738422958 +--- !u!222 &777598075 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 738422954} + m_GameObject: {fileID: 777598071} m_CullTransparentMesh: 1 --- !u!1 &854196019 GameObject: @@ -593,10 +695,10 @@ RectTransform: - {fileID: 1422760736} m_Father: {fileID: 1428247368} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 800, y: 1644} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &854196021 MonoBehaviour: @@ -680,7 +782,7 @@ Camera: m_ShutterSpeed: 0.005 m_Aperture: 16 m_FocusDistance: 10 - m_FocalLength: 50 + m_FocalLength: 41.848976 m_BladeCount: 5 m_Curvature: {x: 2, y: 11} m_BarrelClipping: 0.25 @@ -695,7 +797,7 @@ Camera: height: 1 near clip plane: 0.3 far clip plane: 1000 - field of view: 60 + field of view: 63 orthographic: 0 orthographic size: 5 m_Depth: -1 @@ -728,6 +830,164 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1020609173 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1020609174} + - component: {fileID: 1020609176} + - component: {fileID: 1020609175} + m_Layer: 5 + m_Name: DebugText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1020609174 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1020609173} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1.143419, y: 2.534983, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1404623902} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0.002272, y: -822} + m_SizeDelta: {x: 699.65, y: 648.53} + m_Pivot: {x: 0.5, y: -0.00000010430813} +--- !u!114 &1020609175 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1020609173} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Debug + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 30 + m_fontSizeBase: 30 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 6.392761, y: -1.9801178, z: 8.20871, w: 2.4720232} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1020609176 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1020609173} + m_CullTransparentMesh: 1 +--- !u!1 &1289161921 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + m_PrefabInstance: {fileID: 1499835347} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1289161922 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1289161921} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7aadb45e261a048f2892496636fbde6f, type: 3} + m_Name: + m_EditorClassIdentifier: + angularVelocity: {x: 2, y: 10, z: 0} + space: 0 +--- !u!4 &1289161923 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + m_PrefabInstance: {fileID: 1499835347} + m_PrefabAsset: {fileID: 0} --- !u!1 &1368933211 GameObject: m_ObjectHideFlags: 0 @@ -738,6 +998,7 @@ GameObject: m_Component: - component: {fileID: 1368933212} - component: {fileID: 1368933213} + - component: {fileID: 1368933214} m_Layer: 0 m_Name: StashManager m_TagString: Untagged @@ -772,7 +1033,98 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: c059b5309f9a944cd95c34cec4ad2e03, type: 3} m_Name: m_EditorClassIdentifier: - ConfirmPanel: {fileID: 854196019} + debugLabel: {fileID: 1020609175} + userLabel: {fileID: 1751549686} + confirmPanel: {fileID: 854196019} +--- !u!114 &1368933214 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1368933211} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5e28f9a4b3a6f48f4987de848fe2c560, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1404623901 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1404623902} + - component: {fileID: 1404623904} + - component: {fileID: 1404623903} + m_Layer: 5 + m_Name: DebugPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1404623902 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1404623901} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.87457, y: 0.39448, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1020609174} + - {fileID: 1721725567} + m_Father: {fileID: 1428247368} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 800, y: 1644} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1404623903 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1404623901} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.09433961, g: 0.09433961, b: 0.09433961, a: 0.89411765} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1404623904 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1404623901} + m_CullTransparentMesh: 1 --- !u!1 &1422760735 GameObject: m_ObjectHideFlags: 0 @@ -801,15 +1153,15 @@ RectTransform: m_GameObject: {fileID: 1422760735} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 5, y: 8.4539995, z: 5} + m_LocalScale: {x: 3.4329, y: 6.487177, z: 5} m_ConstrainProportionsScale: 0 m_Children: - {fileID: 2024498068} m_Father: {fileID: 854196020} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0, y: -436} + m_AnchorMin: {x: 0.5, y: 0.45935136} + m_AnchorMax: {x: 0.5, y: 0.45935136} + m_AnchoredPosition: {x: 0, y: -259} m_SizeDelta: {x: 160, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1422760737 @@ -954,7 +1306,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} m_Name: m_EditorClassIdentifier: - m_UiScaleMode: 0 + m_UiScaleMode: 1 m_ReferencePixelsPerUnit: 100 m_ScaleFactor: 1 m_ReferenceResolution: {x: 800, y: 600} @@ -1000,10 +1352,10 @@ RectTransform: m_LocalScale: {x: 0, y: 0, z: 0} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 337360902} - - {fileID: 1704892414} - - {fileID: 854196020} + - {fileID: 777598072} - {fileID: 523908576} + - {fileID: 854196020} + - {fileID: 1404623902} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -1011,7 +1363,7 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 0} ---- !u!1 &1439087196 +--- !u!1 &1461408496 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1019,43 +1371,232 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1439087198} - - component: {fileID: 1439087197} - m_Layer: 0 - m_Name: AccountManager + - component: {fileID: 1461408497} + - component: {fileID: 1461408499} + - component: {fileID: 1461408498} + m_Layer: 5 + m_Name: Text (TMP) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!114 &1439087197 +--- !u!224 &1461408497 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1461408496} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 777598072} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1461408498 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1439087196} + m_GameObject: {fileID: 1461408496} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 11f3e06233e6b4e60bd0fa696dc1ff98, type: 3} + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} m_Name: m_EditorClassIdentifier: - UsernameLabel: {fileID: 1751549686} ---- !u!4 &1439087198 -Transform: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: '?' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 50 + m_fontSizeBase: 50 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 31.759789, y: 10.93298, z: 29.267115, w: 13.794033} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &1461408499 +CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1439087196} + m_GameObject: {fileID: 1461408496} + m_CullTransparentMesh: 1 +--- !u!1001 &1499835347 +PrefabInstance: + m_ObjectHideFlags: 0 serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 642, y: 1389, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 294736976} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalPosition.x + value: -0.10508728 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalPosition.y + value: 0.5090289 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalPosition.z + value: 41.35 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.w + value: 0.9636041 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.y + value: -0.26733354 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: -31.011 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -7635826562936255635, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_Materials.Array.size + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -7635826562936255635, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 2100000, guid: 23a8ea9b4bff34a3ca6fbc9d4bac338c, type: 2} + - target: {fileID: -7635826562936255635, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_Materials.Array.data[1] + value: + objectReference: {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + - target: {fileID: 919132149155446097, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_Name + value: StashLogo + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.w + value: -0.3057225 + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.x + value: -0.0004403601 + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.y + value: 0.9521067 + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalRotation.z + value: 0.005143221 + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: -0.546 + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 215.605 + objectReference: {fileID: 0} + - target: {fileID: 1151388028547126963, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: -0.228 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} + insertIndex: -1 + addedObject: {fileID: 1289161922} + m_SourcePrefab: {fileID: 100100000, guid: 3890e353e9a8b44989fdcec78d682777, type: 3} --- !u!1 &1699005016 GameObject: m_ObjectHideFlags: 0 @@ -1224,7 +1765,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -80, y: 522.06287} + m_AnchoredPosition: {x: 27, y: -535.60004} m_SizeDelta: {x: 163.6691, y: 53.8744} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1702200496 @@ -1274,14 +1815,14 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 56 - m_fontSizeBase: 56 + m_fontSize: 36 + m_fontSizeBase: 36 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 - m_fontStyle: 0 - m_HorizontalAlignment: 1 + m_fontStyle: 1 + m_HorizontalAlignment: 2 m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 @@ -1310,7 +1851,7 @@ MonoBehaviour: m_VertexBufferAutoSizeReduction: 0 m_useMaxVisibleDescender: 1 m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} + m_margin: {x: -344.98517, y: 0, z: -290.5457, w: 21.525337} m_isUsingLegacyAnimationComponent: 0 m_isVolumetricText: 0 m_hasFontAssetChanged: 0 @@ -1324,7 +1865,7 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1702200494} m_CullTransparentMesh: 1 ---- !u!1 &1704892413 +--- !u!1 &1721725566 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1332,42 +1873,175 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1704892414} - - component: {fileID: 1704892416} - - component: {fileID: 1704892415} + - component: {fileID: 1721725567} + - component: {fileID: 1721725570} + - component: {fileID: 1721725569} + - component: {fileID: 1721725568} m_Layer: 5 - m_Name: Text + m_Name: Close m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1704892414 +--- !u!224 &1721725567 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1704892413} + m_GameObject: {fileID: 1721725566} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 3.4329, y: 6.487177, z: 5} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1826589513} + m_Father: {fileID: 1404623902} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.45935136} + m_AnchorMax: {x: 0.5, y: 0.45935136} + m_AnchoredPosition: {x: 324, y: 716} + m_SizeDelta: {x: 31.4646, y: 34.816} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1721725568 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1721725566} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1721725569} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1404623901} + m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &1721725569 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1721725566} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0.48584908, b: 0.48584908, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1721725570 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1721725566} + m_CullTransparentMesh: 1 +--- !u!1 &1751549684 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1751549685} + - component: {fileID: 1751549687} + - component: {fileID: 1751549686} + m_Layer: 5 + m_Name: User + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1751549685 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1751549684} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 1428247368} + m_Father: {fileID: 523908576} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -98, y: -71} - m_SizeDelta: {x: 200, y: 50} + m_AnchoredPosition: {x: 87, y: -589.1} + m_SizeDelta: {x: 163.6691, y: 53.8744} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1704892415 +--- !u!114 &1751549686 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1704892413} + m_GameObject: {fileID: 1751549684} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} @@ -1381,7 +2055,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Stash Demo + m_text: Not Signed In m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -1408,14 +2082,14 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 100 - m_fontSizeBase: 100 + m_fontSize: 36 + m_fontSizeBase: 36 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 0 - m_HorizontalAlignment: 1 + m_HorizontalAlignment: 2 m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 @@ -1444,21 +2118,21 @@ MonoBehaviour: m_VertexBufferAutoSizeReduction: 0 m_useMaxVisibleDescender: 1 m_pageToDisplay: 1 - m_margin: {x: -66.857574, y: 0, z: -409.39893, w: 0} + m_margin: {x: -407.31235, y: 0, z: -231.45154, w: 4.752468} m_isUsingLegacyAnimationComponent: 0 m_isVolumetricText: 0 m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1704892416 +--- !u!222 &1751549687 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1704892413} + m_GameObject: {fileID: 1751549684} m_CullTransparentMesh: 1 ---- !u!1 &1751549684 +--- !u!1 &1826589512 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1466,42 +2140,42 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1751549685} - - component: {fileID: 1751549687} - - component: {fileID: 1751549686} + - component: {fileID: 1826589513} + - component: {fileID: 1826589515} + - component: {fileID: 1826589514} m_Layer: 5 - m_Name: User + m_Name: Text (TMP) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1751549685 +--- !u!224 &1826589513 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1751549684} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_GameObject: {fileID: 1826589512} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 523908576} + m_Father: {fileID: 1721725567} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 72, y: 522.06287} - m_SizeDelta: {x: 163.6691, y: 53.8744} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1751549686 +--- !u!114 &1826589514 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1751549684} + m_GameObject: {fileID: 1826589512} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} @@ -1515,7 +2189,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: '[-]' + m_text: X m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -1524,8 +2198,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: @@ -1542,15 +2216,15 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 56 - m_fontSizeBase: 56 + m_fontSize: 24 + m_fontSizeBase: 24 m_fontWeight: 400 m_enableAutoSizing: 0 m_fontSizeMin: 18 m_fontSizeMax: 72 m_fontStyle: 0 - m_HorizontalAlignment: 1 - m_VerticalAlignment: 256 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 @@ -1584,13 +2258,13 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!222 &1751549687 +--- !u!222 &1826589515 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1751549684} + m_GameObject: {fileID: 1826589512} m_CullTransparentMesh: 1 --- !u!1 &2024498067 GameObject: @@ -1730,8 +2404,8 @@ CanvasRenderer: SceneRoots: m_ObjectHideFlags: 0 m_Roots: - - {fileID: 373790627} + - {fileID: 768659698} - {fileID: 963194228} - - {fileID: 1428247368} - {fileID: 1368933212} - - {fileID: 1439087198} + - {fileID: 1428247368} + - {fileID: 294736976} diff --git a/Assets/Stash/Scenes/StashGameCenterSample.unity.meta b/Assets/Samples/Scenes/StashSample.unity.meta similarity index 100% rename from Assets/Stash/Scenes/StashGameCenterSample.unity.meta rename to Assets/Samples/Scenes/StashSample.unity.meta diff --git a/Assets/StashSamples/Scripts.meta b/Assets/Samples/Scripts.meta similarity index 100% rename from Assets/StashSamples/Scripts.meta rename to Assets/Samples/Scripts.meta diff --git a/Assets/Samples/Scripts/Auth.meta b/Assets/Samples/Scripts/Auth.meta new file mode 100644 index 0000000..87370e8 --- /dev/null +++ b/Assets/Samples/Scripts/Auth.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 396265e2c0d3f456fadd405d92ed4802 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Scripts/Auth/GameCenter.cs b/Assets/Samples/Scripts/Auth/GameCenter.cs new file mode 100644 index 0000000..242b261 --- /dev/null +++ b/Assets/Samples/Scripts/Auth/GameCenter.cs @@ -0,0 +1,57 @@ +#if UNITY_IOS + +using System; +using System.Threading.Tasks; +using UnityEngine; +using Apple.GameKit; +using Apple.GameKit.Players; + +// More details: https://docs.unity.com/ugs/en-us/manual/authentication/manual/platform-signin-apple-game-center +public static class GameCenter +{ + public static string Signature; + public static string TeamPlayerID; + public static string Salt; + public static string PublicKeyUrl; + public static string Timestamp; + + public static async void Activate() + { + await Login(); + } + + private static async Task Login() + { + if (!GKLocalPlayer.Local.IsAuthenticated) + { + // Perform the authentication. + var player = await GKLocalPlayer.Authenticate(); + Debug.Log($"[APPLE GAME CENTER] Login successful - {player.DisplayName}"); + + // Grab the team player id. + var localPlayer = GKLocalPlayer.Local; + TeamPlayerID = localPlayer.TeamPlayerId; + + //Fetch signature, salt, timestamp and public key for server-side verification. + RefreshCredentials(); + DeeplinkExample.Instance.DisplayUsername(player.DisplayName); + } + else + { + Debug.Log("[APPLE GAME CENTER] Already logged in."); + } + } + + public static async Task RefreshCredentials() + { + var fetchItemsResponse = await GKLocalPlayer.Local.FetchItems(); + Debug.Log($"[APPLE GAME CENTER] Credentials refreshed"); + + Signature = Convert.ToBase64String(fetchItemsResponse.Signature); + Salt = Convert.ToBase64String(fetchItemsResponse.Salt); + PublicKeyUrl = fetchItemsResponse.PublicKeyUrl; + Timestamp = fetchItemsResponse.Timestamp.ToString(); + } +} + +#endif \ No newline at end of file diff --git a/Assets/Samples/Scripts/Auth/GameCenter.cs.meta b/Assets/Samples/Scripts/Auth/GameCenter.cs.meta new file mode 100644 index 0000000..afd44d6 --- /dev/null +++ b/Assets/Samples/Scripts/Auth/GameCenter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6db52edb5888347039edf59597cc1323 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Scripts/Auth/PlayGames.cs b/Assets/Samples/Scripts/Auth/PlayGames.cs new file mode 100644 index 0000000..56c2781 --- /dev/null +++ b/Assets/Samples/Scripts/Auth/PlayGames.cs @@ -0,0 +1,48 @@ +#if UNITY_ANDROID + +using UnityEngine; +using GooglePlayGames; +using GooglePlayGames.BasicApi; + +// More details: https://docs.unity.com/ugs/en-us/manual/authentication/manual/platform-signin-google-play-games +public static class PlayGames +{ + public static string AuthCode; + + public static void Activate() + { + PlayGamesPlatform.Activate(); + Login(); + } + + private static void Login() + { + PlayGamesPlatform.Instance.Authenticate((success) => + { + if (success == SignInStatus.Success) + { + string DisplayName = PlayGamesPlatform.Instance.GetUserDisplayName(); + Debug.Log($"[GOOGLE PLAY GAMES] Login successful - {DisplayName}"); + + //Fetch AuthCode for server-side verification. + RefreshCredentials(); + DeeplinkExample.Instance.DisplayUsername(DisplayName); + } + else + { + Debug.Log("[GOOGLE PLAY GAMES] Login unsuccessful."); + } + }); + } + + public static void RefreshCredentials() + { + PlayGamesPlatform.Instance.RequestServerSideAccess(true, code => + { + Debug.Log($"[GOOGLE PLAY GAMES] Credentials refreshed - {code}"); + AuthCode = code; + }); + } +} + +#endif diff --git a/Assets/Samples/Scripts/Auth/PlayGames.cs.meta b/Assets/Samples/Scripts/Auth/PlayGames.cs.meta new file mode 100644 index 0000000..2866043 --- /dev/null +++ b/Assets/Samples/Scripts/Auth/PlayGames.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 454ac0162cb6f472e8af81b873aa393f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Scripts/DeeplinkExample.cs b/Assets/Samples/Scripts/DeeplinkExample.cs new file mode 100644 index 0000000..c0a9b35 --- /dev/null +++ b/Assets/Samples/Scripts/DeeplinkExample.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections; +using Stash.Core; +using Stash.Core.Exceptions; +using Stash.Models; +using TMPro; +using UnityEngine; + +public class DeeplinkExample : MonoBehaviour +{ + public static DeeplinkExample Instance { get; private set; } + + public TextMeshProUGUI debugLabel; + public TextMeshProUGUI userLabel; + public GameObject confirmPanel; + + private string _stashChallenge; + private const string InternalPlayerId = "TEST_PLAYER_ID"; + + private void Awake() + { + //Event handler "OnDeepLinkActivated" is invoked every time the game is launched or resumed via the Stash’s deep link. + if (Instance == null) + { + Instance = this; + Application.deepLinkActivated += OnDeepLinkActivated; + if (!string.IsNullOrEmpty(Application.absoluteURL)) + { + // Application.absoluteURL not null so process Deep Link on app cold start. + OnDeepLinkActivated(Application.absoluteURL); + } + // Initialize DeepLink Manager global variable. + else _stashChallenge = "[none]"; + DontDestroyOnLoad(gameObject); + } + else + { + Destroy(gameObject); + } + } + + + private void Start() + { + // Automatically log in player on the game launch based on the platform. +#if UNITY_ANDROID + PlayGames.Activate(); +#endif + +#if UNITY_IOS + GameCenter.Activate(); +#endif + } + + + private void OnDeepLinkActivated(string url) + { + //Extract the challenge parameter from the link. + _stashChallenge = url.Split("/link?challenge=")[1]; + if (!string.IsNullOrEmpty(_stashChallenge)) + { + Debug.Log("[STASH] Deeplink Code Challenge: " + _stashChallenge); + + //We display the confirmation dialog. This is not necessary but recommended linking flow. + //If user confirms the linking, dialog object will trigger the ProcessLinking() method. + confirmPanel.SetActive(true); + } + } + + /// + /// Processes linking of the Stash account with Google Play Games or Apple Game Center. + /// + public async void ProcessLinking() + { + confirmPanel.SetActive(false); + + #if UNITY_ANDROID + PlayGames.RefreshCredentials(); + try + { + LinkResponse response = await StashClient.LinkGooglePlayGames(_stashChallenge, InternalPlayerId, PlayGames.AuthCode); + + Debug.Log("[STASH][Google Play Games] Account linked successfully."); + debugLabel.text = response.codeChallenge; + } + catch (StashRequestError e) + { + Debug.LogError($"[STASH][Google Play Games] Account linking failed. Code: {e.Code}"); + debugLabel.text = e.Message; + } + #endif + + #if UNITY_IOS + await GameCenter.RefreshCredentials(); + try + { + LinkResponse response = await StashClient.LinkAppleGameCenter( _stashChallenge, InternalPlayerId, "com.Stash.iosdemo", + GameCenter.TeamPlayerID, GameCenter.Signature, GameCenter.Salt, GameCenter.PublicKeyUrl, GameCenter.Timestamp); + + Debug.Log("[STASH][Apple Game Center] Account linked successfully."); + debugLabel.text = response.codeChallenge; + } + catch (StashRequestError e) + { + Debug.LogError($"[STASH][Apple Game Center] Account linking failed. Code: {e.Code}"); + debugLabel.text = e.Message; + } + #endif + } + + public void DisplayUsername(string username) + { + userLabel.text = username; + } +} \ No newline at end of file diff --git a/Assets/StashSamples/Scripts/DeeplinkHandler.cs.meta b/Assets/Samples/Scripts/DeeplinkExample.cs.meta similarity index 100% rename from Assets/StashSamples/Scripts/DeeplinkHandler.cs.meta rename to Assets/Samples/Scripts/DeeplinkExample.cs.meta diff --git a/Assets/Samples/Scripts/Log.cs b/Assets/Samples/Scripts/Log.cs new file mode 100644 index 0000000..6c6d7ff --- /dev/null +++ b/Assets/Samples/Scripts/Log.cs @@ -0,0 +1,30 @@ +using UnityEngine; +using System.Collections; + +public class Log : MonoBehaviour +{ + uint qsize = 5; + Queue myLogQueue = new Queue(); + + void OnEnable() { + Application.logMessageReceived += HandleLog; + } + + void OnDisable() { + Application.logMessageReceived -= HandleLog; + } + + void HandleLog(string logString, string stackTrace, LogType type) { + myLogQueue.Enqueue("[" + type + "] : " + logString); + if (type == LogType.Exception) + myLogQueue.Enqueue(stackTrace); + while (myLogQueue.Count > qsize) + myLogQueue.Dequeue(); + } + + void OnGUI() { + GUILayout.BeginArea(new Rect(0, 0, Screen.width, Screen.height)); + GUILayout.Label("\n" + string.Join("\n", myLogQueue.ToArray())); + GUILayout.EndArea(); + } +} \ No newline at end of file diff --git a/Assets/Samples/Scripts/Log.cs.meta b/Assets/Samples/Scripts/Log.cs.meta new file mode 100644 index 0000000..feeb754 --- /dev/null +++ b/Assets/Samples/Scripts/Log.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e28f9a4b3a6f48f4987de848fe2c560 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Samples/Scripts/LogoRotation.cs b/Assets/Samples/Scripts/LogoRotation.cs new file mode 100644 index 0000000..7a02014 --- /dev/null +++ b/Assets/Samples/Scripts/LogoRotation.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class LogoRotation : MonoBehaviour +{ + public Vector3 angularVelocity; + public Space space = Space.Self; + void Update () + { + transform.Rotate(angularVelocity * Time.deltaTime, space); + } +} diff --git a/Assets/Samples/Scripts/LogoRotation.cs.meta b/Assets/Samples/Scripts/LogoRotation.cs.meta new file mode 100644 index 0000000..ff72cbf --- /dev/null +++ b/Assets/Samples/Scripts/LogoRotation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7aadb45e261a048f2892496636fbde6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Stash/Images/StashLogo.png b/Assets/Stash/Images/StashLogo.png deleted file mode 100644 index 40e3514..0000000 Binary files a/Assets/Stash/Images/StashLogo.png and /dev/null differ diff --git a/Assets/Stash/Images/StashLogo.png.meta b/Assets/Stash/Images/StashLogo.png.meta deleted file mode 100644 index e74f031..0000000 --- a/Assets/Stash/Images/StashLogo.png.meta +++ /dev/null @@ -1,153 +0,0 @@ -fileFormatVersion: 2 -guid: 2bc96997168164a369465e891b768670 -TextureImporter: - internalIDToNameTable: [] - externalObjects: {} - serializedVersion: 12 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - 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 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 0 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 1 - alignment: 0 - spritePivot: {x: 0.5, y: 0.5} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 3 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: iPhone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 3 - buildTarget: Server - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: [] - outline: [] - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Stash/Scripts/Core/StashClient.cs b/Assets/Stash/Scripts/Core/StashClient.cs index 922f66e..4318c01 100644 --- a/Assets/Stash/Scripts/Core/StashClient.cs +++ b/Assets/Stash/Scripts/Core/StashClient.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using UnityEngine; @@ -7,39 +6,17 @@ namespace Stash.Core { -public class StashClient : MonoBehaviour +public static class StashClient { - private static StashClient _instance; - public static StashClient Instance - { - get - { - if (_instance == null) - { - _instance = FindObjectOfType(); - if (_instance == null) - { - GameObject stashClient = new() - { - name = nameof(StashClient) - }; - _instance = stashClient.AddComponent(); - DontDestroyOnLoad(stashClient); - } - } - return _instance; - } - } - /// /// Links the player's account to Stash account for Apple Account & Google Account. - /// Requires a valid JWT identity token issued by Apple or Google. + /// Requires a valid JWT token issued by any of the supported providers no older than 1 hour. /// - /// Stash challenge from the deeplink. - /// Internal user id, will be used to identify the purchases. - /// Valid idToken (JWT) of the player to be linked. + /// Stash code challenge from the deeplink. + /// Player identification, that will be used to identify purchases. + /// Valid JWT token of the player. /// Returns a confirmation response, or throws StashAPIRequestError if fails. - public async Task LinkGoogleOrApple(string challenge, string internalUserId, string idToken) + public static async Task LinkAccount(string challenge, string playerId, string idToken) { // Create the authorization header with the access token RequestHeader authorizationHeader = new() @@ -54,12 +31,12 @@ public async Task LinkGoogleOrApple(string challenge, string inter code_challenge = challenge, user = new LinkBody.User { - id = internalUserId + id = playerId } }; // Set the URL for the link account endpoint - const string requestUrl = StashConstants.APIRootURL + StashConstants.LinkAccount; + const string requestUrl = StashConstants.RootUrlTest + StashConstants.LinkAccount; // Make a POST request to link the access token Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody), new List { authorizationHeader }); @@ -69,7 +46,6 @@ public async Task LinkGoogleOrApple(string challenge, string inter try { // Parse the response data into a LinkResponse object - Debug.Log("[STASH] LinkGoogleOrApple successful Response: " + result.Data); LinkResponse resultResponse = JsonUtility.FromJson(result.Data); return resultResponse; } @@ -82,46 +58,53 @@ public async Task LinkGoogleOrApple(string challenge, string inter else { // Throw an error if the API request was not successful - throw new StashAPIRequestError(result.StatusCode, result.Data); + throw new StashRequestError(result.StatusCode, result.Data); } } /// /// Links an Apple Game Center account to the Stash user's account. - /// Requires signature generated using fetchItems(forIdentityVerificationSignature:) + /// Requires a valid response (signature, salt, timestamp, publicKeyUrl) received from GameKit "fetchItems" no older than 1 hour. /// - /// The challenge for linking the account. - /// The bundle ID of the iOS/macOS app. (CFBundleIdentifier) - /// The verification signature data that GameKit generates. - /// A random string that GameKit uses to compute the hash and randomize it. + /// Stash code challenge from the deeplink. + /// Player identification, that will be used to identify purchases. + /// The bundle ID of the app (CFBundleIdentifier) + /// GameKit identifier for a player of all the games that you distribute using your Apple developer account. + /// The verification signature data that GameKit generates. (Base64 Encoded) + /// A random string that GameKit uses to compute the hash and randomize it. (Base64 Encoded) /// The URL for the public encryption key. - /// A unique identifier for a player of all the games that you distribute using your developer account. /// The signature’s creation date and time. /// A LinkResponse object. - public async Task LinkAppleGameCenter(string challenge, string bundleId, string signature, - string salt, string publicKeyUrl, string teamPlayerID, string timestamp ) + public static async Task LinkAppleGameCenter(string challenge, string playerId, string bundleId, string teamPlayerID, string signature, + string salt, string publicKeyUrl, string timestamp ) { - // Create the request body with the challenge and internal user id var requestBody = new LinkGameCenterBody() { codeChallenge = challenge, - player = new LinkGameCenterBody.Player + verification = new LinkGameCenterBody.Verification() { - bundleId = bundleId, - playerId = teamPlayerID + player = new LinkGameCenterBody.Player() + { + bundleId = bundleId, + playerId = teamPlayerID + }, + response = new LinkGameCenterBody.Response() + { + signature = signature, + salt = salt, + publicKeyUrl = publicKeyUrl, + timestamp = timestamp + } }, - verification = new LinkGameCenterBody.Verification + user = new LinkGameCenterBody.User() { - signature = signature, - salt = salt, - publicKeyUrl = publicKeyUrl, - timestamp = timestamp + id = playerId } }; // Set the URL for the link account endpoint - const string requestUrl = StashConstants.APIRootURL + StashConstants.LnkGameCenter; + const string requestUrl = StashConstants.RootUrlTest + StashConstants.LinkAppleGameCenter; // Make a POST request to link the access token Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody)); @@ -142,9 +125,58 @@ public async Task LinkAppleGameCenter(string challenge, string bun else { // Throw an error if the API request was not successful - throw new StashAPIRequestError(result.StatusCode, result.Data); + throw new StashRequestError(result.StatusCode, result.Data); } } + /// + /// Links a Google Play Games account to the Stash user's account. + /// Requires valid authorization code generated using "RequestServerSideAccess" from GooglePlayGames no older than 1 hour. + /// + /// Stash code challenge from the deeplink. + /// Player identification, that will be used to identify purchases. + /// The authorization code generated using RequestServerSideAccess + /// A LinkResponse object. + public static async Task LinkGooglePlayGames(string challenge, string playerId, string authCode) + { + // Create the request body with the challenge and internal user id + var requestBody = new LinkGooglePlayGamesBody() + { + codeChallenge = challenge, + verification = new LinkGooglePlayGamesBody.Verification() + { + authCode = authCode + }, + user = new LinkGooglePlayGamesBody.User() + { + id = playerId + } + }; + + // Set the URL for the link account endpoint + const string requestUrl = StashConstants.RootUrlTest + StashConstants.LinkGooglePlayGames; + // Make a POST request to link the access token + Response result = await RestClient.Post(requestUrl, JsonUtility.ToJson(requestBody)); + + // Check the response status code + if (result.StatusCode == 200) + { + try + { + LinkResponse resultResponse = JsonUtility.FromJson(result.Data); + return resultResponse; + } + catch + { + // Throw an error if there is an issue parsing the response data + throw new StashParseError(result.Data); + } + } + else + { + // Throw an error if the API request was not successful + throw new StashRequestError(result.StatusCode, result.Data); + } + } } } \ No newline at end of file diff --git a/Assets/Stash/Scripts/Core/StashConstants.cs b/Assets/Stash/Scripts/Core/StashConstants.cs index 476fdd8..67f6b29 100644 --- a/Assets/Stash/Scripts/Core/StashConstants.cs +++ b/Assets/Stash/Scripts/Core/StashConstants.cs @@ -2,10 +2,11 @@ namespace Stash.Core { public class StashConstants { - public const string APIRootURL = "https://api-rest-f57w5ea4ya-uc.a.run.app"; - public const string TestRootURL = "https://stash.requestcatcher.com"; + public const string RootUrl = "https://api.stash.gg"; + public const string RootUrlTest = "https://test-api.stash.gg"; + public const string LinkAccount = "/sdk/link_code/link"; - public const string LnkGameCenter = "/sdk/link_code/link_game_center"; + public const string LinkAppleGameCenter = "/sdk/link_code/link_apple_game_center"; + public const string LinkGooglePlayGames = "/sdk/link_code/link_google_play_games"; } - } \ No newline at end of file diff --git a/Assets/Stash/Scripts/Core/StashExceptions.cs b/Assets/Stash/Scripts/Core/StashExceptions.cs index 98926be..a63252b 100644 --- a/Assets/Stash/Scripts/Core/StashExceptions.cs +++ b/Assets/Stash/Scripts/Core/StashExceptions.cs @@ -2,25 +2,36 @@ namespace Stash.Core.Exceptions { + /// + /// Thrown when any error occurs while processing a request on the Stash API. + /// Parses the API error code and message. + /// [Serializable] - public class StashAPIRequestError : Exception + public class StashRequestError : Exception { - public StashAPIRequestError() { } + public long Code { get; } + public string Message { get; } + + public StashRequestError() { } - public StashAPIRequestError(long code, string message = null) - : base($"Error Code: {code}, Message: {message}") + public StashRequestError(long code, string message = null) + : base($"[STASH] Error - Code: {code}, Message: {message}") { - + Code = code; + Message = message; } } + /// + /// Exception occurs while parsing the Stash API response, may also occur when the API or network is not reachable. + /// [Serializable] public class StashParseError : Exception { public StashParseError() { } public StashParseError(string message = null) - : base($"Failed while parsing the Stash API response. Message: {message}") + : base($"[STASH] Error while parsing API response. Message: {message}") { } diff --git a/Assets/Stash/Scripts/Models/LinkGameCenterBody.cs b/Assets/Stash/Scripts/Models/LinkGameCenterBody.cs index e12568a..5d8859d 100644 --- a/Assets/Stash/Scripts/Models/LinkGameCenterBody.cs +++ b/Assets/Stash/Scripts/Models/LinkGameCenterBody.cs @@ -6,9 +6,16 @@ namespace Stash.Models public class LinkGameCenterBody { public string codeChallenge; - public Player player; public Verification verification; - + public User user; + + [Serializable] + public class Verification + { + public Player player; + public Response response; + } + [Serializable] public class Player { @@ -17,12 +24,18 @@ public class Player } [Serializable] - public class Verification + public class Response { public string signature; public string salt; public string publicKeyUrl; public string timestamp; } + + [Serializable] + public class User + { + public string id; + } } } \ No newline at end of file diff --git a/Assets/Stash/Scripts/Models/LinkGooglePlayGamesBody.cs b/Assets/Stash/Scripts/Models/LinkGooglePlayGamesBody.cs new file mode 100644 index 0000000..f2cf764 --- /dev/null +++ b/Assets/Stash/Scripts/Models/LinkGooglePlayGamesBody.cs @@ -0,0 +1,24 @@ +using System; + +namespace Stash.Models +{ + [Serializable] + public class LinkGooglePlayGamesBody + { + public string codeChallenge; + public Verification verification; + public User user; + + [Serializable] + public class Verification + { + public string authCode; + } + + [Serializable] + public class User + { + public string id; + } + } +} \ No newline at end of file diff --git a/Assets/Stash/Scripts/Models/LinkGooglePlayGamesBody.cs.meta b/Assets/Stash/Scripts/Models/LinkGooglePlayGamesBody.cs.meta new file mode 100644 index 0000000..40332ed --- /dev/null +++ b/Assets/Stash/Scripts/Models/LinkGooglePlayGamesBody.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 079f028fcaa74888a70ca910a7ce0a89 +timeCreated: 1711370043 \ No newline at end of file diff --git a/Assets/StashSamples/Scripts/AppleGameCenterExampleScript.cs b/Assets/StashSamples/Scripts/AppleGameCenterExampleScript.cs deleted file mode 100644 index 1ebf806..0000000 --- a/Assets/StashSamples/Scripts/AppleGameCenterExampleScript.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Threading.Tasks; -using UnityEngine; -using Apple.GameKit; -using Stash.Core; -using TMPro; -using Unity.Services.Authentication; -using Unity.Services.Core; - - -//https://docs.unity.com/ugs/en-us/manual/authentication/manual/platform-signin-apple-game-center -public class AppleGameCenterExampleScript : MonoBehaviour -{ - public TextMeshProUGUI UsernameLabel; - - string Signature; - string TeamPlayerID; - string Salt; - string Timestamp; - string GamePlayerID; - - async void Start() - { - try - { - await UnityServices.InitializeAsync(); - } - catch (Exception e) - { - Debug.LogException(e); - } - - await Login(); - } - - public async Task Login() - { - if (!GKLocalPlayer.Local.IsAuthenticated) - { - // Perform the authentication. - var player = await GKLocalPlayer.Authenticate(); - Debug.Log($"GameKit Authentication: player {player}"); - - // Grab the display name. - var localPlayer = GKLocalPlayer.Local; - Debug.Log($"Local Player: {localPlayer.DisplayName}"); - UsernameLabel.text = localPlayer.DisplayName; - - // Fetch the items. - var fetchItemsResponse = await GKLocalPlayer.Local.FetchItems(); - Signature = Convert.ToBase64String(fetchItemsResponse.Signature); - Salt = Convert.ToBase64String(fetchItemsResponse.Salt); - Timestamp = fetchItemsResponse.Timestamp.ToString(); - TeamPlayerID = localPlayer.TeamPlayerId; - GamePlayerID = localPlayer.GamePlayerId; - - // Send signature, teamPlayerId, publicKeyURL, salt, timestamp to Stash. - Debug.Log($"GameKit Signature: {Signature}"); - Debug.Log($"GameKit Salt: {Salt}"); - Debug.Log($"GameKit PublicKey URL: {fetchItemsResponse.PublicKeyUrl}"); - Debug.Log($"GameKit TeamPlayerID: {TeamPlayerID} / GamePlayerID: {GamePlayerID}"); - Debug.Log($"GameKit Timestamp: {Timestamp}"); - - //Save latest game center data to player prefs - PlayerPrefs.SetString("Signature", Signature); - PlayerPrefs.SetString("TeamPlayerID", TeamPlayerID); - PlayerPrefs.SetString("Salt", Salt); - PlayerPrefs.SetString("Timestamp", Timestamp); - PlayerPrefs.SetString("GamePlayerID", GamePlayerID); - PlayerPrefs.SetString("PublicKeyURL", fetchItemsResponse.PublicKeyUrl); - - } - else - { - Debug.Log("AppleGameCenter player already logged in."); - } - } - -} \ No newline at end of file diff --git a/Assets/StashSamples/Scripts/DeeplinkHandler.cs b/Assets/StashSamples/Scripts/DeeplinkHandler.cs deleted file mode 100644 index b3b27f8..0000000 --- a/Assets/StashSamples/Scripts/DeeplinkHandler.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections; -using Stash.Core; -using Stash.Core.Exceptions; -using UnityEngine; -using UnityEngine.Networking; -using UnityEngine.SceneManagement; - -public class DeeplinkHandler : MonoBehaviour -{ - public static DeeplinkHandler Instance { get; private set; } - private string stashChallenge; - - public GameObject ConfirmPanel; - - private void Awake() - { - if (Instance == null) - { - Instance = this; - Application.deepLinkActivated += OnDeepLinkActivated; - if (!string.IsNullOrEmpty(Application.absoluteURL)) - { - // Cold start and Application.absoluteURL not null so process Deep Link. - OnDeepLinkActivated(Application.absoluteURL); - } - // Initialize DeepLink Manager global variable. - else stashChallenge = "[none]"; - - DontDestroyOnLoad(gameObject); - } - else - { - Destroy(gameObject); - } - } - - private async void OnDeepLinkActivated(string url) - { - //Extract the challenge parameter from the link. - stashChallenge = url.Split("/link?challenge=")[1]; - if (!string.IsNullOrEmpty(stashChallenge)) - { - //Work with the code challenge, prompt user for confirmation. - Debug.Log("Stash: Deep Link Challenge: " + stashChallenge); - - //Get the Game Center Signature, Salt, Timestamp, TeamPlayerID and GamePlayerID from player prefs. - string Signature = PlayerPrefs.GetString("Signature"); - string Salt = PlayerPrefs.GetString("Salt"); - string Timestamp = PlayerPrefs.GetString("Timestamp"); - string TeamPlayerID = PlayerPrefs.GetString("TeamPlayerID"); - string PublicKeyURL = PlayerPrefs.GetString("PublicKeyURL"); - - //Call linking function "LinkAppleGameCenter" and pass the parameters. - try - { - await StashClient.Instance.LinkAppleGameCenter(stashChallenge, "com.Stash.iosdemo", Signature, Salt, - PublicKeyURL, TeamPlayerID, Timestamp); - Debug.Log("[STASH] Account linked successfully !"); - } - catch (StashAPIRequestError e) - { - Debug.LogWarning("[STASH] Account link failed: " + e.Message); - } - catch (StashParseError e) - { - Debug.LogWarning("[STASH] Failure while parsing the Stash API response: " + e.Message); - } - } - } -} \ No newline at end of file diff --git a/Packages/manifest.json b/Packages/manifest.json index aae823b..76851cc 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -4,6 +4,7 @@ "com.apple.unityplugin.gamekit": "file:/Users/ondrejrehacek/Downloads/AppleUnityPlugins-main/com.apple.unityplugin.gamekit-1.0.4.tgz", "com.unity.collab-proxy": "2.3.1", "com.unity.feature.development": "1.0.1", + "com.unity.mobile.android-logcat": "1.4.0", "com.unity.services.authentication": "3.3.0", "com.unity.textmeshpro": "3.0.6", "com.unity.timeline": "1.7.6", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index e06afb6..a60a362 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -74,6 +74,13 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.mobile.android-logcat": { + "version": "1.4.0", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, "com.unity.nuget.newtonsoft-json": { "version": "3.2.1", "depth": 1, diff --git a/ProjectSettings/AndroidResolverDependencies.xml b/ProjectSettings/AndroidResolverDependencies.xml new file mode 100644 index 0000000..253345d --- /dev/null +++ b/ProjectSettings/AndroidResolverDependencies.xml @@ -0,0 +1,56 @@ + + + com.google.games:gpgs-plugin-support:0.11.01 + + + Assets/Plugins/Android/androidx.annotation.annotation-1.1.0.jar + Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar + Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar + Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar + Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar + Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar + Assets/Plugins/Android/androidx.core.core-1.2.0.aar + Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar + Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar + Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar + Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar + Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar + Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar + Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar + Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar + Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar + Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar + Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar + Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar + Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar + Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar + Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar + Assets/Plugins/Android/androidx.print.print-1.0.0.aar + Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar + Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar + Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.1.0.aar + Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar + Assets/Plugins/Android/com.google.android.gms.play-services-base-18.0.1.aar + Assets/Plugins/Android/com.google.android.gms.play-services-basement-18.0.0.aar + Assets/Plugins/Android/com.google.android.gms.play-services-drive-17.0.0.aar + Assets/Plugins/Android/com.google.android.gms.play-services-games-v2-17.0.0.aar + Assets/Plugins/Android/com.google.android.gms.play-services-nearby-18.0.2.aar + Assets/Plugins/Android/com.google.android.gms.play-services-tasks-18.0.1.aar + Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.11.01.aar + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset index c710c9f..a44ff98 100644 --- a/ProjectSettings/EditorBuildSettings.asset +++ b/ProjectSettings/EditorBuildSettings.asset @@ -6,6 +6,6 @@ EditorBuildSettings: serializedVersion: 2 m_Scenes: - enabled: 1 - path: Assets/Scenes/StashSample.unity + path: Assets/Samples/Scenes/StashSample.unity guid: 9fc0d4010bbf28b4594072e72b8655ab m_configObjects: {} diff --git a/ProjectSettings/GooglePlayGameSettings.txt b/ProjectSettings/GooglePlayGameSettings.txt new file mode 100644 index 0000000..958cec8 --- /dev/null +++ b/ProjectSettings/GooglePlayGameSettings.txt @@ -0,0 +1,9 @@ +lastUpgrade=01101 +proj.pluginVersion=0.11.01 +proj.AppId=1045293753265 +and.BundleId=com.stash.iosdemo +proj.classDir=Assets +proj.ConstantsClassName=GPGSIds +and.ResourceData=%3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%0a%3c%21--Google+Play+game+services+IDs.+Save+this+file+as+res%2fvalues%2fgames-ids.xml+in+your+project.--%3e%0a%3cresources%3e%0a++%3c%21--app_id--%3e%0a++%3cstring+name%3d%22app_id%22+translatable%3d%22false%22%3e1045293753265%3c%2fstring%3e%0a++%3c%21--package_name--%3e%0a++%3cstring+name%3d%22package_name%22+translatable%3d%22false%22%3ecom.stash.iosdemo%3c%2fstring%3e%0a++%3c%21--achievement+Test+Achievement--%3e%0a++%3cstring+name%3d%22achievement_test_achievement%22+translatable%3d%22false%22%3eCgkIscfzgrYeEAIQAw%3c%2fstring%3e%0a%3c%2fresources%3e +and.ClientId=1045293753265-ejh4ifdimiqfqhj2msj2c3h7oib9r7aq.apps.googleusercontent.com +android.SetupDone=true diff --git a/ProjectSettings/GvhProjectSettings.xml b/ProjectSettings/GvhProjectSettings.xml new file mode 100644 index 0000000..1d4f738 --- /dev/null +++ b/ProjectSettings/GvhProjectSettings.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 91dfccc..ae18f31 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -136,7 +136,7 @@ PlayerSettings: vulkanEnableLateAcquireNextImage: 0 vulkanEnableCommandBufferRecycling: 1 loadStoreDebugModeEnabled: 0 - bundleVersion: 0.1 + bundleVersion: 0.4 preloadedAssets: [] metroInputSource: 0 wsaTransparentSwapchain: 0 @@ -158,13 +158,14 @@ PlayerSettings: androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 applicationIdentifier: + Android: com.stash.iosdemo iPhone: com.Stash.iosdemo buildNumber: Standalone: 0 VisionOS: 0 - iPhone: 0 + iPhone: 1 tvOS: 0 - overrideDefaultApplicationIdentifier: 0 + overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 1 AndroidMinSdkVersion: 22 AndroidTargetSdkVersion: 0 @@ -225,7 +226,7 @@ PlayerSettings: iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: - - stashggsample + - stashiosdemo macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 @@ -256,12 +257,12 @@ PlayerSettings: useCustomGradlePropertiesTemplate: 0 useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 - AndroidTargetArchitectures: 1 + AndroidTargetArchitectures: 3 AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} - AndroidKeystoreName: - AndroidKeyaliasName: + AndroidKeystoreName: /Users/ondrejrehacek/Git/Stash/tools/stash_unity_key.keystore + AndroidKeyaliasName: stash AndroidEnableArmv9SecurityFeatures: 0 AndroidBuildApkPerCpuArchitecture: 0 AndroidTVCompatibility: 0 @@ -269,7 +270,7 @@ PlayerSettings: AndroidEnableTango: 0 androidEnableBanner: 1 androidUseLowAccuracyLocation: 0 - androidUseCustomKeystore: 0 + androidUseCustomKeystore: 1 m_AndroidBanners: - width: 320 height: 180 @@ -843,7 +844,8 @@ PlayerSettings: scriptingDefineSymbols: {} additionalCompilerArguments: {} platformArchitecture: {} - scriptingBackend: {} + scriptingBackend: + Android: 1 il2cppCompilerConfiguration: {} il2cppCodeGeneration: {} managedStrippingLevel: