From e2b229edfcf50172eb907d98e1edbe5877f7eef0 Mon Sep 17 00:00:00 2001 From: "Lillith Rose (Device: Lucia)" Date: Wed, 18 Jun 2025 12:31:45 -0400 Subject: [PATCH] misc stuff from other avatars --- .../GestureManagerExporter.asmdef | 27 ++++ .../GestureManagerExporter.asmdef.meta | 7 + .../GestureManagerExporter.cs | 133 ++++++++++++++++++ .../GestureManagerExporter.cs.meta | 11 ++ GestureManagerExporter/README.md | 3 + GestureManagerExporter/README.md.meta | 7 + VRCFAllowRootFeatures.meta | 8 ++ VRCFAllowRootFeatures/README.md | 3 + VRCFAllowRootFeatures/README.md.meta | 7 + .../VRCFAllowRootFeatures.asmdef | 18 +++ .../VRCFAllowRootFeatures.asmdef.meta | 7 + .../VRCFAllowRootFeatures.cs | 31 ++++ .../VRCFAllowRootFeatures.cs.meta | 11 ++ 13 files changed, 273 insertions(+) create mode 100644 GestureManagerExporter/GestureManagerExporter.asmdef create mode 100644 GestureManagerExporter/GestureManagerExporter.asmdef.meta create mode 100644 GestureManagerExporter/GestureManagerExporter.cs create mode 100644 GestureManagerExporter/GestureManagerExporter.cs.meta create mode 100644 GestureManagerExporter/README.md create mode 100644 GestureManagerExporter/README.md.meta create mode 100644 VRCFAllowRootFeatures.meta create mode 100644 VRCFAllowRootFeatures/README.md create mode 100644 VRCFAllowRootFeatures/README.md.meta create mode 100644 VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef create mode 100644 VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef.meta create mode 100644 VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs create mode 100644 VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs.meta diff --git a/GestureManagerExporter/GestureManagerExporter.asmdef b/GestureManagerExporter/GestureManagerExporter.asmdef new file mode 100644 index 0000000..ddcfafe --- /dev/null +++ b/GestureManagerExporter/GestureManagerExporter.asmdef @@ -0,0 +1,27 @@ +{ + "name": "GestureManagerExporter", + "rootNamespace": "", + "references": [ + "GUID:184316a0752f3c74fbd758a2fb0f0d46", + "GUID:f5ea942962a55ed488e8a2962adce217" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [ + "VRCSDK_HAS_HARMONY" + ], + "versionDefines": [ + { + "name": "com.vrchat.base", + "expression": "(3.3.99999,)", + "define": "VRCSDK_HAS_HARMONY" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/GestureManagerExporter/GestureManagerExporter.asmdef.meta b/GestureManagerExporter/GestureManagerExporter.asmdef.meta new file mode 100644 index 0000000..272ef82 --- /dev/null +++ b/GestureManagerExporter/GestureManagerExporter.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 599cb6f19c2a83441af2b00cd74d0ee3 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GestureManagerExporter/GestureManagerExporter.cs b/GestureManagerExporter/GestureManagerExporter.cs new file mode 100644 index 0000000..fcac892 --- /dev/null +++ b/GestureManagerExporter/GestureManagerExporter.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using HarmonyLib; +using Newtonsoft.Json; +using UnityEditor; +using UnityEngine; +using VRC.SDKBase; +using BlackStartX.GestureManager.Editor.Modules.Vrc3; +using BlackStartX.GestureManager.Editor.Modules.Vrc3.Params; + +[InitializeOnLoad] +internal static class GestureManagerExporter +{ + private static bool excludeAnimatorParameters = true; + private static bool sortByDescriptor = true; + + static GestureManagerExporter() + { + var harmony = new Harmony("gay.lilyy.GestureManagerExporter"); + harmony.PatchAll(); + } + + [HarmonyPatch] + private static class PatchParametersLayout + { + static MethodBase TargetMethod() + { + var nestedClass = typeof(ModuleVrc3).Assembly + .GetType("BlackStartX.GestureManager.Editor.Modules.Vrc3.Vrc3Debug.Avatar.Vrc3AvatarDebugWindow+Static"); + + return nestedClass?.GetMethod("ParametersLayout", BindingFlags.NonPublic | BindingFlags.Static); + } + + static void Postfix(ModuleVrc3 module, float width) + { + excludeAnimatorParameters = GUILayout.Toggle(excludeAnimatorParameters, "Exclude Animator-Only Parameters", GUILayout.Width(width)); + sortByDescriptor = GUILayout.Toggle(sortByDescriptor, "Sort by Parameters File", GUILayout.Width(width)); + + if (!GUILayout.Button("Export Parameters to JSON", GUILayout.Width(width))) return; + + var path = EditorUtility.SaveFilePanel( + "Export Parameters", + "Assets", + "avatar_parameters.json", + "json" + ); + + if (string.IsNullOrEmpty(path)) return; + + var parameters = new Dictionary(); + + var avatarDescriptor = module.AvatarDescriptor; + + foreach (var param in module.Params) + { + if (excludeAnimatorParameters) { + if (avatarDescriptor.expressionParameters.FindParameter(param.Key) == null) { + continue; + } + } + + object value = param.Value.Type switch + { + AnimatorControllerParameterType.Float => param.Value.FloatValue(), + AnimatorControllerParameterType.Int => param.Value.IntValue(), + AnimatorControllerParameterType.Bool => param.Value.BoolValue(), + AnimatorControllerParameterType.Trigger => param.Value.BoolValue(), + _ => throw new ArgumentOutOfRangeException(nameof(param.Value.Type), param.Value.Type, null) + }; + + parameters[param.Key] = new + { + type = param.Value.TypeText, + value + }; + } + + if (sortByDescriptor) { + var orderedParams = new Dictionary(); + + var paramNamesInDescriptor = avatarDescriptor.expressionParameters.parameters + .Select(p => p.name) + .Where(name => parameters.ContainsKey(name)); + + foreach (var name in paramNamesInDescriptor) + orderedParams[name] = parameters[name]; + + var unmatchedParams = parameters.Keys + .Where(k => !orderedParams.ContainsKey(k)) + .OrderBy(k => k); + + foreach (var name in unmatchedParams) + orderedParams[name] = parameters[name]; + + parameters = orderedParams; + } + + + var settings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + FloatFormatHandling = FloatFormatHandling.String, // We'll format floats ourselves + Converters = new List { new Float2DecimalConverter() } + }; + + var json = JsonConvert.SerializeObject(parameters, settings); + + File.WriteAllText(path, json); + + EditorUtility.DisplayDialog("Export Complete", $"{parameters.Count} Parameters have been exported successfully!", "OK"); + } + } +} + +class Float2DecimalConverter : JsonConverter +{ + public override bool CanConvert(Type objectType) => + objectType == typeof(float) || objectType == typeof(double); + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is float f) + writer.WriteRawValue(f.ToString("0.00")); + else if (value is double d) + writer.WriteRawValue(d.ToString("0.00")); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => + throw new NotImplementedException(); +} diff --git a/GestureManagerExporter/GestureManagerExporter.cs.meta b/GestureManagerExporter/GestureManagerExporter.cs.meta new file mode 100644 index 0000000..4e978b6 --- /dev/null +++ b/GestureManagerExporter/GestureManagerExporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc83507142543124eb3c70264bc802ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/GestureManagerExporter/README.md b/GestureManagerExporter/README.md new file mode 100644 index 0000000..2da620d --- /dev/null +++ b/GestureManagerExporter/README.md @@ -0,0 +1,3 @@ +# GestureManagerExporter + +A Harmony patch that adds an `Export Parameters` button to the GestureManager avatars debug menu, pulling out all of your parameters so you can diff them \ No newline at end of file diff --git a/GestureManagerExporter/README.md.meta b/GestureManagerExporter/README.md.meta new file mode 100644 index 0000000..9990623 --- /dev/null +++ b/GestureManagerExporter/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8c6cf20c81a2101499ba6f2091da6d2e +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCFAllowRootFeatures.meta b/VRCFAllowRootFeatures.meta new file mode 100644 index 0000000..22a32fe --- /dev/null +++ b/VRCFAllowRootFeatures.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b19908d38fd94146aa0be6de761e3c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCFAllowRootFeatures/README.md b/VRCFAllowRootFeatures/README.md new file mode 100644 index 0000000..d14e2da --- /dev/null +++ b/VRCFAllowRootFeatures/README.md @@ -0,0 +1,3 @@ +# VRCFAllowRootFeatures + +A Harmony patch to disable the `To avoid abuse by prefab creators, this component can only be placed on the root object containing the avatar descriptor, OR a child object containing ONLY vrcfury components.` message \ No newline at end of file diff --git a/VRCFAllowRootFeatures/README.md.meta b/VRCFAllowRootFeatures/README.md.meta new file mode 100644 index 0000000..36304b1 --- /dev/null +++ b/VRCFAllowRootFeatures/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 45c06a4ce7dc45042a050e36ab0dbc2c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef new file mode 100644 index 0000000..c4102cf --- /dev/null +++ b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef @@ -0,0 +1,18 @@ +{ + "name": "VRCFAllowRootFeatures", + "rootNamespace": "", + "references": [ + "GUID:3a48074f337050d4c987242d92d466b6" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef.meta b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef.meta new file mode 100644 index 0000000..32c4f35 --- /dev/null +++ b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c14d83102ee44b14bb9088ece79690e3 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs new file mode 100644 index 0000000..3680357 --- /dev/null +++ b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs @@ -0,0 +1,31 @@ +using System.Reflection; +using HarmonyLib; +using UnityEditor; +using UnityEngine; + +[InitializeOnLoad] +public static class VRCFAllowRootFeatures { + static VRCFAllowRootFeatures() { + var harmony = new Harmony("gay.lilyy.VRCFAllowRootFeatures"); + var featureFinderType = AccessTools.TypeByName("VF.Feature.Base.FeatureFinder"); + + if (featureFinderType == null) { + Debug.LogError("FeatureFinder type not found"); + return; + } + + var method = AccessTools.Method(featureFinderType, "AllowRootFeatures"); + if (method == null) { + Debug.LogError("AllowRootFeatures method not found"); + return; + } + + var prefix = typeof(VRCFAllowRootFeatures).GetMethod(nameof(Prefix), BindingFlags.Static | BindingFlags.NonPublic); + harmony.Patch(method, prefix: new HarmonyMethod(prefix)); + } + + private static bool Prefix(object gameObject, object avatarObject, ref bool __result) { + __result = true; + return false; + } +} diff --git a/VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs.meta b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs.meta new file mode 100644 index 0000000..2f6d414 --- /dev/null +++ b/VRCFAllowRootFeatures/VRCFAllowRootFeatures.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 63d5a4749805a33428c808b6ae6c0dcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: