Added Unity project files

This commit is contained in:
2026-06-07 16:58:24 +01:00
parent 3cc05d260b
commit 23bbcab156
3942 changed files with 453676 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c780449c33592e44bb63c21e2890f25b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,83 @@
using System;
using UnityEditor;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
public class About : EditorWindow
{
[MenuItem("VRWorld Toolkit/About VRWorld Toolkit", false, 40)]
public static void ShowWindow()
{
var window = (About) GetWindow(typeof(About), 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;
[NonSerialized] private int clickCounter;
public void OnEnable()
{
header = new GUIStyle
{
normal =
{
background = Resources.Load("VRWorldToolkit/SplashTextures/VRWTSplashLogo") as Texture2D,
textColor = Color.white,
},
fixedHeight = 140
};
iconTwitter = Resources.Load("VRWorldToolkit/SplashTextures/IconTwitter") as Texture2D;
iconDiscord = Resources.Load("VRWorldToolkit/SplashTextures/IconDiscord") as Texture2D;
iconGithub = Resources.Load("VRWorldToolkit/SplashTextures/IconGithub") as Texture2D;
}
private void OnGUI()
{
// Header Image
if (GUILayout.Button("", header))
{
clickCounter++;
if (clickCounter >= 10)
{
Debug.Log("Toggled benchmark mode for VRWorld Toolkit");
#if VRWT_BENCHMARK
ScriptingDefineManager.RemoveScriptingDefine("VRWT_BENCHMARK");
#else
ScriptingDefineManager.AddScriptingDefine("VRWT_BENCHMARK");
#endif
}
};
// 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.", Styles.RichTextWrap);
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!", Styles.RichTextWrap);
GUILayout.FlexibleSpace();
// Social Buttons
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(iconTwitter, GUIStyle.none)) Application.OpenURL("https://twitter.com/oneVRdev");
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.FlexibleSpace();
EditorGUILayout.EndHorizontal();
GUILayout.Space(20);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b860d7350d99cf342bd9f2ec73c5ae8b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,61 @@
#if BAKERY_INCLUDED
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
public class BakeryCompat
{
public static IEnumerable<GameObject> GetBakeryLights()
{
var names = new[] { "BakeryDirectLight", "BakeryPointLight", "BakerySkyLight" };
foreach (var name in names)
{
var type = Helper.GetTypeFromName(name);
if (type == null) continue;
var objects = UnityEngine.Object.FindObjectsOfType(type);
foreach (var obj in objects)
{
if (obj is Component component && component != null && component.gameObject != null) yield return component.gameObject;
}
}
}
public static (object renderSettingsStorage, Type ftRenderLightmap) TryGetSettings()
{
var ftRenderLightmap = Helper.GetTypeFromName("ftRenderLightmap");
if (ftRenderLightmap == null) return (null, null);
var method = ftRenderLightmap.GetMethod("FindRenderSettingsStorage", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
var renderSettingsStorage = method?.Invoke(null, new object[method?.GetParameters()?.Length ?? 0]);
return (renderSettingsStorage, ftRenderLightmap);
}
public static bool IsRenderDirRNMOrSH(object renderSettingsStorage, Type ftRenderLightmap)
{
if (renderSettingsStorage == null || ftRenderLightmap == null) return false;
var field = renderSettingsStorage.GetType().GetField("renderSettingsRenderDirMode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
var value = field?.GetValue(renderSettingsStorage);
if (value == null) return false;
var enumType = ftRenderLightmap.GetNestedType("RenderDirMode", BindingFlags.Public | BindingFlags.NonPublic);
if (enumType == null) return false;
var name = Enum.GetName(enumType, value);
return name is "RNM" or "SH";
}
public static bool UsesXatlas(object renderSettingsStorage)
{
if (renderSettingsStorage == null) return false;
var field = renderSettingsStorage.GetType().GetField("renderSettingsUnwrapper", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
var value = field?.GetValue(renderSettingsStorage);
return value is int i && i == 1;
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80655d27dc145bf449cb1ca290fe78c8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,75 @@
#if VRC_SDK_VRCSDK3
using System.Linq;
using UnityEditor;
using UnityEngine;
using VRC.Core;
using VRC.SDKBase;
using VRC.SDKBase.Editor.BuildPipeline;
namespace VRWorldToolkit.Editor
{
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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5eeaa016a09318448567f5b566c899b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,552 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build.Reporting;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
public class BuildReportTreeView : TreeView
{
private BuildReport report;
public bool HasReport { get; private set; }
public bool BuildSucceeded { get; private set; }
private enum TreeColumns
{
Type,
Size,
Name,
Extension,
Percentage,
}
private readonly MultiColumnHeader header;
public BuildReportTreeView(TreeViewState state, MultiColumnHeader header, BuildReport report) : base(state, header)
{
this.header = header;
showBorder = true;
showAlternatingRowBackgrounds = true;
this.header.sortingChanged += OnSortingChanged;
SetReport(report);
}
private class BuildListAsset
{
public string AssetType { get; set; }
public string FullPath { get; set; }
public ulong Size { get; set; }
public double Percentage { get; set; }
public BuildListAsset()
{
}
public BuildListAsset(Type assetType, string fullPath, ulong size)
{
AssetType = assetType.Name;
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 ulong size { get; set; }
public double percentage { get; set; }
public BuildReportItem(int id, int depth, Texture previewIcon, string assetType, string displayName, string path, string extension, ulong 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 packedAssets = report.packedAssets;
var bl = new List<BuildListAsset>();
for (var i = 0; i < packedAssets.Length; i++)
{
var packedAssetInfos = packedAssets[i].contents;
for (int j = 0; j < packedAssetInfos.Length; j++)
{
var packedAssetInfo = packedAssetInfos[j];
var asset = new BuildListAsset(packedAssetInfo.type, packedAssetInfo.sourceAssetPath, packedAssetInfo.packedSize);
bl.Add(asset);
}
}
var results = bl
.GroupBy(x => x.FullPath)
.Select(cx => new BuildListAsset()
{
AssetType = cx.First().AssetType,
FullPath = cx.First().FullPath,
Size = cx.Aggregate(0UL, (total, x) => total + 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,
GetFileName(asset.FullPath),
asset.FullPath,
GetFileExtension(asset.FullPath),
asset.Size,
asset.Percentage)
);
}
return root;
static string GetFileName(string path)
{
if (string.IsNullOrEmpty(path))
{
return "Unknown";
}
if (path.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
{
return path;
}
return Path.GetFileName(path);
}
static string GetFileExtension(string path)
{
if (string.IsNullOrEmpty(path) || path.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
{
return "Unknown";
}
return Path.GetExtension(path);
}
}
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 ulong Size;
}
/// <summary>
/// Draw overall stats view of the current build report
/// </summary>
public void DrawOverallStats()
{
if (HasReport && BuildSucceeded)
{
var stats = base.GetRows().Cast<BuildReportItem>().ToList();
var totalSize = stats.Aggregate(0UL, (total, x) => total + x.size);
var grouped = stats
.GroupBy(x => x.assetType)
.Select(cx => new CategoryStats()
{
Name = cx.First().assetType,
Size = cx.Aggregate(0UL, (total, x) => total + 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;
}
var rect = GUILayoutUtility.GetRect(GUIContent.none, EditorStyles.label);
var barGraphRect = rect;
barGraphRect.width *= (float)((double)item.Size / totalSize);
EditorGUI.DrawRect(barGraphRect, new Color(0.28f, 0.37f, 0.51f, 0.6f));
EditorGUIUtility.AddCursorRect(rect, MouseCursor.Link);
GUI.Label(rect , name + " - " + EditorUtility.FormatBytes((long)item.Size), EditorStyles.label);
GUI.Label(rect, ((double)item.Size / totalSize).ToString("P"), Styles.BuildReportStatsLabel);
if (GUI.Button(rect, GUIContent.none, GUIStyle.none))
{
searchString = item.Name;
}
}
EditorGUILayout.EndVertical();
}
}
private Vector2 scrollPosMessages;
public void DrawMessages()
{
if (HasReport && 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("USize", "Uncompressed size of the asset. Unity compresses assets during the build process, so this value will not match the size of the asset within the build."),
contextMenuText = "USize",
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.TreeViewLabelCenter);
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((long)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, Path.GetFileName(clickedItem.path));
menu.AddItem(new GUIContent("Copy Path"), false, ReplaceClipboard, clickedItem.path);
menu.AddItem(new GUIContent("Reveal in Explorer"), false, () => EditorUtility.RevealInFinder(clickedItem.path));
menu.AddItem(new GUIContent("Select in Assets"), false, SelectAssetsInProjectWindow);
// Show the menu
menu.ShowAsContext();
// Function to replace clipboard contents
void ReplaceClipboard(object input)
{
EditorGUIUtility.systemCopyBuffer = (string) input;
}
}
/// <summary>
/// Selects assets in the Project window based on the currently selected BuildReportItems.
/// This is useful for quickly selecting a batch of assets to modify their import settings or other properties in bulk.
/// </summary>
private void SelectAssetsInProjectWindow()
{
// Retrieve the IDs of currently selected items
var selectedItems = GetSelection();
var assetPaths = new List<string>();
// Iterate over each selected item and collect their asset paths
foreach (var itemId in selectedItems)
{
var item = FindItem(itemId, rootItem) as BuildReportItem;
if (item != null && !string.IsNullOrEmpty(item.path))
{
assetPaths.Add(item.path);
}
}
// Load and select the assets in the Project window
var assets = assetPaths.Select(AssetDatabase.LoadAssetAtPath<UnityEngine.Object>).ToArray();
Selection.objects = assets;
}
/// <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;
}
protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
{
var rows = base.BuildRows(root);
var sortedColumn = header.sortedColumnIndex;
if (sortedColumn < 0) return rows;
var isSortedAscending = header.IsSortedAscending(sortedColumn);
var items = rows.Cast<BuildReportItem>();
Func<BuildReportItem, object> selector = sortedColumn switch
{
1 => i => i.size,
2 => i => i.displayName,
3 => i => i.extension,
4 => i => i.size,
_ => i => i.displayName
};
items = isSortedAscending ? items.OrderBy(selector) : items.OrderByDescending(selector);
return items.Cast<TreeViewItem>().ToList();
}
private void OnSortingChanged(MultiColumnHeader _)
{
Reload();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d003bc03a7e1e749bf54fe3fa2a0c3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
using System;
using System.Reflection;
using UnityEngine.Assertions;
namespace VRWorldToolkit.Editor
{
/// <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 });
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e6d4ef7fb3068d4f80218d5e2d95f76
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,141 @@
#if VRC_SDK_VRCSDK3
#if !VRWT_DISABLE_EDITORS
using VRC.SDKBase;
using UnityEditor;
using UnityEngine;
using System.Linq;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using System.Text.RegularExpressions;
using System;
using UnityEngine.Networking;
using Object = UnityEngine.Object;
namespace VRWorldToolkit.Editor
{
/// <summary>
/// Custom editor addition for drawing avatar pedestal bounds
/// </summary>
[CustomEditor(typeof(VRC_AvatarPedestal), true, isFallback = false)]
[CanEditMultipleObjects]
public class CustomAvatarPedestalEditor : UnityEditor.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));
}
if (pedestals.Length == 1 && GUILayout.Button("Open on website"))
{
var blueprintID = UnityWebRequest.EscapeURL(pedestals[0].blueprintId);
if (Regex.IsMatch(blueprintID, AVATAR_ID_REGEX))
{
Application.OpenURL("https://vrchat.com/home/avatar/" + blueprintID);
}
else
{
EditorUtility.DisplayDialog("Warning", "Avatar ID in invalid format.", "Ok");
}
}
}
/// <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
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ed015a875555c741b7f5786054afcb3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
using UnityEditor;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
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
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c8262991e29f8c40a1dac88fb66ff2d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,88 @@
#if VRC_SDK_VRCSDK3
#if !VRWT_DISABLE_EDITORS
using VRC.SDKBase;
using UnityEditor;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
/// <summary>
/// Custom editor for VRC_MirrorReflection with added quick actions
/// </summary>
[CustomEditor(typeof(VRC_MirrorReflection), true, isFallback = false)]
[CanEditMultipleObjects]
public class CustomMirrorEditor : UnityEditor.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(264705);
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 Descriptions");
if (showExplanations)
{
GUILayout.Label("<b>Player:</b>\nThis layer is used to show players other 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>Environment:</b>\nThis layer is used for static meshes and objects in the world. Shares the same properties as the Default layer.", Styles.RichTextWrap);
GUILayout.Label("<b>MirrorReflection:</b>\nThis layer is used to fully show your own self in the mirror.", 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
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b642844c904188f4482604f464a71aa3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,313 @@
using UnityEditor;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
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 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 TreeViewLabelPositive { get; internal set; }
public static GUIStyle TreeViewLabelNegative { get; internal set; }
public static GUIStyle TreeViewLabelDimmed { get; internal set; }
public static GUIStyle TreeViewLabelSelected { get; internal set; }
public static GUIStyle TreeViewLabelRight { get; internal set; }
public static GUIStyle TreeViewLabelRightDimmed { get; internal set; }
public static GUIStyle TreeViewLabelSelectedRight { get; internal set; }
public static GUIStyle TreeViewLabelPositiveRight { get; internal set; }
public static GUIStyle TreeViewLabelNegativeRight { get; internal set; }
public static GUIStyle TreeViewLabelCenter { get; internal set; }
public static GUIStyle TreeViewLabelPositiveCenter { get; internal set; }
public static GUIStyle TreeViewLabelNegativeCenter { get; internal set; }
public static GUIStyle CenteredNoticeLabel { get; internal set; }
public static GUIStyle CenteredNoticeTitle { get; internal set; }
public static GUIStyle BuildReportStatsLabel { get; internal set; }
public static GUIStyle PlatformSelector { 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),
};
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,
};
TreeViewLabelPositive = new GUIStyle(TreeViewLabel)
{
fontStyle = FontStyle.Bold,
normal = { textColor = Color.green },
hover = { textColor = Color.green }
};
TreeViewLabelNegative = new GUIStyle(TreeViewLabel)
{
fontStyle = FontStyle.Bold,
normal = { textColor = Color.red },
hover = { textColor = Color.red }
};
TreeViewLabelDimmed = new GUIStyle(TreeViewLabel)
{
normal = { textColor = new Color(0.5f, 0.5f, 0.5f, 0.5f) },
hover = { textColor = new Color(0.5f, 0.5f, 0.5f, 0.5f) }
};
TreeViewLabelSelected = new GUIStyle("WhiteLabel")
{
alignment = TextAnchor.MiddleLeft,
wordWrap = false,
};
TreeViewLabelRight = new GUIStyle(TreeViewLabel)
{
alignment = TextAnchor.MiddleRight,
};
TreeViewLabelRightDimmed = new GUIStyle(TreeViewLabelRight)
{
normal = { textColor = new Color(0.5f, 0.5f, 0.5f, 0.5f) },
hover = { textColor = new Color(0.5f, 0.5f, 0.5f, 0.5f) }
};
TreeViewLabelSelectedRight = new GUIStyle(TreeViewLabelSelected)
{
alignment = TextAnchor.MiddleRight,
};
TreeViewLabelPositiveRight = new GUIStyle(TreeViewLabelRight)
{
fontStyle = FontStyle.Bold,
normal = { textColor = Color.green },
hover = { textColor = Color.green }
};
TreeViewLabelNegativeRight = new GUIStyle(TreeViewLabelRight)
{
fontStyle = FontStyle.Bold,
normal = { textColor = Color.red },
hover = { textColor = Color.red }
};
TreeViewLabelCenter = new GUIStyle("Label")
{
alignment = TextAnchor.MiddleCenter
};
TreeViewLabelNegativeCenter = new GUIStyle(TreeViewLabelCenter)
{
fontStyle = FontStyle.Bold,
normal = { textColor = Color.red },
hover = { textColor = Color.red }
};
TreeViewLabelPositiveCenter = new GUIStyle(TreeViewLabelCenter)
{
fontStyle = FontStyle.Bold,
normal = { textColor = Color.green },
hover = { textColor = Color.green }
};
CenteredNoticeLabel = new GUIStyle("Label")
{
alignment = TextAnchor.LowerCenter,
fontSize = 17,
fontStyle = FontStyle.BoldAndItalic,
normal = { textColor = new Color(0.33f, 0.33f, 0.33f) }
};
CenteredNoticeTitle = new GUIStyle("Label")
{
alignment = TextAnchor.LowerCenter,
fontSize = 17,
fontStyle = FontStyle.BoldAndItalic,
};
BuildReportStatsLabel = new GUIStyle("Label")
{
alignment = TextAnchor.MiddleRight,
};
PlatformSelector = new GUIStyle(EditorStyles.toolbarButton)
{
fixedHeight = 25,
stretchWidth = true,
};
}
}
public static class Selectors
{
public static readonly string[] maxTextureNames = { "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384" };
public static readonly int[] maxTextureSizes = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384 };
public static int MaxSizeIntPopup(int value)
{
return EditorGUILayout.IntPopup("Max Size", value, maxTextureNames, maxTextureSizes);
}
public static readonly string[] WindowsFormatOptions =
{
new("RGB(A) Compressed BC7"),
new("RGBA Compressed DXT5|BC3"),
new("RGBA Crunched DXT5|BC3"),
new("RGBA 64 bit"),
new("RGBA 32 bit"),
new("ARGB 16 bit"),
new("RG Compressed BC5"),
new("RGBA Float"),
new("RGBA Half"),
};
public static readonly int[] WindowsFormatValues =
{
(int)TextureImporterFormat.BC7,
(int)TextureImporterFormat.DXT5,
(int)TextureImporterFormat.DXT5Crunched,
(int)TextureImporterFormat.RGBA64,
(int)TextureImporterFormat.RGBA32,
(int)TextureImporterFormat.ARGB16,
(int)TextureImporterFormat.BC5,
(int)TextureImporterFormat.RGBAFloat,
(int)TextureImporterFormat.RGBAHalf
};
public static int WindowsFormatIntPopup(int value)
{
return EditorGUILayout.IntPopup("Format", value, WindowsFormatOptions, WindowsFormatValues);
}
public static readonly string[] MobileFormatOptions =
{
"RGB(A) Compressed ASTC 4x4 block",
"RGB(A) Compressed ASTC 5x5 block",
"RGB(A) Compressed ASTC 6x6 block",
"RGB(A) Compressed ASTC 8x8 block",
"RGB(A) Compressed ASTC 10x10 block",
"RGB(A) Compressed ASTC 12x12 block",
"RGBA Compressed ETC2 8 bits",
"RGB + 1-bit Alpha Compressed ETC2 4 bits",
"RGB Compressed ETC2 4 bits",
"RGBA Crunched ETC2",
"RGB Crunched ETC",
"RGBA 32 bit",
"RGBA 16 bit",
"RGB 24 bit",
"RGBA Half",
"RGBA Float",
};
public static readonly int[] MobileFormatValues =
{
(int)TextureImporterFormat.ASTC_4x4,
(int)TextureImporterFormat.ASTC_5x5,
(int)TextureImporterFormat.ASTC_6x6,
(int)TextureImporterFormat.ASTC_8x8,
(int)TextureImporterFormat.ASTC_10x10,
(int)TextureImporterFormat.ASTC_12x12,
(int)TextureImporterFormat.ETC2_RGBA8,
(int)TextureImporterFormat.ETC2_RGB4_PUNCHTHROUGH_ALPHA,
(int)TextureImporterFormat.ETC2_RGB4,
(int)TextureImporterFormat.ETC2_RGBA8Crunched,
(int)TextureImporterFormat.ETC_RGB4Crunched,
(int)TextureImporterFormat.RGBA32,
(int)TextureImporterFormat.RGBA16,
(int)TextureImporterFormat.RGB24,
(int)TextureImporterFormat.RGBAHalf,
(int)TextureImporterFormat.RGBAFloat,
};
public static int MobileFormatIntPopup(int value)
{
return EditorGUILayout.IntPopup("Format", value, MobileFormatOptions, MobileFormatValues);
}
}
public static class Validation
{
/// <summary>
/// Sourced from the whitelist included in the VRCSDK
/// https://creators.vrchat.com/platforms/android/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/2022.3/Documentation/Manual/class-TextureImporterOverride.html
/// </summary>
public static readonly TextureImporterFormat[] UnsupportedCompressionFormatsAndroid =
{
TextureImporterFormat.DXT1,
TextureImporterFormat.DXT5,
TextureImporterFormat.DXT1Crunched,
TextureImporterFormat.DXT5Crunched,
TextureImporterFormat.BC6H,
TextureImporterFormat.BC7,
TextureImporterFormat.PVRTC_RGB2,
TextureImporterFormat.PVRTC_RGB4,
TextureImporterFormat.PVRTC_RGBA2,
TextureImporterFormat.PVRTC_RGBA4,
};
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18d6925c8154648478a78a3c56e1058f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,140 @@
#if VRC_SDK_VRCSDK3
using VRC.SDKBase.Editor.BuildPipeline;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
namespace VRWorldToolkit.Editor
{
public class DisableOnBuildCallback : IVRCSDKBuildRequestedCallback, IProcessSceneWithReport
{
public int callbackOrder => 1;
public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType)
{
DisableOnBuildManager.ToggleObjectsUsingTag("DisableOnBuild", false, false);
DisableOnBuildManager.ToggleObjectsUsingTag("EnableOnBuild", true, false);
return true;
}
public void OnProcessScene(Scene scene, BuildReport report)
{
DisableOnBuildManager.ToggleObjectsUsingTag("DisableOnBuild", false, false);
DisableOnBuildManager.ToggleObjectsUsingTag("EnableOnBuild", true, false);
}
}
public class DisableOnBuildManager : UnityEditor.Editor
{
// Disable On Build
[MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Setup", false, 13)]
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"))
{
Helper.AddTag("DisableOnBuild");
}
}
[MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Setup", true)]
private static bool DisableOnBuildSetupValidate()
{
return !Helper.TagExists("DisableOnBuild");
}
[MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Disable Objects", false, 24)]
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 Helper.TagExists("DisableOnBuild");
}
[MenuItem("VRWorld Toolkit/On Build Functions/Disable On Build/Enable Objects", false, 25)]
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 Helper.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"))
{
Helper.AddTag("EnableOnBuild");
}
}
[MenuItem("VRWorld Toolkit/On Build Functions/Enable On Build/Setup", true)]
private static bool EnableOnBuildSetupValidate()
{
return !Helper.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 Helper.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 Helper.TagExists("EnableOnBuild");
}
public static void ToggleObjectsUsingTag(string tag, bool active, bool markSceneDirty)
{
if (!Helper.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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bdd52a958ec65764aa73bc92ea5cc4e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
using System.Reflection;
using UnityEngine;
using UnityEngine.Assertions;
namespace VRWorldToolkit.Editor
{
/// <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>
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});
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4286f3f47ce16b047add57c7b8b5281d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using UnityEditor;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
public static class Helper
{
public static float GetBrightness(Color color)
{
var num = color.r;
var num2 = color.g;
var num3 = 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 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;
}
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;
#elif UNITY_IOS
return RuntimePlatform.IPhonePlayer;
#else
return RuntimePlatform.WindowsPlayer;
#endif
}
private static readonly Dictionary<string, Type> Cache = new();
public static Type GetTypeFromName(string typeName)
{
if (Cache.TryGetValue(typeName, out var t)) return t;
var type = Type.GetType(typeName);
if (type != null) return type;
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
type = assembly.GetType(typeName);
if (type != null) break;
}
Cache[typeName] = type;
return type;
}
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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5369e6349cede284ca654fec3cb49b1b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 528babda59a4a3442ae04a1a067b9f3f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,39 @@
using System.Reflection;
using UnityEditor;
using UnityEngine.Assertions;
namespace VRWorldToolkit.Editor
{
/// <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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d095f1e0d627e7846ae2d803d04b54e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,180 @@

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
namespace VRWorldToolkit.Editor
{
public class PostProcessingTools : MonoBehaviour
{
#if VRC_SDK_VRCSDK3
[MenuItem("VRWorld Toolkit/Post Processing/Setup Post Processing", false, 1)]
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()
{
return !(Helper.BuildPlatform() is RuntimePlatform.Android);
}
#endif
[MenuItem("VRWorld Toolkit/Post Processing/Post Processing Guide", false, 2)]
private static void PostProcessingGuide()
{
Application.OpenURL("https://gitlab.com/s-ilent/SCSS/-/wikis/Other/Post-Processing");
}
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);
}
}
#if VRC_SDK_VRCSDK3
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);
}
}
}
#endif
public static void SetupPostProcessingGenerics(GameObject camera)
{
#if UNITY_POST_PROCESSING_STACK_V2
//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("VRWorldToolkit/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
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e65609481603134da8675c88def0f3c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,116 @@
#if VRC_SDK_VRCSDK3
#define VRWT_IS_VRC
#endif
#if VRWT_IS_VRC
using VRC.SDKBase;
using VRC.Core;
#endif
using System;
using System.IO;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace VRWorldToolkit.Editor
{
public class QuickFunctions : EditorWindow
{
#if VRWT_IS_VRC
[MenuItem("VRWorld Toolkit/Quick Functions/Copy World ID", false, 4)]
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/Open VRChat Worlds Build Folder", false, 5)]
public static void OpenBuildFolder()
{
#if UNITY_EDITOR_WIN
var userProfilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var localLowPath = Path.Combine(userProfilePath, "AppData", "LocalLow", "VRChat", "VRChat", "Worlds");
if (Directory.Exists(localLowPath)) {
System.Diagnostics.Process.Start("explorer.exe", localLowPath.Replace("/", "\\"));
}
else
{
EditorUtility.DisplayDialog("Folder Not Found", "The VRChat worlds build folder does not exist. It's possible you haven't made a build using the VRChat SDK yet.", "Ok");
}
#else
EditorUtility.DisplayDialog("Info", "This function is only supported while using the Unity Editor on Windows at this time. No action was taken.", "Ok");
#endif
}
[MenuItem("VRWorld Toolkit/Quick Functions/Setup Layers and Collision Matrix", false, 6)]
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()
{
return !UpdateLayers.AreLayersSetup() || !UpdateLayers.IsCollisionLayerMatrixSetup();
}
#endif
[MenuItem("VRWorld Toolkit/Quick Functions/Remove Missing Scripts from Scene", false, 7)]
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");
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3574f219fda73ca4a8c07cc444457e47
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,51 @@
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace VRWorldToolkit.Editor
{
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);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e183946454bd3b147a38db5d972ea1ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,917 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.Profiling;
namespace VRWorldToolkit.Editor
{
public class TextureTreeViewItem : TreeViewItem
{
public Texture Texture { get; }
public TextureImporter Importer { get; }
public TextureImporterType TextureType { get; }
public TextureImporterShape TextureShape { get; }
public TextureImporterFormat Format { get; }
public int MaxTextureSize { get; }
public bool CrunchedCompression { get; }
public int CompressionQuality { get; }
public TextureCompressionMode Compression { get; }
public string AssetPath { get; }
public string FileName { get; }
public long StorageSize { get; }
public int TextureWidth { get; }
public int TextureHeight { get; }
private readonly Dictionary<string, TextureImporterPlatformSettings> _platformSettings = new();
public TextureTreeViewItem(int id, Texture texture, TextureImporter importer) : base(id, 0)
{
Texture = texture;
Importer = importer;
AssetPath = importer.assetPath;
FileName = Path.GetFileName(AssetPath);
StorageSize = EditorTextureUtil.GetStorageMemorySize(texture);
Format = importer.GetDefaultPlatformTextureSettings().format;
TextureWidth = texture.width;
TextureHeight = texture.height;
TextureType = importer.textureType;
TextureShape = importer.textureShape;
MaxTextureSize = importer.maxTextureSize;
CrunchedCompression = importer.crunchedCompression;
CompressionQuality = importer.compressionQuality;
Compression = importer.textureCompression.ToTextureCompressionMode();
displayName = FileName;
CachePlatformSettings("Standalone");
CachePlatformSettings("Android");
CachePlatformSettings("iPhone");
void CachePlatformSettings(string platform)
{
_platformSettings[platform] = Importer.GetPlatformTextureSettings(platform);
}
}
public TextureImporterPlatformSettings GetPlatformSettings(string platform)
{
return _platformSettings.TryGetValue(platform, out var settings) ? settings : null;
}
public int GetPlatformMaxSize(string platform)
{
return GetPlatformSettings(platform).maxTextureSize;
}
public TextureImporterFormat GetPlatformFormat(string platform)
{
return GetPlatformSettings(platform).format;
}
public bool IsPlatformOverridden(string platform)
{
return GetPlatformSettings(platform).overridden;
}
}
public class TextureTreeView : TreeView
{
public enum TreeColumns
{
Icon,
StorageSize,
Name,
TextureSize,
TextureType,
TextureShape,
MaxSize,
Format,
Compression,
Crunched,
CrunchQuality,
MaxSizeWindows,
FormatWindows,
MaxSizeAndroid,
FormatAndroid,
MaxSizeiOS,
FormatiOS,
}
private Dictionary<Texture, TextureImporter> _textures;
private ImporterSettingsManager _settingsManager;
private List<TreeViewItem> _rows = new();
private TreeColumns _sortedColumn = TreeColumns.Name;
private bool _sortAscending = true;
private readonly MultiColumnHeader.HeaderCallback _visibleColumnsChangedHandler;
public TextureTreeView(TreeViewState state, MultiColumnHeader multiColumnHeader, Dictionary<Texture, TextureImporter> textures, ImporterSettingsManager settingsManager) : base(state, multiColumnHeader)
{
_textures = textures;
_settingsManager = settingsManager;
rowHeight = 20;
showAlternatingRowBackgrounds = true;
showBorder = true;
_visibleColumnsChangedHandler = _ => Reload();
multiColumnHeader.sortingChanged += OnSortingChanged;
multiColumnHeader.visibleColumnsChanged += _visibleColumnsChangedHandler;
Reload();
}
public void Cleanup()
{
multiColumnHeader.sortingChanged -= OnSortingChanged;
multiColumnHeader.visibleColumnsChanged -= _visibleColumnsChangedHandler;
}
public void SetTextures(Dictionary<Texture, TextureImporter> textures)
{
_textures = textures;
Reload();
}
public void SetSettingsManager(ImporterSettingsManager settingsManager)
{
_settingsManager = settingsManager;
Reload();
}
public void RefreshItems()
{
Reload();
}
protected override TreeViewItem BuildRoot()
{
var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" };
int id = 1;
foreach (var texture in _textures)
{
if (texture.Value != null)
{
var item = new TextureTreeViewItem(id++, texture.Key, texture.Value);
root.AddChild(item);
}
}
if (!root.hasChildren)
{
root.children = new List<TreeViewItem>();
}
return root;
}
protected override IList<TreeViewItem> BuildRows(TreeViewItem root)
{
_rows.Clear();
if (!root.hasChildren) return _rows;
var filteredItems = root.children
.Cast<TextureTreeViewItem>()
.Where(item => _settingsManager.MatchesFilters(item.Importer));
if (hasSearch)
{
filteredItems = filteredItems
.Where(item => DoesItemMatchSearch(item, searchString));
}
_rows.AddRange(filteredItems);
_rows.Sort((a, b) =>
{
if (a is not TextureTreeViewItem itemA || b is not TextureTreeViewItem itemB) return 0;
int result = _sortedColumn switch
{
TreeColumns.StorageSize => itemA.StorageSize.CompareTo(itemB.StorageSize),
TreeColumns.Name => string.Compare(itemA.FileName, itemB.FileName, StringComparison.OrdinalIgnoreCase),
TreeColumns.TextureSize => (itemA.TextureWidth * itemA.TextureHeight).CompareTo(itemB.TextureWidth * itemB.TextureHeight),
TreeColumns.TextureType => itemA.TextureType.CompareTo(itemB.TextureType),
TreeColumns.TextureShape => itemA.TextureShape.CompareTo(itemB.TextureShape),
TreeColumns.MaxSize => itemA.MaxTextureSize.CompareTo(itemB.MaxTextureSize),
TreeColumns.Compression => itemA.Compression.CompareTo(itemB.Compression),
TreeColumns.Crunched => itemA.CrunchedCompression.CompareTo(itemB.CrunchedCompression),
TreeColumns.CrunchQuality => itemA.CompressionQuality.CompareTo(itemB.CompressionQuality),
TreeColumns.MaxSizeWindows => itemA.GetPlatformMaxSize("Standalone").CompareTo(itemB.GetPlatformMaxSize("Standalone")),
TreeColumns.FormatWindows => itemA.GetPlatformFormat("Standalone").CompareTo(itemB.GetPlatformFormat("Standalone")),
TreeColumns.MaxSizeAndroid => itemA.GetPlatformMaxSize("Android").CompareTo(itemB.GetPlatformMaxSize("Android")),
TreeColumns.FormatAndroid => itemA.GetPlatformFormat("Android").CompareTo(itemB.GetPlatformFormat("Android")),
TreeColumns.MaxSizeiOS => itemA.GetPlatformMaxSize("iPhone").CompareTo(itemB.GetPlatformMaxSize("iPhone")),
TreeColumns.FormatiOS => itemA.GetPlatformFormat("iPhone").CompareTo(itemB.GetPlatformFormat("iPhone")),
_ => 0
};
return _sortAscending ? result : -result;
});
return _rows;
}
protected override void RowGUI(RowGUIArgs args)
{
var item = args.item as TextureTreeViewItem;
if (item == null) return;
for (int i = 0; i < args.GetNumVisibleColumns(); i++)
{
var rect = args.GetCellRect(i);
var columnIndex = args.GetColumn(i);
CenterRectUsingSingleLineHeight(ref rect);
DrawCell(rect, item, (TreeColumns)columnIndex, args.selected);
}
}
protected override bool DoesItemMatchSearch(TreeViewItem item, string search)
{
if (item is not TextureTreeViewItem textureItem) return false;
return textureItem.FileName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0 ||
textureItem.AssetPath.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0;
}
protected override void SingleClickedItem(int id)
{
base.SingleClickedItem(id);
if (FindItem(id, rootItem) is TextureTreeViewItem item)
{
EditorGUIUtility.PingObject(item.Texture);
}
}
protected override void DoubleClickedItem(int id)
{
base.DoubleClickedItem(id);
if (FindItem(id, rootItem) is TextureTreeViewItem item)
{
Selection.activeObject = item.Texture;
EditorApplication.ExecuteMenuItem("Window/General/Inspector");
}
}
protected override void ContextClickedItem(int id)
{
base.ContextClickedItem(id);
if (FindItem(id, rootItem) is not TextureTreeViewItem item) return;
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Copy Name"), false, ReplaceClipboard, Path.GetFileName(item.AssetPath));
menu.AddItem(new GUIContent("Copy Path"), false, ReplaceClipboard, item.AssetPath);
menu.AddSeparator("");
menu.AddItem(new GUIContent("Reveal in Explorer"), false, () => EditorUtility.RevealInFinder(item.AssetPath));
menu.AddItem(new GUIContent("Select in Assets"), false, SelectAssetsInProjectWindow);
menu.ShowAsContext();
void ReplaceClipboard(object input)
{
EditorGUIUtility.systemCopyBuffer = (string)input;
}
}
/// <summary>
/// Selects assets in the Project window based on the currently selected BuildReportItems.
/// This is useful for quickly selecting a batch of assets to modify their import settings or other properties in bulk.
/// Original PR for BuildReportTreeView by @akira0245, see here: https://github.com/oneVR/VRWorldToolkit/pull/26
/// </summary>
private void SelectAssetsInProjectWindow()
{
// Retrieve the IDs of currently selected items
var selectedItems = GetSelection();
var assetPaths = new List<string>();
// Iterate over each selected item and collect their asset paths
foreach (var itemId in selectedItems)
{
var item = FindItem(itemId, rootItem) as TextureTreeViewItem;
if (item != null && !string.IsNullOrEmpty(item.AssetPath))
{
assetPaths.Add(item.AssetPath);
}
}
// Load and select the assets in the Project window
var assets = assetPaths.Select(AssetDatabase.LoadAssetAtPath<UnityEngine.Object>).ToArray();
Selection.objects = assets;
EditorApplication.ExecuteMenuItem("Window/General/Inspector");
}
private void DrawCell(Rect rect, TextureTreeViewItem item, TreeColumns column, bool selected)
{
var labelStyle = selected ? Styles.TreeViewLabelSelected : Styles.TreeViewLabel;
var labelStyleRight = selected ? Styles.TreeViewLabelSelectedRight : Styles.TreeViewLabelRight;
switch (column)
{
case TreeColumns.Icon:
var iconRect = new Rect(rect.x + 4, rect.y + 1, 16, 16);
var preview = AssetPreview.GetMiniThumbnail(item.Texture);
if (preview != null)
{
GUI.DrawTexture(iconRect, preview, ScaleMode.ScaleToFit);
}
break;
case TreeColumns.Name:
GUI.Label(rect, item.FileName, labelStyle);
break;
case TreeColumns.TextureSize:
GUI.Label(rect, $"{item.TextureWidth}x{item.TextureHeight}", labelStyleRight);
break;
case TreeColumns.TextureType:
GUI.Label(rect, item.TextureType.GetDisplayName(), labelStyle);
break;
case TreeColumns.TextureShape:
GUI.Label(rect, item.TextureShape.GetDisplayName(), labelStyle);
break;
case TreeColumns.MaxSize:
DrawMaxSizeCell(rect, item, labelStyleRight);
break;
case TreeColumns.Format:
// Using ToString here returns CompressedAutomatic instead of Automatic so manually overriding it here
if (item.Format == TextureImporterFormat.Automatic)
{
GUI.Label(rect, "Automatic", labelStyle);
}
else
{
GUI.Label(rect, item.Format.ToString(), labelStyle);
}
break;
case TreeColumns.Compression:
DrawCompression(rect, item, labelStyle);
break;
case TreeColumns.Crunched:
DrawCrunchedCell(rect, item);
break;
case TreeColumns.CrunchQuality:
DrawCrunchQualityCell(rect, item, labelStyleRight);
break;
case TreeColumns.StorageSize:
GUI.Label(rect, EditorUtility.FormatBytes(item.StorageSize), labelStyleRight);
break;
case TreeColumns.MaxSizeWindows:
DrawPlatformMaxSize(rect, item, "Standalone", labelStyleRight);
break;
case TreeColumns.FormatWindows:
DrawPlatformFormat(rect, item, "Standalone", labelStyle);
break;
case TreeColumns.MaxSizeAndroid:
DrawPlatformMaxSize(rect, item, "Android", labelStyleRight);
break;
case TreeColumns.FormatAndroid:
DrawPlatformFormat(rect, item, "Android", labelStyle);
break;
case TreeColumns.MaxSizeiOS:
DrawPlatformMaxSize(rect, item, "iPhone", labelStyleRight);
break;
case TreeColumns.FormatiOS:
DrawPlatformFormat(rect, item, "iPhone", labelStyle);
break;
}
}
private void DrawCompression(Rect rect, TextureTreeViewItem item, GUIStyle style)
{
var currentValue = item.Compression;
string currentText = ObjectNames.NicifyVariableName(currentValue.ToString());
if (_settingsManager.DefaultSettings.ChangeCompression)
{
if (_settingsManager.DefaultSettings.IgnoreUncompressed && currentValue == TextureCompressionMode.None)
{
GUI.Label(rect, currentText, style);
return;
}
var newValue = _settingsManager.DefaultSettings.Compression;
if (currentValue != newValue)
{
string tooltip = $"Current: {currentText}";
string text = ObjectNames.NicifyVariableName(newValue.ToString());
if (MemorySize(newValue) < MemorySize(currentValue))
{
GUI.Label(rect, new GUIContent($"↓ {text}", tooltip), Styles.TreeViewLabelPositive);
}
else
{
GUI.Label(rect, new GUIContent($"↑ {text}", tooltip), Styles.TreeViewLabelNegative);
}
return;
int MemorySize(TextureCompressionMode mode) => mode switch
{
TextureCompressionMode.LowQuality => 1,
TextureCompressionMode.NormalQuality => 2,
TextureCompressionMode.HighQuality => 3,
TextureCompressionMode.None => 4,
_ => 2
};
}
}
GUI.Label(rect, currentText, style);
}
private void DrawCrunchedCell(Rect rect, TextureTreeViewItem item)
{
var hasCompression = _settingsManager.DefaultSettings.ChangeCompression ? _settingsManager.DefaultSettings.Compression : item.Compression;
if (hasCompression == TextureCompressionMode.None || _settingsManager.DefaultSettings.IgnoreUncompressed && item.Compression == TextureCompressionMode.None)
{
GUI.Label(rect, "―", Styles.TreeViewLabelCenter);
return;
}
bool currentValue = item.CrunchedCompression;
if (_settingsManager.DefaultSettings.ChangeCrunch)
{
bool skip = _settingsManager.DefaultSettings.SkipCrunchWhen switch
{
DontOverrideWhen.AlreadyDisabled => !currentValue,
DontOverrideWhen.AlreadyEnabled => currentValue,
_ => false
};
if (!skip)
{
bool newValue = _settingsManager.DefaultSettings.UseCrunch;
if (currentValue != newValue)
{
string tooltip = $"Current: {(currentValue ? "Yes" : "No")}";
string text = newValue ? "✓" : "―";
var style = newValue ? Styles.TreeViewLabelPositiveCenter : Styles.TreeViewLabelNegativeCenter;
GUI.Label(rect, new GUIContent(text, tooltip), style);
return;
}
}
}
GUI.Label(rect, currentValue ? "✓" : "―", Styles.TreeViewLabelCenter);
}
private void DrawCrunchQualityCell(Rect rect, TextureTreeViewItem item, GUIStyle style)
{
var hasCompression = _settingsManager.DefaultSettings.ChangeCompression ? _settingsManager.DefaultSettings.Compression : item.Compression;
if (hasCompression == TextureCompressionMode.None || (_settingsManager.DefaultSettings.IgnoreUncompressed && item.Compression == TextureCompressionMode.None))
{
GUI.Label(rect, "―", style);
return;
}
bool currentCrunch = item.CrunchedCompression;
int currentQuality = item.CompressionQuality;
bool effectiveCrunch = currentCrunch;
if (_settingsManager.DefaultSettings.ChangeCrunch)
{
bool skip = _settingsManager.DefaultSettings.SkipCrunchWhen switch
{
DontOverrideWhen.AlreadyDisabled => !currentCrunch,
DontOverrideWhen.AlreadyEnabled => currentCrunch,
_ => false
};
if (!skip)
{
effectiveCrunch = _settingsManager.DefaultSettings.UseCrunch;
}
}
if (!effectiveCrunch)
{
GUI.Label(rect, "―", style);
return;
}
int displayQuality = currentQuality;
bool changes = false;
if (_settingsManager.DefaultSettings.ChangeCrunch)
{
bool skip = _settingsManager.DefaultSettings.SkipCrunchWhen switch
{
DontOverrideWhen.AlreadyDisabled => !currentCrunch,
DontOverrideWhen.AlreadyEnabled => currentCrunch,
_ => false
};
if (!skip && _settingsManager.DefaultSettings.UseCrunch)
{
int newQuality = _settingsManager.DefaultSettings.CrunchQuality;
changes = _settingsManager.DefaultSettings.CrunchQualityCondition switch
{
OverrideCondition.Always => currentQuality != newQuality,
OverrideCondition.Smaller => currentQuality < newQuality,
OverrideCondition.Bigger => currentQuality > newQuality,
_ => false
};
if (changes)
{
displayQuality = newQuality;
}
}
}
if (changes)
{
string tooltip = $"Current: {currentQuality}";
if (displayQuality > currentQuality)
{
GUI.Label(rect, new GUIContent($"↑ {displayQuality}", tooltip), Styles.TreeViewLabelNegativeRight);
}
else
{
GUI.Label(rect, new GUIContent($"↓ {displayQuality}", tooltip), Styles.TreeViewLabelPositiveRight);
}
return;
}
GUI.Label(rect, currentQuality.ToString(), style);
}
private void DrawMaxSizeCell(Rect rect, TextureTreeViewItem item, GUIStyle style)
{
int currentSize = item.MaxTextureSize;
string text = currentSize.ToString();
if (_settingsManager.DefaultSettings.ChangeMaxSize)
{
int newSize = _settingsManager.MaxTextureSize;
bool changes = _settingsManager.DefaultSettings.MaxSizeCondition switch
{
OverrideCondition.Always => currentSize != newSize,
OverrideCondition.Smaller => currentSize < newSize,
OverrideCondition.Bigger => currentSize > newSize,
_ => false
};
if (changes)
{
var tooltip = $"Current: {currentSize}";
if (newSize < currentSize)
{
text = $"↓ {newSize}";
GUI.Label(rect, new GUIContent(text, tooltip), Styles.TreeViewLabelPositiveRight);
}
else
{
text = $"↑ {newSize}";
GUI.Label(rect, new GUIContent(text, tooltip), Styles.TreeViewLabelNegativeRight);
}
return;
}
}
GUI.Label(rect, text, style);
}
private void DrawPlatformMaxSize(Rect rect, TextureTreeViewItem item, string platform, GUIStyle style)
{
int currentSize = item.GetPlatformMaxSize(platform);
var platformSettings = _settingsManager.GetPlatformSettings(platform);
bool isOverridden = item.IsPlatformOverridden(platform) || platformSettings.Override;
if (platformSettings.DisableOverrides)
{
GUI.Label(rect, $"({item.Importer.maxTextureSize})", Styles.TreeViewLabelRightDimmed);
return;
}
if (platformSettings.Override)
{
int newSize = platformSettings.MaxTextureSize;
bool changes = platformSettings.MaxSizeCondition switch
{
OverrideCondition.Always => currentSize != newSize,
OverrideCondition.Smaller => currentSize < newSize,
OverrideCondition.Bigger => currentSize > newSize,
_ => false
};
if (changes)
{
string tooltip = $"Current: {currentSize}";
if (newSize < currentSize)
{
GUI.Label(rect, new GUIContent($"↓ {newSize}", tooltip), Styles.TreeViewLabelPositiveRight);
}
else
{
GUI.Label(rect, new GUIContent($"↑ {newSize}", tooltip), Styles.TreeViewLabelNegativeRight);
}
return;
}
}
string displayText = isOverridden ? currentSize.ToString() : $"({item.Importer.maxTextureSize})";
GUI.Label(rect, displayText, isOverridden ? style : Styles.TreeViewLabelRightDimmed);
}
private void DrawPlatformFormat(Rect rect, TextureTreeViewItem item, string platform, GUIStyle style)
{
var platformSettings = _settingsManager.GetPlatformSettings(platform);
if (!platformSettings.DisableOverrides && platformSettings.Override && (TextureImporterFormat)platformSettings.Format != item.GetPlatformFormat(platform))
{
GUI.Label(rect, ((TextureImporterFormat)platformSettings.Format).ToString(), Styles.TreeViewLabelPositive);
return;
}
if (!item.IsPlatformOverridden(platform) && !platformSettings.Override || platformSettings.DisableOverrides)
{
GUI.Label(rect, "(Automatic)", Styles.TreeViewLabelDimmed);
return;
}
GUI.Label(rect, item.GetPlatformFormat(platform).ToString(), style);
}
private void OnSortingChanged(MultiColumnHeader header)
{
if (header.sortedColumnIndex < 0)
return;
_sortedColumn = (TreeColumns)header.sortedColumnIndex;
_sortAscending = header.IsSortedAscending(header.sortedColumnIndex);
Reload();
}
private const int WidthSize = 60;
private const int WidthFormat = 85;
private const int MaxWidthFormat = 250;
private const int MinWidthFormat = 60;
public static MultiColumnHeaderState CreateDefaultMultiColumnHeaderState(float treeViewWidth)
{
var columns = new[]
{
new MultiColumnHeaderState.Column
{
headerContent = EditorGUIUtility.IconContent("Texture Icon"),
contextMenuText = "Preview",
headerTextAlignment = TextAlignment.Center,
sortedAscending = true,
sortingArrowAlignment = TextAlignment.Center,
width = 25,
minWidth = 25,
maxWidth = 25,
autoResize = false,
allowToggleVisibility = false
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Storage Size", "Storage size on disk"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = 80,
minWidth = 80,
maxWidth = 80,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Name"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = true,
sortingArrowAlignment = TextAlignment.Center,
width = 150,
minWidth = 80,
autoResize = true,
allowToggleVisibility = false
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Original Size", "Original texture dimensions"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = 80,
minWidth = 60,
maxWidth = 100,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Type"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = true,
sortingArrowAlignment = TextAlignment.Right,
width = 80,
minWidth = 60,
maxWidth = 200,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Shape"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = true,
sortingArrowAlignment = TextAlignment.Right,
width = 80,
minWidth = 60,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Max Size"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = WidthSize,
minWidth = WidthSize,
maxWidth = WidthSize,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Format", "Format Default"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Left,
width = WidthFormat,
minWidth = MinWidthFormat,
maxWidth = MaxWidthFormat,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Compression"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = true,
sortingArrowAlignment = TextAlignment.Right,
width = 100,
minWidth = 80,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Crunched"),
headerTextAlignment = TextAlignment.Center,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = 70,
minWidth = 60,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Quality"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = 60,
minWidth = 50,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Windows"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = WidthSize,
minWidth = WidthSize,
maxWidth = WidthSize,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Format", "Format Windows"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Left,
width = WidthFormat,
minWidth = MinWidthFormat,
maxWidth = MaxWidthFormat,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Android"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = WidthSize,
minWidth = WidthSize,
maxWidth = WidthSize,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Format", "Format Android"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = WidthFormat,
minWidth = MinWidthFormat,
maxWidth = MaxWidthFormat,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("iOS"),
headerTextAlignment = TextAlignment.Right,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = WidthSize,
minWidth = WidthSize,
maxWidth = WidthSize,
autoResize = false,
allowToggleVisibility = true
},
new MultiColumnHeaderState.Column
{
headerContent = new GUIContent("Format", "Format iOS"),
headerTextAlignment = TextAlignment.Left,
sortedAscending = false,
sortingArrowAlignment = TextAlignment.Right,
width = WidthFormat,
minWidth = MinWidthFormat,
maxWidth = MaxWidthFormat,
autoResize = false,
allowToggleVisibility = true
},
};
var state = new MultiColumnHeaderState(columns);
// var state = new MultiColumnHeaderState(columns)
// {
// visibleColumns = new[]
// {
// (int)TreeColumns.Icon,
// (int)TreeColumns.StorageSize,
// (int)TreeColumns.Name,
// (int)TreeColumns.TextureSize,
// (int)TreeColumns.MaxSize,
// (int)TreeColumns.Compression,
// (int)TreeColumns.Crunched,
// (int)TreeColumns.MaxSizeWindows,
// (int)TreeColumns.MaxSizeAndroid,
// (int)TreeColumns.MaxSizeiOS,
// }
// };
return state;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b22a8afd8b86b4b4aad48d782610dffb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
{
"name": "VRWorldToolkit.Editor",
"references": [
"GUID:e82e209be578ee94c94cfc45c20bfb14",
"GUID:d60799ab2a985554ea1a39cd38695018",
"GUID:290dd5870d0ead646bcb6ea5c6a60af5",
"GUID:a1653399f63795746b1857281d1e400d"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 856896ecec314274f87485d17fa918aa
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c500574965f085d48b1c116e05466777
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d4c1f247799a190408e8f0e319b9b195
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,90 @@
# VRWorld Toolkit
<img src="https://github.com/oneVR/VRWorldToolkit/assets/4764355/0672bef5-0aa4-42b4-b388-1a47bc1ba998">
<div align="center">
[![GitHub stars](https://img.shields.io/github/stars/oneVR/VRWorldToolkit?style=for-the-badge)](https://github.com/oneVR/VRWorldToolkit/stargazers)
[![GitHub all releases](https://img.shields.io/github/downloads/oneVR/VRWorldToolkit/total?style=for-the-badge)](https://github.com/oneVR/VRWorldToolkit/releases)
[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/oneVR/VRWorldToolkit?sort=semver&style=for-the-badge)](https://github.com/oneVR/VRWorldToolkit/releases/latest)
[![Project License](https://img.shields.io/badge/license-MIT-brightgreen?style=for-the-badge)](https://github.com/oneVR/VRWorldToolkit/blob/master/LICENSE)
![GitHub repo size](https://img.shields.io/github/repo-size/oneVR/VRWorldToolkit?style=for-the-badge)
</div>
**VRWorld Toolkit** is a Unity Editor extension with the purpose of making VRChat world creation more accessible and making it easier to create a good-performing world. The main supported use case is for VRChat world projects, but avatar projects and projects without the VRChat SDK are supported in a limited capacity.
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). Pull requests are also welcome.
## Setup
### Requirements
* Unity 2022.3.x
### Getting Started
* If you are not using VRChat Creator Companion, you can import the Unity Package from the latest release from [here](https://github.com/oneVR/VRWorldToolkit/releases) into your Unity project
* When using VRChat Creator Companion, you can find the VRWorld Toolkit from the built-in Curated repositories.
* After importing, you will see the VRWorld Toolkit dropdown appear in the toolbar if not check [Troubleshooting](#troubleshooting)
### Troubleshooting
> [!IMPORTANT]
> First, if you are working on a VRChat project, make sure you are running the latest SDK version if not [update](https://creators.vrchat.com/sdk/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* currently have these, 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 that added them to your project.
A rare issue can also be 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://github.com/oneVR/VRWorldToolkit/assets/4764355/52c0c25c-c3e9-4b73-8e88-b4e10c884040">
### World Debugger
Goes through the scene, 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 scene's world ID to the clipboard without having to fumble trying to find 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 of where the pedestal image will appear in-game when you select the GameObject with the pedestal component on it
## 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 with 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!*

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6951d11f20831894aadd8a27299ba677
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 831f8764e30b4254cafd8a1d246123cc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 27314978a241be24d85e5e1cad1e4236
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 472b0d41b861604469188907bc9a05c0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -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:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f6fabb62862200044840f6fa004668d2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eaac6f7291834264f97854154e89bf76
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b6e7922a4d527d54a9a279a71c067c5d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -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:

View File

@ -0,0 +1,23 @@
{
"name": "dev.onevr.vrworldtoolkit",
"version": "3.4.1",
"displayName": "VRWorld Toolkit",
"description": "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.",
"unity": "2022.3",
"documentationUrl": "https://github.com/oneVR/VRWorldToolkit",
"licensesUrl": "https://github.com/oneVR/VRWorldToolkit/blob/master/LICENSE",
"dependencies": {
"com.unity.postprocessing": "3.1.1"
},
"vpmDependencies": {
},
"url" : "https://github.com/oneVR/VRWorldToolkit.git#vpm",
"author": {
"name": "oneVRdev",
"email": "15145@pm.me",
"url": "https://oneVR.dev/"
},
"legacyFolders": {
"Assets\\VRWorldToolkit": "fb6f58799fddd184a94ea8cd32c9db5a"
}
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c5411ff6b13745d4098377433f74bc9f
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: