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: 8a5eb0ad795b9544799dec3b042b6af9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

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

View File

@ -0,0 +1,101 @@
/************************************************************************************
Filename : ONSPAudioSourceEditor.cs
Content : This script adds editor functionality to OculusSpatializerUserParams script.
Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
Licensed under the Oculus SDK Version 3.5 (the "License");
you may not use the Oculus SDK except in compliance with the License,
which is provided at the time of installation or download, or which
otherwise accompanies this software in either electronic or hard copy form.
You may obtain a copy of the License at
https://developer.oculus.com/licenses/sdk-3.5/
Unless required by applicable law or agreed to in writing, the Oculus SDK
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************************/
#define CUSTOM_LAYOUT
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
[CustomEditor(typeof(ONSPAudioSource))]
public class OculusSpatializerUserParamsEditor : Editor
{
// target component
private ONSPAudioSource m_Component;
// OnEnable
void OnEnable()
{
m_Component = (ONSPAudioSource)target;
}
// OnInspectorGUI
public override void OnInspectorGUI()
{
GUI.color = Color.white;
Undo.RecordObject(m_Component, "OculusSpatializerUserParams");
{
EditorGUILayout.HelpBox("Please use a VRC_SpatialAudioSource in the future.", MessageType.Error);
#if CUSTOM_LAYOUT
m_Component.EnableSpatialization = EditorGUILayout.Toggle("Spatialization Enabled", m_Component.EnableSpatialization);
m_Component.EnableRfl = EditorGUILayout.Toggle("Reflections Enabled", m_Component.EnableRfl);
m_Component.Gain = EditorGUILayout.FloatField("Gain", m_Component.Gain);
Separator();
Label ("OCULUS ATTENUATION");
m_Component.UseInvSqr = EditorGUILayout.Toggle("Enabled", m_Component.UseInvSqr);
Label ("");
Label("RANGE (0.0 - 1000000.0 meters)");
m_Component.Near = EditorGUILayout.FloatField("Minimum", m_Component.Near);
m_Component.Far = EditorGUILayout.FloatField("Maximum", m_Component.Far);
Label("");
Label("VOLUMETRIC RADIUS (0.0 - 1000.0 meters)");
m_Component.VolumetricRadius = EditorGUILayout.FloatField("Radius", m_Component.VolumetricRadius);
Separator();
Label("REVERB SEND LEVEL (-60.0 - 20.0 decibels)");
m_Component.ReverbSend = EditorGUILayout.FloatField(" ", m_Component.ReverbSend);
Separator();
#else
DrawDefaultInspector ();
#endif
}
if (GUI.changed)
{
EditorUtility.SetDirty(m_Component);
}
}
// Utilities, move out of here (or copy over to other editor script)
// Separator
void Separator()
{
GUI.color = new Color(1, 1, 1, 0.25f);
GUILayout.Box("", "HorizontalSlider", GUILayout.Height(16));
GUI.color = Color.white;
}
// Label
void Label(string label)
{
EditorGUILayout.LabelField (label);
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: cb850b86de9091d4db4595959c56f954
timeCreated: 1442269815
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c4c0a58edfe7425bb1e4b7a5de9a87b1
timeCreated: 1683056861

View File

@ -0,0 +1,8 @@
namespace VRC.SDKBase.Editor.Api
{
public interface IVRCContent
{
string ID { get; set; }
string Name { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2970d5a709404efb9249205c86afaf20
timeCreated: 1687867386

View File

@ -0,0 +1,32 @@
using Newtonsoft.Json;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCAgreement
{
[JsonProperty("id")]
public string ID { get; set; }
public string AgreementCode { get; set; }
public string ContentId { get; set; }
public string AgreementFulltext { get; set; }
public int Version { get; set; }
public string[] Tags { get; set; }
}
public struct VRCAgreementCheckRequest
{
public string UserId { get; set; }
public string AgreementCode { get; set; }
public string ContentId { get; set; }
public int Version { get; set; }
}
public struct VRCAgreementCheckResponse
{
public bool Agreed { get; set; }
public string UserId { get; set; }
public string AgreementCode { get; set; }
public string ContentId { get; set; }
public int Version { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e4a6b18f112e459c871dee35e8dc2858
timeCreated: 1739229610

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using UnityEditor;
namespace VRC.SDKBase.Editor.Api
{
[InitializeOnLoad]
internal static class VRCApiCache
{
private static long DEFAULT_CACHE_TIME;
private static Dictionary<string, (DateTime timestamp, object data)> _cache;
static VRCApiCache()
{
_cache = new Dictionary<string, (DateTime timestamp, object data)>();
DEFAULT_CACHE_TIME = 1000 * 60 * 1; // 1 minute
}
public static T Add<T>(string key, T value)
{
_cache[key] = (DateTime.UtcNow, value);
return value;
}
public static T Get<T>(string key, out bool cached)
{
if (_cache.TryGetValue(key, out var value))
{
if (DateTime.UtcNow.Subtract(value.timestamp).TotalMilliseconds < DEFAULT_CACHE_TIME)
{
cached = true;
return (T) value.data;
}
cached = false;
return default;
}
cached = false;
return default;
}
public static void Invalidate(string key)
{
_cache.Remove(key);
}
public static void Clear()
{
_cache = new Dictionary<string, (DateTime timestamp, object data)>();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c2861b3597c849e08c2126c83ef3fca7
timeCreated: 1683145545

View File

@ -0,0 +1,12 @@
namespace VRC.SDKBase.Editor.Api
{
public struct VRCApiError
{
public VRCApiErrorContent Error { get; set; }
public struct VRCApiErrorContent {
public string Message { get; set; }
public int Code { get; set; }
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 67fd710f3e92422eba267779143a9c5f
timeCreated: 1687964156

View File

@ -0,0 +1,59 @@
using System;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using Newtonsoft.Json;
[assembly: InternalsVisibleTo("VRC.SDK3A.Editor")]
[assembly: InternalsVisibleTo("VRC.SDK3.Editor")]
namespace VRC.SDKBase.Editor.Api
{
/// <summary>
/// VRCApi request failed
/// </summary>
public class RequestFailedException : Exception
{
public HttpResponseMessage HttpMessage;
public HttpStatusCode StatusCode;
public RequestFailedException(string message) : base(message)
{
}
public RequestFailedException(string message, HttpResponseMessage httpMessage) : base(message)
{
HttpMessage = httpMessage;
}
public RequestFailedException(string message, HttpResponseMessage httpMessage, HttpStatusCode statusCode) : base(message)
{
HttpMessage = httpMessage;
StatusCode = statusCode;
}
}
public class JsonSerializationException : Exception
{
public JsonSerializationException(string message, Exception innerException) : base(message, innerException)
{
}
}
/// <summary>
/// VRChat API returned an error
/// </summary>
public class ApiErrorException : Exception
{
public HttpResponseMessage HttpMessage;
public HttpStatusCode StatusCode;
public string ErrorMessage;
public ApiErrorException(HttpResponseMessage httpMessage, string jsonContent)
{
var json = JsonConvert.DeserializeObject<VRCApiError>(jsonContent, VRCApi.JSON_OPTIONS);
HttpMessage = httpMessage;
StatusCode = httpMessage.StatusCode;
ErrorMessage = json.Error.Message;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 536cf9130a7e41a19f0d7e5d7900210d
timeCreated: 1683135644

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCAssetReviewNotesRequest
{
public string ReviewNotes { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 37f2155d6021416b8ad57feb5216957d
timeCreated: 1743116496

View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using VRC.Core;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCAvatar: IVRCContent
{
public enum AvatarVariant
{
Standard,
Impostor
}
public struct AvatarStyles
{
public string Primary { get; set; }
public string Secondary { get; set; }
}
[JsonProperty("id")]
public string ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<string> Tags { get; set; }
public string AuthorName { get; set; }
public string AuthorId { get; set; }
public string ImageUrl { get; set; }
public string ThumbnailImageUrl { get; set; }
public string ReleaseStatus { get; set; }
public AvatarStyles Styles { get; set; }
public bool Lock { get; set; }
public string ActiveAssetReviewId { get; set; }
public bool PendingUpload { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty("updated_at")]
public DateTime UpdatedAt { get; set; }
public int Version { get; set; }
public List<VRCUnityPackage> UnityPackages { get; set; }
public bool Featured { get; set; }
public string UnityPackageUrl { get; set; }
public Dictionary<string, string> UnityPackageUrlObject { get; set; }
public string GetLatestAssetUrlForPlatform(string platform)
{
string assetUrl = null;
var preferredUnityVersion = new UnityVersion();
if (this.UnityPackages == null) return null;
foreach (var unityPackage in this.UnityPackages)
{
if (UnityVersion.Parse(unityPackage.UnityVersion).CompareTo(preferredUnityVersion) < 0) continue;
if (unityPackage.Variant != null)
{
AvatarVariant variant = (AvatarVariant)Enum.Parse(typeof(AvatarVariant), unityPackage.Variant, true);
if (variant == AvatarVariant.Impostor) continue;
}
if (unityPackage.Platform != platform) continue;
assetUrl = unityPackage.AssetUrl;
preferredUnityVersion = UnityVersion.Parse(unityPackage.UnityVersion);
}
return assetUrl;
}
public string GetLatestAssetUrlForCurrentPlatform()
{
return GetLatestAssetUrlForPlatform(Tools.Platform);
}
/// <summary>
/// Checks if user-editable data is equal between avatar records
/// </summary>
/// <param name="target"></param>
/// <returns></returns>
public bool ContentInfoEqual(VRCAvatar target)
{
return target.Name.Equals(Name) &&
target.Description.Equals(Description) &&
target.Tags.SequenceEqual(Tags) &&
target.ReleaseStatus.Equals(ReleaseStatus);
}
}
// Only a subset of fields is allowed to be changed through the SDK
public struct VRCAvatarChanges {
public string Name { get; set; }
public string Description { get; set; }
public List<string> Tags { get; set; }
public string ReleaseStatus { get; set; }
// Styles should be submitted via style ID and not the style Name
public string PrimaryStyle { get; set; }
public string SecondaryStyle { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 93e3e8f8e94746a6b83e7431081ef622
timeCreated: 1683135174

View File

@ -0,0 +1,12 @@
using Newtonsoft.Json;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCAvatarStyle
{
[JsonProperty("id")]
public string ID { get; set; }
public string StyleName { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a53e0d0d4a9549dbbb6fedba8fec4f2d
timeCreated: 1744068776

View File

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCFile
{
[JsonProperty("id")]
public string ID { get; set; }
public string Name { get; set; }
public string OwnerId { get; set; }
public string MimeType { get; set; }
public string Extension { get; set; }
public List<VersionEntry> Versions { get; set; }
public class VersionEntry
{
public int Version { get; set; }
public string Status { get; set; }
public DateTime CreatedAt { get; set; }
public bool Deleted { get; set; }
public FileDescriptor File { get; set; }
public FileDescriptor Signature { get; set; }
public FileDescriptor Delta { get; set; }
public class FileDescriptor
{
public string Status { get; set; }
public string URL { get; set; }
public string MD5 { get; set; }
public string Category { get; set; }
public int SizeInBytes { get; set; }
public string FileName { get; set; }
public string UploadId { get; set; }
[JsonProperty("cdns")]
public List<string> CDNs { get; set; }
}
}
public int GetLatestVersion()
{
return (this.Versions?.Count ?? 0) - 1;
}
/// <summary>
/// Returns true if there is a valid version that is not deleted.
/// </summary>
public bool HasExistingOrPendingVersion()
{
var latestVersion = GetLatestVersion();
if (latestVersion > 0)
{
latestVersion -= Versions.Count(v => v == null || v.Deleted);
}
return latestVersion > 0;
}
public bool IsLatestVersionWaiting()
{
if (!HasExistingOrPendingVersion()) return false;
var version = Versions[GetLatestVersion()];
if (version.Status == "waiting") return true;
return ((version.File?.Status == "waiting") ||
(version.Signature?.Status == "waiting"));
}
public bool IsLatestVersionQueued()
{
if (!HasExistingOrPendingVersion()) return false;
var version = Versions[GetLatestVersion()];
if (version.Status == "queued") return true;
return ((version.File?.Status == "queued") ||
(version.Signature?.Status == "queued"));
}
public bool IsLatestVersionErrored()
{
if (!HasExistingOrPendingVersion()) return false;
var version = Versions[GetLatestVersion()];
if (version.Status == "error") return true;
return ((version.File?.Status == "error") ||
(version.Signature?.Status == "error"));
}
public bool HasQueuedOperation()
{
if (IsLatestVersionWaiting()) return false;
return HasExistingOrPendingVersion() && IsLatestVersionQueued();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 45cf16ea678f4615920c2d510d154633
timeCreated: 1686655895

View File

@ -0,0 +1,48 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using VRC.Core;
namespace VRC.SDKBase.Editor.Api
{
internal class VRCProgressContent: HttpContent
{
private readonly HttpContent _source;
private readonly Action<float> _onProgress;
public VRCProgressContent(HttpContent source, Action<float> onProgress)
{
_source = source;
_onProgress = onProgress;
}
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
var sendBuffer = new byte[4 * 1024 * 1024];
var totalBytesRead = 0L;
using (var inputStream = await _source.ReadAsStreamAsync())
{
var totalBytes = inputStream.Length;
var bytesRead = 0;
while ((bytesRead = await inputStream.ReadAsync(sendBuffer, 0, sendBuffer.Length)) > 0)
{
await stream.WriteAsync(sendBuffer, 0, bytesRead);
totalBytesRead += bytesRead;
_onProgress((float)totalBytesRead / totalBytes);
Core.Logger.Log($"Sent {totalBytesRead} out of {totalBytes}", API.LOG_CATEGORY);
}
}
}
protected override bool TryComputeLength(out long length)
{
length = _source.Headers.ContentLength.GetValueOrDefault();
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 685a233b2bbf4a99a5f62f2d9727f484
timeCreated: 1686669873

View File

@ -0,0 +1,164 @@
using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
[assembly: InternalsVisibleTo("VRC.SDK3A.Editor")]
[assembly: InternalsVisibleTo("VRC.SDK3.Editor")]
namespace VRC.SDKBase.Editor.Api
{
internal class VRCTools
{
internal static byte[] GetFileMD5(string filePath)
{
var hash = MD5.Create();
using var fileStream = File.OpenRead(filePath);
return hash.ComputeHash(fileStream);
}
internal static async Task<string> GenerateFileSignature(string sourceFilePath, string targetFilePath)
{
await using var fileStream = File.OpenRead(sourceFilePath);
await using var inStream = librsync.net.Librsync.ComputeSignature(fileStream);
await using var signatureStream = File.Open(targetFilePath, FileMode.Create, FileAccess.Write);
await inStream.CopyToAsync(signatureStream);
return targetFilePath;
}
internal static async Task CleanupTempFiles(string fileId)
{
var folder = VRC.Tools.GetTempFolderPath(fileId);
while (Directory.Exists(folder))
{
try
{
if (Directory.Exists(folder))
Directory.Delete(folder, true);
}
catch (System.Exception)
{
// ignored
}
await Task.Delay(10);
}
}
internal static string GetMimeTypeFromExtension(string extension)
{
if (extension == ".vrcw")
return "application/x-world";
if (extension == ".vrca")
return "application/x-avatar";
if (extension == ".vrcp")
return "application/x-prop";
if (extension == ".dll")
return "application/x-msdownload";
if (extension == ".unitypackage")
return "application/gzip";
if (extension == ".gz")
return "application/gzip";
if (extension == ".jpg")
return "image/jpg";
if (extension == ".png")
return "image/png";
if (extension == ".sig")
return "application/x-rsync-signature";
if (extension == ".delta")
return "application/x-rsync-delta";
return "application/octet-stream";
}
/// <summary>
/// This expands the send buffer size from around 256KB up to 4MB (our preferred send buffer size)
/// This dramatically speeds up file uploads
///
/// Unfortunately, APIs meant to be used for this aren't available in Mono version of .NET in Unity
/// So we have to use reflection to get to the private fields and properties we need
/// </summary>
/// <param name="targetUrl">Url to expand the send buffer for</param>
/// <param name="sendRequest">Request task to expand the buffer for</param>
/// <param name="cancellationToken"></param>
internal static async Task IncreaseSendBuffer(Uri targetUrl, Task sendRequest,
CancellationToken cancellationToken)
{
var servicePointScheduler = typeof(ServicePoint).GetProperty("Scheduler", BindingFlags.NonPublic | BindingFlags.Instance);
var servicePointGroups = servicePointScheduler?.PropertyType.GetField("groups", BindingFlags.NonPublic | BindingFlags.Instance);
var groupsList = servicePointGroups?.FieldType.GetProperty("Values");
var connectionStateType = servicePointGroups?.FieldType.GenericTypeArguments[1];
var connectionsList = connectionStateType?.GetField("connections", BindingFlags.NonPublic | BindingFlags.Instance);
var connection = connectionsList?.FieldType.GenericTypeArguments[0];
var socket = connection?.GetField("socket", BindingFlags.NonPublic | BindingFlags.Instance);
while (!sendRequest.IsCompleted && !cancellationToken.IsCancellationRequested)
{
await Task.Delay(250, cancellationToken);
try
{
var servicePoint = ServicePointManager.FindServicePoint(targetUrl);
var scheduler = servicePointScheduler?.GetValue(servicePoint);
if (scheduler == null)
{
continue;
}
// This can be null on mac/linux, so we add an extra check
var servicePointGroup = servicePointGroups?.GetValue(scheduler);
if (servicePointGroup == null)
{
continue;
}
var groups = (IEnumerable) groupsList?.GetValue(servicePointGroup);
// we're going to retry finding the active service point
if (groups == null)
{
continue;
}
foreach (var group in groups)
{
var connections = (IEnumerable) connectionsList?.GetValue(group);
if (connections == null)
{
continue;
}
foreach (var webConnection in connections)
{
if (webConnection == null)
{
continue;
}
var socketInstance = (Socket) socket?.GetValue(webConnection);
if (socketInstance != null && socketInstance.Connected &&
socketInstance.SendBufferSize < 4 * 1024 * 1024)
{
socketInstance.SendBufferSize = 4 * 1024 * 1024;
return;
}
}
}
}
catch (Exception e)
{
Core.Logger.LogWarning($"Failed to increase send buffer {e.Message}", Core.API.LOG_CATEGORY);
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e259a399dbb4ef19a7a89d2b4233247
timeCreated: 1686658578

View File

@ -0,0 +1,20 @@
using System;
using Newtonsoft.Json;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCUnityPackage
{
[JsonProperty("id")]
public string ID { get; set; }
public string AssetUrl { get; set; }
public string UnityVersion { get; set; }
public long UnitySortNumber { get; set; }
public int AssetVersion { get; set; }
public string Platform { get; set; }
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
public string Variant { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f7f09500761d4a019e606df903a022c8
timeCreated: 1683134817

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using VRC.Core;
namespace VRC.SDKBase.Editor.Api
{
public struct VRCWorld: IVRCContent
{
[JsonProperty("id")]
public string ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string PreviewYoutubeId { get; set; }
public List<string> Tags { get; set; }
public List<string> UdonProducts { get; set; }
public string AuthorName { get; set; }
public string AuthorId { get; set; }
public string ImageUrl { get; set; }
public string ThumbnailImageUrl { get; set; }
public string ReleaseStatus { get; set; }
public int Capacity { get; set; }
public int RecommendedCapacity { get; set; }
public int Favorites { get; set; }
public int Visits { get; set; }
// public int Popularity { get; set; } // this field doesn't deserialize correctly for VERY popular worlds, ignoring in SDK for now
public int Heat { get; set; }
public int Occupants { get; set; }
public int PublicOccupants { get; set; }
public int PrivateOccupants { get; set; }
public List<Instance> Instances { get; set; }
public struct Instance
{
public string ID { get; set; }
public int Occupants { get; set; }
}
[JsonProperty("created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty("updated_at")]
public DateTime UpdatedAt { get; set; }
public DateTime PublicationDate { get; set; }
public DateTime LabsPublicationDate { get; set; }
public int Version { get; set; }
public List<VRCUnityPackage> UnityPackages { get; set; }
public string Organization { get; set; }
public bool Featured { get; set; }
public string GetLatestAssetUrlForPlatform(string platform)
{
string assetUrl = null;
var preferredUnityVersion = new UnityVersion();
if (this.UnityPackages == null) return null;
foreach (var unityPackage in this.UnityPackages)
{
if (UnityVersion.Parse(unityPackage.UnityVersion).CompareTo(preferredUnityVersion) < 0) continue;
if (unityPackage.Platform != platform) continue;
assetUrl = unityPackage.AssetUrl;
preferredUnityVersion = UnityVersion.Parse(unityPackage.UnityVersion);
}
return assetUrl;
}
}
// Only a subset of fields is allowed to be changed through the SDK
public struct VRCWorldChanges {
public string Name { get; set; }
public string Description { get; set; }
public int Capacity { get; set; }
public int RecommendedCapacity { get; set; }
public string PreviewYoutubeId { get; set; }
public List<string> Tags { get; set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bcf1554494894265b68fbf2e7c089782
timeCreated: 1683134291

View File

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

View File

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

View File

@ -0,0 +1,18 @@
#if VRC_SDK_PIPELINE_SAMPLES
using UnityEditor;
namespace VRC.SDKBase.Editor.BuildPipeline.Samples
{
public class VRCSDKBuildRequestedCallbackSample : IVRCSDKBuildRequestedCallback
{
public int callbackOrder => 0;
public bool OnBuildRequested(VRCSDKRequestedBuildType requestedBuildType)
{
return EditorUtility.DisplayDialog("Build Confirmation", "Are you sure you want to build?", "Yes", "Not Yes");
}
}
}
#endif

View File

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

View File

@ -0,0 +1,12 @@
{
"name": "VRC.SDKBase.Editor.BuildPipeline",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": []
}

View File

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

View File

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

View File

@ -0,0 +1,230 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
using VRC.SDKBase;
[InitializeOnLoad]
public class AutoAddSpatialAudioComponents
{
public static bool Enabled = true;
static AutoAddSpatialAudioComponents()
{
EditorApplication.hierarchyChanged += OnHierarchyWindowChanged;
EditorApplication.projectChanged += OnProjectWindowChanged;
RegisterCallbacks();
}
static void OnHierarchyWindowChanged()
{
if (!Enabled)
{
EditorApplication.hierarchyChanged -= OnHierarchyWindowChanged;
return;
}
// check for proper use of VRCSP, and warn
//TryToAddSpatializationToAllAudioSources(true, false);
}
static void OnProjectWindowChanged()
{
RegisterCallbacks();
}
static void RegisterCallbacks()
{
VRCSdkControlPanel._EnableSpatialization = VRCSDKControlPanel_EnableSpatialization;
}
// callback from VrcSdkControlPanel in dll
public static void VRCSDKControlPanel_EnableSpatialization()
{
Debug.Log("Enabling spatialization on 3D AudioSources...");
TryToAddSpatializationToAllAudioSources(false, true);
}
static bool ApplyDefaultSpatializationToAudioSource(AudioSource audioSrc, bool force = false)
{
if (audioSrc == null)
return false;
var vrcsp = audioSrc.gameObject.GetComponent<VRC.SDKBase.VRC_SpatialAudioSource>();
// don't make changes if we already have a vrcsp and we aren't forcing
if (vrcsp != null && !force)
return false;
if (force)
audioSrc.spatialBlend = 1;
bool initValues = force;
// is audio source set to be 2D?
bool is2D = audioSrc.spatialBlend == 0;
if (vrcsp == null)
{
// no onsp and no vrcsp, so add
vrcsp = audioSrc.gameObject.AddComponent<VRC.SDKBase.VRC_SpatialAudioSource>();
if (is2D)
{
// this audio source was marked as 2D, leave the vrcsp disabled
vrcsp.EnableSpatialization = false;
}
initValues = true;
}
audioSrc.spatialize = vrcsp.EnableSpatialization;
vrcsp.enabled = true;
if (initValues)
{
bool isAvatar = audioSrc.GetComponentInParent<VRC.SDKBase.VRC_AvatarDescriptor>();
vrcsp.Gain = isAvatar ? AudioManagerSettings.AvatarAudioMaxGain : AudioManagerSettings.RoomAudioGain;
vrcsp.Near = 0;
vrcsp.Far = isAvatar ? AudioManagerSettings.AvatarAudioMaxRange : AudioManagerSettings.RoomAudioMaxRange;
vrcsp.UseAudioSourceVolumeCurve = false;
}
return true;
}
public static void TryToAddSpatializationToAllAudioSources(bool newAudioSourcesOnly, bool includeInactive)
{
AudioSource[] allAudioSources = includeInactive ? Resources.FindObjectsOfTypeAll<AudioSource>() : Object.FindObjectsByType<AudioSource>(FindObjectsSortMode.None);
foreach (AudioSource src in allAudioSources)
{
if (src == null || src.gameObject == null || src.gameObject.scene != UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene())
{
continue;
}
if (newAudioSourcesOnly)
{
if (!IsNewAudioSource(src))
continue;
UnityEngine.Audio.AudioMixerGroup mixer = AssetDatabase.LoadAssetAtPath<UnityEngine.Audio.AudioMixerGroup>("Assets/VRCSDK/Dependencies/OSPNative/scenes/mixers/SpatializerMixer.mixer");
if (mixer != null)
{
src.outputAudioMixerGroup = mixer;
}
}
if (ApplyDefaultSpatializationToAudioSource(src, false))
{
Debug.Log("Automatically added VRC_SpatialAudioSource component to " + GetGameObjectPath(src.gameObject) + "!");
}
}
}
static bool IsNewAudioSource(AudioSource src)
{
var vrcsp = src.GetComponent<VRC_SpatialAudioSource>();
if (vrcsp != null)
return false;
if (src.clip != null)
return false;
if (src.outputAudioMixerGroup != null)
return false;
if (src.mute || src.bypassEffects || src.bypassReverbZones || !src.playOnAwake || src.loop)
return false;
if (src.priority != 128 ||
!Mathf.Approximately(src.volume, 1.0f) ||
!Mathf.Approximately(src.pitch, 1.0f) ||
!Mathf.Approximately(src.panStereo, 0.0f) ||
!Mathf.Approximately(src.spatialBlend, 0.0f) ||
!Mathf.Approximately(src.reverbZoneMix, 1.0f))
{
return false;
}
if (!Mathf.Approximately(src.dopplerLevel, 1.0f) ||
!Mathf.Approximately(src.spread, 0.0f) ||
src.rolloffMode != AudioRolloffMode.Logarithmic ||
!Mathf.Approximately(src.minDistance, 1.0f) ||
!Mathf.Approximately(src.maxDistance, 500.0f))
{
return false;
}
return true;
}
static string GetGameObjectPath(GameObject obj)
{
string path = "/" + obj.name;
while (obj.transform.parent != null)
{
obj = obj.transform.parent.gameObject;
path = "/" + obj.name + path;
}
return path;
}
public static void ConvertONSPAudioSource(AudioSource src)
{
if (src == null) return;
var onsp = src.GetComponent<ONSPAudioSource>();
if (onsp != null)
{
var vrcsp = src.gameObject.GetComponent<VRC.SDKBase.VRC_SpatialAudioSource>();
if (vrcsp == null)
{
// copy the values from deprecated component
vrcsp = src.gameObject.AddComponent<VRC.SDKBase.VRC_SpatialAudioSource>();
vrcsp.Gain = onsp.Gain;
vrcsp.Near = onsp.Near;
vrcsp.Far = onsp.Far;
vrcsp.UseAudioSourceVolumeCurve = !onsp.UseInvSqr;
vrcsp.EnableSpatialization = onsp.EnableSpatialization;
}
// remove deprecated component
Component.DestroyImmediate(onsp);
}
}
public static void AddVRCSpatialToBareAudioSource(AudioSource src)
{
if (src == null) return;
var vrcsp = src.gameObject.GetComponent<VRC.SDKBase.VRC_SpatialAudioSource>();
if (vrcsp != null) return;
#if VRC_SDK_VRCSDK2
vrcsp = src.gameObject.AddComponent<VRCSDK2.VRC_SpatialAudioSource>();
#elif UDON
vrcsp = src.gameObject.AddComponent<VRC.SDK3.Components.VRCSpatialAudioSource>();
#endif
// add default values
bool isAvatar = src.gameObject.GetComponentInParent<VRC.SDKBase.VRC_AvatarDescriptor>();
vrcsp.Gain = isAvatar ? AudioManagerSettings.AvatarAudioMaxGain : AudioManagerSettings.RoomAudioGain;
vrcsp.Near = 0;
vrcsp.Far = isAvatar ? AudioManagerSettings.AvatarAudioMaxRange : AudioManagerSettings.RoomAudioMaxRange;
vrcsp.UseAudioSourceVolumeCurve = false;
// enable spatialization if src is not 2D
vrcsp.EnableSpatialization = false;
AnimationCurve curve = src.GetCustomCurve(AudioSourceCurveType.SpatialBlend);
if (curve != null)
{
foreach (var key in curve.keys)
{
if (key.value != 0 || key.inTangent != 0)
{
vrcsp.EnableSpatialization = true;
break;
}
}
}
}
}

View File

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

View File

@ -0,0 +1,62 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
public class EditorCoroutine
{
public static EditorCoroutine Start( IEnumerator _routine )
{
EditorCoroutine coroutine = new EditorCoroutine(_routine);
coroutine.start();
return coroutine;
}
public static EditorCoroutine Start(System.Action _action)
{
EditorCoroutine coroutine = new EditorCoroutine(_action);
coroutine.start();
return coroutine;
}
readonly IEnumerator routine;
EditorCoroutine( IEnumerator _routine )
{
routine = _routine;
}
readonly System.Action action;
EditorCoroutine(System.Action _action)
{
action = _action;
}
void start()
{
EditorApplication.update += update;
}
public void stop()
{
EditorApplication.update -= update;
}
void update()
{
if (routine != null)
{
if (!routine.MoveNext())
stop();
}
else if (action != null)
{
action();
stop();
}
else
stop();
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 89005ebc9543e0a4284893c09ca19b1d
timeCreated: 1473271738
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,17 @@
using UnityEditor;
using UnityEngine.SceneManagement;
[InitializeOnLoad]
public static class EditorHandling
{
static EditorHandling()
{
UnityEditor.SceneManagement.EditorSceneManager.sceneOpened += SceneOpenedCallback;
}
static void SceneOpenedCallback( Scene scene, UnityEditor.SceneManagement.OpenSceneMode mode)
{
// refresh window when scene is opened to display content images correctly
if (null != VRCSdkControlPanel.window) VRCSdkControlPanel.window.Reset();
}
}

View File

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

View File

@ -0,0 +1,358 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.Collections.Generic;
using System.Linq;
using VRC.SDKBase;
namespace VRCSDK2
{
#if VRC_SDK_VRCSDK2
[CustomEditor(typeof(VRCSDK2.VRC_EventHandler))]
public class EventHandlerEditor : UnityEditor.Editor
{
bool showDeferredEvents = false;
static VRCSDK2.VRC_EventHandler.VrcEventType lastAddedEventType = VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage;
public override void OnInspectorGUI()
{
VRCSDK2.VRC_EventHandler myTarget = (VRCSDK2.VRC_EventHandler)target;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("ID:");
EditorGUILayout.EndHorizontal();
if (myTarget.GetComponent<VRCSDK2.VRC_Trigger>() != null)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Add Events via the VRC_Trigger on this object.");
EditorGUILayout.EndHorizontal();
}
else
{
EditorGUI.BeginChangeCheck();
RenderOldEditor(myTarget);
if (EditorGUI.EndChangeCheck())
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
if (myTarget.deferredEvents.Count > 0)
{
showDeferredEvents = EditorGUILayout.Foldout(showDeferredEvents, "Deferred Events");
if (showDeferredEvents)
RenderEvents(myTarget.deferredEvents);
}
}
int[] sendMessageMethodIndicies;
private void RenderOldEditor(VRCSDK2.VRC_EventHandler myTarget)
{
EditorGUILayout.HelpBox("Please use a VRC_Trigger in the future.", MessageType.Error);
if (GUILayout.Button("Add Event Handler"))
myTarget.Events.Add(new VRCSDK2.VRC_EventHandler.VrcEvent());
bool first = true;
int deleteEventIndex = -1;
if (sendMessageMethodIndicies == null || sendMessageMethodIndicies.Length != myTarget.Events.Count)
sendMessageMethodIndicies = new int[myTarget.Events.Count + 1];
for (int i = 0; i < myTarget.Events.Count; ++i)
{
if (!first)
EditorGUILayout.Separator();
first = false;
EditorGUILayout.LabelField("Event " + (i + 1).ToString());
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Event Name");
myTarget.Events[i].Name = EditorGUILayout.TextField(myTarget.Events[i].Name);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Event Type");
myTarget.Events[i].EventType = (VRCSDK2.VRC_EventHandler.VrcEventType)EditorGUILayout.EnumPopup(myTarget.Events[i].EventType);
EditorGUILayout.EndHorizontal();
switch (myTarget.Events[i].EventType)
{
case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationBool:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Variable");
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Operation");
myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationFloat:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Variable");
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Value");
myTarget.Events[i].ParameterFloat = EditorGUILayout.FloatField(myTarget.Events[i].ParameterFloat);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationTrigger:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Trigger");
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.AudioTrigger:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("AudioSource");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.MeshVisibility:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Mesh");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Operation");
myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.PlayAnimation:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Target");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Animation");
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.RunConsoleCommand:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Command");
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Receiver");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Message");
// sorry for this shit show. Below allows us to show a list of public methods, but also allow custom messages
var methods = VRC_EditorTools.GetAccessibleMethodsOnGameObject(myTarget.Events[i].ParameterObject);
List<string> methodList = methods.Values.Aggregate(new List<string>(), (acc, lst) => { acc.AddRange(lst.Select(mi => mi.Name)); return acc; });
methodList.Add("Custom Message");
string[] _choices = methodList.ToArray();
int currentIndex = methodList.Count - 1;
if (methodList.Contains(myTarget.Events[i].ParameterString))
currentIndex = methodList.IndexOf(myTarget.Events[i].ParameterString);
sendMessageMethodIndicies[i] = EditorGUILayout.Popup(currentIndex, _choices);
if (sendMessageMethodIndicies[i] != methodList.Count - 1)
{
myTarget.Events[i].ParameterString = _choices[sendMessageMethodIndicies[i]];
}
else
{
if (methodList.Contains(myTarget.Events[i].ParameterString))
myTarget.Events[i].ParameterString = "";
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
}
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.SetGameObjectActive:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("GameObject");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Operation");
myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.SetParticlePlaying:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Target");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Operation");
myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.TeleportPlayer:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Location");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Align Room To Destination");
myTarget.Events[i].ParameterBoolOp = (VRCSDK2.VRC_EventHandler.VrcBooleanOp)EditorGUILayout.EnumPopup(myTarget.Events[i].ParameterBoolOp);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelURI:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("URI");
myTarget.Events[i].ParameterString = EditorGUILayout.TextField(myTarget.Events[i].ParameterString);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Panel");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
break;
case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelVolume:
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Volume");
myTarget.Events[i].ParameterFloat = EditorGUILayout.FloatField(myTarget.Events[i].ParameterFloat);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Panel");
myTarget.Events[i].ParameterObject = (GameObject)EditorGUILayout.ObjectField(myTarget.Events[i].ParameterObject, typeof(GameObject), true);
EditorGUILayout.EndHorizontal();
break;
default:
EditorGUILayout.BeginHorizontal();
GUIStyle redText = new GUIStyle();
redText.normal.textColor = Color.red;
EditorGUILayout.LabelField("Unsupported event type", redText);
EditorGUILayout.EndHorizontal();
break;
}
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Delete " + myTarget.Events[i].Name + "?");
if (GUILayout.Button("delete"))
deleteEventIndex = i;
EditorGUILayout.EndHorizontal();
if (myTarget.Events[i].ParameterObject == null)
myTarget.Events[i].ParameterObject = myTarget.gameObject;
}
if (deleteEventIndex != -1)
myTarget.Events.RemoveAt(deleteEventIndex);
}
private void RenderEvents(IEnumerable<VRCSDK2.VRC_EventHandler.EventInfo> entries)
{
foreach (VRCSDK2.VRC_EventHandler.EventInfo entry in entries)
{
EditorGUILayout.PrefixLabel("Target");
EditorGUILayout.ObjectField(entry.evt.ParameterObject, typeof(GameObject), true);
EditorGUILayout.LabelField(string.Format("Name: {0}", entry.evt.Name));
EditorGUILayout.LabelField(string.Format("Type: {0}", entry.evt.EventType));
EditorGUILayout.LabelField(string.Format("Bool: {0}", entry.evt.ParameterBool));
EditorGUILayout.LabelField(string.Format("Float: {0}", entry.evt.ParameterFloat));
EditorGUILayout.LabelField(string.Format("Int: {0}", entry.evt.ParameterInt));
EditorGUILayout.LabelField(string.Format("String: {0}", entry.evt.ParameterString));
EditorGUILayout.Space();
}
}
public static void RenderEditor(VRCSDK2.VRC_EventHandler myTarget)
{
bool first = true;
int deleteEventIndex = -1;
for (int i = 0; i < myTarget.Events.Count; ++i)
{
if (!first)
EditorGUILayout.Separator();
first = false;
if (RenderEventHeader(myTarget, myTarget.Events[i]))
deleteEventIndex = i;
RenderEventHeader(myTarget, myTarget.Events[i]);
if (myTarget.Events[i].ParameterObject == null)
myTarget.Events[i].ParameterObject = myTarget.gameObject;
}
if (deleteEventIndex != -1)
myTarget.Events.RemoveAt(deleteEventIndex);
}
public static VRCSDK2.VRC_EventHandler.VrcEvent RenderAddEvent(VRCSDK2.VRC_EventHandler myTarget)
{
VRCSDK2.VRC_EventHandler.VrcEvent newEvent = null;
EditorGUILayout.BeginHorizontal();
lastAddedEventType = VRC_EditorTools.FilteredEnumPopup("New Event Type", lastAddedEventType, (v) => v != VRCSDK2.VRC_EventHandler.VrcEventType.SpawnObject && v != VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage);
if (GUILayout.Button("Add"))
{
newEvent = new VRCSDK2.VRC_EventHandler.VrcEvent
{
EventType = lastAddedEventType,
ParameterObject = myTarget.gameObject
};
myTarget.Events.Add(newEvent);
EditorUtility.SetDirty(myTarget);
}
EditorGUILayout.EndHorizontal();
return newEvent;
}
public static bool RenderEventHeader(VRCSDK2.VRC_EventHandler myTarget, VRCSDK2.VRC_EventHandler.VrcEvent evt)
{
EditorGUILayout.BeginHorizontal();
evt.EventType = VRC_EditorTools.FilteredEnumPopup("New Event Type", evt.EventType, (v) => v != VRCSDK2.VRC_EventHandler.VrcEventType.SpawnObject && v != VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage);
bool delete = GUILayout.Button("Remove");
EditorGUILayout.EndHorizontal();
return delete;
}
}
[CustomEditor(typeof(VRC.SDKBase.VRC_EventHandler))]
public class SDKBaseEventHandlerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Event Handlers are not supported in VRCSDK3.");
if (GUILayout.Button("replace me with the correct VRC_EventHandler"))
{
var go = ((VRC.SDKBase.VRC_EventHandler)target).gameObject;
DestroyImmediate(target);
go.AddComponent<VRCSDK2.VRC_EventHandler>();
}
}
}
#else
[CustomEditor(typeof(VRC.SDKBase.VRC_EventHandler))]
public class SDKBaseEventHandlerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Event Handlers are not supported in VRCSDK3.");
if( GUILayout.Button("delete me") )
DestroyImmediate(target);
}
}
#endif
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4810e652e8242384c834320970702290
timeCreated: 1454469344
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,48 @@
#if VRC_SDK_VRCSDK2 && UNITY_EDITOR
#pragma warning disable 0618
using UnityEditor;
using System.Collections;
namespace VRCSDK2
{
[CustomEditor(typeof(VRCSDK2.VRC_KeyEvents))]
public class VRC_KeyEventsEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error);
}
}
[CustomEditor(typeof(VRCSDK2.VRC_UseEvents))]
public class VRC_UseEventsEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error);
}
}
[CustomEditor(typeof(VRCSDK2.VRC_TriggerColliderEventTrigger))]
public class VRC_TriggerColliderEventTriggerEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error);
}
}
[CustomEditor(typeof(VRCSDK2.VRC_TimedEvents))]
public class VRC_TimedEventsEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("Obsolete. Please use a VRC_Trigger instead.", MessageType.Error);
}
}
}
#pragma warning restore 0618
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 482185bf29f12074dada194ffef6a682
timeCreated: 1475877803
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,225 @@
#if VRC_SDK_VRCSDK2 && !VRC_CLIENT
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using VRC.SDK3.Editor;
using VRC.SDKBase.Editor;
[CustomEditor(typeof(VRCSDK2.VRC_AvatarDescriptor))]
public class AvatarDescriptorEditor : Editor
{
VRCSDK2.VRC_AvatarDescriptor avatarDescriptor;
VRC.Core.PipelineManager pipelineManager;
SkinnedMeshRenderer selectedMesh;
List<string> blendShapeNames = null;
bool shouldRefreshVisemes = false;
public override void OnInspectorGUI()
{
if (avatarDescriptor == null)
avatarDescriptor = (VRCSDK2.VRC_AvatarDescriptor)target;
if (pipelineManager == null)
{
pipelineManager = avatarDescriptor.GetComponent<VRC.Core.PipelineManager>();
if (pipelineManager == null)
avatarDescriptor.gameObject.AddComponent<VRC.Core.PipelineManager>();
}
// DrawDefaultInspector();
if(VRCSdkControlPanel.window != null)
{
if( GUILayout.Button( "Select this avatar in the SDK control panel" ) )
VRCSdkControlPanelAvatarBuilder.SelectAvatar(avatarDescriptor);
}
avatarDescriptor.ViewPosition = EditorGUILayout.Vector3Field("View Position", avatarDescriptor.ViewPosition);
//avatarDescriptor.Name = EditorGUILayout.TextField("Avatar Name", avatarDescriptor.Name);
avatarDescriptor.Animations = (VRCSDK2.VRC_AvatarDescriptor.AnimationSet)EditorGUILayout.EnumPopup("Default Animation Set", avatarDescriptor.Animations);
avatarDescriptor.CustomStandingAnims = (AnimatorOverrideController)EditorGUILayout.ObjectField("Custom Standing Anims", avatarDescriptor.CustomStandingAnims, typeof(AnimatorOverrideController), true, null);
avatarDescriptor.CustomSittingAnims = (AnimatorOverrideController)EditorGUILayout.ObjectField("Custom Sitting Anims", avatarDescriptor.CustomSittingAnims, typeof(AnimatorOverrideController), true, null);
avatarDescriptor.ScaleIPD = EditorGUILayout.Toggle("Scale IPD", avatarDescriptor.ScaleIPD);
avatarDescriptor.lipSync = (VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle)EditorGUILayout.EnumPopup("Lip Sync", avatarDescriptor.lipSync);
switch (avatarDescriptor.lipSync)
{
case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.Default:
if (GUILayout.Button("Auto Detect!"))
AutoDetectLipSync();
break;
case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBlendShape:
avatarDescriptor.VisemeSkinnedMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", avatarDescriptor.VisemeSkinnedMesh, typeof(SkinnedMeshRenderer), true);
if (avatarDescriptor.VisemeSkinnedMesh != null)
{
DetermineBlendShapeNames();
int current = -1;
for (int b = 0; b < blendShapeNames.Count; ++b)
if (avatarDescriptor.MouthOpenBlendShapeName == blendShapeNames[b])
current = b;
string title = "Jaw Flap Blend Shape";
int next = EditorGUILayout.Popup(title, current, blendShapeNames.ToArray());
if (next >= 0)
avatarDescriptor.MouthOpenBlendShapeName = blendShapeNames[next];
}
break;
case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBone:
avatarDescriptor.lipSyncJawBone = (Transform)EditorGUILayout.ObjectField("Jaw Bone", avatarDescriptor.lipSyncJawBone, typeof(Transform), true);
break;
case VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape:
SkinnedMeshRenderer prev = avatarDescriptor.VisemeSkinnedMesh;
avatarDescriptor.VisemeSkinnedMesh = (SkinnedMeshRenderer)EditorGUILayout.ObjectField("Face Mesh", avatarDescriptor.VisemeSkinnedMesh, typeof(SkinnedMeshRenderer), true);
if (avatarDescriptor.VisemeSkinnedMesh != prev)
shouldRefreshVisemes = true;
if (avatarDescriptor.VisemeSkinnedMesh != null)
{
DetermineBlendShapeNames();
if (avatarDescriptor.VisemeBlendShapes == null || avatarDescriptor.VisemeBlendShapes.Length != (int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count)
avatarDescriptor.VisemeBlendShapes = new string[(int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count];
for (int i = 0; i < (int)VRCSDK2.VRC_AvatarDescriptor.Viseme.Count; ++i)
{
int current = -1;
for (int b = 0; b < blendShapeNames.Count; ++b)
if (avatarDescriptor.VisemeBlendShapes[i] == blendShapeNames[b])
current = b;
string title = "Viseme: " + ((VRCSDK2.VRC_AvatarDescriptor.Viseme)i).ToString();
int next = EditorGUILayout.Popup(title, current, blendShapeNames.ToArray());
if (next >= 0)
avatarDescriptor.VisemeBlendShapes[i] = blendShapeNames[next];
}
if (shouldRefreshVisemes)
AutoDetectVisemes();
}
break;
}
EditorGUILayout.LabelField("Unity Version", avatarDescriptor.unityVersion);
}
void DetermineBlendShapeNames()
{
if (avatarDescriptor.VisemeSkinnedMesh != null &&
avatarDescriptor.VisemeSkinnedMesh != selectedMesh)
{
blendShapeNames = new List<string>();
blendShapeNames.Add("-none-");
selectedMesh = avatarDescriptor.VisemeSkinnedMesh;
if ((selectedMesh != null) && (selectedMesh.sharedMesh != null))
{
for (int i = 0; i < selectedMesh.sharedMesh.blendShapeCount; ++i)
blendShapeNames.Add(selectedMesh.sharedMesh.GetBlendShapeName(i));
}
}
}
void AutoDetectVisemes()
{
// prioritize strict - but fallback to looser - naming and don't touch user-overrides
List<string> blendShapes = new List<string>(blendShapeNames);
blendShapes.Remove("-none-");
for (int v = 0; v < avatarDescriptor.VisemeBlendShapes.Length; v++)
{
if (string.IsNullOrEmpty(avatarDescriptor.VisemeBlendShapes[v]))
{
string viseme = ((VRCSDK2.VRC_AvatarDescriptor.Viseme)v).ToString().ToLowerInvariant();
foreach (string s in blendShapes)
{
if (s.ToLowerInvariant() == "vrc.v_" + viseme)
{
avatarDescriptor.VisemeBlendShapes[v] = s;
goto next;
}
}
foreach (string s in blendShapes)
{
if (s.ToLowerInvariant() == "v_" + viseme)
{
avatarDescriptor.VisemeBlendShapes[v] = s;
goto next;
}
}
foreach (string s in blendShapes)
{
if (s.ToLowerInvariant().EndsWith(viseme))
{
avatarDescriptor.VisemeBlendShapes[v] = s;
goto next;
}
}
foreach (string s in blendShapes)
{
if (s.ToLowerInvariant() == viseme)
{
avatarDescriptor.VisemeBlendShapes[v] = s;
goto next;
}
}
foreach (string s in blendShapes)
{
if (s.ToLowerInvariant().Contains(viseme))
{
avatarDescriptor.VisemeBlendShapes[v] = s;
goto next;
}
}
next: { }
}
}
shouldRefreshVisemes = false;
}
void AutoDetectLipSync()
{
var smrs = avatarDescriptor.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (var smr in smrs)
{
if (smr.sharedMesh.blendShapeCount > 0)
{
avatarDescriptor.lipSyncJawBone = null;
if (smr.sharedMesh.blendShapeCount > 1)
{
avatarDescriptor.lipSync = VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.VisemeBlendShape;
avatarDescriptor.VisemeSkinnedMesh = smr;
shouldRefreshVisemes = true;
}
else
{
avatarDescriptor.lipSync = VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBlendShape;
avatarDescriptor.VisemeSkinnedMesh = null;
}
return;
}
}
Animator a = avatarDescriptor.GetComponent<Animator>();
if (!a)
EditorUtility.DisplayDialog("Ooops", "This avatar has no Animator and can have no lipsync.", "OK");
else if (a.GetBoneTransform(HumanBodyBones.Jaw) != null)
{
avatarDescriptor.lipSync = VRCSDK2.VRC_AvatarDescriptor.LipSyncStyle.JawFlapBone;
avatarDescriptor.lipSyncJawBone = avatarDescriptor.GetComponent<Animator>().GetBoneTransform(HumanBodyBones.Jaw);
avatarDescriptor.VisemeSkinnedMesh = null;
return;
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5e83254bb97e84795ac882692ae124ba
timeCreated: 1450462624
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using System.Collections;
using UnityEditor;
using System;
[CustomEditor(typeof(VRCSDK2.VRC_ObjectSpawn))]
public class VRCObjectSpawnEditor : Editor
{
VRCSDK2.VRC_ObjectSpawn spawn;
void OnEnable()
{
if (spawn == null)
spawn = (VRCSDK2.VRC_ObjectSpawn)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 26a75599848adb449b7aceed5090e35c
timeCreated: 1463516633
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using System.Collections;
using UnityEditor;
using System;
[CustomEditor(typeof(VRCSDK2.VRC_ObjectSync))]
public class VRCObjectSyncEditor : Editor
{
VRCSDK2.VRC_ObjectSync sync;
void OnEnable()
{
if (sync == null)
sync = (VRCSDK2.VRC_ObjectSync)target;
}
public override void OnInspectorGUI()
{
sync.SynchronizePhysics = EditorGUILayout.Toggle("Synchronize Physics",sync.SynchronizePhysics);
sync.AllowCollisionTransfer = EditorGUILayout.Toggle("Allow Collision Transfer", sync.AllowCollisionTransfer);
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ed4aad2698d3b62408e69b57c7748791
timeCreated: 1463516212
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,37 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using UnityEditor;
public class VRCPlayerModEditorWindow : EditorWindow {
public delegate void AddModCallback();
public static AddModCallback addModCallback;
private static VRCSDK2.VRC_PlayerMods myTarget;
private static VRCSDK2.VRCPlayerModFactory.PlayerModType type;
public static void Init (VRCSDK2.VRC_PlayerMods target, AddModCallback callback)
{
// Get existing open window or if none, make a new one:
EditorWindow.GetWindow (typeof (VRCPlayerModEditorWindow));
addModCallback = callback;
myTarget = target;
type = VRCSDK2.VRCPlayerModFactory.PlayerModType.Jump;
}
void OnGUI ()
{
type = (VRCSDK2.VRCPlayerModFactory.PlayerModType)EditorGUILayout.EnumPopup("Mods", type);
if(GUILayout.Button("Add Mod"))
{
VRCSDK2.VRCPlayerMod mod = VRCSDK2.VRCPlayerModFactory.Create(type);
myTarget.AddMod(mod);
addModCallback();
}
}
}
#endif

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8986a640e24a0754ea0aded12234b808
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,109 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System;
namespace VRCSDK2
{
[CustomEditor(typeof(VRCSDK2.VRC_PlayerMods))]
public class VRCPlayerModsEditor : UnityEditor.Editor
{
VRCSDK2.VRC_PlayerMods myTarget;
void OnEnable()
{
if(myTarget == null)
myTarget = (VRCSDK2.VRC_PlayerMods)target;
}
public override void OnInspectorGUI()
{
myTarget.isRoomPlayerMods = EditorGUILayout.Toggle("isRoomPlayerMods", myTarget.isRoomPlayerMods);
List<VRCSDK2.VRCPlayerMod> playerMods = myTarget.playerMods;
for(int i=0; i<playerMods.Count; ++i)
{
VRCSDK2.VRCPlayerMod mod = playerMods[i];
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField(mod.name, EditorStyles.boldLabel);
if( mod.allowNameEdit )
mod.name = EditorGUILayout.TextField( "Mod Name: ", mod.name );
for(int j=0; j<mod.properties.Count; ++j)
{
VRCSDK2.VRCPlayerModProperty prop = mod.properties[j];
myTarget.playerMods[i].properties[j] = DrawFieldForProp(prop);
}
if(GUILayout.Button ("Remove Mod"))
{
myTarget.RemoveMod(mod);
break;
}
EditorGUILayout.EndVertical();
}
if(GUILayout.Button("Add Mods"))
{
VRCPlayerModEditorWindow.AddModCallback adcb = OnInspectorGUI;
VRCPlayerModEditorWindow.Init(myTarget, adcb);
}
}
VRCSDK2.VRCPlayerModProperty DrawFieldForProp(VRCSDK2.VRCPlayerModProperty property)
{
if(property.type.SystemType == typeof(int))
{
property.intValue = EditorGUILayout.IntField(property.name, property.intValue);
}
else if(property.type.SystemType == typeof(float))
{
property.floatValue = EditorGUILayout.FloatField(property.name, property.floatValue);
}
else if(property.type.SystemType == typeof(string))
{
property.stringValue = EditorGUILayout.TextField(property.name, property.stringValue);
}
else if(property.type.SystemType == typeof(bool))
{
property.boolValue = EditorGUILayout.Toggle(property.name, property.boolValue);
}
else if(property.type.SystemType == typeof(GameObject))
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField( property.name );
property.gameObjectValue = (GameObject) EditorGUILayout.ObjectField( property.gameObjectValue, typeof( GameObject ), true );
EditorGUILayout.EndHorizontal();
}
else if(property.type.SystemType == typeof(KeyCode))
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField( property.name );
property.keyCodeValue = (KeyCode) EditorGUILayout.EnumPopup( property.keyCodeValue );
EditorGUILayout.EndHorizontal();
}
else if(property.type.SystemType == typeof(VRCSDK2.VRC_EventHandler.VrcBroadcastType))
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField( property.name );
property.broadcastValue = (VRCSDK2.VRC_EventHandler.VrcBroadcastType) EditorGUILayout.EnumPopup( property.broadcastValue );
EditorGUILayout.EndHorizontal();
}
else if(property.type.SystemType == typeof(VRCSDK2.VRCPlayerModFactory.HealthOnDeathAction))
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField( property.name );
property.onDeathActionValue = (VRCSDK2.VRCPlayerModFactory.HealthOnDeathAction) EditorGUILayout.EnumPopup( property.onDeathActionValue);
EditorGUILayout.EndHorizontal();
}
else if(property.type.SystemType == typeof(RuntimeAnimatorController))
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField( property.name );
property.animationController = (RuntimeAnimatorController) EditorGUILayout.ObjectField( property.animationController, typeof( RuntimeAnimatorController ), false );
EditorGUILayout.EndHorizontal();
}
return property;
}
}
}
#endif

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 792e7964a56e51f4188e1221751642e9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,46 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System;
[CustomEditor(typeof(VRCSDK2.VRC_Station))]
public class VRCPlayerStationEditor : Editor
{
VRCSDK2.VRC_Station myTarget;
SerializedProperty onRemoteEnter;
SerializedProperty onRemoteExit;
SerializedProperty onLocalEnter;
SerializedProperty onLocalExit;
void OnEnable()
{
if(myTarget == null)
myTarget = (VRCSDK2.VRC_Station)target;
onRemoteEnter = serializedObject.FindProperty("OnRemotePlayerEnterStation");
onRemoteExit = serializedObject.FindProperty("OnRemotePlayerExitStation");
onLocalEnter = serializedObject.FindProperty("OnLocalPlayerEnterStation");
onLocalExit = serializedObject.FindProperty("OnLocalPlayerExitStation");
}
public override void OnInspectorGUI()
{
myTarget.PlayerMobility = (VRC.SDKBase.VRCStation.Mobility)EditorGUILayout.EnumPopup("Player Mobility", myTarget.PlayerMobility);
myTarget.canUseStationFromStation = EditorGUILayout.Toggle("Can Use Station From Station", myTarget.canUseStationFromStation);
myTarget.animatorController = (RuntimeAnimatorController)EditorGUILayout.ObjectField("Animator Controller", myTarget.animatorController, typeof(RuntimeAnimatorController), false);
myTarget.disableStationExit = EditorGUILayout.Toggle("Disable Station Exit", myTarget.disableStationExit);
myTarget.seated = EditorGUILayout.Toggle("Seated", myTarget.seated);
myTarget.stationEnterPlayerLocation = (Transform)EditorGUILayout.ObjectField("Player Enter Location", myTarget.stationEnterPlayerLocation, typeof(Transform), true);
myTarget.stationExitPlayerLocation = (Transform)EditorGUILayout.ObjectField("Player Exit Location", myTarget.stationExitPlayerLocation, typeof(Transform), true);
myTarget.controlsObject = (VRC.SDKBase.VRC_ObjectApi)EditorGUILayout.ObjectField("API Object", myTarget.controlsObject, typeof(VRC.SDKBase.VRC_ObjectApi), false);
EditorGUILayout.PropertyField(onRemoteEnter, new GUIContent("On Remote Player Enter"));
EditorGUILayout.PropertyField(onRemoteExit, new GUIContent("On Remote Player Exit"));
EditorGUILayout.PropertyField(onLocalEnter, new GUIContent("On Local Player Enter"));
EditorGUILayout.PropertyField(onLocalExit, new GUIContent("On Local Player Exit"));
}
}
#endif

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 5262a02c32e41e047bdfdfc3b63db8ff
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,29 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomEditor (typeof(VRCSDK2.VRC_SceneDescriptor))]
public class VRCSceneDescriptorEditor : Editor
{
VRCSDK2.VRC_SceneDescriptor sceneDescriptor;
VRC.Core.PipelineManager pipelineManager;
public override void OnInspectorGUI()
{
if(sceneDescriptor == null)
sceneDescriptor = (VRCSDK2.VRC_SceneDescriptor)target;
if(pipelineManager == null)
{
pipelineManager = sceneDescriptor.GetComponent<VRC.Core.PipelineManager>();
if(pipelineManager == null)
sceneDescriptor.gameObject.AddComponent<VRC.Core.PipelineManager>();
}
DrawDefaultInspector();
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e9cbc493bbbc443fb92898aa84d221ec
timeCreated: 1450463561
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,130 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace VRCSDK2
{
//[CustomPropertyDrawer(typeof(VRC_AvatarVariations.VariationCategory))]
//public class PropertyDrawer_AvatarVariation_VariationCategory : PropertyDrawer
//{
// public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
// {
// //EditorGUILayout.Label("blah");
// if (property == null)
// return;
// SerializedProperty nameProperty = property.FindPropertyRelative("name");
// //SerializedProperty mirrorProperty = property.FindPropertyRelative("mirror");
// //SerializedProperty typeProperty = property.FindPropertyRelative("type");
// //SerializedProperty valueProperty = null;
// //switch (typeProperty.enumValueIndex)
// //{
// // case (int)VRC_DataStorage.VrcDataType.Bool:
// // valueProperty = property.FindPropertyRelative("valueBool");
// // break;
// // case (int)VRC_DataStorage.VrcDataType.Float:
// // valueProperty = property.FindPropertyRelative("valueFloat");
// // break;
// // case (int)VRC_DataStorage.VrcDataType.Int:
// // valueProperty = property.FindPropertyRelative("valueInt");
// // break;
// // case (int)VRC_DataStorage.VrcDataType.String:
// // valueProperty = property.FindPropertyRelative("valueString");
// // break;
// // case (int)VRC_DataStorage.VrcDataType.SerializeObject:
// // valueProperty = property.FindPropertyRelative("serializeComponent");
// // break;
// // case (int)VRC_DataStorage.VrcDataType.None:
// // case (int)VRC_DataStorage.VrcDataType.SerializeBytes:
// // break;
// //}
// EditorGUI.BeginProperty(rect, label, property);
// int baseWidth = (int)(rect.width / 4);
// Rect nameRect = new Rect(rect.x, rect.y, baseWidth, rect.height);
// //Rect mirrorRect = new Rect(rect.x + baseWidth, rect.y, baseWidth, rect.height);
// //Rect typeRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth, rect.height);
// //Rect valueRect = new Rect(rect.x + baseWidth * 3, rect.y, baseWidth, rect.height);
// //Rect typeValueRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth * 2, rect.height);
// EditorGUI.PropertyField(nameRect, nameProperty, GUIContent.none);
// //EditorGUI.PropertyField(mirrorRect, mirrorProperty, GUIContent.none);
// //switch (mirrorProperty.enumValueIndex)
// //{
// // case (int)VRC_DataStorage.VrcDataMirror.None:
// // if (valueProperty == null)
// // VRC_EditorTools.FilteredEnumPopup<VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true);
// // else
// // {
// // VRC_EditorTools.FilteredEnumPopup<VRC_DataStorage.VrcDataType>(typeRect, typeProperty, t => true);
// // EditorGUI.PropertyField(valueRect, valueProperty, GUIContent.none);
// // }
// // break;
// // case (int)VRC_DataStorage.VrcDataMirror.SerializeComponent:
// // typeProperty.enumValueIndex = (int)VRC_DataStorage.VrcDataType.SerializeObject;
// // EditorGUI.PropertyField(typeValueRect, valueProperty, GUIContent.none);
// // break;
// // default:
// // VRC_EditorTools.FilteredEnumPopup<VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true);
// // break;
// //}
// EditorGUI.EndProperty();
// }
//}
//[CustomEditor(typeof(VRC_AvatarVariations))]
//public class VRC_AvatarVariationsEditor : Editor
//{
// SerializedProperty categories;
// void OnEnable()
// {
// categories = serializedObject.FindProperty("categories");
// }
// public override void OnInspectorGUI()
// {
// //serializedObject.Update();
// // EditorGUILayout.PropertyField(categories);
// //serializedObject.ApplyModifiedProperties();
// //if (target == null)
// // return;
// ////var prop = serializedObject.FindProperty("root");
// ////EditorGUILayout.PropertyField(prop, new GUIContent("Show Help"));
// //VRCSDK2.VRC_AvatarVariations variations = target as VRCSDK2.VRC_AvatarVariations;
// //if (variations.categories == null)
// // variations.categories = new VRC_AvatarVariations.VariationCategory[0];
// //foreach ( var vc in variations.categories )
// //{
// // vc.name = EditorGUILayout.TextField("Variation Name", vc.name);
// //// SerializedProperty triggers = triggersProperty.Copy();
// //// int triggersLength = triggers.arraySize;
// //// List<int> to_remove = new List<int>();
// //// for (int idx = 0; idx < triggersLength; ++idx)
// //// {
// //// SerializedProperty triggerProperty = triggers.GetArrayElementAtIndex(idx);
// //// }
// //// EditorGUILayout.LabelField("");
// ////// helpProperty = serializedObject.FindProperty("ShowHelp");
// ////// EditorGUILayout.PropertyField(helpProperty, new GUIContent("Show Help"));
// //}
// ////EditorGUILayout.
// DrawDefaultInspector();
// }
//}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: eeda995d0ceac6443a54716996eab52e
timeCreated: 1511373338
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,91 @@
#if VRC_SDK_VRCSDK2 && UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using VRC.SDKBase;
namespace VRCSDK2
{
[CustomPropertyDrawer(typeof(VRCSDK2.VRC_DataStorage.VrcDataElement))]
public class CustomDataElementDrawer : PropertyDrawer
{
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
{
if (property == null)
return;
SerializedProperty nameProperty = property.FindPropertyRelative("name");
SerializedProperty mirrorProperty = property.FindPropertyRelative("mirror");
SerializedProperty typeProperty = property.FindPropertyRelative("type");
SerializedProperty valueProperty = null;
switch (typeProperty.enumValueIndex)
{
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.Bool:
valueProperty = property.FindPropertyRelative("valueBool");
break;
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.Float:
valueProperty = property.FindPropertyRelative("valueFloat");
break;
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.Int:
valueProperty = property.FindPropertyRelative("valueInt");
break;
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.String:
valueProperty = property.FindPropertyRelative("valueString");
break;
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.SerializeObject:
valueProperty = property.FindPropertyRelative("serializeComponent");
break;
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.None:
case (int)VRCSDK2.VRC_DataStorage.VrcDataType.SerializeBytes:
break;
}
EditorGUI.BeginProperty(rect, label, property);
int baseWidth = (int)(rect.width / 4);
Rect nameRect = new Rect(rect.x, rect.y, baseWidth, rect.height);
Rect mirrorRect = new Rect(rect.x + baseWidth, rect.y, baseWidth, rect.height);
Rect typeRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth, rect.height);
Rect valueRect = new Rect(rect.x + baseWidth * 3, rect.y, baseWidth, rect.height);
Rect typeValueRect = new Rect(rect.x + baseWidth * 2, rect.y, baseWidth * 2, rect.height);
EditorGUI.PropertyField(nameRect, nameProperty, GUIContent.none);
EditorGUI.PropertyField(mirrorRect, mirrorProperty, GUIContent.none);
switch (mirrorProperty.enumValueIndex)
{
case (int)VRCSDK2.VRC_DataStorage.VrcDataMirror.None:
if (valueProperty == null)
VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true);
else
{
VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_DataStorage.VrcDataType>(typeRect, typeProperty, t => true);
EditorGUI.PropertyField(valueRect, valueProperty, GUIContent.none);
}
break;
case (int)VRCSDK2.VRC_DataStorage.VrcDataMirror.SerializeComponent:
typeProperty.enumValueIndex = (int)VRCSDK2.VRC_DataStorage.VrcDataType.SerializeObject;
EditorGUI.PropertyField(typeValueRect, valueProperty, GUIContent.none);
break;
default:
VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_DataStorage.VrcDataType>(typeValueRect, typeProperty, t => true);
break;
}
EditorGUI.EndProperty();
}
}
[CustomEditor(typeof(VRCSDK2.VRC_DataStorage)), CanEditMultipleObjects]
public class VRC_DataStorageEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
VRCSDK2.VRC_ObjectSync os = ((VRCSDK2.VRC_DataStorage)target).GetComponent<VRCSDK2.VRC_ObjectSync>();
if (os != null && os.SynchronizePhysics)
EditorGUILayout.HelpBox("Consider either removing the VRC_ObjectSync or disabling SynchronizePhysics.", MessageType.Warning);
DrawDefaultInspector();
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0ac7998a36f085844847acbc046d4e27
timeCreated: 1478191469
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,57 @@
using UnityEngine;
using UnityEditor;
using VRC_DestructibleStandard = VRC.SDKBase.VRC_DestructibleStandard;
using VRC.SDKBase;
[CustomEditor(typeof(VRC_DestructibleStandard))]
[CanEditMultipleObjects]
public class VRC_DestructibleStandardEditor : Editor
{
VRC_DestructibleStandard ds;
SerializedProperty maxHealth;
SerializedProperty currentHealth;
SerializedProperty healable;
SerializedProperty onDamagedTrigger;
SerializedProperty onDestroyedTrigger;
SerializedProperty onHealedTrigger;
SerializedProperty onFullHealedTrigger;
void OnEnable()
{
maxHealth = serializedObject.FindProperty("maxHealth");
currentHealth = serializedObject.FindProperty("currentHealth");
healable = serializedObject.FindProperty("healable");
onDamagedTrigger = serializedObject.FindProperty("onDamagedTrigger");
onDestroyedTrigger = serializedObject.FindProperty("onDestructedTrigger");
onHealedTrigger = serializedObject.FindProperty("onHealedTrigger");
onFullHealedTrigger = serializedObject.FindProperty("onFullHealedTrigger");
}
public override void OnInspectorGUI()
{
ds = (VRC_DestructibleStandard)target;
// Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
serializedObject.Update ();
EditorGUILayout.PropertyField(maxHealth, new GUIContent("Max Health"));
EditorGUILayout.PropertyField(currentHealth, new GUIContent("Current Health"));
EditorGUILayout.PropertyField(healable, new GUIContent("Is Healable"));
EditorGUILayout.PropertyField(onDamagedTrigger, new GUIContent("On Damaged Trigger"));
VRC_EditorTools.DrawTriggerActionCallback("On Damaged Action", ds.onDamagedTrigger, ds.onDamagedEvent);
EditorGUILayout.PropertyField(onDestroyedTrigger, new GUIContent("On Destructed Trigger"));
VRC_EditorTools.DrawTriggerActionCallback("On Destructed Action", ds.onDestructedTrigger, ds.onDestructedEvent);
EditorGUILayout.PropertyField(onHealedTrigger, new GUIContent("On Healed Trigger"));
VRC_EditorTools.DrawTriggerActionCallback("On Healed Action", ds.onHealedTrigger, ds.onHealedEvent);
EditorGUILayout.PropertyField(onFullHealedTrigger, new GUIContent("On Full Healed Trigger"));
VRC_EditorTools.DrawTriggerActionCallback("On Full Healed Action", ds.onFullHealedTrigger, ds.onFullHealedEvent);
// Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
serializedObject.ApplyModifiedProperties ();
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3b63b118c0591b548ba1797e6be4292e
timeCreated: 1477161996
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,19 @@
#if VRC_SDK_VRCSDK2
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(VRCSDK2.VRC_ObjectSync))]
public class VRC_ObjectSyncEditor : Editor {
public override void OnInspectorGUI()
{
VRCSDK2.VRC_ObjectSync c = ((VRCSDK2.VRC_ObjectSync)target);
if ((c.gameObject.GetComponent<Animator>() != null || c.gameObject.GetComponent<Animation>() != null) && c.SynchronizePhysics)
EditorGUILayout.HelpBox("If the Animator or Animation moves the root position of this object then it will conflict with physics synchronization.", MessageType.Warning);
if (c.GetComponent<VRCSDK2.VRC_DataStorage>() != null && c.SynchronizePhysics)
EditorGUILayout.HelpBox("Consider either removing the VRC_DataStorage or disabling SynchronizePhysics.", MessageType.Warning);
DrawDefaultInspector();
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e19a7147a2386554a8e4d6e414f190a2
timeCreated: 1504908295
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,70 @@
#if VRC_SDK_VRCSDK2 && UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace VRCSDK2
{
[CustomEditor(typeof(VRCSDK2.VRC_Pickup))]
public class VRC_PickupEditor : UnityEditor.Editor
{
private void InspectorField(string propertyName, string humanName)
{
SerializedProperty propertyField = serializedObject.FindProperty(propertyName);
EditorGUILayout.PropertyField(propertyField, new GUIContent(humanName), true);
}
private SerializedProperty momentumTransferMethodProperty;
private SerializedProperty disallowTheftProperty;
private SerializedProperty exactGunProperty;
private SerializedProperty exactGripProperty;
private SerializedProperty allowManipulationWhenEquippedProperty;
private SerializedProperty orientationProperty;
private SerializedProperty autoHoldProperty;
private SerializedProperty interactionTextProperty;
private SerializedProperty useTextProperty;
private SerializedProperty throwVelocityBoostMinSpeedProperty;
private SerializedProperty throwVelocityBoostScaleProperty;
private SerializedProperty pickupableProperty;
private SerializedProperty proximityProperty;
public override void OnInspectorGUI()
{
momentumTransferMethodProperty = serializedObject.FindProperty("MomentumTransferMethod");
disallowTheftProperty = serializedObject.FindProperty("DisallowTheft");
exactGunProperty = serializedObject.FindProperty("ExactGun");
exactGripProperty = serializedObject.FindProperty("ExactGrip");
allowManipulationWhenEquippedProperty = serializedObject.FindProperty("allowManipulationWhenEquipped");
orientationProperty = serializedObject.FindProperty("orientation");
autoHoldProperty = serializedObject.FindProperty("AutoHold");
interactionTextProperty = serializedObject.FindProperty("InteractionText");
useTextProperty = serializedObject.FindProperty("UseText");
throwVelocityBoostMinSpeedProperty = serializedObject.FindProperty("ThrowVelocityBoostMinSpeed");
throwVelocityBoostScaleProperty = serializedObject.FindProperty("ThrowVelocityBoostScale");
pickupableProperty = serializedObject.FindProperty("pickupable");
proximityProperty = serializedObject.FindProperty("proximity");
EditorGUILayout.BeginVertical(GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 30));
EditorGUILayout.PropertyField(momentumTransferMethodProperty, new GUIContent("Momentum Transfer Method"));
EditorGUILayout.PropertyField(disallowTheftProperty, new GUIContent("Disallow Theft"));
EditorGUILayout.PropertyField(exactGunProperty, new GUIContent("Exact Gun"));
EditorGUILayout.PropertyField(exactGripProperty, new GUIContent("Exact Grip"));
EditorGUILayout.PropertyField(allowManipulationWhenEquippedProperty, new GUIContent("Allow Manipulation When Equipped"));
EditorGUILayout.PropertyField(orientationProperty, new GUIContent("Orientation"));
EditorGUILayout.PropertyField(autoHoldProperty, new GUIContent("AutoHold", "If the pickup is supposed to be aligned to the hand (i.e. orientation field is set to Gun or Grip), auto-detect means that it will be Equipped(not dropped when they release trigger), otherwise just hold as a normal pickup."));
EditorGUILayout.PropertyField(interactionTextProperty, new GUIContent("Interaction Text","Text displayed when user hovers over the pickup."));
if (autoHoldProperty.enumValueIndex != (int)VRCSDK2.VRC_Pickup.AutoHoldMode.No)
EditorGUILayout.PropertyField(useTextProperty, new GUIContent("Use Text", "Text to display describing action for clicking button, when this pickup is already being held."));
EditorGUILayout.PropertyField(throwVelocityBoostMinSpeedProperty, new GUIContent("Throw Velocity Boost Min Speed"));
EditorGUILayout.PropertyField(throwVelocityBoostScaleProperty, new GUIContent("Throw Velocity Boost Scale"));
EditorGUILayout.PropertyField(pickupableProperty, new GUIContent("Pickupable"));
EditorGUILayout.PropertyField(proximityProperty, new GUIContent("Proximity"));
EditorGUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
}
#endif

View File

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

View File

@ -0,0 +1,106 @@
#if VRC_SDK_VRCSDK2
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System;
namespace VRCSDK2
{
[CustomEditor(typeof(VRCSDK2.VRC_PlayerAudioOverride))]
public class VRC_PlayerAudioOverrideEditor : UnityEditor.Editor
{
private bool voShow = true;
private bool voAdv = false;
private bool avShow = true;
private bool avAdv = false;
private SerializedProperty prioProperty;
private SerializedProperty globalProperty;
private SerializedProperty regionProperty;
private SerializedProperty voGainProperty;
private SerializedProperty voNearProperty;
private SerializedProperty voFarProperty;
private SerializedProperty voRadiusProperty;
private SerializedProperty voDisableLpProperty;
private SerializedProperty avGainProperty;
private SerializedProperty avNearProperty;
private SerializedProperty avFarProperty;
private SerializedProperty avRadiusProperty;
private SerializedProperty avForceSpatialProperty;
private SerializedProperty avAllowCustomProperty;
public override void OnInspectorGUI()
{
globalProperty = serializedObject.FindProperty("global");
regionProperty = serializedObject.FindProperty("region");
prioProperty = serializedObject.FindProperty("regionPriority");
voGainProperty = serializedObject.FindProperty("VoiceGain");
voNearProperty = serializedObject.FindProperty("VoiceNear");
voFarProperty = serializedObject.FindProperty("VoiceFar");
voRadiusProperty = serializedObject.FindProperty("VoiceVolumetricRadius");
voDisableLpProperty = serializedObject.FindProperty("VoiceDisableLowpass");
avGainProperty = serializedObject.FindProperty("AvatarGainLimit");
avNearProperty = serializedObject.FindProperty("AvatarNearLimit");
avFarProperty = serializedObject.FindProperty("AvatarFarLimit");
avRadiusProperty = serializedObject.FindProperty("AvatarVolumetricRadiusLimit");
avForceSpatialProperty = serializedObject.FindProperty("AvatarForceSpatial");
avAllowCustomProperty = serializedObject.FindProperty("AvatarAllowCustomCurve");
serializedObject.Update();
EditorGUILayout.BeginVertical();
var ovr = serializedObject.targetObject as VRCSDK2.VRC_PlayerAudioOverride;
EditorGUILayout.PropertyField(globalProperty, new GUIContent("Global"));
if (!ovr.global)
{
EditorGUILayout.PropertyField(regionProperty, new GUIContent("Region"));
EditorGUILayout.PropertyField(prioProperty, new GUIContent("Priority"));
}
voShow = EditorGUILayout.Foldout(voShow, "Voice Settings");
if (voShow)
{
EditorGUILayout.PropertyField(voGainProperty, new GUIContent("Gain"));
EditorGUILayout.PropertyField(voFarProperty, new GUIContent("Far"));
EditorGUI.indentLevel++;
voAdv = EditorGUILayout.Foldout(voAdv, "Advanced Options");
if (voAdv)
{
EditorGUILayout.PropertyField(voNearProperty, new GUIContent("Near"));
EditorGUILayout.PropertyField(voRadiusProperty, new GUIContent("Volumetric Radius"));
EditorGUILayout.PropertyField(voDisableLpProperty, new GUIContent("Disable Lowpass Filter"));
}
EditorGUI.indentLevel--;
}
avShow = EditorGUILayout.Foldout(avShow, "Avatar Audio Limits");
if (avShow)
{
EditorGUILayout.PropertyField(avGainProperty, new GUIContent("Gain Limit"));
EditorGUILayout.PropertyField(avFarProperty, new GUIContent("Far Limit"));
EditorGUI.indentLevel++;
avAdv = EditorGUILayout.Foldout(avAdv, "Advanced Options");
if (avAdv)
{
EditorGUILayout.PropertyField(avNearProperty, new GUIContent("Near Limit"));
EditorGUILayout.PropertyField(avRadiusProperty, new GUIContent("Volumetric Radius Limit"));
EditorGUILayout.PropertyField(avForceSpatialProperty, new GUIContent("Force Spatial"));
EditorGUILayout.PropertyField(avAllowCustomProperty, new GUIContent("Allow Custom Curve"));
}
EditorGUI.indentLevel--;
}
EditorGUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5c545625e0bf93045ac1c5864141c5c1
timeCreated: 1474315179
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
#if VRC_SDK_VRCSDK2 && UNITY_EDITOR
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System;
namespace VRCSDK2
{
[CustomEditor(typeof(VRCSDK2.VRC_SpatialAudioSource))]
public class VRC_SpatialAudioSourceEditor : UnityEditor.Editor
{
private bool showAdvancedOptions = false;
private SerializedProperty gainProperty;
private SerializedProperty nearProperty;
private SerializedProperty farProperty;
private SerializedProperty volRadiusProperty;
private SerializedProperty enableSpatialProperty;
private SerializedProperty useCurveProperty;
public override void OnInspectorGUI()
{
gainProperty = serializedObject.FindProperty("Gain");
nearProperty = serializedObject.FindProperty("Near");
farProperty = serializedObject.FindProperty("Far");
volRadiusProperty = serializedObject.FindProperty("VolumetricRadius");
enableSpatialProperty = serializedObject.FindProperty("EnableSpatialization");
useCurveProperty = serializedObject.FindProperty("UseAudioSourceVolumeCurve");
serializedObject.Update();
VRCSDK2.VRC_SpatialAudioSource target = serializedObject.targetObject as VRCSDK2.VRC_SpatialAudioSource;
AudioSource source = target.GetComponent<AudioSource>();
EditorGUILayout.BeginVertical();
EditorGUILayout.PropertyField(gainProperty, new GUIContent("Gain"));
EditorGUILayout.PropertyField(farProperty, new GUIContent("Far"));
showAdvancedOptions = EditorGUILayout.Foldout(showAdvancedOptions, "Advanced Options");
bool enableSp = enableSpatialProperty.boolValue;
if (showAdvancedOptions)
{
EditorGUILayout.PropertyField(nearProperty, new GUIContent("Near"));
EditorGUILayout.PropertyField(volRadiusProperty, new GUIContent("Volumetric Radius"));
EditorGUILayout.PropertyField(enableSpatialProperty, new GUIContent("Enable Spatialization"));
if (enableSp)
EditorGUILayout.PropertyField(useCurveProperty, new GUIContent("Use AudioSource Volume Curve"));
}
EditorGUILayout.EndVertical();
if (source != null)
source.spatialize = enableSp;
serializedObject.ApplyModifiedProperties();
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0d2d4cba733f5eb4ba170368e67710d2
timeCreated: 1474315179
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,105 @@
#if VRC_SDK_VRCSDK2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using VRC.SDKBase;
[CustomPropertyDrawer(typeof(VRCSDK2.VRC_SyncVideoPlayer.VideoEntry))]
public class CustomVideoEntryDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty source = property.FindPropertyRelative("Source");
SerializedProperty ratio = property.FindPropertyRelative("AspectRatio");
SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed");
SerializedProperty clip = property.FindPropertyRelative("VideoClip");
SerializedProperty url = property.FindPropertyRelative("URL");
return EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing
+ EditorGUI.GetPropertyHeight(ratio, new GUIContent("Aspect Ratio"), true) + EditorGUIUtility.standardVerticalSpacing
+ EditorGUI.GetPropertyHeight(speed, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing
+ Mathf.Max(EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true), EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true)) + EditorGUIUtility.standardVerticalSpacing;
}
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
{
SerializedProperty source = property.FindPropertyRelative("Source");
SerializedProperty ratio = property.FindPropertyRelative("AspectRatio");
SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed");
SerializedProperty clip = property.FindPropertyRelative("VideoClip");
SerializedProperty url = property.FindPropertyRelative("URL");
EditorGUI.BeginProperty(rect, label, property);
float x = rect.x;
float y = rect.y;
float w = rect.width;
float h = EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing;
VRC_EditorTools.FilteredEnumPopup<UnityEngine.Video.VideoSource>(new Rect(x, y, w, h), source, (e) => e == UnityEngine.Video.VideoSource.Url);
y += h;
if (source.enumValueIndex == (int)UnityEngine.Video.VideoSource.Url)
{
h = EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), url);
y += h;
}
else
{
h = EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), clip);
y += h;
}
h = EditorGUI.GetPropertyHeight(ratio, new GUIContent("AspectRatio"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), ratio);
y += h;
h = EditorGUI.GetPropertyHeight(ratio, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), speed);
if (speed.floatValue == 0f)
speed.floatValue = 1f;
y += h;
EditorGUI.EndProperty();
}
}
[CustomEditor(typeof(VRCSDK2.VRC_SyncVideoPlayer))]
public class SyncVideoPlayerEditor : Editor
{
ReorderableList sourceList;
public override void OnInspectorGUI()
{
SerializedProperty searchRoot = serializedObject.FindProperty("VideoSearchRoot");
EditorGUILayout.PropertyField(searchRoot);
SerializedProperty maxQual = serializedObject.FindProperty("MaxStreamQuality");
EditorGUILayout.PropertyField(maxQual);
EditorGUILayout.Space();
sourceList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
private void OnEnable()
{
SerializedProperty videos = serializedObject.FindProperty("Videos");
sourceList = new ReorderableList(serializedObject, videos);
sourceList.drawElementCallback += (Rect rect, int index, bool active, bool focused) =>
{
EditorGUI.PropertyField(rect, serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index));
};
sourceList.elementHeightCallback += (int index) =>
{
SerializedProperty element = serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index);
return EditorGUI.GetPropertyHeight(element);
};
sourceList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, "Videos");
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ae0e74693b7899f47bd98864f94b9311
timeCreated: 1499468412
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,117 @@
#if VRC_SDK_VRCSDK2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using VRC.SDKBase;
[CustomPropertyDrawer(typeof(VRCSDK2.VRC_SyncVideoStream.VideoEntry))]
public class CustomVideoStreamEntryDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty source = property.FindPropertyRelative("Source");
SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed");
SerializedProperty clip = property.FindPropertyRelative("VideoClip");
SerializedProperty url = property.FindPropertyRelative("URL");
SerializedProperty live = property.FindPropertyRelative("SyncType");
SerializedProperty sync = property.FindPropertyRelative("SyncMinutes");
return EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing
+ EditorGUI.GetPropertyHeight(speed, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing
+ Mathf.Max(EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true), EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true)) + EditorGUIUtility.standardVerticalSpacing
+ EditorGUI.GetPropertyHeight(live, new GUIContent("SyncType"), true) + EditorGUIUtility.standardVerticalSpacing
+ EditorGUI.GetPropertyHeight(sync, new GUIContent("SyncMinutes"), true) + EditorGUIUtility.standardVerticalSpacing;
}
public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
{
SerializedProperty source = property.FindPropertyRelative("Source");
SerializedProperty speed = property.FindPropertyRelative("PlaybackSpeed");
SerializedProperty clip = property.FindPropertyRelative("VideoClip");
SerializedProperty url = property.FindPropertyRelative("URL");
SerializedProperty live = property.FindPropertyRelative("SyncType");
SerializedProperty sync = property.FindPropertyRelative("SyncMinutes");
EditorGUI.BeginProperty(rect, label, property);
float x = rect.x;
float y = rect.y;
float w = rect.width;
float h = EditorGUI.GetPropertyHeight(source, new GUIContent("Source"), true) + EditorGUIUtility.standardVerticalSpacing;
VRC_EditorTools.FilteredEnumPopup<UnityEngine.Video.VideoSource>(new Rect(x, y, w, h), source, (e) => e == UnityEngine.Video.VideoSource.Url);
y += h;
if (source.enumValueIndex == (int)UnityEngine.Video.VideoSource.Url)
{
h = EditorGUI.GetPropertyHeight(url, new GUIContent("URL"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), url);
y += h;
}
else
{
h = EditorGUI.GetPropertyHeight(clip, new GUIContent("VideoClip"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), clip);
y += h;
}
h = EditorGUI.GetPropertyHeight(speed, new GUIContent("Playback Speed"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), speed);
if (speed.floatValue == 0f)
speed.floatValue = 1f;
y += h;
h = EditorGUI.GetPropertyHeight(live, new GUIContent("SyncType"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), live);
y += h;
h = EditorGUI.GetPropertyHeight(sync, new GUIContent("SyncMinutes"), true) + EditorGUIUtility.standardVerticalSpacing;
EditorGUI.PropertyField(new Rect(x, y, w, h), sync);
if (sync.floatValue < 1f)
sync.floatValue = 0;
y += h;
EditorGUI.EndProperty();
}
}
[CustomEditor(typeof(VRCSDK2.VRC_SyncVideoStream))]
public class SyncVideoStreamEditor : Editor
{
ReorderableList sourceList;
public override void OnInspectorGUI()
{
SerializedProperty searchRoot = serializedObject.FindProperty("VideoSearchRoot");
EditorGUILayout.PropertyField(searchRoot);
SerializedProperty maxQual = serializedObject.FindProperty("MaxStreamQuality");
EditorGUILayout.PropertyField(maxQual);
SerializedProperty autoStart = serializedObject.FindProperty("AutoStart");
EditorGUILayout.PropertyField(autoStart);
EditorGUILayout.Space();
sourceList.DoLayoutList();
serializedObject.ApplyModifiedProperties();
}
private void OnEnable()
{
SerializedProperty videos = serializedObject.FindProperty("Videos");
sourceList = new ReorderableList(serializedObject, videos);
sourceList.drawElementCallback += (Rect rect, int index, bool active, bool focused) =>
{
EditorGUI.PropertyField(rect, serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index));
};
sourceList.elementHeightCallback += (int index) =>
{
SerializedProperty element = serializedObject.FindProperty("Videos").GetArrayElementAtIndex(index);
return EditorGUI.GetPropertyHeight(element);
};
sourceList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, "Videos");
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3f9dccfed0b072f49a307b3f20a7e768
timeCreated: 1528745185
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3aecd666943878944a811acb9db2ace7
timeCreated: 1474315179
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,215 @@
#if VRC_SDK_VRCSDK2 && UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEditor.Build;
using System;
using ZLinq;
using VRC.SDKBase.Editor;
namespace VRCSDK2
{
[CustomEditor(typeof(VRCSDK2.VRC_WebPanel))]
public class VRC_WebPanelEditor : UnityEditor.Editor
{
private void InspectorField(string propertyName, string humanName)
{
SerializedProperty propertyField = serializedObject.FindProperty(propertyName);
EditorGUILayout.PropertyField(propertyField, new GUIContent(humanName), true);
}
bool showFiles = false;
System.Collections.Generic.List<string> directories = null;
System.Collections.Generic.List<string> files = null;
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginVertical();
EditorGUILayout.HelpBox("Do not play any videos with Web Panels, use VRC_SyncVideoPlayer instead!", MessageType.Error);
EditorGUILayout.Space();
InspectorField("proximity", "Proximity for Interactivity");
EditorGUILayout.Space();
VRCSDK2.VRC_WebPanel web = (VRCSDK2.VRC_WebPanel)target;
if (Application.isPlaying)
{
InspectorField("webRoot", "Web Root");
InspectorField("defaultUrl", "URI");
showFiles = web.webData != null && EditorGUILayout.Foldout(showFiles, web.webData.Count.ToString() + " files imported");
if (showFiles)
foreach (var file in web.webData)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel(file.path);
EditorGUILayout.LabelField(file.data.Length.ToString());
EditorGUILayout.EndHorizontal();
}
}
else
{
SerializedProperty webRoot = serializedObject.FindProperty("webRoot");
RenderDirectoryList(serializedObject, "webRoot", "Path To Web Content");
if (string.IsNullOrEmpty(webRoot.stringValue))
{
InspectorField("defaultUrl", "Start URI");
}
else
{
RenderWebRootSelector(serializedObject, "defaultUrl", "Start Page");
if (VRCSettings.DisplayHelpBoxes)
{
EditorGUILayout.HelpBox("Javascript API bindings are called with engine.call('methodName', ...), which returns a promise-like object.", MessageType.Info);
EditorGUILayout.HelpBox("Javascript may call ListBindings() to discover available API bindings.", MessageType.Info);
EditorGUILayout.HelpBox("Javascript may listen for the 'onBindingsReady' event to execute script when the page is fully loaded and API bindings are available.", MessageType.Info);
}
}
}
EditorGUILayout.Space();
InspectorField("cookiesEnabled", "Enable Cookies");
InspectorField("interactive", "Is Interactive");
InspectorField("localOnly", "Only Visible Locally");
if (!web.localOnly)
{
InspectorField("syncURI", "Synchronize URI");
InspectorField("syncInput", "Synchronize Mouse Position");
}
InspectorField("transparent", "Transparent Background");
InspectorField("autoFormSubmit", "Input should Submit Forms");
EditorGUILayout.Space();
InspectorField("station", "Interaction Station");
EditorGUILayout.Space();
InspectorField("cursor", "Mouse Cursor Object");
EditorGUILayout.Space();
InspectorField("resolutionWidth", "Resolution Width");
InspectorField("resolutionHeight", "Resolution Height");
InspectorField("displayRegion", "Display Region");
EditorGUILayout.Space();
InspectorField("extraVideoScreens", "Duplicate Screens");
EditorGUILayout.EndVertical();
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
}
private void AddSubDirectories(ref System.Collections.Generic.List<string> l, string root)
{
if (!Directory.Exists(root))
{
return;
}
if (!root.StartsWith(Application.dataPath + Path.DirectorySeparatorChar + "VRCSDK")
|| root == Application.dataPath + Path.DirectorySeparatorChar + "VRCSDK" + Path.DirectorySeparatorChar + "Examples" + Path.DirectorySeparatorChar + "Sample Assets" + Path.DirectorySeparatorChar + "WebRoot")
l.Add(root.Substring(Application.dataPath.Length));
string[] subdirectories = Directory.GetDirectories(root);
foreach (string dir in subdirectories)
AddSubDirectories(ref l, dir);
}
private void RenderDirectoryList(SerializedObject obj, string propertyName, string humanName)
{
if (directories == null)
{
directories = new System.Collections.Generic.List<string>();
directories.Add("No Web Content Directory");
AddSubDirectories(ref directories, Application.dataPath + Path.DirectorySeparatorChar);
}
SerializedProperty target = serializedObject.FindProperty(propertyName);
int selectedIdx = target.stringValue == null ? 0 : directories.IndexOf(target.stringValue);
if (selectedIdx < 0 || selectedIdx >= directories.Count)
selectedIdx = 0;
selectedIdx = EditorGUILayout.Popup(humanName, selectedIdx, directories.ToArray());
if (selectedIdx > 0 && selectedIdx < directories.Count)
target.stringValue = directories[selectedIdx];
else
target.stringValue = null;
}
private void AddSubDirectoryFiles(ref System.Collections.Generic.List<string> l, string root)
{
if (!Directory.Exists(root))
return;
string[] files = Directory.GetFiles(root);
foreach (string file in files.Where(f => f.ToLower().EndsWith(".html") || f.ToLower().EndsWith(".htm")))
l.Add(file.Substring(Application.dataPath.Length));
string[] subdirectories = Directory.GetDirectories(root);
foreach (string dir in subdirectories)
AddSubDirectoryFiles(ref l, dir);
}
private void RenderWebRootSelector(SerializedObject obj, string propertyName, string humanName)
{
SerializedProperty webRoot = obj.FindProperty("webRoot");
SerializedProperty target = serializedObject.FindProperty(propertyName);
if (files == null)
{
files = new System.Collections.Generic.List<string>();
AddSubDirectoryFiles(ref files, Application.dataPath + webRoot.stringValue);
if (files.Count == 0)
{
EditorGUILayout.HelpBox("No suitable html files found in Web Content path.", MessageType.Error);
return;
}
}
int selectedIdx = 0;
try
{
System.Uri uri = string.IsNullOrEmpty(target.stringValue) ? null : new Uri(target.stringValue);
selectedIdx = uri == null ? 0 : files.IndexOf(uri.AbsolutePath.Replace('/', System.IO.Path.DirectorySeparatorChar));
if (selectedIdx < 0 || selectedIdx >= files.Count)
selectedIdx = 0;
}
catch { }
selectedIdx = EditorGUILayout.Popup(humanName, selectedIdx, files.ToArray());
if (selectedIdx >= 0 && selectedIdx < files.Count)
{
System.UriBuilder builder = new UriBuilder()
{
Scheme = "file",
Path = files[selectedIdx].Replace(System.IO.Path.DirectorySeparatorChar, '/'),
Host = ""
};
target.stringValue = builder.Uri.ToString();
}
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d09b36020f697be4d9a0f5a6a48cfa83
timeCreated: 1457992191
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,20 @@
#if UNITY_EDITOR && VRC_SDK_VRCSDK2
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace VRCSDK2
{
[CustomEditor(typeof(VRC_YouTubeSync))]
public class VRC_YouTubeSyncEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
EditorGUILayout.HelpBox("This component is deprecated, please use the VRC_SyncVideoPlayer component instead.", MessageType.Error);
}
}
}
#endif

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 764e26c1ca28e2e45a30c778c1955a47
timeCreated: 1474675311
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@ -0,0 +1,36 @@

using System;
using UnityEngine;
using UnityEngine.UIElements;
// Common interface used by all builder panels inside their respective packages
/// <summary>
/// This interface is reserved for SDK use, refer to Interfaces inside the Public SDK API folder for public APIs
/// </summary>
public interface IVRCSdkControlPanelBuilder
{
void Initialize();
void ShowSettingsOptions();
bool IsValidBuilder(out string message);
void CreateBuilderErrorGUI(VisualElement root);
void CreateValidationsGUI(VisualElement root);
EventHandler OnContentChanged { get; set; }
EventHandler OnShouldRevalidate { get; set; }
void RegisterBuilder(VRCSdkControlPanel baseBuilder);
void SelectAllComponents();
void CreateContentInfoGUI(VisualElement root);
void CreateBuildGUI(VisualElement root);
/// <summary>
/// Returns the image to show within the Builder tab. If no image is provided - the default image is used
/// </summary>
/// <returns></returns>
Texture2D GetHeaderImage()
{
return null;
}
}

View File

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

View File

@ -0,0 +1,511 @@
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using VRC.Core;
using VRC.Editor;
using VRC.SDKBase.Editor;
[assembly:InternalsVisibleTo("VRC.ExampleCentral.Editor")]
/// This class sets up the basic panel layout and draws the main tabs
/// Implementation of each tab is handled within other files extending this partial class
[ExecuteInEditMode]
public partial class VRCSdkControlPanel : EditorWindow, IVRCSdkPanelApi
{
public static VRCSdkControlPanel window;
[MenuItem("VRChat SDK/Show Control Panel", false, 600)]
internal static void ShowControlPanel()
{
if (!ConfigManager.RemoteConfig.IsInitialized())
{
VRC.Core.API.SetOnlineMode(true);
ConfigManager.RemoteConfig.Init(() => ShowControlPanel());
return;
}
GetWindow(typeof(VRCSdkControlPanel));
window.titleContent.text = "VRChat SDK";
window.minSize = new Vector2(SdkWindowWidth + 4, 450);
window.maxSize = new Vector2(SdkWindowWidth + 4, 2000);
window.Init();
window.Show();
}
public VRCSdkControlPanel()
{
window = this;
}
#region IMGUI Init
public static GUIStyle titleGuiStyle;
public static GUIStyle boxGuiStyle;
public static GUIStyle infoGuiStyle;
public static GUIStyle listButtonStyleEven;
public static GUIStyle listButtonStyleOdd;
public static GUIStyle listButtonStyleSelected;
public static GUIStyle scrollViewSeparatorStyle;
public static GUIStyle searchBarStyle;
public static GUIStyle accountWindowStyle;
public static GUIStyle centeredLabelStyle;
public static GUIStyle contentDescriptionStyle;
public static GUIStyle contentTitleStyle;
public static GUIStyle unityUpgradeBannerStyle;
void InitializeStyles()
{
titleGuiStyle = new GUIStyle();
titleGuiStyle.fontSize = 15;
titleGuiStyle.fontStyle = FontStyle.BoldAndItalic;
titleGuiStyle.alignment = TextAnchor.MiddleCenter;
titleGuiStyle.wordWrap = true;
if (EditorGUIUtility.isProSkin)
titleGuiStyle.normal.textColor = Color.white;
else
titleGuiStyle.normal.textColor = Color.black;
boxGuiStyle = new GUIStyle
{
padding = new RectOffset(5,5,5,5)
};
if (EditorGUIUtility.isProSkin)
{
boxGuiStyle.normal.background = CreateBackgroundColorImage(new Color(0.3f, 0.3f, 0.3f));
boxGuiStyle.normal.textColor = Color.white;
}
else
{
boxGuiStyle.normal.background = CreateBackgroundColorImage(new Color(0.85f, 0.85f, 0.85f));
boxGuiStyle.normal.textColor = Color.black;
}
infoGuiStyle = new GUIStyle();
infoGuiStyle.wordWrap = true;
if (EditorGUIUtility.isProSkin)
infoGuiStyle.normal.textColor = Color.white;
else
infoGuiStyle.normal.textColor = Color.black;
infoGuiStyle.margin = new RectOffset(10, 10, 10, 10);
listButtonStyleEven = new GUIStyle();
listButtonStyleEven.margin = new RectOffset(0, 0, 0, 0);
listButtonStyleEven.border = new RectOffset(0, 0, 0, 0);
if (EditorGUIUtility.isProSkin)
{
listButtonStyleEven.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
listButtonStyleEven.normal.background = CreateBackgroundColorImage(new Color(0.540f, 0.540f, 0.54f));
}
else
{
listButtonStyleEven.normal.textColor = Color.black;
listButtonStyleEven.normal.background = CreateBackgroundColorImage(new Color(0.85f, 0.85f, 0.85f));
}
listButtonStyleOdd = new GUIStyle();
listButtonStyleOdd.margin = new RectOffset(0, 0, 0, 0);
listButtonStyleOdd.border = new RectOffset(0, 0, 0, 0);
if (EditorGUIUtility.isProSkin)
{
listButtonStyleOdd.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
//listButtonStyleOdd.normal.background = CreateBackgroundColorImage(new Color(0.50f, 0.50f, 0.50f));
}
else
{
listButtonStyleOdd.normal.textColor = Color.black;
listButtonStyleOdd.normal.background = CreateBackgroundColorImage(new Color(0.90f, 0.90f, 0.90f));
}
listButtonStyleSelected = new GUIStyle();
listButtonStyleSelected.normal.textColor = Color.white;
listButtonStyleSelected.margin = new RectOffset(0, 0, 0, 0);
if (EditorGUIUtility.isProSkin)
{
listButtonStyleSelected.normal.textColor = new Color(0.8f, 0.8f, 0.8f);
listButtonStyleSelected.normal.background = CreateBackgroundColorImage(new Color(0.4f, 0.4f, 0.4f));
}
else
{
listButtonStyleSelected.normal.textColor = Color.black;
listButtonStyleSelected.normal.background = CreateBackgroundColorImage(new Color(0.75f, 0.75f, 0.75f));
}
scrollViewSeparatorStyle = new GUIStyle("Toolbar");
scrollViewSeparatorStyle.fixedWidth = SdkWindowWidth + 10;
scrollViewSeparatorStyle.fixedHeight = 4;
scrollViewSeparatorStyle.margin.top = 1;
searchBarStyle = new GUIStyle("Toolbar");
searchBarStyle.fixedWidth = SdkWindowWidth - 8;
searchBarStyle.fixedHeight = 23;
searchBarStyle.padding.top = 3;
accountWindowStyle = new GUIStyle("window")
{
padding = new RectOffset(10, 10, 10, 10),
margin = new RectOffset(0,0,30,30)
};
centeredLabelStyle = new GUIStyle(EditorStyles.boldLabel)
{
alignment = TextAnchor.UpperCenter,
margin = new RectOffset(0,0,0,10)
};
contentDescriptionStyle = new GUIStyle(EditorStyles.wordWrappedLabel)
{
wordWrap = true
};
contentTitleStyle = new GUIStyle(EditorStyles.boldLabel)
{
wordWrap = true
};
unityUpgradeBannerStyle = new GUIStyle
{
normal = new GUIStyleState
{
background = Resources.Load<Texture2D>("vrcSdkMigrateTo2022Splash")
},
alignment = TextAnchor.LowerCenter,
margin = new RectOffset(0,0,20,0),
fixedWidth = 506,
fixedHeight = 148
};
}
#endregion
private void Init()
{
InitializeStyles();
ResetIssues();
InitAccount();
}
private void OnEnable()
{
OnEnableAccount();
_stylesInitialized = false;
OnPanelLoggedIn -= RestoreTab;
OnPanelLoggedIn += RestoreTab;
OnUserPlatformsFetched -= RefreshPlatformSwitcher;
OnUserPlatformsFetched += RefreshPlatformSwitcher;
AssemblyReloadEvents.afterAssemblyReload -= BuilderAssemblyReload;
AssemblyReloadEvents.afterAssemblyReload += BuilderAssemblyReload;
OnSdkPanelEnable?.Invoke(this, null);
_panelState = SdkPanelState.Idle;
OnSdkPanelStateChange?.Invoke(this, _panelState);
TabsEnabled = true;
}
private void OnDisable()
{
OnPanelLoggedIn -= RestoreTab;
OnUserPlatformsFetched -= RefreshPlatformSwitcher;
AssemblyReloadEvents.afterAssemblyReload -= BuilderAssemblyReload;
OnSdkPanelDisable?.Invoke(this, null);
_panelState = SdkPanelState.Idle;
OnSdkPanelStateChange?.Invoke(this, _panelState);
}
private void RestoreTab(object sender, APIUser e)
{
rootVisualElement.schedule.Execute(() =>
{
SelectTab(PanelTab.Builder);
}).ExecuteLater(200);
}
private void OnDestroy()
{
AccountDestroy();
}
public const int SdkWindowWidth = 512;
private readonly bool[] _toolbarOptionsLoggedIn = new bool[4] {true, true, true, true};
private readonly bool[] _toolbarOptionsNotLoggedIn = new bool[4] {true, false, false, true};
private bool _stylesInitialized;
private SdkPanelState _panelState = SdkPanelState.Idle;
private Button _authenticationTabBtn;
private Button _buildTabBtn;
private Button _contentManagerTabBtn;
private Button _settingsTabBtn;
private Button[] _tabButtons;
private VisualElement _sdkPanel;
private VisualElement _builderPanel;
private VisualTreeAsset _builderPanelLayout;
private StyleSheet _builderPanelStyles;
private float _windowOpenTime;
private bool _tabsEnabled;
internal bool TabsEnabled
{
get => _tabsEnabled;
set
{
_tabsEnabled = value;
if (_tabButtons != null)
{
foreach (var button in _tabButtons)
{
button.SetEnabled(value);
}
}
}
}
internal enum PanelTab
{
Account,
Builder,
ContentManager,
Settings
}
private void CreateGUI()
{
if (window == null)
{
window = (VRCSdkControlPanel)EditorWindow.GetWindow(typeof(VRCSdkControlPanel));
}
_windowOpenTime = Time.realtimeSinceStartup;
var visualTree = Resources.Load<VisualTreeAsset>("VRCSdkPanelLayout");
visualTree.CloneTree(rootVisualElement);
var styles = Resources.Load<StyleSheet>("VRCSdkPanelStyles");
rootVisualElement.styleSheets.Add(styles);
rootVisualElement.AddToClassList(EditorGUIUtility.isProSkin ? "dark" : "light");
_sdkPanel = rootVisualElement.Q("sdk-container");
_builderPanel = rootVisualElement.Q("builder-panel");
CreateTabs();
RenderTabs();
rootVisualElement.schedule.Execute(() =>
{
var currentPanel = VRCSettings.ActiveWindowPanel;
if (EditorApplication.isPlaying && currentPanel != 0)
{
SelectTab(PanelTab.Account);
return;
}
// Check that the tabs are enabled, if not - we must re-render tabs
if (APIUser.IsLoggedIn && (!_tabButtons[1].enabledSelf || !_tabButtons[2].enabledSelf))
{
RenderTabs();
return;
}
// When the user isn't logged in - we only allow Settings and Authentication tabs to be viewed
if (APIUser.IsLoggedIn || currentPanel == 0 || currentPanel == 3) return;
SelectTab(PanelTab.Account);
}).Every(500);
var sdkContainer = rootVisualElement.Q("sdk-container");
sdkContainer.Add(new IMGUIContainer(() =>
{
if (!_stylesInitialized)
{
InitializeStyles();
_stylesInitialized = true;
}
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.BeginVertical();
if (Application.isPlaying)
{
GUI.enabled = false;
GUILayout.Space(20);
EditorGUILayout.LabelField("Unity Application is running ...\nStop it to access the Control Panel", titleGuiStyle, GUILayout.Width(SdkWindowWidth));
GUI.enabled = true;
GUILayout.EndVertical();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
return;
}
EditorGUILayout.Space();
GUILayout.EndVertical();
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
switch ((PanelTab) VRCSettings.ActiveWindowPanel)
{
case PanelTab.Builder:
break;
case PanelTab.ContentManager:
ShowContent();
break;
case PanelTab.Settings:
ShowSettings();
break;
case PanelTab.Account:
default:
ShowAccount();
break;
}
}));
EnvConfig.SetActiveSDKDefines();
}
private void CreateTabs()
{
_authenticationTabBtn = rootVisualElement.Q<Button>("tab-authentication");
_buildTabBtn = rootVisualElement.Q<Button>("tab-builder");
_contentManagerTabBtn = rootVisualElement.Q<Button>("tab-content-manager");
_settingsTabBtn = rootVisualElement.Q<Button>("tab-settings");
_tabButtons = new[]
{
_authenticationTabBtn,
_buildTabBtn,
_contentManagerTabBtn,
_settingsTabBtn
};
var currentPanel = VRCSettings.ActiveWindowPanel;
for (int i = 0; i < _tabButtons.Length; i++)
{
var btnIndex = i;
_tabButtons[i].EnableInClassList("active", currentPanel == btnIndex);
_tabButtons[i].SetEnabled(APIUser.IsLoggedIn ? _toolbarOptionsLoggedIn[i] : _toolbarOptionsNotLoggedIn[i]);
_tabButtons[i].clicked += () => SelectTab((PanelTab) btnIndex);
}
}
private void SelectTab(PanelTab tab)
{
if (_tabButtons == null) return;
if (EditorApplication.isPlaying) return;
if (VRCSettings.ActiveWindowPanel == (int) tab)
{
return;
}
VRCSettings.ActiveWindowPanel = (int) tab;
RenderTabs();
}
internal PanelTab CurrentTab => (PanelTab) VRCSettings.ActiveWindowPanel;
private void RenderTabs()
{
var currentPanel = (PanelTab) VRCSettings.ActiveWindowPanel;
if (currentPanel != PanelTab.Builder)
{
if (_defaultHeaderImage == null)
{
_defaultHeaderImage = Resources.Load<Texture2D>("SDK_Panel_Banner");
}
rootVisualElement.Q("banner").style.backgroundImage = _defaultHeaderImage;
}
for (int i = 0; i < _tabButtons.Length; i++)
{
_tabButtons[i].EnableInClassList("active", currentPanel == (PanelTab) i);
if (!TabsEnabled) continue;
_tabButtons[i].SetEnabled(APIUser.IsLoggedIn ? _toolbarOptionsLoggedIn[i] : _toolbarOptionsNotLoggedIn[i]);
}
if (currentPanel == PanelTab.Builder)
{
if (_builderPanel.childCount != 0) return;
ShowBuilders();
_builderPanel.RemoveFromClassList("d-none");
_sdkPanel.AddToClassList("d-none");
}
else if (_builderPanel.childCount == 1)
{
_builderPanel.AddToClassList("d-none");
_sdkPanel.RemoveFromClassList("d-none");
_builderPanel.Remove(_builderPanel.Children().First());
_builderPanel.styleSheets.Remove(_builderPanelStyles);
}
}
[UnityEditor.Callbacks.PostProcessScene]
static void OnPostProcessScene()
{
if (window != null)
window.Reset();
}
private void OnFocus()
{
Reset();
}
public void Reset()
{
ResetIssues();
// style backgrounds may be nulled on scene load. detect if so has happened
if((boxGuiStyle != null) && (boxGuiStyle.normal.background == null))
InitializeStyles();
}
[UnityEditor.Callbacks.DidReloadScripts(int.MaxValue)]
static void DidReloadScripts()
{
try
{
RefreshApiUrlSetting();
}
catch(Exception e)
{
//Unity's Mono is trash and randomly fails to assemblies types.
Debug.LogException(e);
}
}
#region Internal API
[UsedImplicitly]
internal void SetPanelIdle()
{
_panelState = SdkPanelState.Idle;
OnSdkPanelStateChange?.Invoke(this, _panelState);
}
[UsedImplicitly]
internal void SetPanelBuilding()
{
_panelState = SdkPanelState.Building;
OnSdkPanelStateChange?.Invoke(this, _panelState);
}
[UsedImplicitly]
internal void SetPanelUploading()
{
_panelState = SdkPanelState.Uploading;
OnSdkPanelStateChange?.Invoke(this, _panelState);
}
#endregion
#region Public API
public static event EventHandler OnSdkPanelEnable;
public static event EventHandler OnSdkPanelDisable;
public static event EventHandler<SdkPanelState> OnSdkPanelStateChange;
public SdkPanelState PanelState => _panelState;
#endregion
}

View File

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

View File

@ -0,0 +1,686 @@
using System;
using UnityEngine;
using UnityEditor;
using VRC.Core;
using System.Text.RegularExpressions;
using UnityEngine.UIElements;
using VRC.SDKBase.Editor;
public enum TwoFactorType
{
None,
TOTP,
Email,
}
// This file handles the Account tab of the SDK Panel
public partial class VRCSdkControlPanel : EditorWindow
{
static bool isInitialized = false;
static string clientInstallPath;
static bool signingIn = false;
static double latestSignInTime = -1.0d;
static string error = null;
private const string UNITY_UPGRADE_PROMPT_URL = "https://creators.vrchat.com/sdk/upgrade/unity-2022";
private const double LogoutCooldownAfterLogin = 0.75d;
public static bool FutureProofPublishEnabled { get { return UnityEditor.EditorPrefs.GetBool("futureProofPublish", DefaultFutureProofPublishEnabled); } }
//public static bool DefaultFutureProofPublishEnabled { get { return !SDKClientUtilities.IsInternalSDK(); } }
public static bool DefaultFutureProofPublishEnabled { get { return false; } }
internal static event EventHandler<APIUser> OnPanelLoggedIn;
internal static event EventHandler OnPanelLoggedOut;
internal static event EventHandler<ApiUserPlatforms> OnUserPlatformsFetched;
static string storedUsername
{
get
{
return null;
}
set
{
EditorPrefs.DeleteKey("sdk#username");
}
}
static string storedPassword
{
get
{
return null;
}
set
{
EditorPrefs.DeleteKey("sdk#password");
}
}
static string username { get; set; } = null;
static string password { get; set; } = null;
public static ApiServerEnvironment ApiEnvironment => serverEnvironment;
static ApiServerEnvironment serverEnvironment
{
get
{
ApiServerEnvironment env = ApiServerEnvironment.Release;
try
{
env = (ApiServerEnvironment)System.Enum.Parse(typeof(ApiServerEnvironment), UnityEditor.EditorPrefs.GetString("VRC_ApiServerEnvironment", env.ToString()));
}
catch (System.Exception e)
{
Debug.LogError("Invalid server environment name - " + e.ToString());
}
return env;
}
set
{
UnityEditor.EditorPrefs.SetString("VRC_ApiServerEnvironment", value.ToString());
API.SetApiUrlFromEnvironment(value);
}
}
private void OnEnableAccount()
{
entered2faCodeIsInvalid = false;
warningIconGraphic = Resources.Load("2FAIcons/SDK_Warning_Triangle_icon") as Texture2D;
}
public static void RefreshApiUrlSetting()
{
// this forces the static api url variable to be reset from the server environment set in editor prefs.
// needed because the static variable states get cleared when entering / exiting play mode
ApiServerEnvironment env = serverEnvironment;
serverEnvironment = env;
}
public static void InitAccount()
{
if (isInitialized)
return;
if (!APIUser.IsLoggedIn && ApiCredentials.Load())
{
APIUser.InitialFetchCurrentUser(c =>
{
window.rootVisualElement.Q<IMGUIContainer>().MarkDirtyRepaint();
if (c.Model is not APIUser apiUser)
{
VRC.Core.Logger.LogError("Failed to load user information, please log in again");
return;
}
AnalyticsSDK.LoggedInUserChanged(apiUser);
OnPanelLoggedIn?.Invoke(window, apiUser);
ApiUserPlatforms.Fetch(apiUser.id, userPlatforms =>
{
OnUserPlatformsFetched?.Invoke(window, userPlatforms);
}, null);
}, null);
}
// This code proceeds without waiting for the user fetch above to complete
clientInstallPath = SDKClientUtilities.GetSavedVRCInstallPath();
if (string.IsNullOrEmpty(clientInstallPath))
clientInstallPath = SDKClientUtilities.LoadRegistryVRCInstallPath();
signingIn = false;
isInitialized = true;
ClearContent();
}
void OnAccountGUI()
{
using (new GUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
AccountWindowGUI();
GUILayout.FlexibleSpace();
}
}
void AccountWindowGUI()
{
using (new EditorGUILayout.VerticalScope(accountWindowStyle, GUILayout.Width(340)))
{
EditorGUILayout.LabelField("Account", centeredLabelStyle);
if (signingIn)
{
if (twoFactorAuthenticationEntryType == TwoFactorType.None)
{
EditorGUILayout.LabelField("Signing in as " + username + ".");
}
OnTwoFactorAuthenticationGUI(twoFactorAuthenticationEntryType);
return;
}
if (APIUser.IsLoggedIn)
{
if (Status != "Connected")
{
EditorGUILayout.LabelField(Status);
}
OnCreatorStatusGUI();
// Add a space, pushing this away from the line that contained "Verify" on the previous page.
EditorGUILayout.Space(EditorGUIUtility.singleLineHeight);
// Disable the logout button for a short amount of time after logging in.
// This attempts to patch UX difficulties where users try to click "Verify" on the previous screen as
// 2FA automatically submits so they end up accidentally clicking Logout instead.
bool wasRecentLogin = latestSignInTime >= 0.0d && EditorApplication.timeSinceStartup < latestSignInTime + LogoutCooldownAfterLogin;
using (new EditorGUI.DisabledScope(wasRecentLogin))
{
if (GUILayout.Button("Logout"))
{
storedUsername = username = null;
storedPassword = password = null;
VRC.Tools.ClearCookies();
APIUser.Logout();
ClearContent();
OnPanelLoggedOut?.Invoke(window, EventArgs.Empty);
}
}
return;
}
InitAccount();
ApiServerEnvironment newEnv = ApiServerEnvironment.Release;
if (VRCSettings.DisplayAdvancedSettings)
newEnv = (ApiServerEnvironment)EditorGUILayout.EnumPopup("Use API", serverEnvironment);
if (serverEnvironment != newEnv)
serverEnvironment = newEnv;
const string controlNameUser = "input_user";
const string controlNamePass = "input_pass";
GUI.SetNextControlName(controlNameUser);
username = EditorGUILayout.TextField("Username/Email", username);
GUI.SetNextControlName(controlNamePass);
password = EditorGUILayout.PasswordField("Password", password);
bool attemptKeyboardSignIn = false;
if (
Event.current != null &&
Event.current.type == EventType.KeyUp &&
(Event.current.keyCode == KeyCode.Return || Event.current.keyCode == KeyCode.KeypadEnter))
{
switch (GUI.GetNameOfFocusedControl())
{
case controlNameUser:
GUI.FocusControl(controlNamePass);
break;
case controlNamePass:
attemptKeyboardSignIn = true;
break;
}
}
if (GUILayout.Button("Sign In") || attemptKeyboardSignIn)
{
SignIn(true);
}
if (GUILayout.Button("Sign up"))
{
Application.OpenURL("https://vrchat.com/register");
}
}
}
static void OnCreatorStatusGUI()
{
EditorGUILayout.LabelField("Logged in as:", APIUser.CurrentUser.displayName);
//if (SDKClientUtilities.IsInternalSDK())
// EditorGUILayout.LabelField("Developer Status: ", APIUser.CurrentUser.developerType.ToString());
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical();
EditorGUILayout.LabelField("World Creator Status: ", APIUser.CurrentUser.canPublishWorlds ? "Allowed to publish worlds" : "Not yet allowed to publish worlds");
EditorGUILayout.LabelField("Avatar Creator Status: ", APIUser.CurrentUser.canPublishAvatars ? "Allowed to publish avatars" : "Not yet allowed to publish avatars");
EditorGUILayout.EndVertical();
if (!APIUser.CurrentUser.canPublishWorldsAndAvatars)
{
if (GUILayout.Button("More Info..."))
{
ShowContentPublishPermissionsDialog();
}
}
EditorGUILayout.EndHorizontal();
}
void ShowAccount()
{
if (ConfigManager.RemoteConfig.IsInitialized())
{
if (ConfigManager.RemoteConfig.HasKey("sdkUnityVersion"))
{
string sdkUnityVersion = ConfigManager.RemoteConfig.GetString("sdkUnityVersion");
if (string.IsNullOrEmpty(sdkUnityVersion))
EditorGUILayout.LabelField("Could not fetch remote config.");
else if (Application.unityVersion != sdkUnityVersion)
{
var currentVersion = UnityVersion.Parse(Application.unityVersion).major;
var sdkVersion = UnityVersion.Parse(sdkUnityVersion).major;
if (currentVersion < sdkVersion && sdkVersion == 2022)
{
using (new EditorGUILayout.VerticalScope(unityUpgradeBannerStyle))
{
EditorGUILayout.Space(115);
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.Space();
if (GUILayout.Button("Learn More"))
{
Application.OpenURL(UNITY_UPGRADE_PROMPT_URL);
}
EditorGUILayout.Space();
}
EditorGUILayout.Space(5);
}
}
else
{
EditorGUILayout.LabelField("Unity Version", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Wrong Unity version. Please use " + sdkUnityVersion);
}
}
}
}
else
{
API.SetOnlineMode(true);
ConfigManager.RemoteConfig.Init();
}
OnAccountGUI();
}
private const string TWO_FACTOR_AUTHENTICATION_HELP_URL = "https://docs.vrchat.com/docs/setup-2fa";
private const string ENTER_2FA_CODE_TITLE_STRING = "Enter a numeric code from your authenticator app.";
private const string ENTER_2FA_CODE_LABEL_STRING = "Code:";
private const string ENTER_2FA_CODE_GUI_EVENT = "Authentication Code Field";
private const string ENTER_EMAIL_2FA_CODE_TITLE_STRING = "Check your email for a numeric code.";
private const string CHECKING_2FA_CODE_STRING = "Checking code...";
private const string ENTER_2FA_CODE_INVALID_CODE_STRING = "Oops, that code didn't work.\nTry again!";
private const string ENTER_2FA_CODE_VERIFY_STRING = "Verify";
private const string ENTER_2FA_CODE_CANCEL_STRING = "Cancel";
private const string ENTER_2FA_CODE_HELP_STRING = "Help";
private const int WARNING_ICON_SIZE = 60;
private const int WARNING_FONT_HEIGHT = 14;
static private Texture2D warningIconGraphic;
static bool entered2faCodeIsInvalid;
static bool authorizationCodeWasVerified;
static private int previousAuthenticationCodeLength = 0;
static bool checkingCode;
static string authenticationCode = "";
static string lastCheckedAuthenticationCode = "";
static System.Action onAuthenticationVerifiedAction;
static TwoFactorType _twoFactorAuthenticationEntryType = TwoFactorType.None;
static TwoFactorType twoFactorAuthenticationEntryType
{
get
{
return _twoFactorAuthenticationEntryType;
}
set
{
_twoFactorAuthenticationEntryType = value;
authenticationCode = "";
lastCheckedAuthenticationCode = "";
if (_twoFactorAuthenticationEntryType == TwoFactorType.None && !authorizationCodeWasVerified)
Logout();
}
}
static bool IsValidAuthenticationCodeFormat()
{
bool isValid2faAuthenticationCode = false;
if (!string.IsNullOrEmpty(authenticationCode))
{
// check if the input is a valid 6-digit numberic code (ignoring spaces)
Regex rx = new Regex(@"^(\s*\d\s*){6}$", RegexOptions.Compiled);
MatchCollection matches6DigitCode = rx.Matches(authenticationCode);
isValid2faAuthenticationCode = (matches6DigitCode.Count == 1);
}
return isValid2faAuthenticationCode;
}
static bool IsValidRecoveryCodeFormat()
{
bool isValid2faRecoveryCode = false;
if (!string.IsNullOrEmpty(authenticationCode))
{
// check if the input is a valid 8-digit alpha-numberic code (format xxxx-xxxx) "-" is optional & ignore any spaces
// OTP codes also exclude the letters i,l,o and the digit 1 to prevent any confusion
Regex rx = new Regex(@"^(\s*[a-hj-km-np-zA-HJ-KM-NP-Z02-9]\s*){4}-?(\s*[a-hj-km-np-zA-HJ-KM-NP-Z02-9]\s*){4}$", RegexOptions.Compiled);
MatchCollection matchesRecoveryCode = rx.Matches(authenticationCode);
isValid2faRecoveryCode = (matchesRecoveryCode.Count == 1);
}
return isValid2faRecoveryCode;
}
static void OnTwoFactorAuthenticationGUI(TwoFactorType twoFactorType)
{
if (twoFactorType == TwoFactorType.None)
return;
const int ENTER_2FA_CODE_BORDER_SIZE = 20;
const int ENTER_2FA_CODE_BUTTON_WIDTH = 260;
const int ENTER_2FA_CODE_VERIFY_BUTTON_WIDTH = ENTER_2FA_CODE_BUTTON_WIDTH / 2;
const int ENTER_2FA_CODE_ENTRY_REGION_WIDTH = 130;
const int ENTER_2FA_CODE_MIN_WINDOW_WIDTH = ENTER_2FA_CODE_VERIFY_BUTTON_WIDTH + ENTER_2FA_CODE_ENTRY_REGION_WIDTH + (ENTER_2FA_CODE_BORDER_SIZE * 3);
bool isValidAuthenticationCode = IsValidAuthenticationCodeFormat();
// Invalid code text
if (entered2faCodeIsInvalid)
{
GUIStyle s = new GUIStyle(EditorStyles.label)
{
normal =
{
textColor = new Color(1,0.3f,0.3f)
},
fontSize = WARNING_FONT_HEIGHT,
fixedHeight = WARNING_ICON_SIZE
};
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.FlexibleSpace();
using (new EditorGUILayout.VerticalScope())
{
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Label(new GUIContent(warningIconGraphic), GUILayout.Width(WARNING_ICON_SIZE), GUILayout.Height(WARNING_ICON_SIZE));
EditorGUILayout.LabelField(ENTER_2FA_CODE_INVALID_CODE_STRING, s);
}
}
GUILayout.FlexibleSpace();
}
}
else if (checkingCode)
{
// Display checking code message
EditorGUILayout.BeginVertical();
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
GUIStyle s = new GUIStyle(EditorStyles.label);
s.alignment = TextAnchor.MiddleCenter;
s.fixedHeight = WARNING_ICON_SIZE;
EditorGUILayout.LabelField(CHECKING_2FA_CODE_STRING, s, GUILayout.Height(WARNING_ICON_SIZE));
EditorGUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
EditorGUILayout.EndVertical();
}
else
{
EditorGUILayout.BeginHorizontal();
GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE);
GUILayout.FlexibleSpace();
GUIStyle titleStyle = new GUIStyle(EditorStyles.label);
titleStyle.alignment = TextAnchor.MiddleCenter;
titleStyle.wordWrap = true;
string twofactorTitle = "Enter Code";
switch (twoFactorType)
{
case TwoFactorType.TOTP:
twofactorTitle = ENTER_2FA_CODE_TITLE_STRING;
break;
case TwoFactorType.Email:
twofactorTitle = ENTER_EMAIL_2FA_CODE_TITLE_STRING;
break;
}
EditorGUILayout.LabelField(twofactorTitle, titleStyle, GUILayout.Width(ENTER_2FA_CODE_MIN_WINDOW_WIDTH - (2 * ENTER_2FA_CODE_BORDER_SIZE)), GUILayout.Height(WARNING_ICON_SIZE), GUILayout.ExpandHeight(true));
GUILayout.FlexibleSpace();
GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE);
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.BeginHorizontal();
GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE);
GUILayout.FlexibleSpace();
Vector2 size = EditorStyles.boldLabel.CalcSize(new GUIContent(ENTER_2FA_CODE_LABEL_STRING));
EditorGUILayout.LabelField(ENTER_2FA_CODE_LABEL_STRING, EditorStyles.boldLabel, GUILayout.MaxWidth(size.x));
authenticationCode = EditorGUILayout.TextField(authenticationCode);
// Verify 2FA code button
if (lastCheckedAuthenticationCode != authenticationCode && IsValidAuthenticationCodeFormat()
|| GUILayout.Button(ENTER_2FA_CODE_VERIFY_STRING, GUILayout.Width(ENTER_2FA_CODE_VERIFY_BUTTON_WIDTH)))
{
lastCheckedAuthenticationCode = authenticationCode;
checkingCode = true;
string authCodeType = API2FA.TIME_BASED_ONE_TIME_PASSWORD_AUTHENTICATION;
switch (twoFactorType)
{
case TwoFactorType.TOTP:
authCodeType = API2FA.TIME_BASED_ONE_TIME_PASSWORD_AUTHENTICATION;
break;
case TwoFactorType.Email:
authCodeType = API2FA.EMAIL_BASED_ONE_TIME_PASSWORD_AUTHENTICATION;
break;
}
APIUser.VerifyTwoFactorAuthCode(authenticationCode, authCodeType, username, password,
delegate
{
// valid 2FA code submitted
entered2faCodeIsInvalid = false;
authorizationCodeWasVerified = true;
checkingCode = false;
twoFactorAuthenticationEntryType = TwoFactorType.None;
if (null != onAuthenticationVerifiedAction)
onAuthenticationVerifiedAction();
},
delegate
{
entered2faCodeIsInvalid = true;
checkingCode = false;
}
);
}
GUILayout.FlexibleSpace();
GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE);
EditorGUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
// after user has entered an invalid code causing the invalid code message to be displayed,
// edit the code will change it's length meaning it is invalid format, so we can clear the invalid code setting until they resubmit
if (previousAuthenticationCodeLength != authenticationCode.Length)
{
previousAuthenticationCodeLength = authenticationCode.Length;
entered2faCodeIsInvalid = false;
}
GUI.enabled = true;
GUILayout.FlexibleSpace();
GUILayout.Space(ENTER_2FA_CODE_BORDER_SIZE);
EditorGUILayout.EndHorizontal();
GUILayout.FlexibleSpace();
// Two-Factor Authentication Help button
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button(ENTER_2FA_CODE_HELP_STRING))
{
Application.OpenURL(TWO_FACTOR_AUTHENTICATION_HELP_URL);
}
EditorGUILayout.EndHorizontal();
// Cancel button
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button(ENTER_2FA_CODE_CANCEL_STRING))
{
twoFactorAuthenticationEntryType = TwoFactorType.None;
Logout();
}
EditorGUILayout.EndHorizontal();
}
private static string Status
{
get
{
if (!APIUser.IsLoggedIn)
return error == null ? "Please log in." : "Error in authenticating: " + error;
if (signingIn)
return "Logging in.";
else
{
if( serverEnvironment == ApiServerEnvironment.Dev )
return "Connected to " + serverEnvironment.ToString();
return "Connected";
}
}
}
private static void OnAuthenticationCompleted()
{
AttemptLogin();
}
private static void AttemptLogin()
{
APIUser.Login(username, password,
delegate (ApiModelContainer<APIUser> c)
{
APIUser user = c.Model as APIUser;
if (c.Cookies.ContainsKey("twoFactorAuth"))
ApiCredentials.Set(user.username, username, "vrchat", c.Cookies["auth"], c.Cookies["twoFactorAuth"]);
else if (c.Cookies.ContainsKey("auth"))
ApiCredentials.Set(user.username, username, "vrchat", c.Cookies["auth"]);
else
ApiCredentials.SetHumanName(user.username);
signingIn = false;
latestSignInTime = EditorApplication.timeSinceStartup;
error = null;
storedUsername = null;
storedPassword = null;
AnalyticsSDK.LoggedInUserChanged(user);
OnPanelLoggedIn?.Invoke(window, user);
if (!APIUser.CurrentUser.canPublishWorldsAndAvatars)
{
if (UnityEditor.SessionState.GetString("HasShownContentPublishPermissionsDialogForUser", "") != user.id)
{
UnityEditor.SessionState.SetString("HasShownContentPublishPermissionsDialogForUser", user.id);
VRCSdkControlPanel.ShowContentPublishPermissionsDialog();
}
}
// Fetch platforms that the user can publish to
ApiUserPlatforms.Fetch(user.id, userPlatforms => {
OnUserPlatformsFetched?.Invoke(window, userPlatforms);
}, null);
},
delegate (ApiModelContainer<APIUser> c)
{
Logout();
error = c.Error;
EditorUtility.DisplayDialog("Error logging in", error, "OK");
VRC.Core.Logger.Log("Error logging in: " + error);
},
delegate (ApiModelContainer<API2FA> c)
{
window.rootVisualElement.Q<IMGUIContainer>().MarkDirtyRepaint();
if (c.Cookies.ContainsKey("auth"))
ApiCredentials.Set(username, username, "vrchat", c.Cookies["auth"]);
API2FA model2FA = c.Model as API2FA;
if (model2FA.requiresTwoFactorAuth.Contains(API2FA.TIME_BASED_ONE_TIME_PASSWORD_AUTHENTICATION))
twoFactorAuthenticationEntryType = TwoFactorType.TOTP;
else if (model2FA.requiresTwoFactorAuth.Contains(API2FA.EMAIL_BASED_ONE_TIME_PASSWORD_AUTHENTICATION))
twoFactorAuthenticationEntryType = TwoFactorType.Email;
else
twoFactorAuthenticationEntryType = TwoFactorType.None;
onAuthenticationVerifiedAction = OnAuthenticationCompleted;
}
);
}
private static object syncObject = new object();
private void SignIn(bool explicitAttempt)
{
lock (syncObject)
{
if (signingIn
|| APIUser.IsLoggedIn
|| (!explicitAttempt && string.IsNullOrEmpty(storedUsername)))
return;
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
EditorUtility.DisplayDialog("Error logging in", "Please enter a valid username and password.", "OK");
return;
}
signingIn = true;
}
InitAccount();
AttemptLogin();
// Show login status immediately without needing an automatic repaint (cursor movement).
Repaint();
}
public static void Logout()
{
signingIn = false;
storedUsername = null;
storedPassword = null;
VRC.Tools.ClearCookies();
APIUser.Logout();
OnPanelLoggedOut?.Invoke(window, EventArgs.Empty);
}
private void AccountDestroy()
{
signingIn = false;
isInitialized = false;
}
}

View File

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

View File

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

View File

@ -0,0 +1,16 @@
using System;
using JetBrains.Annotations;
namespace VRC.SDKBase.Editor
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
[MeansImplicitUse]
public class VRCSdkControlPanelBuilderAttribute : Attribute
{
public Type Type { get; }
public VRCSdkControlPanelBuilderAttribute(Type type)
{
Type = type;
}
}
}

Some files were not shown because too many files have changed in this diff Show More