Skip to content

Commit

Permalink
Refactor, bump to 0.1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
I5UCC committed Apr 15, 2024
1 parent 46e8ca3 commit 256df9a
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 227 deletions.
295 changes: 69 additions & 226 deletions Editor/VRCMultiUploader.cs
Original file line number Diff line number Diff line change
@@ -1,259 +1,102 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;
using System;
using System.Reflection;
using VRC.SDK3A.Editor;
using VRC.SDKBase.Editor;
using VRC.SDKBase.Editor.Api;
using VRC.Core;
using System.Threading;
using System.Threading.Tasks;

public class VRCMultiUploader : MonoBehaviour
namespace VRCMultiUploader
{
[MenuItem("VRCMultiUploader/Build and Test")]
private static void BuildAndTest() => BuildAll(true);

[MenuItem("VRCMultiUploader/Build and Publish")]
private static void BuildAndUpload() => BuildAll();

public static async Task BuildAll(bool test = false)
[InitializeOnLoad]
public class VrcMultiUploader : MonoBehaviour
{
foreach (var w in Resources.FindObjectsOfTypeAll<VRCMultiUploader_PopupWindow>())
if (w) w.Close();
EditorApplication.ExecuteMenuItem("VRChat SDK/Show Control Panel");
GameObject avatarObject = null;
string blueprintId = null;
static VrcMultiUploader()
{
EditorApplication.delayCall += () =>
{
PopupWindow.CloseAllInstances();
EditorApplication.ExecuteMenuItem("VRChat SDK/Show Control Panel");
};
}

PipelineManager[] avatars = FindObjectsOfType<PipelineManager>();
int avatarCount = avatars.Length;
[MenuItem("VRCMultiUploader/Build and Test All", false, 1000)]
private static async Task BuildAndTest() => await BuildAll(true);

VRCMultiUploader_PopupWindow progressWindow = VRCMultiUploader_PopupWindow.Create(avatarCount);
Debug.Log("Found " + avatarCount + " active Avatars in the Scene.");
[MenuItem("VRCMultiUploader/Build and Publish All", false, 1001)]
private static async Task BuildAndUpload() => await BuildAll();

progressWindow.Progress(0, "Getting Builder...");
if (!VRCSdkControlPanel.TryGetBuilder(out IVRCSdkAvatarBuilderApi builder))
public static async Task BuildAll(bool test = false)
{
progressWindow.Close();
EditorUtility.DisplayDialog("MultiUploader - Error", "Could not get Builder. Please open the SDK Control Panel and try again.", "OK");
return;
}
PopupWindow.CloseAllInstances();
EditorApplication.ExecuteMenuItem("VRChat SDK/Show Control Panel");

for (int i = 0; i < avatarCount; i++)
{
avatarObject = avatars[i].gameObject;
blueprintId = avatars[i].blueprintId;
PipelineManager[] avatars = FindObjectsOfType<PipelineManager>();
int avatarCount = avatars.Length;

if (!test && (blueprintId == null || blueprintId == ""))
PopupWindow progressWindow = PopupWindow.Create(avatarCount);
Debug.Log("Found " + avatarCount + " active Avatars in the Scene.");

progressWindow.Progress(0, "Getting Builder...");
if (!VRCSdkControlPanel.TryGetBuilder(out IVRCSdkAvatarBuilderApi builder))
{
Debug.LogError("Avatar " + avatars[i].gameObject.name + " does not have a blueprintId set.");
EditorUtility.DisplayDialog("MultiUploader - Error", "Avatar " + avatarObject.name + " does not have a blueprintId set."
+ "\nPlease upload this avatar once before trying to update it with MultiUploader."
+ "\nThis avatar will be skipped.", "OK");
continue;
progressWindow.Close();
EditorUtility.DisplayDialog("MultiUploader - Error", "Could not get Builder. Please open the SDK Control Panel and try again.", "OK");
return;
}

progressWindow.Progress(i, "Uploading avatar:\n" + avatarObject.name);
try
for (int i = 0; i < avatarCount; i++)
{
if (!test)
GameObject avatarObject = avatars[i].gameObject;
string blueprintId = avatars[i].blueprintId;

if (!test && (blueprintId == null || blueprintId == ""))
{
Debug.Log($"Uploading avatar: {avatarObject.name} with blueprintId: {blueprintId}");
VRCAvatar av = await VRCApi.GetAvatar(blueprintId);
await builder.BuildAndUpload(avatarObject, av);
Debug.LogError("Avatar " + avatars[i].gameObject.name + " does not have a blueprintId set.");
EditorUtility.DisplayDialog("MultiUploader - Error", "Avatar " + avatarObject.name + " does not have a blueprintId set."
+ "\nPlease upload this avatar once before trying to update it with MultiUploader."
+ "\nThis avatar will be skipped.", "OK");
continue;
}
else

progressWindow.Progress(i, "Uploading avatar:\n" + avatarObject.name);
try
{
Debug.Log($"Uploading avatar {avatarObject.name} for testing.");
await builder.BuildAndTest(avatarObject);
if (!test)
{
Debug.Log($"Uploading avatar: {avatarObject.name} with blueprintId: {blueprintId}");
VRCAvatar av = await VRCApi.GetAvatar(blueprintId);
await builder.BuildAndUpload(avatarObject, av);
}
else
{
Debug.Log($"Uploading avatar {avatarObject.name} for testing.");
await builder.BuildAndTest(avatarObject);
}
if (progressWindow.cancelled)
{
progressWindow.Progress(i, $"Cancelled! ({i + 1}/{avatarCount})", true);
return;
}
progressWindow.Progress(i, "Finished uploading avatar:\n" + avatarObject.name, true);
Thread.Sleep(2000);
}
if (progressWindow.cancelled)
catch (NullReferenceException e)
{
progressWindow.Progress(i, $"Cancelled! ({i + 1}/{avatarCount})", true);
progressWindow.Close();
EditorUtility.DisplayDialog("MultiUploader - Error", "SDK Control Panel hasn't been opened yet. Please open the SDK Control Panel and try again.", "OK");
Debug.LogError(e.Message + e.StackTrace);
return;
}
progressWindow.Progress(i, "Finished uploading avatar:\n" + avatarObject.name, true);
Thread.Sleep(2000);
}
catch (NullReferenceException e)
{
progressWindow.Close();
EditorUtility.DisplayDialog("MultiUploader - Error", "SDK Control Panel hasn't been opened yet. Please open the SDK Control Panel and try again.", "OK");
Debug.LogError(e.Message + e.StackTrace);
return;
}
catch (Exception e)
{
Debug.LogError(e.Message + e.StackTrace);
}
}

progressWindow.Progress(avatarCount, $"Finished uploading all Avatars! ({avatarCount}/{avatarCount})", true);
progressWindow.ShowOKButton();
}
}

