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