diff options
author | tylermurphy534 <tylermurphy534@gmail.com> | 2022-11-06 15:12:42 -0500 |
---|---|---|
committer | tylermurphy534 <tylermurphy534@gmail.com> | 2022-11-06 15:12:42 -0500 |
commit | eb84bb298d2b95aec7b2ae12cbf25ac64f25379a (patch) | |
tree | efd616a157df06ab661c6d56651853431ac6b08b /VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/RuntimeWorldCreation.cs | |
download | unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.gz unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.bz2 unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.zip |
move to self host
Diffstat (limited to 'VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/RuntimeWorldCreation.cs')
-rw-r--r-- | VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/RuntimeWorldCreation.cs | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/RuntimeWorldCreation.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/RuntimeWorldCreation.cs new file mode 100644 index 00000000..e002d2f8 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/RuntimeWorldCreation.cs @@ -0,0 +1,681 @@ +#define COMMUNITY_LABS_SDK +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.SceneManagement; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Resources; +using VRC.Core; +using System; +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace VRCSDK2 +{ +#if UNITY_EDITOR + public class RuntimeWorldCreation : RuntimeAPICreation + { + public GameObject waitingPanel; + public GameObject blueprintPanel; + public GameObject errorPanel; + + public Text titleText; + public InputField blueprintName; + public InputField blueprintDescription; + public InputField worldCapacity; + public RawImage bpImage; + public Image liveBpImage; + public Toggle shouldUpdateImageToggle; + public Toggle releasePublic; + public Toggle contentNsfw; + + public Toggle contentSex; + public Toggle contentViolence; + public Toggle contentGore; + public Toggle contentOther; + + public Toggle contentFeatured; + public Toggle contentSDKExample; + + public Image showInWorldsMenuGroup; + public Toggle showInActiveWorlds; + public Toggle showInPopularWorlds; + public Toggle showInNewWorlds; + + public InputField userTags; + + public UnityEngine.UI.Button uploadButton; + + public UnityEngine.UI.Button openCommunityLabsDocsButton; + + public GameObject publishToCommunityLabsPanel; + + private Toggle publishToCommLabsToggle; + + private ApiWorld worldRecord; + + private const int MAX_USER_TAGS_FOR_WORLD = 5; + private const int MAX_CHARACTERS_ALLOWED_IN_USER_TAG = 20; + List<String> customTags; + + public static bool IsCurrentWorldInCommunityLabs = false; + public static bool IsCurrentWorldUploaded = false; + public static bool IsCurrentWorldPubliclyPublished = false; + public static bool HasExceededPublishLimit = false; + + new void Start() + { + if (!Application.isEditor || !Application.isPlaying) + return; + + base.Start(); + + IsCurrentWorldInCommunityLabs = false; + IsCurrentWorldUploaded = false; + IsCurrentWorldPubliclyPublished = false; + + + var desc = pipelineManager.GetComponent<VRC.SDKBase.VRC_SceneDescriptor>(); + desc.PositionPortraitCamera(imageCapture.shotCamera.transform); + + Application.runInBackground = true; + UnityEngine.XR.XRSettings.enabled = false; + + uploadButton.onClick.AddListener(SetupUpload); + + openCommunityLabsDocsButton.onClick.AddListener(OpenCommunityLabsDocumentation); + + shouldUpdateImageToggle.onValueChanged.AddListener(ToggleUpdateImage); + + releasePublic.gameObject.SetActive(false); + + System.Action<string> onError = (err) => { + VRC.Core.Logger.LogError("Could not authenticate - " + err, DebugLevel.Always); + blueprintPanel.SetActive(false); + errorPanel.SetActive(true); + }; + + if (!ApiCredentials.Load()) + onError("Not logged in"); + else + APIUser.InitialFetchCurrentUser( + delegate (ApiModelContainer<APIUser> c) + { + UserLoggedInCallback(c.Model as APIUser); + }, + delegate (ApiModelContainer<APIUser> c) + { + onError(c.Error); + } + ); + +#if !COMMUNITY_LABS_SDK + publishToCommunityLabsPanel.gameObject.SetActive(false); +#endif + } + + void UserLoggedInCallback(APIUser user) + { + pipelineManager.user = user; + + ApiWorld model = new ApiWorld(); + model.id = pipelineManager.blueprintId; + model.Fetch(null, + (c) => + { + VRC.Core.Logger.Log("<color=magenta>Updating an existing world.</color>", DebugLevel.All); + worldRecord = c.Model as ApiWorld; + pipelineManager.completedSDKPipeline = !string.IsNullOrEmpty(worldRecord.authorId); + GetUserUploadInformationAndSetupUI(model.id); + }, + (c) => + { + VRC.Core.Logger.Log("<color=magenta>World record not found, creating a new world.</color>", DebugLevel.All); + worldRecord = new ApiWorld { capacity = 16 }; + pipelineManager.completedSDKPipeline = false; + worldRecord.id = pipelineManager.blueprintId; + GetUserUploadInformationAndSetupUI(model.id); + }); + } + + void CheckWorldStatus(string worldId, Action onCheckComplete) + { + // check if world has been previously uploaded, and if world is in community labs + ApiWorld.FetchUploadedWorlds( + delegate (IEnumerable<ApiWorld> worlds) + { + ApiWorld selectedWorld = worlds.FirstOrDefault(w => w.id == worldId); + if (null!=selectedWorld) + { + IsCurrentWorldInCommunityLabs = selectedWorld.IsCommunityLabsWorld; + IsCurrentWorldPubliclyPublished = selectedWorld.IsPublicPublishedWorld; + IsCurrentWorldUploaded = true; + } + if (onCheckComplete != null) onCheckComplete(); + + }, + delegate (string err) + { + IsCurrentWorldInCommunityLabs = false; + IsCurrentWorldUploaded = false; + IsCurrentWorldPubliclyPublished = false; + Debug.Log("CheckWorldStatus error:" + err); + if (onCheckComplete != null) onCheckComplete(); + } + ); + } + + + void GetUserUploadInformationAndSetupUI(string worldId) + { + CheckWorldStatus(worldId, delegate() + { + bool hasSufficientTrustLevelToPublishToCommunityLabs = APIUser.CurrentUser.hasKnownTrustLevel; + APIUser.FetchPublishWorldsInformation( + (c) => + { + try + { + Dictionary<string, object> publish = c as Dictionary<string, object>; + if (publish["canPublish"] is bool) + { + HasExceededPublishLimit = !(bool)(publish["canPublish"]); + } + else + HasExceededPublishLimit = true; + } + catch (Exception) + { + HasExceededPublishLimit = true; + } + + if(Application.isPlaying) + { + SetupUI(hasSufficientTrustLevelToPublishToCommunityLabs, HasExceededPublishLimit); + } + }, + (c) => + { + if(Application.isPlaying) + { + SetupUI(hasSufficientTrustLevelToPublishToCommunityLabs, HasExceededPublishLimit); + } + } + ); + } + ); + } + + void SetupUI(bool hasEnoughTrustToPublishToCL = false, bool hasExceededWeeklyPublishLimit = false) + { +#if COMMUNITY_LABS_SDK + // do not display community labs panel if updating an existing CL world or updating a public world + publishToCommunityLabsPanel.gameObject.SetActive(!IsCurrentWorldUploaded); +#endif + + if (!ValidateAssetBundleBlueprintID(worldRecord.id)) + { + blueprintPanel.SetActive(false); + errorPanel.SetActive(true); + OnSDKPipelineError("The asset bundle is out of date. Please rebuild the scene using 'New Build'.", "The blueprint ID in the scene does not match the id in the asset bundle."); + return; + } + + contentFeatured.gameObject.SetActive(APIUser.CurrentUser.hasSuperPowers); + contentSDKExample.gameObject.SetActive(APIUser.CurrentUser.hasSuperPowers); + + if (APIUser.Exists(pipelineManager.user)) + { + waitingPanel.SetActive(false); + blueprintPanel.SetActive(true); + errorPanel.SetActive(false); + + if (string.IsNullOrEmpty(worldRecord.authorId) || worldRecord.authorId == pipelineManager.user.id) + { + titleText.text = "Configure World"; + blueprintName.text = worldRecord.name; + worldCapacity.text = worldRecord.capacity.ToString(); + contentSex.isOn = worldRecord.tags.Contains("content_sex"); + contentViolence.isOn = worldRecord.tags.Contains("content_violence"); + contentGore.isOn = worldRecord.tags.Contains("content_gore"); + contentOther.isOn = worldRecord.tags.Contains("content_other"); + shouldUpdateImageToggle.interactable = isUpdate; + shouldUpdateImageToggle.isOn = !isUpdate; + liveBpImage.enabled = !isUpdate; + bpImage.enabled = isUpdate; + + if (!APIUser.CurrentUser.hasSuperPowers) + { + releasePublic.gameObject.SetActive(false); + releasePublic.isOn = false; + releasePublic.interactable = false; + + contentFeatured.isOn = contentSDKExample.isOn = false; + } + else + { + contentFeatured.isOn = worldRecord.tags.Contains("content_featured"); + contentSDKExample.isOn = worldRecord.tags.Contains("content_sdk_example"); + + releasePublic.isOn = worldRecord.releaseStatus == "public"; + releasePublic.gameObject.SetActive(true); + } + + // "show in worlds menu" + if (APIUser.CurrentUser.hasSuperPowers) + { + showInWorldsMenuGroup.gameObject.SetActive(true); + showInActiveWorlds.isOn = !worldRecord.tags.Contains("admin_hide_active"); + showInPopularWorlds.isOn = !worldRecord.tags.Contains("admin_hide_popular"); + showInNewWorlds.isOn = !worldRecord.tags.Contains("admin_hide_new"); + } + else + { + showInWorldsMenuGroup.gameObject.SetActive(false); + } + + blueprintDescription.text = worldRecord.description; + + userTags.text = ""; + foreach (var tag in worldRecord.publicTags) + { + userTags.text = userTags.text + tag.Replace("author_tag_", ""); + userTags.text = userTags.text + " "; + } + + ImageDownloader.DownloadImage(worldRecord.imageUrl, 0, obj => bpImage.texture = obj, null); + } + else // user does not own world id associated with descriptor + { + Debug.LogErrorFormat("{0} is not an owner of {1}", worldRecord.authorId, pipelineManager.user.id); + blueprintPanel.SetActive(false); + errorPanel.SetActive(true); + } + } + else + { + waitingPanel.SetActive(true); + blueprintPanel.SetActive(false); + errorPanel.SetActive(false); + + if (!APIUser.CurrentUser.hasSuperPowers) + { + releasePublic.gameObject.SetActive(false); + releasePublic.isOn = false; + releasePublic.interactable = false; + } + else + { + releasePublic.gameObject.SetActive(true); + releasePublic.isOn = false; + } + } + + // set up publish to Community Labs checkbox and text + int worldsPublishedThisWeek = hasExceededWeeklyPublishLimit ? 1 : 0; + int maximumWorldsAllowedToPublishPerWeek = 1; + publishToCommLabsToggle = publishToCommunityLabsPanel.GetComponentInChildren<Toggle>(); + + if (null != publishToCommLabsToggle) + { + // disable publishing to CL checkbox if not enough trust or exceeded publish limit + publishToCommLabsToggle.interactable = hasEnoughTrustToPublishToCL && !hasExceededWeeklyPublishLimit; + + Text publishText = publishToCommLabsToggle.gameObject.GetComponentInChildren<Text>(); + if (null != publishText) + { + if (!hasEnoughTrustToPublishToCL) + { + publishText.text = "Not enough Trust to Publish to Community Labs"; + } + else + { + if (hasExceededWeeklyPublishLimit) + { + publishText.text = "Publish limit for Community Labs Exceeded\n" + "(" + worldsPublishedThisWeek + "/" + maximumWorldsAllowedToPublishPerWeek + " Published this week)"; + } + else + { + publishText.text = "Publish to Community Labs\n" + "(" + worldsPublishedThisWeek + "/" + maximumWorldsAllowedToPublishPerWeek + " Published this week)"; + } + } + } + } + } + + public void SetupUpload() + { + if (!ParseUserTags()) + return; + + publishingToCommunityLabs = (publishToCommLabsToggle != null) && (publishToCommLabsToggle.isActiveAndEnabled) && (publishToCommLabsToggle.isOn); + + uploadTitle = "Preparing For Upload"; + isUploading = true; + + string abPath = UnityEditor.EditorPrefs.GetString("currentBuildingAssetBundlePath"); + + + string unityPackagePath = UnityEditor.EditorPrefs.GetString("VRC_exportedUnityPackagePath"); + + UnityEditor.EditorPrefs.SetBool("VRCSDK2_scene_changed", true); + UnityEditor.EditorPrefs.SetInt("VRCSDK2_capacity", System.Convert.ToInt16(worldCapacity.text)); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_content_sex", contentSex.isOn); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_content_violence", contentViolence.isOn); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_content_gore", contentGore.isOn); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_content_other", contentOther.isOn); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_release_public", releasePublic.isOn); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_content_featured", contentFeatured.isOn); + UnityEditor.EditorPrefs.SetBool("VRCSDK2_content_sdk_example", contentSDKExample.isOn); + + if (string.IsNullOrEmpty(worldRecord.id)) + { + pipelineManager.AssignId(); + worldRecord.id = pipelineManager.blueprintId; + } + + string blueprintId = worldRecord.id; + int version = Mathf.Max(1, worldRecord.version + 1); + PrepareVRCPathForS3(abPath, blueprintId, version, ApiWorld.VERSION); + + if (!string.IsNullOrEmpty(unityPackagePath) && System.IO.File.Exists(unityPackagePath)) + { + VRC.Core.Logger.Log("Found unity package path. Preparing to upload!", DebugLevel.All); + PrepareUnityPackageForS3(unityPackagePath, blueprintId, version, ApiWorld.VERSION); + } + + StartCoroutine(UploadNew()); + } + + void OnUploadedWorld() + { + const string devUrl = "https://dev-api.vrchat.cloud"; + const string releaseUrl = "https://vrchat.com"; + + string uploadedWorldURL = (API.IsDevApi() ? devUrl : releaseUrl) + "/home/world/" + pipelineManager.blueprintId; + OnSDKPipelineComplete(uploadedWorldURL); + } + + IEnumerator UploadNew() + { + bool caughtInvalidInput = false; + if (!ValidateNameInput(blueprintName)) + caughtInvalidInput = true; + + if (caughtInvalidInput) + yield break; + + VRC.Core.Logger.Log("Starting upload", DebugLevel.Always); + + // upload unity package + if (!string.IsNullOrEmpty(uploadUnityPackagePath)) + { + yield return StartCoroutine(UploadFile(uploadUnityPackagePath, isUpdate ? worldRecord.unityPackageUrl : "", GetFriendlyWorldFileName("Unity package"), "Unity package", + delegate (string fileUrl) + { + cloudFrontUnityPackageUrl = fileUrl; + } + )); + } + + // upload asset bundle + if (!string.IsNullOrEmpty(uploadVrcPath)) + { + yield return StartCoroutine(UploadFile(uploadVrcPath, isUpdate ? worldRecord.assetUrl : "", GetFriendlyWorldFileName("Asset bundle"), "Asset bundle", + delegate (string fileUrl) + { + cloudFrontAssetUrl = fileUrl; + } + )); + } + + if (isUpdate) + yield return StartCoroutine(UpdateBlueprint()); + else + yield return StartCoroutine(CreateBlueprint()); + + if (publishingToCommunityLabs) + { + ApiWorld.PublishWorldToCommunityLabs(pipelineManager.blueprintId, + (world) => OnUploadedWorld(), + (err) => + { + Debug.LogError("PublishWorldToCommunityLabs error:" + err); + OnUploadedWorld(); + } + ); + } + else + { + OnUploadedWorld(); + } + } + + private string GetFriendlyWorldFileName(string type) + { + return "World - " + blueprintName.text + " - " + type + " - " + Application.unityVersion + "_" + ApiWorld.VERSION.ApiVersion + + "_" + VRC.Tools.Platform + "_" + API.GetServerEnvironmentForApiUrl(); + } + + List<string> BuildTags() + { + var tags = new List<string>(); + if (contentSex.isOn) + tags.Add("content_sex"); + if (contentViolence.isOn) + tags.Add("content_violence"); + if (contentGore.isOn) + tags.Add("content_gore"); + if (contentOther.isOn) + tags.Add("content_other"); + + if (APIUser.CurrentUser.hasSuperPowers) + { + if (contentFeatured.isOn) + tags.Add("content_featured"); + if (contentSDKExample.isOn) + tags.Add("content_sdk_example"); + if(releasePublic.isOn) + tags.Add("admin_approved"); + } + + // "show in worlds menu" + if (APIUser.CurrentUser.hasSuperPowers) + { + if (!showInActiveWorlds.isOn) + tags.Add("admin_hide_active"); + if (!showInPopularWorlds.isOn) + tags.Add("admin_hide_popular"); + if (!showInNewWorlds.isOn) + tags.Add("admin_hide_new"); + } + + // add any author tags + foreach (var word in customTags) + { + // add all custom tags with "author_tag_" prefix + tags.Add("author_tag_" + word); + } + + return tags; + } + + bool ParseUserTags() + { + bool validTags = true; + customTags = new List<string>(); + char[] delimiterChars = { ' ', ',', '.', ':', '\t', '\n', '"', '#' }; + + // split user tags into individual words + string[] words = userTags.text.Split(delimiterChars, StringSplitOptions.RemoveEmptyEntries); + + foreach (var word in words) + { + customTags.Add(word.ToLower()); + } + + // check that number of tags is within tag limit + if (words.Count() > MAX_USER_TAGS_FOR_WORLD) + { + validTags = false; + UnityEditor.EditorUtility.DisplayDialog("Tags are limited to a maximum of " + MAX_USER_TAGS_FOR_WORLD + " per world.", "Please remove excess tags before uploading!", "OK"); + } + else + { + // check that no tags exceed maximum tag length + int maximumTagLength = 0; + foreach (string item in words) + { + if (item.Length > maximumTagLength) + { + maximumTagLength = item.Length; + } + } + + if (maximumTagLength > MAX_CHARACTERS_ALLOWED_IN_USER_TAG) + { + validTags = false; + UnityEditor.EditorUtility.DisplayDialog("Tags are limited to a maximum of " + MAX_CHARACTERS_ALLOWED_IN_USER_TAG + " characters per tag.", "One or more of your tags exceeds the maximum " + MAX_CHARACTERS_ALLOWED_IN_USER_TAG + " character limit.\n\n" + "Please shorten tags before uploading!", "OK"); + } + else + { + // make sure tags are all alphanumeric + foreach (var word in words) + { + if (!word.All(char.IsLetterOrDigit)) + { + validTags = false; + UnityEditor.EditorUtility.DisplayDialog("Tags should consist of alphanumeric characters only.", "Please remove any non-alphanumeric characters from tags before uploading!", "OK"); + } + } + } + } + + return validTags; + } + + protected override IEnumerator CreateBlueprint() + { + yield return StartCoroutine(UpdateImage(isUpdate ? worldRecord.imageUrl : "", GetFriendlyWorldFileName("Image"))); + + SetUploadProgress("Saving Blueprint to user", "Almost finished!!", 0.0f); + ApiWorld world = new ApiWorld + { + id = worldRecord.id, + authorName = pipelineManager.user.displayName, + authorId = pipelineManager.user.id, + name = blueprintName.text, + imageUrl = cloudFrontImageUrl, + assetUrl = cloudFrontAssetUrl, + unityPackageUrl = cloudFrontUnityPackageUrl, + description = blueprintDescription.text, + tags = BuildTags(), + releaseStatus = (releasePublic.isOn) ? ("public") : ("private"), + capacity = System.Convert.ToInt16(worldCapacity.text), + occupants = 0, + shouldAddToAuthor = true + }; + + if (APIUser.CurrentUser.hasSuperPowers) + world.isCurated = contentFeatured.isOn || contentSDKExample.isOn; + else + world.isCurated = false; + + bool doneUploading = false; + world.Post( + (c) => + { + ApiWorld savedBP = (ApiWorld)c.Model; + pipelineManager.blueprintId = savedBP.id; + UnityEditor.EditorPrefs.SetString("blueprintID-" + pipelineManager.GetInstanceID().ToString(), savedBP.id); + VRC.Core.Logger.Log("Setting blueprintID on pipeline manager and editor prefs", DebugLevel.All); + doneUploading = true; + }, + (c) => { doneUploading = true; Debug.LogError(c.Error); }); + + while (!doneUploading) + yield return null; + } + + protected override IEnumerator UpdateBlueprint() + { + bool doneUploading = false; + + worldRecord.name = blueprintName.text; + worldRecord.description = blueprintDescription.text; + worldRecord.capacity = System.Convert.ToInt16(worldCapacity.text); + worldRecord.assetUrl = cloudFrontAssetUrl; + worldRecord.tags = BuildTags(); + worldRecord.releaseStatus = (releasePublic.isOn) ? ("public") : ("private"); + worldRecord.unityPackageUrl = cloudFrontUnityPackageUrl; + worldRecord.isCurated = contentFeatured.isOn || contentSDKExample.isOn; + + if (shouldUpdateImageToggle.isOn) + { + yield return StartCoroutine(UpdateImage(isUpdate ? worldRecord.imageUrl : "", GetFriendlyWorldFileName("Image"))); + + worldRecord.imageUrl = cloudFrontImageUrl; + } + + SetUploadProgress("Saving Blueprint", "Almost finished!!", 0.0f); + worldRecord.Save((c) => doneUploading = true, (c) => { doneUploading = true; Debug.LogError(c.Error); }); + + while (!doneUploading) + yield return null; + } + + void ToggleUpdateImage(bool isOn) + { + if (isOn) + { + bpImage.enabled = false; + liveBpImage.enabled = true; + } + else + { + bpImage.enabled = true; + liveBpImage.enabled = false; + ImageDownloader.DownloadImage(worldRecord.imageUrl, 0, obj => bpImage.texture = obj, null); + } + } + + protected override void DisplayUpdateCompletedDialog(string contentUrl = null) + { +#if UNITY_EDITOR +#if COMMUNITY_LABS_SDK + if (null != contentUrl) + { + CheckWorldStatus(pipelineManager.blueprintId, delegate () + { + ContentUploadedDialog window = (ContentUploadedDialog)EditorWindow.GetWindow(typeof(ContentUploadedDialog), true, "VRCSDK", true); + window.setContentURL(contentUrl); + window.Show(); + // refresh UI based on uploaded world + GetUserUploadInformationAndSetupUI(pipelineManager.blueprintId); + } + ); + } + else +#endif + base.DisplayUpdateCompletedDialog(contentUrl); +#endif + } + + private void OpenCommunityLabsDocumentation() + { + Application.OpenURL(CommunityLabsConstants.COMMUNITY_LABS_DOCUMENTATION_URL); + } + + void OnDestroy() + { + UnityEditor.EditorUtility.ClearProgressBar(); + UnityEditor.EditorPrefs.DeleteKey("currentBuildingAssetBundlePath"); + } + } +#endif +} + + |