[InitializeOnLoad]
public class VRCMultiUploader_PopupWindow : EditorWindow
{
private Label toplabel;
private Label label;
private Button ok_button;
private Button cancel_button;
private ProgressBar progress;
private VisualElement infoBox;
private static int amountofAvatars;
public bool cancelled = false;

static VRCMultiUploader_PopupWindow()
{
EditorApplication.delayCall += () =>
{
foreach (var w in Resources.FindObjectsOfTypeAll<VRCMultiUploader_PopupWindow>())
{
if (w) w.Close();
}
};
}

public static VRCMultiUploader_PopupWindow Create(int amount)
{
amountofAvatars = amount;
var window = CreateInstance<VRCMultiUploader_PopupWindow>();
var mainWindowPos = GetEditorMainWindowPos();
var size = new Vector2(500, 125);
window.position = new Rect(mainWindowPos.xMin + (mainWindowPos.width - size.x) * 0.5f, mainWindowPos.yMax * 0.5f + 150, size.x, size.y);
window.ShowPopup();
return window;
}

public void OnEnable()
{
var root = rootVisualElement;

infoBox = new VisualElement();
root.Add(infoBox);

toplabel = new Label("- VRCMultiUploader v0.1.3 by I5UCC -");
toplabel.style.paddingTop = 7;
toplabel.style.paddingBottom = 10;
toplabel.style.paddingLeft = 20;
toplabel.style.paddingRight = 20;
toplabel.style.unityTextAlign = TextAnchor.MiddleCenter;
toplabel.style.fontSize = 12;
infoBox.Add(toplabel);

progress = new ProgressBar();
progress.style.paddingTop = 0;
progress.style.paddingLeft = 20;
progress.style.paddingRight = 20;
progress.style.paddingBottom = 0;
progress.style.fontSize = 14;
infoBox.Add(progress);

label = new Label("");
label.style.paddingTop = 5;
label.style.paddingBottom = 0;
label.style.paddingLeft = 20;
label.style.paddingRight = 20;
label.style.fontSize = 24;
label.style.unityTextAlign = TextAnchor.MiddleCenter;
infoBox.Add(label);

cancel_button = new Button(() =>
{
cancelled = true;
ShowOKButton();
});
cancel_button.text = "X";
cancel_button.style.width = 20;
cancel_button.style.height = 20;
cancel_button.style.position = Position.Absolute;
cancel_button.style.right = 0;
cancel_button.style.top = 2;
infoBox.Add(cancel_button);
}

public void ShowOKButton()
{
ok_button = new Button(() => Close());
ok_button.text = "OK";
ok_button.style.width = 200;
ok_button.style.fontSize = 16;
ok_button.style.marginTop = 17;
ok_button.style.marginLeft = 20;
ok_button.style.marginRight = 20;
ok_button.style.unityTextAlign = TextAnchor.MiddleCenter;
ok_button.style.alignSelf = Align.Center;

infoBox.Remove(progress);
infoBox.Remove(cancel_button);
infoBox.Add(ok_button);
RepaintNow();
}

public void Progress(int current, string info, bool finished = false)
{
current += 1;
label.text = info;
progress.value = (float)(current - 1) / amountofAvatars * 100;
int percent = (int)Math.Round(progress.value);
if (current > amountofAvatars) current = amountofAvatars;
progress.title = $"{current}/{amountofAvatars} ({percent}%)";
Debug.Log($"Progress ({current}/{amountofAvatars}): {info}");
RepaintNow();
}

private void RepaintNow()
{
GetType().GetMethod("RepaintImmediately", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Invoke(this, new object[] { });
}

private static Type[] GetAllDerivedTypes(System.AppDomain aAppDomain, System.Type aType)
{
var result = new List<Type>();
var assemblies = aAppDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(aType))
result.Add(type);
catch (Exception e)
{
Debug.LogError(e.Message + e.StackTrace);
}
}
}
return result.ToArray();
}

