using System.Collections; using System.Collections.Generic; using System; using System.IO; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; using VRC.Core; #if UNITY_EDITOR using UnityEditor; #endif namespace VRCSDK2 { #if UNITY_EDITOR public class RuntimeAPICreation : MonoBehaviour { public VRC.Core.PipelineManager pipelineManager; protected bool forceNewFileCreation = false; protected bool useFileApi = false; protected bool isUploading = false; protected float uploadProgress = 0f; protected string uploadMessage; protected string uploadTitle; protected string uploadVrcPath; protected string uploadUnityPackagePath; protected string cloudFrontAssetUrl; protected string cloudFrontImageUrl; protected string cloudFrontUnityPackageUrl; protected CameraImageCapture imageCapture; private bool cancelRequested = false; public static bool publishingToCommunityLabs = false; private Dictionary mRetryState = new Dictionary(); protected bool isUpdate { get { return pipelineManager.completedSDKPipeline; } } protected void Start() { if (!Application.isEditor || !Application.isPlaying) return; PipelineSaver ps = GameObject.FindObjectOfType(); pipelineManager = ps.gameObject.GetComponent(); imageCapture = GetComponent(); imageCapture.shotCamera = GameObject.Find("VRCCam").GetComponent(); LoadUploadRetryStateFromCache(); forceNewFileCreation = UnityEditor.EditorPrefs.GetBool("forceNewFileCreation", true); useFileApi = UnityEditor.EditorPrefs.GetBool("useFileApi", false); API.SetOnlineMode(true); } protected void Update() { if (isUploading) { bool cancelled = UnityEditor.EditorUtility.DisplayCancelableProgressBar(uploadTitle, uploadMessage, uploadProgress); if (cancelled) { cancelRequested = true; } if (EditorApplication.isPaused) EditorApplication.isPaused = false; } } protected void LoadUploadRetryStateFromCache() { try { string json = File.ReadAllText(GetUploadRetryStateFilePath()); mRetryState = VRC.Tools.ObjDictToStringDict(VRC.Tools.JsonDecode(json) as Dictionary); Debug.LogFormat(" loaded retry state: {0}", json); } catch (Exception) { // normal case return; } Debug.Log("Loaded upload retry state from: " + GetUploadRetryStateFilePath()); } protected void SaveUploadRetryState(string key, string val) { if (string.IsNullOrEmpty(val)) return; mRetryState[key] = val; SaveUploadRetryState(); } protected void SaveUploadRetryState() { try { Directory.CreateDirectory(Path.GetDirectoryName(GetUploadRetryStateFilePath())); string json = VRC.Tools.JsonEncode(mRetryState); File.WriteAllText(GetUploadRetryStateFilePath(), json); Debug.LogFormat(" wrote retry state: {0}", json); } catch (Exception e) { Debug.LogError("Couldn't save upload retry state: " + GetUploadRetryStateFilePath() + "\n" + e.Message); return; } Debug.Log("Saved upload retry state to: " + GetUploadRetryStateFilePath()); } protected void ClearUploadRetryState() { try { if (!File.Exists(GetUploadRetryStateFilePath())) return; File.Delete(GetUploadRetryStateFilePath()); } catch (Exception e) { Debug.LogError("Couldn't delete upload retry state: " + GetUploadRetryStateFilePath() + "\n" + e.Message); return; } Debug.Log("Cleared upload retry state at: " + GetUploadRetryStateFilePath()); } protected string GetUploadRetryStateFilePath() { string id = UnityEditor.AssetDatabase.AssetPathToGUID(SceneManager.GetActiveScene().path); return Path.Combine(VRC.Tools.GetTempFolderPath(id), "upload_retry.dat"); } protected string GetUploadRetryStateValue(string key) { return mRetryState.ContainsKey(key) ? mRetryState[key] : ""; } protected virtual void DisplayUpdateCompletedDialog(string contentUrl=null) { if (UnityEditor.EditorUtility.DisplayDialog("VRChat SDK", "Update Complete! Launch VRChat to see your uploaded content." + (null==contentUrl ? "" : "\n\nManage content at: " + contentUrl ), (null == contentUrl) ? "Okay" : CommunityLabsConstants.MANAGE_WORLD_IN_BROWSER_STRING, (null == contentUrl) ? "" : "Done" )) { if (null!=contentUrl) { Application.OpenURL(contentUrl); } } } protected void OnSDKPipelineComplete(string contentUrl=null) { VRC.Core.Logger.Log("OnSDKPipelineComplete", DebugLevel.All); isUploading = false; pipelineManager.completedSDKPipeline = true; ClearUploadRetryState(); UnityEditor.EditorPrefs.SetBool("forceNewFileCreation", false); UnityEditor.EditorApplication.isPaused = false; UnityEditor.EditorApplication.isPlaying = false; UnityEditor.EditorUtility.ClearProgressBar(); DisplayUpdateCompletedDialog(contentUrl); } protected void OnSDKPipelineError(string error, string details) { VRC.Core.Logger.Log("OnSDKPipelineError: " + error + " - " + details, DebugLevel.All); isUploading = false; pipelineManager.completedSDKPipeline = true; UnityEditor.EditorApplication.isPaused = false; UnityEditor.EditorApplication.isPlaying = false; UnityEditor.EditorUtility.ClearProgressBar(); if (cancelRequested) UnityEditor.EditorUtility.DisplayDialog("VRChat SDK", "The update was cancelled.", "Okay"); else UnityEditor.EditorUtility.DisplayDialog("VRChat SDK", "Error updating content. " + error + "\n" + details, "Okay"); } protected void SetUploadProgress(string title, string message, float progress) { uploadTitle = title; uploadMessage = message; uploadProgress = progress; } protected bool WasCancelRequested(ApiFile apiFile) { return cancelRequested; } protected void PrepareUnityPackageForS3(string packagePath, string blueprintId, int version, AssetVersion assetVersion) { uploadUnityPackagePath = Application.temporaryCachePath + "/" + blueprintId + "_" + version.ToString() + "_" + Application.unityVersion + "_" + assetVersion.ApiVersion + "_" + VRC.Tools.Platform + "_" + API.GetServerEnvironmentForApiUrl() + ".unitypackage"; uploadUnityPackagePath.Trim(); uploadUnityPackagePath.Replace(' ', '_'); if (System.IO.File.Exists(uploadUnityPackagePath)) System.IO.File.Delete(uploadUnityPackagePath); System.IO.File.Copy(packagePath, uploadUnityPackagePath); } protected void PrepareVRCPathForS3(string abPath, string blueprintId, int version, AssetVersion assetVersion) { uploadVrcPath = Application.temporaryCachePath + "/" + blueprintId + "_" + version.ToString() + "_" + Application.unityVersion + "_" + assetVersion.ApiVersion + "_" + VRC.Tools.Platform + "_" + API.GetServerEnvironmentForApiUrl() + System.IO.Path.GetExtension(abPath); uploadVrcPath.Trim(); uploadVrcPath.Replace(' ', '_'); if (System.IO.File.Exists(uploadVrcPath)) System.IO.File.Delete(uploadVrcPath); System.IO.File.Copy(abPath, uploadVrcPath); } protected IEnumerator UploadFile(string filename, string existingFileUrl, string friendlyFilename, string fileType, Action onSuccess) { if (string.IsNullOrEmpty(filename)) yield break; VRC.Core.Logger.Log("Uploading " + fileType + "(" + filename + ") ...", DebugLevel.All); SetUploadProgress("Uploading " + fileType + "...", "", 0.0f); string fileId = GetUploadRetryStateValue(filename); if (string.IsNullOrEmpty(fileId)) fileId = isUpdate ? ApiFile.ParseFileIdFromFileAPIUrl(existingFileUrl) : ""; string errorStr = ""; string newFileUrl = ""; yield return StartCoroutine(ApiFileHelper.Instance.UploadFile(filename, forceNewFileCreation ? "" : fileId, friendlyFilename, delegate (ApiFile apiFile, string message) { newFileUrl = apiFile.GetFileURL(); if (VRC.Core.Logger.DebugLevelIsEnabled(DebugLevel.API)) VRC.Core.Logger.Log(fileType + " upload succeeded: " + message + " (" + filename + ") => " + apiFile.ToString(), DebugLevel.API); else VRC.Core.Logger.Log(fileType + " upload succeeded ", DebugLevel.Always); }, delegate (ApiFile apiFile, string error) { SaveUploadRetryState(filename, apiFile.id); errorStr = error; Debug.LogError(fileType + " upload failed: " + error + " (" + filename + ") => " + apiFile.ToString()); }, delegate (ApiFile apiFile, string status, string subStatus, float pct) { SetUploadProgress("Uploading " + fileType + "...", status + (!string.IsNullOrEmpty(subStatus) ? " (" + subStatus + ")" : ""), pct); }, WasCancelRequested )); if (!string.IsNullOrEmpty(errorStr)) { OnSDKPipelineError(fileType + " upload failed.", errorStr); yield break; } if (onSuccess != null) onSuccess(newFileUrl); } protected IEnumerator UpdateImage(string existingFileUrl, string friendlyFileName) { string imagePath = imageCapture.TakePicture(); if (!string.IsNullOrEmpty(imagePath)) { yield return StartCoroutine(UploadFile(imagePath, existingFileUrl, friendlyFileName, "Image", delegate (string fileUrl) { cloudFrontImageUrl = fileUrl; } )); } } protected virtual IEnumerator CreateBlueprint() { throw new NotImplementedException(); } protected virtual IEnumerator UpdateBlueprint() { throw new NotImplementedException(); } protected bool ValidateNameInput(InputField nameInput) { bool isValid = true; if (string.IsNullOrEmpty(nameInput.text)) { isUploading = false; UnityEditor.EditorUtility.DisplayDialog("Invalid Input", "Cannot leave the name field empty.", "OK"); isValid = false; } return isValid; } protected bool ValidateAssetBundleBlueprintID(string blueprintID) { string lastBuiltID = UnityEditor.EditorPrefs.GetString("lastBuiltAssetBundleBlueprintID", ""); return !string.IsNullOrEmpty(lastBuiltID) && lastBuiltID == blueprintID; } } #endif }