Added Unity project files
This commit is contained in:
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73acba29b9a1642488ce2db2127141f3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,53 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using VRCSceneDescriptor = VRC.SDK3.Components.VRCSceneDescriptor;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class SpawnGizmoDrawer
|
||||
{
|
||||
private static VRCSceneDescriptor sceneDescriptor;
|
||||
|
||||
static SpawnGizmoDrawer()
|
||||
{
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
}
|
||||
|
||||
static void OnSceneGUI(SceneView sceneView)
|
||||
{
|
||||
if (Selection.activeTransform == null)
|
||||
return;
|
||||
|
||||
if (sceneDescriptor == null)
|
||||
{
|
||||
sceneDescriptor = GameObject.FindFirstObjectByType<VRCSceneDescriptor>();
|
||||
if (sceneDescriptor == null)
|
||||
return;
|
||||
}
|
||||
|
||||
Transform selected = Selection.activeTransform;
|
||||
foreach (Transform spawn in sceneDescriptor.spawns)
|
||||
{
|
||||
if (spawn == null)
|
||||
continue;
|
||||
|
||||
if (spawn == selected)
|
||||
{
|
||||
if (sceneDescriptor.spawnRadius != 0)
|
||||
Handles.DrawWireDisc(spawn.position, Vector3.up, sceneDescriptor.spawnRadius);
|
||||
else
|
||||
{
|
||||
float size = HandleUtility.GetHandleSize(spawn.position) * 0.5f;
|
||||
Vector3 pos = spawn.position;
|
||||
Vector3 offset1 = (Vector3.forward + Vector3.right).normalized * size;
|
||||
Vector3 offset2 = (Vector3.forward - Vector3.right).normalized * size;
|
||||
Handles.DrawLine(pos + offset1, pos - offset1);
|
||||
Handles.DrawLine(pos + offset2, pos - offset2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59a956eb4084499dbbc4004a6922c503
|
||||
timeCreated: 1744910458
|
||||
@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
using VRC.SDK3.Components;
|
||||
using VRC.SDKBase.Editor.Api;
|
||||
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(VRCAvatarPedestal))]
|
||||
public class VRCAvatarPedestalEditor : VRCInspectorBase
|
||||
{
|
||||
|
||||
private SerializedProperty _blueprintId;
|
||||
private SerializedProperty _placement;
|
||||
private SerializedProperty _changeAvatarsOnUse;
|
||||
private SerializedProperty _scale;
|
||||
|
||||
private PropertyField _fieldBlueprintId;
|
||||
private PropertyField _fieldPlacement;
|
||||
private PropertyField _fieldChangeAvatarsOnUse;
|
||||
private PropertyField _fieldScale;
|
||||
|
||||
private HelpBox _errorMessageBox;
|
||||
private HelpBox _warningMessageBox;
|
||||
|
||||
private const string ERROR_PRIVATE_AVATAR = "This pedestal contains a private avatar ID. Only the author of the avatar will be able to see the pedestal and interact with it in VRChat.";
|
||||
private const string ERROR_PRIVATE_OWN_AVATAR = "This pedestal contains a private avatar ID of your own. Only you will be able to see the pedestal and interact with it in VRChat.";
|
||||
private const string ERROR_FAILED_TO_LOAD = "Failed to load avatar information. Make sure the avatar ID is valid and the avatar is public.";
|
||||
private const string ERROR_UNAUTHORIZED = "Failed to load avatar information. Make sure you are logged in via the VRChat SDK Control Panel.";
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_blueprintId = serializedObject.FindProperty(nameof(VRCAvatarPedestal.blueprintId));
|
||||
_placement = serializedObject.FindProperty(nameof(VRCAvatarPedestal.Placement));
|
||||
_changeAvatarsOnUse = serializedObject.FindProperty(nameof(VRCAvatarPedestal.ChangeAvatarsOnUse));
|
||||
_scale = serializedObject.FindProperty(nameof(VRCAvatarPedestal.scale));
|
||||
}
|
||||
|
||||
public override void BuildInspectorGUI()
|
||||
{
|
||||
base.BuildInspectorGUI();
|
||||
_fieldBlueprintId = AddFieldLabel(_blueprintId, "Avatar ID");
|
||||
|
||||
_errorMessageBox = new HelpBox(string.Empty, HelpBoxMessageType.Error)
|
||||
{
|
||||
style =
|
||||
{
|
||||
display = DisplayStyle.None
|
||||
}
|
||||
};
|
||||
Root.Add(_errorMessageBox);
|
||||
_warningMessageBox = new HelpBox(string.Empty, HelpBoxMessageType.Warning)
|
||||
{
|
||||
style =
|
||||
{
|
||||
display = DisplayStyle.None
|
||||
}
|
||||
};
|
||||
Root.Add(_warningMessageBox);
|
||||
|
||||
_fieldPlacement = AddField(_placement);
|
||||
_fieldChangeAvatarsOnUse = AddField(_changeAvatarsOnUse);
|
||||
_fieldScale = AddField(_scale);
|
||||
_fieldBlueprintId.RegisterValueChangeCallback(evt => AvatarChanged(evt.changedProperty.stringValue).ConfigureAwait(false));
|
||||
|
||||
AvatarChanged(_blueprintId.stringValue).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void ShowError(string message)
|
||||
{
|
||||
HideWarning();
|
||||
_errorMessageBox.text = message;
|
||||
_errorMessageBox.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
|
||||
private void HideError()
|
||||
{
|
||||
_errorMessageBox.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
private void ShowWarning(string message)
|
||||
{
|
||||
HideError();
|
||||
_warningMessageBox.text = message;
|
||||
_warningMessageBox.style.display = DisplayStyle.Flex;
|
||||
}
|
||||
|
||||
private void HideWarning()
|
||||
{
|
||||
_warningMessageBox.style.display = DisplayStyle.None;
|
||||
}
|
||||
|
||||
private async Task AvatarChanged(string id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
HideError();
|
||||
HideWarning();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to log in if the user is not logged in
|
||||
if (!Core.APIUser.IsLoggedIn)
|
||||
{
|
||||
// No void task completion source in .NET Standard, so we use a <bool> here
|
||||
var resultTask = new TaskCompletionSource<bool>();
|
||||
Core.APIUser.InitialFetchCurrentUser(_ => resultTask.SetResult(true), _ => resultTask.SetResult(false));
|
||||
await resultTask.Task;
|
||||
}
|
||||
var avatarInfo = await VRCApi.GetAvatar(id, true);
|
||||
// AVM Avatars should not trigger a warning or error
|
||||
if (avatarInfo.ReleaseStatus != "public" && !avatarInfo.Lock)
|
||||
{
|
||||
if (avatarInfo.AuthorId == Core.APIUser.CurrentUser?.id)
|
||||
{
|
||||
Core.Logger.LogWarning(ERROR_PRIVATE_OWN_AVATAR);
|
||||
ShowWarning(ERROR_PRIVATE_OWN_AVATAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
Core.Logger.LogError(ERROR_PRIVATE_AVATAR);
|
||||
ShowError(ERROR_PRIVATE_AVATAR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If everything is ok - we can hide all the messages
|
||||
HideWarning();
|
||||
HideError();
|
||||
}
|
||||
catch (ApiErrorException e)
|
||||
{
|
||||
if (e.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
Core.Logger.LogError(ERROR_PRIVATE_AVATAR);
|
||||
ShowError(ERROR_PRIVATE_AVATAR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.StatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
Core.Logger.LogWarning(ERROR_UNAUTHORIZED);
|
||||
ShowWarning(ERROR_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
Core.Logger.LogException(e);
|
||||
Core.Logger.LogError(e.ErrorMessage);
|
||||
Core.Logger.LogWarning(ERROR_FAILED_TO_LOAD);
|
||||
ShowWarning(ERROR_FAILED_TO_LOAD);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Core.Logger.LogException(e);
|
||||
Core.Logger.LogWarning(ERROR_FAILED_TO_LOAD);
|
||||
ShowWarning(ERROR_FAILED_TO_LOAD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92daf15a37b84806a147aa8127651a17
|
||||
timeCreated: 1746046539
|
||||
@ -0,0 +1,328 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Components;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public static class VRCCameraDollyDrawer
|
||||
{
|
||||
private static readonly Color[] SplineColors =
|
||||
{
|
||||
new(0f, 0.7f, 0.7f),
|
||||
new(1f, 0.5f, 0f),
|
||||
new(0.6f, 0f, 0.8f),
|
||||
new(0.6f, 0.4f, 0.2f),
|
||||
new(0.2f, 0.6f, 0.9f),
|
||||
new(0.9f, 0.6f, 0.7f),
|
||||
new(0.3f, 0.3f, 0.7f),
|
||||
Color.yellow,
|
||||
new(0.8f, 0.3f, 0.3f),
|
||||
Color.magenta,
|
||||
};
|
||||
|
||||
private static VRCCameraDollyAnimation ANIMATION;
|
||||
|
||||
static VRCCameraDollyDrawer()
|
||||
{
|
||||
SceneView.duringSceneGui += OnSceneGUI;
|
||||
}
|
||||
|
||||
static void OnSceneGUI(SceneView sceneView)
|
||||
{
|
||||
// don't draw if gizmos are off
|
||||
if (!SceneView.currentDrawingSceneView.drawGizmos) return;
|
||||
|
||||
Transform[] selection = Selection.transforms;
|
||||
if (selection == null || selection.Length == 0) return;
|
||||
|
||||
// check each selected object
|
||||
foreach (Transform selected in selection)
|
||||
{
|
||||
VRCCameraDollyPath path;
|
||||
|
||||
// if an animation is selected, draw all of its paths
|
||||
if (selected.TryGetComponent(out ANIMATION))
|
||||
{
|
||||
if (ANIMATION.Paths == null) return;
|
||||
|
||||
// draw paths
|
||||
int pathIndex;
|
||||
for (pathIndex = 0; pathIndex < ANIMATION.Paths.Length; pathIndex++)
|
||||
{
|
||||
path = ANIMATION.Paths[pathIndex];
|
||||
if (path == null) continue;
|
||||
|
||||
DrawPath(ANIMATION, path);
|
||||
DrawPoints(ANIMATION, path);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// if a path is selected, draw it
|
||||
if (selected.TryGetComponent(out path))
|
||||
ANIMATION = path.GetComponentInParent<VRCCameraDollyAnimation>();
|
||||
|
||||
// if a point is selected, also draw its path
|
||||
else if (selected.TryGetComponent(out VRCCameraDollyPathPoint point))
|
||||
{
|
||||
ANIMATION = point.GetComponentInParent<VRCCameraDollyAnimation>();
|
||||
path = point.GetComponentInParent<VRCCameraDollyPath>();
|
||||
}
|
||||
|
||||
// if selected object isn't an animation, path, or point, don't draw anything
|
||||
else return;
|
||||
|
||||
DrawPath(ANIMATION, path);
|
||||
DrawPoints(ANIMATION, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DrawPath(VRCCameraDollyAnimation animation, VRCCameraDollyPath path)
|
||||
{
|
||||
if (!IsPathValid(animation, path)) return;
|
||||
|
||||
int index = path.transform.GetSiblingIndex();
|
||||
Handles.color = animation.gameObject.activeInHierarchy
|
||||
? SplineColors[index % SplineColors.Length]
|
||||
: Color.gray;
|
||||
|
||||
var points = path.Points
|
||||
.Where(p => p != null)
|
||||
.Select(p => p.transform.position)
|
||||
.ToList();
|
||||
|
||||
VRCCameraDollyAnimation.VRCCameraDollyPathType pathType = animation.PathType;
|
||||
if (points.Count < 4)
|
||||
{
|
||||
pathType = VRCCameraDollyAnimation.VRCCameraDollyPathType.Linear;
|
||||
}
|
||||
|
||||
if (pathType == VRCCameraDollyAnimation.VRCCameraDollyPathType.Linear)
|
||||
{
|
||||
for (int i = 0; i <= points.Count - 2; i++)
|
||||
{
|
||||
Handles.DrawLine(points[i], points[i+1], 5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 prev = GetPointOnSpline(points, 0f, pathType);
|
||||
for (int i = 1; i <= VRCCameraDollyAnimation.RESOLUTION; i++)
|
||||
{
|
||||
float t = i / (float)VRCCameraDollyAnimation.RESOLUTION;
|
||||
Vector3 curr = GetPointOnSpline(points, t, pathType);
|
||||
Handles.DrawLine(prev, curr, 5);
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
// draw path label in the path's color
|
||||
Handles.Label(points[0] + new Vector3(0,0.3f,0), $"Path {index+1}",
|
||||
new GUIStyle { fontSize = 25, normal = new GUIStyleState { textColor = Handles.color } });
|
||||
}
|
||||
|
||||
private static void DrawPoints(VRCCameraDollyAnimation animation, VRCCameraDollyPath path)
|
||||
{
|
||||
if (!IsPathValid(animation, path)) return;
|
||||
|
||||
for (int i = 0; i < path.Points.Length; i++)
|
||||
{
|
||||
var point = path.Points[i];
|
||||
if (point == null) continue;
|
||||
|
||||
if (animation.PathType != VRCCameraDollyAnimation.VRCCameraDollyPathType.Linear &&
|
||||
path.Points.Length >= 4 && (i == 0 || i == path.Points.Length - 1))
|
||||
{
|
||||
Handles.color = Color.red;
|
||||
Handles.DrawWireCube(point.transform.position, new Vector3(0.15f, 0.15f, 0.15f));
|
||||
Handles.Label(point.transform.position + new Vector3(0,0.1f,0), $"{(i == 0 ? "Start" : "End")} Anchor");
|
||||
|
||||
// anchors show a dotted line
|
||||
Handles.color = Color.blue;
|
||||
if (i == 0)
|
||||
Handles.DrawDottedLine(point.transform.position, path.Points[1].transform.position, 5);
|
||||
else
|
||||
Handles.DrawDottedLine(path.Points[i - 1].transform.position, point.transform.position,
|
||||
5);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 pos = point.transform.position;
|
||||
Quaternion rot = point.transform.rotation;
|
||||
|
||||
Handles.color = Color.grey;
|
||||
Handles.SphereHandleCap(0, pos, rot, 0.1f, EventType.Repaint);
|
||||
Handles.Label(point.transform.position + new Vector3(0,0.1f,0), $"Point {i+1}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsPathValid(VRCCameraDollyAnimation animation, VRCCameraDollyPath path)
|
||||
{
|
||||
if (animation == null ||
|
||||
path == null ||
|
||||
path.Points == null ||
|
||||
path.Points.Length < 2)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static Vector3 GetPointOnSpline(List<Vector3> points, float t, VRCCameraDollyAnimation.VRCCameraDollyPathType pathType)
|
||||
{
|
||||
return pathType switch
|
||||
{
|
||||
VRCCameraDollyAnimation.VRCCameraDollyPathType.Linear => Linear(points, t),
|
||||
VRCCameraDollyAnimation.VRCCameraDollyPathType.Loose => CatmullRom(points, t),
|
||||
VRCCameraDollyAnimation.VRCCameraDollyPathType.Fitted => BSpline(points, t),
|
||||
_ => Vector3.zero
|
||||
};
|
||||
}
|
||||
|
||||
static Vector3 Linear(List<Vector3> pts, float t)
|
||||
{
|
||||
int i = Mathf.FloorToInt(t * (pts.Count - 1));
|
||||
i = Mathf.Clamp(i, 0, pts.Count - 2);
|
||||
float localT = t * (pts.Count - 1) - i;
|
||||
return Vector3.Lerp(pts[i], pts[i + 1], localT);
|
||||
}
|
||||
|
||||
static Vector3 CatmullRom(List<Vector3> points, float t)
|
||||
{
|
||||
if (points.Count < 4) return Linear(points, t);
|
||||
|
||||
int numSections = points.Count - 3;
|
||||
float u = t * numSections;
|
||||
int i = Mathf.Clamp(Mathf.FloorToInt(u), 0, numSections - 1);
|
||||
u -= i;
|
||||
|
||||
Vector3 p0 = points[i];
|
||||
Vector3 p1 = points[i + 1];
|
||||
Vector3 p2 = points[i + 2];
|
||||
Vector3 p3 = points[i + 3];
|
||||
|
||||
return 0.5f * (
|
||||
2f * p1 +
|
||||
(-p0 + p2) * u +
|
||||
(2f * p0 - 5f * p1 + 4f * p2 - p3) * u * u +
|
||||
(-p0 + 3f * p1 - 3f * p2 + p3) * u * u * u
|
||||
);
|
||||
}
|
||||
|
||||
private static Vector3 BSpline(List<Vector3> points, float t)
|
||||
{
|
||||
if (points.Count < 4) return Linear(points, t);
|
||||
|
||||
int numSections = points.Count - 3;
|
||||
float u = t * numSections;
|
||||
int i = Mathf.Clamp(Mathf.FloorToInt(u), 0, numSections - 1);
|
||||
u -= i;
|
||||
|
||||
Vector3 p0 = points[i];
|
||||
Vector3 p1 = points[i + 1];
|
||||
Vector3 p2 = points[i + 2];
|
||||
Vector3 p3 = points[i + 3];
|
||||
|
||||
return GetBSplinePoint(p0, p1, p2, p3, u);
|
||||
}
|
||||
|
||||
private static Vector3 GetBSplinePoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
||||
{
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
float b0 = (-t3 + 3f * t2 - 3f * t + 1f) / 6f;
|
||||
float b1 = (3f * t3 - 6f * t2 + 4f) / 6f;
|
||||
float b2 = (-3f * t3 + 3f * t2 + 3f * t + 1f) / 6f;
|
||||
float b3 = t3 / 6f;
|
||||
Vector3 position = b0 * p0 + b1 * p1 + b2 * p2 + b3 * p3;
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(VRCCameraDollyAnimation))]
|
||||
public class VRCCameraDollyAnimationEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
if (GUILayout.Button("Collect Paths & Points"))
|
||||
{
|
||||
var animation = (VRCCameraDollyAnimation)target;
|
||||
SerializedObject animationSO = new SerializedObject(animation);
|
||||
SerializedProperty pathsProp = animationSO.FindProperty("Paths");
|
||||
pathsProp.ClearArray();
|
||||
|
||||
int pathIndex = 0;
|
||||
foreach (Transform path in animation.transform)
|
||||
{
|
||||
if (!path.TryGetComponent<VRCCameraDollyPath>(out var pathComponent)) continue;
|
||||
|
||||
SerializedObject pathSO = new SerializedObject(pathComponent);
|
||||
SerializedProperty pointsProp = pathSO.FindProperty("Points");
|
||||
pointsProp.ClearArray();
|
||||
|
||||
int pointIndex = 0;
|
||||
foreach (Transform point in path)
|
||||
{
|
||||
if (!point.TryGetComponent<VRCCameraDollyPathPoint>(out var pointComponent)) continue;
|
||||
if (pointComponent != null)
|
||||
{
|
||||
pointsProp.InsertArrayElementAtIndex(pointIndex);
|
||||
pointsProp.GetArrayElementAtIndex(pointIndex).objectReferenceValue = pointComponent;
|
||||
pointIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
pathSO.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(pathComponent);
|
||||
|
||||
pathsProp.InsertArrayElementAtIndex(pathIndex);
|
||||
pathsProp.GetArrayElementAtIndex(pathIndex).objectReferenceValue = pathComponent;
|
||||
pathIndex++;
|
||||
}
|
||||
|
||||
animationSO.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(animation);
|
||||
EditorSceneManager.MarkSceneDirty(animation.gameObject.scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(VRCCameraDollyPath))]
|
||||
public class VRCCameraDollyPathEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
if (GUILayout.Button("Collect Points"))
|
||||
{
|
||||
var path = (VRCCameraDollyPath)target;
|
||||
SerializedObject pathSO = new SerializedObject(path);
|
||||
SerializedProperty pointsProp = pathSO.FindProperty("Points");
|
||||
pointsProp.ClearArray();
|
||||
|
||||
int pointIndex = 0;
|
||||
foreach (Transform point in path.transform)
|
||||
{
|
||||
if (!point.TryGetComponent<VRCCameraDollyPathPoint>(out var pointComponent)) continue;
|
||||
if (pointComponent != null)
|
||||
{
|
||||
pointsProp.InsertArrayElementAtIndex(pointIndex);
|
||||
pointsProp.GetArrayElementAtIndex(pointIndex).objectReferenceValue = pointComponent;
|
||||
pointIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
pathSO.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(path);
|
||||
EditorSceneManager.MarkSceneDirty(path.gameObject.scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6348c1cdc3444611a7fdbac6d268dc58
|
||||
timeCreated: 1748027556
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
#if VRC_SDK_VRCSDK3
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
|
||||
[CustomEditor(typeof(VRC.SDK3.Components.VRCDestructibleUdon))]
|
||||
public class VRCDestructibleUdonEditor : Editor
|
||||
{
|
||||
VRC.SDK3.Components.VRCDestructibleUdon myTarget;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (myTarget == null)
|
||||
myTarget = (VRC.SDK3.Components.VRCDestructibleUdon)target;
|
||||
}
|
||||
|
||||
string[] UdonMethods = null;
|
||||
string[] UdonVariables = null;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
var udon = myTarget.GetComponent<VRC.Udon.UdonBehaviour>();
|
||||
if (udon != null)
|
||||
{
|
||||
#if VRC_CLIENT
|
||||
myTarget.UdonMethodApplyDamage = EditorGUILayout.TextField("On Apply Damage", myTarget.UdonMethodApplyDamage);
|
||||
myTarget.UdonMethodApplyHealing= EditorGUILayout.TextField("On Apply Healing", myTarget.UdonMethodApplyHealing);
|
||||
myTarget.UdonVariableCurrentHealth= EditorGUILayout.TextField("Current Health Variable", myTarget.UdonVariableCurrentHealth);
|
||||
myTarget.UdonVariableMaxHealth = EditorGUILayout.TextField("On Max Health Variable", myTarget.UdonVariableMaxHealth);
|
||||
#else
|
||||
List<string> methods = new List<string>(udon.GetPrograms());
|
||||
methods.Insert(0, "-none-");
|
||||
myTarget.UdonMethodApplyDamage = DrawUdonProgramPicker("On Apply Damage", myTarget.UdonMethodApplyDamage, methods);
|
||||
myTarget.UdonMethodApplyHealing = DrawUdonProgramPicker("On Apply Healing", myTarget.UdonMethodApplyHealing, methods);
|
||||
List<string> variables = new List<string>(udon.publicVariables.VariableSymbols);
|
||||
variables.Insert(0, "-none-");
|
||||
myTarget.UdonVariableCurrentHealth = DrawUdonProgramPicker("Current Health Variable", myTarget.UdonVariableCurrentHealth, variables);
|
||||
myTarget.UdonVariableMaxHealth = DrawUdonProgramPicker("Max Health Variable", myTarget.UdonVariableMaxHealth, variables);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
string DrawUdonProgramPicker(string title, string current, List<string> choices)
|
||||
{
|
||||
int index = choices.IndexOf(current);
|
||||
if (index == -1)
|
||||
index = 0;
|
||||
int value = EditorGUILayout.Popup(title, index, choices.ToArray());
|
||||
if (value != 0)
|
||||
return choices[value];
|
||||
return current;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d57b23c04034119448f23c5fdbc57662
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,25 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Midi;
|
||||
using VRC.SDKBase.Midi;
|
||||
#if (UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN) && !UNITY_ANDROID
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CustomEditor(typeof(VRCMidiListener))]
|
||||
public class VRCMidiListenerEditor : UnityEditor.Editor
|
||||
{
|
||||
#if UNITY_STANDALONE_WIN
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
public static void InitializeMidi()
|
||||
{
|
||||
VRCMidiHandler.OnLog = (message) => Debug.Log(message);
|
||||
VRCMidiHandler.Initialize = () =>
|
||||
{
|
||||
return VRCMidiHandler.OpenMidiInput<VRCPortMidiInput>(
|
||||
EditorPrefs.GetString(VRCMidiWindow.DEVICE_NAME_STRING));
|
||||
};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b1017097f3d46cd949892e0fce3ece9
|
||||
timeCreated: 1612853300
|
||||
@ -0,0 +1,319 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Midi;
|
||||
|
||||
public class VRCMidiEditorVisualizer : EditorWindow
|
||||
{
|
||||
private MidiFile _midiFile;
|
||||
private Vector2 _scroll;
|
||||
private bool _hasGenerated;
|
||||
private float _maxDistanceNotes;
|
||||
|
||||
private PreviewRenderUtility _previewRenderUtility;
|
||||
private Texture _outputTexture;
|
||||
private Mesh _meshMidi;
|
||||
private Mesh _meshSideNotes;
|
||||
private Mesh _meshTime;
|
||||
private Material _mainMaterial;
|
||||
private List<int> _usedChannels;
|
||||
private Dictionary<int, Color> _colors;
|
||||
|
||||
public static void Init(MidiFile midiFile)
|
||||
{
|
||||
// Get existing open window or if none, make a new one:
|
||||
VRCMidiEditorVisualizer window = GetWindow<VRCMidiEditorVisualizer>();
|
||||
window._midiFile = midiFile;
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_previewRenderUtility = new PreviewRenderUtility(false);
|
||||
var camera = _previewRenderUtility.camera;
|
||||
camera.orthographic = true;
|
||||
camera.nearClipPlane = 0.3f;
|
||||
camera.farClipPlane = 10;
|
||||
camera.orthographicSize = 20f;
|
||||
camera.transform.position = new Vector3(0f, 2f, 0f);
|
||||
camera.transform.LookAt(Vector3.zero);
|
||||
|
||||
InititlizeData();
|
||||
wantsMouseMove = true;
|
||||
}
|
||||
|
||||
private void InititlizeData()
|
||||
{
|
||||
_mainMaterial = new Material(Shader.Find("VRChat/Mobile/Toon Lit"));
|
||||
|
||||
_meshMidi = new Mesh();
|
||||
_meshSideNotes = new Mesh();
|
||||
_meshTime = new Mesh();
|
||||
|
||||
_hasGenerated = false;
|
||||
}
|
||||
|
||||
public void OnDisable()
|
||||
{
|
||||
if (_previewRenderUtility != null)
|
||||
{
|
||||
_previewRenderUtility.Cleanup();
|
||||
}
|
||||
|
||||
if (_meshMidi != null)
|
||||
{
|
||||
DestroyImmediate(_meshMidi);
|
||||
DestroyImmediate(_meshSideNotes);
|
||||
DestroyImmediate(_meshTime);
|
||||
DestroyImmediate(_mainMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (_midiFile == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Editor was created without Midi File.", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_meshMidi == null)
|
||||
{
|
||||
InititlizeData();
|
||||
}
|
||||
|
||||
|
||||
if (!_hasGenerated)
|
||||
{
|
||||
GenerateNoteObject();
|
||||
GenerateMeshTime();
|
||||
}
|
||||
|
||||
GenerateSideNotes();
|
||||
ShowChannelLegend();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
// Main Note area
|
||||
_scroll = EditorGUILayout.BeginScrollView(_scroll, false, false, GUILayout.ExpandWidth(true));
|
||||
Rect rect = GUILayoutUtility.GetRect(_maxDistanceNotes*10, 1280);
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
rect.width = position.width-16;
|
||||
rect.height = position.height - EditorGUIUtility.singleLineHeight*2 -3;
|
||||
rect.y += EditorGUIUtility.singleLineHeight+3;
|
||||
|
||||
var camera = _previewRenderUtility.camera;
|
||||
camera.orthographicSize = rect.height / 20;
|
||||
camera.transform.position = new Vector3(rect.width / 20 + _scroll.x / 10, 2, 128 - rect.height / 20 - _scroll.y / 10);
|
||||
|
||||
_previewRenderUtility.BeginPreview(rect, GUIStyle.none);
|
||||
_previewRenderUtility.DrawMesh(_meshTime, Matrix4x4.identity, _mainMaterial, 0);
|
||||
_previewRenderUtility.DrawMesh(_meshMidi,Matrix4x4.identity,_mainMaterial,0);
|
||||
_previewRenderUtility.DrawMesh(_meshSideNotes, Vector3.right * (_scroll.x / 10), Quaternion.identity, _mainMaterial,0);
|
||||
_previewRenderUtility.camera.Render();
|
||||
_previewRenderUtility.EndAndDrawPreview(rect);
|
||||
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (Event.current.type == EventType.MouseMove)
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void ShowChannelLegend()
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField("Channels:");
|
||||
foreach (int channel in _usedChannels)
|
||||
{
|
||||
EditorGUILayout.LabelField(channel.ToString(), new GUIStyle(){alignment = TextAnchor.MiddleCenter, normal = new GUIStyleState(){textColor = _colors[channel]}}, new GUILayoutOption[]{GUILayout.Width(20)});
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public void GenerateNoteObject()
|
||||
{
|
||||
_meshMidi.Clear();
|
||||
_usedChannels = new List<int>();
|
||||
|
||||
MidiData data = _midiFile.data;
|
||||
|
||||
List<Vector3> positions = new List<Vector3>();
|
||||
List<int> tri = new List<int>();
|
||||
List<Color> colors = new List<Color>();
|
||||
|
||||
// Iterate over the list once to get all the used channels
|
||||
foreach (var track in data.tracks)
|
||||
{
|
||||
foreach (var block in track.blocks)
|
||||
{
|
||||
if(!_usedChannels.Contains(block.channel)) _usedChannels.Add(block.channel);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate colors for all channels, spread across spectrum evenly
|
||||
_colors = new Dictionary<int, Color>();
|
||||
for (int i = 0; i < _usedChannels.Count; i++)
|
||||
{
|
||||
float normalizedPosition = Mathf.InverseLerp(0, _usedChannels.Count, i);
|
||||
_colors.Add(_usedChannels[i], Color.HSVToRGB(normalizedPosition, .9f, .9f));
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (int TrackIndex = 0; TrackIndex < data.tracks.Length; TrackIndex++)
|
||||
{
|
||||
MidiData.MidiTrack track = data.tracks[TrackIndex];
|
||||
MidiData.MidiBlock[] blocks = track.blocks;
|
||||
|
||||
for(int blockIndex = 0; blockIndex < blocks.Length; blockIndex++)
|
||||
{
|
||||
MidiData.MidiBlock block = blocks[blockIndex];
|
||||
float endTime = block.endTimeMs / 100 + 10;
|
||||
if ( _maxDistanceNotes < endTime)
|
||||
{
|
||||
_maxDistanceNotes = endTime;
|
||||
}
|
||||
|
||||
positions.Add(new Vector3((block.startTimeMs / 100f) + 10, 0, block.note ));
|
||||
positions.Add(new Vector3(endTime, 0, block.note ));
|
||||
positions.Add(new Vector3((block.startTimeMs / 100f) + 10, 0, block.note + 1f));
|
||||
positions.Add(new Vector3(endTime, 0, block.note + 1f));
|
||||
|
||||
tri.Add(index);
|
||||
tri.Add(index + 2);
|
||||
tri.Add(index + 1);
|
||||
tri.Add(index + 1);
|
||||
tri.Add(index + 2);
|
||||
tri.Add(index + 3);
|
||||
index += 4;
|
||||
|
||||
colors.Add(_colors[block.channel]);
|
||||
colors.Add(_colors[block.channel]);
|
||||
colors.Add(_colors[block.channel]);
|
||||
colors.Add(_colors[block.channel]);
|
||||
|
||||
if(!_usedChannels.Contains(block.channel)) _usedChannels.Add(block.channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var camera = _previewRenderUtility.camera;
|
||||
camera.transform.position = new Vector3(_maxDistanceNotes/2, 2f, 64);
|
||||
|
||||
_meshMidi.vertices = positions.ToArray();
|
||||
_meshMidi.triangles = tri.ToArray();
|
||||
_meshMidi.colors = colors.ToArray();
|
||||
_hasGenerated = true;
|
||||
}
|
||||
|
||||
public void GenerateSideNotes()
|
||||
{
|
||||
|
||||
_meshSideNotes.Clear();
|
||||
|
||||
List<Vector3> positions = new List<Vector3>();
|
||||
List<int> tri = new List<int>();
|
||||
List<Color> colors = new List<Color>();
|
||||
|
||||
int index = 0;
|
||||
int skip = -1;
|
||||
bool whiteNote = true;
|
||||
|
||||
Color color;
|
||||
for (int Notes = 0; Notes < 128; Notes++)
|
||||
{
|
||||
skip++;
|
||||
skip %= 12;
|
||||
|
||||
if (skip == 5 || skip == 0)
|
||||
{
|
||||
whiteNote = !whiteNote;
|
||||
}
|
||||
|
||||
whiteNote = !whiteNote;
|
||||
|
||||
if (whiteNote)
|
||||
{
|
||||
positions.Add(new Vector3(0, 0.3f, Notes + 0.05f));
|
||||
positions.Add(new Vector3(10, 0.3f, Notes + 0.05f));
|
||||
positions.Add(new Vector3(0, 0.3f, Notes + 0.95f));
|
||||
positions.Add(new Vector3(10, 0.3f, Notes + 0.95f));
|
||||
|
||||
color = Color.white;
|
||||
}
|
||||
else
|
||||
{
|
||||
positions.Add(new Vector3(0, 0.3f, Notes + 0.05f));
|
||||
positions.Add(new Vector3(10, 0.3f, Notes + 0.05f));
|
||||
positions.Add(new Vector3(0, 0.3f, Notes + 0.95f));
|
||||
positions.Add(new Vector3(10, 0.3f, Notes + 0.95f));
|
||||
color = Color.black;
|
||||
|
||||
}
|
||||
|
||||
if(Mathf.FloorToInt((1280 - (GUIUtility.GUIToScreenPoint(Event.current.mousePosition).y + _scroll.y - position.y - EditorGUIUtility.singleLineHeight*2.3f))/ 10) == Notes)
|
||||
{
|
||||
color = Color.gray;
|
||||
}
|
||||
|
||||
colors.Add(color);
|
||||
colors.Add(color);
|
||||
colors.Add(color);
|
||||
colors.Add(color);
|
||||
|
||||
tri.Add(index);
|
||||
tri.Add(index + 2);
|
||||
tri.Add(index + 1);
|
||||
tri.Add(index + 1);
|
||||
tri.Add(index + 2);
|
||||
tri.Add(index + 3);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
_meshSideNotes.vertices = positions.ToArray();
|
||||
_meshSideNotes.triangles = tri.ToArray();
|
||||
_meshSideNotes.colors = colors.ToArray();
|
||||
}
|
||||
|
||||
private void GenerateMeshTime()
|
||||
{
|
||||
_meshTime.Clear();
|
||||
|
||||
List<Vector3> positions = new List<Vector3>();
|
||||
List<int> tri = new List<int>();
|
||||
List<Color> colors = new List<Color>();
|
||||
|
||||
int index = 0;
|
||||
int amount = Mathf.CeilToInt(((_maxDistanceNotes-10) / 600) * _midiFile.data.bpm);
|
||||
|
||||
Color color = Color.black;
|
||||
for (int beats = 0; beats < amount; beats++)
|
||||
{
|
||||
float offset = (beats * (600f / _midiFile.data.bpm)) + 10;
|
||||
positions.Add(new Vector3(-0.1f + offset, -0.3f, 0));
|
||||
positions.Add(new Vector3(0.1f + offset, -0.3f, 0));
|
||||
positions.Add(new Vector3(-0.1f + offset, -0.3f, 128));
|
||||
positions.Add(new Vector3(0.1f + offset, -0.3f, 128));
|
||||
|
||||
colors.Add(color);
|
||||
colors.Add(color);
|
||||
colors.Add(color);
|
||||
colors.Add(color);
|
||||
|
||||
tri.Add(index);
|
||||
tri.Add(index + 2);
|
||||
tri.Add(index + 1);
|
||||
tri.Add(index + 1);
|
||||
tri.Add(index + 2);
|
||||
tri.Add(index + 3);
|
||||
index += 4;
|
||||
}
|
||||
|
||||
_meshTime.vertices = positions.ToArray();
|
||||
_meshTime.triangles = tri.ToArray();
|
||||
_meshTime.colors = colors.ToArray();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88390b175b72faa49b553b95cbcac908
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,144 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Midi;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CustomEditor(typeof(VRCMidiPlayer))]
|
||||
public class VRCMidiPlayerEditor : UnityEditor.Editor
|
||||
{
|
||||
private VRCMidiPlayer _player;
|
||||
public bool displayDebugBlocks;
|
||||
|
||||
// Serialized Properties
|
||||
private SerializedProperty _midiFileProp;
|
||||
private SerializedProperty _audioSourceProp;
|
||||
private SerializedProperty _targetBehavioursProp;
|
||||
|
||||
private const string MidiAssetReloadKey = "MidiAssetReloaded";
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
// Fetch the objects from the GameObject script to display in the inspector
|
||||
_midiFileProp = serializedObject.FindProperty(nameof(VRCMidiPlayer.midiFile));
|
||||
_audioSourceProp = serializedObject.FindProperty(nameof(VRCMidiPlayer.audioSource));
|
||||
_targetBehavioursProp = serializedObject.FindProperty(nameof(VRCMidiPlayer.targetBehaviours));
|
||||
|
||||
_player = (VRCMidiPlayer)target;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
displayDebugBlocks = EditorPrefs.GetBool(GetPrefsNameFor(nameof(displayDebugBlocks)), false);
|
||||
}
|
||||
|
||||
private static string GetPrefsNameFor(string value)
|
||||
{
|
||||
return $"VRCMidiPlayerEditor.{value}";
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
bool _isReady = _player.midiFile != null &&
|
||||
_player.audioSource != null &&
|
||||
_player.audioSource.clip != null &&
|
||||
_player.targetBehaviours.Length > 0 &&
|
||||
_player.targetBehaviours[0] != null ;
|
||||
|
||||
if (_isReady)
|
||||
{
|
||||
EditorGUILayout.HelpBox("✔ Midi Player is Ready!", MessageType.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Not Ready - see messages below.", MessageType.Warning);
|
||||
}
|
||||
|
||||
// Display Midi File Field
|
||||
EditorGUILayout.PropertyField(
|
||||
_midiFileProp,
|
||||
new GUIContent(
|
||||
"Midi File", null,
|
||||
"The MIDI file in SMF format whose data you want to trigger."
|
||||
));
|
||||
|
||||
// Ensure a Midi File is set before continuing
|
||||
if (!_player.midiFile)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Choose a Midi File to continue setting up the Player.", MessageType.Info);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
// Display Audio Source Field
|
||||
EditorGUILayout.PropertyField(
|
||||
_audioSourceProp,
|
||||
new GUIContent(
|
||||
"Audio Source", null,
|
||||
"The AudioSource component with the audio clip corresponding to your MIDI data."
|
||||
));
|
||||
|
||||
// Add audio source if it's not set
|
||||
if (!_player.audioSource)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Set or Create an AudioSource to continue.", MessageType.Info);
|
||||
if (GUILayout.Button("Create One Here"))
|
||||
{
|
||||
_player.audioSource = _player.gameObject.AddComponent<AudioSource>();
|
||||
}
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
// Force reimport midi assets one time per session
|
||||
if (_player.midiFile != null && _player.midiFile.audioClip == null)
|
||||
{
|
||||
string key = $"{MidiAssetReloadKey}-{_player.midiFile.GetInstanceID()}";
|
||||
if (!SessionState.GetBool(key, false))
|
||||
{
|
||||
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(_player.midiFile), ImportAssetOptions.ForceUpdate);
|
||||
SessionState.SetBool(key, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically set AudioSource clip from MidiAsset if possible
|
||||
else if (_player.midiFile.audioClip != null && _player.audioSource.clip == null || _player.audioSource.clip != _player.midiFile.audioClip )
|
||||
{
|
||||
_player.audioSource.clip = _player.midiFile.audioClip;
|
||||
}
|
||||
|
||||
if (_player.audioSource.clip == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("You need to set the AudioClip in the AudioSource.", MessageType.Warning);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
// Display target UdonBehaviours field
|
||||
EditorGUILayout.PropertyField(
|
||||
_targetBehavioursProp,
|
||||
new GUIContent(
|
||||
"Target Behaviours", null,
|
||||
"An array of UdonBehaviours which will have MIDI Note On and Off events sent to them"
|
||||
));
|
||||
|
||||
// Exit Early if there are not target behaviours set
|
||||
if (_player.targetBehaviours.Length == 0 || _player.targetBehaviours[0] == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Set some target UdonBehaviours above to continue.", MessageType.Info);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
bool openVisualizer = GUILayout.Button("Open Visualizer");
|
||||
if (openVisualizer)
|
||||
{
|
||||
VRCMidiEditorVisualizer.Init(_player.midiFile);
|
||||
}
|
||||
|
||||
// Apply changes to the serializedProperty - always do this at the end of OnInspectorGUI.
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76fb4f8f2f07c024795a6acecfeaefcc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,244 @@
|
||||
#if VRC_SDK_VRCSDK3 && UNITY_EDITOR
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using VRC.SDKBase;
|
||||
using VRC.SDKBase.Editor.Versioning;
|
||||
using VRCPickup = VRC.SDK3.Components.VRCPickup;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(VRCPickup))]
|
||||
public class VRCPickupEditor3 : VRCInspectorBase
|
||||
{
|
||||
private SerializedProperty propVersion;
|
||||
private SerializedProperty propMomentumTransferMethod;
|
||||
private SerializedProperty propDisallowTheft;
|
||||
private SerializedProperty propExactGun;
|
||||
private SerializedProperty propExactGrip;
|
||||
private SerializedProperty propAllowManipulationWhenEquipped;
|
||||
private SerializedProperty propOrientation;
|
||||
private SerializedProperty propAutoHold;
|
||||
private SerializedProperty propInteractionText;
|
||||
private SerializedProperty propUseText;
|
||||
private SerializedProperty propThrowVelocityBoostMinSpeed;
|
||||
private SerializedProperty propThrowVelocityBoostScale;
|
||||
private SerializedProperty propPickupable;
|
||||
private SerializedProperty propProximity;
|
||||
|
||||
private PropertyField fieldMomentumTransferMethod;
|
||||
private PropertyField fieldDisallowTheft;
|
||||
private PropertyField fieldExactGun;
|
||||
private PropertyField fieldExactGrip;
|
||||
private PropertyField fieldAllowManipulationWhenEquipped;
|
||||
private PropertyField fieldOrientation;
|
||||
private PropertyField fieldAutoHold;
|
||||
private PropertyField fieldInteractionText;
|
||||
private PropertyField fieldUseText;
|
||||
private PropertyField fieldThrowVelocityBoostMinSpeed;
|
||||
private PropertyField fieldThrowVelocityBoostScale;
|
||||
private PropertyField fieldPickupable;
|
||||
private PropertyField fieldProximity;
|
||||
|
||||
private ComponentVersionUI<VRCPickup.Version> versionUI;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
propVersion = serializedObject.FindProperty(nameof(VRCPickup.version));
|
||||
propMomentumTransferMethod = serializedObject.FindProperty(nameof(VRCPickup.MomentumTransferMethod));
|
||||
propDisallowTheft = serializedObject.FindProperty(nameof(VRCPickup.DisallowTheft));
|
||||
propExactGun = serializedObject.FindProperty(nameof(VRCPickup.ExactGun));
|
||||
propExactGrip = serializedObject.FindProperty(nameof(VRCPickup.ExactGrip));
|
||||
propAllowManipulationWhenEquipped = serializedObject.FindProperty(nameof(VRCPickup.allowManipulationWhenEquipped));
|
||||
propOrientation = serializedObject.FindProperty(nameof(VRCPickup.orientation));
|
||||
propAutoHold = serializedObject.FindProperty(nameof(VRCPickup.AutoHold));
|
||||
propInteractionText = serializedObject.FindProperty(nameof(VRCPickup.InteractionText));
|
||||
propUseText = serializedObject.FindProperty(nameof(VRCPickup.UseText));
|
||||
propThrowVelocityBoostMinSpeed = serializedObject.FindProperty(nameof(VRCPickup.ThrowVelocityBoostMinSpeed));
|
||||
propThrowVelocityBoostScale = serializedObject.FindProperty(nameof(VRCPickup.ThrowVelocityBoostScale));
|
||||
propPickupable = serializedObject.FindProperty(nameof(VRCPickup.pickupable));
|
||||
propProximity = serializedObject.FindProperty(nameof(VRCPickup.proximity));
|
||||
}
|
||||
|
||||
#region Inspector GUI Construction (Common Pattern for All Custom Editors)
|
||||
|
||||
public override void BuildInspectorGUI()
|
||||
{
|
||||
base.BuildInspectorGUI();
|
||||
|
||||
// Add version system
|
||||
var migrator = new VRCPickupVersionMigrator(propAutoHold, propOrientation, propInteractionText, OnVersionChanged);
|
||||
versionUI = AddVersionSystem(propVersion, migrator,
|
||||
"https://creators.vrchat.com/worlds/components/vrc_pickup#versions");
|
||||
// Create AutoHold enum field (shown in V1.0, hidden in V1.1+ when toggle is used)
|
||||
fieldAutoHold = AddField(propAutoHold);
|
||||
fieldAutoHold.RegisterValueChangeCallback(AutoHoldCallback);
|
||||
|
||||
fieldUseText = AddFieldTooltip(propUseText,
|
||||
"Text to display describing action for clicking button, when this pickup is already being held.");
|
||||
fieldInteractionText = AddFieldTooltip(propInteractionText,
|
||||
"Text displayed when user hovers over the pickup.");
|
||||
fieldProximity = AddField(propProximity);
|
||||
|
||||
fieldOrientation = AddField(propOrientation);
|
||||
fieldOrientation.RegisterValueChangeCallback(OrientationCallback);
|
||||
|
||||
fieldExactGun = AddField(propExactGun);
|
||||
fieldExactGrip = AddField(propExactGrip);
|
||||
fieldPickupable = AddField(propPickupable);
|
||||
fieldDisallowTheft = AddField(propDisallowTheft);
|
||||
fieldAllowManipulationWhenEquipped = AddField(propAllowManipulationWhenEquipped);
|
||||
fieldMomentumTransferMethod = AddField(propMomentumTransferMethod);
|
||||
fieldThrowVelocityBoostMinSpeed = AddField(propThrowVelocityBoostMinSpeed);
|
||||
fieldThrowVelocityBoostScale = AddField(propThrowVelocityBoostScale);
|
||||
|
||||
// Now that all fields are created, we can update their visibility based on version
|
||||
var pickup = target as VRCPickup;
|
||||
SetupAutoHoldField(pickup.version);
|
||||
RefreshAllFieldVisibility(pickup.version);
|
||||
}
|
||||
|
||||
// Creates the toggle field for modern AutoHold UI (V1.1+)
|
||||
private void SetupAutoHoldField(VRCPickup.Version version)
|
||||
{
|
||||
var container = fieldAutoHold.parent;
|
||||
|
||||
if (!fieldAutoHold.ClassListContains("auto-hold-enum-field"))
|
||||
fieldAutoHold.AddToClassList("auto-hold-enum-field");
|
||||
|
||||
var toggleField = container.Query().Name("autoHoldToggle").First() as Toggle;
|
||||
if (toggleField == null)
|
||||
{
|
||||
toggleField = new Toggle("Auto Hold")
|
||||
{
|
||||
name = "autoHoldToggle",
|
||||
tooltip = "When enabled, the pickup will stay in hand when trigger is released"
|
||||
};
|
||||
toggleField.AddToClassList("auto-hold-toggle-field");
|
||||
|
||||
toggleField.RegisterValueChangedCallback(evt => {
|
||||
serializedObject.Update();
|
||||
propAutoHold.enumValueIndex = evt.newValue ?
|
||||
(int)VRC_Pickup.AutoHoldMode.Yes :
|
||||
(int)VRC_Pickup.AutoHoldMode.No;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
AutoHoldChanged();
|
||||
});
|
||||
|
||||
container.Insert(container.IndexOf(fieldAutoHold) + 1, toggleField);
|
||||
}
|
||||
}
|
||||
|
||||
// Switches between enum dropdown (V1.0) and toggle (V1.1+) for AutoHold field
|
||||
private void UpdateAutoHoldFieldVisibility(VRCPickup.Version version)
|
||||
{
|
||||
var container = fieldAutoHold.parent;
|
||||
var toggleField = container.Query().Name("autoHoldToggle").First() as Toggle;
|
||||
|
||||
if (toggleField == null) return;
|
||||
|
||||
if (IsModernVersion(version))
|
||||
{
|
||||
fieldAutoHold.style.display = DisplayStyle.None;
|
||||
toggleField.style.display = DisplayStyle.Flex;
|
||||
UpdateToggleFromEnumValue(toggleField);
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldAutoHold.style.display = DisplayStyle.Flex;
|
||||
toggleField.style.display = DisplayStyle.None;
|
||||
}
|
||||
}
|
||||
|
||||
// Syncs toggle state with underlying enum value without triggering callbacks
|
||||
private void UpdateToggleFromEnumValue(Toggle toggle)
|
||||
{
|
||||
bool treatAsAutoHold = propAutoHold.enumValueIndex
|
||||
is (int)VRC_Pickup.AutoHoldMode.Yes
|
||||
or (int)VRC_Pickup.AutoHoldMode.Sometimes;
|
||||
toggle.SetValueWithoutNotify(treatAsAutoHold);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region VRC Pickup-Specific Helper Methods
|
||||
|
||||
// Checks if version uses modern UI (toggle instead of enum dropdown)
|
||||
private bool IsModernVersion(VRCPickup.Version version)
|
||||
{
|
||||
return version > VRCPickup.Version.Version_1_0;
|
||||
}
|
||||
|
||||
private void AutoHoldCallback(SerializedPropertyChangeEvent evt)
|
||||
{
|
||||
AutoHoldChanged();
|
||||
}
|
||||
|
||||
// Updates UseText field visibility when AutoHold setting changes
|
||||
private void AutoHoldChanged()
|
||||
{
|
||||
bool canDisplayUseText = propAutoHold.enumValueIndex
|
||||
is (int)VRC_Pickup.AutoHoldMode.Yes
|
||||
or (int)VRC_Pickup.AutoHoldMode.Sometimes
|
||||
or (int)VRC_Pickup.AutoHoldMode.AutoDetect; // Use text can appear if gun or grip transforms are assigned.
|
||||
|
||||
fieldUseText.SetVisible(canDisplayUseText);
|
||||
|
||||
// Update version upgrade info visibility
|
||||
versionUI?.RefreshUpgradeInfo();
|
||||
}
|
||||
|
||||
private void OrientationCallback(SerializedPropertyChangeEvent evt) => OrientationChanged();
|
||||
|
||||
// Shows/hides ExactGun and ExactGrip fields based on pickup orientation
|
||||
private void OrientationChanged()
|
||||
{
|
||||
switch ((VRC_Pickup.PickupOrientation)propOrientation.enumValueIndex)
|
||||
{
|
||||
case VRC_Pickup.PickupOrientation.Any:
|
||||
fieldExactGun.SetVisible(true);
|
||||
fieldExactGrip.SetVisible(true);
|
||||
break;
|
||||
case VRC_Pickup.PickupOrientation.Grip:
|
||||
fieldExactGun.SetVisible(false);
|
||||
fieldExactGrip.SetVisible(true);
|
||||
break;
|
||||
case VRC_Pickup.PickupOrientation.Gun:
|
||||
fieldExactGun.SetVisible(true);
|
||||
fieldExactGrip.SetVisible(false);
|
||||
break;
|
||||
}
|
||||
|
||||
// Update version upgrade info since orientation affects AutoDetect migration
|
||||
versionUI?.RefreshUpgradeInfo();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Version-Dependent UI Management (Pattern for Versioned Components)
|
||||
|
||||
// Refreshes all field visibility based on current version and field states
|
||||
private void RefreshAllFieldVisibility(VRCPickup.Version version)
|
||||
{
|
||||
versionUI?.RefreshUpgradeInfo();
|
||||
UpdateAutoHoldFieldVisibility(version);
|
||||
OrientationChanged();
|
||||
AutoHoldChanged();
|
||||
}
|
||||
|
||||
// Called when version changes to update UI elements
|
||||
private void OnVersionChanged(VRCPickup.Version newVersion)
|
||||
{
|
||||
RefreshAllFieldVisibility(newVersion);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8cc4c1876b26174fbaeb062178a6bda
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,154 @@
|
||||
using UnityEditor;
|
||||
using VRC.SDK3.Components;
|
||||
using VRC.SDKBase;
|
||||
using VRC.SDKBase.Editor.Versioning;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Version migration logic for VRCPickup
|
||||
/// </summary>
|
||||
internal class VRCPickupVersionMigrator : ComponentVersionMigrator<VRCPickup.Version>
|
||||
{
|
||||
private readonly SerializedProperty autoHoldProperty;
|
||||
private readonly SerializedProperty orientationProperty;
|
||||
private readonly SerializedProperty interactionTextProperty;
|
||||
private readonly System.Action<VRCPickup.Version> onVersionChangedCallback;
|
||||
|
||||
public VRCPickupVersionMigrator(SerializedProperty autoHoldProperty, SerializedProperty orientationProperty, SerializedProperty interactionTextProperty, System.Action<VRCPickup.Version> onVersionChangedCallback = null)
|
||||
{
|
||||
this.autoHoldProperty = autoHoldProperty;
|
||||
this.orientationProperty = orientationProperty;
|
||||
this.interactionTextProperty = interactionTextProperty;
|
||||
this.onVersionChangedCallback = onVersionChangedCallback;
|
||||
}
|
||||
|
||||
// Creates the success dialog message explaining what specific changes were made during upgrade
|
||||
public override string GetUpgradeChangesMessage(VRCPickup.Version oldVersion, VRCPickup.Version newVersion, SerializedObject serializedObject)
|
||||
{
|
||||
if (newVersion <= oldVersion) return null;
|
||||
|
||||
// Handle multi-selection with simplified message
|
||||
if (serializedObject.isEditingMultipleObjects)
|
||||
return $"Version upgraded successfully!\n{serializedObject.targetObjects.Length} pickup(s) upgraded to Version 1.1.";
|
||||
|
||||
var orientation = (VRC_Pickup.PickupOrientation)orientationProperty.enumValueIndex;
|
||||
var message = "Version upgraded successfully!\n";
|
||||
|
||||
int oldAutoHoldValue = autoHoldProperty.enumValueIndex;
|
||||
var changes = new System.Collections.Generic.List<string>();
|
||||
|
||||
if (oldAutoHoldValue == (int)VRC_Pickup.AutoHoldMode.Sometimes)
|
||||
{
|
||||
changes.Add("Changed 'Sometimes' to 'Yes' for better controller compatibility");
|
||||
}
|
||||
else if (oldAutoHoldValue == (int)VRC_Pickup.AutoHoldMode.AutoDetect)
|
||||
{
|
||||
bool willBeAutoHold = VRC_Pickup.IsGlobalAutoHoldPickup((VRC_Pickup.AutoHoldMode)oldAutoHoldValue, orientation);
|
||||
var newValue = willBeAutoHold ? "Yes" : "No";
|
||||
|
||||
var change = $"Changed 'Auto Detect' to '{newValue}' based on orientation ({orientation})";
|
||||
|
||||
if (newValue == "No")
|
||||
{
|
||||
change += "\n'Any' orientation pickups don't use auto-hold";
|
||||
}
|
||||
else
|
||||
{
|
||||
change += "\nGrip/Gun orientation pickups use auto-hold";
|
||||
}
|
||||
|
||||
changes.Add(change);
|
||||
}
|
||||
|
||||
if (changes.Count > 0)
|
||||
{
|
||||
message += "Changes made:\n" + string.Join("\n", changes);
|
||||
}
|
||||
else
|
||||
{
|
||||
message += "No changes needed - your settings are already compatible with this version.";
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
// Performs the actual data migration when upgrading to a specific version
|
||||
public override void MigrateToVersion(VRCPickup.Version oldVersion, VRCPickup.Version newVersion, SerializedObject serializedObject)
|
||||
{
|
||||
// Handle migration from old busted AutoHold to Global AutoHold
|
||||
if (oldVersion == VRCPickup.Version.Version_1_0)
|
||||
{
|
||||
var currentOrientation = (VRC_Pickup.PickupOrientation)orientationProperty.enumValueIndex;
|
||||
var currentAutoHoldMode = (VRC_Pickup.AutoHoldMode)autoHoldProperty.enumValueIndex;
|
||||
|
||||
bool willBeAutoHold = VRC_Pickup.IsGlobalAutoHoldPickup(currentAutoHoldMode, currentOrientation);
|
||||
var newAutoHoldMode = willBeAutoHold ? VRC_Pickup.AutoHoldMode.Yes : VRC_Pickup.AutoHoldMode.No;
|
||||
|
||||
if ((int)newAutoHoldMode != autoHoldProperty.enumValueIndex)
|
||||
{
|
||||
autoHoldProperty.enumValueIndex = (int)newAutoHoldMode;
|
||||
autoHoldProperty.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Determines when to show the upgrade info box at the top of the inspector
|
||||
public override bool ShouldShowUpgradePrompt(VRCPickup.Version version, SerializedObject serializedObject)
|
||||
{
|
||||
// Always show upgrade for ANY Version 1.0 pickup in multi-selection
|
||||
if (serializedObject.isEditingMultipleObjects)
|
||||
return version == VRCPickup.Version.Version_1_0;
|
||||
|
||||
return version == VRCPickup.Version.Version_1_0 &&
|
||||
(autoHoldProperty.enumValueIndex == (int)VRC_Pickup.AutoHoldMode.Sometimes ||
|
||||
autoHoldProperty.enumValueIndex == (int)VRC_Pickup.AutoHoldMode.AutoDetect);
|
||||
}
|
||||
|
||||
// Returns message about why they should upgrade
|
||||
public override string GetUpgradePromptText(VRCPickup.Version currentVersion, VRCPickup.Version latestVersion)
|
||||
{
|
||||
// Multi-selection mode - simplified message
|
||||
if (autoHoldProperty.serializedObject.isEditingMultipleObjects)
|
||||
return "Selected pickups use older settings.\nUpgrade all to Version 1.1 for better compatibility and simplified options.";
|
||||
|
||||
int currentAutoHoldValue = autoHoldProperty.enumValueIndex;
|
||||
var orientation = (VRC_Pickup.PickupOrientation)orientationProperty.enumValueIndex;
|
||||
bool willBeAutoHold = VRC_Pickup.IsGlobalAutoHoldPickup((VRC_Pickup.AutoHoldMode)currentAutoHoldValue, orientation);
|
||||
|
||||
// Handle Sometimes - always problematic
|
||||
if (currentAutoHoldValue == (int)VRC_Pickup.AutoHoldMode.Sometimes)
|
||||
{
|
||||
return "This pickup uses older auto-hold settings that don't work for many controllers.\n" +
|
||||
"Upgrade to Version 1.1 for better compatibility and reduced hand fatigue.";
|
||||
}
|
||||
|
||||
// Handle AutoDetect - check what it will become
|
||||
if (currentAutoHoldValue == (int)VRC_Pickup.AutoHoldMode.AutoDetect)
|
||||
{
|
||||
if (willBeAutoHold)
|
||||
{
|
||||
return "This pickup uses older auto-hold settings that don't work for many controllers.\n" +
|
||||
"Upgrade to Version 1.1 for better compatibility and reduced hand fatigue.";
|
||||
}
|
||||
}
|
||||
|
||||
// Handle No and AutoDetect that becomes No - won't change function but will simplify UI
|
||||
if (!willBeAutoHold)
|
||||
{
|
||||
return "This pickup uses older auto-hold settings.\nUpgrading won't change the way it functions,\n" +
|
||||
"but it will simplify the options below.";
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return "Upgrade to Version 1.1 for improved compatibility and simplified settings.";
|
||||
}
|
||||
|
||||
// Called after version change to notify editor for UI updates
|
||||
public override void OnVersionChanged(VRCPickup.Version version, SerializedObject serializedObject)
|
||||
{
|
||||
onVersionChangedCallback?.Invoke(version);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5f6789012345678901234abcdef0123
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,52 @@
|
||||
#if VRC_SDK_VRCSDK3 && UNITY_EDITOR
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using UnityEngine.UIElements;
|
||||
using VRCStation = VRC.SDK3.Components.VRCStation;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(VRCStation))]
|
||||
public class VRCPlayerStationEditor3 : VRCInspectorBase
|
||||
{
|
||||
|
||||
private SerializedProperty propPlayerMobility;
|
||||
private SerializedProperty propCanUseStationFromStation;
|
||||
private SerializedProperty propAnimatorController;
|
||||
private SerializedProperty propDisableStationExit;
|
||||
private SerializedProperty propSeated;
|
||||
private SerializedProperty propStationEnterPlayerLocation;
|
||||
private SerializedProperty propStationExitPlayerLocation;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
propPlayerMobility = serializedObject.FindProperty(nameof(VRCStation.PlayerMobility));
|
||||
propCanUseStationFromStation = serializedObject.FindProperty(nameof(VRCStation.canUseStationFromStation));
|
||||
propAnimatorController = serializedObject.FindProperty(nameof(VRCStation.animatorController));
|
||||
propDisableStationExit = serializedObject.FindProperty(nameof(VRCStation.disableStationExit));
|
||||
propSeated = serializedObject.FindProperty(nameof(VRCStation.seated));
|
||||
propStationEnterPlayerLocation = serializedObject.FindProperty(nameof(VRCStation.stationEnterPlayerLocation));
|
||||
propStationExitPlayerLocation = serializedObject.FindProperty(nameof(VRCStation.stationExitPlayerLocation));
|
||||
}
|
||||
|
||||
public override void BuildInspectorGUI()
|
||||
{
|
||||
base.BuildInspectorGUI();
|
||||
|
||||
AddField(propPlayerMobility);
|
||||
AddField(propSeated);
|
||||
AddField(propDisableStationExit);
|
||||
AddField(propCanUseStationFromStation);
|
||||
AddField(propStationEnterPlayerLocation);
|
||||
AddField(propStationExitPlayerLocation);
|
||||
AddField(propAnimatorController);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8901d07a685ca424492a3cabff506184
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,51 @@
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
using VRC.SDKBase;
|
||||
using VRCPortalMarker = VRC.SDK3.Components.VRCPortalMarker;
|
||||
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(VRCPortalMarker))]
|
||||
public class VRCPortalMarkerEditor : VRCInspectorBase
|
||||
{
|
||||
|
||||
private SerializedProperty propWorld;
|
||||
private SerializedProperty propRoomId;
|
||||
private SerializedProperty propCustomPortalName;
|
||||
|
||||
private PropertyField fieldWorld;
|
||||
private PropertyField fieldRoomId;
|
||||
private PropertyField fieldCustomPortalName;
|
||||
|
||||
private HelpBox helpBoxTag;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
propWorld = serializedObject.FindProperty(nameof(VRCPortalMarker.world));
|
||||
propRoomId = serializedObject.FindProperty(nameof(VRCPortalMarker.roomId));
|
||||
propCustomPortalName = serializedObject.FindProperty(nameof(VRCPortalMarker.customPortalName));
|
||||
}
|
||||
|
||||
public override void BuildInspectorGUI()
|
||||
{
|
||||
base.BuildInspectorGUI();
|
||||
fieldRoomId = AddFieldLabel(propRoomId, "World ID");
|
||||
fieldCustomPortalName = AddField(propCustomPortalName);
|
||||
fieldWorld = AddField(propWorld);
|
||||
fieldWorld.RegisterValueChangeCallback(evt => WorldChanged());
|
||||
|
||||
WorldChanged();
|
||||
}
|
||||
|
||||
private void WorldChanged()
|
||||
{
|
||||
bool value = (VRC_PortalMarker.VRChatWorld)propWorld.enumValueIndex == VRC_PortalMarker.VRChatWorld.None;
|
||||
fieldRoomId.SetEnabled(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0eab965d110d6a41b44e8c56b81f7bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,213 @@
|
||||
#if VRC_SDK_VRCSDK3 && UNITY_EDITOR
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using VRC.Core;
|
||||
using VRCSceneDescriptor = VRC.SDK3.Components.VRCSceneDescriptor;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(VRCSceneDescriptor))]
|
||||
public class VRCSceneDescriptorEditor3 : VRCInspectorBase
|
||||
{
|
||||
private VRCSceneDescriptor sceneDescriptor;
|
||||
|
||||
private SerializedProperty propSpawns;
|
||||
private SerializedProperty propSpawnRadius;
|
||||
private SerializedProperty propSpawnOrder;
|
||||
private SerializedProperty propSpawnOrientation;
|
||||
private SerializedProperty propReferenceCamera;
|
||||
private SerializedProperty propRespawnHeightY;
|
||||
private SerializedProperty propObjectBehaviourAtRespawnHeight;
|
||||
private SerializedProperty propForbidUserPortals;
|
||||
private SerializedProperty propUnityVersion;
|
||||
private SerializedProperty propDynamicPrefabs;
|
||||
private SerializedProperty propDynamicMaterials;
|
||||
private SerializedProperty propNetworkIDs;
|
||||
private SerializedProperty propPortraitCameraPositionOffset;
|
||||
private SerializedProperty propPortraitCameraRotationOffset;
|
||||
private SerializedProperty propInteractPassthrough;
|
||||
|
||||
[NonSerialized] private string[] layerNames;
|
||||
private int mask;
|
||||
|
||||
private const string INTERACTION_HELPBOX_LABEL =
|
||||
"Interaction through User layers is blocked by default. Use the \"Interact Passthrough\" mask to define layers that will be transparent to interaction (allow interactions to pass through).";
|
||||
private const string INTERACTION_HELPBOX_URL = "https://creators.vrchat.com/worlds/layers/#interaction-block-and-passthrough-on-vrchat-layers";
|
||||
private const int USER_LAYER_START = 22;
|
||||
private const int USER_LAYER_COUNT = 10;
|
||||
|
||||
private const float HANDLE_SIZE = 0.1f;
|
||||
private static readonly Color RespawnHeightGizmoColor = new(0, 1, 0, 0.25f);
|
||||
private Vector3[] respawnHeightGizmoCorners;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
sceneDescriptor = (VRCSceneDescriptor)target;
|
||||
|
||||
propSpawns = serializedObject.FindProperty(nameof(VRCSceneDescriptor.spawns));
|
||||
propSpawnRadius = serializedObject.FindProperty(nameof(VRCSceneDescriptor.spawnRadius));
|
||||
propSpawnOrder = serializedObject.FindProperty(nameof(VRCSceneDescriptor.spawnOrder));
|
||||
propSpawnOrientation = serializedObject.FindProperty(nameof(VRCSceneDescriptor.spawnOrientation));
|
||||
propReferenceCamera = serializedObject.FindProperty(nameof(VRCSceneDescriptor.ReferenceCamera));
|
||||
propRespawnHeightY = serializedObject.FindProperty(nameof(VRCSceneDescriptor.RespawnHeightY));
|
||||
propObjectBehaviourAtRespawnHeight = serializedObject.FindProperty(nameof(VRCSceneDescriptor.ObjectBehaviourAtRespawnHeight));
|
||||
propForbidUserPortals = serializedObject.FindProperty(nameof(VRCSceneDescriptor.ForbidUserPortals));
|
||||
propUnityVersion = serializedObject.FindProperty(nameof(VRCSceneDescriptor.unityVersion));
|
||||
propDynamicPrefabs = serializedObject.FindProperty(nameof(VRCSceneDescriptor.DynamicPrefabs));
|
||||
propDynamicMaterials = serializedObject.FindProperty(nameof(VRCSceneDescriptor.DynamicMaterials));
|
||||
propPortraitCameraPositionOffset = serializedObject.FindProperty(nameof(VRCSceneDescriptor.portraitCameraPositionOffset));
|
||||
propPortraitCameraRotationOffset = serializedObject.FindProperty(nameof(VRCSceneDescriptor.portraitCameraRotationOffset));
|
||||
propInteractPassthrough = serializedObject.FindProperty(nameof(VRCSceneDescriptor.interactThruLayers));
|
||||
|
||||
// Using NetworkIDCollection here doesn't expose the actual list of network IDs in the inspector
|
||||
propNetworkIDs = serializedObject.FindProperty("NetworkIDs");
|
||||
|
||||
GetRespawnHeightGizmoPlaneCorners(false);
|
||||
PopulateUserLayerNames();
|
||||
HierarchyChanged();
|
||||
EditorApplication.hierarchyChanged += HierarchyChanged;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.hierarchyChanged -= HierarchyChanged;
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
var handlePosition = new Vector3(
|
||||
sceneDescriptor.transform.position.x,
|
||||
sceneDescriptor.RespawnHeightY,
|
||||
sceneDescriptor.transform.position.z);
|
||||
|
||||
var handleSize = HandleUtility.GetHandleSize(handlePosition) * HANDLE_SIZE;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Vector3 newHandlePosition = Handles.FreeMoveHandle(handlePosition, handleSize, Vector3.up, Handles.DotHandleCap);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(sceneDescriptor, "Move Respawn Height Y");
|
||||
sceneDescriptor.RespawnHeightY = newHandlePosition.y;
|
||||
EditorUtility.SetDirty(sceneDescriptor);
|
||||
}
|
||||
|
||||
GetRespawnHeightGizmoPlaneCorners();
|
||||
Handles.DrawSolidRectangleWithOutline(respawnHeightGizmoCorners, RespawnHeightGizmoColor, Color.green);
|
||||
|
||||
foreach (Transform spawn in sceneDescriptor.spawns)
|
||||
{
|
||||
if (!spawn) continue;
|
||||
Vector3 position = spawn.position;
|
||||
Handles.color = Color.white;
|
||||
if (sceneDescriptor.spawnRadius > 0)
|
||||
Handles.DrawWireDisc(position, Vector3.up, sceneDescriptor.spawnRadius);
|
||||
else
|
||||
{
|
||||
float size = HandleUtility.GetHandleSize(spawn.position) * 0.5f;
|
||||
Vector3 pos = spawn.position;
|
||||
Vector3 offset1 = (Vector3.forward + Vector3.right).normalized * size;
|
||||
Vector3 offset2 = (Vector3.forward - Vector3.right).normalized * size;
|
||||
Handles.DrawLine(pos + offset1, pos - offset1);
|
||||
Handles.DrawLine(pos + offset2, pos - offset2);
|
||||
}
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawLine(position, position + Vector3.up);
|
||||
Handles.color = Color.blue;
|
||||
Handles.DrawLine(position, position + spawn.forward);
|
||||
}
|
||||
Handles.color = Color.white;
|
||||
}
|
||||
|
||||
private void HierarchyChanged()
|
||||
{
|
||||
// This cannot be a RequireComponent because VRC.Core isn't included in VRC.Base.
|
||||
if (!sceneDescriptor.GetComponent<PipelineManager>())
|
||||
{
|
||||
sceneDescriptor.gameObject.AddComponent<PipelineManager>();
|
||||
}
|
||||
|
||||
if (sceneDescriptor.spawns == null || sceneDescriptor.spawns.Length == 0)
|
||||
{
|
||||
Undo.RecordObject(sceneDescriptor, "Grabbed new Spawn Position");
|
||||
sceneDescriptor.spawns = new[] { sceneDescriptor.transform };
|
||||
Debug.LogWarning($"Scene Descriptor spawns were empty, adding a default Spawn.");
|
||||
}
|
||||
}
|
||||
|
||||
public override void BuildInspectorGUI()
|
||||
{
|
||||
base.BuildInspectorGUI();
|
||||
|
||||
AddField(propSpawns);
|
||||
AddFieldTooltip(propSpawnRadius, "Players spawn at a random spot within the radius. Set to zero to have players spawn at the exact spawn position.");
|
||||
AddField(propSpawnOrder);
|
||||
AddField(propSpawnOrientation);
|
||||
AddField(propReferenceCamera);
|
||||
AddField(propRespawnHeightY);
|
||||
AddField(propForbidUserPortals);
|
||||
AddField(propObjectBehaviourAtRespawnHeight);
|
||||
AddField(propNetworkIDs, "Network IDs", "The Network ID Collection");
|
||||
|
||||
MaskField fieldPassthrough = new ("Interact Passthrough");
|
||||
fieldPassthrough.AddToClassList("unity-base-field__aligned");
|
||||
fieldPassthrough.choices = layerNames.ToList();
|
||||
fieldPassthrough.BindProperty(propInteractPassthrough);
|
||||
Root.Add(fieldPassthrough);
|
||||
|
||||
HelpBox helpBox = new (INTERACTION_HELPBOX_LABEL, HelpBoxMessageType.Info);
|
||||
|
||||
Button buttonDocs = new () { text = "Docs" };
|
||||
buttonDocs.clicked += () => Application.OpenURL(INTERACTION_HELPBOX_URL);
|
||||
helpBox.Add(buttonDocs);
|
||||
|
||||
Root.Add(helpBox);
|
||||
|
||||
}
|
||||
|
||||
private void PopulateUserLayerNames()
|
||||
{
|
||||
if (layerNames == null)
|
||||
{
|
||||
layerNames = new string[USER_LAYER_COUNT];
|
||||
}
|
||||
|
||||
for (int i = 0; i < USER_LAYER_COUNT; ++i)
|
||||
{
|
||||
string layerName = LayerMask.LayerToName(USER_LAYER_START + i);
|
||||
if (string.IsNullOrWhiteSpace(layerName))
|
||||
{
|
||||
layerNames[i] = $"<<layer {USER_LAYER_START + i}>>";
|
||||
}
|
||||
else
|
||||
{
|
||||
layerNames[i] = layerName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetRespawnHeightGizmoPlaneCorners(bool checkRespawnHeightChanged = true)
|
||||
{
|
||||
// only get new corners if respawn height has changed
|
||||
if (checkRespawnHeightChanged &&
|
||||
Mathf.Approximately(respawnHeightGizmoCorners[0].y, sceneDescriptor.RespawnHeightY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
respawnHeightGizmoCorners = new[]
|
||||
{
|
||||
new Vector3(sceneDescriptor.transform.position.x-5, sceneDescriptor.RespawnHeightY, sceneDescriptor.transform.position.z-5),
|
||||
new Vector3(sceneDescriptor.transform.position.x-5, sceneDescriptor.RespawnHeightY, sceneDescriptor.transform.position.z+5),
|
||||
new Vector3(sceneDescriptor.transform.position.x+5, sceneDescriptor.RespawnHeightY, sceneDescriptor.transform.position.z+5),
|
||||
new Vector3(sceneDescriptor.transform.position.x+5, sceneDescriptor.RespawnHeightY, sceneDescriptor.transform.position.z-5)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b2b9ac625bc5b04c887ff9ee9b5fdbe
|
||||
timeCreated: 1450463561
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,77 @@
|
||||
#if VRC_SDK_VRCSDK3
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine.UIElements;
|
||||
using VRCSpatialAudioSource = VRC.SDK3.Components.VRCSpatialAudioSource;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(VRCSpatialAudioSource))]
|
||||
public class VRCSpatialAudioSourceEditor3 : VRCInspectorBase
|
||||
{
|
||||
|
||||
private const string SHOW_ADVANCED_OPTIONS_KEY = "VRC.SDK3.Components.VRCSpatialAudioSource.ShowAdvancedOptions";
|
||||
|
||||
private SerializedProperty propGain;
|
||||
private SerializedProperty propNear;
|
||||
private SerializedProperty propFar;
|
||||
private SerializedProperty propVolumetricRadius;
|
||||
private SerializedProperty propEnableSpatialization;
|
||||
private SerializedProperty propUseAudioSourceVolumeCurve;
|
||||
|
||||
private PropertyField fieldEnableSpatialization;
|
||||
private PropertyField fieldUseAudioSourceVolumeCurve;
|
||||
|
||||
private VRCSpatialAudioSource script;
|
||||
private AudioSource source;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
script = (VRCSpatialAudioSource)target;
|
||||
|
||||
source = script.GetComponent<AudioSource>();
|
||||
|
||||
propGain = serializedObject.FindProperty(nameof(VRCSpatialAudioSource.Gain));
|
||||
propNear = serializedObject.FindProperty(nameof(VRCSpatialAudioSource.Near));
|
||||
propFar = serializedObject.FindProperty(nameof(VRCSpatialAudioSource.Far));
|
||||
propVolumetricRadius = serializedObject.FindProperty(nameof(VRCSpatialAudioSource.VolumetricRadius));
|
||||
propEnableSpatialization = serializedObject.FindProperty(nameof(VRCSpatialAudioSource.EnableSpatialization));
|
||||
propUseAudioSourceVolumeCurve = serializedObject.FindProperty(nameof(VRCSpatialAudioSource.UseAudioSourceVolumeCurve));
|
||||
}
|
||||
|
||||
public override void BuildInspectorGUI()
|
||||
{
|
||||
base.BuildInspectorGUI();
|
||||
|
||||
AddField(propGain);
|
||||
AddField(propFar);
|
||||
|
||||
Foldout foldout = AddKeyedFoldout("Advanced Options", SHOW_ADVANCED_OPTIONS_KEY);
|
||||
foldout.Add(AddField(propNear));
|
||||
foldout.Add(AddField(propVolumetricRadius));
|
||||
|
||||
fieldEnableSpatialization = AddField(propEnableSpatialization);
|
||||
fieldEnableSpatialization.RegisterValueChangeCallback(EnableSpatializationCallback);
|
||||
foldout.Add(fieldEnableSpatialization);
|
||||
|
||||
fieldUseAudioSourceVolumeCurve = AddField(propUseAudioSourceVolumeCurve);
|
||||
foldout.Add(fieldUseAudioSourceVolumeCurve);
|
||||
|
||||
UseAudioSourceVolumeCurveChanged();
|
||||
}
|
||||
|
||||
private void EnableSpatializationCallback(SerializedPropertyChangeEvent evt) => UseAudioSourceVolumeCurveChanged();
|
||||
|
||||
private void UseAudioSourceVolumeCurveChanged()
|
||||
{
|
||||
source.spatialize = propEnableSpatialization.boolValue;
|
||||
fieldUseAudioSourceVolumeCurve.SetVisible(propEnableSpatialization.boolValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f8f999a8e1ebee4588f94a8a618d7c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,314 @@
|
||||
using TMPro;
|
||||
using TMPro.EditorUtilities;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Presets;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace VRC.SDK3.Components.Editor
|
||||
{
|
||||
public class VRCTMP
|
||||
{
|
||||
private static TMP_DefaultControls.Resources s_StandardResources;
|
||||
|
||||
private const string kUILayerName = "Default";
|
||||
|
||||
private const string kStandardSpritePath = "UI/Skin/UISprite.psd";
|
||||
private const string kBackgroundSpritePath = "UI/Skin/Background.psd";
|
||||
private const string kInputFieldBackgroundPath = "UI/Skin/InputFieldBackground.psd";
|
||||
private const string kKnobPath = "UI/Skin/Knob.psd";
|
||||
private const string kCheckmarkPath = "UI/Skin/Checkmark.psd";
|
||||
private const string kDropdownArrowPath = "UI/Skin/DropdownArrow.psd";
|
||||
private const string kMaskPath = "UI/Skin/UIMask.psd";
|
||||
|
||||
private static TMP_DefaultControls.Resources GetStandardResources()
|
||||
{
|
||||
if (s_StandardResources.standard == null)
|
||||
{
|
||||
s_StandardResources.standard = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
|
||||
s_StandardResources.background = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpritePath);
|
||||
s_StandardResources.inputField = AssetDatabase.GetBuiltinExtraResource<Sprite>(kInputFieldBackgroundPath);
|
||||
s_StandardResources.knob = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
||||
s_StandardResources.checkmark = AssetDatabase.GetBuiltinExtraResource<Sprite>(kCheckmarkPath);
|
||||
s_StandardResources.dropdown = AssetDatabase.GetBuiltinExtraResource<Sprite>(kDropdownArrowPath);
|
||||
s_StandardResources.mask = AssetDatabase.GetBuiltinExtraResource<Sprite>(kMaskPath);
|
||||
}
|
||||
return s_StandardResources;
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/Text - TextMeshPro (VRC)", false, 9)]
|
||||
private static void CreateTextVRCTMP(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject go = TMP_DefaultControls.CreateText(GetStandardResources());
|
||||
|
||||
TextMeshProUGUI textComponent = go.GetComponent<TextMeshProUGUI>();
|
||||
|
||||
textComponent.fontSize = TMP_Settings.defaultFontSize;
|
||||
textComponent.color = Color.white;
|
||||
textComponent.text = "New Text";
|
||||
|
||||
PlaceUIElementRoot(go, menuCommand);
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/Button - TextMeshPro (VRC)", false, 10)]
|
||||
public static void AddButton(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject go = TMP_DefaultControls.CreateButton(GetStandardResources());
|
||||
|
||||
// Override font size
|
||||
TMP_Text textComponent = go.GetComponentInChildren<TMP_Text>();
|
||||
textComponent.fontSize = 24;
|
||||
|
||||
PlaceUIElementRoot(go, menuCommand);
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/Dropdown - TextMeshPro (VRC)", false, 11)]
|
||||
private static void CreateTextVRCDropdown(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject go = TMP_DefaultControls.CreateDropdown(GetStandardResources());
|
||||
PlaceUIElementRoot(go, menuCommand);
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/Input Field - TextMeshPro (VRC)", false, 12)]
|
||||
private static void CreateTextVRCInputfield(MenuCommand menuCommand)
|
||||
{
|
||||
GameObject go = TMP_DefaultControls.CreateInputField(GetStandardResources());
|
||||
PlaceUIElementRoot(go, menuCommand);
|
||||
}
|
||||
|
||||
// TMP Object creation code from TextMeshPro edited to place in a vrc way
|
||||
private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand)
|
||||
{
|
||||
GameObject parent = menuCommand.context as GameObject;
|
||||
bool explicitParentChoice = true;
|
||||
if (parent == null)
|
||||
{
|
||||
parent = GetOrCreateCanvasGameObject();
|
||||
explicitParentChoice = false;
|
||||
|
||||
// If in Prefab Mode, Canvas has to be part of Prefab contents,
|
||||
// otherwise use Prefab root instead.
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (prefabStage != null && !prefabStage.IsPartOfPrefabContents(parent))
|
||||
parent = prefabStage.prefabContentsRoot;
|
||||
}
|
||||
|
||||
if (parent.GetComponentsInParent<Canvas>(true).Length == 0)
|
||||
{
|
||||
// Create canvas under context GameObject,
|
||||
// and make that be the parent which UI element is added under.
|
||||
GameObject canvas = CreateNewUI();
|
||||
Undo.SetTransformParent(canvas.transform, parent.transform, "");
|
||||
parent = canvas;
|
||||
}
|
||||
|
||||
GameObjectUtility.EnsureUniqueNameForSibling(element);
|
||||
|
||||
SetParentAndAlign(element, parent);
|
||||
if (!explicitParentChoice) // not a context click, so center in sceneview
|
||||
SetPositionVisibleinSceneView(parent.GetComponent<RectTransform>(), element.GetComponent<RectTransform>());
|
||||
|
||||
// This call ensure any change made to created Objects after they where registered will be part of the Undo.
|
||||
Undo.RegisterFullObjectHierarchyUndo(parent == null ? element : parent, "");
|
||||
|
||||
// We have to fix up the undo name since the name of the object was only known after reparenting it.
|
||||
Undo.SetCurrentGroupName("Create " + element.name);
|
||||
|
||||
Selection.activeGameObject = element;
|
||||
}
|
||||
|
||||
// Helper function that returns a Canvas GameObject; preferably a parent of the selection, or other existing Canvas.
|
||||
public static GameObject GetOrCreateCanvasGameObject()
|
||||
{
|
||||
GameObject selectedGo = Selection.activeGameObject;
|
||||
|
||||
// Try to find a gameobject that is the selected GO or one if its parents.
|
||||
Canvas canvas = (selectedGo != null) ? selectedGo.GetComponentInParent<Canvas>() : null;
|
||||
if (IsValidCanvas(canvas))
|
||||
return canvas.gameObject;
|
||||
|
||||
// No canvas in selection or its parents? Then use any valid canvas.
|
||||
// We have to find all loaded Canvases, not just the ones in main scenes.
|
||||
Canvas[] canvasArray = StageUtility.GetCurrentStageHandle().FindComponentsOfType<Canvas>();
|
||||
for (int i = 0; i < canvasArray.Length; i++)
|
||||
if (IsValidCanvas(canvasArray[i]))
|
||||
return canvasArray[i].gameObject;
|
||||
|
||||
// No canvas in the scene at all? Then create a new one.
|
||||
return CreateNewUI();
|
||||
}
|
||||
|
||||
static bool IsValidCanvas(Canvas canvas)
|
||||
{
|
||||
if (canvas == null || !canvas.gameObject.activeInHierarchy)
|
||||
return false;
|
||||
|
||||
// It's important that the non-editable canvas from a prefab scene won't be rejected,
|
||||
// but canvases not visible in the Hierarchy at all do. Don't check for HideAndDontSave.
|
||||
if (EditorUtility.IsPersistent(canvas) || (canvas.hideFlags & HideFlags.HideInHierarchy) != 0)
|
||||
return false;
|
||||
|
||||
if (StageUtility.GetStageHandle(canvas.gameObject) != StageUtility.GetCurrentStageHandle())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void SetParentAndAlign(GameObject child, GameObject parent)
|
||||
{
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
Undo.SetTransformParent(child.transform, parent.transform, "");
|
||||
|
||||
RectTransform rectTransform = child.transform as RectTransform;
|
||||
if (rectTransform)
|
||||
{
|
||||
rectTransform.anchoredPosition = Vector2.zero;
|
||||
Vector3 localPosition = rectTransform.localPosition;
|
||||
localPosition.z = 0;
|
||||
rectTransform.localPosition = localPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
child.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
child.transform.localRotation = Quaternion.identity;
|
||||
child.transform.localScale = Vector3.one;
|
||||
|
||||
SetLayerRecursively(child, parent.layer);
|
||||
}
|
||||
|
||||
private static void SetLayerRecursively(GameObject go, int layer)
|
||||
{
|
||||
go.layer = layer;
|
||||
Transform t = go.transform;
|
||||
for (int i = 0; i < t.childCount; i++)
|
||||
SetLayerRecursively(t.GetChild(i).gameObject, layer);
|
||||
}
|
||||
|
||||
|
||||
public static GameObject CreateNewUI()
|
||||
{
|
||||
// Root for the UI
|
||||
var root = new GameObject("Canvas");
|
||||
root.layer = LayerMask.NameToLayer(kUILayerName);
|
||||
Canvas canvas = root.AddComponent<Canvas>();
|
||||
RectTransform canvasRTransform = canvas.GetComponent<RectTransform>();
|
||||
canvasRTransform.localScale = new Vector3(0.001f, 0.001f,0.001f);
|
||||
canvasRTransform.sizeDelta = new Vector2(1000, 1000);
|
||||
|
||||
SceneView sceneView = SceneView.lastActiveSceneView;
|
||||
|
||||
if (sceneView == null && SceneView.sceneViews.Count > 0)
|
||||
sceneView = SceneView.sceneViews[0] as SceneView;
|
||||
|
||||
// Couldn't find a SceneView. Don't set position.
|
||||
if (sceneView != null && sceneView.camera != null)
|
||||
{
|
||||
Camera camera = sceneView.camera;
|
||||
|
||||
canvasRTransform.position = camera.transform.position + camera.transform.forward * 2;
|
||||
}
|
||||
|
||||
canvas.renderMode = RenderMode.WorldSpace;
|
||||
root.AddComponent<CanvasScaler>();
|
||||
root.AddComponent<GraphicRaycaster>();
|
||||
root.AddComponent<VRCUiShape>();
|
||||
|
||||
// Works for all stages.
|
||||
StageUtility.PlaceGameObjectInCurrentStage(root);
|
||||
bool customScene = false;
|
||||
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (prefabStage != null)
|
||||
{
|
||||
root.transform.SetParent(prefabStage.prefabContentsRoot.transform, false);
|
||||
customScene = true;
|
||||
}
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);
|
||||
|
||||
// If there is no event system add one...
|
||||
// No need to place event system in custom scene as these are temporary anyway.
|
||||
// It can be argued for or against placing it in the user scenes,
|
||||
// but let's not modify scene user is not currently looking at.
|
||||
if (!customScene)
|
||||
CreateEventSystem(false);
|
||||
return root;
|
||||
}
|
||||
|
||||
private static void SetPositionVisibleinSceneView(RectTransform canvasRTransform, RectTransform itemTransform)
|
||||
{
|
||||
// Find the best scene view
|
||||
SceneView sceneView = SceneView.lastActiveSceneView;
|
||||
|
||||
if (sceneView == null && SceneView.sceneViews.Count > 0)
|
||||
sceneView = SceneView.sceneViews[0] as SceneView;
|
||||
|
||||
// Couldn't find a SceneView. Don't set position.
|
||||
if (sceneView == null || sceneView.camera == null)
|
||||
return;
|
||||
|
||||
// Create world space Plane from canvas position.
|
||||
Camera camera = sceneView.camera;
|
||||
Vector3 position = Vector3.zero;
|
||||
Vector2 localPlanePosition;
|
||||
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(canvasRTransform, new Vector2(camera.pixelWidth / 2, camera.pixelHeight / 2), camera, out localPlanePosition))
|
||||
{
|
||||
// Adjust for canvas pivot
|
||||
localPlanePosition.x = localPlanePosition.x + canvasRTransform.sizeDelta.x * canvasRTransform.pivot.x;
|
||||
localPlanePosition.y = localPlanePosition.y + canvasRTransform.sizeDelta.y * canvasRTransform.pivot.y;
|
||||
|
||||
localPlanePosition.x = Mathf.Clamp(localPlanePosition.x, 0, canvasRTransform.sizeDelta.x);
|
||||
localPlanePosition.y = Mathf.Clamp(localPlanePosition.y, 0, canvasRTransform.sizeDelta.y);
|
||||
|
||||
// Adjust for anchoring
|
||||
position.x = localPlanePosition.x - canvasRTransform.sizeDelta.x * itemTransform.anchorMin.x;
|
||||
position.y = localPlanePosition.y - canvasRTransform.sizeDelta.y * itemTransform.anchorMin.y;
|
||||
|
||||
Vector3 minLocalPosition;
|
||||
minLocalPosition.x = canvasRTransform.sizeDelta.x * (0 - canvasRTransform.pivot.x) + itemTransform.sizeDelta.x * itemTransform.pivot.x;
|
||||
minLocalPosition.y = canvasRTransform.sizeDelta.y * (0 - canvasRTransform.pivot.y) + itemTransform.sizeDelta.y * itemTransform.pivot.y;
|
||||
|
||||
Vector3 maxLocalPosition;
|
||||
maxLocalPosition.x = canvasRTransform.sizeDelta.x * (1 - canvasRTransform.pivot.x) - itemTransform.sizeDelta.x * itemTransform.pivot.x;
|
||||
maxLocalPosition.y = canvasRTransform.sizeDelta.y * (1 - canvasRTransform.pivot.y) - itemTransform.sizeDelta.y * itemTransform.pivot.y;
|
||||
|
||||
position.x = Mathf.Clamp(position.x, minLocalPosition.x, maxLocalPosition.x);
|
||||
position.y = Mathf.Clamp(position.y, minLocalPosition.y, maxLocalPosition.y);
|
||||
}
|
||||
|
||||
itemTransform.anchoredPosition = position;
|
||||
itemTransform.localRotation = Quaternion.identity;
|
||||
itemTransform.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
private static void CreateEventSystem(bool select)
|
||||
{
|
||||
CreateEventSystem(select, null);
|
||||
}
|
||||
|
||||
|
||||
private static void CreateEventSystem(bool select, GameObject parent)
|
||||
{
|
||||
var esys = Object.FindFirstObjectByType<EventSystem>();
|
||||
if (esys == null)
|
||||
{
|
||||
var eventSystem = new GameObject("EventSystem");
|
||||
GameObjectUtility.SetParentAndAlign(eventSystem, parent);
|
||||
esys = eventSystem.AddComponent<EventSystem>();
|
||||
eventSystem.AddComponent<StandaloneInputModule>();
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name);
|
||||
}
|
||||
|
||||
if (select && esys != null)
|
||||
{
|
||||
Selection.activeGameObject = esys.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 577bc48ccbd86fc4e8804e4ed36a6dac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23f17aebd51f4e47a14b911202aadc67
|
||||
timeCreated: 1687986184
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43abf37538cf87c47bc585a3b129b533
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ea84963dc71d3d4b9d00a0bad947493
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,5 @@
|
||||
<UXML xmlns="UnityEngine.UIElements">
|
||||
<VisualElement name="notification-block" class="col mt-2 mb-2 w-100 align-items-center">
|
||||
<Label text="Your world was built successfully!" class="text-lg" />
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 236433fe0b3378242a1b83d2199b9d27
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@ -0,0 +1,3 @@
|
||||
Label {
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4675f35fd0b48947b0f1870568c7209
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace VRC.SDK3A.Editor.Elements
|
||||
{
|
||||
public class WorldBuildSuccessNotification: VisualElement
|
||||
{
|
||||
public WorldBuildSuccessNotification()
|
||||
{
|
||||
Resources.Load<VisualTreeAsset>("WorldBuildSuccessNotification").CloneTree(this);
|
||||
styleSheets.Add(Resources.Load<StyleSheet>("WorldBuildSuccessNotificationStyles"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8917c827433f542428ebdaf7cc31bf34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 204d80e392324bdd9d3501521801054b
|
||||
timeCreated: 1687987392
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a36a593f0532114eab83a5da968c0c9
|
||||
timeCreated: 1687898224
|
||||
@ -0,0 +1,8 @@
|
||||
<UXML xmlns="UnityEngine.UIElements">
|
||||
<VisualElement name="notification-block" class="col mt-2 mb-2 w-100">
|
||||
<Label text="Your world failed to build or upload because of the following reason" />
|
||||
<Label name="notification-error-reason" class="mt-2 p-2 white-space-normal" />
|
||||
<Label text="We recommend taking a look at the console for more details" class="mt-2" />
|
||||
<Button class="mt-3 pl-4 pr-4 pt-2 pb-2 text-bold" text="Check Console for more details" name="open-unity-console" />
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceb22344bc36ee24cb99cf412a7534d7
|
||||
timeCreated: 1687898224
|
||||
@ -0,0 +1,3 @@
|
||||
#notification-error-reason {
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7d711ed3e43b3b4cbdc2b976f450581
|
||||
timeCreated: 1687898224
|
||||
@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using VRC.SDKBase;
|
||||
|
||||
namespace VRC.SDK3.Editor.Elements
|
||||
{
|
||||
public class WorldUploadErrorNotification: VisualElement
|
||||
{
|
||||
public WorldUploadErrorNotification(string error)
|
||||
{
|
||||
Resources.Load<VisualTreeAsset>("WorldUploadErrorNotification").CloneTree(this);
|
||||
styleSheets.Add(Resources.Load<StyleSheet>("WorldUploadErrorNotificationStyles"));
|
||||
|
||||
this.Q<Label>("notification-error-reason").text = error;
|
||||
|
||||
var openUnityConsole = this.Q<Button>("open-unity-console");
|
||||
openUnityConsole.clicked += VRC_EditorTools.OpenConsoleWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75cec36013175db44880a380b8f9b334
|
||||
timeCreated: 1687898224
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4c631740417436d826d7897a41ade5b
|
||||
timeCreated: 1687987392
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5aa8a359743c55245afd9d6e2d2ab053
|
||||
timeCreated: 1687895445
|
||||
@ -0,0 +1,6 @@
|
||||
<UXML xmlns="UnityEngine.UIElements">
|
||||
<VisualElement name="notification-block" class="col mt-2 mb-2 w-100 align-items-center">
|
||||
<Label text="Your world was published to VRChat!" class="text-lg" />
|
||||
<Button class="mt-3 pl-4 pr-4 pt-2 pb-2 text-bold" text="See it on the VRChat Website" name="open-world-page-button" />
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0cb08821623b5c46ae5e6a0b1f3e2b1
|
||||
timeCreated: 1687895455
|
||||
@ -0,0 +1,3 @@
|
||||
Label {
|
||||
-unity-text-align: middle-center;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 501977f645ca1b947b49df74d5162a8b
|
||||
timeCreated: 1687895466
|
||||
@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace VRC.SDK3.Editor.Elements
|
||||
{
|
||||
public class WorldUploadSuccessNotification: VisualElement
|
||||
{
|
||||
public WorldUploadSuccessNotification(string id)
|
||||
{
|
||||
Resources.Load<VisualTreeAsset>("WorldUploadSuccessNotification").CloneTree(this);
|
||||
styleSheets.Add(Resources.Load<StyleSheet>("WorldUploadSuccessNotificationStyles"));
|
||||
|
||||
var openWorldPageButton = this.Q<Button>("open-world-page-button");
|
||||
openWorldPageButton.clicked += () =>
|
||||
{
|
||||
Application.OpenURL($"https://vrchat.com/home/world/{id}");
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11e30a0715a549f4086eadde63e2d2de
|
||||
timeCreated: 1687895210
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a3d4a940f274e42a8c0de5d08c7866c
|
||||
timeCreated: 1687987606
|
||||
@ -0,0 +1,120 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase.Editor;
|
||||
using VRC.SDKBase.Editor.Api;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the public interface you can use to interact with the Worlds SDK Builder
|
||||
/// </summary>
|
||||
public interface IVRCSdkWorldBuilderApi : IVRCSdkBuilderApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds the currently open scene and returns a path to the built world bundle.
|
||||
/// Make sure the world has a valid SceneDescriptor and PipelineManager components present.
|
||||
/// </summary>
|
||||
/// <returns>Path to the bundle</returns>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
[PublicAPI]
|
||||
Task<string> Build();
|
||||
|
||||
/// <summary>
|
||||
/// Builds the currently open scene and returns a path + signature of the newly built bundle.
|
||||
/// Make sure the world has a valid SceneDescriptor and PipelineManager components present.
|
||||
/// </summary>
|
||||
/// <returns>Tuple containing the path to the bundle and its signature</returns>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
[PublicAPI]
|
||||
Task<(string path, string signature)> BuildWithSignature();
|
||||
|
||||
/// <summary>
|
||||
/// Builds and uploads the currently open scene for the VRCWorld specified.
|
||||
/// Make sure the world has a valid SceneDescriptor and PipelineManager components present
|
||||
/// </summary>
|
||||
/// <param name="world">VRCWorld object with world info. Must have a Name for world creation</param>
|
||||
/// <param name="thumbnailPath">Path to the thumbnail image on disk. Must be specified for world creation</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
/// <exception cref="OwnershipException">Current User does not own the target content</exception>
|
||||
/// <exception cref="UploadException">Content failed to upload</exception>
|
||||
/// <exception cref="BundleExistsException">This exact bundle was already uploaded</exception>
|
||||
[PublicAPI]
|
||||
Task BuildAndUpload(VRCWorld world, string thumbnailPath = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Builds and uploads the currently open scene for the VRCWorld specified.
|
||||
/// Make sure the world has a valid SceneDescriptor and PipelineManager components present
|
||||
/// </summary>
|
||||
/// <param name="world">VRCWorld object with world info. Must have a Name for world creation</param>
|
||||
/// <param name="signature">Bundle signature provided by the SDK</param>
|
||||
/// <param name="thumbnailPath">Path to the thumbnail image on disk. Must be specified for world creation</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
/// <exception cref="OwnershipException">Current User does not own the target content</exception>
|
||||
/// <exception cref="UploadException">Content failed to upload</exception>
|
||||
/// /// <exception cref="BundleExistsException">This exact bundle was already uploaded</exception>
|
||||
[PublicAPI]
|
||||
Task BuildAndUpload(VRCWorld world, string signature, string thumbnailPath = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Starts a multi-platform build chain for the currently open scene
|
||||
/// This will automatically switch the editor to each of the supported platforms and perform a build+upload
|
||||
/// If any of the platforms encounter an error, the build chain will be stopped and the error will be thrown similar to BuildAndUpload
|
||||
/// </summary>
|
||||
/// <param name="world">VRCWorld object with world info. Must have a Name for world creation</param>
|
||||
/// <param name="thumbnailPath">Path to the thumbnail image on disk. Must be specified for world creation</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
/// <exception cref="OwnershipException">Current User does not own the target content</exception>
|
||||
/// <exception cref="UploadException">Content failed to upload</exception>
|
||||
/// <exception cref="BundleExistsException">This exact bundle was already uploaded</exception>
|
||||
[PublicAPI]
|
||||
Task BuildAndUploadMultiPlatform(VRCWorld world, string thumbnailPath = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Builds the currently open scene and launches / reloads a test client
|
||||
/// </summary>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
[PublicAPI]
|
||||
Task BuildAndTest();
|
||||
|
||||
/// <summary>
|
||||
/// Reopens / reloads the test clients with the last built world
|
||||
/// </summary>
|
||||
/// <exception cref="BuilderException">Build process has encountered an error</exception>
|
||||
/// <exception cref="BuildBlockedException">Build was blocked by the SDK Callback</exception>
|
||||
/// <exception cref="ValidationException">Content has validation errors</exception>
|
||||
[PublicAPI]
|
||||
Task TestLastBuild();
|
||||
|
||||
/// <summary>
|
||||
/// Uploads the last built world for the VRCWorld specified
|
||||
/// </summary>
|
||||
/// <param name="world">VRCWorld object with world info. Must have a Name for world creation</param>
|
||||
/// <param name="thumbnailPath">Path to the thumbnail image on disk. Must be specified for world creation</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <exception cref="OwnershipException">Current User does not own the target content</exception>
|
||||
/// <exception cref="UploadException">Content failed to upload</exception>
|
||||
/// <exception cref="BundleExistsException">This exact bundle was already uploaded</exception>
|
||||
[PublicAPI]
|
||||
Task UploadLastBuild(VRCWorld world, string thumbnailPath = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd8923a5088f4aa89bcd97d8cdab1dbe
|
||||
timeCreated: 1687987621
|
||||
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
public class PublishConfirmationWindow: PopupWindowContent
|
||||
{
|
||||
//Set the window size
|
||||
public override Vector2 GetWindowSize()
|
||||
{
|
||||
return new Vector2(400, 300);
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect rect)
|
||||
{
|
||||
// Intentionally left empty
|
||||
}
|
||||
|
||||
private string _title;
|
||||
private string _text;
|
||||
private string _yesText;
|
||||
private string _noText;
|
||||
private Action _yesAction;
|
||||
private Action _noAction;
|
||||
|
||||
public PublishConfirmationWindow(string title, string text, string yesText, string noText, Action yesAction = null, Action noAction = null)
|
||||
{
|
||||
_title = title;
|
||||
_text = text;
|
||||
_yesText = yesText;
|
||||
_noText = noText;
|
||||
_yesAction = yesAction;
|
||||
_noAction = noAction;
|
||||
}
|
||||
|
||||
private VisualElement _r;
|
||||
|
||||
public override void OnOpen()
|
||||
{
|
||||
_r = editorWindow.rootVisualElement;
|
||||
Resources.Load<VisualTreeAsset>("PublishConfirmationWindow").CloneTree(_r);
|
||||
_r.styleSheets.Add(Resources.Load<StyleSheet>("PublishConfirmationWindowStyles"));
|
||||
_r.styleSheets.Add(Resources.Load<StyleSheet>("VRCSdkPanelStyles"));
|
||||
|
||||
_r.Q<Label>("title").text = _title;
|
||||
_r.Q<Label>("body").text = _text;
|
||||
_r.Q<Button>("yes-button").text = _yesText;
|
||||
_r.Q<Button>("no-button").text = _noText;
|
||||
if (_yesAction != null)
|
||||
{
|
||||
_r.Q<Button>("yes-button").clicked += _yesAction;
|
||||
}
|
||||
_r.Q<Button>("yes-button").clicked += editorWindow.Close;
|
||||
if (_noAction != null)
|
||||
{
|
||||
_r.Q<Button>("no-button").clicked += _noAction;
|
||||
}
|
||||
_r.Q<Button>("no-button").clicked += editorWindow.Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ef91745551f415993180eaec9a0c74d
|
||||
timeCreated: 1691082161
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9556a92e1094bbea79b9f30db892d9a
|
||||
timeCreated: 1687972218
|
||||
@ -0,0 +1,12 @@
|
||||
<UXML xmlns="UnityEngine.UIElements">
|
||||
<ScrollView>
|
||||
<VisualElement name="root" class="p-2">
|
||||
<Label name="title" class="header3 mb-2" />
|
||||
<Label name="body" enable-rich-text="true" class="mt-2 mb-2 white-space-normal" />
|
||||
<VisualElement class="mb-2 row align-items-center w-100">
|
||||
<Button class="mr-2 bg-button-bg flex-1 pt-2 pb-2" name="yes-button" />
|
||||
<Button name="no-button" class="flex-1 pt-2 pb-2" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</ScrollView>
|
||||
</UXML>
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 019a4b561d5d4614a85046e7a1c58751
|
||||
timeCreated: 1691075541
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da1f468c8c7846afab7d03f3f4c52139
|
||||
timeCreated: 1691075553
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 128 KiB |
@ -0,0 +1,140 @@
|
||||
fileFormatVersion: 2
|
||||
guid: babec5659a990ea42ae98eef1116739c
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 12
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 0
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: iPhone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Android
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
ignorePlatformSupport: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
nameFileIdTable: {}
|
||||
mipmapLimitGroupName:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,48 @@
|
||||
<UXML xmlns="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:vrc="VRC.SDKBase.Editor.Elements">
|
||||
<VisualElement class="col relative" name="section-3">
|
||||
<VisualElement class="mt-2 col pr-2 pl-2" name="build-buttons-block">
|
||||
<VisualElement class="row">
|
||||
<VisualElement class="col flex-grow-1 align-items-start mr-3" name="build-type-container">
|
||||
<Label class="d-flex mt-2 mb-2 text-bold" text="Build Type" />
|
||||
<!-- build-type-dropdown gets inserted here -->
|
||||
</VisualElement>
|
||||
|
||||
<VisualElement class="col" name="platform-container">
|
||||
<vrc:PlatformSwitcherPopup label="Platform(s)" name="platform-switcher-popup" />
|
||||
</VisualElement>
|
||||
|
||||
<VisualElement class="col ml-3" name="num-clients-container">
|
||||
<Label class="ml-0 mr-1 mt-2 mb-2 pr-2 d-flex text-bold" text="Clients" />
|
||||
<uie:IntegerField name="num-clients" class="ml-0" value="1"/>
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
|
||||
<VisualElement class="row justify-content-between">
|
||||
<VisualElement class="row" name="force-non-vr-container">
|
||||
<Toggle name="force-non-vr"/>
|
||||
<Label text="Force Non-VR" class="white-space-normal m-2 options-text-color" />
|
||||
</VisualElement>
|
||||
<VisualElement class="row" name="enable-world-reload-container">
|
||||
<Label text="Enable World Reload" class="white-space-normal m-2 options-text-color" />
|
||||
<Toggle name="enable-world-reload"/>
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
|
||||
<VisualElement class="mt-2">
|
||||
<Button name="main-action-button" class="pt-4 pb-4 text-lg text-bold ml-0 mr-0" />
|
||||
<VisualElement name="main-action-disabled-block" class="d-none absolute text-lg text-bold text-grey-200">
|
||||
<Label name="main-action-disabled-text" text="You must fix the issues listed above before you can Upload a Build" class="white-space-normal" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
|
||||
<VisualElement class="row justify-content-between">
|
||||
<VisualElement class="row m-2 d-none">
|
||||
<Label text="Run Performance Streaming" class="ml-2 flex-shrink-1 white-space-normal pr-2 options-text-color text-right" />
|
||||
<Toggle name="run-performance-streaming" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
<VisualElement class="d-none" name="v3-block" />
|
||||
<vrc:BuilderProgress name="progress-bar" />
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fddc9f028e2d45a097fc34a58821d37b
|
||||
timeCreated: 1685525413
|
||||
@ -0,0 +1,8 @@
|
||||
#local-test-settings Toggle {
|
||||
border-bottom-width: 0;
|
||||
background-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
#local-test-settings Toggle Label {
|
||||
-unity-font-style: normal;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3924ac38bc424700bf8f1f30557680d2
|
||||
timeCreated: 1687972283
|
||||
@ -0,0 +1,90 @@
|
||||
<UXML xmlns="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xmlns:vrc="VRC.SDKBase.Editor.Elements">
|
||||
<VisualElement class="row pt-2 pl-2 pr-2 pb-2 flex-grow-1" name="content-info">
|
||||
<VisualElement class="col mr-2 flex-7">
|
||||
<vrc:VRCTextField class="content-info-field mb-2" required="true" label="Name" placeholder="Enter your world's public name..." name="content-name" vertical="true" />
|
||||
<VisualElement class="row mb-2 m-unity-field">
|
||||
<VisualElement class="col flex-1">
|
||||
<VisualElement class="row align-items-center justify-content-between w-100 mb-1">
|
||||
<Label class="text-bold" text="Max. Capacity" />
|
||||
<Button class="help-button" tooltip="What is Maximum Capacity" name="show-capacity-help-button" />
|
||||
</VisualElement>
|
||||
<uie:IntegerField tooltip="Maximum capacity" class="ml-0" value="32" name="content-capacity" required="true" />
|
||||
</VisualElement>
|
||||
<VisualElement class="col flex-1">
|
||||
<VisualElement class="row align-items-center justify-content-between w-100 mb-1">
|
||||
<Label class="text-bold" text="Rec. Capacity" />
|
||||
<Button class="help-button" tooltip="What is Recommended Capacity" name="show-recommended-capacity-help-button" />
|
||||
</VisualElement>
|
||||
<uie:IntegerField tooltip="Recommended Capacity" class="ml-0 mr-0" value="16" name="content-recommended-capacity" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
<VisualElement class="row m-unity-field" name="warnings-tags-block">
|
||||
<VisualElement class="col flex-1">
|
||||
<vrc:ContentWarningsField label="Content Warnings" class="mb-2 mr-unity-field" name="content-warnings" />
|
||||
</VisualElement>
|
||||
<VisualElement class="col flex-1">
|
||||
<vrc:TagsField label="Tags" class="content-info-field w-100 mt-2" name="content-tags" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
<vrc:VRCTextField class="content-info-field mb-2" label="Description" multiline="true" placeholder="Describe world so it is easier to find!" name="content-description" vertical="true" />
|
||||
<VisualElement class="row mb-3">
|
||||
<VisualElement class="col m-unity-field mt-2">
|
||||
<Label class="field-label text-bold mb-2" text="Last Updated" />
|
||||
<Label text="Loading..." name="last-updated-label" />
|
||||
</VisualElement>
|
||||
<VisualElement class="col m-unity-field mt-2">
|
||||
<Label class="field-label text-bold mb-2" text="Version" />
|
||||
<Label text="Loading..." name="version-label" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
<VisualElement class="col m-unity-field">
|
||||
<Label class="field-label text-bold mb-2" text="Supported Platforms" />
|
||||
<Label text="Loading..." name="content-platform-info" />
|
||||
</VisualElement>
|
||||
<VisualElement class="mt-2 mb-2 w-100 col d-none">
|
||||
<VisualElement class="row align-items-center m-unity-field">
|
||||
<Label class="field-label" text="Current Visibility" />
|
||||
<Label text="Loading..." name="visibility-label" />
|
||||
</VisualElement>
|
||||
<VisualElement class="mt-2 d-none row align-items-center" name="publish-block">
|
||||
<Button name="publish-button" class="flex-grow-1" />
|
||||
<Button class="help-button" tooltip="Learn more about Community Labs" name="community-labs-help-button" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
<VisualElement class="col flex-5">
|
||||
<VisualElement name="visibility-block" class="col mb-2" />
|
||||
<vrc:Modal title="Publish to Community Labs" name="labs-publish-modal">
|
||||
<VisualElement class="col p-3">
|
||||
<Label class="white-space-normal mb-2" text="Publishing this world will put it in to the Community Labs" />
|
||||
<Label class="white-space-normal mb-2" text="Other users will be able to see your world, and it will either stay in the Labs, get promoted to Public status, or be placed back in to Private status, based on community response." />
|
||||
<Label class="white-space-normal mb-2" text="We encourage you to get the word out about your world if you want it to survive! If your world violates our Community Guidelines, you could get in trouble by posting it!" />
|
||||
<Label class="white-space-normal" text="You're only allowed to publish one world per week, so make sure to put your best foot forward!" />
|
||||
</VisualElement>
|
||||
<VisualElement class="row pl-3 pr-3 pb-3">
|
||||
<Button text="Yes, do it!" name="publish-to-labs-btn" class="flex-1 ml-0" />
|
||||
<Button text="No, keep the world private" name="publish-to-labs-cancel-btn" class="flex-1 mr-0" />
|
||||
</VisualElement>
|
||||
</vrc:Modal>
|
||||
<vrc:Modal title="Unpublishing a World" name="unpublish-modal">
|
||||
<VisualElement class="col p-3">
|
||||
<Label class="white-space-normal mb-2" text="Unpublishing this world will remove it from Public." />
|
||||
<Label class="white-space-normal mb-2" text="If you want to make it public again, it will need to go through Community Labs." />
|
||||
<Label class="white-space-normal mb-2" text="You're only allowed to publish one world per week, and when you remove a world from the labs, you don't get your one world back. Are you sure?" />
|
||||
</VisualElement>
|
||||
<VisualElement class="row pl-3 pr-3 pb-3">
|
||||
<Button text="Yes, do it!" name="unpublish-btn" class="flex-1 ml-0" />
|
||||
<Button text="No, keep the world public" name="unpublish-cancel-btn" class="flex-1 mr-0" />
|
||||
</VisualElement>
|
||||
</vrc:Modal>
|
||||
<VisualElement class="col m-unity-field">
|
||||
<vrc:ThumbnailBlock />
|
||||
</VisualElement>
|
||||
<VisualElement class="row align-items-center justify-content-end m-unity-field">
|
||||
<Label text="World Debugging" class="field-label text-right mr-2" />
|
||||
<Toggle name="world-debugging-toggle" class="top-05 relative" />
|
||||
<Button class="help-button" tooltip="What is World Debugging" name="show-world-debugging-help-button" />
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</VisualElement>
|
||||
</UXML>
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7edf86396674750aa7d941446bba8fe
|
||||
timeCreated: 1684521742
|
||||
@ -0,0 +1,19 @@
|
||||
#world-debugging-toggle {
|
||||
border-bottom-width: 0;
|
||||
background-color: rgba(0,0,0,0);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#visibility-block PopupField {
|
||||
flex-direction: column;
|
||||
}
|
||||
#visibility-block PopupField > Label {
|
||||
font-size: 12px;
|
||||
-unity-font-style: bold;
|
||||
margin-bottom: 5px;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#content-description {
|
||||
min-height: 77px;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 140c4a1abe4d4a5bb6ebfc5853bd8f22
|
||||
timeCreated: 1687972622
|
||||
@ -0,0 +1,48 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using VRC.SDKBase.Editor.Source.Helpers;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
[InitializeOnLoad]
|
||||
public class SDK3ImportFix
|
||||
{
|
||||
private const string worldsReimportedKey = "WORLDS_REIMPORTED";
|
||||
|
||||
static SDK3ImportFix()
|
||||
{
|
||||
// Skip if we've already checked for the canary file during this Editor Session
|
||||
if (!SessionState.GetBool(worldsReimportedKey, false))
|
||||
{
|
||||
// Check for canary file in Library - package probably needs a reimport after a Library wipe
|
||||
string canaryFilePath = Path.Combine("Library", worldsReimportedKey);
|
||||
if (File.Exists(canaryFilePath))
|
||||
{
|
||||
SessionState.SetBool(worldsReimportedKey, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma warning disable 4014
|
||||
ReloadSDK();
|
||||
#pragma warning restore 4014
|
||||
File.WriteAllText(canaryFilePath, worldsReimportedKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task ReloadSDK()
|
||||
{
|
||||
// Set session key to true, limiting the reload to one run per session
|
||||
SessionState.SetBool(worldsReimportedKey, true);
|
||||
|
||||
//Wait for project to finish compiling
|
||||
while (EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||
{
|
||||
await Task.Delay(250);
|
||||
}
|
||||
|
||||
ReloadUtil.ReloadSDK();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 857dfa28ea5a4d00b87e04081e0d68e2
|
||||
timeCreated: 1632519867
|
||||
@ -0,0 +1,71 @@
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRC.SDK3.Editor
|
||||
{
|
||||
public class SampleImporter
|
||||
{
|
||||
private const string exampleScenePath =
|
||||
"Packages/com.vrchat.worlds/Samples/UdonExampleScene/UdonExampleScene.unity";
|
||||
private const string ccplayerhitScenePath =
|
||||
"Packages/com.vrchat.worlds/Samples/OnControllerColliderHitExampleScene/OnControllerColliderHitSampleScene.unity";
|
||||
private const string minimapScenePath =
|
||||
"Packages/com.vrchat.worlds/Samples/GraphicsBlitExampleScene/Minimap Sample Scene.unity";
|
||||
private const string midiPlaybackScenePath =
|
||||
"Packages/com.vrchat.worlds/Samples/MidiPlaybackExampleScene/MidiPlaybackScene.unity";
|
||||
private const string aiNavigationScenePath =
|
||||
"Packages/com.vrchat.worlds/Samples/AINavmeshScene/AINavmeshSceneExample.unity";
|
||||
|
||||
[MenuItem("VRChat SDK/Samples/UdonExampleScene", false, 981)]
|
||||
private static void OpenSampleUdonExampleScene()
|
||||
{
|
||||
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
EditorSceneManager.OpenScene(exampleScenePath);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("VRChat SDK/Samples/ControllerColliderPlayerHit", false, 982)]
|
||||
private static void OpenCCPlayerHitExampleScene()
|
||||
{
|
||||
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
EditorSceneManager.OpenScene(ccplayerhitScenePath);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("VRChat SDK/Samples/Minimap", false, 983)]
|
||||
private static void OpenMinimapExampleScene()
|
||||
{
|
||||
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
EditorSceneManager.OpenScene(minimapScenePath);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("VRChat SDK/Samples/MidiPlayback", false, 984)]
|
||||
private static void OpenMidiPlaybackExampleScene()
|
||||
{
|
||||
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
EditorSceneManager.OpenScene(midiPlaybackScenePath);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("VRChat SDK/Samples/Show Sample Documentation", false, 985)]
|
||||
private static void ShowSampleDocumentation()
|
||||
{
|
||||
Application.OpenURL("https://creators.vrchat.com/worlds/examples/");
|
||||
}
|
||||
|
||||
[MenuItem("VRChat SDK/Samples/AI Navigation")]
|
||||
private static void OpenAINavigationScene()
|
||||
{
|
||||
if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
|
||||
{
|
||||
EditorSceneManager.OpenScene(aiNavigationScenePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b56ebc0667f4a2eb02271d4b50dfb25
|
||||
timeCreated: 1674684606
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0b73331be6c26f4b89114d305cf4b19
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81474508413c9834f828b4df9f6ea8b8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,16 @@
|
||||
#listinginfo-elem {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#copylisting-btn {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
#copygroup-btn {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#groupinfo-label {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d224dc29736cb9841a28474730e7cab2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@ -0,0 +1,8 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement name="listinginfo-elem" >
|
||||
<Style src="ListingInfo.uss" />
|
||||
<ui:Button text="Copy Listing ID" name="copylisting-btn" />
|
||||
<ui:Button text="Copy Group ID" name="copygroup-btn" />
|
||||
<ui:Label text="This listing is not used in any group." name="groupinfo-label" />
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6724ec48439eb974296016be79041d9a
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@ -0,0 +1,100 @@
|
||||
#product-elem {
|
||||
height: 64px;
|
||||
flex-direction: row;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#image-elem {
|
||||
width: 64px;
|
||||
flex-shrink: 0;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
margin-left: 0;
|
||||
margin-right: 5px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
border-left-color: rgba(0, 0, 0, 0.25);
|
||||
border-right-color: rgba(0, 0, 0, 0.25);
|
||||
border-top-color: rgba(0, 0, 0, 0.25);
|
||||
border-bottom-color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
#imagefetch-btn {
|
||||
height: auto;
|
||||
width: auto;
|
||||
flex-grow: 1;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
white-space: normal;
|
||||
flex-basis: 0;
|
||||
}
|
||||
|
||||
#imagedelete-btn {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
white-space: nowrap;
|
||||
flex-grow: 0;
|
||||
-unity-font-style: bold;
|
||||
-unity-text-align: middle-center;
|
||||
font-size: 12px;
|
||||
border-left-width: 0;
|
||||
border-right-width: 0;
|
||||
border-top-width: 0;
|
||||
border-bottom-width: 0;
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
#text-elem {
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#name-label {
|
||||
-unity-font-style: bold;
|
||||
font-size: 14px;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#desc-label {
|
||||
white-space: normal;
|
||||
flex-wrap: wrap;
|
||||
font-size: 11px;
|
||||
-unity-font-style: normal;
|
||||
flex-shrink: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#buttons-elem {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
width: 112px;
|
||||
flex-shrink: 0;
|
||||
max-width: 112px;
|
||||
}
|
||||
|
||||
#customgui-elem > Button {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#customgui-elem {
|
||||
display: none;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#find-btn {
|
||||
flex-grow: 1;
|
||||
white-space: normal;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a117358ea147804091dc5ea3caff5e5
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@ -0,0 +1,17 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement name="product-elem">
|
||||
<Style src="UdonProduct.uss" />
|
||||
<ui:VisualElement name="image-elem" tooltip="Fetched product images are stored in your Unity project, which may increase the size of your world. It is recommended to only fetch the images if you plan on using them with Udon.">
|
||||
<ui:Button text="Fetch image" name="imagefetch-btn" />
|
||||
<ui:Button text="✖" name="imagedelete-btn" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="text-elem" >
|
||||
<ui:Label text="Product A" binding-path="_Name" name="name-label" />
|
||||
<ui:Label text="Description of the product, this is a description of the product right here as you can see. " binding-path="_Description" name="desc-label" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="buttons-elem" >
|
||||
<ui:VisualElement name="customgui-elem" />
|
||||
<ui:Button text="Find in project" name="find-btn" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 812df186f845ade4aa400a80e7aa8577
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@ -0,0 +1,29 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement name="header-elem">
|
||||
<Style src="UdonProductsManager_Common.uss" />
|
||||
<ui:VisualElement name="logintext-elem" class="infobox error">
|
||||
<ui:Label text="You need to be logged in before fetching the details of Udon products." name="logintext-label" />
|
||||
</ui:VisualElement>
|
||||
<ui:Button text="Import/Refresh all UdonProducts" name="importrefresh-btn" />
|
||||
<ui:VisualElement name="importbrowse-elem">
|
||||
<ui:Label text="Import in..." name="importbrowse-label" />
|
||||
<ui:TextField readonly="true" focusable="false" binding-path="importPath" name="importbrowse-textfield" />
|
||||
<uie:ToolbarButton text="Browse" name="importbrowse-btn" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="sort-elem">
|
||||
<uie:ToolbarToggle focusable="false" label="Sort by Scene/Project" name="sortbyproject-btn" />
|
||||
<uie:ToolbarToggle focusable="false" label="Sort by Listings" name="sortbylistings-btn" />
|
||||
</ui:VisualElement>
|
||||
<uie:ToolbarSearchField focusable="true" name="searchbar-input" style="display: none;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="main-elem">
|
||||
<Style src="UdonProductsManager_Common.uss" />
|
||||
<ui:ScrollView name="main-scrollview" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="footer-elem" >
|
||||
<Style src="UdonProductsManager_Common.uss" />
|
||||
<ui:VisualElement name="infobox-elem" class="infobox" style="visibility: hidden;">
|
||||
<ui:Label name="infobox-label" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f37d939a10aa6f4db958867a3134583
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
|
||||
@ -0,0 +1,124 @@
|
||||
#logintext-elem {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#infobox-elem {
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#infobox-label {
|
||||
white-space: normal;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.infobox {
|
||||
border-top-left-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-left-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
.infobox > Label {
|
||||
-unity-text-align: middle-left;
|
||||
flex-grow: 1;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
#header-elem {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 1px;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.1);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#footer-elem {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
border-top-width: 2px;
|
||||
border-top-color: rgba(0, 0, 0, 0.1);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#importrefresh-btn {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#sort-elem {
|
||||
flex-direction: row;
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
#sortbyproject-btn, #sortbylistings-btn
|
||||
{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#searchbar-input {
|
||||
width: auto;
|
||||
height: auto;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#main-elem {
|
||||
height: auto;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#main-scrollview {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
#logintext-elem {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#importbrowse-elem {
|
||||
flex-direction: row;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
#importbrowse-label {
|
||||
-unity-text-align: middle-left;
|
||||
}
|
||||
|
||||
#importbrowse-textfield {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#footer-elem {
|
||||
min-height: 3%;
|
||||
flex-direction: column-reverse;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4ea363175552f5448a58f058e68e1c0
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@ -0,0 +1,27 @@
|
||||
.infobox {
|
||||
border-color: rgb(35, 35, 35);
|
||||
background-color: rgba(96, 96, 96, 0.2);
|
||||
}
|
||||
|
||||
.infobox > Label {
|
||||
color: rgb(189, 189, 189);
|
||||
}
|
||||
|
||||
.infobox.warning {
|
||||
border-color: rgba(255, 215, 0, 0.5);
|
||||
background-color: rgba(255, 215, 0, 0.25);
|
||||
}
|
||||
|
||||
.infobox.warning > Label {
|
||||
color: rgb(255, 215, 0);
|
||||
}
|
||||
|
||||
.infobox.error {
|
||||
border-color: rgba(255, 0, 0, 0.5);
|
||||
background-color: rgba(255, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.infobox.error > Label {
|
||||
color: rgb(255, 100, 100);
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbc798c6928475444a1e396633f50b3d
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
@ -0,0 +1,26 @@
|
||||
.infobox {
|
||||
border-color: rgba(0, 0, 0, 0.27);
|
||||
background-color: rgba(235, 235, 235, 0.2);
|
||||
}
|
||||
|
||||
.infobox > Label {
|
||||
color: rgba(22, 22, 22, 255);
|
||||
}
|
||||
|
||||
.infobox.warning {
|
||||
border-color: rgba(255, 215, 0, 0.5);
|
||||
background-color: rgba(255, 215, 0, 0.25);
|
||||
}
|
||||
|
||||
.infobox.warning > Label {
|
||||
color: rgb(255, 255, 200);
|
||||
}
|
||||
|
||||
.infobox.error {
|
||||
border-color: rgba(255, 0, 0, 0.5);
|
||||
background-color: rgba(255, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.infobox.error > Label {
|
||||
color: rgb(166, 28, 28);
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5674ec0d53513c2438781be77c07e365
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
|
||||
disableValidation: 0
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e86b4bbd3fb4fa44fbe478e1e59b73e2
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,701 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!29 &1
|
||||
OcclusionCullingSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_OcclusionBakeSettings:
|
||||
smallestOccluder: 5
|
||||
smallestHole: 0.25
|
||||
backfaceThreshold: 100
|
||||
m_SceneGUID: 00000000000000000000000000000000
|
||||
m_OcclusionCullingData: {fileID: 0}
|
||||
--- !u!104 &2
|
||||
RenderSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 9
|
||||
m_Fog: 0
|
||||
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
|
||||
m_FogMode: 3
|
||||
m_FogDensity: 0.01
|
||||
m_LinearFogStart: 0
|
||||
m_LinearFogEnd: 300
|
||||
m_AmbientSkyColor: {r: 0.6037736, g: 0.6037736, b: 0.6037736, a: 1}
|
||||
m_AmbientEquatorColor: {r: 0.3542186, g: 0.36578855, b: 0.3773585, a: 1}
|
||||
m_AmbientGroundColor: {r: 0.1981132, g: 0.19344072, b: 0.18409576, a: 1}
|
||||
m_AmbientIntensity: 1
|
||||
m_AmbientMode: 1
|
||||
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 2100000, guid: 21221da753878694b9b9518a540dda85, type: 2}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
m_HaloTexture: {fileID: 0}
|
||||
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_DefaultReflectionMode: 0
|
||||
m_DefaultReflectionResolution: 128
|
||||
m_ReflectionBounces: 1
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 0}
|
||||
m_IndirectSpecularColor: {r: 0.3322065, g: 0.3627174, b: 0.46474278, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 12
|
||||
m_GIWorkflowMode: 1
|
||||
m_GISettings:
|
||||
serializedVersion: 2
|
||||
m_BounceScale: 1
|
||||
m_IndirectOutputScale: 1
|
||||
m_AlbedoBoost: 1
|
||||
m_EnvironmentLightingMode: 0
|
||||
m_EnableBakedLightmaps: 1
|
||||
m_EnableRealtimeLightmaps: 1
|
||||
m_LightmapEditorSettings:
|
||||
serializedVersion: 12
|
||||
m_Resolution: 2
|
||||
m_BakeResolution: 40
|
||||
m_AtlasSize: 1024
|
||||
m_AO: 0
|
||||
m_AOMaxDistance: 1
|
||||
m_CompAOExponent: 1
|
||||
m_CompAOExponentDirect: 0
|
||||
m_ExtractAmbientOcclusion: 0
|
||||
m_Padding: 2
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_LightmapsBakeMode: 1
|
||||
m_TextureCompression: 1
|
||||
m_FinalGather: 0
|
||||
m_FinalGatherFiltering: 1
|
||||
m_FinalGatherRayCount: 256
|
||||
m_ReflectionCompression: 2
|
||||
m_MixedBakeMode: 2
|
||||
m_BakeBackend: 1
|
||||
m_PVRSampling: 1
|
||||
m_PVRDirectSampleCount: 32
|
||||
m_PVRSampleCount: 500
|
||||
m_PVRBounces: 2
|
||||
m_PVREnvironmentSampleCount: 500
|
||||
m_PVREnvironmentReferencePointCount: 2048
|
||||
m_PVRFilteringMode: 2
|
||||
m_PVRDenoiserTypeDirect: 0
|
||||
m_PVRDenoiserTypeIndirect: 0
|
||||
m_PVRDenoiserTypeAO: 0
|
||||
m_PVRFilterTypeDirect: 0
|
||||
m_PVRFilterTypeIndirect: 0
|
||||
m_PVRFilterTypeAO: 0
|
||||
m_PVREnvironmentMIS: 0
|
||||
m_PVRCulling: 1
|
||||
m_PVRFilteringGaussRadiusDirect: 1
|
||||
m_PVRFilteringGaussRadiusIndirect: 5
|
||||
m_PVRFilteringGaussRadiusAO: 2
|
||||
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
|
||||
m_PVRFilteringAtrousPositionSigmaIndirect: 2
|
||||
m_PVRFilteringAtrousPositionSigmaAO: 1
|
||||
m_ExportTrainingData: 0
|
||||
m_TrainingDataDestination: TrainingData
|
||||
m_LightProbeSampleCountMultiplier: 4
|
||||
m_LightingDataAsset: {fileID: 112000000, guid: 93758136d0b55324482fcfce76a34bff,
|
||||
type: 2}
|
||||
m_LightingSettings: {fileID: 4890085278179872738, guid: 7774fab823fc47d4283c662c6d671e8d,
|
||||
type: 2}
|
||||
--- !u!196 &4
|
||||
NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 3
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.4
|
||||
ledgeDropHeight: 0
|
||||
maxJumpAcrossDistance: 0
|
||||
minRegionArea: 2
|
||||
manualCellSize: 0
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
buildHeightMesh: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_NavMeshData: {fileID: 0}
|
||||
--- !u!1 &358170787
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 358170790}
|
||||
- component: {fileID: 358170789}
|
||||
- component: {fileID: 358170788}
|
||||
m_Layer: 0
|
||||
m_Name: EventSystem
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &358170788
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 358170787}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_SendPointerHoverToParent: 1
|
||||
m_HorizontalAxis: Horizontal
|
||||
m_VerticalAxis: Vertical
|
||||
m_SubmitButton: Submit
|
||||
m_CancelButton: Cancel
|
||||
m_InputActionsPerSecond: 10
|
||||
m_RepeatDelay: 0.5
|
||||
m_ForceModuleActive: 0
|
||||
--- !u!114 &358170789
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 358170787}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_FirstSelected: {fileID: 0}
|
||||
m_sendNavigationEvents: 1
|
||||
m_DragThreshold: 10
|
||||
--- !u!4 &358170790
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 358170787}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1069902874
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1069902877}
|
||||
- component: {fileID: 1069902876}
|
||||
- component: {fileID: 1069902875}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!81 &1069902875
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1069902874}
|
||||
m_Enabled: 1
|
||||
--- !u!20 &1069902876
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1069902874}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 1
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 0
|
||||
orthographic size: 5
|
||||
m_Depth: -1
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 0}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &1069902877
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1069902874}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1.5, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1787983409
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1787983411}
|
||||
- component: {fileID: 1787983410}
|
||||
m_Layer: 0
|
||||
m_Name: Directional Light
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!108 &1787983410
|
||||
Light:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1787983409}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Intensity: 1
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.80208
|
||||
m_CookieSize: 10
|
||||
m_Shadows:
|
||||
m_Type: 2
|
||||
m_Resolution: -1
|
||||
m_CustomResolution: -1
|
||||
m_Strength: 1
|
||||
m_Bias: 0.05
|
||||
m_NormalBias: 0.4
|
||||
m_NearPlane: 0.2
|
||||
m_CullingMatrixOverride:
|
||||
e00: 1
|
||||
e01: 0
|
||||
e02: 0
|
||||
e03: 0
|
||||
e10: 0
|
||||
e11: 1
|
||||
e12: 0
|
||||
e13: 0
|
||||
e20: 0
|
||||
e21: 0
|
||||
e22: 1
|
||||
e23: 0
|
||||
e30: 0
|
||||
e31: 0
|
||||
e32: 0
|
||||
e33: 1
|
||||
m_UseCullingMatrixOverride: 0
|
||||
m_Cookie: {fileID: 0}
|
||||
m_DrawHalo: 0
|
||||
m_Flare: {fileID: 0}
|
||||
m_RenderMode: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingLayerMask: 1
|
||||
m_Lightmapping: 4
|
||||
m_LightShadowCasterMode: 0
|
||||
m_AreaSize: {x: 1, y: 1}
|
||||
m_BounceIntensity: 1
|
||||
m_ColorTemperature: 6570
|
||||
m_UseColorTemperature: 0
|
||||
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_UseBoundingSphereOverride: 0
|
||||
m_UseViewFrustumForShadowCasterCull: 1
|
||||
m_ShadowRadius: 0
|
||||
m_ShadowAngle: 0
|
||||
--- !u!4 &1787983411
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1787983409}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.73976463, y: 0.34240803, z: 0.05048304, w: 0.5770238}
|
||||
m_LocalPosition: {x: 0, y: 6, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 55, y: 125, z: 100}
|
||||
--- !u!114 &3231720197660963110
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3480278762663670689}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 45115577ef41a5b4ca741ed302693907, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
interactTextPlacement: {fileID: 0}
|
||||
interactText: Use
|
||||
interactTextGO: {fileID: 0}
|
||||
proximity: 2
|
||||
SynchronizePosition: 0
|
||||
AllowCollisionOwnershipTransfer: 0
|
||||
Reliable: 0
|
||||
_syncMethod: 1
|
||||
serializedProgramAsset: {fileID: 11400000, guid: 21a13e0a0a257474f97830fdcc78b27e,
|
||||
type: 2}
|
||||
programSource: {fileID: 11400000, guid: c8df303ceb45ae84f85a11591f741734, type: 2}
|
||||
serializedPublicVariablesBytesString: Ai8AAAAAATIAAABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlAFQAYQBiAGwAZQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AAAAAAAYBAAAAAAAAACcBBAAAAHQAeQBwAGUAAWgAAABTAHkAcwB0AGUAbQAuAEMAbwBsAGwAZQBjAHQAaQBvAG4AcwAuAEcAZQBuAGUAcgBpAGMALgBMAGkAcwB0AGAAMQBbAFsAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4ALgBJAG4AdABlAHIAZgBhAGMAZQBzAC4ASQBVAGQAbwBuAFYAYQByAGkAYQBiAGwAZQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AXQBdACwAIABtAHMAYwBvAHIAbABpAGIAAQEJAAAAVgBhAHIAaQBhAGIAbABlAHMALwEAAAABaAAAAFMAeQBzAHQAZQBtAC4AQwBvAGwAbABlAGMAdABpAG8AbgBzAC4ARwBlAG4AZQByAGkAYwAuAEwAaQBzAHQAYAAxAFsAWwBWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAEkAbgB0AGUAcgBmAGEAYwBlAHMALgBJAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlACwAIABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgBdAF0ALAAgAG0AcwBjAG8AcgBsAGkAYgABAAAABgQAAAAAAAAAAi8CAAAAAUoAAABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlAGAAMQBbAFsAUwB5AHMAdABlAG0ALgBTAGkAbgBnAGwAZQAsACAAbQBzAGMAbwByAGwAaQBiAF0AXQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AAgAAAAYCAAAAAAAAACcBBAAAAHQAeQBwAGUAARcAAABTAHkAcwB0AGUAbQAuAFMAdAByAGkAbgBnACwAIABtAHMAYwBvAHIAbABpAGIAJwEKAAAAUwB5AG0AYgBvAGwATgBhAG0AZQABCwAAAGoAdQBtAHAASQBtAHAAdQBsAHMAZQAnAQQAAAB0AHkAcABlAAEXAAAAUwB5AHMAdABlAG0ALgBTAGkAbgBnAGwAZQAsACAAbQBzAGMAbwByAGwAaQBiAB8BBQAAAFYAYQBsAHUAZQAAAEBABwUCMAIAAAADAAAABgIAAAAAAAAAJwEEAAAAdAB5AHAAZQABFwAAAFMAeQBzAHQAZQBtAC4AUwB0AHIAaQBuAGcALAAgAG0AcwBjAG8AcgBsAGkAYgAnAQoAAABTAHkAbQBiAG8AbABOAGEAbQBlAAEJAAAAdwBhAGwAawBTAHAAZQBlAGQAJwEEAAAAdAB5AHAAZQABFwAAAFMAeQBzAHQAZQBtAC4AUwBpAG4AZwBsAGUALAAgAG0AcwBjAG8AcgBsAGkAYgAfAQUAAABWAGEAbAB1AGUAAAAAQAcFAjACAAAABAAAAAYCAAAAAAAAACcBBAAAAHQAeQBwAGUAARcAAABTAHkAcwB0AGUAbQAuAFMAdAByAGkAbgBnACwAIABtAHMAYwBvAHIAbABpAGIAJwEKAAAAUwB5AG0AYgBvAGwATgBhAG0AZQABCAAAAHIAdQBuAFMAcABlAGUAZAAnAQQAAAB0AHkAcABlAAEXAAAAUwB5AHMAdABlAG0ALgBTAGkAbgBnAGwAZQAsACAAbQBzAGMAbwByAGwAaQBiAB8BBQAAAFYAYQBsAHUAZQAAAIBABwUCMAIAAAAFAAAABgIAAAAAAAAAJwEEAAAAdAB5AHAAZQABFwAAAFMAeQBzAHQAZQBtAC4AUwB0AHIAaQBuAGcALAAgAG0AcwBjAG8AcgBsAGkAYgAnAQoAAABTAHkAbQBiAG8AbABOAGEAbQBlAAELAAAAcwB0AHIAYQBmAGUAUwBwAGUAZQBkACcBBAAAAHQAeQBwAGUAARcAAABTAHkAcwB0AGUAbQAuAFMAaQBuAGcAbABlACwAIABtAHMAYwBvAHIAbABpAGIAHwEFAAAAVgBhAGwAdQBlAAAAAEAHBQcFBwU=
|
||||
publicVariablesUnityEngineObjects: []
|
||||
publicVariablesSerializationDataFormat: 0
|
||||
--- !u!4 &3480278762663400089
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3480278762663670689}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: -2.558}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3480278762663670689
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3480278762663400089}
|
||||
- component: {fileID: 7111575897785925491}
|
||||
- component: {fileID: 3591906996255472209}
|
||||
- component: {fileID: 3231720197660963110}
|
||||
- component: {fileID: 3480278762663670690}
|
||||
m_Layer: 0
|
||||
m_Name: VRCWorld
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &3480278762663670690
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3480278762663670689}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 45115577ef41a5b4ca741ed302693907, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
interactTextPlacement: {fileID: 0}
|
||||
interactText: Use
|
||||
interactTextGO: {fileID: 0}
|
||||
proximity: 2
|
||||
SynchronizePosition: 0
|
||||
AllowCollisionOwnershipTransfer: 1
|
||||
Reliable: 0
|
||||
_syncMethod: 1
|
||||
serializedProgramAsset: {fileID: 11400000, guid: a82912e628ffbe845afde2e220e1a277,
|
||||
type: 2}
|
||||
programSource: {fileID: 11400000, guid: 566cc00e27d5822449529a3785eae366, type: 2}
|
||||
serializedPublicVariablesBytesString: Ai8AAAAAATIAAABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlAFQAYQBiAGwAZQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AAAAAAAYBAAAAAAAAACcBBAAAAHQAeQBwAGUAAWgAAABTAHkAcwB0AGUAbQAuAEMAbwBsAGwAZQBjAHQAaQBvAG4AcwAuAEcAZQBuAGUAcgBpAGMALgBMAGkAcwB0AGAAMQBbAFsAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4ALgBJAG4AdABlAHIAZgBhAGMAZQBzAC4ASQBVAGQAbwBuAFYAYQByAGkAYQBiAGwAZQAsACAAVgBSAEMALgBVAGQAbwBuAC4AQwBvAG0AbQBvAG4AXQBdACwAIABtAHMAYwBvAHIAbABpAGIAAQEJAAAAVgBhAHIAaQBhAGIAbABlAHMALwEAAAABaAAAAFMAeQBzAHQAZQBtAC4AQwBvAGwAbABlAGMAdABpAG8AbgBzAC4ARwBlAG4AZQByAGkAYwAuAEwAaQBzAHQAYAAxAFsAWwBWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAEkAbgB0AGUAcgBmAGEAYwBlAHMALgBJAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlACwAIABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgBdAF0ALAAgAG0AcwBjAG8AcgBsAGkAYgABAAAABgQAAAAAAAAAAi8CAAAAAUsAAABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAuAFUAZABvAG4AVgBhAHIAaQBhAGIAbABlAGAAMQBbAFsAUwB5AHMAdABlAG0ALgBCAG8AbwBsAGUAYQBuACwAIABtAHMAYwBvAHIAbABpAGIAXQBdACwAIABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgACAAAABgIAAAAAAAAAJwEEAAAAdAB5AHAAZQABFwAAAFMAeQBzAHQAZQBtAC4AUwB0AHIAaQBuAGcALAAgAG0AcwBjAG8AcgBsAGkAYgAnAQoAAABTAHkAbQBiAG8AbABOAGEAbQBlAAEUAAAAZABpAHMAYQBiAGwAZQBBAHYAYQB0AGEAcgBTAGMAYQBsAGkAbgBnACcBBAAAAHQAeQBwAGUAARgAAABTAHkAcwB0AGUAbQAuAEIAbwBvAGwAZQBhAG4ALAAgAG0AcwBjAG8AcgBsAGkAYgArAQUAAABWAGEAbAB1AGUAAAcFAjACAAAAAwAAAAYCAAAAAAAAACcBBAAAAHQAeQBwAGUAARcAAABTAHkAcwB0AGUAbQAuAFMAdAByAGkAbgBnACwAIABtAHMAYwBvAHIAbABpAGIAJwEKAAAAUwB5AG0AYgBvAGwATgBhAG0AZQABEwAAAGEAbAB3AGEAeQBzAEUAbgBmAG8AcgBjAGUASABlAGkAZwBoAHQAJwEEAAAAdAB5AHAAZQABGAAAAFMAeQBzAHQAZQBtAC4AQgBvAG8AbABlAGEAbgAsACAAbQBzAGMAbwByAGwAaQBiACsBBQAAAFYAYQBsAHUAZQAABwUCLwMAAAABSgAAAFYAUgBDAC4AVQBkAG8AbgAuAEMAbwBtAG0AbwBuAC4AVQBkAG8AbgBWAGEAcgBpAGEAYgBsAGUAYAAxAFsAWwBTAHkAcwB0AGUAbQAuAFMAaQBuAGcAbABlACwAIABtAHMAYwBvAHIAbABpAGIAXQBdACwAIABWAFIAQwAuAFUAZABvAG4ALgBDAG8AbQBtAG8AbgAEAAAABgIAAAAAAAAAJwEEAAAAdAB5AHAAZQABFwAAAFMAeQBzAHQAZQBtAC4AUwB0AHIAaQBuAGcALAAgAG0AcwBjAG8AcgBsAGkAYgAnAQoAAABTAHkAbQBiAG8AbABOAGEAbQBlAAENAAAAbQBpAG4AaQBtAHUAbQBIAGUAaQBnAGgAdAAnAQQAAAB0AHkAcABlAAEXAAAAUwB5AHMAdABlAG0ALgBTAGkAbgBnAGwAZQAsACAAbQBzAGMAbwByAGwAaQBiAB8BBQAAAFYAYQBsAHUAZQDNzEw+BwUCMAMAAAAFAAAABgIAAAAAAAAAJwEEAAAAdAB5AHAAZQABFwAAAFMAeQBzAHQAZQBtAC4AUwB0AHIAaQBuAGcALAAgAG0AcwBjAG8AcgBsAGkAYgAnAQoAAABTAHkAbQBiAG8AbABOAGEAbQBlAAENAAAAbQBhAHgAaQBtAHUAbQBIAGUAaQBnAGgAdAAnAQQAAAB0AHkAcABlAAEXAAAAUwB5AHMAdABlAG0ALgBTAGkAbgBnAGwAZQAsACAAbQBzAGMAbwByAGwAaQBiAB8BBQAAAFYAYQBsAHUAZQAAAKBABwUHBQcF
|
||||
publicVariablesUnityEngineObjects: []
|
||||
publicVariablesSerializationDataFormat: 0
|
||||
--- !u!114 &3591906996255472209
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3480278762663670689}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
launchedFromSDKPipeline: 0
|
||||
completedSDKPipeline: 0
|
||||
blueprintId:
|
||||
contentType: 1
|
||||
assetBundleUnityVersion:
|
||||
fallbackStatus: 0
|
||||
--- !u!114 &7111575897785925491
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3480278762663670689}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -17141911, guid: 661092b4961be7145bfbe56e1e62337b, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
spawns:
|
||||
- {fileID: 3480278762663400089}
|
||||
spawnRadius: 0.2
|
||||
spawnOrder: 2
|
||||
spawnOrientation: 0
|
||||
ReferenceCamera: {fileID: 1069902874}
|
||||
RespawnHeightY: -100
|
||||
ObjectBehaviourAtRespawnHeight: 0
|
||||
ForbidUserPortals: 0
|
||||
interactThruLayers: 0
|
||||
autoSpatializeAudioSources: 0
|
||||
gravity: {x: 0, y: -9.81, z: 0}
|
||||
layerCollisionArr: 01010101010001010101010100010001010101010101010101010101010101010101010101000101010101010001000101010101010101010101010101010101010101010100010101010101000100010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101000101010101010001000101010101010101010101010101010101000000010000010100000000000000000000000000000101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100010101010101000100010101010101010101010101010101010101010101010001010100000100000000000001010101010101010101010101010101010101000101010000010000000000000101010101010101010101010101010101010100010101010101000100010101010101010101010101010101010100000001000001010000000000000000000000000000010101010101010101010101010101000101010000010001010101010000000001010101010101010101000000010000010100000000000100000000000000000101010101010101010101010101010001010100000100010001010101010101010101010101010101010101010101000101010000010001000101010101010101010101010101010101010101010100010101000001000100010101010101010101010101010101010101010101010001010101010100000001010101010101010101010101010101010101010101000101010101010000000101010101010101010101010101010101010101010100010101010101000000010101010101010101010101010101010101010101010001010101010100000001010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101
|
||||
capacity: 0
|
||||
contentSex: 0
|
||||
contentViolence: 0
|
||||
contentGore: 0
|
||||
contentOther: 0
|
||||
releasePublic: 0
|
||||
unityVersion: 2019.4.31f1
|
||||
udonProducts: []
|
||||
Name:
|
||||
NSFW: 0
|
||||
SpawnPosition: {x: 0, y: 0, z: 0}
|
||||
SpawnLocation: {fileID: 0}
|
||||
DrawDistance: 0
|
||||
useAssignedLayers: 0
|
||||
DynamicPrefabs: []
|
||||
DynamicMaterials:
|
||||
- {fileID: 2100000, guid: 74de320d298ce3e498b0401ec1ffcb7f, type: 2}
|
||||
- {fileID: 2100000, guid: 1c987494452b85f4ab4cac3322415907, type: 2}
|
||||
- {fileID: 2100000, guid: c815f7613a04b724089c206857e57c6a, type: 2}
|
||||
- {fileID: 2100000, guid: fd20e45036ef323459e8286e9c23c02c, type: 2}
|
||||
LightMapsNear: []
|
||||
LightMapsFar: []
|
||||
LightMode: 0
|
||||
RenderAmbientEquatorColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
RenderAmbientGroundColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
RenderAmbientIntensity: 0
|
||||
RenderAmbientLight: {r: 0, g: 0, b: 0, a: 0}
|
||||
RenderAmbientMode: 0
|
||||
RenderAmbientProbe:
|
||||
sh[ 0]: 0
|
||||
sh[ 1]: 0
|
||||
sh[ 2]: 0
|
||||
sh[ 3]: 0
|
||||
sh[ 4]: 0
|
||||
sh[ 5]: 0
|
||||
sh[ 6]: 0
|
||||
sh[ 7]: 0
|
||||
sh[ 8]: 0
|
||||
sh[ 9]: 0
|
||||
sh[10]: 0
|
||||
sh[11]: 0
|
||||
sh[12]: 0
|
||||
sh[13]: 0
|
||||
sh[14]: 0
|
||||
sh[15]: 0
|
||||
sh[16]: 0
|
||||
sh[17]: 0
|
||||
sh[18]: 0
|
||||
sh[19]: 0
|
||||
sh[20]: 0
|
||||
sh[21]: 0
|
||||
sh[22]: 0
|
||||
sh[23]: 0
|
||||
sh[24]: 0
|
||||
sh[25]: 0
|
||||
sh[26]: 0
|
||||
RenderAmbientSkyColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
RenderFog: 0
|
||||
RenderFogColor: {r: 0, g: 0, b: 0, a: 0}
|
||||
RenderFogMode: 0
|
||||
RenderFogDensity: 0
|
||||
RenderFogLinearStart: 0
|
||||
RenderFogLinearEnd: 0
|
||||
RenderHaloStrength: 0
|
||||
RenderFlareFadeSpeed: 0
|
||||
RenderFlareStrength: 0
|
||||
RenderCustomReflection: {fileID: 0}
|
||||
RenderDefaultReflectionMode: 0
|
||||
RenderDefaultReflectionResolution: 0
|
||||
RenderReflectionBounces: 0
|
||||
RenderReflectionIntensity: 0
|
||||
RenderSkybox: {fileID: 0}
|
||||
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
|
||||
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
|
||||
PlayerPersistence: []
|
||||
--- !u!64 &7606902903243430482
|
||||
MeshCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7606902903243430483}
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_LayerOverridePriority: 0
|
||||
m_IsTrigger: 0
|
||||
m_ProvidesContacts: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 5
|
||||
m_Convex: 0
|
||||
m_CookingOptions: 30
|
||||
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!1 &7606902903243430483
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7606902903243430487}
|
||||
- component: {fileID: 7606902903243430484}
|
||||
- component: {fileID: 7606902903243430485}
|
||||
- component: {fileID: 7606902903243430482}
|
||||
m_Layer: 0
|
||||
m_Name: Floor
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!33 &7606902903243430484
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7606902903243430483}
|
||||
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!23 &7606902903243430485
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7606902903243430483}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_StaticShadowCaster: 0
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: fd20e45036ef323459e8286e9c23c02c, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!4 &7606902903243430487
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7606902903243430483}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 100, y: 100, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 3480278762663400089}
|
||||
- {fileID: 1069902877}
|
||||
- {fileID: 1787983411}
|
||||
- {fileID: 7606902903243430487}
|
||||
- {fileID: 358170790}
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93517af8dc41f034aa64948626b03573
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user