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 /VRCSDK3Worlds/Assets/VRWorldToolkit | |
download | unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.gz unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.tar.bz2 unityprojects-eb84bb298d2b95aec7b2ae12cbf25ac64f25379a.zip |
move to self host
Diffstat (limited to 'VRCSDK3Worlds/Assets/VRWorldToolkit')
79 files changed, 9141 insertions, 0 deletions
diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/LICENSE b/VRCSDK3Worlds/Assets/VRWorldToolkit/LICENSE new file mode 100644 index 00000000..7b452180 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 oneVR + +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/VRCSDK3Worlds/Assets/VRWorldToolkit/LICENSE.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/LICENSE.meta new file mode 100644 index 00000000..cee146f6 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d4c1f247799a190408e8f0e319b9b195 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs.meta new file mode 100644 index 00000000..bc0e42b0 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 989c97bd816dfe14e9a39cb722b71037 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs/DepthPass.prefab b/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs/DepthPass.prefab new file mode 100644 index 00000000..f02a4d7a --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs/DepthPass.prefab @@ -0,0 +1,71 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6200045910917526951 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1770991844035162551} + - component: {fileID: 8266425946052086372} + m_Layer: 0 + m_Name: DepthPass + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1770991844035162551 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6200045910917526951} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!108 &8266425946052086372 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6200045910917526951} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 0.001 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 1 + m_Resolution: 0 + m_CustomResolution: -1 + m_Strength: 0 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs/DepthPass.prefab.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs/DepthPass.prefab.meta new file mode 100644 index 00000000..a445ac7d --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Prefabs/DepthPass.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9036cddced1892b42bbde6e1919fbf15 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/README.md b/VRCSDK3Worlds/Assets/VRWorldToolkit/README.md new file mode 100644 index 00000000..e7c8c0b2 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/README.md @@ -0,0 +1,92 @@ +# VRWorld Toolkit + +<img src="https://user-images.githubusercontent.com/4764355/114099005-d2a86880-98ca-11eb-8de1-f77360503d6d.png"> + +<div align="center"> + +[](https://github.com/oneVR/VRWorldToolkit/stargazers) +[](https://github.com/oneVR/VRWorldToolkit/releases) +[](https://github.com/oneVR/VRWorldToolkit/releases/latest) +[](https://github.com/oneVR/VRWorldToolkit/blob/master/LICENSE) + + +</div> + +**VRWorld Toolkit** is a Unity Editor extension made to make VRChat world creation more accessible and lower the entry-level to make a good performing world. Currently, the tool is aimed only at people making VRChat worlds, and most functions only work with the VRCSDK imported, but this might change in the future. + +To report problems, you can either join my [Discord server](https://discord.com/invite/FCm28DM) or create [a new issue](https://github.com/oneVR/VRWorldToolkit/issues/new/choose). Also check out my [Patreon](https://www.patreon.com/onevr)! + +## Setup + +### Requirements +* Unity 2018.4.20f1 +* Latest VRChat SDK [SDK2 / SDK3 Worlds or Avatars](https://vrchat.com/home/download) + +### Getting Started +* Import the latest release from [here](https://github.com/oneVR/VRWorldToolkit/releases) into your Unity project +* After, if everything went well, you will see the VRWorld Toolkit dropdown appear at the top bar if not check [Troubleshooting](#troubleshooting) + +### Troubleshooting +First, make sure you are running the latest SDK (SDK2 / SDK3 Worlds or Avatars) if not [update](https://docs.vrchat.com/docs/updating-the-sdk). This project is kept up to date, supporting the latest SDK versions. Support for older versions is not guaranteed. + +Start by opening the Unity Console either by using `Ctrl + Shift + C` or from `Window > General > Console`. Afterward, make sure red errors are enabled from the top right corner of the window. Finally, press `Clear` in the top left corner, which will narrow the view down to only compilation stopping errors. + +If the errors that are left mention Post Processing or Bakery when the project * does not* have these in it currently, see the following paragraphs. + +The most common issue is when the project previously had `Post Processing` or `Bakery` but has since been removed. This will leave behind a Scripting Define Symbol that the assets automatically add, making VRWorld Toolkit think they still exist in the project. + +This can be manually removed from `Edit > Project Settings > Player > Other Settings > Scripting Define Symbols` + +* For Bakery: `BAKERY_INCLUDED` +* For Post Processing: `UNITY_POST_PROCESSING_STACK_V2` + +These symbols' primary function is to load parts of code only when they are set in the project. However, they do not automatically get removed with the asset. + +A more rare issue is also caused by having a `Bloom.cs` script or just `Bloom` class in the global namespace in your project conflicting with Post Processing. This can usually be seen in the console by having repeated errors for Post Processing bloom not being able to be accessed from VRWorld Toolkit scripts. The easiest solution is finding and removing the offending script often found just by searching for `Bloom` in your assets. + +## Main features + +<img align="right" width="400" margin="20" src="https://user-images.githubusercontent.com/4764355/114107922-9bda4e80-98da-11eb-8024-ad2bde3c5b6b.png"> + +### World Debugger +Goes through the scene and checks for common issues, and makes suggestions on what to improve. Includes over 90 different tips, warnings, errors, and general messages! + +It also allows viewing the stats of the latest builds SDK has done for an easily accessible overview of what the build consists of. It also saves the latest Windows and Android builds separately for easy comparison between the two. + +### Disable On Build +After the setup is run from `VRWorld Toolkit > Disable On Build > Setup` a new tag is added `DisableOnBuild` that automatically disables all GameObjects marked with it before a build happens. The most significant use case for this is easier to manage trigger-based occlusion. + +### Post Processing +Offers a one-click solution to having a working Post Processing setup with a simple example profile for further editing. + +### Quick Functions + +#### Copy World ID +Helps you to quickly copy the current scenes world ID to clipboard without having to fumble finding the Scene Descriptor. + +#### Mass Texture Importer +Batch processes textures to quickly apply crunch compression and other settings to all textures in the current scene or all assets in the project. + +### Custom Editors +Adds more features to the pre-existing VRChat components to make them easier to use and provide quality of life improvements. If not needed, they can also be easily disabled from `VRWorld Toolkit > Custom Editor > Disable`. + +Includes additions to: + +* VRC Mirror Reflection + * Quick set layers to commonly used setups + * Warnings and messages for common problems people run into with mirrors + * Explanations for VRChat specific layers +* VRC Avatar Pedestal + * Adds a feature to mass copy and set IDs to pedestals while having multiple selected + * Draws outlines to where the pedestal image will appear in-game when you select the GameObject with the pedestal component on it + +### Useful Links +Quick access to commonly used links related to VRChat content creation. + +## Special Thanks to + +* [Pumkin](https://github.com/rurre/PumkinsAvatarTools) - For helping me a lot to get started and creating the original Disable On Upload feature that got me started on this project +* [Silent](http://s-ilent.gitlab.io/index.html) - For making my texts more clear and for help on Post Processing features +* [Metamaniac (Table)](https://twitter.com/Metamensa) - Checked through my texts and found all the stupid typos I made + +**Disclaimer:** This extension is still a work in progress. Even though I try to test it thoroughly, things can break. *Remember to make backups of your projects and use this at your own risk!*
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/README.md.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/README.md.meta new file mode 100644 index 00000000..7a8a40a8 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6951d11f20831894aadd8a27299ba677 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources.meta new file mode 100644 index 00000000..f24d9f03 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 831f8764e30b4254cafd8a1d246123cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons.meta new file mode 100644 index 00000000..64233e1d --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 472b0d41b861604469188907bc9a05c0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Bad_FPS_Icon.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Bad_FPS_Icon.png Binary files differnew file mode 100644 index 00000000..94dd5182 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Bad_FPS_Icon.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Bad_FPS_Icon.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Bad_FPS_Icon.png.meta new file mode 100644 index 00000000..bae95028 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Bad_FPS_Icon.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: cf3514a8266576c44bdb115f3e90ad2d +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 31acc89a03d9b2d4b88b66958d9cd3db + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Error_Icon.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Error_Icon.png Binary files differnew file mode 100644 index 00000000..36847cd1 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Error_Icon.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Error_Icon.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Error_Icon.png.meta new file mode 100644 index 00000000..d4a8e673 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Error_Icon.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 6552be13f9333b440ab2f70db54f4bcd +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 32644b905b32aa2438f44128c90461b0 + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Good_FPS_Icon.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Good_FPS_Icon.png Binary files differnew file mode 100644 index 00000000..001a5f7d --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Good_FPS_Icon.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Good_FPS_Icon.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Good_FPS_Icon.png.meta new file mode 100644 index 00000000..0024299d --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Good_FPS_Icon.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: ba2fba4f6e6b52641b65057aae7d8c91 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: edd65e5dbff80e445ad875319838179c + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Info.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Info.png Binary files differnew file mode 100644 index 00000000..9d0a6371 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Info.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Info.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Info.png.meta new file mode 100644 index 00000000..0c5a7199 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Info.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 31fe8245f609dbe449606eeb22eceea4 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: cbff5f00b516cc849bf2b84aa1a0a233 + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Tips.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Tips.png Binary files differnew file mode 100644 index 00000000..30da8b88 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Tips.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Tips.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Tips.png.meta new file mode 100644 index 00000000..80962729 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Performance_Tips.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: a3de8bd254d420d4c8d381013287bdc9 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 3769a45d396071645a012783697b46b7 + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Warning_Icon.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Warning_Icon.png Binary files differnew file mode 100644 index 00000000..e3c97c74 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Warning_Icon.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Warning_Icon.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Warning_Icon.png.meta new file mode 100644 index 00000000..9c0d0902 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/DebuggerIcons/Warning_Icon.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 9716735332b04a3459d8446f7b8dd369 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 16 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: 1 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 7736e6fd97215f24fa5bc47b66e79468 + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing.meta new file mode 100644 index 00000000..232c04fd --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f6fabb62862200044840f6fa004668d2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing/SilentProfile.asset b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing/SilentProfile.asset new file mode 100644 index 00000000..bacd3e07 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing/SilentProfile.asset @@ -0,0 +1,1413 @@ +%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: 8e6292b2c06870d4495f009f912b9600, type: 3} + m_Name: SilentProfile + m_EditorClassIdentifier: + settings: + - {fileID: 114357776453000568} + - {fileID: 114458790615753430} + - {fileID: 114254744475804696} +--- !u!114 &114254744475804696 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: 48a79b01ea5641d4aa6daa2e23605641, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: + active: 1 + enabled: + overrideState: 1 + value: 1 + intensity: + overrideState: 1 + value: 0.15 + threshold: + overrideState: 1 + value: 0 + softKnee: + overrideState: 1 + value: 0 + clamp: + overrideState: 1 + value: 100 + diffusion: + overrideState: 1 + value: 10 + anamorphicRatio: + overrideState: 1 + value: 0 + color: + overrideState: 1 + value: {r: 1, g: 1, b: 1, a: 1} + fastMode: + overrideState: 1 + value: 0 + dirtTexture: + overrideState: 1 + value: {fileID: 0} + defaultState: 1 + dirtIntensity: + overrideState: 1 + value: 0 +--- !u!114 &114357776453000568 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: b3f6f3f7c722b4544b97e3c75840aa33, type: 3} + m_Name: AutoExposure + m_EditorClassIdentifier: + active: 1 + enabled: + overrideState: 1 + value: 1 + filtering: + overrideState: 1 + value: {x: 50, y: 95} + minLuminance: + overrideState: 1 + value: 0 + maxLuminance: + overrideState: 1 + value: 0 + keyValue: + overrideState: 1 + value: 1 + eyeAdaptation: + overrideState: 1 + value: 0 + speedUp: + overrideState: 1 + value: 2 + speedDown: + overrideState: 1 + value: 1 +--- !u!114 &114458790615753430 +MonoBehaviour: + m_ObjectHideFlags: 3 + 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: adb84e30e02715445aeb9959894e3b4d, type: 3} + m_Name: ColorGrading + m_EditorClassIdentifier: + active: 1 + enabled: + overrideState: 1 + value: 1 + gradingMode: + overrideState: 1 + value: 1 + externalLut: + overrideState: 1 + value: {fileID: 0} + defaultState: 1 + tonemapper: + overrideState: 1 + value: 2 + toneCurveToeStrength: + overrideState: 1 + value: 0 + toneCurveToeLength: + overrideState: 1 + value: 0.5 + toneCurveShoulderStrength: + overrideState: 1 + value: 0 + toneCurveShoulderLength: + overrideState: 1 + value: 0.5 + toneCurveShoulderAngle: + overrideState: 1 + value: 0 + toneCurveGamma: + overrideState: 1 + value: 1 + ldrLut: + overrideState: 1 + value: {fileID: 0} + defaultState: 4 + ldrLutContribution: + overrideState: 1 + value: 1 + temperature: + overrideState: 1 + value: 0 + tint: + overrideState: 1 + value: 0 + colorFilter: + overrideState: 1 + value: {r: 1, g: 1, b: 1, a: 1} + hueShift: + overrideState: 1 + value: 0 + saturation: + overrideState: 1 + value: 0 + brightness: + overrideState: 1 + value: 0 + postExposure: + overrideState: 1 + value: 0 + contrast: + overrideState: 1 + value: 0 + mixerRedOutRedIn: + overrideState: 1 + value: 100 + mixerRedOutGreenIn: + overrideState: 1 + value: 0 + mixerRedOutBlueIn: + overrideState: 1 + value: 0 + mixerGreenOutRedIn: + overrideState: 1 + value: 0 + mixerGreenOutGreenIn: + overrideState: 1 + value: 100 + mixerGreenOutBlueIn: + overrideState: 1 + value: 0 + mixerBlueOutRedIn: + overrideState: 1 + value: 0 + mixerBlueOutGreenIn: + overrideState: 1 + value: 0 + mixerBlueOutBlueIn: + overrideState: 1 + value: 100 + lift: + overrideState: 1 + value: {x: 1, y: 1, z: 1, w: 0} + gamma: + overrideState: 1 + value: {x: 1, y: 1, z: 1, w: 0} + gain: + overrideState: 1 + value: {x: 1, y: 1, z: 1, w: 0} + masterCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + redCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + greenCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + blueCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + cachedData: + - 0 + - 0.0078125 + - 0.015625 + - 0.0234375 + - 0.03125 + - 0.0390625 + - 0.046875 + - 0.0546875 + - 0.0625 + - 0.0703125 + - 0.078125 + - 0.0859375 + - 0.09375 + - 0.1015625 + - 0.109375 + - 0.1171875 + - 0.125 + - 0.1328125 + - 0.140625 + - 0.1484375 + - 0.15625 + - 0.1640625 + - 0.171875 + - 0.1796875 + - 0.1875 + - 0.1953125 + - 0.203125 + - 0.2109375 + - 0.21875 + - 0.2265625 + - 0.234375 + - 0.2421875 + - 0.25 + - 0.2578125 + - 0.265625 + - 0.2734375 + - 0.28125 + - 0.2890625 + - 0.296875 + - 0.3046875 + - 0.3125 + - 0.3203125 + - 0.328125 + - 0.3359375 + - 0.34375 + - 0.3515625 + - 0.359375 + - 0.3671875 + - 0.375 + - 0.3828125 + - 0.390625 + - 0.3984375 + - 0.40625 + - 0.4140625 + - 0.421875 + - 0.4296875 + - 0.4375 + - 0.4453125 + - 0.453125 + - 0.4609375 + - 0.46875 + - 0.4765625 + - 0.484375 + - 0.4921875 + - 0.5 + - 0.5078125 + - 0.515625 + - 0.5234375 + - 0.53125 + - 0.5390625 + - 0.546875 + - 0.5546875 + - 0.5625 + - 0.5703125 + - 0.578125 + - 0.5859375 + - 0.59375 + - 0.6015625 + - 0.609375 + - 0.6171875 + - 0.625 + - 0.6328125 + - 0.640625 + - 0.6484375 + - 0.65625 + - 0.6640625 + - 0.671875 + - 0.6796875 + - 0.6875 + - 0.6953125 + - 0.703125 + - 0.7109375 + - 0.71875 + - 0.7265625 + - 0.734375 + - 0.7421875 + - 0.75 + - 0.7578125 + - 0.765625 + - 0.7734375 + - 0.78125 + - 0.7890625 + - 0.796875 + - 0.8046875 + - 0.8125 + - 0.8203125 + - 0.828125 + - 0.8359375 + - 0.84375 + - 0.8515625 + - 0.859375 + - 0.8671875 + - 0.875 + - 0.8828125 + - 0.890625 + - 0.8984375 + - 0.90625 + - 0.9140625 + - 0.921875 + - 0.9296875 + - 0.9375 + - 0.9453125 + - 0.953125 + - 0.9609375 + - 0.96875 + - 0.9765625 + - 0.984375 + - 0.9921875 + hueVsHueCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + hueVsSatCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + satVsSatCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + lumVsSatCurve: + overrideState: 1 + value: + curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + cachedData: + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 + - 0.5 diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing/SilentProfile.asset.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing/SilentProfile.asset.meta new file mode 100644 index 00000000..4125e9d4 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/PostProcessing/SilentProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eaac6f7291834264f97854154e89bf76 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures.meta new file mode 100644 index 00000000..13500e0a --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6e7922a4d527d54a9a279a71c067c5d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconDiscord.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconDiscord.png Binary files differnew file mode 100644 index 00000000..1d01080a --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconDiscord.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconDiscord.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconDiscord.png.meta new file mode 100644 index 00000000..7bb4dae4 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconDiscord.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 86dcb7ad296bf7a4c92042ff5ff2899d +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + 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 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconGithub.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconGithub.png Binary files differnew file mode 100644 index 00000000..05acd0ed --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconGithub.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconGithub.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconGithub.png.meta new file mode 100644 index 00000000..3b0af608 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconGithub.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: ee7466bdf89c818418a3324760b635bd +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + 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 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconKofi.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconKofi.png Binary files differnew file mode 100644 index 00000000..738ff2e5 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconKofi.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconKofi.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconKofi.png.meta new file mode 100644 index 00000000..6a9c4653 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconKofi.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: fd5c545bd69dd2c43aa5b4bb62d798c1 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + 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 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconPatreon.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconPatreon.png Binary files differnew file mode 100644 index 00000000..9751fcb3 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconPatreon.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconPatreon.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconPatreon.png.meta new file mode 100644 index 00000000..d108b827 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconPatreon.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 53bf21fdf6f6ed14c8147f35a68527a9 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + 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 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconTwitter.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconTwitter.png Binary files differnew file mode 100644 index 00000000..b97cab5e --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconTwitter.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconTwitter.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconTwitter.png.meta new file mode 100644 index 00000000..79277dda --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/IconTwitter.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 22ccd964427c9504d86b684f95542950 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + 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 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/VRWTSplashLogo.png b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/VRWTSplashLogo.png Binary files differnew file mode 100644 index 00000000..7dc75092 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/VRWTSplashLogo.png diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/VRWTSplashLogo.png.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/VRWTSplashLogo.png.meta new file mode 100644 index 00000000..422a46df --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Resources/SplashTextures/VRWTSplashLogo.png.meta @@ -0,0 +1,110 @@ +fileFormatVersion: 2 +guid: 8ac7bb233e24a7d44b1e5c093c7a9973 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + 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 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 2 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + 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: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts.meta new file mode 100644 index 00000000..cf98b3f0 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 94a6e7a1d404daa44b95f464e9d45764 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor.meta new file mode 100644 index 00000000..00b169d8 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c780449c33592e44bb63c21e2890f25b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildChecksManager.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildChecksManager.cs new file mode 100644 index 00000000..56eccbe4 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildChecksManager.cs @@ -0,0 +1,82 @@ +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +using UnityEngine; +using VRC.SDKBase.Editor.BuildPipeline; +#if VRC_SDK_VRCSDK3 +using VRC.SDKBase; +#endif +#if VRC_SDK_VRCSDK2 +using VRCSDK2; +#endif +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +using VRC.Core; +#endif +using UnityEditor; +using System.Linq; + +namespace VRWorldToolkit +{ + public class BuildChecksManager : IVRCSDKBuildRequestedCallback + { + public int callbackOrder => 0; + + public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType) + { + if (requestedBuildType == VRCSDKRequestedBuildType.Scene) + { + if (Object.FindObjectsOfType(typeof(VRC_SceneDescriptor)) is VRC_SceneDescriptor[] descriptors && descriptors.Length > 0) + { + var spawnProblems = false; + var descriptor = descriptors[0]; + + if (descriptor.spawns != null) + { + var spawns = descriptor.spawns.Where(s => s != null).ToArray(); + var spawnsLength = descriptor.spawns.Length; + + if (spawnsLength != spawns.Length || spawnsLength == 0) + { + spawnProblems = true; + } + } + else + { + spawnProblems = true; + } + + if (spawnProblems) + { + var selection = EditorUtility.DisplayDialogComplex("VRWorld Toolkit: Problem spawn points!", "Null or empty spawn points set in Scene Descriptor.\r\n\r\nSpawning into a null or empty spawn point will cause you get thrown back into your home world.\r\n\r\nSelect Cancel Build if you want to fix the problem yourself or press Bypass to ignore the problem and continue.", + "Fix And Continue", "Cancel Build", "Bypass"); + + switch (selection) + { + case 0: + WorldDebugger.FixSpawns(descriptor).Invoke(); + break; + case 1: + return false; + } + } + + if (Object.FindObjectsOfType(typeof(PipelineManager)) is PipelineManager[] pipelines && pipelines.Length > 1) + { + var selection = EditorUtility.DisplayDialogComplex("VRWorld Toolkit: Multiple Pipeline managers!", "Multiple Pipeline Manager components found in scene.\r\n\r\nThis can break the upload process and cause you to not be able to load into the world.\r\n\r\nSelect Cancel Build if you want to fix the problem yourself or press Bypass to ignore the problem and continue.", + "Fix And Continue", "Cancel Build", "Bypass"); + + switch (selection) + { + case 0: + WorldDebugger.RemoveBadPipelineManagers(pipelines).Invoke(); + break; + case 1: + return false; + } + } + } + } + + return true; + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildChecksManager.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildChecksManager.cs.meta new file mode 100644 index 00000000..c71cf899 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildChecksManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5eeaa016a09318448567f5b566c899b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildReportTreeView.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildReportTreeView.cs new file mode 100644 index 00000000..37273916 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildReportTreeView.cs @@ -0,0 +1,520 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEditor.IMGUI.Controls; +using UnityEngine; +using VRWorldToolkit.DataStructures; + +namespace VRWorldToolkit +{ + public class BuildReportTreeView : TreeView + { + private BuildReport report; + private bool hasReport; + public bool BuildSucceeded { get; private set; } + + private enum TreeColumns + { + Type, + Size, + Name, + Extension, + Percentage, + } + + public BuildReportTreeView(TreeViewState state, MultiColumnHeader multiColumnHeader, BuildReport report) : base(state, multiColumnHeader) + { + showBorder = true; + showAlternatingRowBackgrounds = true; + multiColumnHeader.sortingChanged += OnSortingChanged; + + SetReport(report); + } + + private class BuildListAsset + { + public string AssetType { get; set; } + public string FullPath { get; set; } + public int Size { get; set; } + public double Percentage { get; set; } + + public BuildListAsset() + { + } + + public BuildListAsset(string assetType, string fullPath, int size) + { + AssetType = assetType; + FullPath = fullPath; + Size = size; + } + } + + private sealed class BuildReportItem : TreeViewItem + { + public Texture previewIcon { get; set; } + public string assetType { get; set; } + public string path { get; set; } + public string extension { get; set; } + public int size { get; set; } + public double percentage { get; set; } + + public BuildReportItem(int id, int depth, Texture previewIcon, string assetType, string displayName, string path, string extension, int size, double percentage) : base(id, depth, displayName) + { + this.previewIcon = previewIcon; + this.assetType = assetType; + this.displayName = displayName; + this.path = path; + this.extension = extension; + this.size = size; + this.percentage = percentage; + } + } + + protected override TreeViewItem BuildRoot() + { + var root = new TreeViewItem {id = -1, depth = -1}; + + var serializedReport = new SerializedObject(report); + + var bl = new List<BuildListAsset>(); + + var appendices = serializedReport.FindProperty("m_Appendices"); + + for (var i = 0; i < appendices.arraySize; i++) + { + var appendix = appendices.GetArrayElementAtIndex(i); + + if (appendix.objectReferenceValue.GetType() != typeof(UnityEngine.Object)) continue; + + var serializedAppendix = new SerializedObject(appendix.objectReferenceValue); + + if (serializedAppendix.FindProperty("m_ShortPath") is null) continue; + + var contents = serializedAppendix.FindProperty("m_Contents"); + + for (var j = 0; j < contents.arraySize; j++) + { + var entry = contents.GetArrayElementAtIndex(j); + + var fullPath = entry.FindPropertyRelative("buildTimeAssetPath").stringValue; + + var assetImporter = AssetImporter.GetAtPath(fullPath); + + var type = assetImporter != null ? assetImporter.GetType().Name : "Unknown"; + + if (type.EndsWith("Importer")) + { + type = type.Remove(type.Length - 8); + } + + var byteSize = entry.FindPropertyRelative("packedSize").intValue; + + var asset = new BuildListAsset(type, fullPath, byteSize); + + bl.Add(asset); + } + } + + var results = bl + .GroupBy(x => x.FullPath) + .Select(cx => new BuildListAsset() + { + AssetType = cx.First().AssetType, + FullPath = cx.First().FullPath, + Size = cx.Sum(x => x.Size), + }) + .OrderByDescending(x => x.Size) + .ToList(); + + var totalSize = results.Sum(x => (long) x.Size); + + for (var i = 0; i < results.Count; i++) + { + results[i].Percentage = (double) results[i].Size / totalSize; + } + + for (var i = 0; i < results.Count; i++) + { + var asset = results[i]; + + root.AddChild(new BuildReportItem(i, + 0, + AssetDatabase.GetCachedIcon(asset.FullPath), + asset.AssetType, + asset.FullPath == "" ? "Unknown" : Path.GetFileName(asset.FullPath), + asset.FullPath, + Path.GetExtension(asset.FullPath), + asset.Size, + asset.Percentage) + ); + } + + return root; + } + + public void SetReport(BuildReport newReport) + { + report = newReport; + hasReport = report != null; + BuildSucceeded = hasReport && report.summary.result == BuildResult.Succeeded; + + if (hasReport && BuildSucceeded) + { + Reload(); + } + } + + private bool HasMessages() + { + return report.summary.totalErrors > 0 || report.summary.totalWarnings > 0; + } + + private struct CategoryStats + { + public string Name; + public int Size; + } + + /// <summary> + /// Draw overall stats view of the current build report + /// </summary> + public void DrawOverallStats() + { + if (BuildSucceeded) + { + var stats = base.GetRows().Cast<BuildReportItem>().ToList(); + + var totalSize = stats.Sum(x => x.size); + + var grouped = stats + .GroupBy(x => x.assetType) + .Select(cx => new CategoryStats() + { + Name = cx.First().assetType, + Size = cx.Sum(x => x.size), + }).OrderByDescending(x => x.Size) + .ToArray(); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + for (var i = 0; i < grouped.Length; i++) + { + var item = grouped[i]; + + string name; + + switch (item.Name) + { + case "Mono": + name = "Scripts"; + break; + case "Model": + case "Texture": + case "Shader": + case "Asset": + case "TrueTypeFont": + case "Plugin": + case "Prefab": + name = item.Name + "s"; + break; + default: + name = item.Name; + break; + } + + if (GUILayout.Button(name + " - " + EditorUtility.FormatBytes(item.Size) + " - " + ((double) item.Size / totalSize).ToString("P"), EditorStyles.label)) + { + searchString = item.Name; + } + } + + EditorGUILayout.EndVertical(); + } + } + + private Vector2 scrollPosMessages; + + public void DrawMessages() + { + if (HasMessages()) + { + EditorGUILayout.BeginVertical(); + scrollPosMessages = EditorGUILayout.BeginScrollView(scrollPosMessages); + + var steps = report.steps; + + for (var i = 0; i < steps.Length; i++) + { + var step = steps[i]; + + if (step.messages.Length > 0) + { + GUILayout.Label(step.name, Styles.BoldWrap); + + for (var j = 0; j < step.messages.Length; j++) + { + var message = step.messages[j]; + + var messageType = MessageType.Info; + + switch (message.type) + { + case LogType.Error: + case LogType.Exception: + messageType = MessageType.Error; + break; + case LogType.Assert: + case LogType.Warning: + messageType = MessageType.Warning; + break; + } + + EditorGUILayout.HelpBox(message.content, messageType); + } + + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + } + } + + EditorGUILayout.EndScrollView(); + EditorGUILayout.EndVertical(); + } + else + { + EditorGUILayout.HelpBox("No messages to show.", MessageType.Info); + } + } + + public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState(float treeViewWidth) + { + var columns = new[] + { + new MultiColumnHeaderState.Column + { + headerContent = EditorGUIUtility.IconContent("FilterByType"), + contextMenuText = "Preview", + headerTextAlignment = TextAlignment.Center, + canSort = false, + width = 20, + minWidth = 20, + maxWidth = 20, + autoResize = false, + allowToggleVisibility = true + }, + new MultiColumnHeaderState.Column + { + headerContent = new GUIContent("Size", "Uncompressed size of asset"), + contextMenuText = "Size", + headerTextAlignment = TextAlignment.Left, + sortedAscending = true, + sortingArrowAlignment = TextAlignment.Right, + width = 60, + minWidth = 60, + maxWidth = 75, + autoResize = false, + allowToggleVisibility = true + }, + new MultiColumnHeaderState.Column + { + headerContent = new GUIContent("Name"), + headerTextAlignment = TextAlignment.Left, + sortedAscending = true, + sortingArrowAlignment = TextAlignment.Center, + width = 250, + minWidth = 60, + autoResize = true, + allowToggleVisibility = false + }, + new MultiColumnHeaderState.Column + { + headerContent = new GUIContent("Type", "File type"), + contextMenuText = "Type", + headerTextAlignment = TextAlignment.Left, + sortedAscending = true, + sortingArrowAlignment = TextAlignment.Right, + width = 60, + minWidth = 60, + maxWidth = 100, + autoResize = true, + allowToggleVisibility = true + }, + new MultiColumnHeaderState.Column + { + headerContent = new GUIContent("%", "Percentage out of all assets"), + contextMenuText = "Percentage", + headerTextAlignment = TextAlignment.Left, + sortedAscending = true, + sortingArrowAlignment = TextAlignment.Right, + width = 60, + minWidth = 60, + maxWidth = 70, + autoResize = false, + allowToggleVisibility = true + } + }; + + var state = new MultiColumnHeaderState(columns); + return state; + } + + protected override void RowGUI(RowGUIArgs args) + { + var buildReportItem = (BuildReportItem) args.item; + + for (var visibleColumnIndex = 0; visibleColumnIndex < args.GetNumVisibleColumns(); visibleColumnIndex++) + { + Rect rect; + // Get the current cell rect and index + if (visibleColumnIndex == 2) + { + var rectOne = args.GetCellRect(visibleColumnIndex); + var rectTwo = args.GetCellRect(3); + + rect = new Rect(rectOne.position, new Vector2(rectOne.width + rectTwo.width, rectOne.height)); + } + else + { + rect = args.GetCellRect(visibleColumnIndex); + } + + var columnIndex = (TreeColumns) args.GetColumn(visibleColumnIndex); + + //Set label style to white if cell is selected otherwise to normal + var labelStyle = args.selected ? Styles.TreeViewLabelSelected : Styles.TreeViewLabel; + + //Handle drawing of the columns + switch (columnIndex) + { + case TreeColumns.Type: + GUI.Label(rect, buildReportItem.previewIcon, Styles.Center); + break; + case TreeColumns.Name: + if (args.selected && buildReportItem.path != "") + { + EditorGUI.LabelField(rect, buildReportItem.path, labelStyle); + } + else + { + EditorGUI.LabelField(rect, buildReportItem.displayName, labelStyle); + } + + break; + case TreeColumns.Extension: + //EditorGUI.LabelField(rect, buildReportItem.extension, labelStyle); + break; + case TreeColumns.Size: + EditorGUI.LabelField(rect, EditorUtility.FormatBytes(buildReportItem.size), labelStyle); + break; + case TreeColumns.Percentage: + EditorGUI.LabelField(rect, buildReportItem.percentage.ToString("P"), labelStyle); + break; + default: + throw new ArgumentOutOfRangeException(nameof(columnIndex), columnIndex, null); + } + } + } + + /// <summary> + /// Handle double clicks inside the TreeView + /// </summary> + /// <param name="id"></param> + protected override void DoubleClickedItem(int id) + { + base.DoubleClickedItem(id); + + // Get the clicked item + var clickedItem = (BuildReportItem) FindItem(id, rootItem); + + //Ping clicked asset in project window + EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(clickedItem.path)); + } + + /// <summary> + /// Handle context clicks inside the TreeView + /// </summary> + /// <param name="id">ID of the clicked TreeView item</param> + protected override void ContextClickedItem(int id) + { + base.ContextClickedItem(id); + + // Get the clicked item + var clickedItem = (BuildReportItem) FindItem(id, rootItem); + + //base.SetSelection(new IList<int>()); + + // Create new + var menu = new GenericMenu(); + + // Create the menu items + menu.AddItem(new GUIContent("Copy Name"), false, ReplaceClipboard, clickedItem.displayName + clickedItem.extension); + menu.AddItem(new GUIContent("Copy Path"), false, ReplaceClipboard, clickedItem.path); + + // Show the menu + menu.ShowAsContext(); + + // Function to replace clipboard contents + void ReplaceClipboard(object input) + { + EditorGUIUtility.systemCopyBuffer = (string) input; + } + } + + /// <summary> + /// Check if current item matches the search string + /// </summary> + /// <param name="item">Item to match</param> + /// <param name="search">Search string</param> + /// <returns>Returns true if the search term matches name or asset type</returns> + protected override bool DoesItemMatchSearch(TreeViewItem item, string search) + { + // Cast match item for parameter access + var textureTreeViewItem = (BuildReportItem) item; + + // Try to match the search string to item name or asset type and return true if it does + return textureTreeViewItem.displayName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0 || + textureTreeViewItem.assetType.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0; + } + + /// <summary> + /// Handle TreeView columns sorting changes + /// </summary> + private void OnSortingChanged(MultiColumnHeader multiColumnHeader) + { + if (!(multiColumnHeader.sortedColumnIndex > -1)) return; + + // Get TreeView items + var items = rootItem.children.Cast<BuildReportItem>(); + + // Sort items by sorted column + switch (multiColumnHeader.sortedColumnIndex) + { + case 2: + items = items.OrderBy(x => x.displayName); + break; + case 3: + items = items.OrderBy(x => x.extension); + break; + case 1: + case 4: + items = items.OrderBy(x => x.size); + break; + } + + // Reverse list if not sorted ascending + if (!multiColumnHeader.IsSortedAscending(multiColumnHeader.sortedColumnIndex)) + { + items = items.Reverse(); + } + + // Cast collection back to a list + rootItem.children = items.Cast<TreeViewItem>().ToList(); + + // Build rows again with the new sorting + BuildRows(rootItem); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildReportTreeView.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildReportTreeView.cs.meta new file mode 100644 index 00000000..10d45896 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/BuildReportTreeView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d003bc03a7e1e749bf54fe3fa2a0c3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ConsoleFlagUtil.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ConsoleFlagUtil.cs new file mode 100644 index 00000000..33b641b2 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ConsoleFlagUtil.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEngine.Assertions; + +namespace VRWorldToolkit +{ + /// <summary> + /// Utility for setting and getting console error pause flag with reflection + /// </summary> + public static class ConsoleFlagUtil + { + private static readonly System.Type systemType; + private static MethodInfo mMethod_GetConsoleErrorPause; + private static MethodInfo mMethod_SetConsoleErrorPause; + + static ConsoleFlagUtil() + { + systemType = Assembly.Load("UnityEditor.dll").GetType("UnityEditor.ConsoleWindow"); + Assert.IsNotNull(systemType); + } + + public static bool GetConsoleErrorPause() + { + if (mMethod_GetConsoleErrorPause == null) + mMethod_GetConsoleErrorPause = systemType.GetMethod("GetConsoleErrorPause", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_GetConsoleErrorPause); + return (bool)mMethod_GetConsoleErrorPause.Invoke(null, null); + } + + public static void SetConsoleErrorPause(Boolean enabled) + { + if (mMethod_SetConsoleErrorPause == null) + mMethod_SetConsoleErrorPause = systemType.GetMethod("SetConsoleErrorPause", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_SetConsoleErrorPause); + mMethod_SetConsoleErrorPause.Invoke(null, new object[] { enabled }); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ConsoleFlagUtil.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ConsoleFlagUtil.cs.meta new file mode 100644 index 00000000..82995435 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ConsoleFlagUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e6d4ef7fb3068d4f80218d5e2d95f76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomAvatarPedestalEditor.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomAvatarPedestalEditor.cs new file mode 100644 index 00000000..21d0ddab --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomAvatarPedestalEditor.cs @@ -0,0 +1,131 @@ +#if VRC_SDK_VRCSDK3 +using VRC.SDKBase; +#endif +#if VRC_SDK_VRCSDK2 +using VRCSDK2; +#endif +using UnityEditor; +using UnityEngine; +using System.Linq; +using UnityEngine.SceneManagement; +using UnityEditor.SceneManagement; +using System.Text.RegularExpressions; +using System; +using VRWorldToolkit.DataStructures; +using Object = UnityEngine.Object; + +#if (VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3) && !VRWT_DISABLE_EDITORS +namespace VRWorldToolkit +{ + /// <summary> + /// Custom editor addition for drawing avatar pedestal bounds + /// </summary> + [CustomEditor(typeof(VRC_AvatarPedestal), true, isFallback = false)] + [CanEditMultipleObjects] + public class CustomAvatarPedestalEditor : Editor + { + private const float INNER_BOUND = 1.5f; + private const float OUTER_BOUND = 2f; + + private const string AVATAR_ID_REGEX = "avtr_[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}"; + + private bool setIDsFoldout; + private string avatarIDArea = ""; + + private string[] avatarIDs; + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("VRWorld Toolkit Additions", EditorStyles.boldLabel); + + var pedestals = serializedObject.targetObjects.Select(x => x as VRC_AvatarPedestal).OrderBy(x => x.transform.GetSiblingIndex()).ToArray(); + + setIDsFoldout = EditorGUILayout.Foldout(setIDsFoldout, "Mass set avatar IDs"); + if (setIDsFoldout) + { + if (Selection.activeTransform) + { + avatarIDArea = EditorGUILayout.TextArea(avatarIDArea, GUILayout.ExpandWidth(true)); + + avatarIDs = Regex.Matches(avatarIDArea, AVATAR_ID_REGEX).Cast<Match>().Select(m => m.Value).ToArray(); + + EditorGUILayout.LabelField("IDs found/Pedestals selected: ", avatarIDs.Length + "/" + serializedObject.targetObjects.Length, avatarIDs.Length > serializedObject.targetObjects.Length ? Styles.RedLabel : GUIStyle.none); + + if (GUILayout.Button("Set IDs")) + { + var count = Math.Min(serializedObject.targetObjects.Length, avatarIDs.Length); + + Undo.RegisterCompleteObjectUndo(pedestals.ToArray<Object>(), "Avatar ID Change"); + + for (var i = 0; i < count; i++) + { + pedestals[i].blueprintId = avatarIDs[i]; + PrefabUtility.RecordPrefabInstancePropertyModifications(pedestals[i]); + } + + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + } + + EditorGUILayout.Space(); + } + } + + GUILayout.Label("Selected IDs (Ordered by hierarchy):"); + + for (var i = 0; i < pedestals.Length; i++) + { + EditorGUI.BeginChangeCheck(); + + pedestals[i].blueprintId = EditorGUILayout.DelayedTextField(pedestals[i].name + " ID: ", pedestals[i].blueprintId); + + if (EditorGUI.EndChangeCheck()) + { + PrefabUtility.RecordPrefabInstancePropertyModifications(pedestals[i]); + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + } + } + + if (GUILayout.Button("Copy selected IDs")) + { + EditorGUIUtility.systemCopyBuffer = string.Join("\n", pedestals.Select(x => x.blueprintId)); + } + } + + /// <summary> + /// Draw bounds for selected avatar pedestals + /// </summary> + [DrawGizmo(GizmoType.Selected | GizmoType.Active)] + static void DrawAvatarPedestalGizmos(VRC_AvatarPedestal pedestal, GizmoType gizmoType) + { + if (Vector3.Distance(pedestal.transform.position, Camera.current.transform.position) > 25f) return; + + // Get transform from the pedestal placement value otherwise get transform of the pedestal itself + var pedestalTransform = pedestal.Placement != null ? pedestal.Placement : pedestal.transform; + + // Set gizmo matrix to match the pedestal for proper placement and rotation + Gizmos.matrix = pedestalTransform.localToWorldMatrix; + Gizmos.color = Color.green; + + // Draw the outer bound of the pedestal + Gizmos.DrawWireCube(Vector3.up * 1.2f, new Vector3(1f * OUTER_BOUND, 1f * OUTER_BOUND)); + + // Change color to red if showing the front is active and active camera is behind the pedestal + var cameraDirection = pedestalTransform.position - Camera.current.transform.position; + + var angle = Vector3.Angle(pedestalTransform.forward, cameraDirection); + + if (Mathf.Abs(angle) < 90) + { + Gizmos.color = Color.red; + } + + // Draw the inner bound of the pedestal + Gizmos.DrawWireCube(Vector3.up * 1.2f, new Vector3(1f * INNER_BOUND, 1f * INNER_BOUND)); + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomAvatarPedestalEditor.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomAvatarPedestalEditor.cs.meta new file mode 100644 index 00000000..12eab7ce --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomAvatarPedestalEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ed015a875555c741b7f5786054afcb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomEditorManager.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomEditorManager.cs new file mode 100644 index 00000000..c97a5d56 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomEditorManager.cs @@ -0,0 +1,42 @@ +using UnityEditor; +using UnityEngine; + +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +namespace VRWorldToolkit +{ + public class CustomEditorManager : MonoBehaviour + { + [MenuItem("VRWorld Toolkit/Custom Editors/Enable", false, 3)] + private static void EnableCustomEditors() + { + ScriptingDefineManager.RemoveScriptingDefine("VRWT_DISABLE_EDITORS"); + } + + [MenuItem("VRWorld Toolkit/Custom Editors/Enable", true)] + private static bool EnableCustomEditorsValidate() + { +#if VRWT_DISABLE_EDITORS + return true; +#else + return false; +#endif + } + + [MenuItem("VRWorld Toolkit/Custom Editors/Disable", false, 4)] + private static void DisableCustomEditors() + { + ScriptingDefineManager.AddScriptingDefine("VRWT_DISABLE_EDITORS"); + } + + [MenuItem("VRWorld Toolkit/Custom Editors/Disable", true)] + private static bool DisableCustomEditorsValidate() + { +#if !VRWT_DISABLE_EDITORS + return true; +#else + return false; +#endif + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomEditorManager.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomEditorManager.cs.meta new file mode 100644 index 00000000..4415c6bb --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomEditorManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c8262991e29f8c40a1dac88fb66ff2d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomMirrorEditor.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomMirrorEditor.cs new file mode 100644 index 00000000..f934612c --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomMirrorEditor.cs @@ -0,0 +1,91 @@ +#if VRC_SDK_VRCSDK3 +using VRC.SDKBase; +#endif +#if VRC_SDK_VRCSDK2 +using VRCSDK2; +#endif +using UnityEditor; +using UnityEngine; +using VRWorldToolkit.DataStructures; + +#if (VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3) && !VRWT_DISABLE_EDITORS +namespace VRWorldToolkit +{ + /// <summary> + /// Custom editor for VRC_MirrorReflection with added quick actions + /// </summary> + [CustomEditor(typeof(VRC_MirrorReflection), true, isFallback = false)] + [CanEditMultipleObjects] + public class CustomMirrorEditor : Editor + { + private bool showExplanations; + private SerializedProperty mirrorMask; + + private void OnEnable() + { + mirrorMask = serializedObject.FindProperty("m_ReflectLayers"); + } + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + serializedObject.Update(); + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("VRWorld Toolkit Additions", EditorStyles.boldLabel); + + EditorGUILayout.LabelField("Quick set Reflect Layers:"); + + EditorGUILayout.BeginHorizontal(); + + if (GUILayout.Button("Show only players")) MirrorLayerChange(262656); + + if (GUILayout.Button("Show players/world")) MirrorLayerChange(262657); + + EditorGUILayout.EndHorizontal(); + + if (Selection.gameObjects.Length == 1) + { + var currentMirror = (VRC_MirrorReflection) target; + + if ((LightmapSettings.lightProbes != null && LightmapSettings.lightProbes.positions.Length == 0 && currentMirror.m_DisablePixelLights) || (LightmapSettings.lightProbes is null && currentMirror.m_DisablePixelLights)) + EditorGUILayout.HelpBox("No baked light probes were found in lighting data. Dynamic objects such as players and pickups will not appear lit in mirrors without baked light probes.", MessageType.Warning); + + if (mirrorMask.intValue == -1025) + EditorGUILayout.HelpBox("This mirror has default layers set. Unnecessary layers should be disabled to save on performance.", MessageType.Info); + + if (Helper.LayerIncludedInMask(LayerMask.NameToLayer("UiMenu"), mirrorMask.intValue)) + EditorGUILayout.HelpBox("Having UiMenu enabled on mirrors causes VRChat UI elements to be rendered twice, causing a noticeable performance drop in populated instances.", MessageType.Warning); + + if (!Helper.LayerIncludedInMask(LayerMask.NameToLayer("MirrorReflection"), mirrorMask.intValue)) + EditorGUILayout.HelpBox("Having the MirrorReflection layer disabled will stop the player from seeing themselves in the mirror.", MessageType.Warning); + + if (Helper.LayerIncludedInMask(LayerMask.NameToLayer("PlayerLocal"), mirrorMask.intValue)) + EditorGUILayout.HelpBox("PlayerLocal is only meant to be seen in first-person view and should not be enabled on mirrors.", MessageType.Error); + } + + showExplanations = EditorGUILayout.Foldout(showExplanations, "VRChat specific layer explanations"); + + if (showExplanations) + { + GUILayout.Label("<b>Player:</b>\nThis layer is used for other players than yourself", Styles.RichTextWrap); + GUILayout.Label("<b>PlayerLocal:</b>\nThis layer is only used for first-person view and should not be enabled in mirrors", Styles.RichTextWrap); + GUILayout.Label("<b>MirrorReflection:</b>\nThis layer is used for your own mirror version", Styles.RichTextWrap); + } + + serializedObject.ApplyModifiedProperties(); + } + + /// <summary> + /// Change selected Reflect Layers on selected VRC_MirrorReflections to the supplied LayerMask value + /// </summary> + /// <param name="layerMask">New LayerMask value to set for Reflect Layers</param> + private void MirrorLayerChange(int layerMask) + { + mirrorMask.intValue = layerMask; + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomMirrorEditor.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomMirrorEditor.cs.meta new file mode 100644 index 00000000..53405816 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/CustomMirrorEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b642844c904188f4482604f464a71aa3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/DisableOnBuildManager.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/DisableOnBuildManager.cs new file mode 100644 index 00000000..0d89c073 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/DisableOnBuildManager.cs @@ -0,0 +1,132 @@ +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +using VRC.SDKBase.Editor.BuildPipeline; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace VRWorldToolkit +{ + public class DisableOnBuildCallback : IVRCSDKBuildRequestedCallback + { + public int callbackOrder => 1; + + public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType) + { + DisableOnBuildManager.ToggleObjectsUsingTag("DisableOnBuild", false, false); + DisableOnBuildManager.ToggleObjectsUsingTag("EnableOnBuild", true, false); + + return true; + } + } + + public class DisableOnBuildManager : Editor + { + // Disable On Build + [MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Setup", false, 2)] + private static void DisableOnBuildSetup() + { + if (EditorUtility.DisplayDialog("Setup Disable On Build", "This setup will add a new tag DisableOnBuild. Assigning this tag to a GameObject will disable it before a build happens.", "Setup", "Cancel")) + { + TagHelper.AddTag("DisableOnBuild"); + } + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Setup", true)] + private static bool DisableOnBuildSetupValidate() + { + return !TagHelper.TagExists("DisableOnBuild"); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Disable Objects", false, 13)] + private static void DisableDisableObjectsLoop() + { + ToggleObjectsUsingTag("DisableOnBuild", false, true); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Disable Objects", true)] + private static bool DisableDisableObjectsValidate() + { + return TagHelper.TagExists("DisableOnBuild"); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Enable Objects", false, 14)] + private static void EnableDisableObjectsLoop() + { + ToggleObjectsUsingTag("DisableOnBuild", true, true); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Enable Objects", true)] + private static bool EnableObjectsLoopValidate() + { + return TagHelper.TagExists("DisableOnBuild"); + } + + // Enable On Build + [MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Setup", false, 13)] + private static void EnableOnBuildSetup() + { + if (EditorUtility.DisplayDialog("Setup Enable On Build", "This setup will add a new tag EnableOnBuild. Assigning this tag to a GameObject will enable it before a build happens.", "Setup", "Cancel")) + { + TagHelper.AddTag("EnableOnBuild"); + } + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Setup", true)] + private static bool EnableOnBuildSetupValidate() + { + return !TagHelper.TagExists("EnableOnBuild"); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Disable Objects", false, 24)] + private static void DisableEnableObjectsLoop() + { + ToggleObjectsUsingTag("EnableOnBuild", false, true); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Disable Objects", true)] + private static bool DisableEnableObjectsValidate() + { + return TagHelper.TagExists("EnableOnBuild"); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Enable Objects", false, 25)] + private static void EnableEnableObjectsLoop() + { + ToggleObjectsUsingTag("EnableOnBuild", true, true); + } + + [MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Enable Objects", true)] + private static bool EnableEnableObjectsLoopValidate() + { + return TagHelper.TagExists("EnableOnBuild"); + } + + public static void ToggleObjectsUsingTag(string tag, bool active, bool markSceneDirty) + { + if (!TagHelper.TagExists(tag)) return; + + var toggledGameObjectCount = 0; + var allGameObjects = Resources.FindObjectsOfTypeAll(typeof(GameObject)); + var allGameObjectsLength = allGameObjects.Length; + for (var i = 0; i < allGameObjectsLength; i++) + { + var gameObject = allGameObjects[i] as GameObject; + + if (gameObject.hideFlags != HideFlags.None || EditorUtility.IsPersistent(gameObject.transform.root.gameObject)) continue; + + if (gameObject.CompareTag(tag)) + { + gameObject.SetActive(active); + toggledGameObjectCount++; + } + } + + var state = active ? "active" : "inactive"; + var plural = toggledGameObjectCount > 1 ? "s" : ""; + Debug.Log($"Set {toggledGameObjectCount} GameObject{plural} in Scene with tag {tag} to be {state}"); + if (markSceneDirty) EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/DisableOnBuildManager.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/DisableOnBuildManager.cs.meta new file mode 100644 index 00000000..37ecc044 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/DisableOnBuildManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bdd52a958ec65764aa73bc92ea5cc4e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/EditorTextureUtil.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/EditorTextureUtil.cs new file mode 100644 index 00000000..737d99d4 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/EditorTextureUtil.cs @@ -0,0 +1,77 @@ +using System.Reflection; +using UnityEngine; +using UnityEngine.Assertions; + +/// <summary> +/// <see cref="UnityEditor.TextureUtil"/> Accessor +/// </summary> +/// <author>Seibe TAKAHASHI</author> +/// <remarks> +/// (c) 2017 Seibe TAKAHASHI. +/// This code is released under the MIT License. +/// http://opensource.org/licenses/mit-license.php +/// </remarks> + +namespace VRWorldToolkit +{ + public static class EditorTextureUtil + { + private static readonly System.Type cType; + private static MethodInfo mMethod_GetMipmapCount; + private static MethodInfo mMethod_GetTextureFormat; + private static MethodInfo mMethod_GetRuntimeMemorySizeLong; + private static MethodInfo mMethod_GetStorageMemorySizeLong; + private static MethodInfo mMethod_IsNonPowerOfTwo; + + static EditorTextureUtil() + { + cType = Assembly.Load("UnityEditor.dll").GetType("UnityEditor.TextureUtil"); + Assert.IsNotNull(cType); + } + + public static int GetMipmapCount(Texture texture) + { + if (mMethod_GetMipmapCount == null) + mMethod_GetMipmapCount = cType.GetMethod("GetMipmapCount", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_GetMipmapCount); + return (int) mMethod_GetMipmapCount.Invoke(null, new[] {texture}); + } + + public static TextureFormat GetTextureFormat(Texture texture) + { + if (mMethod_GetTextureFormat == null) + mMethod_GetTextureFormat = cType.GetMethod("GetTextureFormat", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_GetTextureFormat); + return (TextureFormat) mMethod_GetTextureFormat.Invoke(null, new[] {texture}); + } + + public static long GetRuntimeMemorySize(Texture texture) + { + if (mMethod_GetRuntimeMemorySizeLong == null) + mMethod_GetRuntimeMemorySizeLong = cType.GetMethod("GetRuntimeMemorySizeLong", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_GetRuntimeMemorySizeLong); + return (long) mMethod_GetRuntimeMemorySizeLong.Invoke(null, new[] {texture}); + } + + public static long GetStorageMemorySize(Texture texture) + { + if (mMethod_GetStorageMemorySizeLong == null) + mMethod_GetStorageMemorySizeLong = cType.GetMethod("GetStorageMemorySizeLong", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_GetStorageMemorySizeLong); + return (long) mMethod_GetStorageMemorySizeLong.Invoke(null, new[] {texture}); + } + + public static bool IsNonPowerOfTwo(Texture2D texture) + { + if (mMethod_IsNonPowerOfTwo == null) + mMethod_IsNonPowerOfTwo = cType.GetMethod("IsNonPowerOfTwo", BindingFlags.Static | BindingFlags.Public); + + Assert.IsNotNull(mMethod_IsNonPowerOfTwo); + return (bool) mMethod_IsNonPowerOfTwo.Invoke(null, new[] {texture}); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/EditorTextureUtil.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/EditorTextureUtil.cs.meta new file mode 100644 index 00000000..bcb38075 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/EditorTextureUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4286f3f47ce16b047add57c7b8b5281d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/Helper.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/Helper.cs new file mode 100644 index 00000000..4ff4b8d4 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/Helper.cs @@ -0,0 +1,213 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.PackageManager; +using UnityEditor.PackageManager.Requests; +using UnityEngine; + +namespace VRWorldToolkit +{ + public static class Helper + { + public static string ReturnPlural(int counter) + { + return counter > 1 ? "s" : ""; + } + + public static bool CheckNameSpace(string namespaceName) + { + return (from assembly in AppDomain.CurrentDomain.GetAssemblies() + from type in assembly.GetTypes() + where type.Namespace == namespaceName + select type).Any(); + } + + public static float GetBrightness(Color color) + { + var num = ((float) color.r); + var num2 = ((float) color.g); + var num3 = ((float) color.b); + var num4 = num; + var num5 = num; + if (num2 > num4) + num4 = num2; + if (num3 > num4) + num4 = num3; + if (num2 < num5) + num5 = num2; + if (num3 < num5) + num5 = num3; + return (num4 + num5) / 2; + } + + public static string Truncate(string text, int length) + { + if (text.Length > length) + { + text = text.Substring(0, length); + text += "..."; + } + + return text; + } + + public static int[] GetAllLayerNumbersFromMask(LayerMask layerMask) + { + List<int> layers = new List<int>(); + for (int i = 0; i < 32; i++) + { + if (layerMask == (layerMask | (1 << i))) + { + layers.Add(i); + } + } + + return layers.ToArray(); + } + + public static GameObject CreateMainCamera() + { + var camera = new GameObject("Main Camera"); + camera.AddComponent<Camera>(); + camera.AddComponent<AudioListener>(); + camera.tag = "MainCamera"; + + return camera; + } + + private static AddRequest packageManagerRequest; + + public static void ImportPackage(string package) + { + packageManagerRequest = Client.Add(package); + EditorApplication.update += PackageImportProgress; + } + + private static void PackageImportProgress() + { + if (packageManagerRequest.IsCompleted) + { + if (packageManagerRequest.Status == StatusCode.Success) + Debug.Log("Installed: " + packageManagerRequest.Result.packageId); + else if (packageManagerRequest.Status >= StatusCode.Failure) + Debug.Log(packageManagerRequest.Error.message); + + EditorApplication.update -= PackageImportProgress; + } + } + + public static string GetAllLayersFromMask(LayerMask layerMask) + { + List<string> layers = new List<string>(); + for (var i = 0; i < 32; i++) + { + if (layerMask == (layerMask | (1 << i))) + { + layers.Add(LayerMask.LayerToName(i)); + } + } + + return String.Join(", ", layers.ToArray()); + } + + public static bool LayerIncludedInMask(int layer, LayerMask layermask) + { + return layermask == (layermask | (1 << layer)); + } + + public static string FormatTime(TimeSpan t) + { + var formattedTime = ""; + if (t.TotalDays > 1) + { + formattedTime = string.Concat(formattedTime, t.Days + " days "); + } + + if (t.TotalHours > 1) + { + formattedTime = string.Concat(formattedTime, t.Hours + " days "); + } + + if (t.TotalMinutes > 1) + { + formattedTime = string.Concat(formattedTime, t.Minutes + " minutes "); + } + else + { + formattedTime = string.Concat(formattedTime, t.Seconds + " seconds"); + } + + return formattedTime; + } + + public static RuntimePlatform BuildPlatform() + { +#if UNITY_ANDROID + return RuntimePlatform.Android; +#else + return RuntimePlatform.WindowsPlayer; +#endif + } + + public static Type GetTypeFromName(string typeName) + { + var type = Type.GetType(typeName); + if (type != null) return type; + foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) + { + type = a.GetType(typeName); + if (type != null) + { + return type; + } + } + + return null; + } + + public static string GetSteamVrcExecutablePath() + { + var steamKey = Registry.LocalMachine.OpenSubKey("Software\\Valve\\Steam") ?? Registry.LocalMachine.OpenSubKey("Software\\Wow6432Node\\Valve\\Steam"); + + if (steamKey != null) + { + const string commonPath = "\\SteamApps\\common"; + const string executablePath = "\\VRChat.exe"; + + var steamPath = (string) steamKey.GetValue("InstallPath"); + + var configFile = Path.Combine(steamPath, "config", "config.vdf"); + + var folders = new List<string> {steamPath + commonPath}; + + var configText = File.ReadAllText(configFile); + + folders.AddRange(Regex.Matches(configText, "(?<=BaseInstallFolder.*\".+?\").+?(?=\")").Cast<Match>().Select(x => x.Value + commonPath)); + + foreach (var folder in folders) + { + try + { + var matches = Directory.GetDirectories(folder, "VRChat"); + if (matches.Length >= 1) + { + var finalPath = matches[0] + executablePath; + + if (File.Exists(finalPath)) return finalPath; + } + } + catch (DirectoryNotFoundException) + { + //continue + } + } + } + + return null; + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/Helper.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/Helper.cs.meta new file mode 100644 index 00000000..c415fa69 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/Helper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5369e6349cede284ca654fec3cb49b1b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/MassTextureImporter.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/MassTextureImporter.cs new file mode 100644 index 00000000..32c233ab --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/MassTextureImporter.cs @@ -0,0 +1,473 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; +using VRWorldToolkit.DataStructures; + +namespace VRWorldToolkit +{ + public class TextureDetails + { + private int? uncrunchedCount; + private int? normalMaps; + private int? cubemaps; + private long? storageSize; + + private readonly Dictionary<Texture, TextureImporter> textureList = new Dictionary<Texture, TextureImporter>(); + + public void AddTexture(TextureImporter textureImporter, Texture texture) + { + if (!textureList.ContainsKey(texture) && textureImporter != null) + { + textureList.Add(texture, textureImporter); + } + } + + public int TextureCount => textureList.Count; + + public int UncrunchedCount + { + get + { + if (uncrunchedCount is null) + { + uncrunchedCount = textureList.Count(x => !x.Value.crunchedCompression); + } + + return (int) uncrunchedCount; + } + } + + public int NormalMaps + { + get + { + if (normalMaps is null) + { + normalMaps = textureList.Count(x => x.Value.textureType == TextureImporterType.NormalMap); + } + + return (int) normalMaps; + } + } + + public int Cubemaps + { + get + { + if (cubemaps is null) + { + cubemaps = textureList.Count(x => x.Value.textureShape == TextureImporterShape.TextureCube); + } + + return (int) cubemaps; + } + } + + public long StorageSize + { + get + { + if (storageSize is null) + { + storageSize = textureList.Sum(x => EditorTextureUtil.GetStorageMemorySize(x.Key)); + } + + return (long) storageSize; + } + } + + public IEnumerable<TextureImporter> GetImporters + { + get { return textureList.Select(x => x.Value).ToArray(); } + } + + public void ResetStats() + { + uncrunchedCount = null; + storageSize = null; + } + } + + public class ImporterSettingsManager + { + // Mip Maps + public bool DontChangeMipMaps { get; private set; } + public bool StreamingMipMap { get; private set; } = true; + public bool GenerateMipMaps { get; private set; } = true; + public bool DontChangeAniso { get; private set; } = true; + public int AnisoLevel { get; private set; } = 1; + public OverrideWhenSize OverrideAnisoWhen { get; private set; } + + // Max Texture Size + public int MaxTextureSize { get; private set; } = 2048; + public OverrideWhenSize OverrideMaxTextureSizeWhen { get; private set; } = OverrideWhenSize.BiggerThan; + + // Crunch compression + public bool CrunchCompression { get; private set; } = true; + public int CompressionQuality { get; private set; } = 80; + public DontOverrideWhen DontOverrideCrunchWhen { get; private set; } = DontOverrideWhen.AlreadyEnabled; + public OverrideWhenSize OverrideCrunchCompressionSizeWhen { get; private set; } = OverrideWhenSize.BiggerThan; + + // Ignores + public bool IgnoreCubemaps { get; private set; } = true; + public OverrideWhenSize OverrideCubemapSettingsWhen { get; private set; } = OverrideWhenSize.SmallerThan; + public int CubemapSize { get; private set; } = 512; + public bool IgnoreNormalMaps { get; private set; } = true; + + private readonly string[] maxTextureNames = {"32", "64", "128", "256", "512", "1024", "2048", "4096", "8192"}; + private readonly int[] maxTextureSizes = {32, 64, 128, 256, 512, 1024, 2048, 4096, 8192}; + + public enum OverrideWhenSize + { + Always, + SmallerThan, + BiggerThan + } + + public enum DontOverrideWhen + { + Never, + AlreadyDisabled, + AlreadyEnabled + } + + public void DrawSettings() + { + GUILayout.Label("Mip Maps", Styles.BoldWrap); + DontChangeMipMaps = EditorGUILayout.Toggle("Don't Change", DontChangeMipMaps); + using (new EditorGUI.DisabledScope(DontChangeMipMaps)) + { + StreamingMipMap = EditorGUILayout.Toggle("Streaming Mip Maps", StreamingMipMap); + GenerateMipMaps = EditorGUILayout.Toggle("Generate Mip Maps", GenerateMipMaps); + } + + GUILayout.Label("Aniso Level", Styles.BoldWrap); + DontChangeAniso = EditorGUILayout.Toggle("Don't Change", DontChangeAniso); + using (new EditorGUI.DisabledScope(DontChangeAniso)) + { + AnisoLevel = EditorGUILayout.IntSlider("Aniso Level", AnisoLevel, 0, 16); + using (new EditorGUI.IndentLevelScope()) + { + OverrideAnisoWhen = (OverrideWhenSize) EditorGUILayout.EnumPopup("Override When", OverrideAnisoWhen); + } + } + + GUILayout.Label("Size", Styles.BoldWrap); + MaxTextureSize = EditorGUILayout.IntPopup("Max Size", MaxTextureSize, maxTextureNames, maxTextureSizes); + using (new EditorGUI.IndentLevelScope()) + { + OverrideMaxTextureSizeWhen = (OverrideWhenSize) EditorGUILayout.EnumPopup("Override When", OverrideMaxTextureSizeWhen); + } + + GUILayout.Label("Crunch Compression", Styles.BoldWrap); + CrunchCompression = EditorGUILayout.Toggle("Use Crunch Compression", CrunchCompression); + using (new EditorGUI.DisabledScope(!CrunchCompression)) + { + CompressionQuality = EditorGUILayout.IntSlider(CompressionQuality, 1, 100); + using (new EditorGUI.IndentLevelScope()) + { + OverrideCrunchCompressionSizeWhen = (OverrideWhenSize) EditorGUILayout.EnumPopup("Override When", OverrideCrunchCompressionSizeWhen); + } + } + + using (new EditorGUI.IndentLevelScope()) + { + DontOverrideCrunchWhen = (DontOverrideWhen) EditorGUILayout.EnumPopup("Don't Override When", DontOverrideCrunchWhen); + } + + GUILayout.Label("Ignore", Styles.BoldWrap); + IgnoreCubemaps = EditorGUILayout.Toggle("Cubemaps", IgnoreCubemaps); + using (new EditorGUI.IndentLevelScope()) + { + using (new EditorGUI.DisabledScope(!IgnoreCubemaps)) + { + OverrideCubemapSettingsWhen = (OverrideWhenSize) EditorGUILayout.EnumPopup("Ignore When", OverrideCubemapSettingsWhen); + using (new EditorGUI.DisabledScope(OverrideCubemapSettingsWhen == OverrideWhenSize.Always)) + { + CubemapSize = EditorGUILayout.IntPopup("Ignore Size", CubemapSize, maxTextureNames, maxTextureSizes); + } + } + } + + IgnoreNormalMaps = EditorGUILayout.Toggle("Normal maps", IgnoreNormalMaps); + } + + public void ProcessTextures(TextureDetails details) + { + try + { + AssetDatabase.StartAssetEditing(); + + var importers = details.GetImporters; + var count = details.TextureCount; + var current = 1; + foreach (var importer in importers) + { + EditorUtility.DisplayProgressBar("Applying New Settings", importer.assetPath, (float) current / count); + + if (IgnoreNormalMaps && importer.textureType == TextureImporterType.NormalMap) + continue; + + if (IgnoreCubemaps && importer.textureShape == TextureImporterShape.TextureCube) + { + var oldMaxTextureSize = importer.maxTextureSize; + var newMaxTextureSize = MaxTextureSize; + + switch (OverrideCubemapSettingsWhen) + { + case OverrideWhenSize.SmallerThan: + if (oldMaxTextureSize > newMaxTextureSize) continue; + break; + case OverrideWhenSize.BiggerThan: + if (oldMaxTextureSize < newMaxTextureSize) continue; + break; + } + } + + if (!DontChangeMipMaps) + { + importer.mipmapEnabled = GenerateMipMaps; + importer.streamingMipmaps = StreamingMipMap; + } + + if (!DontChangeAniso) + { + var oldAnisoLevel = importer.anisoLevel; + var newAnisoLevel = AnisoLevel; + + switch (OverrideAnisoWhen) + { + case OverrideWhenSize.Always: + importer.anisoLevel = AnisoLevel; + break; + case OverrideWhenSize.SmallerThan: + if (oldAnisoLevel < newAnisoLevel) + { + importer.anisoLevel = newAnisoLevel; + } + + break; + case OverrideWhenSize.BiggerThan: + if (oldAnisoLevel > newAnisoLevel) + { + importer.maxTextureSize = newAnisoLevel; + } + + break; + } + } + + var skipCrunchCompression = false; + + if (DontOverrideCrunchWhen != DontOverrideWhen.Never) + { + switch (DontOverrideCrunchWhen) + { + case DontOverrideWhen.AlreadyDisabled: + if (!importer.crunchedCompression) skipCrunchCompression = true; + break; + case DontOverrideWhen.AlreadyEnabled: + if (importer.crunchedCompression) skipCrunchCompression = true; + break; + } + } + + if (!skipCrunchCompression) + { + var oldMaxTextureSize = importer.maxTextureSize; + var newMaxTextureSize = MaxTextureSize; + importer.crunchedCompression = CrunchCompression; + + if (importer.crunchedCompression) + { + switch (OverrideMaxTextureSizeWhen) + { + case OverrideWhenSize.Always: + importer.maxTextureSize = newMaxTextureSize; + break; + case OverrideWhenSize.SmallerThan: + if (oldMaxTextureSize < newMaxTextureSize) + { + importer.maxTextureSize = newMaxTextureSize; + } + + break; + case OverrideWhenSize.BiggerThan: + if (oldMaxTextureSize > newMaxTextureSize) + { + importer.maxTextureSize = newMaxTextureSize; + } + + break; + } + } + } + + importer.SaveAndReimport(); + current++; + } + } + finally + { + EditorUtility.ClearProgressBar(); + details.ResetStats(); + AssetDatabase.StopAssetEditing(); + } + } + } + + public class MassTextureImporter : EditorWindow + { + [MenuItem("VRWorld Toolkit/Quick Functions/Mass Texture Importer", false, 4)] + public static void ShowWindow() + { + var window = GetWindow(typeof(MassTextureImporter)); + window.titleContent = new GUIContent("Mass Texture Importer"); + window.minSize = new Vector2(400, 530); + window.Show(); + } + + private TextureDetails details = new TextureDetails(); + + private Vector2 scrollPos; + + private ImporterSettingsManager importerSettingsManager = new ImporterSettingsManager(); + + private void OnGUI() + { + GUILayout.Label("Selected Textures", Styles.BoldWrap); + using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) + { + using (new EditorGUILayout.VerticalScope()) + { + GUILayout.Label("<b>Texture Count:</b> " + details.TextureCount, Styles.LabelRichText); + GUILayout.Label("<b>Uncrunched Count:</b> " + details.UncrunchedCount, Styles.LabelRichText); + GUILayout.Label("<b>Storage Size:</b> " + EditorUtility.FormatBytes(details.StorageSize), Styles.LabelRichText); + } + + using (new EditorGUILayout.VerticalScope()) + { + GUILayout.Label("<b>Normal Maps:</b> " + details.NormalMaps, Styles.LabelRichText); + GUILayout.Label("<b>Cubemaps:</b> " + details.Cubemaps, Styles.LabelRichText); + } + } + + importerSettingsManager.DrawSettings(); + + GUILayout.Space(5); + + GUILayout.Label("Get textures from:"); + + using (new EditorGUILayout.HorizontalScope()) + { + if (GUILayout.Button("Scene", GUILayout.Width(70), GUILayout.Height(20))) + { + details = GetAllTexturesFromScene(); + } + + if (GUILayout.Button("Assets", GUILayout.Width(70), GUILayout.Height(20))) + { + details = GetAllTexturesFromAssets(); + } + + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Revert", GUILayout.Width(70), GUILayout.Height(20))) + { + importerSettingsManager = new ImporterSettingsManager(); + } + + if (GUILayout.Button("Apply", GUILayout.Width(70), GUILayout.Height(20))) + { + if (EditorUtility.DisplayDialog("Process Importers?", $"About to process Texture Import settings on {details.TextureCount} textures, this can take a while depending on the amount and size of them.\n\nDo you want to continue?", "Ok", "Cancel")) + { + importerSettingsManager.ProcessTextures(details); + } + } + } + } + + private static TextureDetails GetAllTexturesFromScene() + { + var details = new TextureDetails(); + var checkedMaterials = new List<Material>(); + + var allGameObjects = Resources.FindObjectsOfTypeAll(typeof(GameObject)); + var allGameObjectsLength = allGameObjects.Length; + for (var i = 0; i < allGameObjectsLength; i++) + { + var gameObject = allGameObjects[i] as GameObject; + + if (gameObject.hideFlags != HideFlags.None || EditorUtility.IsPersistent(gameObject.transform.root.gameObject)) continue; + + if (EditorUtility.DisplayCancelableProgressBar("Getting All Textures from Scene", gameObject.name, (float) i / allGameObjectsLength)) + { + break; + } + + var renderers = gameObject.GetComponents<Renderer>(); + for (var j = 0; j < renderers.Length; j++) + { + var renderer = renderers[j]; + for (var k = 0; k < renderer.sharedMaterials.Length; k++) + { + var material = renderer.sharedMaterials[k]; + + if (material == null || checkedMaterials.Contains(material)) + continue; + + checkedMaterials.Add(material); + + var shader = material.shader; + + for (var l = 0; l < ShaderUtil.GetPropertyCount(shader); l++) + { + if (ShaderUtil.GetPropertyType(shader, l) == ShaderUtil.ShaderPropertyType.TexEnv) + { + var texture = material.GetTexture(ShaderUtil.GetPropertyName(shader, l)); + + var textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(texture)) as TextureImporter; + + if (textureImporter != null) + { + details.AddTexture(textureImporter, texture); + } + } + } + } + } + } + + EditorUtility.ClearProgressBar(); + return details; + } + + private static TextureDetails GetAllTexturesFromAssets() + { + var details = new TextureDetails(); + + var assetGuidStrings = AssetDatabase.FindAssets("t:texture2D", new[] {"Assets"}); + + var assetsLength = assetGuidStrings.Length; + for (var i = 0; i < assetsLength; i++) + { + var path = AssetDatabase.GUIDToAssetPath(assetGuidStrings[i]); + + if (EditorUtility.DisplayCancelableProgressBar("Getting All Textures from Assets", Path.GetFileName(path), (float) i / assetsLength)) + { + break; + } + + var texture = AssetDatabase.LoadAssetAtPath<Texture>(path); + var textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; + + details.AddTexture(textureImporter, texture); + } + + EditorUtility.ClearProgressBar(); + return details; + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/MassTextureImporter.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/MassTextureImporter.cs.meta new file mode 100644 index 00000000..de394150 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/MassTextureImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 528babda59a4a3442ae04a1a067b9f3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ModelImporterUtil.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ModelImporterUtil.cs new file mode 100644 index 00000000..49ecf7ca --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ModelImporterUtil.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using UnityEditor; +using UnityEngine.Assertions; + +namespace VRWorldToolkit +{ + /// <summary> + /// Utility for setting and getting internal model importer values + /// </summary> + public static class ModelImporterUtil + { + private static readonly System.Type systemType; + private static PropertyInfo mProperty_LegacyBlendShapeNormals; + + static ModelImporterUtil() + { + systemType = Assembly.Load("UnityEditor.dll").GetType("UnityEditor.ModelImporter"); + Assert.IsNotNull(systemType); + } + + public static bool GetLegacyBlendShapeNormals(ModelImporter importer) + { + if (mProperty_LegacyBlendShapeNormals == null) + mProperty_LegacyBlendShapeNormals = systemType.GetProperty("legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.IsNotNull(mProperty_LegacyBlendShapeNormals); + return (bool)mProperty_LegacyBlendShapeNormals.GetValue(importer); + } + + public static void SetLegacyBlendShapeNormals(ModelImporter importer, bool value) + { + if (mProperty_LegacyBlendShapeNormals == null) + mProperty_LegacyBlendShapeNormals = systemType.GetProperty("legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes", BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.IsNotNull(mProperty_LegacyBlendShapeNormals); + mProperty_LegacyBlendShapeNormals.SetValue(importer, value, null); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ModelImporterUtil.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ModelImporterUtil.cs.meta new file mode 100644 index 00000000..a284edb2 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ModelImporterUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d095f1e0d627e7846ae2d803d04b54e5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/PostProcessingTools.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/PostProcessingTools.cs new file mode 100644 index 00000000..dda406dd --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/PostProcessingTools.cs @@ -0,0 +1,200 @@ +using System.IO; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; +#if UNITY_POST_PROCESSING_STACK_V2 +using UnityEngine.Rendering.PostProcessing; +#endif +#if VRC_SDK_VRCSDK3 +using VRC.SDKBase; +#endif +#if VRC_SDK_VRCSDK2 +using VRCSDK2; +#endif + +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +namespace VRWorldToolkit +{ + public class PostProcessingTools : MonoBehaviour + { + [MenuItem("VRWorld Toolkit/Post Processing/Import Post Processing", false, 1)] + private static void PostProcessingInstall() + { + Helper.ImportPackage("com.unity.postprocessing@3.0.3"); + } + + [MenuItem("VRWorld Toolkit/Post Processing/Import Post Processing", true)] + private static bool PostProcessingInstallValidation() + { +#if UNITY_POST_PROCESSING_STACK_V2 + return false; +#else + return true; +#endif + } + + [MenuItem("VRWorld Toolkit/Post Processing/Setup Post Processing", false, 12)] + private static void PostProcessingSetup() + { +#if UNITY_POST_PROCESSING_STACK_V2 + var sceneDescriptors = FindObjectsOfType(typeof(VRC_SceneDescriptor)) as VRC_SceneDescriptor[]; + var avatarDescriptors = FindObjectsOfType(typeof(VRC_AvatarDescriptor)) as VRC_AvatarDescriptor[]; + + if (UpdateLayers.AreLayersSetup() || EditorUtility.DisplayDialog("Layers Missing!", "You haven't setup the project layers from the VRCSDK Builder tab.\r\n\r\nSelect Continue to set them up now.", "Continue", "Cancel")) + { + UpdateLayers.SetupEditorLayers(); + + if (sceneDescriptors.Length == 0) + { + if (avatarDescriptors.Length > 0) + { + SetupBasicPostProcessing(); + } + else if (EditorUtility.DisplayDialog("Scene descriptor missing!", + "No scene descriptor or avatar descriptors was found. A scene descriptor must exist and contain a reference camera for post-processing to appear in-game.\r\n\r\nYou can add a scene descriptor by adding a VRCWorld prefab included with the SDK.\r\n\r\nSelect Cancel to return and add a scene descriptor so the setup can set the reference camera for you, or select Continue to ignore this warning.", + "Continue", + "Cancel")) + { + SetupBasicPostProcessing(); + } + } + else if (sceneDescriptors.Length > 1) + { + EditorUtility.DisplayDialog("Multiple scene descriptors!", "Multiple scene descriptors found, remove any you aren't using and run the setup again.", "OK"); + } + else + { + SetupWorldPostProcessing(sceneDescriptors); + } + } +#endif + } + + [MenuItem("VRWorld Toolkit/Post Processing/Setup Post Processing", true)] + private static bool PostProcessingSetupValidation() + { +#if UNITY_POST_PROCESSING_STACK_V2 + return !(Helper.BuildPlatform() is RuntimePlatform.Android); +#else + return false; +#endif + } + + [MenuItem("VRWorld Toolkit/Post Processing/Post Processing Guide", false, 13)] + private static void PostProcessingGuide() + { + Application.OpenURL("https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Post-Processing"); + } + +#if UNITY_POST_PROCESSING_STACK_V2 + private static void SetupBasicPostProcessing() + { + GameObject camera = null; + + if (Camera.main != null) + { + camera = Camera.main.gameObject; + } + else + { + if (EditorUtility.DisplayDialog("No main camera!", "No main camera found in the current scene. The main camera is needed to create the Post Processing Volume.\r\n\r\nSelect Continue to create a new one.", "Continue", "Cancel")) + { + camera = Helper.CreateMainCamera(); + } + } + + if (camera != null) + { + SetupPostProcessingGenerics(camera); + } + } + + private static void SetupWorldPostProcessing(VRC_SceneDescriptor[] descriptors) + { + if (EditorUtility.DisplayDialog("Setup Post Processing?", "This will setup your scenes Reference Camera and make a new global volume using the included example Post Processing Profile.", "OK", "Cancel")) + { + var referenceCamera = descriptors.Length > 0 && descriptors[0].ReferenceCamera; + + GameObject camera = null; + + if (!referenceCamera && Camera.main is null) + { + if (EditorUtility.DisplayDialog("No main camera!", "No main camera found in the current scene. The main camera is needed to create the Post Processing Volume.\r\n\r\nSelect Continue to create a new one.", "Continue", "Cancel")) + { + camera = Helper.CreateMainCamera(); + + descriptors[0].ReferenceCamera = camera; + } + } + else if (referenceCamera) + { + camera = descriptors[0].ReferenceCamera; + } + else if (Camera.main != null) + { + camera = Camera.main.gameObject; + } + + if (camera != null) + { + descriptors[0].ReferenceCamera = camera; + PrefabUtility.RecordPrefabInstancePropertyModifications(descriptors[0]); + + SetupPostProcessingGenerics(camera); + } + } + } + + public static void SetupPostProcessingGenerics(GameObject camera) + { + //Use PostProcessing layer if it exists otherwise use Water + var layer = LayerMask.NameToLayer("PostProcessing") > -1 ? "PostProcessing" : "Water"; + + //Make sure the Post Process Layer exists and set it up + if (!camera.GetComponent<PostProcessLayer>()) + camera.AddComponent(typeof(PostProcessLayer)); + var postprocessLayer = camera.GetComponent(typeof(PostProcessLayer)) as PostProcessLayer; + postprocessLayer.volumeLayer = LayerMask.GetMask(layer); + + //Copy the example profile to the Post Processing folder + if (!Directory.Exists("Assets/Post Processing")) + AssetDatabase.CreateFolder("Assets", "Post Processing"); + if (AssetDatabase.LoadAssetAtPath("Assets/Post Processing/SilentProfile.asset", typeof(PostProcessProfile)) == null) + { + var path = AssetDatabase.GetAssetPath(Resources.Load("PostProcessing/SilentProfile")); + + if (path != null) + { + AssetDatabase.CopyAsset(path, "Assets/Post Processing/SilentProfile.asset"); + } + } + + var profileFound = false; + + //Set up the post process volume + var volume = Instantiate(PostProcessManager.instance.QuickVolume(16, 100f)); + if (File.Exists("Assets/Post Processing/SilentProfile.asset")) + { + volume.sharedProfile = (PostProcessProfile) AssetDatabase.LoadAssetAtPath("Assets/Post Processing/SilentProfile.asset", typeof(PostProcessProfile)); + profileFound = true; + } + + // Set volume name and layer + volume.gameObject.name = "Post Processing Volume"; + volume.gameObject.layer = LayerMask.NameToLayer(layer); + + // Mark the scene as dirty for saving + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + + // Set the created volume as active selection in hierarchy + Selection.activeGameObject = volume.gameObject; + + // Notify the user if the default profile was not found during setup + if (!profileFound) + EditorUtility.DisplayDialog("Default profile not found!", "Default Post Processing Profile was not found during setup, so it was automatically not set in the Post Processing Volume.\n\nCreate your profile to finish the setup.", "Ok"); + } +#endif + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/PostProcessingTools.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/PostProcessingTools.cs.meta new file mode 100644 index 00000000..7a163423 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/PostProcessingTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e65609481603134da8675c88def0f3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/QuickFunctions.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/QuickFunctions.cs new file mode 100644 index 00000000..d519b864 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/QuickFunctions.cs @@ -0,0 +1,253 @@ +#if VRC_SDK_VRCSDK3 +using VRC.SDKBase; +#endif +#if VRC_SDK_VRCSDK2 +using VRCSDK2; +#endif +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +using VRC.Core; +#endif +using System; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace VRWorldToolkit +{ + public class QuickFunctions : EditorWindow + { +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 + [MenuItem("VRWorld Toolkit/Quick Functions/Copy World ID", false, 15)] + public static void CopyWorldID() + { + var descriptors = FindObjectsOfType(typeof(VRC_SceneDescriptor)) as VRC_SceneDescriptor[]; + + if (descriptors.Length is 1) + { + var pipelineManager = descriptors[0].GetComponent<PipelineManager>(); + + if (pipelineManager) + { + EditorGUIUtility.systemCopyBuffer = pipelineManager.blueprintId; + } + } + } + + [MenuItem("VRWorld Toolkit/Quick Functions/Copy World ID", true)] + private static bool CopyWorldIDValidate() + { + var descriptors = FindObjectsOfType(typeof(VRC_SceneDescriptor)) as VRC_SceneDescriptor[]; + + if (descriptors.Length is 1) + { + var pipelineManager = descriptors[0].GetComponent<PipelineManager>(); + + if (pipelineManager) + return pipelineManager.blueprintId.Length > 0; + } + + return false; + } + + [MenuItem("VRWorld Toolkit/Quick Functions/Setup Layers and Collision Matrix", false, 16)] + public static void SetupLayersCollisionMatrix() + { + if (!UpdateLayers.AreLayersSetup()) + { + UpdateLayers.SetupEditorLayers(); + } + + if (!UpdateLayers.IsCollisionLayerMatrixSetup()) + { + UpdateLayers.SetupCollisionLayerMatrix(); + } + } + + [MenuItem("VRWorld Toolkit/Quick Functions/Setup Layers and Collision Matrix", true)] + private static bool SetupLayersCollisionMatrixValidate() + { + if (UpdateLayers.AreLayersSetup() && UpdateLayers.IsCollisionLayerMatrixSetup()) + { + return false; + } + + return true; + } +#endif + [MenuItem("VRWorld Toolkit/Quick Functions/Remove Missing Scripts From Scene", false, 17)] + private static void FindAndRemoveMissingScripts() + { + if (EditorUtility.DisplayDialog("Remove Missing Scripts", "Running this will go through all GameObjects in the open scene and remove any components with missing scripts. This action can't be reversed!\n\nAre you sure you want to continue?", "Continue", "Cancel")) + { + var overallRemovedCount = 0; + var allGameObjects = Resources.FindObjectsOfTypeAll(typeof(GameObject)); + var allGameObjectsLength = allGameObjects.Length; + for (var i = 0; i < allGameObjectsLength; i++) + { + var gameObject = allGameObjects[i] as GameObject; + + if (gameObject != null && (gameObject.hideFlags != HideFlags.None || EditorUtility.IsPersistent(gameObject.transform.root.gameObject))) continue; + + if (EditorUtility.DisplayCancelableProgressBar("Checking For Missing Scripts", gameObject.name, (float) i / allGameObjectsLength)) break; + + var removedCount = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(gameObject); + if (removedCount > 0) + { + GameObjectUtility.RemoveMonoBehavioursWithMissingScript(gameObject); + PrefabUtility.RecordPrefabInstancePropertyModifications(gameObject); + overallRemovedCount += removedCount; + } + } + + EditorUtility.ClearProgressBar(); + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + var message = overallRemovedCount > 0 ? $"Removed total of {overallRemovedCount} components with missing scripts." : "No components with missing scripts were found."; + EditorUtility.DisplayDialog("Remove Missing Scripts", message, "Ok"); + } + } + + /// <summary> + /// Sourced from: https://docs.vrchat.com/v2021.2.3/docs/vrchat-configuration-window + /// </summary> + [MenuItem("VRWorld Toolkit/Quick Functions/Add or Match VRChat Quality Settings", false, 18)] + private static void AddOrMatchVRChatQualitySettings() + { + var selection = EditorUtility.DisplayDialogComplex("Match Quality Settings To VRChat", + "Running this will replace or match existing Quality Settings with what VRChat uses.\n\nSelecting Replace will remove unrelated Quality Settings. Add or Match will add the Settings after the existing ones if there are no Quality Settings named the same as VRChat uses. VRHigh will be set as the Standalone default and Quest 2 as Android default.\n\nVRHigh, VRLow, DesktopLow, Quest 2, Quest 1", + "Replace", "Add or Match", "Cancel"); + + if (selection != 2) + { + var qualitySettings = AssetDatabase.LoadAssetAtPath<QualitySettings>("ProjectSettings/QualitySettings.asset"); + var serializedQualitySettings = new SerializedObject(qualitySettings); + var qualitySettingsProperty = serializedQualitySettings.FindProperty("m_QualitySettings"); + var perPlatformDefaultQualityProperty = serializedQualitySettings.FindProperty("m_PerPlatformDefaultQuality"); + + if (selection == 0) + { + qualitySettingsProperty.ClearArray(); + } + + var exceptionHappened = SetQualitySettings(AddOrGetQualitySetting("VRHigh", qualitySettingsProperty), 8, 0, 2, 2, true, true, true, 1, false, 0, 2, 3, 1, 150, 2, 2, 0.3333333f, new Vector3(0.1f, 0.2f, 0.5f), 2, 0, 2, 0, 4096, 2, 4, true); + + exceptionHappened = exceptionHappened || SetQualitySettings(AddOrGetQualitySetting("VRLow", qualitySettingsProperty), 4, 0, 2, 2, false, true, true, 1, false, 0, 2, 2, 1, 75, 2, 1, 0.3333333f, new Vector3(0.1f, 0.2f, 0.5f), 2, 0, 1, 0, 1024, 2, 4, true); + + exceptionHappened = exceptionHappened || SetQualitySettings(AddOrGetQualitySetting("DesktopLow", qualitySettingsProperty), 4, 0, 2, 0, false, true, true, 1, false, 0, 2, 2, 1, 75, 2, 1, 0.3333333f, new Vector3(0.1f, 0.2f, 0.5f), 2, 0, 1, 0, 1024, 2, 4, true); + + exceptionHappened = exceptionHappened || SetQualitySettings(AddOrGetQualitySetting("Quest 2", qualitySettingsProperty), 2, 0, 1, 2, false, true, true, 1, false, 1, 2, 1, 1, 40, 3, 1, 0.3333333f, new Vector3(0.1f, 0.2f, 0.5f), 1, 0, 1, 0, 256, 2, 16, true); + + exceptionHappened = exceptionHappened || SetQualitySettings(AddOrGetQualitySetting("Quest 1", qualitySettingsProperty), 2, 0, 1, 1, false, true, true, 1, false, 1, 2, 1, 1, 40, 3, 1, 0.3333333f, new Vector3(0.1f, 0.2f, 0.5f), 1, 0, 1, 0, 256, 2, 16, true); + + if (exceptionHappened) + { + EditorUtility.DisplayDialog("Failed Applying Quality Settings", "Something went wrong applying new Quality Settings check console for more details.", "Ok"); + } + else + { + for (var i = 0; i < perPlatformDefaultQualityProperty.arraySize; i++) + { + var serializedPropertyPlatform = perPlatformDefaultQualityProperty.GetArrayElementAtIndex(i); + var serializedPropertySetting = serializedPropertyPlatform.FindPropertyRelative("second"); + switch (serializedPropertyPlatform.displayName) + { + case "Standalone": + serializedPropertySetting.intValue = GetQualitySettingIndex("VRHigh", qualitySettingsProperty); + break; + case "Android": + serializedPropertySetting.intValue = GetQualitySettingIndex("Quest 2", qualitySettingsProperty); + break; + } + } + + serializedQualitySettings.ApplyModifiedPropertiesWithoutUndo(); + + QualitySettings.SetQualityLevel(GetQualitySettingIndex("VRHigh", qualitySettingsProperty), true); + } + } + + SerializedProperty AddOrGetQualitySetting(string name, SerializedProperty qualitySettingsProperty) + { + for (var i = 0; i < qualitySettingsProperty.arraySize; i++) + { + var setting = qualitySettingsProperty.GetArrayElementAtIndex(i); + if (setting.FindPropertyRelative("name").stringValue == name) + { + return setting; + } + } + + qualitySettingsProperty.arraySize++; + var newSetting = qualitySettingsProperty.GetArrayElementAtIndex(qualitySettingsProperty.arraySize - 1); + var nameProperty = newSetting.FindPropertyRelative("name"); + nameProperty.stringValue = name; + return newSetting; + } + + int GetQualitySettingIndex(string name, SerializedProperty qualitySettingsProperty) + { + for (var i = 0; i < qualitySettingsProperty.arraySize; i++) + { + var setting = qualitySettingsProperty.GetArrayElementAtIndex(i); + if (setting.FindPropertyRelative("name").stringValue == name) + { + return i; + } + } + + return 0; + } + + bool SetQualitySettings(SerializedProperty qualitySetting, + // Rendering + int pixelLightCount, int textureQuality, int anisotropicTextures, int antiAliasing, bool softParticles, bool realtimeReflectionProbes, bool billboardsFaceCameraPosition, float resolutionScalingFixedDPIFactor, bool streamingMipmapsActive, + // Shadows + int shadowmaskMode, int shadows, int shadowResolution, int shadowProjection, float shadowDistance, int shadowNearPlaneOffset, int shadowCascades, float shadowCascade2Split, Vector3 shadowCascade4Split, + // Other + int blendWeights, int vSyncCount, float lodBias, int maximumLODLevel, int particleRaycastBudget, int asyncUploadTimeSlice, int asyncUploadBufferSize, bool asyncUploadPersistentBuffer) + { + try + { + // Rendering + qualitySetting.FindPropertyRelative("pixelLightCount").intValue = pixelLightCount; + qualitySetting.FindPropertyRelative("textureQuality").enumValueIndex = textureQuality; + qualitySetting.FindPropertyRelative("anisotropicTextures").enumValueIndex = anisotropicTextures; + qualitySetting.FindPropertyRelative("antiAliasing").enumValueIndex = antiAliasing; + qualitySetting.FindPropertyRelative("softParticles").boolValue = softParticles; + qualitySetting.FindPropertyRelative("realtimeReflectionProbes").boolValue = realtimeReflectionProbes; + qualitySetting.FindPropertyRelative("billboardsFaceCameraPosition").boolValue = billboardsFaceCameraPosition; + qualitySetting.FindPropertyRelative("resolutionScalingFixedDPIFactor").floatValue = resolutionScalingFixedDPIFactor; + qualitySetting.FindPropertyRelative("streamingMipmapsActive").boolValue = streamingMipmapsActive; + + // Shadows + qualitySetting.FindPropertyRelative("shadowmaskMode").enumValueIndex = shadowmaskMode; + qualitySetting.FindPropertyRelative("shadows").enumValueIndex = shadows; + qualitySetting.FindPropertyRelative("shadowResolution").enumValueIndex = shadowResolution; + qualitySetting.FindPropertyRelative("shadowProjection").enumValueIndex = shadowProjection; + qualitySetting.FindPropertyRelative("shadowDistance").floatValue = shadowDistance; + qualitySetting.FindPropertyRelative("shadowNearPlaneOffset").floatValue = shadowNearPlaneOffset; + qualitySetting.FindPropertyRelative("shadowCascades").enumValueIndex = shadowCascades; + qualitySetting.FindPropertyRelative("shadowCascade2Split").floatValue = shadowCascade2Split; + qualitySetting.FindPropertyRelative("shadowCascade4Split").vector3Value = shadowCascade4Split; + + // Other + qualitySetting.FindPropertyRelative("blendWeights").enumValueIndex = blendWeights; + qualitySetting.FindPropertyRelative("vSyncCount").enumValueIndex = vSyncCount; + qualitySetting.FindPropertyRelative("lodBias").floatValue = lodBias; + qualitySetting.FindPropertyRelative("maximumLODLevel").intValue = maximumLODLevel; + qualitySetting.FindPropertyRelative("particleRaycastBudget").intValue = particleRaycastBudget; + qualitySetting.FindPropertyRelative("asyncUploadTimeSlice").intValue = asyncUploadTimeSlice; + qualitySetting.FindPropertyRelative("asyncUploadBufferSize").intValue = asyncUploadBufferSize; + qualitySetting.FindPropertyRelative("asyncUploadPersistentBuffer").boolValue = asyncUploadPersistentBuffer; + + return false; + } + catch (Exception e) + { + Console.WriteLine(e); + return true; + } + } + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/QuickFunctions.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/QuickFunctions.cs.meta new file mode 100644 index 00000000..46717ecb --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/QuickFunctions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3574f219fda73ca4a8c07cc444457e47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ScriptingDefineManager.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ScriptingDefineManager.cs new file mode 100644 index 00000000..c49783e7 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ScriptingDefineManager.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace VRWorldToolkit +{ + public class ScriptingDefineManager : MonoBehaviour + { + /// <summary> + /// Add a new scripting define symbol in project settings + /// </summary> + /// <param name="define">Scripting define symbol to add</param> + public static void AddScriptingDefine(string define) + { + var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup).Split(';').ToList(); + + if (defines.Contains(define)) return; + + defines.Add(define); + + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, string.Join(";", defines)); + } + + /// <summary> + /// Remove a scripting define symbol from project settings + /// </summary> + /// <param name="define">Scripting define symbol to remove</param> + public static void RemoveScriptingDefine(string define) + { + var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup).Split(';').ToList(); + + if (!defines.Contains(define)) return; + + defines.Remove(define); + + PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, string.Join(";", defines)); + } + + /// <summary> + /// If scripting define symbol exists + /// </summary> + /// <param name="define">Scripting define symbol to check for</param> + /// <returns></returns> + public static bool ScriptingDefineExists(string define) + { + var defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup).Split(';'); + + return defines.Contains(define); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ScriptingDefineManager.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ScriptingDefineManager.cs.meta new file mode 100644 index 00000000..dfb3681c --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/ScriptingDefineManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e183946454bd3b147a38db5d972ea1ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/TagHelper.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/TagHelper.cs new file mode 100644 index 00000000..487978ac --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/TagHelper.cs @@ -0,0 +1,50 @@ +using UnityEditor; + +namespace VRWorldToolkit +{ + public static class TagHelper + { + public static void AddTag(string tag) + { + UnityEngine.Object[] asset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset"); + if ((asset != null) && (asset.Length > 0)) + { + var so = new SerializedObject(asset[0]); + var tags = so.FindProperty("tags"); + + for (var i = 0; i < tags.arraySize; ++i) + { + if (tags.GetArrayElementAtIndex(i).stringValue == tag) + { + return; + } + } + + tags.InsertArrayElementAtIndex(tags.arraySize); + tags.GetArrayElementAtIndex(tags.arraySize - 1).stringValue = tag; + so.ApplyModifiedProperties(); + so.Update(); + } + } + + public static bool TagExists(string tag) + { + UnityEngine.Object[] asset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset"); + if ((asset != null) && (asset.Length > 0)) + { + var so = new SerializedObject(asset[0]); + var tags = so.FindProperty("tags"); + + for (var i = 0; i < tags.arraySize; ++i) + { + if (tags.GetArrayElementAtIndex(i).stringValue == tag) + { + return true; + } + } + } + + return false; + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/TagHelper.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/TagHelper.cs.meta new file mode 100644 index 00000000..e9081ac6 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/TagHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46423f1e49d51a34ab99fc9ffe68880a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/UsefulLinks.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/UsefulLinks.cs new file mode 100644 index 00000000..3d072779 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/UsefulLinks.cs @@ -0,0 +1,54 @@ +using UnityEditor; +using UnityEngine; + +namespace VRWorldToolkit +{ + public class UsefulLinks : MonoBehaviour + { + [MenuItem("VRWorld Toolkit/Useful Links/VRCPrefabs Database", false, 40)] + private static void VRCPrefabsLink() + { + Application.OpenURL("https://vrcprefabs.com/browse"); + } + + [MenuItem("VRWorld Toolkit/Useful Links/Unofficial VRChat Wiki (EN)", false, 41)] + private static void UnofficialWikiEN() + { + Application.OpenURL("http://vrchat.wikidot.com/"); + } + + [MenuItem("VRWorld Toolkit/Useful Links/VRChat 技術メモ帳 (JP)", false, 42)] + private static void UnofficialWikiJP() + { + Application.OpenURL("https://vrcworld.wiki.fc2.com/"); + } + + [MenuItem("VRWorld Toolkit/Useful Links/CyanEmu", false, 43)] + private static void CyanEmu() + { + Application.OpenURL("https://github.com/CyanLaser/CyanEmu"); + } + + [MenuItem("VRWorld Toolkit/Useful Links/EasyQuestSwitch", false, 44)] + private static void EasyQuestSwitch() + { + Application.OpenURL("https://github.com/JordoVR/EasyQuestSwitch"); + } + +#if UDON + [MenuItem("VRWorld Toolkit/Useful Links/UdonSharp", false, 45)] + private static void UdonSharpLink() + { + Application.OpenURL("https://github.com/Merlin-san/UdonSharp/"); + } +#endif + +#if BAKERY_INCLUDED + [MenuItem("VRWorld Toolkit/Useful Links/Bakery Documentation", false, 46)] + private static void BakeryDocumentationLink() + { + Application.OpenURL("https://geom.io/bakery/"); + } +#endif + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/UsefulLinks.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/UsefulLinks.cs.meta new file mode 100644 index 00000000..05631209 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/UsefulLinks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4eee69455c11f0e4ea998ad0b144e3af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTAbout.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTAbout.cs new file mode 100644 index 00000000..db0e5a4e --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTAbout.cs @@ -0,0 +1,80 @@ +using UnityEditor; +using UnityEngine; + +namespace VRWorldToolkit +{ + public class VRWTAbout : EditorWindow + { + [MenuItem("VRWorld Toolkit/About VRWorld Toolkit", false, 41)] + public static void ShowWindow() + { + var window = (VRWTAbout) GetWindow(typeof(VRWTAbout), true, "VRWorld Toolkit"); + window.minSize = new Vector2(600, 380); + window.maxSize = new Vector2(600, 380); + window.Show(); + } + + private static GUIStyle header, text; + + private static Texture iconTwitter, iconDiscord, iconGithub, iconPatreon, iconKofi; + + public void OnEnable() + { + header = new GUIStyle + { + normal = + { + background = Resources.Load("SplashTextures/VRWTSplashLogo") as Texture2D, + textColor = Color.white, + }, + fixedHeight = 140 + }; + + text = new GUIStyle("Label") + { + wordWrap = true, + richText = true + }; + + iconTwitter = Resources.Load("SplashTextures/IconTwitter") as Texture2D; + iconDiscord = Resources.Load("SplashTextures/IconDiscord") as Texture2D; + iconGithub = Resources.Load("SplashTextures/IconGithub") as Texture2D; + iconPatreon = Resources.Load("SplashTextures/IconPatreon") as Texture2D; + iconKofi = Resources.Load("SplashTextures/IconKofi") as Texture2D; + } + + private void OnGUI() + { + // Header Image + GUILayout.Box("", header); + + // Information Texts + GUILayout.Label("Welcome to VRWorld Toolkit!", EditorStyles.boldLabel); + + GUILayout.Label("VRWorld Toolkit is a project aimed at helping people get into world building faster without spending time combing different documentations for all the smaller mistakes you can make while making your first world. Even for experienced world builders, it helps make tedious steps like setting up post-processing faster and allows you not to forget the dozen little things you need to remember while building worlds.", text); + + GUILayout.Label("If you have suggestions, found problems with the included tools, or want to check my social channels, you can click on the buttons below. Feedback is always welcome, so I know what to improve!", text); + + GUILayout.FlexibleSpace(); + + // Social Buttons + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + if (GUILayout.Button(iconTwitter, GUIStyle.none)) Application.OpenURL("https://twitter.com/Sackboy_1"); + GUILayout.Space(20); + if (GUILayout.Button(iconDiscord, GUIStyle.none)) Application.OpenURL("https://discord.gg/8w2Tc6C"); + GUILayout.Space(20); + if (GUILayout.Button(iconGithub, GUIStyle.none)) Application.OpenURL("https://github.com/oneVR/VRWorldToolkit"); + GUILayout.Space(20); + if (GUILayout.Button(iconPatreon, GUIStyle.none)) Application.OpenURL("https://www.patreon.com/onevr"); + GUILayout.Space(20); + if (GUILayout.Button(iconKofi, GUIStyle.none)) Application.OpenURL("https://ko-fi.com/onevr"); + + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + GUILayout.Space(20); + } + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTAbout.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTAbout.cs.meta new file mode 100644 index 00000000..675cb366 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTAbout.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b860d7350d99cf342bd9f2ec73c5ae8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTDataStructures.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTDataStructures.cs new file mode 100644 index 00000000..a02d61dd --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTDataStructures.cs @@ -0,0 +1,140 @@ +using UnityEditor; +using UnityEngine; + +namespace VRWorldToolkit.DataStructures +{ + public static class Styles + { + public static GUIStyle HelpBoxRichText { get; internal set; } + public static GUIStyle HelpBoxPadded { get; internal set; } + public static GUIStyle LabelRichText { get; internal set; } + public static GUIStyle RichText { get; internal set; } + public static GUIStyle RichTextWrap { get; internal set; } + public static GUIStyle BoldWrap { get; internal set; } + public static GUIStyle RedLabel { get; internal set; } + public static GUIStyle TreeViewLabel { get; internal set; } + public static GUIStyle TreeViewLabelSelected { get; internal set; } + public static GUIStyle CenteredLabel { get; internal set; } + public static GUIStyle Center { get; internal set; } + + static Styles() + { + Reload(); + } + + static void Reload() + { + HelpBoxRichText = new GUIStyle("HelpBox") + { + alignment = TextAnchor.MiddleLeft, + richText = true + }; + + HelpBoxPadded = new GUIStyle("HelpBox") + { + margin = new RectOffset(18, 4, 4, 4), + alignment = TextAnchor.MiddleLeft, + richText = true + }; + + LabelRichText = new GUIStyle("Label") + { + richText = true, + margin = new RectOffset(5, 5, 0, 0), + }; + + RichText = new GUIStyle + { + richText = true + }; + + RichTextWrap = new GUIStyle("Label") + { + richText = true, + wordWrap = true + }; + + BoldWrap = new GUIStyle("boldLabel") + { + wordWrap = true + }; + + RedLabel = new GUIStyle("Label") + { + normal = + { + textColor = Color.red, + }, + }; + + TreeViewLabel = new GUIStyle("Label") + { + alignment = TextAnchor.MiddleLeft, + wordWrap = false, + }; + + TreeViewLabelSelected = new GUIStyle("WhiteLabel") + { + alignment = TextAnchor.MiddleLeft, + wordWrap = false, + }; + + CenteredLabel = new GUIStyle("Label") + { + alignment = TextAnchor.LowerCenter, + fontSize = 17, + fontStyle = FontStyle.BoldAndItalic, + normal = + { + textColor = new Color(0.33f, 0.33f, 0.33f), + } + }; + + Center = new GUIStyle() + { + alignment = TextAnchor.MiddleCenter + }; + } + } + + public static class Validation + { + /// <summary> + /// Sourced from the whitelist included in the VRCSDK + /// https://docs.vrchat.com/docs/quest-content-limitations + /// </summary> + public static readonly string[] WorldShaderWhiteList = + { + "VRChat/Mobile/Standard Lite", + "VRChat/Mobile/Diffuse", + "VRChat/Mobile/Bumped Diffuse", + "VRChat/Mobile/Bumped Mapped Specular", + "VRChat/Mobile/Toon Lit", + "VRChat/Mobile/MatCap Lit", + "VRChat/Mobile/Lightmapped", + "VRChat/Mobile/Skybox", + "VRChat/Mobile/Particles/Additive", + "VRChat/Mobile/Particles/Multiply", + "FX/MirrorReflection", + "UI/Default" + }; + + /// <summary> + /// Sourced from Unity documentation at: + /// https://docs.unity3d.com/2018.4/Documentation/Manual/class-TextureImporterOverride.html + /// </summary> + public static readonly TextureImporterFormat[] UnsupportedCompressionFormatsQuest = + { + TextureImporterFormat.DXT1, + TextureImporterFormat.DXT5, + TextureImporterFormat.DXT1Crunched, + TextureImporterFormat.DXT5Crunched, + TextureImporterFormat.BC6H, + TextureImporterFormat.BC7, + TextureImporterFormat.PVRTC_RGB2, + TextureImporterFormat.PVRTC_RGB4, + TextureImporterFormat.PVRTC_RGBA2, + TextureImporterFormat.PVRTC_RGBA4, + }; + } +}
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTDataStructures.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTDataStructures.cs.meta new file mode 100644 index 00000000..db959900 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/VRWTDataStructures.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18d6925c8154648478a78a3c56e1058f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/WorldDebugger.cs b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/WorldDebugger.cs new file mode 100644 index 00000000..55ede1e4 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/WorldDebugger.cs @@ -0,0 +1,3249 @@ +#if VRC_SDK_VRCSDK3 +using VRC.SDKBase; +#endif +#if VRC_SDK_VRCSDK2 +using VRCSDK2; +#endif +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +using VRC.Core; +#endif +#if UNITY_POST_PROCESSING_STACK_V2 +using UnityEngine.Rendering.PostProcessing; +#endif +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEngine; +using UnityEngine.Rendering; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using UnityEditor.SceneManagement; +using UnityEngine.Profiling; +using UnityEngine.SceneManagement; +using System.Text.RegularExpressions; +using UnityEditor.IMGUI.Controls; +using VRWorldToolkit.DataStructures; +using Microsoft.Win32; +using System.Reflection; +using Object = UnityEngine.Object; +using UnityEngine.UI; +using Debug = UnityEngine.Debug; +using System.Diagnostics; +using System.Globalization; +using UnityEngine.Assertions; + +#if VRC_SDK_VRCSDK2 || VRC_SDK_VRCSDK3 +namespace VRWorldToolkit +{ + public class WorldDebugger : EditorWindow + { + private static Texture badFPS; + private static Texture goodFPS; + private static Texture tips; + private static Texture info; + private static Texture error; + private static Texture warning; + + private static bool recheck = true; + private static bool autoRecheck = true; + + private enum MessageType + { + BadFPS = 0, + GoodFPS = 1, + Tips = 2, + Error = 3, + Warning = 4, + Info = 5 + } + + static Texture GetDebuggerIcon(MessageType infoType) + { + if (!badFPS) + badFPS = Resources.Load<Texture>("DebuggerIcons/Bad_FPS_Icon"); + if (!goodFPS) + goodFPS = Resources.Load<Texture>("DebuggerIcons/Good_FPS_Icon"); + if (!tips) + tips = Resources.Load<Texture>("DebuggerIcons/Performance_Tips"); + if (!info) + info = Resources.Load<Texture>("DebuggerIcons/Performance_Info"); + if (!error) + error = Resources.Load<Texture>("DebuggerIcons/Error_Icon"); + if (!warning) + warning = Resources.Load<Texture>("DebuggerIcons/Warning_Icon"); + + switch (infoType) + { + case MessageType.BadFPS: + return badFPS; + case MessageType.GoodFPS: + return goodFPS; + case MessageType.Tips: + return tips; + case MessageType.Info: + return info; + case MessageType.Error: + return error; + case MessageType.Warning: + return warning; + } + + return info; + } + + [Serializable] + private class SingleMessage + { + public string variable; + public string variable2; + public GameObject[] selectObjects; + public Action AutoFix; + public string assetPath; + + public SingleMessage(string variable) + { + this.variable = variable; + } + + public SingleMessage(string variable, string variable2) + { + this.variable = variable; + this.variable2 = variable2; + } + + public SingleMessage(GameObject[] objs) + { + selectObjects = objs; + } + + public SingleMessage(GameObject obj) + { + selectObjects = new[] {obj}; + } + + public SingleMessage(Action autoFix) + { + AutoFix = autoFix; + } + + public SingleMessage SetSelectObject(GameObject[] objs) + { + selectObjects = objs; + return this; + } + + public SingleMessage SetSelectObject(GameObject obj) + { + selectObjects = new[] {obj}; + return this; + } + + public SingleMessage SetAutoFix(Action autoFix) + { + AutoFix = autoFix; + return this; + } + + public SingleMessage SetAssetPath(string path) + { + assetPath = path; + return this; + } + } + + [Serializable] + private class MessageGroup : IEquatable<MessageGroup> + { + public readonly string Message; + public readonly string CombinedMessage; + public readonly string AdditionalInfo; + + private bool? disableCombinedSelection = null; + private int? objectCount = null; + + public readonly MessageType MessageType; + + public string Documentation; + + public Action GroupAutoFix; + + public readonly List<SingleMessage> MessageList = new List<SingleMessage>(); + + public MessageGroup(string message, MessageType messageType) + { + Message = message; + MessageType = messageType; + } + + public MessageGroup(string message, string combinedMessage, MessageType messageType) + { + Message = message; + CombinedMessage = combinedMessage; + MessageType = messageType; + } + + public MessageGroup(string message, string combinedMessage, string additionalInfo, MessageType messageType) + { + Message = message; + CombinedMessage = combinedMessage; + AdditionalInfo = additionalInfo; + MessageType = messageType; + } + + public MessageGroup SetGroupAutoFix(Action groupAutoFix) + { + GroupAutoFix = groupAutoFix; + return this; + } + + public MessageGroup SetDocumentation(string documentation) + { + Documentation = documentation; + return this; + } + + public MessageGroup AddSingleMessage(SingleMessage message) + { + MessageList.Add(message); + return this; + } + + public int GetTotalCount() + { + if (objectCount is null) + { + var count = 0; + + for (var i = 0; i < MessageList.Count; i++) + { + var item = MessageList[i]; + if (item.selectObjects != null) + { + count += item.selectObjects.Count(); + } + else + { + if (item.assetPath != null) + { + count++; + } + } + } + + objectCount = count; + } + + return (int) objectCount; + } + + public bool HasSelectGameObjects() + { + if (disableCombinedSelection is null) + { + for (var i = 0; i < MessageList.Count; i++) + { + var item = MessageList[i]; + if (item.selectObjects != null && item.selectObjects.Any()) + { + disableCombinedSelection = true; + } + } + + if (disableCombinedSelection == null) + disableCombinedSelection = false; + } + + return (bool) disableCombinedSelection; + } + + public GameObject[] GetSelectObjects() + { + var objs = new List<GameObject>(); + foreach (var item in MessageList.Where(o => o.selectObjects != null)) + { + objs.AddRange(item.selectObjects); + } + + return objs.ToArray(); + } + + public string[] GetAssetPaths() + { + return MessageList.Where(a => a.assetPath != null).Select(item => item.assetPath).ToArray(); + } + + public Action[] GetSeparateActions() + { + return MessageList.Where(m => m.AutoFix != null).Select(m => m.AutoFix).ToArray(); + } + + public bool Buttons() + { + return GetSelectObjects().Any() || GetAssetPaths().Any() || GroupAutoFix != null || GetSeparateActions().Any() || GroupAutoFix != null || Documentation != null; + } + + public override bool Equals(object obj) + { + return Equals(obj as MessageGroup); + } + + public bool Equals(MessageGroup other) + { + return other != null && + Message == other.Message && + CombinedMessage == other.CombinedMessage && + AdditionalInfo == other.AdditionalInfo && + MessageType == other.MessageType; + } + + public override int GetHashCode() + { + var hashCode = 842570769; + hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Message); + hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(CombinedMessage); + hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(AdditionalInfo); + hashCode = hashCode * -1521134295 + MessageType.GetHashCode(); + return hashCode; + } + + public static bool operator ==(MessageGroup group1, MessageGroup group2) + { + return EqualityComparer<MessageGroup>.Default.Equals(group1, group2); + } + + public static bool operator !=(MessageGroup group1, MessageGroup group2) + { + return !(group1 == group2); + } + } + + [Serializable] + private class MessageCategory + { + public string listName; + + [SerializeField] public List<MessageGroup> MessageGroups; + private Dictionary<int, bool> expandedGroups; + [SerializeField] public bool disabled; + + public MessageCategory() + { + MessageGroups = new List<MessageGroup>(); + expandedGroups = new Dictionary<int, bool>(); + } + + public MessageCategory(string listName) + { + MessageGroups = new List<MessageGroup>(); + expandedGroups = new Dictionary<int, bool>(); + + this.listName = listName; + } + + public MessageGroup AddMessageGroup(MessageGroup debuggerMessage) + { + MessageGroups.Add(debuggerMessage); + + return debuggerMessage; + } + + public void ClearMessages() + { + MessageGroups.Clear(); + } + + public bool HasMessages() + { + var count = 0; + + for (var i = 0; i < MessageGroups.Count; i++) + { + var group = MessageGroups[i]; + + if (group.CombinedMessage != null && group.GetTotalCount() > 0) + { + count++; + } + else if (group.CombinedMessage is null) + { + count++; + } + } + + return count > 0; + } + + public bool IsExpanded(MessageGroup mg) + { + var hash = mg.GetHashCode(); + return expandedGroups.ContainsKey(hash) && expandedGroups[hash]; + } + + public void SetExpanded(MessageGroup mg, bool expanded) + { + var hash = mg.GetHashCode(); + if (expandedGroups.ContainsKey(hash)) + { + expandedGroups[hash] = expanded; + } + else + { + expandedGroups.Add(hash, expanded); + } + } + } + + [Serializable] + private class MessageCategoryList + { + [SerializeField] public List<MessageCategory> messageCategory = new List<MessageCategory>(); + private List<MessageCategory> drawList = new List<MessageCategory>(); + + [SerializeField] private Vector2 scrollPos; + + public MessageCategory CreateOrGetCategory(string listName) + { + var oldMessageCategory = messageCategory.Find(x => x.listName == listName); + + if (oldMessageCategory is null) + { + var newMessageCategory = new MessageCategory(listName); + messageCategory.Add(newMessageCategory); + return newMessageCategory; + } + + return oldMessageCategory; + } + + public void DrawTabSelector() + { + EditorGUILayout.BeginHorizontal(); + + for (var i = 0; i < messageCategory.Count; i++) + { + var item = messageCategory[i]; + + var button = "miniButtonMid"; + + if (messageCategory.First() == item) + { + button = "miniButtonLeft"; + } + else if (messageCategory.Last() == item) + { + button = "miniButtonRight"; + } + + item.disabled = GUILayout.Toggle(item.disabled, item.listName, button); + } + + EditorGUILayout.EndHorizontal(); + } + + public bool HasCategories() + { + return messageCategory.Count > 0; + } + + public void ClearCategories() + { + messageCategory.ForEach(m => m.ClearMessages()); + } + + private const int ButtonWidth = 75; + private const int ButtonHeight = 20; + + public void DrawMessages() + { + if (Event.current.type == EventType.Layout) + { + drawList = messageCategory; + } + + using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPos)) + { + scrollPos = scrollView.scrollPosition; + + for (var i = 0; i < drawList.Count; i++) + { + if (drawList[i].disabled) continue; + + var group = drawList[i]; + + GUILayout.Label(group.listName, EditorStyles.boldLabel); + + if (!group.HasMessages()) + { + using (new EditorGUILayout.HorizontalScope()) + { + DrawMessage("No messages found for " + group.listName + ".", MessageType.Info); + } + + continue; + } + + for (var l = 0; l < group.MessageGroups.Count; l++) + { + var messageGroup = group.MessageGroups[l]; + + if (messageGroup.MessageList is null || messageGroup.CombinedMessage != null && messageGroup.MessageList.Count == 0) continue; + + var singleCombinedMessage = messageGroup.MessageList.Count == 1; + var expanded = !singleCombinedMessage && group.IsExpanded(messageGroup); + var hasButtons = messageGroup.Buttons(); + + string finalMessage; + + if (messageGroup.MessageList.Count == 0) + { + finalMessage = messageGroup.Message; + } + else + { + finalMessage = singleCombinedMessage ? string.Format(messageGroup.Message, messageGroup.MessageList[0].variable, messageGroup.MessageList[0].variable2) : string.Format(messageGroup.CombinedMessage ?? string.Empty, messageGroup.GetTotalCount().ToString()); + } + + if (messageGroup.AdditionalInfo != null) + { + finalMessage += " " + messageGroup.AdditionalInfo; + } + + using (new EditorGUILayout.HorizontalScope()) + { + DrawMessage(finalMessage, messageGroup.MessageType); + + if (hasButtons) + { + if (singleCombinedMessage) + { + var message = messageGroup.MessageList[0]; + DrawButtons(message.selectObjects, messageGroup.Documentation, message.assetPath, message.AutoFix, messageGroup.HasSelectGameObjects()); + } + else + { + DrawButtons(messageGroup.GetSelectObjects(), messageGroup.Documentation, null, messageGroup.GroupAutoFix, messageGroup.HasSelectGameObjects()); + } + } + } + + if (messageGroup.MessageList.Count > 1) + { + expanded = EditorGUILayout.Foldout(expanded, "Show separate messages"); + group.SetExpanded(messageGroup, expanded); + + if (!expanded) continue; + + for (var j = 0; j < messageGroup.MessageList.Count; j++) + { + var message = messageGroup.MessageList[j]; + + var finalSingleMessage = string.Format(messageGroup.Message, message.variable, message.variable2); + + using (new EditorGUILayout.HorizontalScope()) + { + DrawPaddedMessage(finalSingleMessage); + DrawButtons(message.selectObjects, null, message.assetPath, message.AutoFix, true); + } + } + + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + } + } + } + + GUILayout.FlexibleSpace(); + } + + void DrawPaddedMessage(string messageText) + { + var box = new GUIContent(messageText); + GUILayout.Box(box, Styles.HelpBoxPadded, GUILayout.ExpandHeight(true), GUILayout.MinWidth(EditorGUIUtility.currentViewWidth - 116)); + } + + void DrawMessage(string messageText, MessageType type) + { + var box = new GUIContent(messageText, GetDebuggerIcon(type)); + GUILayout.Box(box, Styles.HelpBoxRichText, GUILayout.ExpandHeight(true), GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 18)); + } + + void DrawButtons(GameObject[] selectObjects, string infoLink, string assetPath, Action autoFix, bool hasGameObjects) + { + using (new EditorGUILayout.VerticalScope()) + { + var infoLinkSet = infoLink != null; + var autoFixSet = autoFix != null; + var assetPathSet = assetPath != null; + + if (infoLinkSet && GUILayout.Button("More Info", GUILayout.Width(ButtonWidth), GUILayout.Height(ButtonHeight))) + { + Application.OpenURL(infoLink); + } + + if (!infoLinkSet || assetPathSet || hasGameObjects) + { + using (new EditorGUI.DisabledScope(!assetPathSet && !hasGameObjects)) + { + if (assetPathSet) + { + if (GUILayout.Button("Ping Asset", GUILayout.Width(ButtonWidth), GUILayout.Height(ButtonHeight))) + { + EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(assetPath)); + } + } + else + { + if (GUILayout.Button("Select", GUILayout.Width(ButtonWidth), GUILayout.Height(ButtonHeight))) + { + if (selectObjects != null) + { + Selection.objects = selectObjects; + } + } + } + } + } + + if (!(infoLinkSet && (assetPathSet || hasGameObjects))) + { + using (new EditorGUI.DisabledScope(!autoFixSet)) + { + if (GUILayout.Button("Auto Fix", GUILayout.Width(ButtonWidth), GUILayout.Height(ButtonHeight))) + { + autoFix?.Invoke(); + + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + + autoRecheck = true; + recheck = true; + } + } + } + } + } + } + } + + [SerializeField] private int tab; + + [MenuItem("VRWorld Toolkit/World Debugger", false, 20)] + public static void ShowWindow() + { + var window = GetWindow(typeof(WorldDebugger)); + window.titleContent = new GUIContent("World Debugger"); + window.minSize = new Vector2(520, 600); + window.Show(); + } + + #region Actions + + public static Action SelectAsset(GameObject obj) + { + return () => { Selection.activeObject = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(obj)); }; + } + + public static Action SetGenerateLightmapUV(ModelImporter importer) + { + return () => + { + if (EditorUtility.DisplayDialog("Enable lightmap UV generation?", "This operation will enable the lightmap UV generation on the mesh \"" + Path.GetFileName(AssetDatabase.GetAssetPath(importer)) + "\".\n\nDo you want to continue?", "Yes", "Cancel")) + { + importer.generateSecondaryUV = true; + importer.SaveAndReimport(); + } + }; + } + + public static Action SetGenerateLightmapUV(List<ModelImporter> importers) + { + return () => + { + if (EditorUtility.DisplayDialog("Enable lightmap UV generation?", "This operation will enable the lightmap UV generation on " + importers.Count + " meshes.\n\nDo you want to continue?", "Yes", "Cancel")) + { + importers.ForEach(i => + { + i.generateSecondaryUV = true; + i.SaveAndReimport(); + }); + } + }; + } + + public static Action RemoveBadPipelineManagers(PipelineManager[] pipelineManagers) + { + return () => + { + foreach (var pipelineManager in pipelineManagers) + { + if (pipelineManager.gameObject.GetComponent<VRC_SceneDescriptor>()) + continue; + + DestroyImmediate(pipelineManager.gameObject.GetComponent<PipelineManager>()); + } + }; + } + + public static Action SetLegacyBlendShapeNormals(ModelImporter importer) + { + return () => + { + if (EditorUtility.DisplayDialog("Enable Legacy Blend Shape Normals?", "This operation will enable Legacy Blend Shape Normals on the model \"" + Path.GetFileName(AssetDatabase.GetAssetPath(importer)) + "\".\n\nDo you want to continue?", "Yes", "Cancel")) + { + ModelImporterUtil.SetLegacyBlendShapeNormals(importer, true); + importer.SaveAndReimport(); + } + }; + } + + public static Action SetLegacyBlendShapeNormals(ModelImporter[] importers) + { + return () => + { + if (EditorUtility.DisplayDialog("Enable Legacy Blend Shape Normals?", "This operation will enable Legacy Blend Shape Normals on " + importers.Length + " models. This can take some time, depending on the number of models and their size.\n\nDo you want to continue?", "Yes", "Cancel")) + { + for (var i = 0; i < importers.Length; i++) + { + ModelImporterUtil.SetLegacyBlendShapeNormals(importers[i], true); + importers[i].SaveAndReimport(); + } + } + }; + } + + public static Action DisableComponent(Behaviour behaviour) + { + return () => + { + if (EditorUtility.DisplayDialog("Disable component?", "This operation will disable the " + behaviour.GetType() + " on the GameObject \"" + behaviour.gameObject.name + "\".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(behaviour, "Disable Component"); + behaviour.enabled = false; + PrefabUtility.RecordPrefabInstancePropertyModifications(behaviour); + } + }; + } + + public static Action DisableComponent(Behaviour[] behaviours) + { + return () => + { + if (EditorUtility.DisplayDialog("Disable component?", "This operation will disable the " + behaviours[0].GetType() + " component on " + behaviours.Count().ToString() + " GameObjects.\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(behaviours.ToArray<Object>(), "Mass Disable Components"); + + for (var i = 0; i < behaviours.Length; i++) + { + var b = behaviours.ToList()[i]; + b.enabled = false; + PrefabUtility.RecordPrefabInstancePropertyModifications(b); + } + } + }; + } + + public static Action SetObjectLayer(GameObject obj, string layer) + { + return () => + { + if (EditorUtility.DisplayDialog("Change layer?", "This operation will change the layer of " + obj.name + " to " + layer + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(obj, "Layer Change"); + obj.layer = LayerMask.NameToLayer(layer); + PrefabUtility.RecordPrefabInstancePropertyModifications(obj); + } + }; + } + + public static Action SetObjectLayer(GameObject[] objs, string layer) + { + return () => + { + if (EditorUtility.DisplayDialog("Change layer?", "This operation will change " + objs.Length + " GameObjects layer to " + layer + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(objs.ToArray<Object>(), "Mass Layer Change"); + + for (var index = 0; index < objs.ToList().Count; index++) + { + var o = objs.ToList()[index]; + o.layer = LayerMask.NameToLayer(layer); + PrefabUtility.RecordPrefabInstancePropertyModifications(o); + } + } + }; + } + + public static Action SetSelectableNavigationMode(Selectable selectable, Navigation.Mode mode) + { + return () => + { + if (EditorUtility.DisplayDialog("Change Navigation mode?", "This operation will change the Navigation mode on UI Element \"" + selectable.gameObject.name + "\" to " + mode.ToString() + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(selectable, "Navigation Mode Change"); + + var navigation = selectable.navigation; + + navigation.mode = Navigation.Mode.None; + + selectable.navigation = navigation; + + PrefabUtility.RecordPrefabInstancePropertyModifications(selectable); + } + }; + } + + public static Action SetSelectableNavigationMode(Selectable[] selectables, Navigation.Mode mode) + { + return () => + { + if (EditorUtility.DisplayDialog("Change Navigation mode?", "This operation will change " + selectables.Length + " UI Elements Navigation to " + mode.ToString() + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(selectables.ToArray<Object>(), "Mass Navigation Mode Change"); + + for (var i = 0; i < selectables.Length; i++) + { + var navigation = selectables[i].navigation; + + navigation.mode = Navigation.Mode.None; + + selectables[i].navigation = navigation; + + PrefabUtility.RecordPrefabInstancePropertyModifications(selectables[i]); + } + } + }; + } + + public static Action SetLightmapSize(int newSize) + { + return () => + { + if (EditorUtility.DisplayDialog("Change lightmap size?", "This operation will change your lightmap size from " + LightmapEditorSettings.maxAtlasSize + " to " + newSize + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + LightmapEditorSettings.maxAtlasSize = newSize; + } + }; + } + + public static Action SetLightmapOverrideForQuest(TextureImporter[] textureImporters) + { + return () => + { + if (EditorUtility.DisplayDialog("Set lightmap compression override?", "This operation will set the platform-specific overrides for all lightmaps (" + textureImporters.Length + ") to ATCS 4x4 block format on Android.\n\nWarning this can take a while depending on lightmap size and how many there are.\n\nDo you want to continue?", "Yes", "Cancel")) + { + foreach (var item in textureImporters) + { + var settings = item.GetPlatformTextureSettings("Android"); + + settings.overridden = true; + + settings.format = TextureImporterFormat.ASTC_RGB_4x4; + + item.SetPlatformTextureSettings(settings); + + item.SaveAndReimport(); + } + } + }; + } + + public static Action SetLightmapOverrideForQuest(TextureImporter textureImporter, string lightmapName) + { + return () => + { + if (EditorUtility.DisplayDialog("Set lightmap compression override?", "This operation will set the platform-specific overrides for \"" + lightmapName + "\" to ATCS 4x4 block format on Android.\n\nWarning this can take a while depending on lightmap size.\n\nDo you want to continue?", "Yes", "Cancel")) + { + var settings = textureImporter.GetPlatformTextureSettings("Android"); + + settings.overridden = true; + + settings.format = TextureImporterFormat.ASTC_RGB_4x4; + + textureImporter.SetPlatformTextureSettings(settings); + + textureImporter.SaveAndReimport(); + } + }; + } + + public static Action SetEnviromentReflections(DefaultReflectionMode reflections) + { + return () => { RenderSettings.defaultReflectionMode = reflections; }; + } + + public static Action SetAmbientMode(AmbientMode ambientMode) + { + return () => { RenderSettings.ambientMode = ambientMode; }; + } + + public static Action SetGameObjectTag(GameObject obj, string tag) + { + return () => + { + if (EditorUtility.DisplayDialog("Change tag?", "This operation will change the tag of " + obj.name + " to " + tag + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(obj, "Change Tag"); + obj.tag = tag; + PrefabUtility.RecordPrefabInstancePropertyModifications(obj); + } + }; + } + + public static Action SetGameObjectTag(GameObject[] objs, string tag) + { + return () => + { + if (EditorUtility.DisplayDialog("Change tag?", "This operation will change " + objs.Length + " GameObjects tag to " + tag + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + Undo.RegisterCompleteObjectUndo(objs.ToArray<Object>(), "Mass Change Tag"); + + for (var i = 0; i < objs.ToList().Count; i++) + { + var o = objs.ToList()[i]; + o.tag = tag; + PrefabUtility.RecordPrefabInstancePropertyModifications(o); + } + } + }; + } + + public static Action ChangeShader(Material material, string shader) + { + return () => + { + if (EditorUtility.DisplayDialog("Change shader?", "This operation will change the shader of the material " + material.name + " to " + shader + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + var standard = Shader.Find(shader); + Undo.RegisterCompleteObjectUndo(material, "Changed Shader"); + material.shader = standard; + } + }; + } + + public static Action ChangeShader(Material[] materials, string shader) + { + return () => + { + if (EditorUtility.DisplayDialog("Change shader?", "This operation will change the shader of " + materials.Length + " materials to " + shader + ".\n\nDo you want to continue?", "Yes", "Cancel")) + { + var newShader = Shader.Find(shader); + Undo.RegisterCompleteObjectUndo(materials.ToArray<Object>(), "Changed Shaders"); + materials.ToList().ForEach(m => m.shader = newShader); + } + }; + } + + public static Action RemoveOverlappingLightProbes(LightProbeGroup lightProbeGroup) + { + return () => + { + Undo.RegisterCompleteObjectUndo(lightProbeGroup, "Removed Overlapping Light Probes"); + if (EditorUtility.DisplayDialog("Remove overlapping light probes?", "This operation will remove any overlapping light probes in the group \"" + lightProbeGroup.gameObject.name + "\".\n\nDo you want to continue?", "Yes", "Cancel")) + { + lightProbeGroup.probePositions = lightProbeGroup.probePositions.Distinct().ToArray(); + PrefabUtility.RecordPrefabInstancePropertyModifications(lightProbeGroup); + } + }; + } + + public static Action RemoveOverlappingLightProbes(LightProbeGroup[] lightProbeGroups) + { + return () => + { + Undo.RegisterCompleteObjectUndo(lightProbeGroups, "Removed Overlapping Light Probes"); + if (EditorUtility.DisplayDialog("Remove overlapping light probes?", "This operation will remove any overlapping light probes found in the current scene.\n\nDo you want to continue?", "Yes", "Cancel")) + { + foreach (var lpg in lightProbeGroups) + { + lpg.probePositions = lpg.probePositions.Distinct().ToArray(); + PrefabUtility.RecordPrefabInstancePropertyModifications(lpg); + } + } + }; + } + + public static Action RemoveRedundantLightProbes(LightProbeGroup[] lightProbeGroups) + { + return () => + { + if (LightmapSettings.lightProbes != null) + { + var probes = LightmapSettings.lightProbes.positions; + if (EditorUtility.DisplayDialog("Remove redundant light probes?", "This operation will attempt to remove any redundant light probes in the current scene. Bake your lighting before this operation to avoid any correct light probes getting removed.\n\nDo you want to continue?", "Yes", "Cancel")) + { + foreach (var lpg in lightProbeGroups) + { + lpg.probePositions = lpg.probePositions.Distinct().Where(p => !probes.Contains(p)).ToArray(); + } + } + } + else + { + EditorUtility.DisplayDialog("Baked light probes not found!", "Bake your lighting first before attempting to remove redundant light probes.", "Ok"); + } + }; + } + + public static Action ClearOcclusionCache(long fileCount) + { + return async () => + { + if (EditorUtility.DisplayDialog("Clear Occlusion Cache?", "This will clear your occlusion culling cache. Which has " + fileCount + " files currently. Deleting a massive amount of files can take a while.\n\nDo you want to continue?", "Yes", "Cancel")) + { + long deleteCount = 0; + + var tokenSource = new CancellationTokenSource(); + + var deleteFiles = new Progress<string>(fileName => + { + deleteCount++; + if (EditorUtility.DisplayCancelableProgressBar("Clearing Occlusion Cache", fileName, (float) deleteCount / fileCount)) + { + tokenSource.Cancel(); + } + }); + + var token = tokenSource.Token; + + await Task.Run(() => DeleteFiles(deleteFiles, token), token); + EditorUtility.ClearProgressBar(); + + occlusionCacheFiles = 0; + EditorUtility.DisplayDialog("Files Deleted", "Deleted " + deleteCount + " files.", "Ok"); + } + }; + } + + public static void DeleteFiles(IProgress<string> deleted, CancellationToken cancellationToken) + { + Parallel.ForEach(Directory.EnumerateFiles("Library/Occlusion/"), (file, state) => + { + if (cancellationToken.IsCancellationRequested) + { + state.Break(); + } + + File.Delete(file); + deleted.Report(file); + }); + } + + public static Action FixSpawns(VRC_SceneDescriptor descriptor) + { + return () => + { + Undo.RegisterCompleteObjectUndo(descriptor, "Spawn Points Fixed"); + if (descriptor.spawns is null || descriptor.spawns.Length == 0) + { + descriptor.spawns = new[] {descriptor.gameObject.transform}; + } + + descriptor.spawns = descriptor.spawns.Where(c => c != null).ToArray(); + + PrefabUtility.RecordPrefabInstancePropertyModifications(descriptor); + }; + } + + public static Action ChangeRespawnHeight(VRC_SceneDescriptor descriptor, float newHeight) + { + return () => + { + Undo.RegisterCompleteObjectUndo(descriptor, "Respawn Height Change"); + + descriptor.RespawnHeightY = newHeight; + + PrefabUtility.RecordPrefabInstancePropertyModifications(descriptor); + }; + } + + public static Action SetBuildTarget(BuildTargetGroup group, BuildTarget target) + { + return () => + { + EditorUserBuildSettings.selectedBuildTargetGroup = group; + EditorUserBuildSettings.selectedStandaloneTarget = target; + EditorUserBuildSettings.SwitchActiveBuildTargetAsync(group, target); + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + }; + } + + public static Action FixVRCProjectSettings(VRCProjectSettings settings) + { + return () => + { + // TODO: Cleaner solution to storing these + var newLayers = new[] {"Default", "TransparentFX", "Ignore Raycast", "", "Water", "UI", "", "", "Interactive", "Player", "PlayerLocal", "Environment", "UiMenu", "Pickup", "PickupNoEnvironment", "StereoLeft", "StereoRight", "Walkthrough", "MirrorReflection", "reserved2", "reserved3", "reserved4"}; + + var newCollisionArr = new[] + { + true, true, true, true, true, false, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, false, false, true, false, false, false, false, false, false, true, + true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, false, false, true, false, false, false, false, false, false, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, false, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, false, true, true, true, false, + false, true, false, true, true, true, true, true, false, false, false, false, true, true, true, true, true, true, true, true, true, true, false, false, false, true, false, false, true, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, + false, true, true, true, false, false, true, false, true, false, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, true, true, true, true, true, false, true, true, true, false, false, true, false, true, false, true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, + false, true, true, true, true, true, false, true, true, true, false, false, true, false, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, false, false, true, true, true, true, true, true, true, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, false, false, true, false, true, true, false, false, true, true, true, true, true, false, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, + true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, + false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true, false, true, true, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true + }; + + var so = new SerializedObject(settings); + + var layersSerializedProperty = so.FindProperty("layers"); + + layersSerializedProperty.arraySize = newLayers.Length; + for (var i = 0; i < newLayers.Length; i++) + { + layersSerializedProperty.GetArrayElementAtIndex(i).stringValue = newLayers[i]; + } + + so.FindProperty("numLayers").intValue = 22; + + var collisionArr = so.FindProperty("layerCollisionArr"); + + collisionArr.arraySize = newCollisionArr.Length; + for (var i = 0; i < newCollisionArr.Length; i++) + { + collisionArr.GetArrayElementAtIndex(i).boolValue = newCollisionArr[i]; + } + + so.ApplyModifiedProperties(); + + var systemType = Assembly.Load("VRCCore-Editor").GetType("UpdateLayers"); + var setupLayersToSet = systemType.GetMethod("SetupLayersToSet", BindingFlags.Static | BindingFlags.NonPublic); + Assert.IsNotNull(setupLayersToSet); + setupLayersToSet.Invoke(null, null); + }; + } + + public static Action SetErrorPause(bool enabled) + { + return () => { ConsoleFlagUtil.SetConsoleErrorPause(enabled); }; + } + + public static Action SetVRChatLayers() + { + return UpdateLayers.SetupEditorLayers; + } + + public static Action SetVRChatCollisionMatrix() + { + return UpdateLayers.SetupCollisionLayerMatrix; + } + + public static Action SetFutureProofPublish(bool state) + { + return () => { EditorPrefs.SetBool("futureProofPublish", state); }; + } + + public static Action SetReferenceCamera(VRC_SceneDescriptor descriptor, Camera camera) + { + return () => + { + Undo.RegisterCompleteObjectUndo(descriptor, "Reference Camera Set"); + descriptor.ReferenceCamera = camera.gameObject; + PrefabUtility.RecordPrefabInstancePropertyModifications(descriptor); + }; + } + + public static Action SetVRCInstallPath() + { + return () => + { + var clientPath = Helper.GetSteamVrcExecutablePath(); + + if (clientPath != null) + { + SDKClientUtilities.SetVRCInstallPath(clientPath); + } + else if (EditorUtility.DisplayDialog("VRChat Executable Path Not Found", "Could not find the VRChat executable path automatically.\n\nPress Ok to locate it manually.", "Ok", "Cancel")) + { + var newPath = EditorUtility.OpenFilePanel("Locate VRChat.exe", Application.dataPath, "exe"); + SDKClientUtilities.SetVRCInstallPath(newPath); + } + }; + } + +#if UNITY_POST_PROCESSING_STACK_V2 + public enum RemovePpEffect + { + AmbientOcclusion = 0, + ScreenSpaceReflections = 1, + BloomDirt = 2 + } + + public static Action DisablePostProcessEffect(PostProcessProfile postprocessProfile, RemovePpEffect effect) + { + return () => + { + switch (effect) + { + case RemovePpEffect.AmbientOcclusion: + postprocessProfile.GetSetting<AmbientOcclusion>().active = false; + break; + case RemovePpEffect.ScreenSpaceReflections: + postprocessProfile.GetSetting<ScreenSpaceReflections>().active = false; + break; + case RemovePpEffect.BloomDirt: + postprocessProfile.GetSetting<Bloom>().dirtTexture.overrideState = false; + postprocessProfile.GetSetting<Bloom>().dirtIntensity.overrideState = false; + break; + } + }; + } + + public static Action SetPostProcessingInScene(SceneView.SceneViewState sceneViewState, bool isActive) + { + return () => { sceneViewState.showImageEffects = isActive; }; + } + + public static Action SetPostProcessingLayerResources(PostProcessLayer postProcessLayer, PostProcessResources resources) + { + return () => { postProcessLayer.Init(resources); }; + } +#endif + + #endregion + + #region Texts + + private const string NoSceneDescriptor = "The current scene has no Scene Descriptor. Please add one, or drag the VRCWorld prefab to the scene."; + + private const string TooManySceneDescriptors = "Multiple Scene Descriptors were found. Only one scene descriptor can exist in a single scene."; + + private const string TooManyPipelineManagers = "The current scene has multiple Pipeline Managers in it. This can break the world upload process and prevent you from being able to load into the world."; + + private const string WorldDescriptorFar = "Scene Descriptor is {0} units far from the zero point in Unity. Having your world center out this far will cause some noticeable jittering on models. You should move your world closer to the zero point of your scene."; + + private const string WorldDescriptorOff = "Scene Descriptor is {0} units far from the zero point in Unity. It is usually good practice if possible to keep it as close as possible to the absolute zero point to avoid floating-point errors."; + + private const string WronglySetBuildSettings = "Wrongly set build settings detected for current editor runtime. This can cause builds to not go through properly."; + + private const string ImproperlySetupVRCProjectSettings = "Improperly setup VRCProjectSettings detected. This will cause the Control Panel Builder tab to appear empty."; + + private const string VRCProjectSettingsMissing = "VRCProjectSettings not found. The SDK needs it, and missing it will cause the SDK to error out. To fix the problem, reimport the SDK."; + + private const string LastBuildFailed = "Last build failed! Check the Console for compile errors to find the cause. If the error script is in the SDK, try reimporting it. Otherwise, remove or update the problem asset."; + + private const string NoSpawnPointSet = "There are no spawn points set in your Scene Descriptor. Spawning into a world with no spawn point will cause you to get thrown back to your homeworld."; + + private const string NullSpawnPoint = "Null spawn point set Scene Descriptor. Spawning into a null spawn point will cause you to get thrown back to your homeworld."; + + private const string ReferenceCameraClearFlagsNotSkybox = "The current reference camera's clear flags are not set to Skybox. This can cause rendering problems in-game."; + + private const string ReferenceCameraClippingPlaneRatio = "Too high of a ratio between reference camera's near ({0}) and far ({1}) clip values can cause rendering issues in-game."; + + private const string ReferenceCameraNearClipPlaneOver = "The current reference camera's near clip value is {0}. This value gets clamped to be between 0.01 and 0.05."; + + private const string NoReferenceCameraSetGeneral = "No reference camera set in the Scene Descriptor. Using a reference camera allows the world's rendering distance to be changed by changing the camera's near and far clipping planes."; + + private const string ReferenceCameraHasNoCameraComponent = "The GameObject \"{0}\" currently set in the Scene Descriptor as a reference camera does not have a camera component. This can cause various problems in-game."; + + private const string ColliderUnderSpawnIsTrigger = "The collider \"{0}\" under your spawn point {1} has been set as Is Trigger."; + private const string ColliderUnderSpawnIsTriggerCombined = "Found \"{0}\" spawn points which have a collider set as Is Trigger underneath."; + private const string ColliderUnderSpawnIsTriggerInfo = "Spawning into a world with nothing to stand on will cause the players to fall forever."; + + private const string SpawnUnderRespawnHeight = "Spawn point \"{0}\" is placed {1} units under the Respawn Height set in Scene Descriptor."; + private const string SpawnUnderRespawnHeightCombined = "Found {0} spawn points under Respawn Height set in Scene Descriptor."; + private const string SpawnUnderRespawnHeightInfo = "Spawning under the Respawn Height causes players to get stuck while respawning infinitely."; + + private const string NoColliderUnderSpawn = "Spawn point \"{0}\" does not have a collider under it."; + private const string NoColliderUnderSpawnCombined = "Found {0} spawn points with no collider under them."; + private const string NoColliderUnderSpawnInfo = "Spawning into a world with nothing to stand on will cause the players to fall forever."; + + private const string RespawnHeightAboveCollider = "The collider below spawn point \"{1}\" is below respawn height set in scene descriptor."; + private const string RespawnHeightAboveColliderCombined = "Found {0} spawn points where the collider is below the respawn height."; + private const string RespawnHeightAboveColliderInfo = "This will cause players to get stuck while respawning infinitely."; + + private const string NoPlayerMods = "No Player Mods were found in the scene. Player mods are needed for adding jumping and changing walking speed."; + + private const string TriggerTriggerNoCollider = "You have an OnEnterTrigger or OnExitTrigger Trigger \"{0}\" that does not have a Collider on it."; + private const string ColliderTriggerNoCollider = "You have an OnEnterCollider or OnExitCollider Trigger \"{0}\" that does not have a Collider on it."; + + private const string TriggerTriggerWrongLayer = "You have an OnEnterTrigger or OnExitTrigger Trigger \"{0}\" that is not on the MirrorReflection layer."; + private const string TriggerTriggerWrongLayerCombined = "You have {0} OnEnterTrigger or OnExitTrigger Triggers that are not on the MirrorReflection layer."; + private const string TriggerTriggerWrongLayerInfo = "This can stop raycasts from working correctly, making you unable to interact with objects and UI Buttons."; + + private const string MirrorONByDefault = "The mirror \"{0}\" is on by default."; + private const string MirrorONByDefaultCombined = "The scene has {0} mirrors on by default."; + private const string MirrorONByDefaultInfo = "This is an awful practice. Any mirrors in worlds should be disabled by default."; + + private const string MirrorWithDefaultLayers = "The mirror \"{0}\" has the default Reflect Layers set."; + private const string MirrorWithDefaultLayersCombined = "You have {0} mirrors that have the default Reflect Layers set."; + private const string MirrorWithDefaultLayersInfo = "Only having the layers needed to have enabled in mirrors can save a lot of frames, especially in populated instances."; + + private const string LegacyBlendShapeIssues = "Skinned mesh renderer found with model {0} ({1}) without Legacy Blend Shape Normals enabled."; + private const string LegacyBlendShapeIssuesCombined = "Found {0} models without Legacy Blend Shape Normals enabled."; + private const string LegacyBlendShapeIssuesInfo = "This can significantly increase the size of the world."; + + private const string BakedOcclusionCulling = "Baked Occlusion Culling found."; + + private const string NoOcclusionAreas = "No occlusion areas were found. Occlusion Areas are recommended to help generate higher precision data where the camera is likely to be. If none exist, an area is created automatically containing all Occluders and Occludees."; + + private const string DisabledOcclusionArea = "Occlusion Area {0} found with Is View Volume disabled."; + private const string DisabledOcclusionAreaCombined = "Occlusion Areas found with Is View Volume disabled."; + private const string DisabledOcclusionAreaInfo = "Without this enabled, the Occlusion Area does not get used for the occlusion bake."; + + private const string NoOcclusionCulling = "The current scene does not have baked Occlusion Culling. Occlusion culling often gives a large performance boost, especially in larger worlds with multiple rooms or areas."; + + private const string OcclusionCullingCacheWarning = "The current project's occlusion culling cache has {0} files. When the occlusion culling cache grows too big, baking occlusion culling can take much longer than intended. It can be cleared with no adverse effects."; + + private const string ActiveCameraOutputtingToRenderTexture = "Active camera \"{0}\" outputting to a render texture."; + private const string ActiveCameraOutputtingToRenderTextureCombined = "The current scene has {0} active cameras outputting to render textures."; + private const string ActiveCameraOutputtingToRenderTextureInfo = "This will affect performance negatively by causing more draw calls to happen. They should only be enabled when needed."; + + private const string ActiveCameraWithOverZeroDepth = "Active camera \"{0}\" targeting display 1 with render depth over 0."; + private const string ActiveCameraWithOverZeroDepthCombined = "The current scene has {0} active cameras targeting display 1 with render depth over 0."; + private const string ActiveCameraWithOverZeroDepthInfo = "This will cause it to render over the upload screen, not allowing you to upload."; + + private const string NoToonShaders = "Toon shaders should be avoided for world-building, as they are missing crucial things for making worlds. For world-building, the most recommended shader is Standard."; + + private const string NonCrunchedTextures = "{0}% of the textures used in the scene have not been crunch compressed. Crunch compression can significantly reduce the size of the world download. It can be found from the texture's import settings."; + + private const string SingleColorEnvironmentLighting = "Consider changing the Environment Lighting Source from Color to Gradient for better ambient lighting."; + + private const string DarkEnvironmentLighting = "Using dark colors for Environment Lighting can cause avatars to look weird. Only use dark Environment Lighting if the world has dark lighting."; + + private const string CustomEnvironmentReflectionsNull = "The current scenes Environment Reflections have been set to custom, but a custom cubemap has not been defined."; + + private const string NoLightmapUV = "The model found in the scene \"{0}\" is set to be lightmapped, but does not have Lightmap UVs."; + private const string NoLightmapUVCombined = "The current scene has {0} models set to be lightmapped that do not have Lightmap UVs."; + private const string NoLightmapUVInfo = "This can cause issues when baking lighting if the main UV is not suitable for lightmapping. You can enable generating Lightmap UVs in the model's import settings."; + + private const string LightsNotBaked = "The current scene is using realtime lighting. Consider baked lighting for improved performance."; + + private const string ConsiderLargerLightmaps = "Possibly unoptimized lighting setup detected with a high amount of separate lightmaps compared to the currently set Lightmap Size.\nConsider increasing Lightmap Size from {0} to 2048 or larger and adjusting the individual Scale In Lightmap value on mesh renderers to fit things on a smaller amount of lightmaps."; + + private const string ConsiderSmallerLightmaps = "Baking lightmaps at 4096 with Progressive GPU will silently fall back to CPU Progressive. More than 12GB GPU Memory is needed to bake 4k lightmaps with GPU Progressive."; + + private const string NonBakedBakedLight = "The light {0} is set to be baked/mixed, but it has not been baked yet!"; + private const string NonBakedBakedLightCombined = "The scene contains {0} baked/mixed lights that have not been baked!"; + private const string NonBakedBakedLightInfo = "Baked lights that have not been baked yet function as realtime lights in-game."; + + private const string LightingDataAssetInfo = "The current scene's lighting data asset takes up {0} MB of the world's size. This contains the scene's light probe data and realtime GI data."; + + private const string NoLightProbes = "No light probes found in the current scene. Without light probes, baked lights are not able to affect dynamic objects such as players and pickups."; + + private const string LightProbeCountNotBaked = "The current scene contains {0} light probes, but {1} of them have not been baked yet."; + + private const string LightProbesRemovedNotReBaked = "Some light probes have been removed after the last bake. Bake them again to update the scene's lighting data. The lighting data contains {0} baked light probes, and the current scene has {1} light probes."; + + private const string LightProbeCount = "The current scene contains {0} baked light probes."; + + private const string OverlappingLightProbes = "Light Probe Group \"{0}\" has {1} overlapping light probes."; + private const string OverlappingLightProbesCombined = "Found {0} Light Probe Groups with overlapping light probes."; + private const string OverlappingLightProbesInfo = "These can cause a slowdown in the editor and will not get baked because Unity will skip any extra overlapping probes."; + + private const string NoReflectionProbes = "The current scene has no active reflection probes. Reflection probes are needed to have proper reflections on reflective materials."; + + private const string ReflectionProbesSomeUnbaked = "The reflection probe \"{0}\" is unbaked."; + private const string ReflectionProbesSomeUnbakedCombined = "The current scene has {0} unbaked reflection probes."; + + private const string ReflectionProbeCountText = "The current scene has {0} reflection probes."; + + private const string PostProcessingImportedButNotSetup = "The current project has Post Processing imported, but you have not set it up yet."; + + private const string PostProcessingDisabledInSceneView = "Post-processing is disabled in the scene view. You will not be able to preview any post-processing effects without enabling it first."; + + private const string PostProcessingNoResourcesSet = "The Post Process Layer on \"{0}\" does not have its resources field set properly. This causes post-processing to error out. This can be fixed by recreating the Post Processing Layer on the GameObject."; + + private const string NoReferenceCameraSetPp = "The current scene's Scene Descriptor has no Reference Camera set. Without a Reference Camera set, post-processing will not be visible in-game."; + + private const string NoPostProcessingVolumes = "No enabled Post Processing Volumes found in the scene. A Post Processing Volume is needed to apply effects to the camera's Post Processing Layer."; + + private const string ReferenceCameraNoPostProcessingLayer = "The current Reference Camera does not have a Post Processing Layer on it. A Post Processing Layer is needed for the Post Processing Volume to affect the camera."; + + private const string PostProcessLayerUsingReservedLayer = "Your current Post Process Layer uses one of the VRChat reserved layers. Using these will break post-processing while in-game."; + + private const string VolumeBlendingLayerNotSet = "You don't have a Volume Blending Layer set in the Post Process Layer, so post-processing will not work. Using the Water or PostProcessing layer is recommended."; + + private const string PostProcessingVolumeNotGlobalNoCollider = "Post Processing Volume \"{0}\" is not marked as Global and does not have a collider."; + private const string PostProcessingVolumeNotGlobalNoColliderCombined = "Found {0} Post Processing Volumes that are not marked as Global and do not have a collider."; + private const string PostProcessingVolumeNotGlobalNoColliderInfo = "The volume will not affect the camera without one of these set on it."; + + private const string NoProfileSet = "Post Processing Volume \"{0}\" does not have a profile set."; + private const string NoProfileSetCombined = "Found {0} Post Processing Volumes with no profile set."; + + private const string NoMatchingLayersFound = "No enabled Post Processing Volumes found with matching layers to the main Post Processing Layer. Layers currently set to: {0}"; + + private const string TonemapperMissing = "No global Tonemapper found. When there is no Tonemapper set, the colors in the scene will be distorted. Ideally, use Neutral or ACES."; + + private const string TooHighBloomIntensity = "Do not raise the Bloom intensity too high! It is best to use a low Bloom intensity, between 0.01 to 0.3."; + + private const string TooHighBloomThreshold = "You should avoid having the Bloom Threshold be set to a high value, as it might cause unexpected problems with bright avatars. Ideally, it should be kept at 0, but always below 1.0."; + + private const string NoBloomDirtInVR = "Avoid using Bloom Dirt, it looks terrible in VR!"; + + private const string NoAmbientOcclusion = "Do not use Post Processing Ambient Occlusion in VRChat! VRChat uses Forward rendering, so it gets applied on top of EVERYTHING, which is bad! It also has a super high rendering cost in VR."; + + private const string DepthOfFieldWarning = "Depth of field has a high performance cost and is very disorienting in VR. If you want to use depth of field, it should be disabled by default."; + + private const string ScreenSpaceReflectionsWarning = "Screen-space Reflections only works when using deferred rendering. Because VRChat uses Forward rendering, this should not be used."; + + private const string VignetteWarning = "Only use Post Processing Vignette in small amounts. A powerful vignette can cause sickness in VR."; + + private const string NoPostProcessingImported = "Post Processing package not found in the project."; + + private const string QuestBakedLightingWarning = "Realtime lighting for Quest content should be avoided and instead have a properly baked lighting setup for optimal performance."; + + private const string AmbientModeSetToCustom = "The current scene's Environment Lighting setting is broken. This will override all light probes in the scene with black ambient light. Please change it to something else."; + + private const string NoProblemsFoundInPp = "No problems were found in your post-processing setup. In some cases where post-processing is working in the editor but not in-game, some imported assets may be causing it not to function correctly."; + + private const string BakeryLightNotSetEditorOnly = "Your Bakery light named \"{0}\" is not set to be EditorOnly."; + private const string BakeryLightNotSetEditorOnlyCombined = "You have {0} Bakery lights are not set to be EditorOnly."; + private const string BakeryLightNotSetEditorOnlyInfo = "This causes unnecessary errors in the output log loading into a world in VRChat because external scripts get removed in the upload process."; + + private const string BakeryLightUnityLight = "Your Bakery light named \"{0}\" has an active Unity Light component on it."; + private const string BakeryLightUnityLightCombined = "You have {0} Bakery lights that have an active Unity Light component on it."; + private const string BakeryLightUnityLightInfo = "These will not get baked with Bakery and will keep acting as realtime lights even if set to baked."; + + private const string QuestLightmapCompressionOverride = "Lightmap \"{0}\" does not have a platform-specific override set for Android."; + private const string QuestLightmapCompressionOverrideCombined = "No platform-specific override set on {0} lightmaps for Android."; + private const string QuestLightmapCompressionOverrideInfo = "Without setting a proper platform-specific override when building for Android, lightmaps can show noticeable banding. Suggested format \"ASTC 4x4 block\"."; + + private const string MissingShaderWarning = "The material \"{0}\" found in the scene has a missing or broken shader."; + private const string MissingShaderWarningCombined = "Found {0} materials in the current scene that have missing or broken shaders."; + private const string MissingShaderWarningInfo = "These will fallback to the pink error shader."; + + private const string ErrorPauseWarning = "You have Error Pause enabled in your console. This can cause your world upload to fail by interrupting the build process."; + + private const string MultipleScenesLoaded = "Multiple scenes loaded, this is not supported by VRChat and can cause the world upload to fail. Only one scene should be used for world creation at a time."; + + private const string LayersNotSetup = "Project layers are not set up for VRChat yet."; + + private const string CollisionMatrixNotSetup = "The project's Collision Matrix is not set up for VRChat yet."; + + private const string MaterialWithGrabPassShader = "A material ({0}) in the scene has an active GrabPass due to shader \"{1}\"."; + private const string MaterialWithGrabPassShaderCombined = "Found {0} materials in the scene using a GrabPass."; + private const string MaterialWithGrabPassShaderInfoPC = "A GrabPass will halt the rendering to copy the screen's contents into a texture for the shader to read. This has a notable effect on performance."; + private const string MaterialWithGrabPassShaderInfoQuest = "Please change the shader for this material. When a shader uses a GrabPass on Quest, it will cause painful visual artifacts to occur, as they are not supported."; + + private const string DisabledPortalsWarning = "Portal \"{0}\" disabled by default."; + private const string DisabledPortalsWarningCombined = "Found {0} portals disabled by default."; + private const string DisabledPortalsWarningInfo = "Having a portal disabled by default may cause players that are entering to end up in different instances."; + + private const string ShrnmDirectionalModeBakeryError = "SH or RNM directional mode detected in Bakery. Using SH directional mode is not supported in VRChat by default. It requires the usage of VRC Bakery Adapter by Merlin for it to function in-game."; + + private const string BuildANDTestBrokenError = "VRChat link association has not been set up, and the VRChat client path has not been set in the VRCSDK settings. Without one of these settings set, Build & Test will not function."; + + private const string BuildANDTestForceNonVRError = "VRChat client path has not been set to point directly to the VRChat executable in the VRCSDK settings. The Force Non-VR setting for Build & Test will not work."; + + private const string BuildANDTestNoExecutableFound = "Current client path set in the VRCSDK settings does not contain the VRChat executable. This will cause problems with Build & Test functionality."; + + private const string MaterialWithNonWhitelistedShader = "Material \"{0}\" is using an unsupported shader \"{1}\"."; + private const string MaterialWithNonWhitelistedShaderCombined = "Found {0} materials with unsupported shaders."; + private const string MaterialWithNonWhitelistedShaderInfo = "Unsupported shaders can cause problems on the Quest platform if not appropriately used."; + + private const string UIElementWithNavigationNotNone = "The UI Element \"{0}\" does not have its Navigation set to None."; + private const string UIElementWithNavigationNotNoneCombined = "Found {0} UI Elements with their Navigation not set to None."; + private const string UIElementWithNavigationNotNoneInfo = "Setting Navigation to None on UI Elements can stop accidental interactions with them while trying to walk around."; + + private const string NullTriggerReceiver = "Null receiver found on trigger {0}."; + private const string NullTriggerReceiverCombined = "Found {0} null receivers in scene triggers."; + private const string NullTriggerReceiverInfo = "This causes the trigger to target itself, which can sometimes be intentional."; + + private const string TextMeshLightmapStatic = "Text Mesh \"{0}\" marked as lightmap static."; + private const string TextMeshLightmapStaticCombined = "Found {0} Text Meshes marked as lightmap static."; + private const string TextMeshLightmapStaticInfo = "This will cause warnings as the mesh has no normals."; + + private const string UnsupportedCompressionFormatQuest = "Texture {0} using compression format {1} that is not supported on Quest."; + private const string UnsupportedCompressionFormatQuestCombined = "Found {0} textures with compression format not supported on Quest."; + private const string UnsupportedCompressionFormatQuestInfo = "These will appear fine in editor but black in game."; + + private const string HeyYouFoundABug = "Hey, you found a bug! Please send it my way so I can fix it! Check About VRWorld Toolkit to find all the ways to contact me. \"{0}\" on line {1}."; + + private const string FutureProofPublishEnabled = "Future Proof Publish is currently enabled. This is a legacy feature that has no planned functions as of right now. Having it enabled will increase upload times and sometimes cause uploading to fail."; + + #endregion + + private static long occlusionCacheFiles; + + // TODO: Better check threading + private void CountOcclusionCacheFiles() + { + occlusionCacheFiles = Directory.EnumerateFiles("Library/Occlusion/").Count(); + + OcclusionMessageCheck(); + } + + private void OcclusionMessageCheck() + { + if (occlusionCacheFiles > 0) + { + // Set the message type depending on how many files found + var cacheWarningType = MessageType.Info; + if (occlusionCacheFiles > 50000) + { + cacheWarningType = MessageType.Error; + } + else if (occlusionCacheFiles > 5000) + { + cacheWarningType = MessageType.Warning; + } + + optimization.AddMessageGroup(new MessageGroup(OcclusionCullingCacheWarning, cacheWarningType).AddSingleMessage(new SingleMessage(occlusionCacheFiles.ToString()).SetAutoFix(ClearOcclusionCache(occlusionCacheFiles)))); + } + } + + private class CheckedShaderProperties + { + public bool IncludesGrabPass = false; + public readonly List<string> GrabPassLightModeTags = new List<string>(); + } + + private void CheckScene() + { + masterList.ClearCategories(); + + try + { + // Cache repeatedly used values + var androidBuildPlatform = Helper.BuildPlatform() == RuntimePlatform.Android; + + // Get Descriptors + var descriptors = FindObjectsOfType(typeof(VRC_SceneDescriptor)) as VRC_SceneDescriptor[]; + var pipelines = FindObjectsOfType(typeof(PipelineManager)) as PipelineManager[]; + + // Check if a descriptor exists + if (descriptors.Length == 0) + { + general.AddMessageGroup(new MessageGroup(NoSceneDescriptor, MessageType.Error)); + return; + } + + var sceneDescriptor = descriptors[0]; + + // General Checks + + // Make sure only one descriptor exists + if (descriptors.Length > 1) + { + general.AddMessageGroup(new MessageGroup(TooManySceneDescriptors, MessageType.Info).AddSingleMessage(new SingleMessage(Array.ConvertAll(descriptors, s => s.gameObject)))); + return; + } + + // Check for multiple pipeline managers + if (pipelines.Length > 1) + { + general.AddMessageGroup(new MessageGroup(TooManyPipelineManagers, MessageType.Error).AddSingleMessage(new SingleMessage(Array.ConvertAll(pipelines, s => s.gameObject)).SetAutoFix(RemoveBadPipelineManagers(pipelines)))); + } + + // Check how far the descriptor is from zero point for floating point errors + var descriptorRemoteness = (int) Vector3.Distance(sceneDescriptor.transform.position, new Vector3(0.0f, 0.0f, 0.0f)); + + if (descriptorRemoteness > 1500) + { + general.AddMessageGroup(new MessageGroup(WorldDescriptorFar, MessageType.Error).AddSingleMessage(new SingleMessage(descriptorRemoteness.ToString()).SetSelectObject(Array.ConvertAll(descriptors, s => s.gameObject)))); + } + else if (descriptorRemoteness > 500) + { + general.AddMessageGroup(new MessageGroup(WorldDescriptorOff, MessageType.Tips).AddSingleMessage(new SingleMessage(descriptorRemoteness.ToString()).SetSelectObject(Array.ConvertAll(descriptors, s => s.gameObject)))); + } + + switch (Helper.BuildPlatform()) + { + case RuntimePlatform.WindowsPlayer: + if (EditorUserBuildSettings.selectedBuildTargetGroup != BuildTargetGroup.Standalone || + EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.StandaloneWindows64) + { + general.AddMessageGroup(new MessageGroup(WronglySetBuildSettings, MessageType.Error)).SetGroupAutoFix(SetBuildTarget(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64)); + } + + break; + case RuntimePlatform.Android: + if (EditorUserBuildSettings.selectedBuildTargetGroup != BuildTargetGroup.Android || + EditorUserBuildSettings.selectedStandaloneTarget != BuildTarget.Android) + { + general.AddMessageGroup(new MessageGroup(WronglySetBuildSettings, MessageType.Error)).SetGroupAutoFix(SetBuildTarget(BuildTargetGroup.Android, BuildTarget.Android)); + } + + break; + } + + var vrcProjectSettings = Resources.Load<VRCProjectSettings>("VRCProjectSettings"); + if (vrcProjectSettings) + { + if (vrcProjectSettings.layers is null || vrcProjectSettings.layers.Length == 0 || vrcProjectSettings.layerCollisionArr is null || vrcProjectSettings.layerCollisionArr.Length == 0) + { + general.AddMessageGroup(new MessageGroup(ImproperlySetupVRCProjectSettings, MessageType.Error).SetGroupAutoFix(FixVRCProjectSettings(vrcProjectSettings))); + } + else + { + if (!UpdateLayers.AreLayersSetup()) + { + general.AddMessageGroup(new MessageGroup(LayersNotSetup, MessageType.Error).SetGroupAutoFix(SetVRChatLayers())); + } + + if (!UpdateLayers.IsCollisionLayerMatrixSetup()) + { + general.AddMessageGroup(new MessageGroup(CollisionMatrixNotSetup, MessageType.Error).SetGroupAutoFix(SetVRChatCollisionMatrix())); + } + } + } + else + { + general.AddMessageGroup(new MessageGroup(VRCProjectSettingsMissing, MessageType.Error).SetDocumentation("https://docs.vrchat.com/docs/updating-the-sdk")); + } + + if (buildReportWindows != null && buildReportWindows.summary.result == BuildResult.Failed || buildReportQuest != null && buildReportQuest.summary.result == BuildResult.Failed) + { + general.AddMessageGroup(new MessageGroup(LastBuildFailed, MessageType.Error).SetDocumentation("https://github.com/oneVR/VRWorldToolkit/wiki/Fixing-Build-Problems")); + } + + // Check if multiple scenes loaded + if (SceneManager.sceneCount > 1) + { + general.AddMessageGroup(new MessageGroup(MultipleScenesLoaded, MessageType.Error)); + } + + if (EditorPrefs.GetBool("futureProofPublish", true)) + { + general.AddMessageGroup(new MessageGroup(FutureProofPublishEnabled, MessageType.Error).SetGroupAutoFix(SetFutureProofPublish(false))); + } + + // Check if console has error pause on + if (ConsoleFlagUtil.GetConsoleErrorPause()) + { + general.AddMessageGroup(new MessageGroup(ErrorPauseWarning, MessageType.Error).AddSingleMessage(new SingleMessage(SetErrorPause(false)))); + } + + // Check reference camera for possible problems + if (sceneDescriptor.ReferenceCamera != null) + { + var camera = sceneDescriptor.ReferenceCamera.GetComponent<Camera>(); + if (camera != null) + { + if (camera.clearFlags != CameraClearFlags.Skybox) + { + general.AddMessageGroup(new MessageGroup(ReferenceCameraClearFlagsNotSkybox, MessageType.Warning).AddSingleMessage(new SingleMessage(sceneDescriptor.ReferenceCamera))); + } + + // TODO: Investigate better sanity value + if (camera.farClipPlane / camera.nearClipPlane > 200000f) + { + general.AddMessageGroup(new MessageGroup(ReferenceCameraClippingPlaneRatio, MessageType.Warning).AddSingleMessage(new SingleMessage(camera.nearClipPlane.ToString(CultureInfo.InvariantCulture), camera.farClipPlane.ToString(CultureInfo.InvariantCulture)).SetSelectObject(camera.gameObject))); + } + + if (camera.nearClipPlane > 0.05f) + { + general.AddMessageGroup(new MessageGroup(ReferenceCameraNearClipPlaneOver, MessageType.Tips).AddSingleMessage(new SingleMessage(camera.nearClipPlane.ToString(CultureInfo.InvariantCulture)).SetSelectObject(camera.gameObject))); + } + } + else + { + general.AddMessageGroup(new MessageGroup(ReferenceCameraHasNoCameraComponent, MessageType.Error)).AddSingleMessage(new SingleMessage(sceneDescriptor.ReferenceCamera.name).SetSelectObject(sceneDescriptor.ReferenceCamera).SetAutoFix(() => + { + sceneDescriptor.ReferenceCamera = null; + PrefabUtility.RecordPrefabInstancePropertyModifications(sceneDescriptor.gameObject); + })); + } + } + else + { + general.AddMessageGroup(new MessageGroup(NoReferenceCameraSetGeneral, MessageType.Tips).AddSingleMessage(new SingleMessage(sceneDescriptor.gameObject))); + } + +#if UNITY_EDITOR_WIN + // Check for problems with Build & Test + var commandPath = Registry.ClassesRoot.OpenSubKey(@"VRChat\shell\open\command"); + var savedVRCInstallPath = SDKClientUtilities.GetSavedVRCInstallPath(); + if (commandPath is null && savedVRCInstallPath == "\\VRChat.exe") + { + general.AddMessageGroup(new MessageGroup(BuildANDTestBrokenError, MessageType.Error).AddSingleMessage(new SingleMessage(SetVRCInstallPath()))); + } + else if (savedVRCInstallPath == "\\VRChat.exe") + { + general.AddMessageGroup(new MessageGroup(BuildANDTestForceNonVRError, MessageType.Warning).AddSingleMessage(new SingleMessage(SetVRCInstallPath()))); + } + else if (!File.Exists(savedVRCInstallPath)) + { + general.AddMessageGroup(new MessageGroup(BuildANDTestNoExecutableFound, MessageType.Error).AddSingleMessage(new SingleMessage(SetVRCInstallPath()))); + } +#endif + + // Get spawn points for any possible problems + if (sceneDescriptor.spawns != null && sceneDescriptor.spawns.Length > 0) + { + var spawns = sceneDescriptor.spawns.Where(s => s != null).ToArray(); + + var spawnsLength = sceneDescriptor.spawns.Length; + var emptySpawns = spawnsLength != spawns.Length; + + if (emptySpawns) + { + general.AddMessageGroup(new MessageGroup(NullSpawnPoint, MessageType.Error).AddSingleMessage(new SingleMessage(sceneDescriptor.gameObject).SetAutoFix(FixSpawns(sceneDescriptor)))); + } + + var spawnUnderRespawnHeight = general.AddMessageGroup(new MessageGroup(SpawnUnderRespawnHeight, SpawnUnderRespawnHeightCombined, SpawnUnderRespawnHeightInfo, MessageType.Error)); + var noColliderUnderSpawn = general.AddMessageGroup(new MessageGroup(NoColliderUnderSpawn, NoColliderUnderSpawnCombined, NoColliderUnderSpawnInfo, MessageType.Error)); + var colliderUnderSpawnTrigger = general.AddMessageGroup(new MessageGroup(ColliderUnderSpawnIsTrigger, ColliderUnderSpawnIsTriggerCombined, ColliderUnderSpawnIsTriggerInfo, MessageType.Error)); + var respawnHeightAboveCollider = general.AddMessageGroup(new MessageGroup(RespawnHeightAboveCollider, RespawnHeightAboveColliderCombined, RespawnHeightAboveColliderInfo, MessageType.Error)); + + for (var i = 0; i < sceneDescriptor.spawns.Length; i++) + { + if (sceneDescriptor.spawns[i] == null) continue; + + var spawn = sceneDescriptor.spawns[i]; + + if (spawn.position.y < sceneDescriptor.RespawnHeightY) + { + spawnUnderRespawnHeight.AddSingleMessage(new SingleMessage(spawn.gameObject.name, Math.Abs(spawn.position.y - sceneDescriptor.RespawnHeightY).ToString(CultureInfo.InvariantCulture)).SetSelectObject(spawn.gameObject)); + } + + if (!Physics.Raycast(spawn.position + new Vector3(0, 0.01f, 0), Vector3.down, out RaycastHit hit, Mathf.Infinity, ~0, QueryTriggerInteraction.Ignore)) + { + if (Physics.Raycast(spawn.position + new Vector3(0, 0.01f, 0), Vector3.down, out hit, Mathf.Infinity)) + { + if (hit.collider.isTrigger) + { + colliderUnderSpawnTrigger.AddSingleMessage(new SingleMessage(hit.collider.name, spawn.gameObject.name).SetSelectObject(spawn.gameObject)); + } + } + else + { + noColliderUnderSpawn.AddSingleMessage(new SingleMessage(spawn.gameObject.name).SetSelectObject(spawn.gameObject)); + } + } + // Round respawn height to 2 decimals to reflect in-game functionality + else if (Math.Round(hit.point.y, 2) <= Math.Round(sceneDescriptor.RespawnHeightY, 2)) + { + respawnHeightAboveCollider.AddSingleMessage(new SingleMessage(hit.collider.gameObject.name, spawn.gameObject.name).SetSelectObject(spawn.gameObject).SetAutoFix(ChangeRespawnHeight(sceneDescriptor, hit.point.y - 100))); + } + } + } + else + { + general.AddMessageGroup(new MessageGroup(NoSpawnPointSet, MessageType.Error).AddSingleMessage(new SingleMessage(sceneDescriptor.gameObject).SetAutoFix(FixSpawns(sceneDescriptor)))); + } + +#if VRC_SDK_VRCSDK2 + // Check if the world has playermods defined + var playermods = FindObjectsOfType(typeof(VRC_PlayerMods)) as VRC_PlayerMods[]; + if (playermods.Length == 0) + { + general.AddMessageGroup(new MessageGroup(NoPlayerMods, MessageType.Tips)); + } + + // Get triggers in the world + var triggerScripts = (VRC_Trigger[]) VRC_Trigger.FindObjectsOfType(typeof(VRC_Trigger)); + + var triggerWrongLayer = new List<GameObject>(); + + // Check for OnEnterTriggers to make sure they are on mirrorreflection layer + foreach (var triggerScript in triggerScripts) + { + foreach (var trigger in triggerScript.Triggers) + { + if (trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnEnterTrigger || trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnExitTrigger || trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnEnterCollider || trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnExitCollider) + { + if (!triggerScript.gameObject.GetComponent<Collider>()) + { + if (trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnEnterTrigger || trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnExitTrigger) + { + general.AddMessageGroup(new MessageGroup(TriggerTriggerNoCollider, MessageType.Error).AddSingleMessage(new SingleMessage(triggerScript.name).SetSelectObject(triggerScript.gameObject))); + } + else if (trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnEnterCollider || trigger.TriggerType == VRC.SDKBase.VRC_Trigger.TriggerType.OnExitCollider) + { + general.AddMessageGroup(new MessageGroup(ColliderTriggerNoCollider, MessageType.Error).AddSingleMessage(new SingleMessage(triggerScript.name).SetSelectObject(triggerScript.gameObject))); + } + } + + if ((trigger.TriggerType.ToString() == "OnEnterTrigger" || trigger.TriggerType.ToString() == "OnExitTrigger") && triggerScript.gameObject.layer != LayerMask.NameToLayer("MirrorReflection")) + { + var collides = true; + + var triggerLayers = Helper.GetAllLayerNumbersFromMask(trigger.Layers); + for (var i = 0; i < triggerLayers.Length; i++) + { + var item = triggerLayers[i]; + + if (Physics.GetIgnoreLayerCollision(LayerMask.NameToLayer("MirrorReflection"), item)) + { + collides = false; + break; + } + } + + if (collides) + { + triggerWrongLayer.Add(triggerScript.gameObject); + } + } + } + } + } + + if (triggerWrongLayer.Count > 0) + { + var triggerWrongLayerGroup = new MessageGroup(TriggerTriggerWrongLayer, TriggerTriggerWrongLayerCombined, TriggerTriggerWrongLayerInfo, MessageType.Warning); + for (var i = 0; i < triggerWrongLayer.Count; i++) + { + triggerWrongLayerGroup.AddSingleMessage(new SingleMessage(triggerWrongLayer[i].name).SetSelectObject(triggerWrongLayer[i].gameObject).SetAutoFix(SetObjectLayer(triggerWrongLayer[i].gameObject, "MirrorReflection"))); + } + + general.AddMessageGroup(triggerWrongLayerGroup.SetGroupAutoFix(SetObjectLayer(triggerWrongLayerGroup.GetSelectObjects(), "MirrorReflection"))); + } +#endif + + // Optimization Checks + + // Check for occlusion culling + if (StaticOcclusionCulling.umbraDataSize > 0) + { + optimization.AddMessageGroup(new MessageGroup(BakedOcclusionCulling, MessageType.GoodFPS)); + + var occlusionAreas = GameObject.FindObjectsOfType<OcclusionArea>(); + + if (occlusionAreas.Length == 0) + { + optimization.AddMessageGroup(new MessageGroup(NoOcclusionAreas, MessageType.Tips).SetDocumentation("https://docs.unity3d.com/2018.4/Documentation/Manual/class-OcclusionArea.html")); + } + else + { + var disabledOcclusionAreasGroup = optimization.AddMessageGroup(new MessageGroup(DisabledOcclusionArea, DisabledOcclusionAreaCombined, DisabledOcclusionAreaInfo, MessageType.Warning)); + + foreach (var occlusionArea in occlusionAreas) + { + var so = new SerializedObject(occlusionArea); + var sp = so.FindProperty("m_IsViewVolume"); + + if (!sp.boolValue) + { + disabledOcclusionAreasGroup.AddSingleMessage(new SingleMessage(occlusionArea.name).SetSelectObject(occlusionArea.gameObject)); + } + } + } + } + else + { + optimization.AddMessageGroup(new MessageGroup(NoOcclusionCulling, MessageType.Tips).SetDocumentation("https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Occlusion-Culling")); + } + + OcclusionMessageCheck(); + + // Check for possible camera problems + var cameras = FindObjectsOfType<Camera>(); + + if (cameras.Length > 0) + { + var activeCamerasMessages = optimization.AddMessageGroup(new MessageGroup(ActiveCameraOutputtingToRenderTexture, ActiveCameraOutputtingToRenderTextureCombined, ActiveCameraOutputtingToRenderTextureInfo, MessageType.BadFPS)); + var cameraDepthWarning = general.AddMessageGroup(new MessageGroup(ActiveCameraWithOverZeroDepth, ActiveCameraWithOverZeroDepthCombined, ActiveCameraWithOverZeroDepthInfo, MessageType.Error)); + + for (var i = 0; i < cameras.Length; i++) + { + var camera = cameras[i]; + + if (!camera.enabled) continue; + + if (camera.targetTexture) + { + activeCamerasMessages.AddSingleMessage(new SingleMessage(camera.name).SetSelectObject(camera.gameObject)); + } + else if (camera.depth > 0 && camera.targetDisplay == 0) + { + cameraDepthWarning.AddSingleMessage(new SingleMessage(camera.name).SetSelectObject(camera.gameObject)); + } + } + } + + // Get active mirrors in the world and complain about them + var mirrors = FindObjectsOfType(typeof(VRC_MirrorReflection)) as VRC_MirrorReflection[]; + + if (mirrors.Length > 0) + { + var activeCamerasMessage = new MessageGroup(MirrorONByDefault, MirrorONByDefaultCombined, MirrorONByDefaultInfo, MessageType.BadFPS); + for (var i = 0; i < mirrors.Length; i++) + { + if (mirrors[i].enabled) + { + activeCamerasMessage.AddSingleMessage(new SingleMessage(mirrors[i].name).SetSelectObject(mirrors[i].gameObject)); + } + } + + optimization.AddMessageGroup(activeCamerasMessage); + } + + // Lighting Checks + + switch (RenderSettings.ambientMode) + { + case AmbientMode.Custom: + lighting.AddMessageGroup(new MessageGroup(AmbientModeSetToCustom, MessageType.Error).AddSingleMessage(new SingleMessage(SetAmbientMode(AmbientMode.Skybox)))); + break; + case AmbientMode.Flat: + lighting.AddMessageGroup(new MessageGroup(SingleColorEnvironmentLighting, MessageType.Tips)); + break; + } + + if (Helper.GetBrightness(RenderSettings.ambientLight) < 0.1f && RenderSettings.ambientMode.Equals(AmbientMode.Flat) || + Helper.GetBrightness(RenderSettings.ambientSkyColor) < 0.1f && RenderSettings.ambientMode.Equals(AmbientMode.Trilight) || + Helper.GetBrightness(RenderSettings.ambientEquatorColor) < 0.1f && RenderSettings.ambientMode.Equals(AmbientMode.Trilight) || + Helper.GetBrightness(RenderSettings.ambientGroundColor) < 0.1f && RenderSettings.ambientMode.Equals(AmbientMode.Trilight)) + { + lighting.AddMessageGroup(new MessageGroup(DarkEnvironmentLighting, MessageType.Tips)); + } + + if (RenderSettings.defaultReflectionMode.Equals(DefaultReflectionMode.Custom) && !RenderSettings.customReflection) + { + lighting.AddMessageGroup(new MessageGroup(CustomEnvironmentReflectionsNull, MessageType.Error).AddSingleMessage(new SingleMessage(SetEnviromentReflections(DefaultReflectionMode.Skybox)))); + } + + var bakedLighting = false; + var xatlasUnwrapper = false; + +#if BAKERY_INCLUDED + var bakeryLights = new List<GameObject>(); + // TODO: Investigate whether or not these should be included + // bakeryLights.AddRange(Array.ConvertAll(FindObjectsOfType(typeof(BakeryDirectLight)) as BakeryDirectLight[], s => s.gameObject)); + bakeryLights.AddRange(Array.ConvertAll(FindObjectsOfType(typeof(BakeryPointLight)) as BakeryPointLight[], s => s.gameObject)); + bakeryLights.AddRange(Array.ConvertAll(FindObjectsOfType(typeof(BakerySkyLight)) as BakerySkyLight[], s => s.gameObject)); + + var bakerySettings = ftRenderLightmap.FindRenderSettingsStorage(); + + switch ((ftRenderLightmap.RenderDirMode) bakerySettings.renderSettingsRenderDirMode) + { + case ftRenderLightmap.RenderDirMode.RNM: + case ftRenderLightmap.RenderDirMode.SH: + const string className = "Merlin.VRCBakeryAdapter"; + + if (Helper.GetTypeFromName(className) is null) + { + lighting.AddMessageGroup(new MessageGroup(ShrnmDirectionalModeBakeryError, MessageType.Error).SetDocumentation("https://github.com/Merlin-san/VRC-Bakery-Adapter")); + } + + break; + } + + if (bakerySettings.renderSettingsUnwrapper == 1) + { + xatlasUnwrapper = true; + } + + if (bakeryLights.Count > 0) + { + var notEditorOnly = new List<GameObject>(); + var unityLightOnBakeryLight = new List<GameObject>(); + + bakedLighting = true; + + for (var i = 0; i < bakeryLights.Count; i++) + { + if (!bakeryLights[i].CompareTag("EditorOnly")) + { + notEditorOnly.Add(bakeryLights[i]); + } + + if (!bakeryLights[i].GetComponent<Light>()) continue; + + var light = bakeryLights[i].GetComponent<Light>(); + if (!light.bakingOutput.isBaked && light.enabled) + { + unityLightOnBakeryLight.Add(bakeryLights[i]); + } + } + + if (notEditorOnly.Count > 0) + { + var notEditorOnlyGroup = new MessageGroup(BakeryLightNotSetEditorOnly, BakeryLightNotSetEditorOnlyCombined, BakeryLightNotSetEditorOnlyInfo, MessageType.Warning); + foreach (var item in notEditorOnly) + { + notEditorOnlyGroup.AddSingleMessage(new SingleMessage(item.name).SetAutoFix(SetGameObjectTag(item, "EditorOnly")).SetSelectObject(item)); + } + + lighting.AddMessageGroup(notEditorOnlyGroup.SetGroupAutoFix(SetGameObjectTag(notEditorOnly.ToArray(), "EditorOnly"))); + } + + if (unityLightOnBakeryLight.Count > 0) + { + var unityLightGroup = new MessageGroup(BakeryLightUnityLight, BakeryLightUnityLightCombined, BakeryLightUnityLightInfo, MessageType.Warning); + foreach (var item in unityLightOnBakeryLight) + { + unityLightGroup.AddSingleMessage(new SingleMessage(item.name).SetAutoFix(DisableComponent(item.GetComponent<Light>())).SetSelectObject(item)); + } + + lighting.AddMessageGroup(unityLightGroup.SetGroupAutoFix(DisableComponent(Array.ConvertAll(unityLightOnBakeryLight.ToArray(), s => s.GetComponent<Light>())))); + } + } +#endif + + // Get lights in scene + var lights = FindObjectsOfType<Light>(); + + var nonBakedLights = new List<GameObject>(); + + // Go trough the lights to check if the scene contains lights set to be baked + for (var i = 0; i < lights.Length; i++) + { + // Skip checking realtime lights + if (lights[i].lightmapBakeType == LightmapBakeType.Realtime) continue; + + bakedLighting = true; + + if (!lights[i].bakingOutput.isBaked && lights[i].GetComponent<Light>().enabled) + { + nonBakedLights.Add(lights[i].gameObject); + } + } + + if (LightmapSettings.lightmaps.Length > 0) + { + bakedLighting = true; + + if (androidBuildPlatform && EditorUserBuildSettings.androidBuildSubtarget == MobileTextureSubtarget.Generic) + { + var lightmaps = LightmapSettings.lightmaps; + + var androidCompressionGroup = lighting.AddMessageGroup(new MessageGroup(QuestLightmapCompressionOverride, QuestLightmapCompressionOverrideCombined, QuestLightmapCompressionOverrideInfo, MessageType.Tips).SetDocumentation("https://docs.unity3d.com/2018.4/Documentation/Manual/class-TextureImporter.html")); + + for (var i = 0; i < lightmaps.Length; i++) + { + Object lightmap = lightmaps[i].lightmapColor; + + var textureImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(lightmaps[i].lightmapColor)) as TextureImporter; + + var platformSettings = textureImporter.GetPlatformTextureSettings("Android"); + + if (!platformSettings.overridden) + { + androidCompressionGroup.AddSingleMessage(new SingleMessage(lightmap.name).SetAssetPath(textureImporter.assetPath)); + } + } + } + } + + var probes = LightmapSettings.lightProbes; + + // If the scene has baked lights complain about stuff important to baked lighting missing + if (bakedLighting) + { + // Count lightmaps and suggest to use bigger lightmaps if needed + var lightMapSize = LightmapEditorSettings.maxAtlasSize; + if (lightMapSize < 2048 && LightmapSettings.lightmaps.Length >= 4) + { + if (LightmapSettings.lightmaps[0] != null) + { + var lightmap = LightmapSettings.lightmaps[0]; + + if (lightmap.lightmapColor != null && lightmap.lightmapColor.height != 4096) + { + lighting.AddMessageGroup(new MessageGroup(ConsiderLargerLightmaps, MessageType.Tips).AddSingleMessage(new SingleMessage(lightMapSize.ToString()))); + } + } + } + + if (LightmapEditorSettings.lightmapper.Equals(LightmapEditorSettings.Lightmapper.ProgressiveGPU) && lightMapSize == 4096 && SystemInfo.graphicsMemorySize < 12000) + { + lighting.AddMessageGroup(new MessageGroup(ConsiderSmallerLightmaps, MessageType.Warning).AddSingleMessage(new SingleMessage(lightMapSize.ToString()).SetAutoFix(SetLightmapSize(2048)))); + } + + // Count how many light probes the scene has + long probeCounter = 0; + long bakedProbes = probes != null ? probes.count : 0; + + var lightprobegroups = GameObject.FindObjectsOfType<LightProbeGroup>(); + + var overlappingLightProbesGroup = new MessageGroup(OverlappingLightProbes, OverlappingLightProbesCombined, OverlappingLightProbesInfo, MessageType.Info); + + for (var i = 0; i < lightprobegroups.Length; i++) + { + if (lightprobegroups[i].probePositions.GroupBy(p => p).Any(g => g.Count() > 1)) + { + overlappingLightProbesGroup.AddSingleMessage(new SingleMessage(lightprobegroups[i].name, (lightprobegroups[i].probePositions.Length - lightprobegroups[i].probePositions.Distinct().ToArray().Length).ToString()).SetSelectObject(lightprobegroups[i].gameObject).SetAutoFix(RemoveOverlappingLightProbes(lightprobegroups[i]))); + } + + probeCounter += lightprobegroups[i].probePositions.Length; + } + + if (probeCounter > 0) + { + if (probeCounter - bakedProbes < 0) + { + lighting.AddMessageGroup(new MessageGroup(LightProbesRemovedNotReBaked, MessageType.Warning).AddSingleMessage(new SingleMessage(bakedProbes.ToString(), probeCounter.ToString()))); + } + else + { + if (bakedProbes - (0.9 * probeCounter) < 0) + { + lighting.AddMessageGroup(new MessageGroup(LightProbeCountNotBaked, MessageType.Info).AddSingleMessage(new SingleMessage(probeCounter.ToString("n0"), (probeCounter - bakedProbes).ToString("n0")))); + } + else + { + lighting.AddMessageGroup(new MessageGroup(LightProbeCount, MessageType.Info).AddSingleMessage(new SingleMessage(probeCounter.ToString("n0")))); + } + } + } + + if (overlappingLightProbesGroup.GetTotalCount() > 0) + { + if (overlappingLightProbesGroup.GetTotalCount() > 1) + { + overlappingLightProbesGroup.SetGroupAutoFix(RemoveOverlappingLightProbes(lightprobegroups)); + } + + lighting.AddMessageGroup(overlappingLightProbesGroup); + } + + // Since the scene has baked lights complain if there's no lightprobes + else if (probes == null && probeCounter == 0) + { + lighting.AddMessageGroup(new MessageGroup(NoLightProbes, MessageType.Info).SetDocumentation("https://docs.unity3d.com/2018.4/Documentation/Manual/LightProbes.html")); + } + + // Check lighting data asset size if it exists + if (Lightmapping.lightingDataAsset != null) + { + var pathTo = AssetDatabase.GetAssetPath(Lightmapping.lightingDataAsset); + var length = new FileInfo(pathTo).Length; + lighting.AddMessageGroup(new MessageGroup(LightingDataAssetInfo, MessageType.Info).AddSingleMessage(new SingleMessage((length / 1024.0f / 1024.0f).ToString("F2")))); + } + + if (nonBakedLights.Count != 0) + { + var nonBakedLightsGroup = new MessageGroup(NonBakedBakedLight, NonBakedBakedLightCombined, NonBakedBakedLightInfo, MessageType.Warning); + for (var i = 0; i < nonBakedLights.Count; i++) + { + nonBakedLightsGroup.AddSingleMessage(new SingleMessage(nonBakedLights[i].name).SetSelectObject(nonBakedLights[i].gameObject)); + } + + lighting.AddMessageGroup(nonBakedLightsGroup); + } + } + else + { + lighting.AddMessageGroup(new MessageGroup(androidBuildPlatform ? QuestBakedLightingWarning : LightsNotBaked, androidBuildPlatform ? MessageType.Warning : MessageType.Tips) + .SetDocumentation("https://docs.unity3d.com/2018.4/Documentation/Manual/Lightmapping.html")); + } + + // ReflectionProbes + var reflectionprobes = FindObjectsOfType<ReflectionProbe>(); + var unbakedprobes = new List<GameObject>(); + var reflectionProbeCount = reflectionprobes.Count(); + for (var i = 0; i < reflectionprobes.Length; i++) + { + if (!reflectionprobes[i].bakedTexture && reflectionprobes[i].mode == ReflectionProbeMode.Baked) + { + unbakedprobes.Add(reflectionprobes[i].gameObject); + } + } + + if (reflectionProbeCount == 0) + { + lighting.AddMessageGroup(new MessageGroup(NoReflectionProbes, MessageType.Tips).SetDocumentation("https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Reflection-Probes")); + } + else if (reflectionProbeCount > 0) + { + lighting.AddMessageGroup(new MessageGroup(ReflectionProbeCountText, MessageType.Info).AddSingleMessage(new SingleMessage(reflectionProbeCount.ToString()))); + + if (unbakedprobes.Count > 0) + { + var probesUnbakedGroup = new MessageGroup(ReflectionProbesSomeUnbaked, ReflectionProbesSomeUnbakedCombined, MessageType.Warning); + + foreach (var item in unbakedprobes) + { + probesUnbakedGroup.AddSingleMessage(new SingleMessage(item.name).SetSelectObject(item)); + } + + lighting.AddMessageGroup(probesUnbakedGroup); + } + } + + // Post Processing Checks + +#if UNITY_POST_PROCESSING_STACK_V2 + var postProcessVolumes = FindObjectsOfType(typeof(PostProcessVolume)) as PostProcessVolume[]; + PostProcessLayer mainPostProcessLayer = null; + + // Attempt to find the main post process layer + if (sceneDescriptor.ReferenceCamera != null && sceneDescriptor.ReferenceCamera.gameObject.GetComponent(typeof(PostProcessLayer))) + { + mainPostProcessLayer = sceneDescriptor.ReferenceCamera.gameObject.GetComponent(typeof(PostProcessLayer)) as PostProcessLayer; + } + else + { + if (Camera.main != null) + { + if (Camera.main.gameObject.GetComponent(typeof(PostProcessLayer))) + { + mainPostProcessLayer = Camera.main.gameObject.GetComponent(typeof(PostProcessLayer)) as PostProcessLayer; + } + } + } + + // Check if the post processing layer has resources properly set + if (mainPostProcessLayer) + { + var resourcesInfo = typeof(PostProcessLayer).GetField("m_Resources", BindingFlags.NonPublic | BindingFlags.Instance); + + var postProcessResources = resourcesInfo.GetValue(mainPostProcessLayer) as PostProcessResources; + + if (postProcessResources is null) + { + var singleMessage = new SingleMessage(mainPostProcessLayer.gameObject.name).SetSelectObject(mainPostProcessLayer.gameObject); + + postProcessing.AddMessageGroup(new MessageGroup(PostProcessingNoResourcesSet, MessageType.Error).AddSingleMessage(singleMessage)); + + var resources = (PostProcessResources) AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath("d82512f9c8e5d4a4d938b575d47f88d4"), typeof(PostProcessResources)); + + if (resources != null) singleMessage.SetAutoFix(SetPostProcessingLayerResources(mainPostProcessLayer, resources)); + } + } + + // If post processing is imported but no setup isn't detected show a message + if (postProcessVolumes.Length == 0 && mainPostProcessLayer is null) + { + postProcessing.AddMessageGroup(new MessageGroup(PostProcessingImportedButNotSetup, MessageType.Info)); + } + else + { + // Check the scene view for post processing effects being off + var sceneViewState = SceneView.lastActiveSceneView.sceneViewState; + if (!sceneViewState.showImageEffects) + { + postProcessing.AddMessageGroup(new MessageGroup(PostProcessingDisabledInSceneView, MessageType.Info).SetGroupAutoFix(SetPostProcessingInScene(sceneViewState, true))); + } + + // Start by checking if reference camera has been set in the Scene Descriptor + if (!sceneDescriptor.ReferenceCamera) + { + var noReferenceCameraMessage = new SingleMessage(sceneDescriptor.gameObject); + + if (Camera.main && Camera.main.GetComponent<PostProcessLayer>()) + { + noReferenceCameraMessage.SetAutoFix(SetReferenceCamera(sceneDescriptor, Camera.main)); + } + + postProcessing.AddMessageGroup(new MessageGroup(NoReferenceCameraSetPp, MessageType.Warning).AddSingleMessage(noReferenceCameraMessage)); + } + else + { + // Check for post process volumes in the scene + if (postProcessVolumes.Length == 0) + { + postProcessing.AddMessageGroup(new MessageGroup(NoPostProcessingVolumes, MessageType.Info)); + } + else + { + var postprocessLayer = sceneDescriptor.ReferenceCamera.GetComponent(typeof(PostProcessLayer)) as PostProcessLayer; + if (postprocessLayer is null) + { + postProcessing.AddMessageGroup(new MessageGroup(ReferenceCameraNoPostProcessingLayer, MessageType.Error).AddSingleMessage(new SingleMessage(sceneDescriptor.ReferenceCamera.gameObject))); + } + + if (postprocessLayer) + { + var volumeLayer = postprocessLayer.volumeLayer; + if (volumeLayer == 0) + { + postProcessing.AddMessageGroup(new MessageGroup(VolumeBlendingLayerNotSet, MessageType.Error).AddSingleMessage(new SingleMessage(sceneDescriptor.ReferenceCamera.gameObject))); + } + + // Check for usage of reserved layers since they break post processing + var numbersFromMask = Helper.GetAllLayerNumbersFromMask(volumeLayer); + if (numbersFromMask.Contains(19) | numbersFromMask.Contains(20) | numbersFromMask.Contains(21)) + { + postProcessing.AddMessageGroup(new MessageGroup(PostProcessLayerUsingReservedLayer, MessageType.Error).AddSingleMessage(new SingleMessage(postprocessLayer.gameObject.name).SetSelectObject(postprocessLayer.gameObject))); + } + + var noProfileSet = postProcessing.AddMessageGroup(new MessageGroup(NoProfileSet, NoProfileSetCombined, MessageType.Error)); + var volumeNoGlobalNoCollider = postProcessing.AddMessageGroup(new MessageGroup(PostProcessingVolumeNotGlobalNoCollider, PostProcessingVolumeNotGlobalNoColliderCombined, PostProcessingVolumeNotGlobalNoColliderInfo, MessageType.Error)); + var matchingVolumes = new List<PostProcessVolume>(); + foreach (var postProcessVolume in postProcessVolumes) + { + // Check if the layer matches the cameras post processing layer + if (volumeLayer != 0 && (postprocessLayer.volumeLayer == (postprocessLayer.volumeLayer | (1 << postProcessVolume.gameObject.layer)))) + { + matchingVolumes.Add(postProcessVolume); + } + + // Check if the volume has a profile set + if (postProcessVolume.profile is null && postProcessVolume.sharedProfile is null) + { + noProfileSet.AddSingleMessage(new SingleMessage(postProcessVolume.gameObject.name).SetSelectObject(postProcessVolume.gameObject)); + } + + // Check if the collider is either global or has a collider on it + if (!postProcessVolume.isGlobal && !postProcessVolume.GetComponent<Collider>()) + { + volumeNoGlobalNoCollider.AddSingleMessage(new SingleMessage(postProcessVolume.name).SetSelectObject(postProcessVolume.gameObject)); + } + } + + if (matchingVolumes.Count == 0) + { + postProcessing.AddMessageGroup(new MessageGroup(NoMatchingLayersFound, MessageType.Warning).AddSingleMessage(new SingleMessage(Helper.GetAllLayersFromMask(postprocessLayer.volumeLayer)).SetSelectObject(postprocessLayer.gameObject))); + } + + var noTonemapper = true; + + // Go trough the profile settings and see if any bad one's are used + foreach (var postProcessVolume in matchingVolumes) + { + var postProcessProfile = postProcessVolume.profile ? postProcessVolume.profile : postProcessVolume.sharedProfile; + + if (postProcessProfile is null) continue; + + var ambientOcclusion = postProcessProfile.GetSetting<AmbientOcclusion>(); + if (ambientOcclusion && ambientOcclusion.enabled && ambientOcclusion.active) + { + postProcessing.AddMessageGroup(new MessageGroup(NoAmbientOcclusion, MessageType.Error).AddSingleMessage(new SingleMessage(DisablePostProcessEffect(postProcessProfile, RemovePpEffect.AmbientOcclusion)).SetSelectObject(postProcessVolume.gameObject))); + } + + var screenSpaceReflections = postProcessProfile.GetSetting<ScreenSpaceReflections>(); + if (screenSpaceReflections && screenSpaceReflections.enabled && screenSpaceReflections.active) + { + postProcessing.AddMessageGroup(new MessageGroup(ScreenSpaceReflectionsWarning, MessageType.Warning).AddSingleMessage(new SingleMessage(DisablePostProcessEffect(postProcessProfile, RemovePpEffect.ScreenSpaceReflections)).SetSelectObject(postProcessVolume.gameObject))); + } + + var vignette = postProcessProfile.GetSetting<Vignette>(); + if (vignette && vignette.enabled && vignette.active) + { + postProcessing.AddMessageGroup(new MessageGroup(VignetteWarning, MessageType.Warning).AddSingleMessage(new SingleMessage(postProcessVolume.gameObject))); + } + + if (postProcessVolume.isGlobal) + { + var colorGrading = postProcessProfile.GetSetting<ColorGrading>(); + if (colorGrading && colorGrading.enabled && colorGrading.active) + { + if (colorGrading.tonemapper.overrideState && colorGrading.tonemapper.value != Tonemapper.None) + { + noTonemapper = false; + } + } + + var bloom = postProcessProfile.GetSetting<Bloom>(); + if (bloom && bloom.enabled && bloom.active) + { + if (bloom.intensity.overrideState && bloom.intensity.value > 0.3f) + { + postProcessing.AddMessageGroup(new MessageGroup(TooHighBloomIntensity, MessageType.Warning).AddSingleMessage(new SingleMessage(postProcessVolume.gameObject))); + } + + if (bloom.threshold.overrideState && bloom.threshold.value > 1f) + { + postProcessing.AddMessageGroup(new MessageGroup(TooHighBloomThreshold, MessageType.Warning).AddSingleMessage(new SingleMessage(postProcessVolume.gameObject))); + } + + if (bloom.dirtTexture.overrideState && bloom.dirtTexture.value || bloom.dirtIntensity.overrideState && bloom.dirtIntensity.value > 0) + { + postProcessing.AddMessageGroup(new MessageGroup(NoBloomDirtInVR, MessageType.Error).AddSingleMessage(new SingleMessage(DisablePostProcessEffect(postProcessProfile, RemovePpEffect.BloomDirt)).SetSelectObject(postProcessVolume.gameObject))); + } + } + + var depthOfField = postProcessProfile.GetSetting<DepthOfField>(); + if (depthOfField && depthOfField.enabled && depthOfField.active) + { + postProcessing.AddMessageGroup(new MessageGroup(DepthOfFieldWarning, MessageType.Warning).AddSingleMessage(new SingleMessage(postProcessVolume.gameObject))); + } + } + } + + if (noTonemapper) + { + postProcessing.AddMessageGroup(new MessageGroup(TonemapperMissing, MessageType.Tips).SetDocumentation("https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Post-Processing#colour-grading")); + } + } + } + } + + if (!postProcessing.HasMessages()) + { + postProcessing.AddMessageGroup(new MessageGroup(NoProblemsFoundInPp, MessageType.Info)); + } + } +#else + postProcessing.AddMessageGroup(new MessageGroup(NoPostProcessingImported, MessageType.Info)); +#endif + + // GameObject checks + + var importers = new List<ModelImporter>(); + + var unCrunchedTextures = new List<Texture>(); + var badShaders = 0; + var textureCount = 0; + + var missingShaders = new List<Material>(); + var selectablesNotNone = new List<Selectable>(); + var legacyBlendShapes = new List<ModelImporter>(); + + var checkedMaterials = new List<Material>(); + var checkedShaders = new Dictionary<Shader, CheckedShaderProperties>(); + + var mirrorsDefaultLayers = optimization.AddMessageGroup(new MessageGroup(MirrorWithDefaultLayers, MirrorWithDefaultLayersCombined, MirrorWithDefaultLayersInfo, MessageType.Tips)); + var legacyBlendShapeIssues = general.AddMessageGroup(new MessageGroup(LegacyBlendShapeIssues, LegacyBlendShapeIssuesCombined, LegacyBlendShapeIssuesInfo, MessageType.Warning)); + var grabPassShaders = general.AddMessageGroup(new MessageGroup(MaterialWithGrabPassShader, MaterialWithGrabPassShaderCombined, androidBuildPlatform ? MaterialWithGrabPassShaderInfoPC : MaterialWithGrabPassShaderInfoQuest, androidBuildPlatform ? MessageType.Error : MessageType.Info)); + var disabledPortals = general.AddMessageGroup(new MessageGroup(DisabledPortalsWarning, DisabledPortalsWarningCombined, DisabledPortalsWarningInfo, MessageType.Warning)); + var materialWithNonWhitelistedShader = general.AddMessageGroup(new MessageGroup(MaterialWithNonWhitelistedShader, MaterialWithNonWhitelistedShaderCombined, MaterialWithNonWhitelistedShaderInfo, MessageType.Warning).SetDocumentation("https://docs.vrchat.com/docs/quest-content-limitations#shaders")); + var uiElementNavigation = general.AddMessageGroup(new MessageGroup(UIElementWithNavigationNotNone, UIElementWithNavigationNotNoneCombined, UIElementWithNavigationNotNoneInfo, MessageType.Tips)); + var nullTriggerReceivers = general.AddMessageGroup(new MessageGroup(NullTriggerReceiver, NullTriggerReceiverCombined, NullTriggerReceiverInfo, MessageType.Info)); + var textMeshStatic = general.AddMessageGroup(new MessageGroup(TextMeshLightmapStatic, TextMeshLightmapStaticCombined, TextMeshLightmapStaticInfo, MessageType.Warning)); + var unsupportedCompressionFormatQuest = general.AddMessageGroup(new MessageGroup(UnsupportedCompressionFormatQuest, UnsupportedCompressionFormatQuestCombined, UnsupportedCompressionFormatQuestInfo, MessageType.Error).SetDocumentation("https://docs.unity3d.com/2018.4/Documentation/Manual/class-TextureImporterOverride.html")); + + var allGameObjects = Resources.FindObjectsOfTypeAll(typeof(GameObject)); + for (var i = 0; i < allGameObjects.Length; i++) + { + var gameObject = allGameObjects[i] as GameObject; + + if (gameObject.hideFlags != HideFlags.None || EditorUtility.IsPersistent(gameObject.transform.root.gameObject)) continue; + + var staticEditorFlags = GameObjectUtility.GetStaticEditorFlags(gameObject); + var hasMeshRenderer = false; + var renderers = gameObject.GetComponents<Renderer>(); + + for (var k = 0; k < renderers.Length; k++) + { + var renderer = renderers[k]; + + if (renderer.GetType() == typeof(MeshRenderer)) + { + hasMeshRenderer = true; + + // If baked lighting in the scene check for lightmap uvs + if (bakedLighting && (staticEditorFlags & StaticEditorFlags.ContributeGI) != 0 && !xatlasUnwrapper) + { + var meshFilter = gameObject.GetComponent<MeshFilter>(); + + if (meshFilter != null) + { + var sharedMesh = meshFilter.sharedMesh; + + if (AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sharedMesh)) != null) + { + var modelImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sharedMesh)) as ModelImporter; + + if (!importers.Contains(modelImporter)) + { + if (modelImporter != null) + { + var so = new SerializedObject(renderer); + + if (!modelImporter.generateSecondaryUV && sharedMesh.uv2.Length == 0 && so.FindProperty("m_ScaleInLightmap").floatValue != 0) + { + importers.Add(modelImporter); + } + } + } + } + } + } + } + + if (renderer.GetType() == typeof(SkinnedMeshRenderer)) + { + var skinnedMesh = (SkinnedMeshRenderer) renderer; + var sharedMesh = skinnedMesh.sharedMesh; + var importer = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(sharedMesh)) as ModelImporter; + + if (importer != null) + { + if (sharedMesh.blendShapeCount > 0 && importer.importBlendShapeNormals == ModelImporterNormals.Calculate && !ModelImporterUtil.GetLegacyBlendShapeNormals(importer)) + { + legacyBlendShapes.Add(importer); + legacyBlendShapeIssues.AddSingleMessage(new SingleMessage(Path.GetFileName(AssetDatabase.GetAssetPath(sharedMesh)), EditorUtility.FormatBytes(Profiler.GetRuntimeMemorySizeLong(sharedMesh))).SetAssetPath(importer.assetPath).SetAutoFix(SetLegacyBlendShapeNormals(importer))); + } + } + } + + // Check materials for problems + for (var l = 0; l < renderer.sharedMaterials.Length; l++) + { + var material = renderer.sharedMaterials[l]; + + if (material == null || checkedMaterials.Contains(material)) + continue; + + checkedMaterials.Add(material); + + var shader = material.shader; + + if (androidBuildPlatform && !Validation.WorldShaderWhiteList.Contains(shader.name)) + { + var singleMessage = new SingleMessage(material.name, shader.name); + + if (AssetDatabase.GetAssetPath(material).EndsWith(".mat")) + { + singleMessage.SetAssetPath(AssetDatabase.GetAssetPath(material)); + } + else + { + singleMessage.SetSelectObject(gameObject); + } + + materialWithNonWhitelistedShader.AddSingleMessage(singleMessage); + } + + if (!checkedShaders.ContainsKey(shader) && AssetDatabase.GetAssetPath(shader) != null) + { + var assetPath = AssetDatabase.GetAssetPath(shader); + + if (File.Exists(assetPath)) + { + var checkedShaderProperties = new CheckedShaderProperties(); + + // Read shader file to string + var word = File.ReadAllText(assetPath); + + // Strip comments + word = Regex.Replace(word, "(\\/\\/.*)|(\\/\\*)(.*)(\\*\\/)", ""); + + // Match for GrabPass and check if it's active + var grabPassMatch = Regex.Match(word, "GrabPass\\s*{[\\s\\S]*?}"); + if (grabPassMatch.Success) + { + checkedShaderProperties.IncludesGrabPass = true; + var lightModeTags = Regex.Matches(grabPassMatch.Value, "[\"|']LightMode[\"|']\\s*=\\s*[\"|'](\\w*)[\"|']"); + + if (lightModeTags.Count > 0) + { + for (var j = 0; j < lightModeTags.Count; j++) + { + checkedShaderProperties.GrabPassLightModeTags.Add(lightModeTags[j].Groups[1].Value); + } + } + } + + checkedShaders.Add(shader, checkedShaderProperties); + } + } + + if (checkedShaders.ContainsKey(shader)) + { + var checkedShader = checkedShaders[shader]; + if (checkedShader.IncludesGrabPass) + { + var grabPassActive = false; + if (checkedShader.GrabPassLightModeTags.Count > 0) + { + for (var j = 0; j < checkedShader.GrabPassLightModeTags.Count; j++) + { + if (material.GetShaderPassEnabled(checkedShader.GrabPassLightModeTags[j])) grabPassActive = true; + } + } + else + { + grabPassActive = true; + } + + if (grabPassActive) grabPassShaders.AddSingleMessage(new SingleMessage(material.name, shader.name).SetAssetPath(AssetDatabase.GetAssetPath(material))); + } + } + + if (shader.name == "Hidden/InternalErrorShader" && !missingShaders.Contains(material)) + missingShaders.Add(material); + + if (shader.name.StartsWith(".poiyomi") || shader.name.StartsWith("poiyomi") || shader.name.StartsWith("arktoon") || shader.name.StartsWith("Cubedparadox") || shader.name.StartsWith("Silent's Cel Shading") || shader.name.StartsWith("Xiexe")) + badShaders++; + + for (var j = 0; j < ShaderUtil.GetPropertyCount(shader); j++) + { + if (ShaderUtil.GetPropertyType(shader, j) == ShaderUtil.ShaderPropertyType.TexEnv) + { + var texture = material.GetTexture(ShaderUtil.GetPropertyName(shader, j)); + + if (AssetDatabase.GetAssetPath(texture) != "" && !unCrunchedTextures.Contains(texture)) + { + var assetPath = AssetDatabase.GetAssetPath(texture); + var textureImporter = AssetImporter.GetAtPath(assetPath) as TextureImporter; + + if (textureImporter != null) + { + if (!unCrunchedTextures.Contains(texture)) + { + textureCount++; + } + + var platformTextureSettings = textureImporter.GetPlatformTextureSettings("Android"); + if (platformTextureSettings.overridden && Validation.UnsupportedCompressionFormatsQuest.Contains(platformTextureSettings.format)) + { + unsupportedCompressionFormatQuest.AddSingleMessage(new SingleMessage(texture.name, platformTextureSettings.format.ToString()).SetAssetPath(assetPath)); + } + + if (!textureImporter.crunchedCompression && !unCrunchedTextures.Contains(texture) && !textureImporter.textureCompression.Equals(TextureImporterCompression.Uncompressed) && EditorTextureUtil.GetStorageMemorySize(texture) > 500000) + { + unCrunchedTextures.Add(texture); + } + } + } + } + } + } + } + + if (hasMeshRenderer) + { + if ((staticEditorFlags & StaticEditorFlags.ContributeGI) != 0 && gameObject.GetComponent<TextMesh>()) + { + textMeshStatic.AddSingleMessage(new SingleMessage(gameObject.name).SetSelectObject(gameObject)); + } + + if (gameObject.GetComponent<VRC_MirrorReflection>()) + { + var mirrorMask = gameObject.GetComponent<VRC_MirrorReflection>().m_ReflectLayers; + + if (mirrorMask.value == -1025) + { + mirrorsDefaultLayers.AddSingleMessage(new SingleMessage(gameObject.name).SetSelectObject(gameObject)); + } + } + } + + var selectable = gameObject.GetComponent<Selectable>(); + if (selectable != null) + { + if (selectable.navigation.mode != Navigation.Mode.None) + { + uiElementNavigation.AddSingleMessage(new SingleMessage(gameObject.name).SetSelectObject(gameObject).SetAutoFix(SetSelectableNavigationMode(selectable, Navigation.Mode.None))); + + selectablesNotNone.Add(selectable); + } + } + + if (gameObject.activeInHierarchy == false) + { + if (gameObject.GetComponent<VRC_PortalMarker>()) + { + disabledPortals.AddSingleMessage(new SingleMessage(gameObject.name).SetSelectObject(gameObject)); + } + } + +#if VRC_SDK_VRCSDK2 + var trigger = gameObject.GetComponent<VRC_Trigger>(); + if (trigger != null) + { + var missingFound = false; + for (var j = 0; j < trigger.Triggers.Count; j++) + { + var triggerScript = trigger.Triggers[j]; + for (var k = 0; k < triggerScript.Events.Count; k++) + { + var parameterObjects = triggerScript.Events[k].ParameterObjects; + + if (parameterObjects.Length == 0) + { + nullTriggerReceivers.AddSingleMessage(new SingleMessage(gameObject.name).SetSelectObject(gameObject)); + missingFound = true; + break; + } + else + { + for (var l = 0; l < parameterObjects.Length; l++) + { + if (parameterObjects[l].gameObject == null) + { + nullTriggerReceivers.AddSingleMessage(new SingleMessage(gameObject.name).SetSelectObject(gameObject)); + missingFound = true; + break; + } + } + } + } + + if (missingFound) break; + } + } +#endif + } + + if (legacyBlendShapes.Count > 1) + { + legacyBlendShapeIssues.SetGroupAutoFix(SetLegacyBlendShapeNormals(legacyBlendShapes.ToArray())); + } + + if (selectablesNotNone.Count > 1) + { + uiElementNavigation.SetGroupAutoFix(SetSelectableNavigationMode(selectablesNotNone.ToArray(), Navigation.Mode.None)); + } + + // If more than 10% of shaders used in scene are toon shaders to leave room for people using them for avatar displays + if (checkedMaterials.Count > 0) + { + if (badShaders / checkedMaterials.Count * 100 > 10) + { + optimization.AddMessageGroup(new MessageGroup(NoToonShaders, MessageType.Warning)); + } + } + + // Suggest to crunch textures if there are any uncrunched textures found + if (textureCount > 0) + { + var percent = (int) ((float) unCrunchedTextures.Count / (float) textureCount * 100f); + if (percent > 20) + { + optimization.AddMessageGroup(new MessageGroup(NonCrunchedTextures, MessageType.Tips).AddSingleMessage(new SingleMessage(percent.ToString()).SetAutoFix(MassTextureImporter.ShowWindow))); + } + } + + var modelsCount = importers.Count; + if (modelsCount > 0) + { + var noUVGroup = new MessageGroup(NoLightmapUV, NoLightmapUVCombined, NoLightmapUVInfo, MessageType.Warning); + for (var i = 0; i < modelsCount; i++) + { + var modelImporter = importers[i]; + + noUVGroup.AddSingleMessage(new SingleMessage(Path.GetFileName(AssetDatabase.GetAssetPath(modelImporter))).SetAutoFix(SetGenerateLightmapUV(modelImporter)).SetAssetPath(modelImporter.assetPath)); + } + + lighting.AddMessageGroup(noUVGroup.SetGroupAutoFix(SetGenerateLightmapUV(importers)).SetDocumentation("https://docs.unity3d.com/2018.4/Documentation/Manual/LightingGiUvs-GeneratingLightmappingUVs.html")); + } + + var missingShadersCount = missingShaders.Count; + if (missingShadersCount > 0) + { + var missingShadersGroup = new MessageGroup(MissingShaderWarning, MissingShaderWarningCombined, MissingShaderWarningInfo, MessageType.Error); + for (var i = 0; i < missingShaders.Count; i++) + { + missingShadersGroup.AddSingleMessage(new SingleMessage(missingShaders[i].name).SetAssetPath(AssetDatabase.GetAssetPath(missingShaders[i])).SetAutoFix(ChangeShader(missingShaders[i], "Standard"))); + } + + general.AddMessageGroup(missingShadersGroup.SetGroupAutoFix(ChangeShader(missingShaders.ToArray(), "Standard"))); + } + } + catch (Exception exception) + { + general.AddMessageGroup(new MessageGroup(HeyYouFoundABug, MessageType.Error)).AddSingleMessage(new SingleMessage(exception.Message.Replace("\n", " ").Replace("\r", ""), Regex.Matches(exception.StackTrace, "(?<=\\.cs:).*(?<=\\S)")[0].ToString())); + Debug.LogError(exception); + autoRecheck = false; + } + } + + private void OnFocus() + { + if (initDone) + { + RefreshBuild(); + } + + recheck = true; + } + + private const string LastBuild = "Library/LastBuild.buildreport"; + + private const string BuildReportDir = "Assets/_LastBuild/"; + + private const string LastBuildReportPath = "Assets/_LastBuild/LastBuild.buildreport"; + private const string WindowsBuildReportPath = "Assets/_LastBuild/LastWindowsBuild.buildreport"; + private const string QuestBuildReportPath = "Assets/_LastBuild/LastQuestBuild.buildreport"; + + [SerializeField] private BuildReport buildReportWindows; + [SerializeField] private BuildReport buildReportQuest; + + [SerializeField] private TreeViewState treeViewState; + [SerializeField] private MultiColumnHeaderState multiColumnHeaderState; + + private BuildReportTreeView buildReportTreeView; + private SearchField searchField; + + private void RefreshBuild() + { +#if VRWT_BENCHMARK + CheckTime.Restart(); +#endif + if (!Directory.Exists(BuildReportDir)) + Directory.CreateDirectory(BuildReportDir); + if (File.Exists(LastBuild) && (!File.Exists(LastBuildReportPath) || File.GetLastWriteTime(LastBuild) > File.GetLastWriteTime(LastBuildReportPath))) + { + File.Copy(LastBuild, LastBuildReportPath, true); + AssetDatabase.ImportAsset(LastBuildReportPath); + } + + var newBuildSet = false; + if (File.Exists(LastBuildReportPath)) + { + switch (AssetDatabase.LoadAssetAtPath<BuildReport>(LastBuildReportPath).summary.platform) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + if (File.GetLastWriteTime(LastBuildReportPath) > File.GetLastWriteTime(WindowsBuildReportPath)) + { + AssetDatabase.CopyAsset(LastBuildReportPath, WindowsBuildReportPath); + buildReportWindows = (BuildReport) AssetDatabase.LoadAssetAtPath(WindowsBuildReportPath, typeof(BuildReport)); + newBuildSet = true; + } + + break; + case BuildTarget.Android: + if (File.GetLastWriteTime(LastBuildReportPath) > File.GetLastWriteTime(QuestBuildReportPath)) + { + AssetDatabase.CopyAsset(LastBuildReportPath, QuestBuildReportPath); + buildReportQuest = (BuildReport) AssetDatabase.LoadAssetAtPath(QuestBuildReportPath, typeof(BuildReport)); + newBuildSet = true; + } + + break; + } + } + + if (buildReportWindows is null && File.Exists(WindowsBuildReportPath)) + { + buildReportWindows = (BuildReport) AssetDatabase.LoadAssetAtPath(WindowsBuildReportPath, typeof(BuildReport)); + } + + if (buildReportQuest is null && File.Exists(QuestBuildReportPath)) + { + buildReportQuest = (BuildReport) AssetDatabase.LoadAssetAtPath(QuestBuildReportPath, typeof(BuildReport)); + } + + if (buildReportInitDone) + { + BuildReport report = null; + + if (newBuildSet) + { + switch (Helper.BuildPlatform()) + { + case RuntimePlatform.WindowsPlayer: + report = buildReportWindows; + selectedBuildReport = 0; + break; + case RuntimePlatform.Android: + report = buildReportQuest; + selectedBuildReport = 1; + break; + } + } + else + { + if (selectedBuildReport == 1 && buildReportQuest != null) + { + report = buildReportQuest; + } + else + { + selectedBuildReport = 0; + report = buildReportWindows; + } + } + + buildReportTreeView.SetReport(report); + } + +#if VRWT_BENCHMARK + CheckTime.Stop(); + Debug.Log($"Refreshed build reports in: {CheckTime.ElapsedMilliseconds} ms."); +#endif + } + + [NonSerialized] private bool initDone; + [NonSerialized] private bool buildReportInitDone; + + [SerializeField] private MessageCategoryList masterList; + + [SerializeField] private MessageCategory general; + [SerializeField] private MessageCategory optimization; + [SerializeField] private MessageCategory lighting; + [SerializeField] private MessageCategory postProcessing; + + private void InitWhenNeeded() + { + if (!initDone) + { +#if VRWT_BENCHMARK + CheckTime.Restart(); +#endif + RefreshBuild(); + + if (masterList is null) + masterList = new MessageCategoryList(); + + general = masterList.CreateOrGetCategory("General"); + + optimization = masterList.CreateOrGetCategory("Optimization"); + + lighting = masterList.CreateOrGetCategory("Lighting"); + + postProcessing = masterList.CreateOrGetCategory("Post Processing"); + +#if VRC_SDK_VRCSDK3 && UDON + projectType = ProjectType.World; +#elif VRC_SDK_VRCSDK3 && !UDON + projectType = ProjectType.Avatar; +#elif VRC_SDK_VRCSDK2 + var sceneDescriptors = FindObjectsOfType(typeof(VRC_SceneDescriptor)) as VRC_SceneDescriptor[]; + if (sceneDescriptors.Length > 0) + { + projectType = ProjectType.World; + } + else + { + var avatarDescriptors = FindObjectsOfType(typeof(VRC_AvatarDescriptor)) as VRC_AvatarDescriptor[]; + if (avatarDescriptors.Length > 0) + { + projectType = ProjectType.Avatar; + } + } +#else + projectType = ProjectType.Generic; +#endif + + initDone = true; +#if VRWT_BENCHMARK + CheckTime.Stop(); + Debug.Log($"Main initialization done in: {CheckTime.ElapsedMilliseconds} ms."); +#endif + } + + if (!buildReportInitDone && tab == 1) + { +#if VRWT_BENCHMARK + CheckTime.Restart(); +#endif + var firstInit = multiColumnHeaderState == null; + var headerState = BuildReportTreeView.CreateDefaultMultiColumnHeaderState(EditorGUIUtility.currentViewWidth - 121); + if (MultiColumnHeaderState.CanOverwriteSerializedFields(multiColumnHeaderState, headerState)) + MultiColumnHeaderState.OverwriteSerializedFields(multiColumnHeaderState, headerState); + multiColumnHeaderState = headerState; + + var multiColumnHeader = new MultiColumnHeader(headerState); + if (firstInit) + multiColumnHeader.ResizeToFit(); + + if (treeViewState is null) + { + treeViewState = new TreeViewState(); + } + + BuildReport report; + if (selectedBuildReport == 1 && buildReportQuest != null) + { + report = buildReportQuest; + } + else + { + selectedBuildReport = 0; + report = buildReportWindows; + } + + buildReportTreeView = new BuildReportTreeView(treeViewState, multiColumnHeader, report); + searchField = new SearchField(); + searchField.downOrUpArrowKeyPressed += buildReportTreeView.SetFocusAndEnsureSelectedItem; + + buildReportInitDone = true; +#if VRWT_BENCHMARK + CheckTime.Stop(); + Debug.Log($"Build report initialization done in: {CheckTime.ElapsedMilliseconds} ms."); +#endif + } + } + + private static readonly Stopwatch CheckTime = new Stopwatch(); + + private void Refresh() + { + if (!EditorApplication.isPlaying && recheck && autoRecheck && tab == 0) + { + // Check for bloat in occlusion cache + if (occlusionCacheFiles == 0 && Directory.Exists("Library/Occlusion/")) + { + Task.Run(CountOcclusionCacheFiles); + } + + CheckTime.Restart(); + + switch (projectType) + { + case ProjectType.World: + CheckScene(); + break; + } + + CheckTime.Stop(); + + if (CheckTime.ElapsedMilliseconds >= 500) + { + autoRecheck = false; + } + +#if VRWT_BENCHMARK + Debug.Log("Checks done in: " + CheckTime.ElapsedMilliseconds + " ms."); +#endif + + recheck = false; + } + } + + private enum BuildReportType + { + Windows = 0, + Quest = 1 + } + + private static readonly string[] BuildReportToolbar = + { + "Windows", "Quest" + }; + + private static readonly string[] MainToolbar = + { + "Messages", "Build Report" + }; + + [SerializeField] private int selectedBuildReport; + [SerializeField] private bool overallStatsFoldout; + [SerializeField] private bool buildReportMessagesFoldout; + + private enum ProjectType + { + NotDetected, + Generic, + World, + Avatar + } + + private ProjectType projectType = ProjectType.NotDetected; + + private void OnGUI() + { + var current = Event.current; + + if (current.type == EventType.Layout) + { + InitWhenNeeded(); + Refresh(); + } + + DrawBuildReportOverviews(current); + + EditorGUILayout.LabelField("", GUI.skin.horizontalSlider); + + tab = GUILayout.Toolbar(tab, MainToolbar); + + switch (tab) + { + case 0: + MessagesTab(); + break; + case 1: + BuildReportTab(); + break; + } + } + + private void DrawBuildReportOverviews(Event current) + { + using (new EditorGUILayout.HorizontalScope()) + { + if (buildReportWindows) + { + DrawOverview(buildReportWindows, "Windows"); + } + + if (buildReportQuest) + { + DrawOverview(buildReportQuest, "Quest"); + } + } + + void DrawOverview(BuildReport report, string platform) + { + using (var verticalScope = new EditorGUILayout.VerticalScope()) + { + GUILayout.Label($"Last found {platform} build:", EditorStyles.boldLabel); + + using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) + { + GUILayout.Label("<b>Build size:</b> " + EditorUtility.FormatBytes((long) report.summary.totalSize), Styles.LabelRichText); + + GUILayout.Label("<b>Build done:</b> " + report.summary.buildEndedAt.ToLocalTime(), Styles.LabelRichText); + + GUILayout.Label("<b>Errors during build:</b> " + report.summary.totalErrors, Styles.LabelRichText); + + GUILayout.Label("<b>Warnings during build:</b> " + report.summary.totalWarnings, Styles.LabelRichText); + + GUILayout.Label("<b>Build result:</b> " + report.summary.result, Styles.LabelRichText); + } + + if (current.type == EventType.ContextClick && verticalScope.rect.Contains(current.mousePosition)) + { + var path = report.summary.outputPath; + var menu = new GenericMenu(); + + if (File.Exists(path)) + { + menu.AddItem(new GUIContent("Show in Explorer"), false, () => EditorUtility.RevealInFinder(report.summary.outputPath)); + } + else + { + menu.AddDisabledItem(new GUIContent("Show in Explorer")); + } + + menu.ShowAsContext(); + } + } + } + } + + private void MessagesTab() + { + switch (projectType) + { + case ProjectType.NotDetected: + ProjectTypeNotDetected(); + break; + case ProjectType.Generic: + ProjectTypeNotSupportedYet(); + break; + case ProjectType.World: + if (EditorApplication.isPlaying) + { + GUILayout.FlexibleSpace(); + + EditorGUILayout.LabelField("The editor is currently in play mode.", Styles.CenteredLabel, GUILayout.ExpandWidth(true), GUILayout.Height(20)); + EditorGUILayout.LabelField("Stop it to see the messages.", Styles.CenteredLabel, GUILayout.ExpandWidth(true), GUILayout.Height(20)); + + GUILayout.FlexibleSpace(); + } + else + { + if (!autoRecheck && GUILayout.Button("Refresh")) + { + recheck = true; + autoRecheck = true; + } + + masterList.DrawTabSelector(); + + masterList.DrawMessages(); + } + + break; + case ProjectType.Avatar: + ProjectTypeNotSupportedYet(); + break; + } + } + + private void ProjectTypeNotDetected() + { + GUILayout.FlexibleSpace(); + + EditorGUILayout.LabelField($"Current project type not detected.", Styles.CenteredLabel, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true), GUILayout.Height(40)); + + GUILayout.FlexibleSpace(); + } + + private void ProjectTypeNotSupportedYet() + { + GUILayout.FlexibleSpace(); + + EditorGUILayout.LabelField($"{projectType} projects\nnot fully supported yet.", Styles.CenteredLabel, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true), GUILayout.Height(40)); + + GUILayout.FlexibleSpace(); + } + + private void BuildReportTab() + { + if (buildReportInitDone) + { + GUILayout.BeginVertical(); + + GUILayout.BeginHorizontal(EditorStyles.toolbar); + + if (buildReportWindows && buildReportQuest) + { + EditorGUI.BeginChangeCheck(); + + selectedBuildReport = GUILayout.Toolbar(selectedBuildReport, BuildReportToolbar, EditorStyles.toolbarButton); + + if (EditorGUI.EndChangeCheck()) + { + switch ((BuildReportType) selectedBuildReport) + { + case BuildReportType.Windows: + buildReportTreeView.SetReport(buildReportWindows); + break; + case BuildReportType.Quest: + buildReportTreeView.SetReport(buildReportQuest); + break; + } + } + + GUILayout.Space(10); + } + + overallStatsFoldout = GUILayout.Toggle(overallStatsFoldout, "Stats", EditorStyles.toolbarButton); + + buildReportMessagesFoldout = GUILayout.Toggle(buildReportMessagesFoldout, "Messages", EditorStyles.toolbarButton); + + GUILayout.Space(10); + + if (GUILayout.Button("Refresh", EditorStyles.toolbarButton)) + { + RefreshBuild(); + + if (buildReportTreeView.BuildSucceeded) + { + buildReportTreeView.Reload(); + } + else + { + if (buildReportWindows != null) + { + buildReportTreeView.SetReport(buildReportWindows); + } + else if (buildReportQuest != null) + { + buildReportTreeView.SetReport(buildReportQuest); + } + } + } + + GUILayout.FlexibleSpace(); + + buildReportTreeView.searchString = searchField.OnToolbarGUI(buildReportTreeView.searchString); + + GUILayout.EndHorizontal(); + + GUILayout.EndVertical(); + + if (buildReportMessagesFoldout) + { + buildReportTreeView.DrawMessages(); + } + else + { + if (overallStatsFoldout) + { + buildReportTreeView.DrawOverallStats(); + } + + var treeViewRect = EditorGUILayout.BeginVertical(); + + if (buildReportTreeView.BuildSucceeded) + { + buildReportTreeView.OnGUI(treeViewRect); + } + else + { + GUILayout.FlexibleSpace(); + + EditorGUILayout.LabelField($"Last {BuildReportToolbar[selectedBuildReport]} Build Failed", Styles.CenteredLabel, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true), GUILayout.Height(40)); + + GUILayout.FlexibleSpace(); + } + + GUILayout.FlexibleSpace(); + + EditorGUILayout.EndVertical(); + } + } + } + + private void OnInspectorUpdate() + { + Repaint(); + } + } +} +#endif
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/WorldDebugger.cs.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/WorldDebugger.cs.meta new file mode 100644 index 00000000..ded9a5b1 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Scripts/Editor/WorldDebugger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c500574965f085d48b1c116e05466777 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Version.txt b/VRCSDK3Worlds/Assets/VRWorldToolkit/Version.txt new file mode 100644 index 00000000..ef9c5770 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Version.txt @@ -0,0 +1 @@ +V1.11.2
\ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/VRWorldToolkit/Version.txt.meta b/VRCSDK3Worlds/Assets/VRWorldToolkit/Version.txt.meta new file mode 100644 index 00000000..29b19f60 --- /dev/null +++ b/VRCSDK3Worlds/Assets/VRWorldToolkit/Version.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 059d3ed74c017fb41be026e7fa066b4c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: |