public static Rect GetEditorMainWindowPos()
{
if (Application.isBatchMode)
{
return Rect.zero;
}

var containerWinType = GetAllDerivedTypes(System.AppDomain.CurrentDomain, typeof(ScriptableObject))
.Where(t => t.Name == "ContainerWindow")
.FirstOrDefault();
if (containerWinType == null)
throw new System.MissingMemberException("Can't find internal type ContainerWindow. Maybe something has changed inside Unity");
var showModeField = containerWinType.GetField("m_ShowMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var positionProperty = containerWinType.GetProperty("position", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
if (showModeField == null || positionProperty == null)
throw new System.MissingFieldException("Can't find internal fields 'm_ShowMode' or 'position'. Maybe something has changed inside Unity");
var windows = Resources.FindObjectsOfTypeAll(containerWinType);
foreach (var win in windows)
{
var showmode = (int)showModeField.GetValue(win);
if (showmode == 4) // main window
{
var pos = (Rect)positionProperty.GetValue(win, null);
return pos;
}
progressWindow.Progress(avatarCount, $"Finished uploading all Avatars! ({avatarCount}/{avatarCount})", true);
progressWindow.ShowOKButton();
}
throw new System.NotSupportedException("Can't find internal main window. Maybe something has changed inside Unity");
}
}
Loading

0 comments on commit 256df9a

Please sign in to comment.