/// <summary> /// Called when sign in finishes. /// </summary> /// <param name="wasInteractive">If true, this was the interactive (browser-based) sign-in flow.</param> /// <param name="status">The result of the sign in process.</param> private void OnSignInFinished(bool wasInteractive, PolyStatus status) { if (status.ok) { string tok = PolyApi.AccessToken; PtDebug.LogFormat("ABM: Sign in success. Access token: {0}", (tok != null && tok.Length > 6) ? tok.Substring(0, 6) + "..." : "INVALID"); PtAnalytics.SendEvent(PtAnalytics.Action.ACCOUNT_SIGN_IN_SUCCESS); } else if (wasInteractive) { Debug.LogErrorFormat("Failed to sign in. Please try again: " + status); PtAnalytics.SendEvent(PtAnalytics.Action.ACCOUNT_SIGN_IN_FAILURE, status.ToString()); } if (null != refreshCallback) { refreshCallback(); } // If we had a deferred request that was waiting for auth, send it now. if (requestToSendAfterAuth != null) { PtDebug.Log("Sending deferred request that was waiting for auth."); PolyRequest request = requestToSendAfterAuth; requestToSendAfterAuth = null; StartRequest(request); } }
public static void HandlePostInstall() { // Remove from the Editor update loop; we only need this to run once. EditorApplication.update -= HandlePostInstall; // Check if user just installed or upgraded Poly Toolkit. string upgradeFilePath = Path.Combine(Path.Combine(Path.Combine(Application.dataPath, "PolyToolkit"), "Editor"), "upgrade.dat"); string currentVersion = ""; bool isUpgrade = false; try { currentVersion = File.ReadAllText(upgradeFilePath).Trim(); } catch (Exception) {} if (currentVersion != PtSettings.Version.ToString()) { isUpgrade = !string.IsNullOrEmpty(currentVersion); // Show the welcome window. WelcomeWindow.ShowWelcomeWindow(); AssetBrowserWindow.BrowsePolyAssets(); File.WriteAllText(upgradeFilePath, PtSettings.Version.ToString()); } // In the future, if we need to do any post-upgrade maintenance, we can add it here. PtAnalytics.SendEvent(isUpgrade ? PtAnalytics.Action.INSTALL_UPGRADE : PtAnalytics.Action.INSTALL_NEW, PtSettings.Version.ToString()); }
/// <summary> /// Starts downloading and importing the given asset (in the background). When done, the asset will /// be saved to the user's Assets folder. /// </summary> /// <param name="asset">The asset to download and import.</param> /// <param name="ptAssetLocalPath">Path to the PtAsset that should be created (or replaced).</param> /// <param name="options">Import options.</param> public void StartDownloadAndImport(PolyAsset asset, string ptAssetLocalPath, EditTimeImportOptions options) { if (!assetsBeingDownloaded.Add(asset)) { return; } PtDebug.LogFormat("ABM: starting to fetch asset {0} ({1}) -> {2}", asset.name, asset.displayName, ptAssetLocalPath); // Prefer glTF1 to glTF2. // It used to be that no Poly assets had both formats, so the ordering did not matter. // Blocks assets now have both glTF1 and glTF2. PT does not understand the glTF2 version, // so the ordering matters a great deal. PolyFormat glTF2format = asset.GetFormatIfExists(PolyFormatType.GLTF_2); PolyFormat glTFformat = asset.GetFormatIfExists(PolyFormatType.GLTF); PolyMainInternal.FetchProgressCallback progressCallback = (PolyAsset assetBeingFetched, float progress) => { EditorUtility.DisplayProgressBar(DOWNLOAD_PROGRESS_TITLE, DOWNLOAD_PROGRESS_TEXT, progress); }; if (glTFformat != null) { EditorUtility.DisplayProgressBar(DOWNLOAD_PROGRESS_TITLE, DOWNLOAD_PROGRESS_TEXT, 0.0f); PolyMainInternal.Instance.FetchFormatFiles(asset, PolyFormatType.GLTF, (PolyAsset resultAsset, PolyStatus status) => { EditorUtility.ClearProgressBar(); OnFetchFinished(status, resultAsset, /*isGltf2*/ false, ptAssetLocalPath, options); }, progressCallback); } else if (glTF2format != null) { EditorUtility.DisplayProgressBar(DOWNLOAD_PROGRESS_TITLE, DOWNLOAD_PROGRESS_TEXT, 0.0f); PolyMainInternal.Instance.FetchFormatFiles(asset, PolyFormatType.GLTF_2, (PolyAsset resultAsset, PolyStatus status) => { EditorUtility.ClearProgressBar(); OnFetchFinished(status, resultAsset, /*isGltf2*/ true, ptAssetLocalPath, options); }, progressCallback); } else { Debug.LogError("Asset not in GLTF_2 or GLTF format. Can't import."); PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Unsupported format"); } }
private void OnFetchFinished(PolyStatus status, PolyAsset asset, bool isGltf2, string ptAssetLocalPath, EditTimeImportOptions options) { if (!status.ok) { Debug.LogErrorFormat("Error fetching asset {0} ({1}): {2}", asset.name, asset.displayName, status); EditorUtility.DisplayDialog("Download Error", string.Format("*** Error downloading asset '{0}'. Try again later.", asset.displayName), "OK"); PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Asset fetch failed"); return; } string baseName, downloadLocalPath; if (!PrepareDownload(asset, out baseName, out downloadLocalPath)) { return; } string absPath = PtUtils.ToAbsolutePath(downloadLocalPath); string extension = isGltf2 ? ".gltf2" : ".gltf"; string fileName = baseName + extension; // We have to place an import request so that PolyImporter does the right thing when it sees the new file. PolyImporter.AddImportRequest(new PolyImporter.ImportRequest( downloadLocalPath + "/" + fileName, ptAssetLocalPath, options, asset)); // Now unpackage it. GltfProcessor will pick it up automatically. UnpackPackageToFolder(isGltf2 ? asset.GetFormatIfExists(PolyFormatType.GLTF_2) : asset.GetFormatIfExists(PolyFormatType.GLTF), absPath, fileName); PtDebug.LogFormat("ABM: Successfully downloaded {0} to {1}", asset, absPath); AssetDatabase.Refresh(); if (null != refreshCallback) { refreshCallback(); } }
public static void ShowOnlineDocumentation() { PtAnalytics.SendEvent(PtAnalytics.Action.MENU_ONLINE_DOCUMENTATION); Application.OpenURL(ONLINE_DOCUMENTATION_URL); }
public static void ShowWelcomeWindow() { PtAnalytics.SendEvent(PtAnalytics.Action.MENU_GENERAL_INFORMATION); GetWindow <WelcomeWindow>().Show(); }
public static void Generate() { PtAnalytics.SendEvent(PtAnalytics.Action.MENU_UPDATE_ATTRIBUTIONS_FILE); Generate(/* showUi */ true); }
/// <summary> /// Executes the given import request, producing a PtAsset and a prefab. /// </summary> /// <param name="request">The request to perform.</param> private static void ExecuteImportRequest(ImportRequest request) { PtDebug.LogFormat("Executing import request: {0}", request); string gltfFullPath = PtUtils.ToAbsolutePath(request.gltfLocalPath); string assetLocalPath = request.ptAssetLocalPath; string assetFullPath = PtUtils.ToAbsolutePath(assetLocalPath); PtAsset assetToReplace = AssetDatabase.LoadAssetAtPath <PtAsset>(assetLocalPath); GameObject prefabToReplace = null; if (assetToReplace != null) { if (assetToReplace.assetPrefab == null) { Debug.LogErrorFormat("Couldn't find prefab for asset {0}.", assetToReplace); PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Prefab not found"); return; } prefabToReplace = assetToReplace.assetPrefab; } // Determine if file is glTF2 or glTF1. bool isGltf2 = Path.GetExtension(request.gltfLocalPath) == ".gltf2"; // First, import the GLTF and build a GameObject from it. EditorUtility.DisplayProgressBar(PROGRESS_BAR_TITLE, PROGRESS_BAR_TEXT, 0.5f); // Use a SanitizedPath stream loader because any format file we have downloaded and saved to disk we // have replaced the original relative path string with the MD5 string hash. This custom stream loader // will always convert uris passed to it to this hash value, and read them from there. IUriLoader binLoader = new HashedPathBufferedStreamLoader(Path.GetDirectoryName(gltfFullPath)); ImportGltf.GltfImportResult result = null; using (TextReader reader = new StreamReader(gltfFullPath)) { result = ImportGltf.Import(isGltf2 ? GltfSchemaVersion.GLTF2 : GltfSchemaVersion.GLTF1, reader, binLoader, request.options.baseOptions); } EditorUtility.ClearProgressBar(); string baseName = PtUtils.GetPtAssetBaseName(request.polyAsset); result.root.name = baseName; // Create the asset (delete it first if it exists). if (File.Exists(assetFullPath)) { AssetDatabase.DeleteAsset(assetLocalPath); // If we are replacing an existing asset, we should rename the replacement to the new name, // since the name reflects the identity of the asset. So if the user is importing the asset // dog_a381b3g to replace what was previously cat_v81938.asset, the replacement file should // be named dog_a381b3g.asset, not cat_v81938.asset. assetLocalPath = PtUtils.GetDefaultPtAssetPath(request.polyAsset); assetFullPath = PtUtils.ToAbsolutePath(assetLocalPath); } Directory.CreateDirectory(Path.GetDirectoryName(assetFullPath)); // Create the new PtAsset and fill it in. AssetDatabase.CreateAsset(ScriptableObject.CreateInstance <PtAsset>(), assetLocalPath); PtAsset newAsset = AssetDatabase.LoadAssetAtPath <PtAsset>(assetLocalPath); newAsset.name = baseName; newAsset.title = request.polyAsset.displayName ?? ""; newAsset.author = request.polyAsset.authorName ?? ""; newAsset.license = request.polyAsset.license; newAsset.url = request.polyAsset.Url; // Ensure the imported object has a PtAssetObject component which references the PtAsset. result.root.AddComponent <PtAssetObject>().asset = newAsset; // Add all the meshes to the PtAsset. SaveMeshes(result.meshes, newAsset); // If the asset has materials, save those to the PtAsset. if (result.materials != null) { SaveMaterials(result.materials, newAsset); } // If the asset has textures, save those to the PtAsset. if (result.textures != null) { SaveTextures(result.textures, newAsset); } // Reimport is required to ensure custom asset displays correctly. AssetDatabase.ImportAsset(assetLocalPath); GameObject newPrefab; if (prefabToReplace) { // Replace the existing prefab with our new object, without breaking prefab connections. newPrefab = PrefabUtility.ReplacePrefab(result.root, prefabToReplace, ReplacePrefabOptions.ReplaceNameBased); AssetDatabase.RenameAsset(AssetDatabase.GetAssetPath(newPrefab), baseName); } else { // Create a new prefab. // Prefab path is the same as the asset path but with the extension changed to '.prefab'. string prefabLocalPath = Regex.Replace(assetLocalPath, "\\.asset$", ".prefab"); if (!prefabLocalPath.EndsWith(".prefab")) { Debug.LogErrorFormat("Error: failed to compute prefab path for {0}", assetLocalPath); PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Prefab path error"); return; } newPrefab = PrefabUtility.CreatePrefab(prefabLocalPath, result.root); } // Now ensure the asset points to the prefab. newAsset.assetPrefab = newPrefab; if (newAsset.assetPrefab == null) { Debug.LogErrorFormat("Could not get asset prefab reference for asset {0}", newAsset); PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_FAILED, "Prefab ref error"); } GameObject.DestroyImmediate(result.root); AssetDatabase.Refresh(); if (request.options.alsoInstantiate) { PrefabUtility.InstantiatePrefab(newPrefab); } PtDebug.LogFormat("GLTF import complete: {0}", request); PtAnalytics.SendEvent(PtAnalytics.Action.IMPORT_SUCCESSFUL, isGltf2 ? "GLTF2" : "GLTF1"); // If this is a third-party asset, we need to update the attributions file. AttributionFileGenerator.Generate(/* showUi */ false); EditorWindow.GetWindow <AssetBrowserWindow>().HandleAssetImported(request.polyAsset.name); // Select the prefab in the editor so the user knows where it is. AssetDatabase.Refresh(); Selection.activeObject = newPrefab; EditorGUIUtility.PingObject(newPrefab); }
public static void ShowPolyToolkitSettings() { PtAnalytics.SendEvent(PtAnalytics.Action.MENU_SHOW_SETTINGS); Selection.activeObject = PtSettings.Instance; }